@travetto/compiler 3.0.3 → 3.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -45,26 +45,21 @@ $ TRV_BUILD=debug trv build
45
45
  2029-03-14T04:00:04.003Z [manifest ] Started
46
46
  2029-03-14T04:00:04.495Z [manifest ] Completed
47
47
  2029-03-14T04:00:05.066Z [transformers ] Started
48
- 2029-03-14T04:00:05.307Z [transformers ] @travetto-test/transformer Skipped
49
- 2029-03-14T04:00:05.952Z [transformers ] @travetto/app Skipped
50
- 2029-03-14T04:00:06.859Z [transformers ] @travetto/base Skipped
51
- 2029-03-14T04:00:07.720Z [transformers ] @travetto/cache Skipped
52
- 2029-03-14T04:00:08.179Z [transformers ] @travetto/di Skipped
53
- 2029-03-14T04:00:08.588Z [transformers ] @travetto/manifest Skipped
54
- 2029-03-14T04:00:09.493Z [transformers ] @travetto/registry Skipped
55
- 2029-03-14T04:00:10.395Z [transformers ] @travetto/rest Skipped
56
- 2029-03-14T04:00:10.407Z [transformers ] @travetto/schema Skipped
57
- 2029-03-14T04:00:10.799Z [transformers ] @travetto/test Skipped
58
- 2029-03-14T04:00:11.013Z [transformers ] Completed
59
- 2029-03-14T04:00:11.827Z [delta ] Started
60
- 2029-03-14T04:00:11.894Z [delta ] Completed
61
- 2029-03-14T04:00:12.133Z [manifest ] Started
62
- 2029-03-14T04:00:13.123Z [manifest ] Wrote manifest @travetto/mono-repo
63
- 2029-03-14T04:00:14.014Z [manifest ] Completed
64
- 2029-03-14T04:00:14.924Z [compile ] Started action=build changed=
65
- 2029-03-14T04:00:15.690Z [compile ] Skipped
66
- 2029-03-14T04:00:15.865Z [lock ] Releasing build
67
- 2029-03-14T04:00:16.757Z [build ] Successfully built
48
+ 2029-03-14T04:00:05.307Z [transformers ] @travetto/base Skipped
49
+ 2029-03-14T04:00:05.952Z [transformers ] @travetto/cli Skipped
50
+ 2029-03-14T04:00:06.859Z [transformers ] @travetto/manifest Skipped
51
+ 2029-03-14T04:00:07.720Z [transformers ] @travetto/registry Skipped
52
+ 2029-03-14T04:00:08.179Z [transformers ] @travetto/schema Skipped
53
+ 2029-03-14T04:00:08.588Z [transformers ] Completed
54
+ 2029-03-14T04:00:09.493Z [delta ] Started
55
+ 2029-03-14T04:00:10.395Z [delta ] Completed
56
+ 2029-03-14T04:00:10.407Z [manifest ] Started
57
+ 2029-03-14T04:00:10.799Z [manifest ] Wrote manifest @travetto-doc/compiler
58
+ 2029-03-14T04:00:11.013Z [manifest ] Completed
59
+ 2029-03-14T04:00:11.827Z [compile ] Started action=build changed=
60
+ 2029-03-14T04:00:11.894Z [compile ] Skipped
61
+ 2029-03-14T04:00:12.133Z [lock ] Releasing build
62
+ 2029-03-14T04:00:13.123Z [build ] Successfully built
68
63
  ```
69
64
 
70
65
  **Terminal: Sample trv output with default log level**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/compiler",
3
- "version": "3.0.3",
3
+ "version": "3.1.0-rc.1",
4
4
  "description": "The compiler infrastructure for the Travetto framework",
5
5
  "keywords": [
6
6
  "compiler",
@@ -31,12 +31,12 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@parcel/watcher": "^2.1.0",
34
- "@travetto/manifest": "^3.0.3",
35
- "@travetto/terminal": "^3.0.3",
36
- "@travetto/transformer": "^3.0.3"
34
+ "@travetto/manifest": "^3.1.0-rc.0",
35
+ "@travetto/terminal": "^3.1.0-rc.0",
36
+ "@travetto/transformer": "^3.1.0-rc.1"
37
37
  },
38
38
  "peerDependencies": {
39
- "@travetto/cli": "^3.0.3"
39
+ "@travetto/cli": "^3.1.0-rc.2"
40
40
  },
41
41
  "peerDependenciesMeta": {
42
42
  "@travetto/cli": {
package/src/compiler.ts CHANGED
@@ -39,20 +39,6 @@ export class Compiler {
39
39
  this.#watch = watch;
40
40
  }
41
41
 
42
- /**
43
- * Watches local modules
44
- */
45
- #watchLocalModules(emit: CompileEmitter): Promise<() => Promise<void>> {
46
- return new CompilerWatcher(this.#state).watchFiles(async file => {
47
- const err = await emit(file, true);
48
- if (err) {
49
- Log.info('Compilation Error', CompilerUtil.buildTranspileError(file, err));
50
- } else {
51
- Log.info(`Compiled ${file.split('node_modules/')[1]}`);
52
- }
53
- return err;
54
- });
55
- }
56
42
 
57
43
  /**
58
44
  * Compile in a single pass, only emitting dirty files
@@ -119,7 +105,7 @@ export class Compiler {
119
105
  };
120
106
 
121
107
  if (this.#dirtyFiles.length) {
122
- await GlobalTerminal.trackProgress(this.emit(this.#dirtyFiles, emitter), resolveEmittedFile, { position: 'bottom' });
108
+ await GlobalTerminal.trackProgress(this.emit(this.#dirtyFiles, emitter), resolveEmittedFile, { position: 'bottom', minDelay: 50 });
123
109
  if (failed) {
124
110
  Log.debug('Compilation failed');
125
111
  process.exit(1);
@@ -136,13 +122,21 @@ export class Compiler {
136
122
 
137
123
  if (this.#watch) {
138
124
  Log.info('Watch is ready');
139
- await this.#watchLocalModules(emitter);
140
- const output = this.#state.resolveOutputFile('.');
141
- for await (const _ of fs.watch(output)) {
142
- if (!await fs.stat(output).catch(() => false)) {
143
- process.send?.('restart');
125
+ for await (const { file, action } of CompilerWatcher.watch(this.#state)) {
126
+ if (action !== 'delete') {
127
+ const err = await emitter(file, true);
128
+ if (err) {
129
+ Log.info('Compilation Error', CompilerUtil.buildTranspileError(file, err));
130
+ } else {
131
+ Log.info(`Compiled ${file.split('node_modules/')[1]}`);
132
+ }
133
+ } else {
134
+ Log.info(`Removed ${file.split('node_modules/')[1]}`);
144
135
  }
145
136
  }
137
+ if (!process.exitCode) {
138
+ process.send?.('restart');
139
+ }
146
140
  }
147
141
  }
148
142
  }
package/src/util.ts CHANGED
@@ -3,7 +3,6 @@ import ts from 'typescript';
3
3
  import { ManifestContext, ManifestModuleFileType, ManifestModuleUtil, ManifestRoot, Package, path } from '@travetto/manifest';
4
4
 
5
5
  type OutputToSource = (outputFile: string) => ({ source: string } | undefined);
6
- export type FileWatchEvent = { type: 'create' | 'delete' | 'update', path: string };
7
6
 
8
7
  const nativeCwd = process.cwd();
9
8
 
package/src/watch.ts CHANGED
@@ -1,21 +1,28 @@
1
1
  import { readFileSync } from 'fs';
2
- import fs from 'fs/promises';
3
2
 
4
3
  import {
5
4
  ManifestContext, ManifestModuleUtil, ManifestUtil, WatchEvent, ManifestModuleFolderType,
6
- ManifestModuleFileType, path, ManifestModule, watchFolders, WatchEventListener, watchFolderImmediate, WatchConfig
5
+ ManifestModuleFileType, path, ManifestModule, watchFolders, WatchFolder, RootIndex, WatchStream
7
6
  } from '@travetto/manifest';
8
7
  import { getManifestContext } from '@travetto/manifest/bin/context';
9
8
 
10
9
  import { CompilerState } from './state';
11
10
  import { CompilerUtil } from './util';
12
- import { CompileEmitter, CompileWatcherHandler } from './types';
13
11
 
14
12
  /**
15
13
  * Utils for watching
16
14
  */
17
15
  export class CompilerWatcher {
18
16
 
17
+ /**
18
+ * Watch state
19
+ * @param state
20
+ * @returns
21
+ */
22
+ static watch(state: CompilerState): AsyncIterable<WatchEvent> {
23
+ return new CompilerWatcher(state).watchChanges();
24
+ }
25
+
19
26
  #sourceHashes = new Map<string, number>();
20
27
  #manifestContexts = new Map<string, ManifestContext>();
21
28
  #dirtyFiles: { modFolder: string, mod: string, moduleFile?: string, folderKey?: ManifestModuleFolderType, type?: ManifestModuleFileType }[] = [];
@@ -62,15 +69,21 @@ export class CompilerWatcher {
62
69
  }
63
70
 
64
71
  /**
65
- * Get a watcher for a given compiler state
66
- * @param state
67
- * @param handler
68
- * @returns
69
- */
70
- #getWatcher(handler: CompileWatcherHandler): WatchEventListener {
72
+ * Get a watcher for a given compiler state
73
+ * @param state
74
+ * @param handler
75
+ * @returns
76
+ */
77
+ async * watchChanges(): AsyncIterable<WatchEvent> {
78
+ const stream = this.#watchFiles();
79
+
71
80
  const mods = this.#getModuleMap();
81
+ for await (const { file: sourceFile, action, folder } of stream) {
82
+
83
+ if (folder === '.trv_internal') {
84
+ break;
85
+ }
72
86
 
73
- return async ({ file: sourceFile, action }: WatchEvent, folder: string): Promise<void> => {
74
87
  const mod = mods[folder];
75
88
  const moduleFile = mod.sourceFolder ?
76
89
  (sourceFile.includes(mod.sourceFolder) ? sourceFile.split(`${mod.sourceFolder}/`)[1] : sourceFile) :
@@ -91,7 +104,7 @@ export class CompilerWatcher {
91
104
  const hash = CompilerUtil.naiveHash(readFileSync(sourceFile, 'utf8'));
92
105
  const input = this.#state.registerInput(mod, moduleFile);
93
106
  this.#sourceHashes.set(sourceFile, hash);
94
- handler.create(input);
107
+ yield { action, file: input, folder };
95
108
  }
96
109
  break;
97
110
  }
@@ -103,7 +116,7 @@ export class CompilerWatcher {
103
116
  if (this.#sourceHashes.get(sourceFile) !== hash) {
104
117
  this.#state.resetInputSource(entry.input);
105
118
  this.#sourceHashes.set(sourceFile, hash);
106
- handler.update(entry.input);
119
+ yield { action, file: entry.input, folder };
107
120
  }
108
121
  }
109
122
  break;
@@ -114,49 +127,58 @@ export class CompilerWatcher {
114
127
  this.#state.removeInput(entry.input);
115
128
  if (entry.output) {
116
129
  this.#dirtyFiles.push({ mod: mod.name, modFolder: folder });
117
- handler.delete(entry.output);
130
+ yield { action, file: entry.output, folder };
118
131
  }
119
132
  }
120
133
  }
121
134
  }
122
- };
135
+ }
123
136
  }
124
137
 
125
138
  /**
126
139
  * Watch files based on root index
127
140
  */
128
- async watchFiles(emit: CompileEmitter): Promise<() => Promise<void>> {
129
- let watchRoot: (() => Promise<void>) | undefined = undefined;
130
-
141
+ #watchFiles(): WatchStream {
131
142
  const idx = this.#state.manifestIndex;
132
143
  const modules = [...idx.getModuleList('all')].map(x => idx.getModule(x)!);
133
- const remove = (outputFile: string): Promise<void> => fs.rm(outputFile, { force: true });
134
- const handler = this.#getWatcher({ create: emit, update: emit, delete: remove });
135
- const options: WatchConfig = {
136
- filter: ev => {
144
+ const options: Partial<WatchFolder> = {
145
+ filter: (ev: WatchEvent): boolean => {
137
146
  const type = ManifestModuleUtil.getFileType(ev.file);
138
147
  return type === 'ts' || type === 'typings' || type === 'js' || type === 'package-json';
139
148
  },
140
- ignore: ['node_modules']
149
+ ignore: ['node_modules', '**/.trv_*'],
141
150
  };
142
151
 
143
- const moduleFolders = modules
152
+ const moduleFolders: WatchFolder[] = modules
144
153
  .filter(x => !idx.manifest.monoRepo || x.sourcePath !== idx.manifest.workspacePath)
145
- .map(x => [x.sourcePath, x.sourcePath] as const);
154
+ .map(x => ({ src: x.sourcePath, target: x.sourcePath }));
146
155
 
147
156
  // Add monorepo folders
148
157
  if (idx.manifest.monoRepo) {
149
158
  const mono = modules.find(x => x.sourcePath === idx.manifest.workspacePath)!;
150
159
  for (const folder of Object.keys(mono.files)) {
151
160
  if (!folder.startsWith('$')) {
152
- moduleFolders.push([path.resolve(mono.sourcePath, folder), mono.sourcePath]);
161
+ moduleFolders.push({ src: path.resolve(mono.sourcePath, folder), target: mono.sourcePath });
153
162
  }
154
163
  }
155
- watchRoot = await watchFolderImmediate(mono.sourcePath, handler, options);
164
+ moduleFolders.push({ src: mono.sourcePath, target: mono.sourcePath, immediate: true });
156
165
  }
157
166
 
158
- const watchAll = await watchFolders(moduleFolders, handler, options);
167
+ // Watch output folders
168
+ const outputWatch = (root: string, sources: string[]): WatchFolder => {
169
+ const valid = new Set(sources.map(src => path.resolve(root, src)));
170
+ return {
171
+ src: root, target: '.trv_internal', immediate: true, includeHidden: true,
172
+ filter: ev => ev.action === 'delete' && valid.has(path.resolve(root, ev.file))
173
+ };
174
+ };
175
+ moduleFolders.push(
176
+ outputWatch(RootIndex.manifest.workspacePath, [
177
+ RootIndex.manifest.outputFolder,
178
+ RootIndex.manifest.compilerFolder
179
+ ])
180
+ );
159
181
 
160
- return () => Promise.all([watchRoot?.(), watchAll()]).then(() => { });
182
+ return watchFolders(moduleFolders, options);
161
183
  }
162
184
  }
@@ -1,6 +1,7 @@
1
1
  import path from 'path';
2
2
  import fs from 'fs/promises';
3
3
  import os from 'os';
4
+ import timers from 'timers/promises';
4
5
  import cp from 'child_process';
5
6
  import { createRequire } from 'module';
6
7
 
@@ -204,7 +205,7 @@ export class TranspileUtil {
204
205
  try {
205
206
  await this.writeTextFile(deltaFile, changedFiles.join('\n'));
206
207
 
207
- return await LogUtil.withLogger('compiler-exec', log => new Promise<CompileResult>((res, rej) => {
208
+ const result = await LogUtil.withLogger('compiler-exec', log => new Promise<CompileResult>((res, rej) => {
208
209
  proc = cp.spawn(process.argv0, [main, deltaFile, `${watch}`], {
209
210
  env: {
210
211
  ...process.env,
@@ -225,10 +226,19 @@ export class TranspileUtil {
225
226
  kill = (): void => { proc?.kill('SIGKILL'); };
226
227
  process.on('exit', kill);
227
228
  }));
229
+
230
+ if (result === 'restart') {
231
+ await timers.setTimeout(150 + 100 * Math.random());
232
+ }
233
+
234
+ return result;
228
235
  } finally {
229
236
  if (proc?.killed === false) { proc.kill('SIGKILL'); }
230
237
  if (kill) {
231
- process.removeListener('exit', kill);
238
+ process.off('exit', kill);
239
+ }
240
+ if (process.stdout.isTTY) {
241
+ process.stdout.write('\x1b[s\x1b[?25h\x1b[r\x1b[u');
232
242
  }
233
243
  await fs.rm(deltaFile, { force: true });
234
244
  }