@travetto/compiler 8.0.0-alpha.20 → 8.0.0-alpha.22
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 +3 -3
- package/__index__.ts +4 -4
- package/bin/hook.js +4 -3
- package/bin/trvc-target.js +2 -1
- package/bin/trvc.js +2 -1
- package/package.json +4 -4
- package/src/common.ts +15 -9
- package/src/compiler.ts +16 -19
- package/src/event.ts +7 -5
- package/src/log.ts +57 -22
- package/src/queue.ts +4 -2
- package/src/server/client.ts +38 -24
- package/src/server/manager.ts +16 -11
- package/src/server/process-handle.ts +14 -10
- package/src/server/server.ts +43 -23
- package/src/state.ts +74 -41
- package/src/ts-proxy.ts +5 -3
- package/src/types.ts +22 -15
- package/src/util.ts +2 -4
- package/src/watch.ts +80 -68
- package/support/invoke.ts +36 -21
- package/tsconfig.trv.json +4 -12
package/src/watch.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
1
|
import { watch } from 'node:fs';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
3
|
|
|
4
4
|
import { ManifestFileUtil, ManifestModuleUtil, ManifestUtil, PACKAGE_MANAGERS, PackageUtil, path } from '@travetto/manifest';
|
|
5
5
|
|
|
6
|
-
import { CompilerReset, type CompilerWatchEvent, type CompileStateEntry } from './types.ts';
|
|
7
|
-
import type { CompilerState } from './state.ts';
|
|
8
|
-
|
|
9
|
-
import { AsyncQueue } from './queue.ts';
|
|
10
|
-
import { IpcLogger } from './log.ts';
|
|
11
6
|
import { EventUtil } from './event.ts';
|
|
7
|
+
import { IpcLogger } from './log.ts';
|
|
8
|
+
import { AsyncQueue } from './queue.ts';
|
|
9
|
+
import type { CompilerState } from './state.ts';
|
|
10
|
+
import { CompilerReset, type CompilerWatchEvent, type CompileStateEntry } from './types.ts';
|
|
12
11
|
|
|
13
12
|
const log = new IpcLogger({ level: 'debug' });
|
|
14
13
|
|
|
@@ -16,7 +15,7 @@ type CompilerWatchEventCandidate = Omit<CompilerWatchEvent, 'entry'> & { entry?:
|
|
|
16
15
|
|
|
17
16
|
export class CompilerWatcher {
|
|
18
17
|
#state: CompilerState;
|
|
19
|
-
#cleanup: Partial<Record<'tool' | 'workspace' | 'canary' | 'git', () =>
|
|
18
|
+
#cleanup: Partial<Record<'tool' | 'workspace' | 'canary' | 'git', () => void | Promise<void>>> = {};
|
|
20
19
|
#watchCanary: string = '.trv/canary.id';
|
|
21
20
|
#lastWorkspaceModified = Date.now();
|
|
22
21
|
#watchCanaryFrequency = 5;
|
|
@@ -27,22 +26,22 @@ export class CompilerWatcher {
|
|
|
27
26
|
this.#state = state;
|
|
28
27
|
this.#root = state.manifest.workspace.path;
|
|
29
28
|
this.#queue = new AsyncQueue(signal);
|
|
30
|
-
signal.addEventListener('abort', () =>
|
|
29
|
+
signal.addEventListener('abort', () =>
|
|
30
|
+
Object.values(this.#cleanup).forEach(fn => {
|
|
31
|
+
fn?.();
|
|
32
|
+
})
|
|
33
|
+
);
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
async #getWatchIgnores(): Promise<string[]> {
|
|
34
37
|
const pkg = PackageUtil.readPackage(this.#root);
|
|
35
|
-
const patterns = [
|
|
36
|
-
...pkg?.travetto?.build?.watchIgnores ?? [],
|
|
37
|
-
'**/node_modules',
|
|
38
|
-
'.*/**/node_modules'
|
|
39
|
-
];
|
|
38
|
+
const patterns = [...(pkg?.travetto?.build?.watchIgnores ?? []), '**/node_modules', '.*/**/node_modules'];
|
|
40
39
|
const ignores = new Set(['node_modules', '.git', this.#state.resolveOutputFile('.')]);
|
|
41
40
|
for (const item of patterns) {
|
|
42
41
|
if (item.includes('*')) {
|
|
43
42
|
for await (const sub of fs.glob(item, { cwd: this.#root })) {
|
|
44
43
|
if (sub.startsWith('node_modules')) {
|
|
45
|
-
|
|
44
|
+
// Continue
|
|
46
45
|
} else if (sub.endsWith('/node_modules')) {
|
|
47
46
|
ignores.add(sub.split('/node_modules')[0]);
|
|
48
47
|
} else {
|
|
@@ -53,7 +52,7 @@ export class CompilerWatcher {
|
|
|
53
52
|
ignores.add(item);
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
|
-
return [...ignores].toSorted().map(ignore => ignore.endsWith('/') ? ignore : `${ignore}/`);
|
|
55
|
+
return [...ignores].toSorted().map(ignore => (ignore.endsWith('/') ? ignore : `${ignore}/`));
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
#toCandidateEvent({ action, file }: Pick<CompilerWatchEvent, 'action' | 'file'>): CompilerWatchEventCandidate {
|
|
@@ -68,7 +67,7 @@ export class CompilerWatcher {
|
|
|
68
67
|
this.#state.removeSource(entry.sourceFile); // Ensure we remove it
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
return { entry, file: entry?.sourceFile ?? file, action, moduleFile: entry?.moduleFile
|
|
70
|
+
return { entry, file: entry?.sourceFile ?? file, action, moduleFile: entry?.moduleFile ?? '' };
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
#isValidFile(file: string): boolean {
|
|
@@ -97,8 +96,7 @@ export class CompilerWatcher {
|
|
|
97
96
|
|
|
98
97
|
async #updateManifestWithEvents(compilerEvents: CompilerWatchEvent[]): Promise<void> {
|
|
99
98
|
const eventsByModule = this.#state.manifestIndex.groupByLineage(
|
|
100
|
-
compilerEvents.map(event => ({ item: event, module: event.entry!.module.name }))
|
|
101
|
-
.filter(x => x.item.action !== 'update')
|
|
99
|
+
compilerEvents.map(event => ({ item: event, module: event.entry!.module.name })).filter(x => x.item.action !== 'update')
|
|
102
100
|
);
|
|
103
101
|
|
|
104
102
|
for (const [moduleName, events] of eventsByModule.entries()) {
|
|
@@ -116,66 +114,76 @@ export class CompilerWatcher {
|
|
|
116
114
|
async #listenWorkspace(): Promise<void> {
|
|
117
115
|
const lib = await import('@parcel/watcher');
|
|
118
116
|
const ignore = await this.#getWatchIgnores();
|
|
119
|
-
const packageFiles = new Set(
|
|
120
|
-
'package.json',
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
const packageFiles = new Set(
|
|
118
|
+
['package.json', ...PACKAGE_MANAGERS.flatMap(x => [x.workspaceFile!, x.lock].filter(Boolean))].map(file =>
|
|
119
|
+
path.resolve(this.#root, file)
|
|
120
|
+
)
|
|
121
|
+
);
|
|
123
122
|
|
|
124
123
|
log.debug('Ignore Globs', ignore);
|
|
125
124
|
log.debug('Watching', this.#root);
|
|
126
125
|
|
|
127
126
|
await this.#cleanup.workspace?.();
|
|
128
127
|
|
|
129
|
-
const listener = await lib.subscribe(
|
|
130
|
-
this.#
|
|
128
|
+
const listener = await lib.subscribe(
|
|
129
|
+
this.#root,
|
|
130
|
+
async (error, events) => {
|
|
131
|
+
this.#lastWorkspaceModified = Date.now();
|
|
131
132
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
133
|
+
try {
|
|
134
|
+
if (error) {
|
|
135
|
+
throw error instanceof Error ? error : new Error(`${error}`);
|
|
136
|
+
} else if (events.length > 25) {
|
|
137
|
+
throw new CompilerReset(`Large influx of file changes: ${events.length}`);
|
|
138
|
+
} else if (events.some(event => packageFiles.has(path.toPosix(event.path)))) {
|
|
139
|
+
throw new CompilerReset('Package information changed');
|
|
140
|
+
}
|
|
140
141
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
// One event per file set
|
|
143
|
+
const filesChanged = events
|
|
144
|
+
.map(event => ({ file: path.toPosix(event.path), action: event.type }))
|
|
145
|
+
.filter(event => this.#isValidFile(event.file));
|
|
145
146
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
if (filesChanged.length) {
|
|
148
|
+
EventUtil.sendEvent('file', { time: Date.now(), files: filesChanged });
|
|
149
|
+
}
|
|
149
150
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
if (filesChanged.some(item => this.#state.isCompilerFile(item.file))) {
|
|
152
|
+
throw new CompilerReset('Compiler has changed, restarting');
|
|
153
|
+
}
|
|
153
154
|
|
|
154
|
-
|
|
155
|
-
.map(event => this.#toCandidateEvent(event))
|
|
156
|
-
.filter(event => this.#isValidEvent(event));
|
|
155
|
+
const items = filesChanged.map(event => this.#toCandidateEvent(event)).filter(event => this.#isValidEvent(event));
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
if (items.length === 0) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
161
160
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
161
|
+
try {
|
|
162
|
+
await this.#updateManifestWithEvents(items);
|
|
163
|
+
} catch (manifestError) {
|
|
164
|
+
log.info('Restarting due to manifest rebuild failure', manifestError);
|
|
165
|
+
throw new CompilerReset(`Manifest rebuild failure: ${manifestError} `);
|
|
166
|
+
}
|
|
168
167
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
168
|
+
for (const item of items) {
|
|
169
|
+
this.#queue.add(item);
|
|
170
|
+
}
|
|
171
|
+
} catch (out) {
|
|
172
|
+
let error: Error;
|
|
173
|
+
if (out instanceof Error) {
|
|
174
|
+
if (out.message.includes('Events were dropped by the FSEvents client.')) {
|
|
175
|
+
error = new CompilerReset('FSEvents failure, requires restart');
|
|
176
|
+
} else {
|
|
177
|
+
error = out;
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
error = new Error(`${out}`);
|
|
181
|
+
}
|
|
182
|
+
return this.#queue.throw(error);
|
|
175
183
|
}
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
|
|
184
|
+
},
|
|
185
|
+
{ ignore }
|
|
186
|
+
);
|
|
179
187
|
|
|
180
188
|
this.#cleanup.workspace = (): Promise<void> => listener.unsubscribe();
|
|
181
189
|
}
|
|
@@ -183,10 +191,12 @@ export class CompilerWatcher {
|
|
|
183
191
|
async #listenToolFolder(): Promise<void> {
|
|
184
192
|
const build = this.#state.manifest.build;
|
|
185
193
|
const toolRootFolder = path.dirname(path.resolve(this.#root, build.outputFolder));
|
|
186
|
-
const toolFolders = new Set([toolRootFolder, build.typesFolder, build.outputFolder]
|
|
187
|
-
.map(folder => path.resolve(this.#root, folder)));
|
|
194
|
+
const toolFolders = new Set([toolRootFolder, build.typesFolder, build.outputFolder].map(folder => path.resolve(this.#root, folder)));
|
|
188
195
|
|
|
189
|
-
log.debug(
|
|
196
|
+
log.debug(
|
|
197
|
+
'Tooling Folders',
|
|
198
|
+
[...toolFolders].map(folder => folder.replace(`${this.#root}/`, ''))
|
|
199
|
+
);
|
|
190
200
|
|
|
191
201
|
await this.#cleanup.tool?.();
|
|
192
202
|
|
|
@@ -229,7 +239,9 @@ export class CompilerWatcher {
|
|
|
229
239
|
|
|
230
240
|
async #listenGitChanges(): Promise<void> {
|
|
231
241
|
const gitFolder = path.resolve(this.#root, '.git');
|
|
232
|
-
if (!await fs.stat(gitFolder, { throwIfNoEntry: false })) {
|
|
242
|
+
if (!(await fs.stat(gitFolder, { throwIfNoEntry: false }))) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
233
245
|
log.debug('Starting git canary');
|
|
234
246
|
const listener = watch(gitFolder, { encoding: 'utf8' }, async (event, file) => {
|
|
235
247
|
if (!file) {
|
|
@@ -251,4 +263,4 @@ export class CompilerWatcher {
|
|
|
251
263
|
}
|
|
252
264
|
return this.#queue[Symbol.asyncIterator]();
|
|
253
265
|
}
|
|
254
|
-
}
|
|
266
|
+
}
|
package/support/invoke.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
// @trv-no-transform
|
|
2
2
|
import { getManifestContext, ManifestUtil } from '@travetto/manifest';
|
|
3
3
|
|
|
4
|
-
import { Log } from '../src/log.ts';
|
|
5
|
-
import { CompilerManager } from '../src/server/manager.ts';
|
|
6
|
-
import { CompilerClient } from '../src/server/client.ts';
|
|
7
4
|
import { CommonUtil } from '../src/common.ts';
|
|
8
5
|
import { EventUtil } from '../src/event.ts';
|
|
6
|
+
import { Log } from '../src/log.ts';
|
|
7
|
+
import { CompilerClient } from '../src/server/client.ts';
|
|
8
|
+
import { CompilerManager } from '../src/server/manager.ts';
|
|
9
9
|
|
|
10
10
|
const hasColor = (process.stdout.isTTY && /^(0)*$/.test(process.env.NO_COLOR ?? '')) || /1\d*/.test(process.env.FORCE_COLOR ?? '');
|
|
11
|
-
const color =
|
|
12
|
-
|
|
11
|
+
const color =
|
|
12
|
+
(code: number) =>
|
|
13
|
+
(value: string): string =>
|
|
14
|
+
hasColor ? `\x1b[${code}m${value}\x1b[0m` : `${value}`;
|
|
15
|
+
const STYLE = { error: color(91), title: color(36), main: color(92), command: color(35), arg: color(37), description: color(33) };
|
|
13
16
|
|
|
14
17
|
const COMMANDS = {
|
|
15
18
|
start: { description: 'Run the compiler in watch mode' },
|
|
@@ -31,17 +34,26 @@ function showHelp(errorMessage?: string): void {
|
|
|
31
34
|
|
|
32
35
|
const commandWidth = Math.max(...PREPARED.map(config => config.commandLength));
|
|
33
36
|
|
|
34
|
-
console.log(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
'
|
|
40
|
-
' '
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
console.log(
|
|
38
|
+
[
|
|
39
|
+
...(errorMessage ? ['', STYLE.error(errorMessage)] : []),
|
|
40
|
+
'',
|
|
41
|
+
`${STYLE.main('trvc')} ${STYLE.command('[command]')}`,
|
|
42
|
+
'',
|
|
43
|
+
STYLE.title('Available Commands'),
|
|
44
|
+
...PREPARED.map(({ name, args, description, commandLength }) =>
|
|
45
|
+
[
|
|
46
|
+
'*',
|
|
47
|
+
STYLE.command(name),
|
|
48
|
+
...args.map(arg => STYLE.arg(arg)),
|
|
49
|
+
' '.repeat(commandWidth - commandLength),
|
|
50
|
+
'-',
|
|
51
|
+
STYLE.description(description)
|
|
52
|
+
].join(' ')
|
|
53
|
+
),
|
|
54
|
+
''
|
|
55
|
+
].join('\n')
|
|
56
|
+
);
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
const validateInputs = (value: string[]): value is [keyof typeof COMMANDS, ...string[]] => !!value.length && value[0] in COMMANDS;
|
|
@@ -51,7 +63,7 @@ const validateInputs = (value: string[]): value is [keyof typeof COMMANDS, ...st
|
|
|
51
63
|
*/
|
|
52
64
|
export async function invoke(...input: string[]): Promise<unknown> {
|
|
53
65
|
if (!validateInputs(input)) {
|
|
54
|
-
return showHelp(input[0] ? `Unknown trvc command: ${input[0]}` : undefined)
|
|
66
|
+
return showHelp(input[0] ? `Unknown trvc command: ${input[0]}` : undefined);
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
const [command, ...args] = input;
|
|
@@ -62,9 +74,12 @@ export async function invoke(...input: string[]): Promise<unknown> {
|
|
|
62
74
|
Log.root = ctx.workspace.path;
|
|
63
75
|
|
|
64
76
|
switch (command) {
|
|
65
|
-
case 'start':
|
|
66
|
-
|
|
67
|
-
case '
|
|
77
|
+
case 'start':
|
|
78
|
+
return CompilerManager.compile(ctx, client, { watch: true });
|
|
79
|
+
case 'build':
|
|
80
|
+
return CompilerManager.compile(ctx, client, { watch: false });
|
|
81
|
+
case 'restart':
|
|
82
|
+
return CompilerManager.compile(ctx, client, { watch: true, forceRestart: true });
|
|
68
83
|
case 'info': {
|
|
69
84
|
const info = await client.info();
|
|
70
85
|
return CommonUtil.writeStdout(2, info);
|
|
@@ -115,4 +130,4 @@ export async function invoke(...input: string[]): Promise<unknown> {
|
|
|
115
130
|
return import(importTarget);
|
|
116
131
|
}
|
|
117
132
|
}
|
|
118
|
-
}
|
|
133
|
+
}
|
package/tsconfig.trv.json
CHANGED
|
@@ -2,12 +2,8 @@
|
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"moduleResolution": "bundler",
|
|
4
4
|
"allowImportingTsExtensions": true,
|
|
5
|
-
"lib": [
|
|
6
|
-
|
|
7
|
-
],
|
|
8
|
-
"types": [
|
|
9
|
-
"node"
|
|
10
|
-
],
|
|
5
|
+
"lib": ["ESNext"],
|
|
6
|
+
"types": ["node"],
|
|
11
7
|
"jsx": "react-jsx",
|
|
12
8
|
"declaration": true,
|
|
13
9
|
"declarationMap": true,
|
|
@@ -28,10 +24,6 @@
|
|
|
28
24
|
"noEmit": true
|
|
29
25
|
},
|
|
30
26
|
"watchOptions": {
|
|
31
|
-
"excludeDirectories": [
|
|
32
|
-
"**/node_modules",
|
|
33
|
-
"**/.trv",
|
|
34
|
-
"**/.git",
|
|
35
|
-
]
|
|
27
|
+
"excludeDirectories": ["**/node_modules", "**/.trv", "**/.git"]
|
|
36
28
|
}
|
|
37
|
-
}
|
|
29
|
+
}
|