@travetto/compiler 3.0.0-rc.1 → 3.0.0-rc.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/__index__.ts +3 -0
- package/bin/trv.js +96 -0
- package/package.json +32 -15
- package/src/compiler.ts +147 -149
- package/src/state.ts +211 -0
- package/src/util.ts +143 -0
- package/support/compiler-entry.ts +2 -0
- package/support/launcher.ts +160 -0
- package/support/transpile.ts +185 -0
- package/tsconfig.trv.json +23 -0
- package/LICENSE +0 -21
- package/index.ts +0 -3
- package/src/host.ts +0 -142
- package/src/transformer.ts +0 -75
- package/support/dynamic.compiler.ts +0 -72
- package/support/phase.init.ts +0 -13
- package/support/phase.reset.ts +0 -10
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import cp from 'child_process';
|
|
5
|
+
import { createRequire } from 'module';
|
|
6
|
+
|
|
7
|
+
import { DeltaEvent, ManifestContext, ManifestRoot, Package } from '@travetto/manifest';
|
|
8
|
+
|
|
9
|
+
type ModFile = { input: string, output: string, stale: boolean };
|
|
10
|
+
|
|
11
|
+
const SRC_REQ = createRequire(path.resolve('node_modules'));
|
|
12
|
+
const recentStat = (stat: { ctimeMs: number, mtimeMs: number }): number => Math.max(stat.ctimeMs, stat.mtimeMs);
|
|
13
|
+
|
|
14
|
+
export type CompilerLogEvent = [level: 'info' | 'debug' | 'warn', message: string];
|
|
15
|
+
type WithLogger<T> = (log: (...ev: CompilerLogEvent) => void) => Promise<T>;
|
|
16
|
+
type LogConfig = { args?: string[], basic?: boolean };
|
|
17
|
+
const isCompilerLogEvent = (o: unknown): o is CompilerLogEvent => o !== null && o !== undefined && Array.isArray(o);
|
|
18
|
+
|
|
19
|
+
const LEVELS = { warn: true, debug: /^debug$/.test(process.env.TRV_BUILD ?? ''), info: !/^warn$/.test(process.env.TRV_BUILD ?? '') };
|
|
20
|
+
const SCOPE_MAX = 15;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Transpile utilities for launching
|
|
24
|
+
*/
|
|
25
|
+
export class TranspileUtil {
|
|
26
|
+
static #optCache: Record<string, {}> = {};
|
|
27
|
+
|
|
28
|
+
static log(scope: string, args: string[], ...[level, msg]: CompilerLogEvent): void {
|
|
29
|
+
const message = msg.replaceAll(process.cwd(), '.');
|
|
30
|
+
LEVELS[level] && console.debug(new Date().toISOString(), `[${scope.padEnd(SCOPE_MAX, ' ')}]`, ...args, message);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* With logger
|
|
35
|
+
*/
|
|
36
|
+
static withLogger<T>(scope: string, op: WithLogger<T>): Promise<T>;
|
|
37
|
+
static withLogger<T>(scope: string, opts: LogConfig, op: WithLogger<T>): Promise<T>;
|
|
38
|
+
static withLogger<T>(scope: string, opts: LogConfig | WithLogger<T>, op?: WithLogger<T>): Promise<T> {
|
|
39
|
+
const cfg = { basic: true, ...typeof opts === 'function' ? {} : opts };
|
|
40
|
+
const go = typeof opts === 'function' ? opts : op!;
|
|
41
|
+
const log = this.log.bind(null, scope, cfg.args ?? []);
|
|
42
|
+
cfg.basic && log('debug', 'Started');
|
|
43
|
+
return go(log).finally(() => cfg.basic && log('debug', 'Completed'));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Write text file, and ensure folder exists
|
|
48
|
+
*/
|
|
49
|
+
static writeTextFile = (file: string, content: string): Promise<void> =>
|
|
50
|
+
fs.mkdir(path.dirname(file), { recursive: true }).then(() => fs.writeFile(file, content));
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns the compiler options
|
|
54
|
+
*/
|
|
55
|
+
static async getCompilerOptions(ctx: ManifestContext): Promise<{}> {
|
|
56
|
+
if (!(ctx.workspacePath in this.#optCache)) {
|
|
57
|
+
let tsconfig = path.resolve(ctx.workspacePath, 'tsconfig.json');
|
|
58
|
+
|
|
59
|
+
if (!await fs.stat(tsconfig).then(_ => true, _ => false)) {
|
|
60
|
+
tsconfig = SRC_REQ.resolve('@travetto/compiler/tsconfig.trv.json');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const ts = (await import('typescript')).default;
|
|
64
|
+
|
|
65
|
+
const { options } = ts.parseJsonSourceFileConfigFileContent(
|
|
66
|
+
ts.readJsonConfigFile(tsconfig, ts.sys.readFile), ts.sys, ctx.workspacePath
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
options.allowJs = true;
|
|
70
|
+
options.resolveJsonModule = true;
|
|
71
|
+
options.sourceRoot = ctx.workspacePath;
|
|
72
|
+
options.rootDir = ctx.workspacePath;
|
|
73
|
+
options.outDir = path.resolve(ctx.workspacePath);
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
options.module = ctx.moduleType === 'commonjs' ? ts.ModuleKind.CommonJS : ts.ModuleKind.ESNext;
|
|
77
|
+
} catch { }
|
|
78
|
+
|
|
79
|
+
this.#optCache[ctx.workspacePath] = options;
|
|
80
|
+
}
|
|
81
|
+
return this.#optCache[ctx.workspacePath];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Output a file, support for ts, js, and package.json
|
|
86
|
+
*/
|
|
87
|
+
static async transpileFile(ctx: ManifestContext, inputFile: string, outputFile: string): Promise<void> {
|
|
88
|
+
if (inputFile.endsWith('.ts') || inputFile.endsWith('.js')) {
|
|
89
|
+
const compilerOut = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules');
|
|
90
|
+
|
|
91
|
+
const text = (await fs.readFile(inputFile, 'utf8'))
|
|
92
|
+
.replace(/from '([.][^']+)'/g, (_, i) => `from '${i.replace(/[.]js$/, '')}.js'`)
|
|
93
|
+
.replace(/from '(@travetto\/(.*?))'/g, (_, i, s) => `from '${path.resolve(compilerOut, `${i}${s.includes('/') ? '.js' : '/__index__.js'}`)}'`);
|
|
94
|
+
|
|
95
|
+
const ts = (await import('typescript')).default;
|
|
96
|
+
const content = ts.transpile(text, await this.getCompilerOptions(ctx), inputFile);
|
|
97
|
+
await this.writeTextFile(outputFile, content);
|
|
98
|
+
} else if (inputFile.endsWith('package.json')) {
|
|
99
|
+
const pkg: Package = JSON.parse(await fs.readFile(inputFile, 'utf8'));
|
|
100
|
+
const main = pkg.main?.replace(/[.]ts$/, '.js');
|
|
101
|
+
const files = pkg.files?.map(x => x.replace('.ts', '.js'));
|
|
102
|
+
|
|
103
|
+
const content = JSON.stringify({ ...pkg, main, type: ctx.moduleType, files }, null, 2);
|
|
104
|
+
await this.writeTextFile(outputFile, content);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Scan directory to find all project sources for comparison
|
|
110
|
+
*/
|
|
111
|
+
static async getModuleSources(ctx: ManifestContext, module: string, seed: string[]): Promise<ModFile[]> {
|
|
112
|
+
const inputFolder = (ctx.mainModule === module) ?
|
|
113
|
+
process.cwd() :
|
|
114
|
+
path.dirname(SRC_REQ.resolve(`${module}/package.json`));
|
|
115
|
+
|
|
116
|
+
const folders = seed.filter(x => !/[.]/.test(x)).map(x => path.resolve(inputFolder, x));
|
|
117
|
+
const files = seed.filter(x => /[.]/.test(x)).map(x => path.resolve(inputFolder, x));
|
|
118
|
+
|
|
119
|
+
while (folders.length) {
|
|
120
|
+
const sub = folders.pop();
|
|
121
|
+
if (!sub) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for (const file of await fs.readdir(sub).catch(() => [])) {
|
|
126
|
+
if (file.startsWith('.')) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const resolvedInput = path.resolve(sub, file);
|
|
130
|
+
const stat = await fs.stat(resolvedInput);
|
|
131
|
+
|
|
132
|
+
if (stat.isDirectory()) {
|
|
133
|
+
folders.push(resolvedInput);
|
|
134
|
+
} else if (file.endsWith('.d.ts')) {
|
|
135
|
+
// Do nothing
|
|
136
|
+
} else if (file.endsWith('.ts') || file.endsWith('.js')) {
|
|
137
|
+
files.push(resolvedInput);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const outputFolder = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', module);
|
|
143
|
+
const out: ModFile[] = [];
|
|
144
|
+
for (const input of files) {
|
|
145
|
+
const output = input.replace(inputFolder, outputFolder).replace(/[.]ts$/, '.js');
|
|
146
|
+
const inputTs = await fs.stat(input).then(recentStat, () => 0);
|
|
147
|
+
if (inputTs) {
|
|
148
|
+
const outputTs = await fs.stat(output).then(recentStat, () => 0);
|
|
149
|
+
await fs.mkdir(path.dirname(output), { recursive: true, });
|
|
150
|
+
out.push({ input, output, stale: inputTs > outputTs });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Run compiler
|
|
159
|
+
*/
|
|
160
|
+
static async runCompiler(ctx: ManifestContext, manifest: ManifestRoot, changed: DeltaEvent[], watch = false): Promise<void> {
|
|
161
|
+
const compiler = path.resolve(ctx.workspacePath, ctx.compilerFolder);
|
|
162
|
+
const main = path.resolve(compiler, 'node_modules', '@travetto/compiler/support/compiler-entry.js');
|
|
163
|
+
const deltaFile = path.resolve(os.tmpdir(), `manifest-delta.${Date.now()}.${Math.random()}.json`);
|
|
164
|
+
|
|
165
|
+
const changedFiles = changed[0]?.file === '*' ? ['*'] : changed.map(ev =>
|
|
166
|
+
path.resolve(manifest.workspacePath, manifest.modules[ev.module].sourceFolder, ev.file)
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
await this.writeTextFile(deltaFile, changedFiles.join('\n'));
|
|
170
|
+
|
|
171
|
+
await this.withLogger('compiler-exec', async log => {
|
|
172
|
+
await new Promise((res, rej) =>
|
|
173
|
+
cp.spawn(process.argv0, [main, deltaFile, `${watch}`], {
|
|
174
|
+
env: {
|
|
175
|
+
...process.env,
|
|
176
|
+
TRV_MANIFEST: path.resolve(ctx.workspacePath, ctx.outputFolder, 'node_modules', ctx.mainModule),
|
|
177
|
+
},
|
|
178
|
+
stdio: [0, 1, 2, 'ipc'],
|
|
179
|
+
})
|
|
180
|
+
.on('message', msg => isCompilerLogEvent(msg) && log(...msg))
|
|
181
|
+
.on('exit', code => (code !== null && code > 0) ? rej() : res(null))
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "CommonJS",
|
|
4
|
+
"target": "esnext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"lib": [
|
|
7
|
+
"es2022"
|
|
8
|
+
],
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"strictPropertyInitialization": false,
|
|
12
|
+
"experimentalDecorators": true,
|
|
13
|
+
"noEmitOnError": false,
|
|
14
|
+
"noErrorTruncation": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"sourceMap": true,
|
|
17
|
+
"inlineSourceMap": false,
|
|
18
|
+
"removeComments": true,
|
|
19
|
+
"importHelpers": true,
|
|
20
|
+
"noEmitHelpers": true,
|
|
21
|
+
"outDir": "build/"
|
|
22
|
+
},
|
|
23
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2020 ArcSine Technologies
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/index.ts
DELETED
package/src/host.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import { readFileSync } from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
|
|
5
|
-
import { PathUtil, AppCache } from '@travetto/boot';
|
|
6
|
-
import { SourceUtil } from '@travetto/boot/src/internal/source-util';
|
|
7
|
-
import { SystemUtil } from '@travetto/boot/src/internal/system';
|
|
8
|
-
import { TranspileUtil } from '@travetto/boot/src/internal/transpile-util';
|
|
9
|
-
import { SourceIndex } from '@travetto/boot/src/internal/source';
|
|
10
|
-
import { AppManifest } from '@travetto/base';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Manages the source code and typescript relationship.
|
|
14
|
-
*/
|
|
15
|
-
export class SourceHost implements ts.CompilerHost {
|
|
16
|
-
|
|
17
|
-
#rootFiles = new Set<string>();
|
|
18
|
-
#hashes = new Map<string, number>();
|
|
19
|
-
#sources = new Map<string, ts.SourceFile>();
|
|
20
|
-
readonly contents = new Map<string, string>();
|
|
21
|
-
|
|
22
|
-
#trackFile(filename: string, content: string): void {
|
|
23
|
-
this.contents.set(filename, content);
|
|
24
|
-
this.#hashes.set(filename, SystemUtil.naiveHash(readFileSync(filename, 'utf8'))); // Get og content for hashing
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
getCanonicalFileName: (file: string) => string = (f: string) => f;
|
|
28
|
-
getCurrentDirectory: () => string = () => PathUtil.cwd;
|
|
29
|
-
getDefaultLibFileName: (opts: ts.CompilerOptions) => string = (opts: ts.CompilerOptions) => ts.getDefaultLibFileName(opts);
|
|
30
|
-
getNewLine: () => string = () => ts.sys.newLine;
|
|
31
|
-
useCaseSensitiveFileNames: () => boolean = () => ts.sys.useCaseSensitiveFileNames;
|
|
32
|
-
getDefaultLibLocation(): string {
|
|
33
|
-
return path.dirname(ts.getDefaultLibFilePath(TranspileUtil.compilerOptions));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Get root files
|
|
38
|
-
*/
|
|
39
|
-
getRootFiles(): Set<string> {
|
|
40
|
-
if (!this.#rootFiles.size) {
|
|
41
|
-
// Only needed for compilation
|
|
42
|
-
this.#rootFiles = new Set(SourceIndex.findByFolders(AppManifest.source, 'required').map(x => x.file));
|
|
43
|
-
}
|
|
44
|
-
return this.#rootFiles;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Read file from disk, using the transpile pre-processor on .ts files
|
|
49
|
-
*/
|
|
50
|
-
readFile(filename: string): string {
|
|
51
|
-
filename = PathUtil.toUnixTs(filename);
|
|
52
|
-
let content = ts.sys.readFile(filename);
|
|
53
|
-
if (content === undefined) {
|
|
54
|
-
throw new Error(`Unable to read file ${filename}`);
|
|
55
|
-
}
|
|
56
|
-
if (filename.endsWith(SourceUtil.EXT) && !filename.endsWith('.d.ts')) {
|
|
57
|
-
content = SourceUtil.preProcess(filename, content);
|
|
58
|
-
}
|
|
59
|
-
return content;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Write file to disk, and set value in cache as well
|
|
64
|
-
*/
|
|
65
|
-
writeFile(filename: string, content: string): void {
|
|
66
|
-
filename = PathUtil.toUnixTs(filename);
|
|
67
|
-
this.#trackFile(filename, content);
|
|
68
|
-
AppCache.writeEntry(filename, content);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Fetch file
|
|
73
|
-
*/
|
|
74
|
-
fetchFile(filename: string): void {
|
|
75
|
-
filename = PathUtil.toUnixTs(filename);
|
|
76
|
-
const cached = AppCache.readEntry(filename);
|
|
77
|
-
this.#trackFile(filename, cached);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Get a source file on demand
|
|
82
|
-
* @returns
|
|
83
|
-
*/
|
|
84
|
-
getSourceFile(filename: string, __tgt: unknown, __onErr: unknown, force?: boolean): ts.SourceFile {
|
|
85
|
-
if (!this.#sources.has(filename) || force) {
|
|
86
|
-
const content = this.readFile(filename)!;
|
|
87
|
-
this.#sources.set(filename, ts.createSourceFile(filename, content ?? '',
|
|
88
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
89
|
-
(TranspileUtil.compilerOptions as ts.CompilerOptions).target!
|
|
90
|
-
));
|
|
91
|
-
}
|
|
92
|
-
return this.#sources.get(filename)!;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* See if a file exists
|
|
97
|
-
*/
|
|
98
|
-
fileExists(filename: string): boolean {
|
|
99
|
-
filename = PathUtil.toUnixTs(filename);
|
|
100
|
-
return this.contents.has(filename) || ts.sys.fileExists(filename);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* See if a file's hash code has changed
|
|
105
|
-
*/
|
|
106
|
-
hashChanged(filename: string, content?: string): boolean {
|
|
107
|
-
content ??= readFileSync(filename, 'utf8');
|
|
108
|
-
// Let's see if they are really different
|
|
109
|
-
const hash = SystemUtil.naiveHash(content);
|
|
110
|
-
if (hash === this.#hashes.get(filename)) {
|
|
111
|
-
console.debug('Contents Unchanged', { filename });
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
return true;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Unload a file from the transpiler
|
|
119
|
-
*/
|
|
120
|
-
unload(filename: string, unlink = true): void {
|
|
121
|
-
if (this.contents.has(filename)) {
|
|
122
|
-
AppCache.removeExpiredEntry(filename, unlink);
|
|
123
|
-
|
|
124
|
-
if (unlink && this.#hashes.has(filename)) {
|
|
125
|
-
this.#hashes.delete(filename);
|
|
126
|
-
}
|
|
127
|
-
this.#rootFiles.delete(filename);
|
|
128
|
-
this.contents.delete(filename);
|
|
129
|
-
this.#sources.delete(filename);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Reset the transpiler
|
|
135
|
-
*/
|
|
136
|
-
reset(): void {
|
|
137
|
-
this.contents.clear();
|
|
138
|
-
this.#rootFiles.clear();
|
|
139
|
-
this.#hashes.clear();
|
|
140
|
-
this.#sources.clear();
|
|
141
|
-
}
|
|
142
|
-
}
|
package/src/transformer.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
|
|
3
|
-
import { SourceIndex } from '@travetto/boot/src/internal/source';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
NodeTransformer, VisitorFactory, TransformerState, getAllTransformers
|
|
7
|
-
} from '@travetto/transformer'; // Narrow import to minimize scope
|
|
8
|
-
|
|
9
|
-
type TransformerList = { before: ts.TransformerFactory<ts.SourceFile>[] };
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Manages the typescript transformers
|
|
14
|
-
*/
|
|
15
|
-
export class TransformerManager {
|
|
16
|
-
|
|
17
|
-
#cached: TransformerList | undefined;
|
|
18
|
-
#transformers: NodeTransformer<TransformerState>[] = [];
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Read all transformers from disk under the pattern support/transformer.*
|
|
22
|
-
*/
|
|
23
|
-
async init(): Promise<void> {
|
|
24
|
-
if (this.#cached) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Modules
|
|
29
|
-
const found = SourceIndex.find({ folder: 'support', filter: /\/transformer.*[.]ts/ });
|
|
30
|
-
|
|
31
|
-
for (const entry of found) { // Exclude based on blacklist
|
|
32
|
-
this.#transformers.push(...getAllTransformers(await import(entry.file)));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
console.debug('Transformers', {
|
|
36
|
-
order: this.#transformers.map(x => {
|
|
37
|
-
const flags = [
|
|
38
|
-
...(x.target ? [] : ['all']),
|
|
39
|
-
...(x.before ? ['before'] : []),
|
|
40
|
-
...(x.after ? ['after'] : [])
|
|
41
|
-
];
|
|
42
|
-
return { type: x.type, key: x.key, flags: flags.join(' ') };
|
|
43
|
-
})
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Prepare a new visitor factory with a given type checker
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
build(checker: ts.TypeChecker): void {
|
|
50
|
-
const visitor = new VisitorFactory(
|
|
51
|
-
(ctx, src) => new TransformerState(src, ctx.factory, checker),
|
|
52
|
-
this.#transformers
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
// Define transformers for the compiler
|
|
56
|
-
this.#cached = {
|
|
57
|
-
before: [visitor.visitor()]
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Get typescript transformer object
|
|
63
|
-
*/
|
|
64
|
-
getTransformers(): TransformerList | undefined {
|
|
65
|
-
return this.#cached!;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Reset state
|
|
70
|
-
*/
|
|
71
|
-
reset(): void {
|
|
72
|
-
this.#transformers = [];
|
|
73
|
-
this.#cached = undefined;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { AppManifest, Class, ShutdownManager } from '@travetto/base';
|
|
2
|
-
import { RetargettingProxy } from '@travetto/base/src/internal/proxy';
|
|
3
|
-
import { FsUtil, PathUtil } from '@travetto/boot';
|
|
4
|
-
import { ModuleUtil } from '@travetto/boot/src/internal/module-util';
|
|
5
|
-
import { ModuleManager } from '@travetto/boot/src/internal/module';
|
|
6
|
-
|
|
7
|
-
import { FilePresenceManager } from '@travetto/watch';
|
|
8
|
-
|
|
9
|
-
import { Compiler } from '../src/compiler';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Wraps the compiler supporting real-time changes to files
|
|
13
|
-
*/
|
|
14
|
-
export function init($Compiler: Class<typeof Compiler>): typeof $Compiler {
|
|
15
|
-
/**
|
|
16
|
-
* Extending the $Compiler class to add some functionality
|
|
17
|
-
*/
|
|
18
|
-
const Cls = class extends $Compiler {
|
|
19
|
-
#modules = new Map<string, RetargettingProxy<unknown>>();
|
|
20
|
-
|
|
21
|
-
constructor(...args: unknown[]) {
|
|
22
|
-
super(...args);
|
|
23
|
-
|
|
24
|
-
ShutdownManager.onUnhandled(err => {
|
|
25
|
-
if (err && (err.message ?? '').includes('Cannot find module')) { // Handle module reloading
|
|
26
|
-
console.error('Cannot find module', { error: err });
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
}, 0);
|
|
30
|
-
|
|
31
|
-
// Proxy all file loads
|
|
32
|
-
ModuleUtil.addHandler((name, mod) => {
|
|
33
|
-
if (name.includes(PathUtil.cwd) && !name.includes('node_modules') && /src\//.test(name)) {
|
|
34
|
-
if (!this.#modules.has(name)) {
|
|
35
|
-
this.#modules.set(name, new RetargettingProxy(mod));
|
|
36
|
-
} else {
|
|
37
|
-
this.#modules.get(name)!.setTarget(mod);
|
|
38
|
-
}
|
|
39
|
-
return this.#modules.get(name)!.get();
|
|
40
|
-
} else {
|
|
41
|
-
return mod;
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Clear target on unload
|
|
46
|
-
ModuleManager.onUnload(f => this.#modules.get(f)?.setTarget(null));
|
|
47
|
-
|
|
48
|
-
new FilePresenceManager(
|
|
49
|
-
[...AppManifest.source.local, ...AppManifest.source.common]
|
|
50
|
-
.map(x => `./${x}`)
|
|
51
|
-
.filter(x => FsUtil.existsSync(x)),
|
|
52
|
-
{
|
|
53
|
-
ignoreInitial: true,
|
|
54
|
-
validFile: x => x.endsWith('.ts') && !x.endsWith('.d.ts')
|
|
55
|
-
}
|
|
56
|
-
).on('all', ({ event, entry }) => {
|
|
57
|
-
switch (event) {
|
|
58
|
-
case 'added': this.added(entry.file); break;
|
|
59
|
-
case 'removed': this.removed(entry.file); break;
|
|
60
|
-
case 'changed': this.changed(entry.file); break;
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
reset(): void {
|
|
66
|
-
super.reset();
|
|
67
|
-
this.#modules.clear();
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
return Cls;
|
|
72
|
-
}
|
package/support/phase.init.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Responsible for initializing the compiler
|
|
3
|
-
*/
|
|
4
|
-
export const init = {
|
|
5
|
-
key: '@trv:compiler/init',
|
|
6
|
-
after: ['@trv:base/init'],
|
|
7
|
-
before: ['@trv:base/transpile'],
|
|
8
|
-
action: async (): Promise<void> => {
|
|
9
|
-
// Overrides the require behavior
|
|
10
|
-
const { Compiler } = await import('../src/compiler');
|
|
11
|
-
await Compiler.init();
|
|
12
|
-
}
|
|
13
|
-
};
|
package/support/phase.reset.ts
DELETED