@travetto/compiler 3.4.4 → 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.
@@ -1,53 +1,47 @@
1
- import http from 'http';
2
- import fs from 'fs/promises';
3
- import path from 'path';
1
+ import http from 'node:http';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { setMaxListeners } from 'node:events';
4
5
 
5
6
  import type { ManifestContext } from '@travetto/manifest';
6
7
 
7
- import type { CompilerMode, CompilerOp, CompilerServerEvent, CompilerServerEventType, CompilerServerInfo } from '../types';
8
+ import type { CompilerMode, CompilerProgressEvent, CompilerEvent, CompilerEventType, CompilerServerInfo } from '../types';
8
9
  import { LogUtil } from '../log';
9
- import { CompilerClientUtil } from './client';
10
+ import { CompilerClient } from './client';
10
11
  import { CommonUtil } from '../util';
12
+ import { ProcessHandle } from './process-handle';
11
13
 
12
- const log = LogUtil.log.bind(LogUtil, 'compiler-server');
14
+ const log = LogUtil.logger('compiler-server');
13
15
 
14
16
  /**
15
17
  * Compiler Server Class
16
18
  */
17
19
  export class CompilerServer {
18
20
 
19
- static readJSONRequest<T>(req: http.IncomingMessage): Promise<T> {
20
- return new Promise<T>((res, rej) => {
21
- const body: Buffer[] = [];
22
- req.on('data', (chunk) => body.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk));
23
- req.on('end', () => {
24
- try {
25
- res(JSON.parse(Buffer.concat(body).toString('utf8')));
26
- } catch (err) {
27
- rej(err);
28
- }
29
- });
30
- req.on('error', rej);
31
- });
32
- }
33
-
34
21
  #ctx: ManifestContext;
35
22
  #server: http.Server;
36
- #listeners: { res: http.ServerResponse, type: CompilerServerEventType }[] = [];
23
+ #listeners: { res: http.ServerResponse, type: CompilerEventType }[] = [];
37
24
  #shutdown = new AbortController();
38
25
  signal = this.#shutdown.signal;
39
26
  info: CompilerServerInfo;
27
+ #client: CompilerClient;
28
+ #url: string;
29
+ #handle: Record<'compiler' | 'server', ProcessHandle>;
40
30
 
