@travetto/compiler 3.0.0-rc.11 → 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/bin/trv.js +72 -57
- package/package.json +7 -6
- package/src/compiler.ts +83 -85
- package/src/state.ts +50 -64
- package/src/util.ts +21 -80
- package/support/compiler-entry.ts +2 -0
- package/support/launcher.ts +160 -0
- package/support/transpile.ts +185 -0
- package/tsconfig.trv.json +1 -0
- package/bin/transpile.d.ts +0 -32
- package/bin/transpile.js +0 -227
- package/support/bin/compiler-bootstrap.ts +0 -151
- package/support/bin/utils.ts +0 -116
- package/support/main.output.ts +0 -11
package/bin/trv.js
CHANGED
|
@@ -1,81 +1,96 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// @ts-check
|
|
4
|
+
import fs from 'fs/promises';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { createRequire } from 'module';
|
|
7
|
+
|
|
8
|
+
import { getManifestContext } from '@travetto/manifest/bin/context.js';
|
|
9
|
+
|
|
10
|
+
const VALID_OPS = { watch: 'watch', build: 'build', clean: 'clean', manifest: 'manifest' };
|
|
4
11
|
|
|
5
12
|
/**
|
|
6
13
|
* @param {import('@travetto/manifest').ManifestContext} ctx
|
|
7
|
-
* @return {Promise<import('
|
|
14
|
+
* @return {Promise<import('@travetto/compiler/support/launcher')>}
|
|
8
15
|
*/
|
|
9
|
-
async
|
|
10
|
-
const
|
|
11
|
-
const
|
|
16
|
+
const $getLauncher = async (ctx) => {
|
|
17
|
+
const compPkg = createRequire(path.resolve('node_modules')).resolve('@travetto/compiler/package.json');
|
|
18
|
+
const files = [];
|
|
12
19
|
|
|
13
|
-
const
|
|
20
|
+
for (const file of ['support/launcher.js', 'support/transpile.js', 'package.json']) {
|
|
21
|
+
const target = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', '@travetto/compiler', file);
|
|
22
|
+
const src = compPkg.replace('package.json', file.replace(/[.]js$/, '.ts'));
|
|
14
23
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
const targetTime = await fs.stat(target).then(s => Math.max(s.mtimeMs, s.ctimeMs)).catch(() => 0);
|
|
25
|
+
const srcTime = await fs.stat(src).then(s => Math.max(s.mtimeMs, s.ctimeMs));
|
|
26
|
+
// If stale
|
|
27
|
+
if (srcTime > targetTime) {
|
|
28
|
+
const ts = (await import('typescript')).default;
|
|
29
|
+
const module = ctx.moduleType === 'module' ? ts.ModuleKind.ESNext : ts.ModuleKind.CommonJS;
|
|
30
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
31
|
+
const text = await fs.readFile(src, 'utf8');
|
|
32
|
+
if (file.endsWith('.js')) {
|
|
33
|
+
let content = ts.transpile(text, {
|
|
34
|
+
target: ts.ScriptTarget.ES2020, module, esModuleInterop: true, allowSyntheticDefaultImports: true
|
|
35
|
+
});
|
|
36
|
+
if (ctx.moduleType === 'module') {
|
|
37
|
+
content = content.replace(/^((?:im|ex)port .*from '[.][^']+)(')/mg, (_, a, b) => `${a}.js${b}`)
|
|
38
|
+
.replace(/^(import [^\n]*from '[^.][^\n/]+[/][^\n/]+[/][^\n']+)(')/mg, (_, a, b) => `${a}.js${b}`);
|
|
39
|
+
}
|
|
40
|
+
await fs.writeFile(target, content, 'utf8');
|
|
41
|
+
} else {
|
|
42
|
+
const pkg = JSON.parse(text);
|
|
43
|
+
pkg.type = ctx.moduleType;
|
|
44
|
+
await fs.writeFile(target, JSON.stringify(pkg, null, 2), 'utf8');
|
|
45
|
+
}
|
|
46
|
+
// Compile
|
|
47
|
+
}
|
|
48
|
+
files.push(target);
|
|
49
|
+
}
|
|
19
50
|
|
|
20
|
-
try { return require(
|
|
21
|
-
}
|
|
51
|
+
try { return await require(files[0]); }
|
|
52
|
+
catch { return import(files[0]); }
|
|
53
|
+
};
|
|
22
54
|
|
|
23
55
|
/**
|
|
24
|
-
*
|
|
25
|
-
* @param {
|
|
56
|
+
* Parse arguments
|
|
57
|
+
* @param {string[]} args
|
|
58
|
+
* @returns {{ op?: keyof typeof VALID_OPS, clean?: boolean, outputPath?: string, env?: string }}
|
|
26
59
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
60
|
+
function parseArgs(args) {
|
|
61
|
+
const op = VALID_OPS[args.find(x => !x.startsWith('-')) ?? ''];
|
|
62
|
+
return {
|
|
63
|
+
op,
|
|
64
|
+
clean: args.includes('--clean') || args.includes('-c'),
|
|
65
|
+
...(op === 'manifest' ? { outputPath: args[1], env: args[2] } : {})
|
|
66
|
+
};
|
|
67
|
+
}
|
|
35
68
|
|
|
36
|
-
|
|
37
|
-
const
|
|
69
|
+
const exec = async () => {
|
|
70
|
+
const ctx = await getManifestContext();
|
|
71
|
+
const { op, outputPath, env, ...flags } = parseArgs(process.argv.slice(2));
|
|
38
72
|
|
|
39
73
|
// Clean if needed
|
|
40
74
|
if (op === 'clean' || (op && flags.clean)) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
fs.rm(`${ctx.workspacePath}/${folder}`, { force: true, recursive: true })));
|
|
44
|
-
if (op === 'clean') {
|
|
45
|
-
message(`Cleaned ${ctx.workspacePath}: [${ctx.outputFolder}, ${ctx.compilerFolder}]`);
|
|
75
|
+
for (const f of [ctx.outputFolder, ctx.compilerFolder]) {
|
|
76
|
+
await fs.rm(path.resolve(ctx.workspacePath, f), { force: true, recursive: true });
|
|
46
77
|
}
|
|
47
78
|
}
|
|
48
79
|
|
|
80
|
+
if (op === 'clean') { // Clean needs to not attempt to compile/load launcher
|
|
81
|
+
return console.log(`Cleaned ${ctx.workspacePath}: [${ctx.outputFolder}, ${ctx.compilerFolder}]`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const { compile, launchMain, exportManifest } = await $getLauncher(ctx);
|
|
85
|
+
|
|
49
86
|
switch (op) {
|
|
50
|
-
case '
|
|
51
|
-
case 'manifest': {
|
|
52
|
-
const { writeManifest, buildManifest } = await $getBootstrap(ctx);
|
|
53
|
-
const manifest = (await buildManifest(ctx)).manifest;
|
|
54
|
-
await writeManifest(ctx, manifest);
|
|
55
|
-
const output = `${ctx.workspacePath}/${ctx.outputFolder}/${ctx.manifestFile}`;
|
|
56
|
-
message(`Wrote manifest ${output}`);
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
87
|
+
case 'manifest': return exportManifest(ctx, outputPath ?? '', env);
|
|
59
88
|
case 'watch':
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
await compile(ctx);
|
|
65
|
-
message(`Built to ${ctx.workspacePath}/${ctx.outputFolder}`);
|
|
66
|
-
break;
|
|
67
|
-
default: {
|
|
68
|
-
const path = require('path/posix');
|
|
69
|
-
const { manifest } = await compile(ctx);
|
|
70
|
-
const out = path.join(ctx.workspacePath, ctx.outputFolder);
|
|
71
|
-
// TODO: Externalize somehow?
|
|
72
|
-
const cliMain = path.join(out, manifest.modules['@travetto/cli'].output, 'support', 'main.cli.js');
|
|
73
|
-
process.env.TRV_MANIFEST = ctx.mainModule;
|
|
74
|
-
process.env.TRV_OUTPUT = out;
|
|
75
|
-
await import(process.env.TRV_MAIN = cliMain);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
89
|
+
case 'build': return compile(ctx, op);
|
|
90
|
+
default:
|
|
91
|
+
await compile(ctx, op);
|
|
92
|
+
return launchMain(ctx);
|
|
78
93
|
}
|
|
79
|
-
}
|
|
94
|
+
};
|
|
80
95
|
|
|
81
|
-
exec(
|
|
96
|
+
exec();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/compiler",
|
|
3
|
-
"version": "3.0.0-rc.
|
|
3
|
+
"version": "3.0.0-rc.12",
|
|
4
4
|
"description": "Compiler",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compiler",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"email": "travetto.framework@gmail.com",
|
|
14
14
|
"name": "Travetto Framework"
|
|
15
15
|
},
|
|
16
|
+
"type": "module",
|
|
16
17
|
"files": [
|
|
17
18
|
"__index__.ts",
|
|
18
19
|
"src",
|
|
@@ -29,13 +30,13 @@
|
|
|
29
30
|
"directory": "module/compiler"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"@travetto/
|
|
34
|
-
"@travetto/
|
|
35
|
-
"@
|
|
33
|
+
"@parcel/watcher": "^2.1.0",
|
|
34
|
+
"@travetto/manifest": "^3.0.0-rc.7",
|
|
35
|
+
"@travetto/terminal": "^3.0.0-rc.6",
|
|
36
|
+
"@travetto/transformer": "^3.0.0-rc.10"
|
|
36
37
|
},
|
|
37
38
|
"peerDependencies": {
|
|
38
|
-
"@travetto/cli": "^3.0.0-rc.
|
|
39
|
+
"@travetto/cli": "^3.0.0-rc.9"
|
|
39
40
|
},
|
|
40
41
|
"peerDependenciesMeta": {
|
|
41
42
|
"@travetto/cli": {
|
package/src/compiler.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import util from 'util';
|
|
2
|
+
import { install } from 'source-map-support';
|
|
1
3
|
import ts from 'typescript';
|
|
2
4
|
import fs from 'fs/promises';
|
|
3
|
-
import path from 'path';
|
|
4
5
|
|
|
5
|
-
import { ManifestState } from '@travetto/manifest';
|
|
6
6
|
import { GlobalTerminal, TerminalProgressEvent } from '@travetto/terminal';
|
|
7
|
+
import { RootIndex, watchFolders } from '@travetto/manifest';
|
|
8
|
+
import { TransformerManager } from '@travetto/transformer';
|
|
7
9
|
|
|
8
10
|
import { CompilerUtil } from './util';
|
|
9
11
|
import { CompilerState } from './state';
|
|
12
|
+
import type { CompilerLogEvent } from '../support/transpile';
|
|
10
13
|
|
|
11
14
|
export type TransformerProvider = {
|
|
12
15
|
init(checker: ts.TypeChecker): void;
|
|
@@ -14,36 +17,45 @@ export type TransformerProvider = {
|
|
|
14
17
|
};
|
|
15
18
|
|
|
16
19
|
type EmitError = Error | readonly ts.Diagnostic[];
|
|
17
|
-
type Emitter = (file: string, newProgram?: boolean) => EmitError | undefined
|
|
20
|
+
type Emitter = (file: string, newProgram?: boolean) => Promise<EmitError | undefined>;
|
|
18
21
|
type EmitEvent = { file: string, i: number, total: number, err?: EmitError };
|
|
19
22
|
|
|
23
|
+
function log(level: 'info' | 'debug', message: string, ...args: unknown[]): void {
|
|
24
|
+
if (process.send) {
|
|
25
|
+
const ev: CompilerLogEvent = [level, util.format(message, ...args)];
|
|
26
|
+
process.send(ev);
|
|
27
|
+
} else {
|
|
28
|
+
// eslint-disable-next-line no-console
|
|
29
|
+
console[level](message, ...args);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const debug = log.bind(null, 'debug');
|
|
34
|
+
const info = log.bind(null, 'info');
|
|
35
|
+
|
|
20
36
|
/**
|
|
21
37
|
* Compilation support
|
|
22
38
|
*/
|
|
23
39
|
export class Compiler {
|
|
24
40
|
|
|
25
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Run compiler as a main entry point
|
|
43
|
+
*/
|
|
44
|
+
static async main(): Promise<void> {
|
|
45
|
+
const [dirty, watch] = process.argv.slice(2);
|
|
46
|
+
install();
|
|
47
|
+
const dirtyFiles = (await fs.readFile(dirty, 'utf8')).split(/\n/).filter(x => !!x);
|
|
48
|
+
return new Compiler(dirtyFiles).run(watch === 'true');
|
|
49
|
+
}
|
|
50
|
+
|
|
26
51
|
#state: CompilerState;
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.#state = new CompilerState(
|
|
31
|
-
this.#
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
x => (x.files.support ?? [])
|
|
35
|
-
.filter(([f, type]) => type === 'ts' && f.startsWith('support/transformer.'))
|
|
36
|
-
.map(([f]) =>
|
|
37
|
-
path.resolve(
|
|
38
|
-
this.#state.manifest.workspacePath,
|
|
39
|
-
this.#state.manifest.compilerFolder,
|
|
40
|
-
x.output,
|
|
41
|
-
f.replace(/[.][tj]s$/, '.js')
|
|
42
|
-
)
|
|
43
|
-
)
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
return this;
|
|
52
|
+
#dirtyFiles: string[];
|
|
53
|
+
|
|
54
|
+
constructor(dirtyFiles: string[]) {
|
|
55
|
+
this.#state = new CompilerState(RootIndex.manifest);
|
|
56
|
+
this.#dirtyFiles = dirtyFiles[0] === '*' ?
|
|
57
|
+
this.#state.getAllFiles() :
|
|
58
|
+
dirtyFiles.map(f => this.#state.resolveInput(f));
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
get state(): CompilerState {
|
|
@@ -54,44 +66,27 @@ export class Compiler {
|
|
|
54
66
|
* Watches local modules
|
|
55
67
|
*/
|
|
56
68
|
async #watchLocalModules(emit: Emitter): Promise<() => Promise<void>> {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const err = emit(file, true);
|
|
69
|
+
const emitWithError = async (file: string): Promise<void> => {
|
|
70
|
+
const err = await emit(file, true);
|
|
60
71
|
if (err) {
|
|
61
|
-
|
|
72
|
+
info('Compilation Error', CompilerUtil.buildTranspileError(file, err));
|
|
62
73
|
} else {
|
|
63
|
-
|
|
74
|
+
info(`Compiled ${file.split('node_modules/')[1]}`);
|
|
64
75
|
}
|
|
65
76
|
};
|
|
66
77
|
const watcher = this.state.getWatcher({
|
|
67
|
-
create:
|
|
68
|
-
update:
|
|
78
|
+
create: emitWithError,
|
|
79
|
+
update: emitWithError,
|
|
69
80
|
delete: (outputFile) => fs.unlink(outputFile).catch(() => { })
|
|
70
81
|
});
|
|
71
|
-
return
|
|
82
|
+
return watchFolders(RootIndex.getLocalInputFolders(), watcher, {
|
|
83
|
+
filter: ev => ev.file.endsWith('.ts') || ev.file.endsWith('.js'),
|
|
84
|
+
ignore: ['node_modules']
|
|
85
|
+
});
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
async createTransformerProvider(): Promise<TransformerProvider> {
|
|
75
|
-
|
|
76
|
-
return TransformerManager.create(this.#transformers, this.state.manifest);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async writeRawFile(file: string, contents: string, mode?: string): Promise<void> {
|
|
80
|
-
const outFile = path.resolve(
|
|
81
|
-
this.#state.manifest.workspacePath,
|
|
82
|
-
this.#state.manifest.outputFolder,
|
|
83
|
-
file
|
|
84
|
-
);
|
|
85
|
-
await fs.mkdir(path.dirname(outFile), { recursive: true });
|
|
86
|
-
await fs.writeFile(outFile, contents, { encoding: 'utf8', mode });
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async outputInit(): Promise<void> {
|
|
90
|
-
// Write manifest
|
|
91
|
-
await this.writeRawFile(this.#state.manifest.manifestFile, JSON.stringify(this.state.manifest));
|
|
92
|
-
// TODO: This needs to be isolated, just like in the bootstrap
|
|
93
|
-
await this.writeRawFile('trv', '#!/bin/sh\nnode node_modules/@travetto/cli/support/main.cli.js $@\n', '755');
|
|
94
|
-
await this.writeRawFile('trv.cmd', 'node node_modules/@travetto/cli/support/main.cli.js %*\n', '755');
|
|
89
|
+
return TransformerManager.create(this.state.transformers);
|
|
95
90
|
}
|
|
96
91
|
|
|
97
92
|
/**
|
|
@@ -101,28 +96,27 @@ export class Compiler {
|
|
|
101
96
|
let program: ts.Program;
|
|
102
97
|
|
|
103
98
|
const transformers = await this.createTransformerProvider();
|
|
104
|
-
const options = await
|
|
105
|
-
path.resolve(
|
|
106
|
-
this.#state.manifest.workspacePath,
|
|
107
|
-
this.#state.manifest.outputFolder,
|
|
108
|
-
),
|
|
109
|
-
this.#bootTsconfig,
|
|
110
|
-
this.#state.manifest.workspacePath
|
|
111
|
-
);
|
|
99
|
+
const options = await this.state.getCompilerOptions();
|
|
112
100
|
const host = this.state.getCompilerHost(options);
|
|
113
101
|
|
|
114
|
-
const emit = (file: string, needsNewProgram = program === undefined): EmitError | undefined => {
|
|
115
|
-
if (needsNewProgram) {
|
|
116
|
-
program = ts.createProgram({ rootNames: this.#state.getAllFiles(), host, options, oldProgram: program });
|
|
117
|
-
transformers.init(program.getTypeChecker());
|
|
118
|
-
}
|
|
102
|
+
const emit = async (file: string, needsNewProgram = program === undefined): Promise<EmitError | undefined> => {
|
|
119
103
|
try {
|
|
120
|
-
|
|
121
|
-
program.
|
|
122
|
-
|
|
104
|
+
if (needsNewProgram) {
|
|
105
|
+
program = ts.createProgram({ rootNames: this.#state.getAllFiles(), host, options, oldProgram: program });
|
|
106
|
+
transformers.init(program.getTypeChecker());
|
|
107
|
+
}
|
|
108
|
+
if (file.endsWith('.json')) {
|
|
109
|
+
host.writeFile(file, host.readFile(file)!, false);
|
|
110
|
+
} else if (file.endsWith('.js')) {
|
|
111
|
+
host.writeFile(file, ts.transpile(host.readFile(file)!, options), false);
|
|
112
|
+
} else {
|
|
113
|
+
const result = program.emit(
|
|
114
|
+
program.getSourceFile(file)!, host.writeFile, undefined, false, transformers.get()
|
|
115
|
+
);
|
|
123
116
|
|
|
124
|
-
|
|
125
|
-
|
|
117
|
+
if (result.diagnostics?.length) {
|
|
118
|
+
return result.diagnostics;
|
|
119
|
+
}
|
|
126
120
|
}
|
|
127
121
|
} catch (err) {
|
|
128
122
|
if (err instanceof Error) {
|
|
@@ -141,45 +135,49 @@ export class Compiler {
|
|
|
141
135
|
*/
|
|
142
136
|
async * emit(files: string[], emitter: Emitter): AsyncIterable<EmitEvent> {
|
|
143
137
|
let i = 0;
|
|
144
|
-
const manifest = this.#state.manifest;
|
|
145
138
|
for (const file of files) {
|
|
146
|
-
const err = emitter(file);
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
.replace(manifest.compilerFolder, manifest.outputFolder);
|
|
150
|
-
yield { file: outputFile, i: i += 1, err, total: files.length };
|
|
139
|
+
const err = await emitter(file);
|
|
140
|
+
const imp = file.replace(/.*node_modules\//, '');
|
|
141
|
+
yield { file: imp, i: i += 1, err, total: files.length };
|
|
151
142
|
}
|
|
143
|
+
debug(`Compiled ${i} files`);
|
|
152
144
|
}
|
|
153
145
|
|
|
154
146
|
/**
|
|
155
147
|
* Run the compiler
|
|
156
148
|
*/
|
|
157
149
|
async run(watch?: boolean): Promise<void> {
|
|
158
|
-
|
|
150
|
+
debug('Compilation started');
|
|
151
|
+
|
|
159
152
|
const emitter = await this.getCompiler();
|
|
160
153
|
let failed = false;
|
|
161
154
|
|
|
155
|
+
debug('Compiler loaded');
|
|
156
|
+
|
|
162
157
|
const resolveEmittedFile = ({ file, total, i, err }: EmitEvent): TerminalProgressEvent => {
|
|
163
158
|
if (err) {
|
|
164
159
|
failed = true;
|
|
165
160
|
console.error(CompilerUtil.buildTranspileError(file, err));
|
|
166
161
|
}
|
|
167
|
-
return { idx: i, total, text: `Compiling [%idx/%total] -- ${file
|
|
162
|
+
return { idx: i, total, text: `Compiling [%idx/%total] -- ${file}` };
|
|
168
163
|
};
|
|
169
164
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
files = this.state.getAllFiles();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (files.length) {
|
|
176
|
-
await GlobalTerminal.trackProgress(this.emit(files, emitter), resolveEmittedFile, { position: 'bottom' });
|
|
165
|
+
if (this.#dirtyFiles.length) {
|
|
166
|
+
await GlobalTerminal.trackProgress(this.emit(this.#dirtyFiles, emitter), resolveEmittedFile, { position: 'bottom' });
|
|
177
167
|
if (failed) {
|
|
168
|
+
debug('Compilation failed');
|
|
178
169
|
process.exit(1);
|
|
170
|
+
} else {
|
|
171
|
+
debug('Compilation succeeded');
|
|
179
172
|
}
|
|
180
173
|
}
|
|
181
174
|
|
|
182
175
|
if (watch) {
|
|
176
|
+
if (!this.#dirtyFiles.length) {
|
|
177
|
+
const resolved = this.state.resolveInput(RootIndex.getModule('@travetto/manifest')!.files.src[0].sourceFile);
|
|
178
|
+
await emitter(resolved, true);
|
|
179
|
+
}
|
|
180
|
+
info('Watch is ready');
|
|
183
181
|
await this.#watchLocalModules(emitter);
|
|
184
182
|
await new Promise(r => setTimeout(r, 1000 * 60 * 60 * 24));
|
|
185
183
|
}
|
package/src/state.ts
CHANGED
|
@@ -1,36 +1,32 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
-
import {
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
path,
|
|
6
|
-
ManifestModuleUtil, ManifestDelta, ManifestModule,
|
|
7
|
-
ManifestModuleFileType, ManifestRoot, ManifestState
|
|
8
|
-
} from '@travetto/manifest';
|
|
4
|
+
import { path, ManifestModuleUtil, ManifestModule, ManifestModuleFileType, ManifestRoot, WatchEvent } from '@travetto/manifest';
|
|
9
5
|
|
|
10
|
-
import { CompilerUtil
|
|
6
|
+
import { CompilerUtil } from './util';
|
|
7
|
+
import { TranspileUtil } from '../support/transpile';
|
|
11
8
|
|
|
12
9
|
const validFile = (type: ManifestModuleFileType): boolean => type === 'ts' || type === 'package-json' || type === 'js';
|
|
13
10
|
|
|
14
11
|
export class CompilerState {
|
|
15
12
|
|
|
16
13
|
#inputFiles: Set<string>;
|
|
17
|
-
#relativeInputToSource = new Map<string, { source: string, module: ManifestModule }>();
|
|
18
14
|
#inputToSource = new Map<string, string>();
|
|
15
|
+
#stagedOutputToOutput = new Map<string, string>();
|
|
19
16
|
#inputToOutput = new Map<string, string | undefined>();
|
|
20
17
|
#inputDirectoryToSource = new Map<string, string>();
|
|
21
|
-
#sourceInputOutput = new Map<string, { input: string,
|
|
18
|
+
#sourceInputOutput = new Map<string, { source: string, input: string, stagedOutput?: string, output?: string, module: ManifestModule }>();
|
|
22
19
|
|
|
23
20
|
#sourceContents = new Map<string, string | undefined>();
|
|
24
21
|
#sourceFileObjects = new Map<string, ts.SourceFile>();
|
|
25
22
|
#sourceHashes = new Map<string, number>();
|
|
26
23
|
|
|
27
24
|
#manifest: ManifestRoot;
|
|
28
|
-
#delta: ManifestDelta;
|
|
29
25
|
#modules: ManifestModule[];
|
|
26
|
+
#transformers: string[];
|
|
30
27
|
|
|
31
|
-
constructor(
|
|
28
|
+
constructor(manifest: ManifestRoot) {
|
|
32
29
|
this.#manifest = manifest;
|
|
33
|
-
this.#delta = delta;
|
|
34
30
|
this.#modules = Object.values(this.#manifest.modules);
|
|
35
31
|
this.#inputFiles = new Set(this.#modules.flatMap(
|
|
36
32
|
x => [
|
|
@@ -46,14 +42,29 @@ export class CompilerState {
|
|
|
46
42
|
.map(([f]) => this.registerInput(x, f))
|
|
47
43
|
));
|
|
48
44
|
|
|
49
|
-
|
|
45
|
+
this.#transformers = this.#modules.flatMap(
|
|
46
|
+
x => (x.files.$transformer ?? []).map(([f]) =>
|
|
47
|
+
path.resolve(manifest.workspacePath, x.sourceFolder, f)
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async getCompilerOptions(): Promise<ts.CompilerOptions> {
|
|
53
|
+
return {
|
|
54
|
+
...await TranspileUtil.getCompilerOptions(this.#manifest),
|
|
55
|
+
outDir: this.#manifest.workspacePath, // Force to root
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
resolveInput(file: string): string {
|
|
60
|
+
return this.#sourceInputOutput.get(file)!.input;
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
registerInput(module: ManifestModule, moduleFile: string): string {
|
|
53
|
-
const relativeInput = `${module.
|
|
54
|
-
const sourceFile =
|
|
64
|
+
const relativeInput = `${module.outputFolder}/${moduleFile}`;
|
|
65
|
+
const sourceFile = path.toPosix(path.resolve(this.#manifest.workspacePath, module.sourceFolder, moduleFile));
|
|
55
66
|
const sourceFolder = path.dirname(sourceFile);
|
|
56
|
-
const inputFile = path.resolve(relativeInput);
|
|
67
|
+
const inputFile = path.resolve(this.#manifest.workspacePath, '##', relativeInput); // Ensure input is isolated
|
|
57
68
|
const inputFolder = path.dirname(inputFile);
|
|
58
69
|
const fileType = ManifestModuleUtil.getFileType(moduleFile);
|
|
59
70
|
const outputFile = fileType === 'typings' ?
|
|
@@ -61,25 +72,32 @@ export class CompilerState {
|
|
|
61
72
|
path.resolve(
|
|
62
73
|
this.#manifest.workspacePath,
|
|
63
74
|
this.#manifest.outputFolder,
|
|
64
|
-
|
|
75
|
+
CompilerUtil.inputToOutput(relativeInput)
|
|
65
76
|
);
|
|
66
77
|
|
|
78
|
+
// Rewrite stagedOutput to final output form
|
|
79
|
+
const stagedOutputFile = CompilerUtil.inputToOutput(inputFile);
|
|
80
|
+
|
|
67
81
|
this.#inputToSource.set(inputFile, sourceFile);
|
|
68
|
-
this.#sourceInputOutput.set(sourceFile, { input: inputFile, output: outputFile,
|
|
82
|
+
this.#sourceInputOutput.set(sourceFile, { source: sourceFile, input: inputFile, stagedOutput: stagedOutputFile, output: outputFile, module });
|
|
69
83
|
this.#inputToOutput.set(inputFile, outputFile);
|
|
70
84
|
this.#inputDirectoryToSource.set(inputFolder, sourceFolder);
|
|
71
|
-
|
|
85
|
+
|
|
86
|
+
if (stagedOutputFile) {
|
|
87
|
+
this.#stagedOutputToOutput.set(stagedOutputFile, outputFile!);
|
|
88
|
+
this.#stagedOutputToOutput.set(`${stagedOutputFile}.map`, `${outputFile!}.map`);
|
|
89
|
+
}
|
|
72
90
|
|
|
73
91
|
return inputFile;
|
|
74
92
|
}
|
|
75
93
|
|
|
76
94
|
removeInput(inputFile: string): void {
|
|
77
95
|
const source = this.#inputToSource.get(inputFile)!;
|
|
78
|
-
const {
|
|
96
|
+
const { stagedOutput } = this.#sourceInputOutput.get(source)!;
|
|
97
|
+
this.#stagedOutputToOutput.delete(stagedOutput!);
|
|
79
98
|
this.#sourceInputOutput.delete(source);
|
|
80
99
|
this.#inputToSource.delete(inputFile);
|
|
81
100
|
this.#inputToOutput.delete(inputFile);
|
|
82
|
-
this.#relativeInputToSource.delete(relativeInput);
|
|
83
101
|
this.#inputFiles.delete(inputFile);
|
|
84
102
|
}
|
|
85
103
|
|
|
@@ -88,51 +106,29 @@ export class CompilerState {
|
|
|
88
106
|
this.#sourceContents.delete(inputFile);
|
|
89
107
|
}
|
|
90
108
|
|
|
91
|
-
get manifest(): ManifestRoot {
|
|
92
|
-
return this.#manifest;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
109
|
get modules(): ManifestModule[] {
|
|
96
110
|
return this.#modules;
|
|
97
111
|
}
|
|
98
112
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const files: string[] = [];
|
|
102
|
-
for (const [modName, events] of Object.entries(this.#delta)) {
|
|
103
|
-
const mod = this.#manifest.modules[modName];
|
|
104
|
-
for (const { file } of events) {
|
|
105
|
-
const fileType = ManifestModuleUtil.getFileType(file);
|
|
106
|
-
if (validFile(fileType)) {
|
|
107
|
-
files.push(path.resolve(mod.output, file));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return files;
|
|
112
|
-
} else {
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
113
|
+
get transformers(): string[] {
|
|
114
|
+
return this.#transformers;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
getAllFiles(): string[] {
|
|
118
118
|
return [...this.#inputFiles];
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
resolveModuleFile(module: string, file: string): string {
|
|
122
|
-
return `${this.modules.find(m => m.name === module)!.source}/${file}`;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
121
|
// Build watcher
|
|
126
122
|
getWatcher(handler: {
|
|
127
123
|
create: (inputFile: string) => void;
|
|
128
124
|
update: (inputFile: string) => void;
|
|
129
125
|
delete: (outputFile: string) => void;
|
|
130
|
-
}): (ev:
|
|
131
|
-
const mods = Object.fromEntries(this.modules.map(x => [x.
|
|
132
|
-
return ({
|
|
126
|
+
}): (ev: WatchEvent, folder: string) => void {
|
|
127
|
+
const mods = Object.fromEntries(this.modules.map(x => [path.resolve(this.#manifest.workspacePath, x.sourceFolder), x]));
|
|
128
|
+
return ({ file: sourceFile, action }: WatchEvent, folder: string): void => {
|
|
133
129
|
const mod = mods[folder];
|
|
134
|
-
const moduleFile = sourceFile.
|
|
135
|
-
switch (
|
|
130
|
+
const moduleFile = sourceFile.includes(mod.sourceFolder) ? sourceFile.split(`${mod.sourceFolder}/`)[1] : sourceFile;
|
|
131
|
+
switch (action) {
|
|
136
132
|
case 'create': {
|
|
137
133
|
const fileType = ManifestModuleUtil.getFileType(moduleFile);
|
|
138
134
|
if (validFile(fileType)) {
|
|
@@ -165,16 +161,6 @@ export class CompilerState {
|
|
|
165
161
|
}
|
|
166
162
|
}
|
|
167
163
|
}
|
|
168
|
-
|
|
169
|
-
// Update manifest on every change
|
|
170
|
-
writeFile(
|
|
171
|
-
path.resolve(
|
|
172
|
-
this.#manifest.workspacePath,
|
|
173
|
-
this.#manifest.outputFolder,
|
|
174
|
-
this.#manifest.manifestFile
|
|
175
|
-
),
|
|
176
|
-
JSON.stringify(this.#manifest),
|
|
177
|
-
() => { });
|
|
178
164
|
};
|
|
179
165
|
}
|
|
180
166
|
|
|
@@ -202,14 +188,14 @@ export class CompilerState {
|
|
|
202
188
|
sourceFiles?: readonly ts.SourceFile[],
|
|
203
189
|
data?: ts.WriteFileCallbackData
|
|
204
190
|
): void => {
|
|
205
|
-
mkdirSync(path.dirname(outputFile), { recursive: true });
|
|
206
191
|
if (outputFile.endsWith('package.json')) {
|
|
207
|
-
text = CompilerUtil.rewritePackageJSON(this
|
|
192
|
+
text = CompilerUtil.rewritePackageJSON(this.#manifest, text, options);
|
|
208
193
|
} else if (!options.inlineSourceMap && options.sourceMap && outputFile.endsWith('.map')) {
|
|
209
|
-
text = CompilerUtil.rewriteSourceMap(text, f => this.#
|
|
194
|
+
text = CompilerUtil.rewriteSourceMap(this.#manifest.workspacePath, text, f => this.#sourceInputOutput.get(this.#inputToSource.get(f)!));
|
|
210
195
|
} else if (options.inlineSourceMap && CompilerUtil.isSourceMapUrlPosData(data)) {
|
|
211
|
-
text = CompilerUtil.rewriteInlineSourceMap(text, f => this.#
|
|
196
|
+
text = CompilerUtil.rewriteInlineSourceMap(this.#manifest.workspacePath, text, f => this.#sourceInputOutput.get(this.#inputToSource.get(f)!), data);
|
|
212
197
|
}
|
|
198
|
+
outputFile = this.#stagedOutputToOutput.get(outputFile) ?? outputFile;
|
|
213
199
|
ts.sys.writeFile(outputFile, text, bom);
|
|
214
200
|
},
|
|
215
201
|
getSourceFile: (inputFile: string, language: ts.ScriptTarget, __onErr?: unknown): ts.SourceFile => {
|