@travetto/compiler 4.0.0-rc.0 → 4.0.0-rc.1
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 +29 -29
- package/bin/common.js +41 -28
- package/bin/trvc.js +5 -6
- package/package.json +6 -6
- package/src/compiler.ts +68 -37
- package/src/event.ts +1 -1
- package/src/state.ts +39 -21
- package/src/types.ts +1 -1
- package/src/util.ts +4 -4
- package/src/watch.ts +101 -98
- package/support/entry.trvc.ts +47 -22
- package/support/log.ts +22 -24
- package/support/queue.ts +6 -0
- package/support/server/client.ts +59 -31
- package/support/server/process-handle.ts +57 -0
- package/support/server/runner.ts +16 -11
- package/support/server/server.ts +62 -45
- package/support/setup.ts +1 -1
- package/support/types.ts +1 -2
- package/support/util.ts +4 -2
- package/src/internal/watch-core.ts +0 -107
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ This module expands upon the [Typescript](https://typescriptlang.org) compiler,
|
|
|
21
21
|
Beyond the [Typescript](https://typescriptlang.org) compiler functionality, the module provides the primary entry point into the development process.
|
|
22
22
|
|
|
23
23
|
## CLI
|
|
24
|
-
The compiler cli, [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#
|
|
24
|
+
The compiler cli, [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L4) is the entry point for compilation-related operations. It has the ability to check for active builds, and ongoing watch operations to ensure only one process is building at a time. Within the framework, regardless of mono-repo or not, the compilation always targets the entire project. With the efficient caching behavior, this leads to generally a minimal overhead but allows for centralization of all operations.
|
|
25
25
|
|
|
26
26
|
The compiler cli supports the following operations:
|
|
27
27
|
* `start|watch` - Run the compiler in watch mode
|
|
@@ -39,35 +39,35 @@ In addition to the normal output, the compiler supports an environment variable
|
|
|
39
39
|
$ TRV_BUILD=debug trvc build
|
|
40
40
|
|
|
41
41
|
2029-03-14T04:00:00.618Z info [compiler-server] Starting server http://127.0.0.1:25539
|
|
42
|
-
2029-03-14T04:00:00.837Z debug [
|
|
42
|
+
2029-03-14T04:00:00.837Z debug [client.main ] Start Server
|
|
43
43
|
2029-03-14T04:00:01.510Z debug [event-stream ] Started event stream
|
|
44
44
|
2029-03-14T04:00:02.450Z debug [precompile ] Started
|
|
45
|
-
2029-03-14T04:00:02.762Z debug [
|
|
46
|
-
2029-03-14T04:00:02.947Z debug [
|
|
47
|
-
2029-03-14T04:00:03.093Z debug [
|
|
48
|
-
2029-03-14T04:00:04.003Z debug [precompile ]
|
|
49
|
-
2029-03-14T04:00:04.495Z debug [
|
|
50
|
-
2029-03-14T04:00:05.066Z debug [
|
|
51
|
-
2029-03-14T04:00:05.307Z debug [
|
|
52
|
-
2029-03-14T04:00:05.952Z debug [
|
|
53
|
-
2029-03-14T04:00:06.859Z debug [
|
|
54
|
-
2029-03-14T04:00:07.720Z debug [transformers ]
|
|
55
|
-
2029-03-14T04:00:08.179Z debug [transformers ] Skipped @travetto/
|
|
56
|
-
2029-03-14T04:00:08.588Z debug [transformers ] Skipped @travetto/
|
|
57
|
-
2029-03-14T04:00:09.493Z debug [transformers ]
|
|
58
|
-
2029-03-14T04:00:10.395Z debug [
|
|
59
|
-
2029-03-14T04:00:10.407Z debug [
|
|
60
|
-
2029-03-14T04:00:10.799Z debug [
|
|
61
|
-
2029-03-14T04:00:11.013Z debug [
|
|
62
|
-
2029-03-14T04:00:11.827Z debug [
|
|
63
|
-
2029-03-14T04:00:11.894Z
|
|
64
|
-
2029-03-14T04:00:12.133Z debug [
|
|
65
|
-
2029-03-14T04:00:13.123Z debug [
|
|
66
|
-
2029-03-14T04:00:14.014Z info [compiler-server]
|
|
67
|
-
2029-03-14T04:00:14.924Z debug [compiler-
|
|
68
|
-
2029-03-14T04:00:15.690Z
|
|
69
|
-
2029-03-14T04:00:15.865Z
|
|
70
|
-
2029-03-14T04:00:16.757Z debug [client.
|
|
45
|
+
2029-03-14T04:00:02.762Z debug [precompile ] Skipped @travetto/manifest
|
|
46
|
+
2029-03-14T04:00:02.947Z debug [precompile ] Skipped @travetto/transformer
|
|
47
|
+
2029-03-14T04:00:03.093Z debug [precompile ] Skipped @travetto/compiler
|
|
48
|
+
2029-03-14T04:00:04.003Z debug [precompile ] Completed
|
|
49
|
+
2029-03-14T04:00:04.495Z debug [manifest ] Started
|
|
50
|
+
2029-03-14T04:00:05.066Z debug [manifest ] Completed
|
|
51
|
+
2029-03-14T04:00:05.307Z debug [transformers ] Started
|
|
52
|
+
2029-03-14T04:00:05.952Z debug [transformers ] Skipped @travetto/base
|
|
53
|
+
2029-03-14T04:00:06.859Z debug [transformers ] Skipped @travetto/cli
|
|
54
|
+
2029-03-14T04:00:07.720Z debug [transformers ] Skipped @travetto/manifest
|
|
55
|
+
2029-03-14T04:00:08.179Z debug [transformers ] Skipped @travetto/registry
|
|
56
|
+
2029-03-14T04:00:08.588Z debug [transformers ] Skipped @travetto/schema
|
|
57
|
+
2029-03-14T04:00:09.493Z debug [transformers ] Completed
|
|
58
|
+
2029-03-14T04:00:10.395Z debug [delta ] Started
|
|
59
|
+
2029-03-14T04:00:10.407Z debug [delta ] Completed
|
|
60
|
+
2029-03-14T04:00:10.799Z debug [manifest ] Started
|
|
61
|
+
2029-03-14T04:00:11.013Z debug [manifest ] Wrote manifest @travetto-doc/compiler
|
|
62
|
+
2029-03-14T04:00:11.827Z debug [manifest ] Completed
|
|
63
|
+
2029-03-14T04:00:11.894Z info [compiler-server] State changed: compile-end
|
|
64
|
+
2029-03-14T04:00:12.133Z debug [compiler-exec ] Skipped
|
|
65
|
+
2029-03-14T04:00:13.123Z debug [event-stream ] Finished event stream
|
|
66
|
+
2029-03-14T04:00:14.014Z info [compiler-server] Closing down server
|
|
67
|
+
2029-03-14T04:00:14.924Z debug [compiler-server] Server close event
|
|
68
|
+
2029-03-14T04:00:15.690Z info [compiler-server] Closed down server
|
|
69
|
+
2029-03-14T04:00:15.865Z debug [compiler-server] Finished processing events
|
|
70
|
+
2029-03-14T04:00:16.757Z debug [client.main ] End Server
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
**Terminal: Sample trv output with default log level**
|
|
@@ -88,4 +88,4 @@ The compiler will move through the following phases on a given compilation execu
|
|
|
88
88
|
* `Invoke Compiler` - Run [Typescript](https://typescriptlang.org) compiler with the aforementioned enhancements
|
|
89
89
|
|
|
90
90
|
### Bootstrapping
|
|
91
|
-
Given that the framework is distributed as [Typescript](https://typescriptlang.org) only files, there is a bootstrapping problem that needs to be mitigated. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#
|
|
91
|
+
Given that the framework is distributed as [Typescript](https://typescriptlang.org) only files, there is a bootstrapping problem that needs to be mitigated. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L4) entrypoint, along with a small context utility in [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching") are the only [Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript) files needed to run the project. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L4) entry point will compile `@travetto/compiler/support/*` files as the set that is used at startup. These files are also accessible to the compiler as they get re-compiled after the fact.
|
package/bin/common.js
CHANGED
|
@@ -1,47 +1,60 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
import
|
|
2
|
+
import { statSync, readFileSync, writeFileSync, mkdirSync, readdirSync, existsSync, rmSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
|
|
5
5
|
import { getManifestContext } from '@travetto/manifest/bin/context.js';
|
|
6
6
|
|
|
7
7
|
/** @typedef {import('@travetto/manifest').ManifestContext} Ctx */
|
|
8
|
-
/** @typedef {(ctx: Ctx, content:string) => (string | Promise<string>)} Transform */
|
|
9
8
|
|
|
10
|
-
const stat = (/** @type {string}*/ file) => fs.stat(file).then(s => Math.max(s.mtimeMs, s.ctimeMs)).catch(() => 0);
|
|
11
9
|
const TS_EXT = /[.]tsx?$/;
|
|
12
10
|
|
|
13
|
-
const /** @type {
|
|
14
|
-
|
|
11
|
+
const getAge = (/** @type {{mtimeMs:number, ctimeMs:number}} */ st) => Math.max(st.mtimeMs, st.ctimeMs);
|
|
12
|
+
|
|
13
|
+
const getTarget = (/** @type {Ctx} */ ctx, file = '') => ({
|
|
14
|
+
dest: path.resolve(ctx.workspace.path, ctx.build.compilerFolder, 'node_modules', '@travetto/compiler', file).replace(TS_EXT, '.js'),
|
|
15
|
+
src: path.resolve(ctx.workspace.path, ctx.build.compilerModuleFolder, file),
|
|
16
|
+
async writeIfStale(/** @type {(text:string)=>(string|Promise<string>)}*/ transform) {
|
|
17
|
+
if (!existsSync(this.dest) || getAge(statSync(this.dest)) < getAge(statSync(this.src))) {
|
|
18
|
+
const text = readFileSync(this.src, 'utf8');
|
|
19
|
+
mkdirSync(path.dirname(this.dest), { recursive: true });
|
|
20
|
+
writeFileSync(this.dest, await transform(text), 'utf8');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const getTranspiler = async (/** @type {Ctx} */ ctx) => {
|
|
15
26
|
const ts = (await import('typescript')).default;
|
|
16
27
|
const module = ctx.workspace.type === 'module' ? ts.ModuleKind.ESNext : ts.ModuleKind.CommonJS;
|
|
17
|
-
return ts.transpile(content, { target: ts.ScriptTarget.ES2022, module, esModuleInterop: true, allowSyntheticDefaultImports: true });
|
|
28
|
+
return (content = '') => ts.transpile(content, { target: ts.ScriptTarget.ES2022, module, esModuleInterop: true, allowSyntheticDefaultImports: true });
|
|
18
29
|
};
|
|
19
30
|
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
/** @returns {Promise<import('@travetto/compiler/support/entry.trvc')>} */
|
|
32
|
+
async function imp(f = '') { try { return require(f); } catch (err) { return import(f); } }
|
|
22
33
|
|
|
23
|
-
async function
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
export async function getEntry() {
|
|
35
|
+
process.setSourceMapsEnabled(true); // Ensure source map during compilation/development
|
|
36
|
+
process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS ?? ''} --enable-source-maps`; // Ensure it passes to children
|
|
26
37
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const content = await fs.readFile(src, 'utf8');
|
|
30
|
-
await fs.writeFile(target, await transform(ctx, content), 'utf8');
|
|
31
|
-
}
|
|
32
|
-
return target;
|
|
33
|
-
}
|
|
38
|
+
const ctx = getManifestContext();
|
|
39
|
+
const target = getTarget.bind(null, ctx);
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const run = (/** @type {import('@travetto/compiler/support/entry.trvc')} */ mod) => mod.main(ctx);
|
|
41
|
+
// Setup Tsconfig
|
|
42
|
+
const tsconfig = path.resolve(ctx.workspace.path, 'tsconfig.json');
|
|
43
|
+
existsSync(tsconfig) || writeFileSync(tsconfig, JSON.stringify({ extends: '@travetto/compiler/tsconfig.trv.json' }), 'utf8');
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
// Compile support folder
|
|
46
|
+
await target('package.json').writeIfStale(text => JSON.stringify(Object.assign(JSON.parse(text), { type: ctx.workspace.type }), null, 2));
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
let transpile;
|
|
49
|
+
for (const file of readdirSync(target('support').src, { recursive: true, encoding: 'utf8' })) {
|
|
50
|
+
if (TS_EXT.test(file)) { await target(`support/${file}`).writeIfStale(async (text) => (transpile ??= await getTranspiler(ctx))(text)); }
|
|
51
|
+
}
|
|
44
52
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
// Load
|
|
54
|
+
try {
|
|
55
|
+
return await imp(target('support/entry.trvc.ts').dest).then(v => v.main(ctx));
|
|
56
|
+
} catch (err) {
|
|
57
|
+
rmSync(target('.').dest, { recursive: true, force: true });
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
}
|
package/bin/trvc.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS ?? ''} --enable-source-maps --disable-proto=delete`;
|
|
1
|
+
#!/usr/bin/env node
|
|
3
2
|
|
|
4
3
|
// @ts-check
|
|
5
4
|
import { getEntry } from './common.js';
|
|
@@ -26,7 +25,7 @@ getEntry().then(async (ops) => {
|
|
|
26
25
|
switch (op) {
|
|
27
26
|
case undefined:
|
|
28
27
|
case 'help': return console.log(`\n${help()}\n`);
|
|
29
|
-
case 'restart': return ops.
|
|
28
|
+
case 'restart': return ops.restart();
|
|
30
29
|
case 'stop': return ops.stop();
|
|
31
30
|
case 'info': return ops.info().then(v => console.log(JSON.stringify(v, null, 2)));
|
|
32
31
|
case 'event': return ops.events(args[0], v => {
|
|
@@ -36,9 +35,9 @@ getEntry().then(async (ops) => {
|
|
|
36
35
|
});
|
|
37
36
|
case 'clean': return ops.clean();
|
|
38
37
|
case 'manifest': return ops.manifest(args[0], flags.some(x => x === '--prod'));
|
|
39
|
-
case 'start':
|
|
40
|
-
case 'watch':
|
|
41
|
-
case 'build': return ops.
|
|
38
|
+
case 'start':
|
|
39
|
+
case 'watch': return ops.watch();
|
|
40
|
+
case 'build': return ops.build();
|
|
42
41
|
default: console.error(`Unknown trvc operation: ${op}\n`); return console.error(help());
|
|
43
42
|
}
|
|
44
43
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/compiler",
|
|
3
|
-
"version": "4.0.0-rc.
|
|
3
|
+
"version": "4.0.0-rc.1",
|
|
4
4
|
"description": "The compiler infrastructure for the Travetto framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compiler",
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
"directory": "module/compiler"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@parcel/watcher": "^2.
|
|
34
|
-
"@travetto/manifest": "^4.0.0-rc.
|
|
35
|
-
"@travetto/transformer": "^4.0.0-rc.
|
|
36
|
-
"@types/node": "^20.
|
|
33
|
+
"@parcel/watcher": "^2.4.0",
|
|
34
|
+
"@travetto/manifest": "^4.0.0-rc.1",
|
|
35
|
+
"@travetto/transformer": "^4.0.0-rc.1",
|
|
36
|
+
"@types/node": "^20.11.16"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@travetto/cli": "^4.0.0-rc.
|
|
39
|
+
"@travetto/cli": "^4.0.0-rc.1"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
42
42
|
"@travetto/cli": {
|
package/src/compiler.ts
CHANGED
|
@@ -33,18 +33,54 @@ export class Compiler {
|
|
|
33
33
|
#watch?: boolean;
|
|
34
34
|
#ctrl: AbortController;
|
|
35
35
|
#signal: AbortSignal;
|
|
36
|
+
#shuttingDown = false;
|
|
36
37
|
|
|
37
38
|
constructor(state: CompilerState, dirtyFiles: string[], watch?: boolean) {
|
|
38
39
|
this.#state = state;
|
|
39
40
|
this.#dirtyFiles = dirtyFiles[0] === '*' ?
|
|
40
41
|
this.#state.getAllFiles() :
|
|
41
|
-
dirtyFiles.map(f => this.#state.getBySource(f)!.
|
|
42
|
+
dirtyFiles.map(f => this.#state.getBySource(f)!.inputFile);
|
|
42
43
|
this.#watch = watch;
|
|
43
44
|
|
|
44
45
|
this.#ctrl = new AbortController();
|
|
45
46
|
this.#signal = this.#ctrl.signal;
|
|
46
47
|
setMaxListeners(1000, this.#signal);
|
|
47
|
-
process
|
|
48
|
+
process
|
|
49
|
+
.once('disconnect', () => this.#shutdown('manual'))
|
|
50
|
+
.on('message', ev => (ev === 'shutdown') && this.#shutdown('manual'));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#shutdown(mode: 'error' | 'manual' | 'complete' | 'reset', err?: Error): void {
|
|
54
|
+
if (this.#shuttingDown) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.#shuttingDown = true;
|
|
59
|
+
switch (mode) {
|
|
60
|
+
case 'manual': {
|
|
61
|
+
Log.error('Shutting down manually');
|
|
62
|
+
process.exitCode = 2;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case 'error': {
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
if (err) {
|
|
68
|
+
Log.error('Shutting down due to failure', err.message);
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case 'reset': {
|
|
73
|
+
Log.info('Triggering reset due to change in core files');
|
|
74
|
+
EventUtil.sendEvent('state', { state: 'reset' });
|
|
75
|
+
process.exitCode = 0;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// No longer listen to disconnect
|
|
80
|
+
process.removeAllListeners('disconnect');
|
|
81
|
+
process.removeAllListeners('message');
|
|
82
|
+
this.#ctrl.abort();
|
|
83
|
+
setTimeout(() => process.exit(), 1000).unref(); // Allow upto 1s to shutdown gracefully
|
|
48
84
|
}
|
|
49
85
|
|
|
50
86
|
/**
|
|
@@ -145,48 +181,43 @@ export class Compiler {
|
|
|
145
181
|
Log.info('Watch is ready');
|
|
146
182
|
|
|
147
183
|
EventUtil.sendEvent('state', { state: 'watch-start' });
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (action !== 'delete') {
|
|
158
|
-
const err = await emitter(entry.input, true);
|
|
159
|
-
if (err) {
|
|
160
|
-
Log.info('Compilation Error', CompilerUtil.buildTranspileError(entry.input, err));
|
|
184
|
+
try {
|
|
185
|
+
for await (const ev of new CompilerWatcher(this.#state, this.#signal).watchChanges()) {
|
|
186
|
+
if (ev.action !== 'delete') {
|
|
187
|
+
const err = await emitter(ev.entry.inputFile, true);
|
|
188
|
+
if (err) {
|
|
189
|
+
Log.info('Compilation Error', CompilerUtil.buildTranspileError(ev.entry.inputFile, err));
|
|
190
|
+
} else {
|
|
191
|
+
Log.info(`Compiled ${ev.entry.sourceFile} on ${ev.action}`);
|
|
192
|
+
}
|
|
161
193
|
} else {
|
|
162
|
-
|
|
194
|
+
if (ev.entry.outputFile) {
|
|
195
|
+
// Remove output
|
|
196
|
+
Log.info(`Removed ${ev.entry.sourceFile}, ${ev.entry.outputFile}`);
|
|
197
|
+
await fs.rm(ev.entry.outputFile, { force: true }); // Ensure output is deleted
|
|
198
|
+
}
|
|
163
199
|
}
|
|
164
|
-
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
200
|
+
|
|
201
|
+
// Send change events
|
|
202
|
+
EventUtil.sendEvent('change', {
|
|
203
|
+
action: ev.action,
|
|
204
|
+
time: Date.now(),
|
|
205
|
+
file: ev.file,
|
|
206
|
+
output: ev.entry.outputFile!,
|
|
207
|
+
module: ev.entry.module.name
|
|
208
|
+
});
|
|
168
209
|
}
|
|
210
|
+
EventUtil.sendEvent('state', { state: 'watch-end' });
|
|
169
211
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
file: ev.file,
|
|
175
|
-
folder: ev.folder,
|
|
176
|
-
output: ev.entry.output!,
|
|
177
|
-
module: ev.entry.module.name
|
|
178
|
-
});
|
|
212
|
+
} catch (err) {
|
|
213
|
+
if (err instanceof Error) {
|
|
214
|
+
this.#shutdown(err.message === 'RESET' ? 'reset' : 'error', err);
|
|
215
|
+
}
|
|
179
216
|
}
|
|
180
|
-
|
|
181
|
-
EventUtil.sendEvent('state', { state: 'watch-end' });
|
|
182
217
|
}
|
|
183
218
|
|
|
184
|
-
|
|
185
|
-
process.removeAllListeners('disconnect');
|
|
219
|
+
Log.debug('Compiler process shutdown');
|
|
186
220
|
|
|
187
|
-
|
|
188
|
-
process.exitCode = 2;
|
|
189
|
-
Log.error('Shutting down manually');
|
|
190
|
-
}
|
|
221
|
+
this.#shutdown('complete');
|
|
191
222
|
}
|
|
192
223
|
}
|
package/src/event.ts
CHANGED
|
@@ -2,6 +2,6 @@ import type { CompilerEvent, CompilerEventType } from '../support/types';
|
|
|
2
2
|
|
|
3
3
|
export class EventUtil {
|
|
4
4
|
static sendEvent<K extends CompilerEventType, T extends CompilerEvent & { type: K }>(type: K, payload: T['payload']): void {
|
|
5
|
-
process.connected && process.send!({ type, payload });
|
|
5
|
+
process.connected && process.send!({ type, payload }, undefined, { swallowErrors: true });
|
|
6
6
|
}
|
|
7
7
|
}
|
package/src/state.ts
CHANGED
|
@@ -3,9 +3,10 @@ import ts from 'typescript';
|
|
|
3
3
|
import { path, ManifestModuleUtil, ManifestModule, ManifestRoot, ManifestIndex } from '@travetto/manifest';
|
|
4
4
|
import { TransformerManager } from '@travetto/transformer';
|
|
5
5
|
|
|
6
|
+
import { CommonUtil } from '../support/util';
|
|
7
|
+
|
|
6
8
|
import { CompilerUtil } from './util';
|
|
7
9
|
import { CompileStateEntry } from './types';
|
|
8
|
-
import { CommonUtil } from '../support/util';
|
|
9
10
|
|
|
10
11
|
function folderMapper(root: string, prefix: string): { dir: string, translate: (val: string) => string } {
|
|
11
12
|
let matched: string = '~~';
|
|
@@ -26,7 +27,7 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
26
27
|
private constructor() { }
|
|
27
28
|
|
|
28
29
|
#rootDir: string;
|
|
29
|
-
#
|
|
30
|
+
#inputPathToSourcePath: (file: string) => string;
|
|
30
31
|
#outputPath: string;
|
|
31
32
|
#inputFiles = new Set<string>();
|
|
32
33
|
#inputDirectoryToSource = new Map<string, string>();
|
|
@@ -36,6 +37,7 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
36
37
|
|
|
37
38
|
#sourceContents = new Map<string, string | undefined>();
|
|
38
39
|
#sourceFileObjects = new Map<string, ts.SourceFile>();
|
|
40
|
+
#sourceHashes = new Map<string, number>();
|
|
39
41
|
|
|
40
42
|
#manifestIndex: ManifestIndex;
|
|
41
43
|
#manifest: ManifestRoot;
|
|
@@ -43,12 +45,16 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
43
45
|
#transformerManager: TransformerManager;
|
|
44
46
|
#compilerOptions: ts.CompilerOptions;
|
|
45
47
|
|
|
48
|
+
#readFile(inputFile: string): string | undefined {
|
|
49
|
+
return ts.sys.readFile(this.#inputToEntry.get(inputFile)?.sourceFile ?? this.#inputPathToSourcePath(inputFile));
|
|
50
|
+
}
|
|
51
|
+
|
|
46
52
|
async init(idx: ManifestIndex): Promise<this> {
|
|
47
53
|
this.#manifestIndex = idx;
|
|
48
54
|
this.#manifest = idx.manifest;
|
|
49
55
|
const mapper = folderMapper(this.#manifest.workspace.path, '##');
|
|
50
56
|
this.#rootDir = mapper.dir;
|
|
51
|
-
this.#
|
|
57
|
+
this.#inputPathToSourcePath = mapper.translate;
|
|
52
58
|
|
|
53
59
|
this.#outputPath = path.resolve(this.#manifest.workspace.path, this.#manifest.build.outputFolder);
|
|
54
60
|
this.#modules = Object.values(this.#manifest.modules);
|
|
@@ -95,7 +101,7 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
95
101
|
}
|
|
96
102
|
|
|
97
103
|
getArbitraryInputFile(): string {
|
|
98
|
-
return this.getBySource(this.#manifestIndex.getModule('@travetto/manifest')!.files.src[0].sourceFile)!.
|
|
104
|
+
return this.getBySource(this.#manifestIndex.getModule('@travetto/manifest')!.files.src[0].sourceFile)!.inputFile;
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
createProgram(oldProgram?: ts.Program): ts.Program {
|
|
@@ -107,9 +113,9 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
107
113
|
writeInputFile(program: ts.Program, inputFile: string): ts.EmitResult | undefined | void {
|
|
108
114
|
switch (ManifestModuleUtil.getFileType(inputFile)) {
|
|
109
115
|
case 'package-json':
|
|
110
|
-
return this.writeFile(this.#inputToEntry.get(inputFile)!.
|
|
116
|
+
return this.writeFile(this.#inputToEntry.get(inputFile)!.outputFile!, this.readFile(inputFile)!, false);
|
|
111
117
|
case 'js':
|
|
112
|
-
return this.writeFile(this.#inputToEntry.get(inputFile)!.
|
|
118
|
+
return this.writeFile(this.#inputToEntry.get(inputFile)!.outputFile!, ts.transpile(this.readFile(inputFile)!, this.#compilerOptions), false);
|
|
113
119
|
case 'ts':
|
|
114
120
|
return program.emit(
|
|
115
121
|
program.getSourceFile(inputFile)!,
|
|
@@ -134,7 +140,7 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
134
140
|
undefined :
|
|
135
141
|
path.resolve(this.#outputPath, ManifestModuleUtil.sourceToOutputExt(relativeInput));
|
|
136
142
|
|
|
137
|
-
const entry = {
|
|
143
|
+
const entry = { sourceFile, inputFile, outputFile, module };
|
|
138
144
|
|
|
139
145
|
this.#inputToEntry.set(inputFile, entry);
|
|
140
146
|
this.#sourceToEntry.set(sourceFile, entry);
|
|
@@ -145,23 +151,37 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
145
151
|
}
|
|
146
152
|
|
|
147
153
|
this.#inputFiles.add(inputFile);
|
|
148
|
-
|
|
154
|
+
this.#sourceHashes.set(sourceFile, -1); // Unknown
|
|
149
155
|
return entry;
|
|
150
156
|
}
|
|
151
157
|
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
checkIfSourceChanged(inputFile: string): boolean {
|
|
159
|
+
const contents = this.#readFile(inputFile);
|
|
160
|
+
const prevHash = this.#sourceHashes.get(inputFile);
|
|
161
|
+
if (!contents || (contents.length === 0 && prevHash)) {
|
|
162
|
+
return false; // Ignore empty file
|
|
156
163
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
164
|
+
const currentHash = CompilerUtil.naiveHash(contents);
|
|
165
|
+
const changed = prevHash !== currentHash;
|
|
166
|
+
if (changed) {
|
|
167
|
+
this.#sourceHashes.set(inputFile, currentHash);
|
|
168
|
+
this.#sourceContents.set(inputFile, contents);
|
|
169
|
+
this.#sourceFileObjects.delete(inputFile);
|
|
170
|
+
}
|
|
171
|
+
return changed;
|
|
160
172
|
}
|
|
161
173
|
|
|
162
|
-
|
|
174
|
+
removeInput(inputFile: string): void {
|
|
175
|
+
const { outputFile, sourceFile } = this.#inputToEntry.get(inputFile)!;
|
|
176
|
+
if (outputFile) {
|
|
177
|
+
this.#outputToEntry.delete(outputFile);
|
|
178
|
+
}
|
|
163
179
|
this.#sourceFileObjects.delete(inputFile);
|
|
164
180
|
this.#sourceContents.delete(inputFile);
|
|
181
|
+
this.#sourceHashes.delete(inputFile);
|
|
182
|
+
this.#sourceToEntry.delete(sourceFile);
|
|
183
|
+
this.#inputToEntry.delete(inputFile);
|
|
184
|
+
this.#inputFiles.delete(inputFile);
|
|
165
185
|
}
|
|
166
186
|
|
|
167
187
|
getAllFiles(): string[] {
|
|
@@ -177,11 +197,11 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
177
197
|
getDefaultLibLocation(): string { return path.dirname(ts.getDefaultLibFilePath(this.#compilerOptions)); }
|
|
178
198
|
|
|
179
199
|
fileExists(inputFile: string): boolean {
|
|
180
|
-
return this.#inputToEntry.has(inputFile) || ts.sys.fileExists(this.#
|
|
200
|
+
return this.#inputToEntry.has(inputFile) || ts.sys.fileExists(this.#inputPathToSourcePath(inputFile));
|
|
181
201
|
}
|
|
182
202
|
|
|
183
203
|
directoryExists(inputDir: string): boolean {
|
|
184
|
-
return this.#inputDirectoryToSource.has(inputDir) || ts.sys.directoryExists(this.#
|
|
204
|
+
return this.#inputDirectoryToSource.has(inputDir) || ts.sys.directoryExists(this.#inputPathToSourcePath(inputDir));
|
|
185
205
|
}
|
|
186
206
|
|
|
187
207
|
writeFile(
|
|
@@ -203,9 +223,7 @@ export class CompilerState implements ts.CompilerHost {
|
|
|
203
223
|
}
|
|
204
224
|
|
|
205
225
|
readFile(inputFile: string): string | undefined {
|
|
206
|
-
const res = this.#sourceContents.get(inputFile) ??
|
|
207
|
-
this.#inputToEntry.get(inputFile)?.source ?? this.#inputPathToSource(inputFile)
|
|
208
|
-
);
|
|
226
|
+
const res = this.#sourceContents.get(inputFile) ?? this.#readFile(inputFile);
|
|
209
227
|
this.#sourceContents.set(inputFile, res);
|
|
210
228
|
return res;
|
|
211
229
|
}
|
package/src/types.ts
CHANGED
|
@@ -5,4 +5,4 @@ import type { ManifestModule } from '@travetto/manifest';
|
|
|
5
5
|
export type CompileEmitError = Error | readonly ts.Diagnostic[];
|
|
6
6
|
export type CompileEmitter = (file: string, newProgram?: boolean) => Promise<CompileEmitError | undefined>;
|
|
7
7
|
export type CompileEmitEvent = { file: string, i: number, total: number, err?: CompileEmitError };
|
|
8
|
-
export type CompileStateEntry = {
|
|
8
|
+
export type CompileStateEntry = { sourceFile: string, inputFile: string, outputFile?: string, module: ManifestModule };
|
package/src/util.ts
CHANGED
|
@@ -2,7 +2,7 @@ import ts from 'typescript';
|
|
|
2
2
|
|
|
3
3
|
import { ManifestContext, ManifestModuleFileType, ManifestModuleUtil, ManifestRoot, Package, path } from '@travetto/manifest';
|
|
4
4
|
|
|
5
|
-
type OutputToSource = (outputFile: string) => ({
|
|
5
|
+
type OutputToSource = (outputFile: string) => ({ sourceFile: string } | undefined);
|
|
6
6
|
|
|
7
7
|
const nativeCwd = process.cwd();
|
|
8
8
|
|
|
@@ -32,11 +32,11 @@ export class CompilerUtil {
|
|
|
32
32
|
static rewriteSourceMap(ctx: ManifestContext, text: string, outputToSource: OutputToSource): string {
|
|
33
33
|
const data: { sourceRoot?: string, sources: string[] } = JSON.parse(text);
|
|
34
34
|
const output = ManifestModuleUtil.sourceToOutputExt(path.resolve(ctx.workspace.path, ctx.build.outputFolder, data.sources[0]));
|
|
35
|
-
const {
|
|
35
|
+
const { sourceFile } = outputToSource(output) ?? {};
|
|
36
36
|
|
|
37
|
-
if (
|
|
37
|
+
if (sourceFile) {
|
|
38
38
|
delete data.sourceRoot;
|
|
39
|
-
data.sources = [
|
|
39
|
+
data.sources = [sourceFile];
|
|
40
40
|
text = JSON.stringify(data);
|
|
41
41
|
}
|
|
42
42
|
return text;
|