Repository navigation
Expand file tree
/
Copy pathplugin.ts
More file actions
128 lines (104 loc) · 4.81 KB
/
Copy pathplugin.ts
File metadata and controls
128 lines (104 loc) · 4.81 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import type * as ts from 'typescript'
import type { ProgramTransformerExtras } from 'ts-patch';
import * as fs from 'fs';
import * as path from 'path';
/* ****************************************************************************************************************** */
// region: Config
/* ****************************************************************************************************************** */
const srcTypesFileName = path.resolve(__dirname, '../core/shared/plugin-types.ts');
const destTypesFileName = path.resolve(__dirname, 'src/types/plugin-types.ts');
// endregion
/* ****************************************************************************************************************** */
// region: Transformers
/* ****************************************************************************************************************** */
function transformPatchDeclarationsFile(this: typeof ts, ctx: ts.TransformationContext) {
const { factory } = ctx;
const moduleName = factory.createIdentifier('ts');
return (sourceFile: ts.SourceFile) => {
const statements = sourceFile
.statements
.filter(node =>
this.isModuleDeclaration(node) && this.getJSDocTags(node).some(t => t.tagName.text === 'build-types')
)
.map((node: ts.ModuleDeclaration) =>
factory.updateModuleDeclaration(node, node.modifiers, moduleName, node.body)
);
return factory.updateSourceFile(
sourceFile,
statements,
sourceFile.isDeclarationFile
);
}
}
function transformPluginTypes(this: typeof ts, ctx: ts.TransformationContext) {
const { factory } = ctx;
return (sourceFile: ts.SourceFile) => {
const moduleDeclaration =
factory.createModuleDeclaration(
[ factory.createModifier(this.SyntaxKind.DeclareKeyword) ],
factory.createIdentifier('tsp'),
factory.createModuleBlock(
sourceFile
.statements
// TODO - remove the casting once we have tsei again
.filter(node => (<any>this).isDeclaration(node) && this.getCombinedModifierFlags(node as unknown as ts.Declaration))
),
// TODO - remove the casting once we have tsei again
this.NodeFlags.Namespace | this.NodeFlags.ExportContext | (<any>this.NodeFlags).Ambient | this.NodeFlags.ContextFlags
);
return factory.updateSourceFile(sourceFile, [ moduleDeclaration ]);
}
}
// endregion
/* ****************************************************************************************************************** *
* Program Transformer - Build and insert plugin-types.ts
* ****************************************************************************************************************** */
export function transformProgram(
program: ts.Program,
host: ts.CompilerHost,
opt: any,
{ ts }: ProgramTransformerExtras
)
{
host ??= ts.createCompilerHost(program.getCompilerOptions(), true);
const printer = ts.createPrinter({
removeComments: true,
newLine: ts.NewLineKind.LineFeed
});
// TODO - remove the casting once we have tsei again
const srcFileName = (<any>ts).normalizePath(srcTypesFileName);
const destFileName = (<any>ts).normalizePath(destTypesFileName);
hookWriteFile();
generatePluginTypesAndInjectToProgram();
return ts.createProgram(
program.getRootFileNames().concat([ destFileName ]),
program.getCompilerOptions(),
host,
program
);
function hookWriteFile() {
const originalWriteFile = host.writeFile;
host.writeFile = (fileName: string, data: string, ...args: any[]) => {
/* Transform declarations */
if (/module-patch.d.ts$/.test(fileName)) {
let sourceFile = ts.createSourceFile(fileName, data, ts.ScriptTarget.ES2016, true, ts.ScriptKind.TS);
sourceFile = ts.transform(sourceFile, [ transformPatchDeclarationsFile.bind(ts) ]).transformed[0];
return (<any>originalWriteFile)(fileName, printer.printFile(sourceFile), ...args);
}
/* Strip comments from js */
if (/module-patch.js$/.test(fileName)) {
/* Wrap file in closure */
data = `var tsp = (function() {\n${data}\nreturn tsp;})();`;
const sourceFile = ts.createSourceFile(fileName, data, ts.ScriptTarget.ES2016, false, ts.ScriptKind.JS);
return (<any>originalWriteFile)(fileName, printer.printFile(sourceFile), ...args);
}
return (<any>originalWriteFile)(fileName, data, ...args);
}
}
function generatePluginTypesAndInjectToProgram() {
let sourceFile = ts.createSourceFile(srcFileName, fs.readFileSync(srcFileName, 'utf8'), ts.ScriptTarget.ES2015, true);
sourceFile = ts.transform(sourceFile, [ transformPluginTypes.bind(ts) ]).transformed[0];
const moduleBody = `// @ts-nocheck\n/** AUTO-GENERATED - DO NOT EDIT */\n\n/** @build-types */\n` + printer.printFile(sourceFile);
fs.writeFileSync(destFileName, moduleBody);
}
}