@travetto/compiler 8.0.0-alpha.2 → 8.0.0-alpha.21

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 CHANGED
@@ -17,15 +17,15 @@ This module expands upon the [Typescript](https://typescriptlang.org) compiler,
17
17
  * Integration with the [Transformation](https://github.com/travetto/travetto/tree/main/module/transformer#readme "Functionality for AST transformations, with transformer registration, and general utils") module, allowing for rich, type-aware transformations
18
18
  * Automatic conversion to either [Ecmascript Module](https://nodejs.org/api/esm.html) or [CommonJS](https://nodejs.org/api/modules.html) based on the [Package JSON](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) `type` value
19
19
  * Removal of type only imports which can break [Ecmascript Module](https://nodejs.org/api/esm.html)-style output
20
- * Automatic addition of `.js` extension to imports to also support [Ecmascript Module](https://nodejs.org/api/esm.html)-style output
20
+ * Automatic addition of `.js` extension to imports to also support [Ecmascript Module](https://nodejs.org/api/esm.html)-style output
21
21
 
22
22
  Beyond the [Typescript](https://typescriptlang.org) compiler functionality, the module provides the primary entry point into the development process.
23
23
 
24
24
  ## CLI
25
- The compiler cli, [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js) 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
+ The compiler cli, [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js) 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.
26
26
 
27
27
  The compiler cli supports the following operations:
28
- * `start|watch` - Run the compiler in watch mode
28
+ * `start` - Run the compiler in watch mode
29
29
  * `stop` - Stop the compiler if running
30
30
  * `restart` - Restart the compiler in watch mode
31
31
  * `build` - Ensure the project is built and upto date
@@ -36,7 +36,7 @@ The compiler cli supports the following operations:
36
36
  * `manifest [output]` - Generate the project manifest
37
37
  * `manifest:production [output]` - Generate the production project manifest
38
38
 
39
- In addition to the normal output, the compiler supports an environment variable `TRV_BUILD` that supports the following values: `debug`, `info`, `warn` or `none`. This provides different level of logging during the build process which is helpful to diagnose any odd behaviors. When invoking an unknown command (e.g. `<other>` from above), the default level is `warn`. Otherwise the default logging level is `info`.
39
+ In addition to the normal output, the compiler supports an environment variable `TRV_BUILD` that supports the following values: `debug`, `info`, `warn` or `none`. This provides different level of logging during the build process which is helpful to diagnose any odd behaviors. When invoking an unknown command (e.g. `<other>` from above), the default level is `warn`. Otherwise the default logging level is `info`.
40
40
 
41
41
  **Terminal: Sample trv output with debug logging**
42
42
  ```bash
@@ -48,7 +48,7 @@ $ TRV_BUILD=debug trvc build
48
48
  2029-03-14T04:00:02.450Z info [compiler-exec ] Launching compiler
49
49
  2029-03-14T04:00:02.762Z debug [server ] Compilation started
50
50
  2029-03-14T04:00:02.947Z info [server ] State changed: init
51
- 2029-03-14T04:00:03.093Z debug [server ] Compiler loaded
51
+ 2029-03-14T04:00:03.093Z debug [server ] Compiler loaded: 0 files changed
52
52
  2029-03-14T04:00:04.003Z info [server ] State changed: compile-start
53
53
  2029-03-14T04:00:04.495Z info [server ] State changed: compile-end
54
54
  2029-03-14T04:00:05.066Z debug [server ] Compiler process shutdown
package/__index__.ts CHANGED
@@ -2,11 +2,11 @@ export * from './src/common.ts';
2
2
  export * from './src/compiler.ts';
3
3
  export * from './src/event.ts';
4
4
  export * from './src/log.ts';
5
+ export * from './src/server/client.ts';
6
+ export * from './src/server/manager.ts';
7
+ export * from './src/server/process-handle.ts';
8
+ export * from './src/server/server.ts';
5
9
  export * from './src/state.ts';
6
10
  export * from './src/types.ts';
7
11
  export * from './src/util.ts';
8
12
  export * from './src/watch.ts';
9
- export * from './src/server/client.ts';
10
- export * from './src/server/server.ts';
11
- export * from './src/server/manager.ts';
12
- export * from './src/server/process-handle.ts';
package/bin/hook.js CHANGED
@@ -1,20 +1,17 @@
1
- import module from 'node:module';
1
+ // @ts-check
2
+
2
3
  import { readFileSync } from 'node:fs';
4
+ import module from 'node:module';
3
5
  import { fileURLToPath } from 'node:url';
4
6
 
5
- import '@travetto/runtime/support/polyfill.js';
6
-
7
- process.setSourceMapsEnabled(true); // Ensure source map during compilation/development
8
- process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS ?? ''} --enable-source-maps`; // Ensure it passes to children
9
- const ogEmitWarning = process.emitWarning;
10
- Error.stackTraceLimit = 50;
7
+ const ogEmitWarning = process.emitWarning.bind(process);
11
8
 
12
9
  module.registerHooks({
13
10
  load: (url, context, nextLoad) => {
14
11
  if (/[.]tsx?$/.test(url)) {
12
+ const source = readFileSync(fileURLToPath(url), 'utf8');
15
13
  try {
16
- process.emitWarning = () => { }; // Suppress ts-node experimental warnings
17
- const source = readFileSync(fileURLToPath(url), 'utf8');
14
+ process.emitWarning = () => {};
18
15
  return { format: 'module', source: module.stripTypeScriptTypes(source), shortCircuit: true };
19
16
  } finally {
20
17
  process.emitWarning = ogEmitWarning;
@@ -1,4 +1,6 @@
1
1
  // @ts-check
2
+ import '@travetto/runtime/support/patch.js';
2
3
  import './hook.js';
4
+
3
5
  const { Compiler } = await import('../src/compiler.ts');
4
- await Compiler.main();
6
+ await Compiler.main();
package/bin/trvc.js CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // @ts-check
3
+ import '@travetto/runtime/support/patch.js';
3
4
  import './hook.js';
5
+
4
6
  const { invoke } = await import('@travetto/compiler/support/invoke.ts');
5
- await invoke();
7
+ await invoke(...process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/compiler",
3
- "version": "8.0.0-alpha.2",
3
+ "version": "8.0.0-alpha.21",
4
4
  "type": "module",
5
5
  "description": "The compiler infrastructure for the Travetto framework",
6
6
  "keywords": [
@@ -31,11 +31,11 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@parcel/watcher": "^2.5.6",
34
- "@travetto/manifest": "^8.0.0-alpha.2",
35
- "@travetto/transformer": "^8.0.0-alpha.2"
34
+ "@travetto/manifest": "^8.0.0-alpha.11",
35
+ "@travetto/transformer": "^8.0.0-alpha.14"
36
36
  },
37
37
  "peerDependencies": {
38
- "@travetto/cli": "^8.0.0-alpha.3"
38
+ "@travetto/cli": "^8.0.0-alpha.28"
39
39
  },
40
40
  "peerDependenciesMeta": {
41
41
  "@travetto/cli": {
package/src/common.ts CHANGED
@@ -6,11 +6,14 @@ import { type ManifestContext, path } from '@travetto/manifest';
6
6
  import { Log } from './log.ts';
7
7
 
8
8
  export class CommonUtil {
9
-
10
9
  /**
11
10
  * Restartable Event Stream
12
11
  */
13
- static async * restartableEvents<T>(input: (signal: AbortSignal) => AsyncIterable<T>, parent: AbortSignal, shouldRestart: (item: T) => boolean): AsyncIterable<T> {
12
+ static async *restartableEvents<T>(
13
+ input: (signal: AbortSignal) => AsyncIterable<T>,
14
+ parent: AbortSignal,
15
+ shouldRestart: (item: T) => boolean
16
+ ): AsyncIterable<T> {
14
17
  const log = Log.scoped('event-stream');
15
18
  outer: while (!parent.aborted) {
16
19
  const controller = new AbortController();
@@ -37,7 +40,8 @@ export class CommonUtil {
37
40
  log.debug('Finished event stream');
38
41
 
39
42
  // Natural exit, we done
40
- if (!controller.signal.aborted) { // Shutdown source if still running
43
+ if (!controller.signal.aborted) {
44
+ // Shutdown source if still running
41
45
  controller.abort();
42
46
  }
43
47
  return;
@@ -48,14 +52,14 @@ export class CommonUtil {
48
52
  * Non-blocking timeout
49
53
  */
50
54
  static nonBlockingTimeout(time: number): Promise<void> {
51
- return timers.setTimeout(time, undefined, { ref: false }).catch(() => { });
55
+ return timers.setTimeout(time, undefined, { ref: false }).catch(() => {});
52
56
  }
53
57
 
54
58
  /**
55
59
  * Blocking timeout
56
60
  */
57
61
  static blockingTimeout(time: number): Promise<void> {
58
- return timers.setTimeout(time, undefined, { ref: true }).catch(() => { });
62
+ return timers.setTimeout(time, undefined, { ref: true }).catch(() => {});
59
63
  }
60
64
 
61
65
  /**
@@ -76,8 +80,10 @@ export class CommonUtil {
76
80
  * Write to stdout with backpressure handling
77
81
  */
78
82
  static async writeStdout(level: number, data: unknown): Promise<void> {
79
- if (data === undefined) { return; }
83
+ if (data === undefined) {
84
+ return;
85
+ }
80
86
  process.stdout.write(`${JSON.stringify(data, undefined, level)}\n`) ||
81
- await new Promise(resolve => process.stdout.once('drain', resolve));
82
- };
83
- }
87
+ (await new Promise(resolve => process.stdout.once('drain', resolve)));
88
+ }
89
+ }
package/src/compiler.ts CHANGED
@@ -1,16 +1,14 @@
1
- import fs from 'node:fs/promises';
2
1
  import { setMaxListeners } from 'node:events';
2
+ import fs from 'node:fs/promises';
3
3
 
4
- import { getManifestContext, ManifestDeltaUtil, ManifestIndex, ManifestUtil, type DeltaEvent } from '@travetto/manifest';
4
+ import { type DeltaEvent, getManifestContext, ManifestDeltaUtil, ManifestIndex, ManifestUtil } from '@travetto/manifest';
5
5
 
6
- import { CompilerUtil } from './util.ts';
7
- import { CompilerState } from './state.ts';
8
- import { CompilerWatcher } from './watch.ts';
9
- import { type CompileEmitEvent, type CompileEmitter, CompilerReset } from './types.ts';
6
+ import { CommonUtil } from './common.ts';
10
7
  import { EventUtil } from './event.ts';
11
-
12
8
  import { IpcLogger } from './log.ts';
13
- import { CommonUtil } from './common.ts';
9
+ import { CompilerState } from './state.ts';
10
+ import { type CompileEmitEvent, CompilerReset } from './types.ts';
11
+ import { CompilerWatcher } from './watch.ts';
14
12
 
15
13
  const log = new IpcLogger({ level: 'debug' });
16
14
 
@@ -18,7 +16,6 @@ const log = new IpcLogger({ level: 'debug' });
18
16
  * Compilation support
19
17
  */
20
18
  export class Compiler {
21
-
22
19
  /**
23
20
  * Run compiler as a main entry point
24
21
  */
@@ -32,8 +29,8 @@ export class Compiler {
32
29
 
33
30
  #state: CompilerState;
34
31
  #watch?: boolean;
35
- #controller: AbortController;
36
- #signal: AbortSignal;
32
+ #shutdownController: AbortController;
33
+ #shutdownSignal: AbortSignal;
37
34
  #shuttingDown = false;
38
35
  #deltaEvents: DeltaEvent[];
39
36
 
@@ -42,15 +39,13 @@ export class Compiler {
42
39
  this.#watch = watch;
43
40
  this.#deltaEvents = deltaEvents;
44
41
 
45
- this.#controller = new AbortController();
46
- this.#signal = this.#controller.signal;
47
- setMaxListeners(1000, this.#signal);
48
- process
49
- .once('disconnect', () => this.#shutdown('manual'))
50
- .on('message', event => (event === 'shutdown') && this.#shutdown('manual'));
42
+ this.#shutdownController = new AbortController();
43
+ this.#shutdownSignal = this.#shutdownController.signal;
44
+ setMaxListeners(1000, this.#shutdownSignal);
45
+ process.once('disconnect', () => this.#shutdown('manual')).on('message', event => event === 'shutdown' && this.#shutdown('manual'));
51
46
  }
52
47
 
53
- #shutdown(mode: 'error' | 'manual' | 'complete' | 'reset', error?: Error): void {
48
+ #shutdown(mode: 'error' | 'manual' | 'complete' | 'reset', errorMessage?: string): void {
54
49
  if (this.#shuttingDown) {
55
50
  return;
56
51
  }
@@ -64,14 +59,13 @@ export class Compiler {
64
59
  }
65
60
  case 'error': {
66
61
  process.exitCode = 1;
67
- if (error) {
68
- EventUtil.sendEvent('log', { level: 'error', message: error.toString(), time: Date.now() });
69
- log.error('Shutting down due to failure', error.stack);
62
+ if (errorMessage) {
63
+ log.error('Shutting down due to failure', errorMessage);
70
64
  }
71
65
  break;
72
66
  }
73
67
  case 'reset': {
74
- log.info('Reset due to', error?.message);
68
+ log.info('Reset due to', errorMessage);
75
69
  EventUtil.sendEvent('state', { state: 'reset' });
76
70
  process.exitCode = 0;
77
71
  break;
@@ -80,7 +74,7 @@ export class Compiler {
80
74
  // No longer listen to disconnect
81
75
  process.removeAllListeners('disconnect');
82
76
  process.removeAllListeners('message');
83
- this.#controller.abort();
77
+ this.#shutdownController.abort();
84
78
  CommonUtil.nonBlockingTimeout(1000).then(() => process.exit()); // Allow upto 1s to shutdown gracefully
85
79
  }
86
80
 
@@ -110,35 +104,27 @@ export class Compiler {
110
104
  });
111
105
  }
112
106
 
113
- /**
114
- * Compile in a single pass, only emitting dirty files
115
- */
116
- getCompiler(): CompileEmitter {
117
- return (sourceFile: string, needsNewProgram?: boolean) => this.#state.compileSourceFile(sourceFile, needsNewProgram);
118
- }
119
-
120
107
  /**
121
108
  * Emit all files as a stream
122
109
  */
123
- async * emit(files: string[], emitter: CompileEmitter): AsyncIterable<CompileEmitEvent> {
110
+ async *emit(files: string[]): AsyncIterable<CompileEmitEvent> {
124
111
  let i = 0;
125
112
  let lastSent = Date.now();
126
113
 
127
- await emitter(files[0]); // Prime
128
-
129
114
  for (const file of files) {
130
115
  const start = Date.now();
131
- const error = await emitter(file);
116
+ const errors = await this.#state.compileSourceFile(file);
132
117
  const duration = Date.now() - start;
133
118
  const nodeModSeparator = 'node_modules/';
134
119
  const nodeModIdx = file.lastIndexOf(nodeModSeparator);
135
120
  const imp = nodeModIdx >= 0 ? file.substring(nodeModIdx + nodeModSeparator.length) : file;
136
- yield { file: imp, i: i += 1, error, total: files.length, duration };
137
- if ((Date.now() - lastSent) > 50) { // Limit to 1 every 50ms
121
+ yield { file: imp, i: (i += 1), errors, total: files.length, duration };
122
+ if (Date.now() - lastSent > 50) {
123
+ // Limit to 1 every 50ms
138
124
  lastSent = Date.now();
139
125
  EventUtil.sendEvent('progress', { total: files.length, idx: i, message: imp, operation: 'compile' });
140
126
  }
141
- if (this.#signal.aborted) {
127
+ if (this.#shutdownSignal.aborted) {
142
128
  break;
143
129
  }
144
130
  }
@@ -157,49 +143,52 @@ export class Compiler {
157
143
 
158
144
  EventUtil.sendEvent('state', { state: 'init', extra: { processId: process.pid } });
159
145
 
160
- const emitter = this.getCompiler();
161
- let failure: Error | undefined;
146
+ const failures = new Map<string, number>();
162
147
 
163
- log.debug('Compiler loaded');
148
+ log.debug(`Compiler loaded: ${this.#deltaEvents.length} files changed`);
164
149
 
165
150
  EventUtil.sendEvent('state', { state: 'compile-start' });
166
151
 
167
152
  const metrics: CompileEmitEvent[] = [];
168
153
  const isCompilerChanged = this.#deltaEvents.some(event => this.#state.isCompilerFile(event.sourceFile));
169
- const changedFiles = (isCompilerChanged ? this.#state.getAllFiles() : this.#deltaEvents.map(event => event.sourceFile));
170
-
171
- if (this.#watch || changedFiles.length) {
172
- await ManifestUtil.writeManifest(this.#state.manifestIndex.manifest);
173
- await this.#state.initializeTypescript();
174
- }
154
+ const changedFiles = isCompilerChanged ? this.#state.getAllFiles() : this.#deltaEvents.map(event => event.sourceFile);
175
155
 
176
156
  if (changedFiles.length) {
177
- for await (const event of this.emit(changedFiles, emitter)) {
178
- if (event.error) {
179
- const compileError = CompilerUtil.buildTranspileError(event.file, event.error);
180
- failure ??= compileError;
181
- EventUtil.sendEvent('log', { level: 'error', message: compileError.toString(), time: Date.now() });
157
+ for await (const event of this.emit(changedFiles)) {
158
+ if (event.errors?.length) {
159
+ failures.set(event.file, event.errors.length);
160
+ for (const error of event.errors) {
161
+ log.error(`ERROR ${event.file}:${error}`);
162
+ }
163
+ // Touch file to ensure recompilation later
164
+ if (await fs.stat(event.file, { throwIfNoEntry: false })) {
165
+ await fs.utimes(event.file, new Date(), new Date());
166
+ }
182
167
  }
183
168
  metrics.push(event);
184
169
  }
185
- if (this.#signal.aborted) {
170
+ if (this.#shutdownSignal.aborted) {
186
171
  log.debug('Compilation aborted');
187
- } else if (failure) {
188
- log.debug('Compilation failed');
189
- return this.#shutdown('error', failure);
172
+ } else if (failures.size) {
173
+ const sortedFailures = [...failures.entries()].sort((a, b) => a[0].localeCompare(b[0]));
174
+ log.error(
175
+ 'Compilation failed',
176
+ ['', sortedFailures.flatMap(([file, count]) => `- ${file}: ${count} errors found`)].flat(3).join('\n')
177
+ );
190
178
  } else {
191
179
  log.debug('Compilation succeeded');
192
180
  }
193
181
 
194
- // Rebuild manifests if dirty
182
+ // Rebuild manifests
195
183
  const manifest = await ManifestUtil.buildManifest(this.#state.manifestIndex.manifest);
196
184
  await ManifestUtil.writeManifest(manifest);
197
185
  await ManifestUtil.writeDependentManifests(manifest);
186
+
187
+ if (!this.#watch && failures.size) {
188
+ return this.#shutdown('error');
189
+ }
190
+
198
191
  this.#state.manifestIndex.reinitForModule(this.#state.manifest.main.name); // Reload
199
- } else if (this.#watch) {
200
- // Prime compiler before complete
201
- const resolved = this.#state.getArbitraryInputFile();
202
- await emitter(resolved, true);
203
192
  }
204
193
 
205
194
  EventUtil.sendEvent('state', { state: 'compile-end' });
@@ -208,16 +197,22 @@ export class Compiler {
208
197
  this.logStatistics(metrics);
209
198
  }
210
199
 
211
- if (this.#watch && !this.#signal.aborted) {
200
+ if (this.#watch && !this.#shutdownSignal.aborted) {
201
+ const resolved = this.#state.getArbitraryInputFile();
202
+ await this.#state.compileSourceFile(resolved);
203
+
212
204
  log.info('Watch is ready');
213
205
 
214
206
  EventUtil.sendEvent('state', { state: 'watch-start' });
215
207
  try {
216
- for await (const event of new CompilerWatcher(this.#state, this.#signal)) {
208
+ for await (const event of new CompilerWatcher(this.#state, this.#shutdownSignal)) {
217
209
  if (event.action !== 'delete') {
218
- const error = await emitter(event.entry.sourceFile, true);
219
- if (error) {
220
- log.info('Compilation Error', CompilerUtil.buildTranspileError(event.entry.sourceFile, error));
210
+ const errors = await this.#state.compileSourceFile(event.entry.sourceFile, true);
211
+ if (errors?.length) {
212
+ log.error('Compilation failed', `${event.entry.sourceFile}: ${errors.length} errors found`);
213
+ for (const error of errors) {
214
+ log.error(`ERROR ${event.file}:${error}`);
215
+ }
221
216
  } else {
222
217
  log.info(`Compiled ${event.entry.sourceFile} on ${event.action}`);
223
218
  }
@@ -242,7 +237,7 @@ export class Compiler {
242
237
  EventUtil.sendEvent('state', { state: 'watch-end' });
243
238
  } catch (error) {
244
239
  if (error instanceof Error) {
245
- this.#shutdown(error instanceof CompilerReset ? 'reset' : 'error', error);
240
+ this.#shutdown(error instanceof CompilerReset ? 'reset' : 'error', error.message);
246
241
  }
247
242
  }
248
243
  }
package/src/event.ts CHANGED
@@ -3,14 +3,16 @@ import type { CompilerEvent, CompilerEventPayload, CompilerEventType } from './t
3
3
  const VALID_EVENT_TYPES = new Set<CompilerEventType>(['change', 'log', 'progress', 'state', 'all', 'file']);
4
4
 
5
5
  export class EventUtil {
6
-
7
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
8
6
  static isComplilerEventType = (value: string): value is CompilerEventType => VALID_EVENT_TYPES.has(value as CompilerEventType);
9
7
 
10
8
  static isCompilerEvent = (value: unknown): value is CompilerEvent =>
11
- typeof value === 'object' && value !== null && 'type' in value && typeof value.type === 'string' && EventUtil.isComplilerEventType(value.type);
9
+ typeof value === 'object' &&
10
+ value !== null &&
11
+ 'type' in value &&
12
+ typeof value.type === 'string' &&
13
+ EventUtil.isComplilerEventType(value.type);
12
14
 
13
15
  static sendEvent<K extends CompilerEventType, T extends CompilerEventPayload<K>>(type: K, payload: T): void {
14
- process.connected && process.send!({ type, payload }, undefined, undefined, () => { });
16
+ process.connected && process.send!({ type, payload }, undefined, undefined, () => {});
15
17
  }
16
- }
18
+ }
package/src/log.ts CHANGED
@@ -15,7 +15,6 @@ export type LogShape = Record<'info' | 'debug' | 'warn' | 'error', (message: str
15
15
  const ESC = '\x1b[';
16
16
 
17
17
  export class Logger implements LogConfig, LogShape {
18
-
19
18
  static #linePartial: boolean | undefined;
20
19
 
21
20
  /** Rewrite text line, tracking cleanup as necessary */
@@ -23,7 +22,8 @@ export class Logger implements LogConfig, LogShape {
23
22
  if ((!text && !this.#linePartial) || !process.stdout.isTTY) {
24
23
  return;
25
24
  }
26
- if (this.#linePartial === undefined) { // First time
25
+ if (this.#linePartial === undefined) {
26
+ // First time
27
27
  process.stdout.write(`${ESC}?25l`); // Hide cursor
28
28
  process.on('exit', () => this.reset());
29
29
  }
@@ -35,7 +35,9 @@ export class Logger implements LogConfig, LogShape {
35
35
  }
36
36
  }
37
37
 
38
- static reset(): void { process.stdout.write(`${ESC}!p${ESC}?25h`); }
38
+ static reset(): void {
39
+ process.stdout.write(`${ESC}!p${ESC}?25h`);
40
+ }
39
41
 
40
42
  level?: CompilerLogLevel | 'none';
41
43
  root: string = process.cwd();
@@ -47,28 +49,38 @@ export class Logger implements LogConfig, LogShape {
47
49
  }
48
50
 
49
51
  valid(event: CompilerLogEvent): boolean {
50
- return LEVEL_TO_PRIORITY[this.level ?? this.parent?.level!] <= LEVEL_TO_PRIORITY[event.level];
52
+ return LEVEL_TO_PRIORITY[this.level ?? this.parent?.level ?? 'none'] <= LEVEL_TO_PRIORITY[event.level];
51
53
  }
52
54
 
53
55
  /** Log event with filtering by level */
54
56
  render(event: CompilerLogEvent): void {
55
- if (!this.valid(event)) { return; }
56
- const params = [event.message, ...event.args ?? []]
57
- .map(arg => typeof arg === 'string' ? arg.replaceAll(this.root ?? this.parent?.root!, '.') : arg);
57
+ if (!this.valid(event)) {
58
+ return;
59
+ }
60
+ const params = [event.message, ...(event.args ?? [])].map(arg =>
61
+ typeof arg === 'string' ? arg.replaceAll(this.root ?? this.parent?.root, '.') : arg
62
+ );
58
63
 
59
64
  if (event.scope ?? this.scope) {
60
65
  params.unshift(`[${(event.scope ?? this.scope!).padEnd(SCOPE_MAX, ' ')}]`);
61
66
  }
62
67
  params.unshift(new Date().toISOString(), `${event.level.padEnd(5)}`);
63
68
  Logger.rewriteLine(''); // Clear out progress line, if active
64
- // eslint-disable-next-line no-console
65
69
  console[event.level]!(...params);
66
70
  }
67
71
 
68
- info(message: string, ...args: unknown[]): void { return this.render({ level: 'info', message, args }); }
69
- debug(message: string, ...args: unknown[]): void { return this.render({ level: 'debug', message, args }); }
70
- warn(message: string, ...args: unknown[]): void { return this.render({ level: 'warn', message, args }); }
71
- error(message: string, ...args: unknown[]): void { return this.render({ level: 'error', message, args }); }
72
+ info(message: string, ...args: unknown[]): void {
73
+ this.render({ level: 'info', message, args });
74
+ }
75
+ debug(message: string, ...args: unknown[]): void {
76
+ this.render({ level: 'debug', message, args });
77
+ }
78
+ warn(message: string, ...args: unknown[]): void {
79
+ this.render({ level: 'warn', message, args });
80
+ }
81
+ error(message: string, ...args: unknown[]): void {
82
+ this.render({ level: 'error', message, args });
83
+ }
72
84
  }
73
85
 
74
86
  class $RootLogger extends Logger {
@@ -86,9 +98,17 @@ class $RootLogger extends Logger {
86
98
  initLevel(defaultLevel: CompilerLogLevel | 'none'): void {
87
99
  const value = process.env.TRV_QUIET !== 'true' ? process.env.TRV_BUILD : 'none';
88
100
  switch (value) {
89
- case 'debug': case 'warn': case 'error': case 'info': this.level = value; break;
90
- case undefined: this.level = defaultLevel; break;
91
- case 'none': default: this.level = 'none';
101
+ case 'debug':
102
+ case 'warn':
103
+ case 'error':
104
+ case 'info':
105
+ this.level = value;
106
+ break;
107
+ case undefined:
108
+ this.level = defaultLevel;
109
+ break;
110
+ default:
111
+ this.level = 'none';
92
112
  }
93
113
  }
94
114
 
@@ -100,21 +120,34 @@ class $RootLogger extends Logger {
100
120
  /** Scope and provide a callback pattern for access to a logger */
101
121
  wrap<T = unknown>(scope: string, operation: (log: Logger) => Promise<T>, basic = true): Promise<T> {
102
122
  const logger = this.scoped(scope);
103
- return basic ? (logger.debug('Started'), operation(logger).finally(() => logger.debug('Completed'))) : operation(logger);
123
+ if (basic) {
124
+ logger.debug('Started');
125
+ return operation(logger).finally(() => logger.debug('Completed'));
126
+ } else {
127
+ return operation(logger);
128
+ }
104
129
  }
105
130
 
106
131
  /** Write progress event, if active */
107
132
  onProgressEvent(event: CompilerProgressEvent): void | Promise<void> {
108
- if (!(this.logProgress)) { return; }
109
- const progress = Math.trunc(event.idx * 100 / event.total);
110
- const text = event.complete ? '' : `Compiling [${'#'.repeat(Math.trunc(progress / 10)).padEnd(10, ' ')}] [${event.idx}/${event.total}] ${event.message}`;
133
+ if (!this.logProgress) {
134
+ return;
135
+ }
136
+ const progress = Math.trunc((event.idx * 100) / event.total);
137
+ const text = event.complete
138
+ ? ''
139
+ : `Compiling [${'#'.repeat(Math.trunc(progress / 10)).padEnd(10, ' ')}] [${event.idx}/${event.total}] ${event.message}`;
111
140
  return Logger.rewriteLine(text);
112
141
  }
113
142
 
114
143
  /** Write all progress events if active */
115
144
  async consumeProgressEvents(input: () => AsyncIterable<CompilerProgressEvent>): Promise<void> {
116
- if (!(this.logProgress)) { return; }
117
- for await (const event of input()) { this.onProgressEvent(event); }
145
+ if (!this.logProgress) {
146
+ return;
147
+ }
148
+ for await (const event of input()) {
149
+ this.onProgressEvent(event);
150
+ }
118
151
  Logger.reset();
119
152
  }
120
153
  }
@@ -123,7 +156,9 @@ export const Log = new $RootLogger();
123
156
 
124
157
  export class IpcLogger extends Logger {
125
158
  render(event: CompilerLogEvent): void {
126
- if (!this.valid(event)) { return; }
159
+ if (!this.valid(event)) {
160
+ return;
161
+ }
127
162
  if (process.connected && process.send) {
128
163
  process.send({ type: 'log', payload: event });
129
164
  }
package/src/queue.ts CHANGED
@@ -10,7 +10,9 @@ export class AsyncQueue<X> implements AsyncIterator<X>, AsyncIterable<X> {
10
10
  }
11
11
  }
12
12
 
13
- [Symbol.asyncIterator](): AsyncIterator<X> { return this; }
13
+ [Symbol.asyncIterator](): AsyncIterator<X> {
14
+ return this;
15
+ }
14
16
 
15
17
  async next(): Promise<IteratorResult<X>> {
16
18
  while (!this.#done && !this.#queue.length) {
@@ -35,4 +37,4 @@ export class AsyncQueue<X> implements AsyncIterator<X>, AsyncIterable<X> {
35
37
  this.#done = true;
36
38
  this.#ready.resolve();
37
39
  }
38
- }
40
+ }