-
-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathts-create-program.mts
101 lines (98 loc) · 2.6 KB
/
ts-create-program.mts
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
import type typescript from "typescript"
import type tsvfs from "@typescript/vfs"
type TS = typeof typescript
type TSVFS = typeof tsvfs
/** Create Program */
export function createProgram(
{
ts,
compilerOptions,
compilerHost,
}: {
ts: TS
compilerOptions: typescript.CompilerOptions
compilerHost: typescript.CompilerHost
},
options: { filePath: string },
): typescript.Program {
try {
const program = ts.createProgram({
rootNames: [options.filePath],
options: compilerOptions,
host: compilerHost,
})
return program
} catch (e) {
// eslint-disable-next-line no-console -- Demo debug
console.error(e)
throw e
}
}
export function createCompilerOptions(ts: TS): typescript.CompilerOptions {
const compilerOptions: typescript.CompilerOptions = {
target: ts.ScriptTarget.ESNext,
module: ts.ModuleKind.ESNext,
jsx: ts.JsxEmit.Preserve,
strict: true,
}
compilerOptions.lib = [ts.getDefaultLibFileName(compilerOptions)]
return compilerOptions
}
export async function createVirtualCompilerHost(
{
ts,
tsvfs,
compilerOptions,
}: {
ts: TS
tsvfs: TSVFS
compilerOptions: typescript.CompilerOptions
},
{ filePath: targetFilePath }: { filePath: string },
): Promise<{
compilerHost: typescript.CompilerHost
updateFile: (sourceFile: typescript.SourceFile) => boolean
fsMap: Map<string, string>
}> {
const fsMap = await tsvfs.createDefaultMapFromCDN(
{
lib: Array.from(
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- use internal
(ts as any).libMap.keys(),
),
},
ts.version,
true,
ts,
)
const system = tsvfs.createSystem(fsMap)
const host = tsvfs.createVirtualCompilerHost(system, compilerOptions, ts)
// eslint-disable-next-line @typescript-eslint/unbound-method -- backup original
const original = { getSourceFile: host.compilerHost.getSourceFile }
host.compilerHost.getSourceFile = function (
fileName,
languageVersionOrOptions,
...args
) {
if (targetFilePath === fileName) {
// Exclude the target file from caching as it will be modified.
const file = this.readFile(fileName) ?? ""
return ts.createSourceFile(fileName, file, languageVersionOrOptions, true)
}
if (this.fileExists(fileName)) {
return original.getSourceFile.apply(this, [
fileName,
languageVersionOrOptions,
...args,
])
}
// Avoid error
// eslint-disable-next-line no-console -- Demo debug
console.log(`Not exists: ${fileName}`)
return undefined
}
return {
...host,
fsMap,
}
}