-
Notifications
You must be signed in to change notification settings - Fork 20
/
san-source-file.ts
104 lines (91 loc) · 3.32 KB
/
san-source-file.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
* 一个 SanSourceFile 表示一个 San 源文件
*
* San 源文件可以是一个 .san 文件,.js 文件,.ts 文件,也可以是一个 ComponentClass,具体来说:
* - .ts 文件对应的类型是 TypedSanSourceFile
* - .js 文件对应的类型是 JSSanSourceFile
* - .san 文件会通过 WebPack 转换为 .js 文件再进入 SSR,所以也对应 JSSanSourceFile
* - ComponentClass 对应的类型是 DynamicSanSourceFile
*/
import type { SourceFile } from 'ts-morph'
import debugFactory from 'debug'
import { DynamicComponentInfo, ComponentInfo, JSComponentInfo, TypedComponentInfo } from '../models/component-info'
const debug = debugFactory('san-source-file')
/**
* 一个 San 项目中的源文件
*
* 是 TypeScript SourceFile 的封装,但包含组件信息
*/
export abstract class SanSourceFileImpl<T extends ComponentInfo = ComponentInfo> {
constructor (
/**
* 每个组件对应一个 ComponentInfo,它们可以在运行时互相调用,是平铺关系
*/
public readonly componentInfos: T[],
/**
* componentInfos 中作为入口组件的那个
* - 对于 TypeScript 解析来的组件,是默认导出的组件
* - 对于 ComponentClass 解析来的组件,是根组件
*/
public readonly entryComponentInfo?: T
) {}
/**
* 文件路径对于命名空间(编译到非 JavaScript 时)很有用
*/
abstract getFilePath(): string
}
export class DynamicSanSourceFile extends SanSourceFileImpl<DynamicComponentInfo> {
constructor (
componentInfos: DynamicComponentInfo[],
private readonly filePath: string,
public readonly entryComponentInfo: DynamicComponentInfo
) {
super(componentInfos, entryComponentInfo)
}
getFilePath () {
return this.filePath
}
}
export class JSSanSourceFile extends SanSourceFileImpl<JSComponentInfo> {
constructor (
private readonly filePath: string,
private readonly fileContent: string,
componentInfos: JSComponentInfo[],
public readonly entryComponentInfo?: JSComponentInfo
) {
super(componentInfos, entryComponentInfo)
}
getFilePath () {
return this.filePath
}
getFileContent () {
return this.fileContent
}
}
export class TypedSanSourceFile extends SanSourceFileImpl<TypedComponentInfo> {
constructor (
componentInfos: TypedComponentInfo[],
public readonly tsSourceFile: SourceFile,
entryComponentInfo?: TypedComponentInfo
) {
super(componentInfos, entryComponentInfo)
}
getFilePath () {
return this.tsSourceFile.getFilePath()
}
/**
* 遍历组件类声明
*/
* getComponentClassDeclarations () {
for (const info of this.componentInfos) {
yield info.classDeclaration
}
}
}
export type SanSourceFile = DynamicSanSourceFile | TypedSanSourceFile | JSSanSourceFile
export function isTypedSanSourceFile (sourceFile: SanSourceFile): sourceFile is TypedSanSourceFile {
return Object.prototype.hasOwnProperty.call(sourceFile, 'tsSourceFile')
}
export function isJSSanSourceFile (sourceFile: SanSourceFile): sourceFile is JSSanSourceFile {
return !isTypedSanSourceFile(sourceFile) && Object.prototype.hasOwnProperty.call(sourceFile, 'fileContent')
}