@travetto/compiler 7.0.0-rc.0 → 7.0.0-rc.2
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/entry.common.js +26 -26
- package/bin/gen.context.mjs +6 -6
- package/bin/trvc.js +16 -16
- package/package.json +4 -4
- package/src/compiler.ts +41 -40
- package/src/state.ts +16 -16
- package/src/types.ts +1 -1
- package/src/util.ts +4 -4
- package/src/watch.ts +43 -43
- package/support/entry.main.ts +12 -12
- package/support/log.ts +30 -28
- package/support/queue.ts +5 -13
- package/support/server/client.ts +33 -33
- package/support/server/process-handle.ts +19 -19
- package/support/server/runner.ts +9 -8
- package/support/server/server.ts +46 -46
- package/support/setup.ts +33 -28
- package/support/types.ts +2 -2
- package/support/util.ts +5 -5
|
@@ -16,35 +16,35 @@ export class ProcessHandle {
|
|
|
16
16
|
this.#log = Log.scoped(`process-handle.${name}`);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
async
|
|
19
|
+
async writePidFile(processId: number): Promise<void> {
|
|
20
20
|
await fs.mkdir(path.dirname(this.#file), { recursive: true });
|
|
21
|
-
return fs.writeFile(this.#file, JSON.stringify(
|
|
21
|
+
return fs.writeFile(this.#file, JSON.stringify(processId), 'utf8');
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
getProcessId(): Promise<number | undefined> {
|
|
25
25
|
return fs.readFile(this.#file, 'utf8')
|
|
26
|
-
.then(
|
|
26
|
+
.then(processId => +processId > 0 ? +processId : undefined, () => undefined);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
async isRunning(): Promise<boolean> {
|
|
30
|
-
const
|
|
31
|
-
if (!
|
|
30
|
+
const processId = await this.getProcessId();
|
|
31
|
+
if (!processId) { return false; }
|
|
32
32
|
try {
|
|
33
|
-
process.kill(
|
|
34
|
-
this.#log.debug('Is running',
|
|
33
|
+
process.kill(processId, 0); // See if process is still running
|
|
34
|
+
this.#log.debug('Is running', processId);
|
|
35
35
|
return true;
|
|
36
36
|
} catch {
|
|
37
|
-
this.#log.debug('Is not running',
|
|
37
|
+
this.#log.debug('Is not running', processId);
|
|
38
38
|
}
|
|
39
39
|
return false; // Not running
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
async kill(): Promise<boolean> {
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
43
|
+
const processId = await this.getProcessId();
|
|
44
|
+
if (processId && await this.isRunning()) {
|
|
45
45
|
try {
|
|
46
|
-
this.#log.debug('Killing',
|
|
47
|
-
return process.kill(
|
|
46
|
+
this.#log.debug('Killing', processId);
|
|
47
|
+
return process.kill(processId);
|
|
48
48
|
} catch { }
|
|
49
49
|
}
|
|
50
50
|
return false;
|
|
@@ -52,12 +52,12 @@ export class ProcessHandle {
|
|
|
52
52
|
|
|
53
53
|
async ensureKilled(gracePeriod: number = 3000): Promise<boolean> {
|
|
54
54
|
const start = Date.now();
|
|
55
|
-
const
|
|
56
|
-
if (!
|
|
55
|
+
const processId = await this.getProcessId();
|
|
56
|
+
if (!processId) {
|
|
57
57
|
return false;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
this.#log.debug('Ensuring Killed',
|
|
60
|
+
this.#log.debug('Ensuring Killed', processId);
|
|
61
61
|
while ((Date.now() - start) < gracePeriod) { // Ensure its done
|
|
62
62
|
if (!await this.isRunning()) {
|
|
63
63
|
return true;
|
|
@@ -65,10 +65,10 @@ export class ProcessHandle {
|
|
|
65
65
|
await CommonUtil.blockingTimeout(100);
|
|
66
66
|
}
|
|
67
67
|
try {
|
|
68
|
-
this.#log.debug('Force Killing',
|
|
69
|
-
process.kill(
|
|
68
|
+
this.#log.debug('Force Killing', processId);
|
|
69
|
+
process.kill(processId); // Force kill
|
|
70
70
|
} catch { }
|
|
71
|
-
this.#log.debug('Did Kill', this.#file, !!
|
|
71
|
+
this.#log.debug('Did Kill', this.#file, !!processId);
|
|
72
72
|
return true;
|
|
73
73
|
}
|
|
74
74
|
}
|
package/support/server/runner.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { Log } from '../log.ts';
|
|
|
9
9
|
import { CommonUtil } from '../util.ts';
|
|
10
10
|
|
|
11
11
|
const log = Log.scoped('compiler-exec');
|
|
12
|
-
const isEvent = (
|
|
12
|
+
const isEvent = (value: unknown): value is CompilerEvent => !!value && typeof value === 'object' && 'type' in value;
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Running the compiler
|
|
@@ -31,13 +31,14 @@ export class CompilerRunner {
|
|
|
31
31
|
log.debug('Skipped');
|
|
32
32
|
return;
|
|
33
33
|
} else {
|
|
34
|
-
|
|
34
|
+
const changedList = changed.slice(0, 10).map(event => `${event.module}/${event.file}`);
|
|
35
|
+
log.debug(`Started watch=${watch} changed=${changedList}`);
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
const main = CommonUtil.resolveWorkspace(ctx, ctx.build.compilerFolder, 'node_modules', '@travetto/compiler/support/entry.compiler.js');
|
|
38
39
|
const deltaFile = CommonUtil.resolveWorkspace(ctx, ctx.build.compilerFolder, `manifest-delta-${Date.now()}.json`);
|
|
39
40
|
|
|
40
|
-
const changedFiles = changed[0]?.file === '*' ? ['*'] : changed.map(
|
|
41
|
+
const changedFiles = changed[0]?.file === '*' ? ['*'] : changed.map(event => event.sourceFile);
|
|
41
42
|
|
|
42
43
|
const queue = new AsyncQueue<CompilerEvent>();
|
|
43
44
|
|
|
@@ -45,7 +46,7 @@ export class CompilerRunner {
|
|
|
45
46
|
await CommonUtil.writeTextFile(deltaFile, changedFiles.join('\n'));
|
|
46
47
|
|
|
47
48
|
log.info('Launching compiler');
|
|
48
|
-
const
|
|
49
|
+
const subProcess = cp.spawn(process.argv0, [main, deltaFile, `${watch}`], {
|
|
49
50
|
env: {
|
|
50
51
|
...process.env,
|
|
51
52
|
TRV_MANIFEST: CommonUtil.resolveWorkspace(ctx, ctx.build.outputFolder, 'node_modules', ctx.workspace.name),
|
|
@@ -53,12 +54,12 @@ export class CompilerRunner {
|
|
|
53
54
|
detached: true,
|
|
54
55
|
stdio: ['pipe', 1, 2, 'ipc'],
|
|
55
56
|
})
|
|
56
|
-
.on('message',
|
|
57
|
+
.on('message', message => isEvent(message) && queue.add(message))
|
|
57
58
|
.on('exit', () => queue.close());
|
|
58
59
|
|
|
59
60
|
const kill = (): unknown => {
|
|
60
61
|
log.debug('Shutting down process');
|
|
61
|
-
return (
|
|
62
|
+
return (subProcess.connected ? subProcess.send('shutdown', () => subProcess.kill()) : subProcess.kill());
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
process.once('SIGINT', kill);
|
|
@@ -66,8 +67,8 @@ export class CompilerRunner {
|
|
|
66
67
|
|
|
67
68
|
yield* queue;
|
|
68
69
|
|
|
69
|
-
if (
|
|
70
|
-
log.error(`Terminated during compilation, code=${
|
|
70
|
+
if (subProcess.exitCode !== 0) {
|
|
71
|
+
log.error(`Terminated during compilation, code=${subProcess.exitCode}, killed=${subProcess.killed}`);
|
|
71
72
|
}
|
|
72
73
|
process.off('SIGINT', kill);
|
|
73
74
|
|
package/support/server/server.ts
CHANGED
|
@@ -37,8 +37,8 @@ export class CompilerServer {
|
|
|
37
37
|
state: 'startup',
|
|
38
38
|
iteration: Date.now(),
|
|
39
39
|
mode,
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
serverProcessId: process.pid,
|
|
41
|
+
compilerProcessId: -1,
|
|
42
42
|
path: ctx.workspace.path,
|
|
43
43
|
url: this.#url
|
|
44
44
|
};
|
|
@@ -47,7 +47,7 @@ export class CompilerServer {
|
|
|
47
47
|
keepAlive: true,
|
|
48
48
|
requestTimeout: 1000 * 60 * 60,
|
|
49
49
|
keepAliveTimeout: 1000 * 60 * 60,
|
|
50
|
-
}, (
|
|
50
|
+
}, (request, response) => this.#onRequest(request, response));
|
|
51
51
|
|
|
52
52
|
setMaxListeners(1000, this.signal);
|
|
53
53
|
}
|
|
@@ -60,21 +60,21 @@ export class CompilerServer {
|
|
|
60
60
|
return this.info.mode;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
isResetEvent(
|
|
64
|
-
return
|
|
63
|
+
isResetEvent(event: CompilerEvent): boolean {
|
|
64
|
+
return event.type === 'state' && event.payload.state === 'reset';
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
async #tryListen(attempt = 0): Promise<'ok' | 'running'> {
|
|
68
68
|
const output = await new Promise<'ok' | 'running' | 'retry'>((resolve, reject) => {
|
|
69
69
|
this.#server
|
|
70
70
|
.on('listening', () => resolve('ok'))
|
|
71
|
-
.on('error', async
|
|
72
|
-
if ('code' in
|
|
71
|
+
.on('error', async error => {
|
|
72
|
+
if ('code' in error && error.code === 'EADDRINUSE') {
|
|
73
73
|
const info = await this.#client.info();
|
|
74
74
|
resolve((info && info.mode === 'build' && this.mode === 'watch') ? 'retry' : 'running');
|
|
75
75
|
} else {
|
|
76
|
-
log.warn('Failed in running server',
|
|
77
|
-
reject(
|
|
76
|
+
log.warn('Failed in running server', error);
|
|
77
|
+
reject(error);
|
|
78
78
|
}
|
|
79
79
|
})
|
|
80
80
|
.on('close', () => log.debug('Server close event'));
|
|
@@ -92,48 +92,48 @@ export class CompilerServer {
|
|
|
92
92
|
await this.#client.waitForState(['closed'], 'Server closed', this.signal);
|
|
93
93
|
return this.#tryListen(attempt + 1);
|
|
94
94
|
} else if (output === 'ok') {
|
|
95
|
-
await this.#handle.server.
|
|
95
|
+
await this.#handle.server.writePidFile(this.info.serverProcessId);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
return output;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
#addListener(type: CompilerEventType | 'all',
|
|
102
|
-
|
|
101
|
+
#addListener(type: CompilerEventType | 'all', response: http.ServerResponse): void {
|
|
102
|
+
response.writeHead(200);
|
|
103
103
|
const id = `id_${Date.now()}_${Math.random()}`.replace('.', '1');
|
|
104
|
-
(this.#listeners[type] ??= {})[id] =
|
|
105
|
-
this.#listenersAll.add(
|
|
104
|
+
(this.#listeners[type] ??= {})[id] = response;
|
|
105
|
+
this.#listenersAll.add(response);
|
|
106
106
|
if (type === 'state' || type === 'all') { // Send on initial connect
|
|
107
107
|
this.#emitEvent({ type: 'state', payload: { state: this.info.state } }, id);
|
|
108
108
|
} else {
|
|
109
|
-
|
|
109
|
+
response.write('\n'); // Send at least one byte on listen
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
// Do not wait on it
|
|
113
|
-
|
|
113
|
+
response.on('close', () => {
|
|
114
114
|
delete this.#listeners[type]?.[id];
|
|
115
|
-
this.#listenersAll.delete(
|
|
115
|
+
this.#listenersAll.delete(response);
|
|
116
116
|
});
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
#emitEvent(
|
|
119
|
+
#emitEvent(event: CompilerEvent, to?: string): void {
|
|
120
120
|
if (this.#listeners.all) {
|
|
121
|
-
const
|
|
121
|
+
const eventText = JSON.stringify(event);
|
|
122
122
|
for (const [id, item] of Object.entries(this.#listeners.all)) {
|
|
123
123
|
if (item.closed || (to && id !== to)) {
|
|
124
124
|
continue;
|
|
125
125
|
}
|
|
126
|
-
item.write(
|
|
126
|
+
item.write(eventText);
|
|
127
127
|
item.write('\n');
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
-
if (this.#listeners[
|
|
131
|
-
const
|
|
132
|
-
for (const [id, item] of Object.entries(this.#listeners[
|
|
130
|
+
if (this.#listeners[event.type]) {
|
|
131
|
+
const eventText = JSON.stringify(event.payload);
|
|
132
|
+
for (const [id, item] of Object.entries(this.#listeners[event.type]!)) {
|
|
133
133
|
if (item.closed || (to && id !== to)) {
|
|
134
134
|
continue;
|
|
135
135
|
}
|
|
136
|
-
item.write(
|
|
136
|
+
item.write(eventText);
|
|
137
137
|
item.write('\n');
|
|
138
138
|
}
|
|
139
139
|
}
|
|
@@ -143,8 +143,8 @@ export class CompilerServer {
|
|
|
143
143
|
log.info('Server disconnect requested');
|
|
144
144
|
this.info.iteration = Date.now();
|
|
145
145
|
await CommonUtil.blockingTimeout(20);
|
|
146
|
-
for (const
|
|
147
|
-
try {
|
|
146
|
+
for (const listener of this.#listenersAll) {
|
|
147
|
+
try { listener.end(); } catch { }
|
|
148
148
|
}
|
|
149
149
|
this.#listeners = {}; // Ensure its empty
|
|
150
150
|
this.#listenersAll.clear();
|
|
@@ -152,17 +152,17 @@ export class CompilerServer {
|
|
|
152
152
|
|
|
153
153
|
async #clean(): Promise<{ clean: boolean }> {
|
|
154
154
|
await Promise.all([this.#ctx.build.compilerFolder, this.#ctx.build.outputFolder]
|
|
155
|
-
.map(
|
|
155
|
+
.map(folder => fs.rm(CommonUtil.resolveWorkspace(this.#ctx, folder), { recursive: true, force: true })));
|
|
156
156
|
return { clean: true };
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
/**
|
|
160
160
|
* Request handler
|
|
161
161
|
*/
|
|
162
|
-
async #onRequest(
|
|
163
|
-
|
|
162
|
+
async #onRequest(request: http.IncomingMessage, response: http.ServerResponse): Promise<void> {
|
|
163
|
+
response.setHeader('Content-Type', 'application/json');
|
|
164
164
|
|
|
165
|
-
const [, action, subAction] = new URL(`${this.#url}${
|
|
165
|
+
const [, action, subAction] = new URL(`${this.#url}${request.url}`).pathname.split('/');
|
|
166
166
|
|
|
167
167
|
let out: unknown;
|
|
168
168
|
let close = false;
|
|
@@ -170,7 +170,7 @@ export class CompilerServer {
|
|
|
170
170
|
case 'event': {
|
|
171
171
|
switch (subAction) {
|
|
172
172
|
case 'change': case 'log': case 'progress': case 'state': case 'all':
|
|
173
|
-
return this.#addListener(subAction,
|
|
173
|
+
return this.#addListener(subAction, response);
|
|
174
174
|
default: return;
|
|
175
175
|
}
|
|
176
176
|
}
|
|
@@ -179,7 +179,7 @@ export class CompilerServer {
|
|
|
179
179
|
case 'info':
|
|
180
180
|
default: out = this.info ?? {}; break;
|
|
181
181
|
}
|
|
182
|
-
|
|
182
|
+
response.end(JSON.stringify(out));
|
|
183
183
|
if (close) {
|
|
184
184
|
await this.close();
|
|
185
185
|
}
|
|
@@ -188,29 +188,29 @@ export class CompilerServer {
|
|
|
188
188
|
/**
|
|
189
189
|
* Process events
|
|
190
190
|
*/
|
|
191
|
-
async processEvents(
|
|
192
|
-
for await (const
|
|
193
|
-
if (
|
|
194
|
-
await Log.onProgressEvent(
|
|
191
|
+
async processEvents(input: (signal: AbortSignal) => AsyncIterable<CompilerEvent>): Promise<void> {
|
|
192
|
+
for await (const event of CommonUtil.restartableEvents(input, this.signal, this.isResetEvent)) {
|
|
193
|
+
if (event.type === 'progress') {
|
|
194
|
+
await Log.onProgressEvent(event.payload);
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
this.#emitEvent(
|
|
197
|
+
this.#emitEvent(event);
|
|
198
198
|
|
|
199
|
-
if (
|
|
200
|
-
this.info.state =
|
|
201
|
-
if (
|
|
202
|
-
if (this.info.mode === 'watch' && !this.info.
|
|
199
|
+
if (event.type === 'state') {
|
|
200
|
+
this.info.state = event.payload.state;
|
|
201
|
+
if (event.payload.state === 'init' && event.payload.extra && 'processId' in event.payload.extra && typeof event.payload.extra.processId === 'number') {
|
|
202
|
+
if (this.info.mode === 'watch' && !this.info.compilerProcessId) {
|
|
203
203
|
// Ensure we are killing in watch mode on first set
|
|
204
204
|
await this.#handle.compiler.kill();
|
|
205
205
|
}
|
|
206
|
-
this.info.
|
|
207
|
-
await this.#handle.compiler.
|
|
206
|
+
this.info.compilerProcessId = event.payload.extra.processId;
|
|
207
|
+
await this.#handle.compiler.writePidFile(this.info.compilerProcessId);
|
|
208
208
|
}
|
|
209
209
|
log.info(`State changed: ${this.info.state}`);
|
|
210
|
-
} else if (
|
|
211
|
-
log.render(
|
|
210
|
+
} else if (event.type === 'log') {
|
|
211
|
+
log.render(event.payload);
|
|
212
212
|
}
|
|
213
|
-
if (this.isResetEvent(
|
|
213
|
+
if (this.isResetEvent(event)) {
|
|
214
214
|
await this.#disconnectActive();
|
|
215
215
|
}
|
|
216
216
|
}
|
package/support/setup.ts
CHANGED
|
@@ -13,10 +13,10 @@ type ModFile = { input: string, output: string, stale: boolean };
|
|
|
13
13
|
const SOURCE_SEED = ['package.json', '__index__.ts', 'src', 'support', 'bin'];
|
|
14
14
|
const PRECOMPILE_MODS = ['@travetto/manifest', '@travetto/transformer', '@travetto/compiler'];
|
|
15
15
|
const RECENT_STAT = (stat: { ctimeMs: number, mtimeMs: number }): number => Math.max(stat.ctimeMs, stat.mtimeMs);
|
|
16
|
-
const
|
|
16
|
+
const REQUIRE = createRequire(path.resolve('node_modules')).resolve.bind(null);
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
const
|
|
18
|
+
const SOURCE_EXT_REGEX = /[.][cm]?[tj]s$/;
|
|
19
|
+
const BARE_IMPORT_REGEX = /^(@[^/]+[/])?[^.][^@/]+$/;
|
|
20
20
|
const OUTPUT_EXT = '.js';
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -30,15 +30,15 @@ export class CompilerSetup {
|
|
|
30
30
|
static #importManifest = (ctx: ManifestContext): Promise<
|
|
31
31
|
Pick<typeof import('@travetto/manifest'), 'ManifestDeltaUtil' | 'ManifestUtil'>
|
|
32
32
|
> => {
|
|
33
|
-
const all = ['util', 'delta'].map(
|
|
34
|
-
import(CommonUtil.resolveWorkspace(ctx, ctx.build.compilerFolder, 'node_modules', `@travetto/manifest/src/${
|
|
33
|
+
const all = ['util', 'delta'].map(file =>
|
|
34
|
+
import(CommonUtil.resolveWorkspace(ctx, ctx.build.compilerFolder, 'node_modules', `@travetto/manifest/src/${file}${OUTPUT_EXT}`))
|
|
35
35
|
);
|
|
36
|
-
return Promise.all(all).then(
|
|
36
|
+
return Promise.all(all).then(results => Object.assign({}, ...results));
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
/** Convert a file to a given ext */
|
|
40
40
|
static #sourceToExtension(sourceFile: string, ext: string): string {
|
|
41
|
-
return sourceFile.replace(
|
|
41
|
+
return sourceFile.replace(SOURCE_EXT_REGEX, ext);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -57,11 +57,11 @@ export class CompilerSetup {
|
|
|
57
57
|
const compilerOut = CommonUtil.resolveWorkspace(ctx, ctx.build.compilerFolder, 'node_modules');
|
|
58
58
|
|
|
59
59
|
const text = (await fs.readFile(sourceFile, 'utf8'))
|
|
60
|
-
.replace(/from ['"](([.]+|@travetto)[/][^']+)['"]/g, (_, clause,
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
return `from '${
|
|
60
|
+
.replace(/from ['"](([.]+|@travetto)[/][^']+)['"]/g, (_, clause, moduleName) => {
|
|
61
|
+
const root = this.#sourceToOutputExt(clause);
|
|
62
|
+
const suffix = root.endsWith(OUTPUT_EXT) ? '' : (BARE_IMPORT_REGEX.test(clause) ? `/__index__${OUTPUT_EXT}` : OUTPUT_EXT);
|
|
63
|
+
const prefix = moduleName === '@travetto' ? `${compilerOut}/` : '';
|
|
64
|
+
return `from '${prefix}${root}${suffix}'`;
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
const ts = (await import('typescript')).default;
|
|
@@ -75,7 +75,7 @@ export class CompilerSetup {
|
|
|
75
75
|
} else if (type === 'package-json') {
|
|
76
76
|
const pkg: Package = JSON.parse(await fs.readFile(sourceFile, 'utf8'));
|
|
77
77
|
const main = pkg.main ? this.#sourceToOutputExt(pkg.main) : undefined;
|
|
78
|
-
const files = pkg.files?.map(
|
|
78
|
+
const files = pkg.files?.map(file => this.#sourceToOutputExt(file));
|
|
79
79
|
|
|
80
80
|
const content = JSON.stringify({ ...pkg, main, type: ctx.workspace.type, files }, null, 2);
|
|
81
81
|
await CommonUtil.writeTextFile(outputFile, content);
|
|
@@ -86,10 +86,10 @@ export class CompilerSetup {
|
|
|
86
86
|
* Scan directory to find all project sources for comparison
|
|
87
87
|
*/
|
|
88
88
|
static async #getModuleSources(ctx: ManifestContext, module: string, seed: string[]): Promise<ModFile[]> {
|
|
89
|
-
const inputFolder = path.dirname(
|
|
89
|
+
const inputFolder = path.dirname(REQUIRE(`${module}/package.json`));
|
|
90
90
|
|
|
91
|
-
const folders = seed.filter(
|
|
92
|
-
const files = seed.filter(
|
|
91
|
+
const folders = seed.filter(folder => !/[.]/.test(folder)).map(folder => path.resolve(inputFolder, folder));
|
|
92
|
+
const files = seed.filter(file => /[.]/.test(file)).map(file => path.resolve(inputFolder, file));
|
|
93
93
|
|
|
94
94
|
while (folders.length) {
|
|
95
95
|
const sub = folders.pop();
|
|
@@ -134,18 +134,20 @@ export class CompilerSetup {
|
|
|
134
134
|
*/
|
|
135
135
|
static async #compileIfStale(ctx: ManifestContext, scope: string, mod: string, seed: string[]): Promise<string[]> {
|
|
136
136
|
const files = await this.#getModuleSources(ctx, mod, seed);
|
|
137
|
-
const changes = files.filter(
|
|
137
|
+
const changes = files.filter(file => file.stale).map(file => file.input);
|
|
138
138
|
const out: string[] = [];
|
|
139
139
|
|
|
140
140
|
try {
|
|
141
141
|
await Log.wrap(scope, async log => {
|
|
142
|
-
if (files.some(
|
|
142
|
+
if (files.some(file => file.stale)) {
|
|
143
143
|
log.debug('Starting', mod);
|
|
144
|
-
for (const file of files
|
|
145
|
-
|
|
144
|
+
for (const file of files) {
|
|
145
|
+
if (file.stale) {
|
|
146
|
+
await this.#transpileFile(ctx, file.input, file.output);
|
|
147
|
+
}
|
|
146
148
|
}
|
|
147
149
|
if (changes.length) {
|
|
148
|
-
out.push(...changes.map(
|
|
150
|
+
out.push(...changes.map(file => `${mod}/${file}`));
|
|
149
151
|
log.debug(`Source changed: ${changes.join(', ')}`, mod);
|
|
150
152
|
}
|
|
151
153
|
log.debug('Completed', mod);
|
|
@@ -153,8 +155,8 @@ export class CompilerSetup {
|
|
|
153
155
|
log.debug('Skipped', mod);
|
|
154
156
|
}
|
|
155
157
|
}, false);
|
|
156
|
-
} catch (
|
|
157
|
-
console.error(
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.error(error);
|
|
158
160
|
}
|
|
159
161
|
return out;
|
|
160
162
|
}
|
|
@@ -195,8 +197,11 @@ export class CompilerSetup {
|
|
|
195
197
|
ManifestUtil.buildManifest(ManifestUtil.getWorkspaceContext(ctx)));
|
|
196
198
|
|
|
197
199
|
await Log.wrap('transformers', async () => {
|
|
198
|
-
for (const mod of Object.values(manifest.modules)
|
|
199
|
-
|
|
200
|
+
for (const mod of Object.values(manifest.modules)) {
|
|
201
|
+
if (mod.files.$transformer?.length) {
|
|
202
|
+
changes += (await this.#compileIfStale(ctx, 'transformers', mod.name,
|
|
203
|
+
['package.json', ...mod.files.$transformer!.map(file => file[0])])).length;
|
|
204
|
+
}
|
|
200
205
|
}
|
|
201
206
|
});
|
|
202
207
|
|
|
@@ -224,18 +229,18 @@ export class CompilerSetup {
|
|
|
224
229
|
// Update all manifests when in mono repo
|
|
225
230
|
if (delta.length && ctx.workspace.mono) {
|
|
226
231
|
const names: string[] = [];
|
|
227
|
-
const mods = Object.values(manifest.modules).filter(
|
|
232
|
+
const mods = Object.values(manifest.modules).filter(mod => mod.workspace && mod.name !== ctx.workspace.name);
|
|
228
233
|
for (const mod of mods) {
|
|
229
234
|
const modCtx = ManifestUtil.getModuleContext(ctx, mod.sourceFolder, true);
|
|
230
235
|
const modManifest = await ManifestUtil.buildManifest(modCtx);
|
|
231
236
|
await ManifestUtil.writeManifest(modManifest);
|
|
232
237
|
names.push(mod.name);
|
|
233
238
|
}
|
|
234
|
-
log.debug(`Changes triggered ${delta.slice(0, 10).map(
|
|
239
|
+
log.debug(`Changes triggered ${delta.slice(0, 10).map(event => `${event.type}:${event.module}:${event.file}`)}`);
|
|
235
240
|
log.debug(`Rewrote monorepo manifests [changes=${delta.length}] ${names.slice(0, 10).join(', ')}`);
|
|
236
241
|
}
|
|
237
242
|
});
|
|
238
243
|
|
|
239
|
-
return delta.filter(
|
|
244
|
+
return delta.filter(event => event.type === 'added' || event.type === 'changed');
|
|
240
245
|
}
|
|
241
246
|
}
|
package/support/types.ts
CHANGED
|
@@ -17,8 +17,8 @@ export type CompilerEventType = CompilerEvent['type'];
|
|
|
17
17
|
|
|
18
18
|
export type CompilerServerInfo = {
|
|
19
19
|
path: string;
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
serverProcessId: number;
|
|
21
|
+
compilerProcessId: number;
|
|
22
22
|
state: CompilerStateType;
|
|
23
23
|
mode: CompilerMode;
|
|
24
24
|
iteration: number;
|
package/support/util.ts
CHANGED
|
@@ -29,7 +29,7 @@ export class CommonUtil {
|
|
|
29
29
|
/**
|
|
30
30
|
* Restartable Event Stream
|
|
31
31
|
*/
|
|
32
|
-
static async * restartableEvents<T>(
|
|
32
|
+
static async * restartableEvents<T>(input: (signal: AbortSignal) => AsyncIterable<T>, parent: AbortSignal, shouldRestart: (item: T) => boolean): AsyncIterable<T> {
|
|
33
33
|
const log = Log.scoped('event-stream');
|
|
34
34
|
outer: while (!parent.aborted) {
|
|
35
35
|
const controller = new AbortController();
|
|
@@ -38,14 +38,14 @@ export class CommonUtil {
|
|
|
38
38
|
const kill = (): void => controller.abort();
|
|
39
39
|
parent.addEventListener('abort', kill);
|
|
40
40
|
|
|
41
|
-
const comp =
|
|
41
|
+
const comp = input(controller.signal);
|
|
42
42
|
|
|
43
43
|
log.debug('Started event stream');
|
|
44
44
|
|
|
45
45
|
// Wait for all events, close at the end
|
|
46
|
-
for await (const
|
|
47
|
-
yield
|
|
48
|
-
if (shouldRestart(
|
|
46
|
+
for await (const event of comp) {
|
|
47
|
+
yield event;
|
|
48
|
+
if (shouldRestart(event)) {
|
|
49
49
|
log.debug('Restarting stream');
|
|
50
50
|
controller.abort(); // Ensure terminated of process
|
|
51
51
|
parent.removeEventListener('abort', kill);
|