41
- constructor(ctx: ManifestContext, op: CompilerOp) {
31
+ constructor(ctx: ManifestContext, mode: CompilerMode) {
42
32
  this.#ctx = ctx;
33
+ this.#client = new CompilerClient(ctx, LogUtil.logger('client.server'));
34
+ this.#url = this.#client.url;
35
+ this.#handle = { server: new ProcessHandle(ctx, 'server'), compiler: new ProcessHandle(ctx, 'compiler') };
36
+
43
37
  this.info = {
44
38
  state: 'startup',
45
39
  iteration: Date.now(),
46
- mode: op === 'run' ? 'build' : op,
40
+ mode,
47
41
  serverPid: process.pid,
48
42
  compilerPid: -1,
49
- path: ctx.workspacePath,
50
- url: ctx.compilerUrl
43
+ path: ctx.workspace.path,
44
+ url: this.#url
51
45
  };
52
46
 
53
47
  this.#server = http.createServer({
@@ -56,15 +50,14 @@ export class CompilerServer {
56
50
  keepAliveTimeout: 1000 * 60 * 60,
57
51
  }, (req, res) => this.#onRequest(req, res));
58
52
 
59
- // Connect
60
- process.on('SIGINT', () => this.#shutdown.abort());
53
+ setMaxListeners(1000, this.signal);
61
54
  }
62
55
 
63
56
  get mode(): CompilerMode {
64
57
  return this.info.mode;
65
58
  }
66
59
 
67
- isResetEvent(ev: CompilerServerEvent): boolean {
60
+ isResetEvent(ev: CompilerEvent): boolean {
68
61
  return ev.type === 'state' && ev.payload.state === 'reset';
69
62
  }
70
63
 
@@ -74,14 +67,16 @@ export class CompilerServer {
74
67
  .on('listening', () => resolve('ok'))
75
68
  .on('error', async err => {
76
69
  if ('code' in err && err.code === 'EADDRINUSE') {
77
- const info = await CompilerClientUtil.getServerInfo(this.#ctx);
70
+ const info = await this.#client.info();
78
71
  resolve((info && info.mode === 'build' && this.mode === 'watch') ? 'retry' : 'running');
79
72
  } else {
73
+ log('warn', 'Failed in running server', err);
80
74
  reject(err);
81
75
  }
82
- });
76
+ })
77
+ .on('close', () => log('debug', 'Server close event'));
83
78
 
84
- const url = new URL(this.#ctx.compilerUrl);
79
+ const url = new URL(this.#url);
85
80
  setTimeout(() => this.#server.listen(+url.port, url.hostname), 1); // Run async
86
81
  });
87
82
 
@@ -91,8 +86,10 @@ export class CompilerServer {
91
86
  }
92
87
  log('info', 'Waiting for build to finish, before retrying');
93
88
  // Let the server finish
94
- await CompilerClientUtil.waitForState(this.#ctx, ['close'], this.signal);
89
+ await this.#client.waitForState(['close'], 'Server closed', this.signal);
95
90
  return this.#tryListen(attempt + 1);
91
+ } else if (output === 'ok') {
92
+ await this.#handle.server.writePid(this.info.serverPid);
96
93
  }
97
94
 
98
95
  return output;
@@ -102,12 +99,16 @@ export class CompilerServer {
102
99
  res.writeHead(200);
103
100
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
104
101
  this.#listeners.push({ res, type: type as 'change' });
102
+ if (type === 'state') { // Send on initial connect
103
+ res.write(JSON.stringify({ state: this.info.state }));
104
+ }
105
+ res.write('\n'); // Send at least one byte on listen
105
106
  await new Promise(resolve => res.on('close', resolve));
106
107
  this.#listeners.splice(this.#listeners.findIndex(x => x.res === res), 1);
107
108
  res.end();
108
109
  }
109
110
 
110
- #emitEvent(ev: CompilerServerEvent): void {
111
+ #emitEvent(ev: CompilerEvent): void {
111
112
  const msg = `${JSON.stringify(ev.payload)}\n`;
112
113
  for (const el of this.#listeners) {
113
114
  if (!el.res.closed && el.type === ev.type) {
@@ -120,12 +121,14 @@ export class CompilerServer {
120
121
  log('info', 'Server disconnect requested');
121
122
  this.info.iteration = Date.now();
122
123
  await new Promise(r => setTimeout(r, 20));
123
- this.#server.closeAllConnections(); // Force reconnects
124
+ for (const el of this.#listeners) {
125
+ el.res.destroy();
126
+ }
124
127
  }
125
128
 
126
129
  async #clean(): Promise<{ clean: boolean }> {
127
- await Promise.all([this.#ctx.compilerFolder, this.#ctx.outputFolder]
128
- .map(f => fs.rm(path.resolve(this.#ctx.workspacePath, f), { recursive: true, force: true })));
130
+ await Promise.all([this.#ctx.build.compilerFolder, this.#ctx.build.outputFolder]
131
+ .map(f => fs.rm(path.resolve(this.#ctx.workspace.path, f), { recursive: true, force: true })));
129
132
  return { clean: true };
130
133
  }
131
134
 
@@ -135,16 +138,20 @@ export class CompilerServer {
135
138
  async #onRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
136
139
  res.setHeader('Content-Type', 'application/json');
137
140
 
138
- const [, action, subAction] = new URL(`${this.#ctx.compilerUrl}${req.url}`).pathname.split('/');
141
+ const [, action, subAction] = new URL(`${this.#url}${req.url}`).pathname.split('/');
139
142
 
140
143
  log('debug', 'Receive request', { action, subAction });
141
144
 
142
145
  let out: unknown;
143
146
  switch (action) {
144
- case 'send-event': await this.#emitEvent(await CompilerServer.readJSONRequest(req)); out = { received: true }; break;
145
147
  case 'event': return await this.#addListener(subAction, res);
146
- case 'stop': out = await this.close(); break;
147
148
  case 'clean': out = await this.#clean(); break;
149
+ case 'stop': {
150
+ // Must send immediately
151
+ res.end(JSON.stringify({ closing: true }));
152
+ await this.close();
153
+ break;
154
+ }
148
155
  case 'info':
149
156
  default: out = this.info ?? {}; break;
150
157
  }
@@ -154,19 +161,23 @@ export class CompilerServer {
154
161
  /**
155
162
  * Process events
156
163
  */
157
- async processEvents(src: (signal: AbortSignal) => AsyncIterable<CompilerServerEvent>): Promise<void> {
158
-
159
- CompilerClientUtil.streamLogs(this.#ctx, this.signal); // Send logs to stdout
160
-
164
+ async processEvents(src: (signal: AbortSignal) => AsyncIterable<CompilerEvent>): Promise<void> {
161
165
  for await (const ev of CommonUtil.restartableEvents(src, this.signal, this.isResetEvent)) {
166
+ if (ev.type === 'progress') {
167
+ await LogUtil.logProgress?.(ev.payload);
168
+ }
169
+
162
170
  this.#emitEvent(ev);
163
171
 
164
172
  if (ev.type === 'state') {
165
173
  this.info.state = ev.payload.state;
174
+ await this.#handle.compiler.writePid(this.info.compilerPid);
166
175
  if (ev.payload.state === 'init' && ev.payload.extra && 'pid' in ev.payload.extra && typeof ev.payload.extra.pid === 'number') {
167
176
  this.info.compilerPid = ev.payload.extra.pid;
168
177
  }
169
178
  log('info', `State changed: ${this.info.state}`);
179
+ } else if (ev.type === 'log') {
180
+ LogUtil.logEvent(ev.payload);
170
181
  }
171
182
  if (this.isResetEvent(ev)) {
172
183
  await this.#disconnectActive();
@@ -175,27 +186,44 @@ export class CompilerServer {
175
186
 
176
187
  // Terminate, after letting all remaining events emit
177
188
  await this.close();
189
+
190
+ log('debug', 'Finished processing events');
178
191
  }
179
192
 
180
193
  /**
181
194
  * Close server
182
195
  */
183
- async close(): Promise<unknown> {
184
- if (this.signal.aborted) {
185
- return;
196
+ async close(): Promise<void> {
197
+ log('info', 'Closing down server');
198
+
199
+ // If we are in a place where progress exists
200
+ if (this.info.state === 'compile-start') {
201
+ const cancel: CompilerProgressEvent = { complete: true, idx: 0, total: 0, message: 'Complete', operation: 'compile' };
202
+ LogUtil.logProgress?.(cancel);
203
+ this.#emitEvent({ type: 'progress', payload: cancel });
186
204
  }
187
205
 
188
- log('info', 'Closing down server');
189
- await new Promise(r => {
190
- this.#server.close(r);
191
- this.#emitEvent({ type: 'state', payload: { state: 'close' } });
192
- this.#server.unref();
193
- setImmediate(() => {
194
- this.#server.closeAllConnections();
195
- this.#shutdown.abort();
206
+ try {
207
+ await new Promise((resolve, reject) => {
208
+ setTimeout(reject, 2000).unref(); // 2s max wait
209
+ this.#server.close(resolve);
210
+ this.#emitEvent({ type: 'state', payload: { state: 'close' } });
211
+ setImmediate(() => {
212
+ this.#server.closeAllConnections();
213
+ this.#shutdown.abort();
214
+ });
196
215
  });
197
- });
198
- return { closing: true };
216
+ } catch { // Timeout or other error
217
+ // Force shutdown
218
+ this.#server.closeAllConnections();
219
+ if (this.info.compilerPid) { // Ensure its killed
220
+ try {
221
+ process.kill(this.info.compilerPid);
222
+ } catch { }
223
+ }
224
+ }
225
+
226
+ log('info', 'Closed down server');
199
227
  }
200
228
 
201
229
  /**
@@ -203,7 +231,7 @@ export class CompilerServer {
203
231
  */
204
232
  async listen(): Promise<CompilerServer | undefined> {
205
233
  const running = await this.#tryListen() === 'ok';
206
- log('info', running ? 'Starting server' : 'Server already running under a different process', this.#ctx.compilerUrl);
234
+ log('info', running ? 'Starting server' : 'Server already running under a different process', this.#url);
207
235
  return running ? this : undefined;
208
236
  }
209
237
  }
package/support/setup.ts CHANGED
@@ -1,16 +1,18 @@
1
- import path from 'path';
2
- import fs from 'fs/promises';
1
+ import path from 'node:path';
2
+ import { createRequire } from 'node:module';
3
+ import fs from 'node:fs/promises';
3
4
 
4
- import { type DeltaEvent, type ManifestContext, type ManifestRoot, Package } from '@travetto/manifest';
5
+ import { type DeltaEvent, type ManifestContext, type Package } from '@travetto/manifest';
5
6
 
6
7
  import { LogUtil } from './log';
7
8
  import { CommonUtil } from './util';
8
9
 
9
10
  type ModFile = { input: string, output: string, stale: boolean };
10
11
 
11
- const SOURCE_SEED = ['package.json', 'index.ts', '__index__.ts', 'src', 'support', 'bin'];
12
- const PRECOMPILE_MODS = ['@travetto/terminal', '@travetto/manifest', '@travetto/transformer', '@travetto/compiler'];
12
+ const SOURCE_SEED = ['package.json', '__index__.ts', 'src', 'support', 'bin'];
13
+ const PRECOMPILE_MODS = ['@travetto/manifest', '@travetto/transformer', '@travetto/compiler'];
13
14
  const RECENT_STAT = (stat: { ctimeMs: number, mtimeMs: number }): number => Math.max(stat.ctimeMs, stat.mtimeMs);
15
+ const REQ = createRequire(path.resolve('node_modules')).resolve.bind(null);
14
16
 
15
17
  /**
16
18
  * Compiler Setup Utilities
@@ -18,10 +20,16 @@ const RECENT_STAT = (stat: { ctimeMs: number, mtimeMs: number }): number => Math
18
20
  export class CompilerSetup {
19
21
 
20
22
  /**
21
- * Import a compiled manifest
23
+ * Import compiled manifest utilities
22
24
  */
23
- static #importManifest = (ctx: ManifestContext): Promise<typeof import('@travetto/manifest')> =>
24
- import(path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', '@travetto/manifest/__index__.js'));
25
+ static #importManifest = (ctx: ManifestContext): Promise<
26
+ Pick<typeof import('@travetto/manifest'), 'ManifestDeltaUtil' | 'ManifestUtil'>
27
+ > => {
28
+ const all = ['util', 'delta'].map(f =>
29
+ import(path.resolve(ctx.workspace.path, ctx.build.compilerFolder, 'node_modules', `@travetto/manifest/src/${f}.js`))
30
+ );
31
+ return Promise.all(all).then(props => Object.assign({}, ...props));
32
+ };
25
33
 
26
34
  /** Convert a file to a given ext */
27
35
  static #sourceToExtension(inputFile: string, ext: string): string {
@@ -41,7 +49,7 @@ export class CompilerSetup {
41
49
  static async #transpileFile(ctx: ManifestContext, inputFile: string, outputFile: string): Promise<void> {
42
50
  const type = CommonUtil.getFileType(inputFile);
43
51
  if (type === 'js' || type === 'ts') {
44
- const compilerOut = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules');
52
+ const compilerOut = path.resolve(ctx.workspace.path, ctx.build.compilerFolder, 'node_modules');
45
53
 
46
54
  const text = (await fs.readFile(inputFile, 'utf8'))
47
55
  .replace(/from '([.][^']+)'/g, (_, i) => `from '${i.replace(/[.]js$/, '')}.js'`)
@@ -59,7 +67,7 @@ export class CompilerSetup {
59
67
  const main = pkg.main ? this.#sourceToOutputExt(pkg.main) : undefined;
60
68
  const files = pkg.files?.map(x => this.#sourceToOutputExt(x));
61
69
 
62
- const content = JSON.stringify({ ...pkg, main, type: ctx.moduleType, files }, null, 2);
70
+ const content = JSON.stringify({ ...pkg, main, type: ctx.workspace.type, files }, null, 2);
63
71
  await CommonUtil.writeTextFile(outputFile, content);
64
72
  }
65
73
  }
@@ -68,9 +76,7 @@ export class CompilerSetup {
68
76
  * Scan directory to find all project sources for comparison
69
77
  */
70
78
  static async #getModuleSources(ctx: ManifestContext, module: string, seed: string[]): Promise<ModFile[]> {
71
- const inputFolder = (ctx.mainModule === module) ?
72
- process.cwd() :
73
- CommonUtil.resolveModuleFolder(module);
79
+ const inputFolder = path.dirname(REQ(`${module}/package.json`));
74
80
 
75
81
  const folders = seed.filter(x => !/[.]/.test(x)).map(x => path.resolve(inputFolder, x));
76
82
  const files = seed.filter(x => /[.]/.test(x)).map(x => path.resolve(inputFolder, x));
@@ -98,7 +104,7 @@ export class CompilerSetup {
98
104
  }
99
105
  }
100
106
 
101
- const outputFolder = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', module);
107
+ const outputFolder = path.resolve(ctx.workspace.path, ctx.build.compilerFolder, 'node_modules', module);
102
108
  const out: ModFile[] = [];
103
109
  for (const input of files) {
104
110
  const output = this.#sourceToOutputExt(input.replace(inputFolder, outputFolder));
@@ -162,25 +168,21 @@ export class CompilerSetup {
162
168
  }
163
169
 
164
170
  /**
165
- * Sets up compiler, and produces a manifest and set of changes that need to be processed
171
+ * Sets up compiler, and produces a set of changes that need to be processed
166
172
  */
167
- static async setup(ctx: ManifestContext): Promise<{ manifest: ManifestRoot, changed: DeltaEvent[] }> {
173
+ static async setup(ctx: ManifestContext): Promise<DeltaEvent[]> {
168
174
  let changes = 0;
169
175
 
170
176
  await LogUtil.withLogger('precompile', async () => {
171
177
  for (const mod of PRECOMPILE_MODS) {
172
- const count = (await this.#compileIfStale(ctx, 'precompile', mod, SOURCE_SEED)).length;
173
- if (mod !== '@travetto/terminal') {
174
- changes += count;
175
- }
178
+ changes += (await this.#compileIfStale(ctx, 'precompile', mod, SOURCE_SEED)).length;
176
179
  }
177
180
  });
178
181
 
179
- const { ManifestUtil, ManifestDeltaUtil, PackageUtil } = await this.#importManifest(ctx);
180
-
181
- PackageUtil.clearCache();
182
+ const { ManifestUtil, ManifestDeltaUtil } = await this.#importManifest(ctx);
182
183
 
183
- const manifest = await LogUtil.withLogger('manifest', () => ManifestUtil.buildManifest(ctx));
184
+ const manifest = await LogUtil.withLogger('manifest', () =>
185
+ ManifestUtil.buildManifest(ManifestUtil.getWorkspaceContext(ctx)));
184
186
 
185
187
  await LogUtil.withLogger('transformers', async () => {
186
188
  for (const mod of Object.values(manifest.modules).filter(m => m.files.$transformer?.length)) {
@@ -191,30 +193,32 @@ export class CompilerSetup {
191
193
  const delta = await LogUtil.withLogger('delta', async log => {
192
194
  if (changes) {
193
195
  log('debug', 'Skipping, everything changed');
194
- return [{ type: 'changed', file: '*', module: ctx.mainModule } as const];
196
+ return [{ type: 'changed', file: '*', module: ctx.workspace.name, sourceFile: '' } as const];
195
197
  } else {
196
- return ManifestDeltaUtil.produceDelta(ctx, manifest);
198
+ return ManifestDeltaUtil.produceDelta(manifest);
197
199
  }
198
200
  });
199
201
 
200
202
  if (changes) {
201
203
  await LogUtil.withLogger('reset', async log => {
202
- await fs.rm(path.resolve(ctx.workspacePath, ctx.outputFolder), { recursive: true, force: true });
204
+ await fs.rm(path.resolve(ctx.workspace.path, ctx.build.outputFolder), { recursive: true, force: true });
203
205
  log('info', 'Clearing output due to compiler changes');
204
206
  }, false);
205
207
  }
206
208
 
207
209
  // Write manifest
208
210
  await LogUtil.withLogger('manifest', async log => {
209
- await ManifestUtil.writeManifest(ctx, manifest);
210
- log('debug', `Wrote manifest ${ctx.mainModule}`);
211
+ await ManifestUtil.writeManifest(manifest);
212
+ log('debug', `Wrote manifest ${ctx.workspace.name}`);
211
213
 
212
- // Update all manifests
213
- if (delta.length && ctx.monoRepo && !ctx.mainFolder) {
214
+ // Update all manifests when in mono repo
215
+ if (delta.length && ctx.workspace.mono) {
214
216
  const names: string[] = [];
215
- const mods = Object.values(manifest.modules).filter(x => x.local && x.name !== ctx.mainModule);
217
+ const mods = Object.values(manifest.modules).filter(x => x.workspace && x.name !== ctx.workspace.name);
216
218
  for (const mod of mods) {
217
- await ManifestUtil.rewriteManifest(path.resolve(ctx.workspacePath, mod.sourceFolder));
219
+ const modCtx = ManifestUtil.getModuleContext(ctx, mod.sourceFolder);
220
+ const modManifest = await ManifestUtil.buildManifest(modCtx);
221
+ await ManifestUtil.writeManifest(modManifest);
218
222
  names.push(mod.name);
219
223
  }
220
224
  log('debug', `Changes triggered ${delta.slice(0, 10).map(x => `${x.type}:${x.module}:${x.file}`)}`);
@@ -222,8 +226,6 @@ export class CompilerSetup {
222
226
  }
223
227
  });
224
228
 
225
- const changed = delta.filter(x => x.type === 'added' || x.type === 'changed');
226
-
227
- return { manifest, changed };
229
+ return delta.filter(x => x.type === 'added' || x.type === 'changed');
228
230
  }
229
231
  }
package/support/types.ts CHANGED
@@ -1,20 +1,19 @@
1
1
  export type CompilerMode = 'build' | 'watch';
2
- export type CompilerOp = CompilerMode | 'run';
3
2
 
4
3
  export type CompilerStateType = 'startup' | 'init' | 'compile-start' | 'compile-end' | 'watch-start' | 'watch-end' | 'reset' | 'close';
5
- export type CompilerChangeEvent = { file: string, action: 'create' | 'update' | 'delete', folder: string, output: string, module: string, time: number };
4
+ export type CompilerChangeEvent = { file: string, action: 'create' | 'update' | 'delete', output: string, module: string, time: number };
6
5
  export type CompilerLogLevel = 'info' | 'debug' | 'warn' | 'error';
7
6
  export type CompilerLogEvent = { level: CompilerLogLevel, message: string, time: number, args?: unknown[], scope?: string };
8
7
  export type CompilerProgressEvent = { idx: number, total: number, message: string, operation: 'compile', complete?: boolean };
9
8
  export type CompilerStateEvent = { state: CompilerStateType, extra?: Record<string, unknown> };
10
9
 
11
- export type CompilerServerEvent =
10
+ export type CompilerEvent =
12
11
  { type: 'change', payload: CompilerChangeEvent } |
13
12
  { type: 'log', payload: CompilerLogEvent } |
14
13
  { type: 'progress', payload: CompilerProgressEvent } |
15
14
  { type: 'state', payload: CompilerStateEvent };
16
15
 
17
- export type CompilerServerEventType = CompilerServerEvent['type'];
16
+ export type CompilerEventType = CompilerEvent['type'];
18
17
 
19
18
  export type CompilerServerInfo = {
20
19
  path: string;
package/support/util.ts CHANGED
@@ -1,50 +1,42 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
3
- import { createRequire } from 'module';
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { setMaxListeners } from 'node:events';
4
4
 
5
5
  import type { ManifestContext } from '@travetto/manifest';
6
6
 
7
7
  import { LogUtil } from './log';
8
8
 
9
9
  const OPT_CACHE: Record<string, import('typescript').CompilerOptions> = {};
10
- const SRC_REQ = createRequire(path.resolve('node_modules'));
11
10
 
12
11
  export class CommonUtil {
13
12
  /**
14
13
  * Returns the compiler options
15
14
  */
16
15
  static async getCompilerOptions(ctx: ManifestContext): Promise<{}> {
17
- if (!(ctx.workspacePath in OPT_CACHE)) {
18
- let tsconfig = path.resolve(ctx.workspacePath, 'tsconfig.json');
16
+ if (!(ctx.workspace.path in OPT_CACHE)) {
17
+ let tsconfig = path.resolve(ctx.workspace.path, 'tsconfig.json');
19
18
 
20
19
  if (!await fs.stat(tsconfig).then(_ => true, _ => false)) {
21
- tsconfig = SRC_REQ.resolve('@travetto/compiler/tsconfig.trv.json');
20
+ tsconfig = path.resolve(ctx.workspace.path, ctx.build.compilerModuleFolder, 'tsconfig.trv.json');
22
21
  }
23
22
 
24
23
  const ts = (await import('typescript')).default;
25
24
 
26
25
  const { options } = ts.parseJsonSourceFileConfigFileContent(
27
- ts.readJsonConfigFile(tsconfig, ts.sys.readFile), ts.sys, ctx.workspacePath
26
+ ts.readJsonConfigFile(tsconfig, ts.sys.readFile), ts.sys, ctx.workspace.path
28
27
  );
29
28
 
30
- OPT_CACHE[ctx.workspacePath] = {
29
+ OPT_CACHE[ctx.workspace.path] = {
31
30
  ...options,
32
31
  allowJs: true,
33
32
  resolveJsonModule: true,
34
- sourceRoot: ctx.workspacePath,
35
- rootDir: ctx.workspacePath,
36
- outDir: path.resolve(ctx.workspacePath),
37
- module: ctx.moduleType === 'commonjs' ? ts.ModuleKind.CommonJS : ts.ModuleKind.ESNext,
33
+ sourceRoot: ctx.workspace.path,
34
+ rootDir: ctx.workspace.path,
35
+ outDir: path.resolve(ctx.workspace.path),
36
+ module: ctx.workspace.type === 'commonjs' ? ts.ModuleKind.CommonJS : ts.ModuleKind.ESNext,
38
37
  };
39
38
  }
40
- return OPT_CACHE[ctx.workspacePath];
41
- }
42
-
43
- /**
44
- * Resolve module location
45
- */
46
- static resolveModuleFolder(mod: string): string {
47
- return path.dirname(SRC_REQ.resolve(`${mod}/package.json`));
39
+ return OPT_CACHE[ctx.workspace.path];
48
40
  }
49
41
 
50
42
  /**
@@ -66,25 +58,28 @@ export class CommonUtil {
66
58
  * Restartable Event Stream
67
59
  */
68
60
  static async * restartableEvents<T>(src: (signal: AbortSignal) => AsyncIterable<T>, parent: AbortSignal, shouldRestart: (item: T) => boolean): AsyncIterable<T> {
61
+ const log = LogUtil.logger('event-stream');
69
62
  outer: while (!parent.aborted) {
70
63
  const controller = new AbortController();
64
+ setMaxListeners(1000, controller.signal);
71
65
  // Chain
72
66
  parent.addEventListener('abort', () => controller.abort());
73
67
 
74
68
  const comp = src(controller.signal);
75
69
 
76
- LogUtil.log('event-stream', 'debug', 'Started event stream');
70
+ log('debug', 'Started event stream');
77
71
 
78
72
  // Wait for all events, close at the end
79
73
  for await (const ev of comp) {
80
74
  yield ev;
81
75
  if (shouldRestart(ev)) {
76
+ log('debug', 'Restarting stream');
82
77
  controller.abort(); // Ensure terminated of process
83
78
  continue outer;
84
79
  }
85
80
  }
86
81
 
87
- LogUtil.log('event-stream', 'debug', 'Finished event stream');
82
+ log('debug', 'Finished event stream');
88
83
 
89
84
  // Natural exit, we done
90
85
  if (!controller.signal.aborted) { // Shutdown source if still running
@@ -100,8 +95,8 @@ export class CommonUtil {
100
95
  */
101
96
  static moduleLoader(ctx: ManifestContext): (mod: string) => Promise<unknown> {
102
97
  return (mod) => {
103
- const outputRoot = path.resolve(ctx.workspacePath, ctx.outputFolder);
104
- process.env.TRV_MANIFEST = path.resolve(outputRoot, 'node_modules', ctx.mainModule); // Setup for running
98
+ const outputRoot = path.resolve(ctx.workspace.path, ctx.build.outputFolder);
99
+ process.env.TRV_MANIFEST = path.resolve(outputRoot, 'node_modules', ctx.main.name); // Setup for running
105
100
  return import(path.join(outputRoot, 'node_modules', mod)); // Return function to run import on a module
106
101
  };
107
102
  }