@travetto/compiler 7.0.0-rc.4 → 7.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/compiler",
3
- "version": "7.0.0-rc.4",
3
+ "version": "7.0.1",
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.1",
34
- "@travetto/manifest": "^7.0.0-rc.3",
35
- "@travetto/transformer": "^7.0.0-rc.4"
34
+ "@travetto/manifest": "^7.0.0",
35
+ "@travetto/transformer": "^7.0.1"
36
36
  },
37
37
  "peerDependencies": {
38
- "@travetto/cli": "^7.0.0-rc.5"
38
+ "@travetto/cli": "^7.0.1"
39
39
  },
40
40
  "peerDependenciesMeta": {
41
41
  "@travetto/cli": {
package/src/event.ts CHANGED
@@ -1,7 +1,7 @@
1
- import type { CompilerEvent, CompilerEventType } from '../support/types.ts';
1
+ import type { CompilerEventPayload, CompilerEventType } from '../support/types.ts';
2
2
 
3
3
  export class EventUtil {
4
- static sendEvent<K extends CompilerEventType, T extends CompilerEvent & { type: K }>(type: K, payload: T['payload']): void {
4
+ static sendEvent<K extends CompilerEventType, T extends CompilerEventPayload<K>>(type: K, payload: T): void {
5
5
  process.connected && process.send!({ type, payload }, undefined, undefined, () => { });
6
6
  }
7
7
  }
package/src/watch.ts CHANGED
@@ -9,6 +9,7 @@ import { CompilerUtil } from './util.ts';
9
9
 
10
10
  import { AsyncQueue } from '../support/queue.ts';
11
11
  import { IpcLogger } from '../support/log.ts';
12
+ import { EventUtil } from './event.ts';
12
13
 
13
14
  const log = new IpcLogger({ level: 'debug' });
14
15
 
@@ -56,7 +57,7 @@ export class CompilerWatcher {
56
57
  return [...ignores].toSorted().map(ignore => ignore.endsWith('/') ? ignore : `${ignore}/`);
57
58
  }
58
59
 
59
- #toCandidateEvent(action: CompilerWatchEvent['action'], file: string): CompilerWatchEventCandidate {
60
+ #toCandidateEvent({ action, file }: Pick<CompilerWatchEvent, 'action' | 'file'>): CompilerWatchEventCandidate {
60
61
  let entry = this.#state.getBySource(file);
61
62
  const mod = entry?.module ?? this.#state.manifestIndex.findModuleForArbitraryFile(file);
62
63
  if (mod && action === 'create' && !entry) {
@@ -69,19 +70,25 @@ export class CompilerWatcher {
69
70
  return { entry, file: entry?.sourceFile ?? file, action };
70
71
  }
71
72
 
72
- #isValidEvent(event: CompilerWatchEventCandidate): event is CompilerWatchEvent {
73
- const relativeFile = event.file.replace(`${this.#root}/`, '');
73
+ #isValidFile(file: string): boolean {
74
+ const relativeFile = file.replace(`${this.#root}/`, '');
74
75
  if (relativeFile === this.#watchCanary) {
75
76
  return false;
76
77
  } else if (relativeFile.startsWith('.')) {
77
78
  return false;
78
- } else if (!event.entry) {
79
- log.debug(`Skipping unknown file ${relativeFile}`);
79
+ }
80
+ return true;
81
+ }
82
+
83
+ #isValidEvent(event: CompilerWatchEventCandidate): event is CompilerWatchEvent {
84
+ if (!event.entry) {
85
+ log.debug(`Skipping unknown file ${event.file}`);
80
86
  return false;
81
87
  } else if (event.action === 'update' && !this.#state.checkIfSourceChanged(event.entry.sourceFile)) {
88
+ const relativeFile = event.file.replace(`${this.#root}/`, '');
82
89
  log.debug(`Skipping update, as contents unchanged ${relativeFile}`);
83
90
  return false;
84
- } else if (!CompilerUtil.validFile(ManifestModuleUtil.getFileType(relativeFile))) {
91
+ } else if (!CompilerUtil.validFile(ManifestModuleUtil.getFileType(event.file))) {
85
92
  return false;
86
93
  }
87
94
  return true;
@@ -168,10 +175,20 @@ export class CompilerWatcher {
168
175
  throw new CompilerReset('Package information changed');
169
176
  }
170
177
 
171
- const items = events
172
- .map(event => this.#toCandidateEvent(event.type, path.toPosix(event.path)))
178
+ // One event per file set
179
+ const filesChanged = events.map(e => ({ file: path.toPosix(e.path), action: e.type })).filter(e => this.#isValidFile(e.file));
180
+ if (filesChanged.length) {
181
+ EventUtil.sendEvent('file', { time: Date.now(), files: filesChanged });
182
+ }
183
+
184
+ const items = filesChanged
185
+ .map(event => this.#toCandidateEvent(event))
173
186
  .filter(event => this.#isValidEvent(event));
174
187
 
188
+ if (items.length === 0) {
189
+ return;
190
+ }
191
+
175
192
  try {
176
193
  await this.#reconcileManifestUpdates(items);
177
194
  } catch (manifestError) {
@@ -3,7 +3,7 @@ import fs from 'node:fs/promises';
3
3
 
4
4
  import type { ManifestContext } from '@travetto/manifest';
5
5
 
6
- import type { CompilerMode, CompilerServerInfo } from './types.ts';
6
+ import { isComplilerEventType, type CompilerMode, type CompilerServerInfo } from './types.ts';
7
7
  import { Log } from './log.ts';
8
8
  import { CompilerSetup } from './setup.ts';
9
9
  import { CompilerServer } from './server/server.ts';
@@ -72,9 +72,8 @@ export const main = (ctx: ManifestContext) => {
72
72
 
73
73
  /** Stream events */
74
74
  events: async (type: string, handler: (event: unknown) => unknown): Promise<void> => {
75
- if (type === 'change' || type === 'log' || type === 'progress' || type === 'state' || type === 'all') {
76
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
77
- for await (const event of client.fetchEvents(type as 'change')) { await handler(event); }
75
+ if (isComplilerEventType(type)) {
76
+ for await (const event of client.fetchEvents(type)) { await handler(event); }
78
77
  } else {
79
78
  throw new Error(`Unknown event type: ${type}`);
80
79
  }
@@ -4,7 +4,7 @@ import http, { Agent } from 'node:http';
4
4
 
5
5
  import { ManifestContext } from '@travetto/manifest';
6
6
 
7
- import type { CompilerEvent, CompilerEventType, CompilerServerInfo, CompilerStateType } from '../types.ts';
7
+ import type { CompilerEventPayload, CompilerEventType, CompilerServerInfo, CompilerStateType } from '../types.ts';
8
8
  import type { LogShape } from '../log.ts';
9
9
  import { CommonUtil } from '../util.ts';
10
10
  import { ProcessHandle } from './process-handle.ts';
@@ -91,12 +91,7 @@ export class CompilerClient {
91
91
  }
92
92
 
93
93
  /** Fetch compiler events */
94
- fetchEvents<
95
- V extends CompilerEventType,
96
- T extends (CompilerEvent & { type: V })['payload']
97
- >(type: V, config?: FetchEventsConfig<T>): AsyncIterable<T>;
98
- fetchEvents(type: 'all', config?: FetchEventsConfig<CompilerEvent>): AsyncIterable<CompilerEvent>;
99
- async * fetchEvents<T = unknown>(type: string, config: FetchEventsConfig<T> = {}): AsyncIterable<T> {
94
+ async * fetchEvents<V extends CompilerEventType, T extends CompilerEventPayload<V>>(type: V, config: FetchEventsConfig<T> = {}): AsyncIterable<T> {
100
95
  let info = await this.info();
101
96
  if (!info) {
102
97
  return;
@@ -4,7 +4,10 @@ import { setMaxListeners } from 'node:events';
4
4
 
5
5
  import type { ManifestContext } from '@travetto/manifest';
6
6
 
7
- import type { CompilerMode, CompilerProgressEvent, CompilerEvent, CompilerEventType, CompilerServerInfo } from '../types.ts';
7
+ import {
8
+ type CompilerMode, type CompilerProgressEvent, type CompilerEvent,
9
+ type CompilerEventType, type CompilerServerInfo, isComplilerEventType
10
+ } from '../types.ts';
8
11
  import { Log } from '../log.ts';
9
12
  import { CommonUtil } from '../util.ts';
10
13
  import { CompilerClient } from './client.ts';
@@ -20,7 +23,7 @@ export class CompilerServer {
20
23
  #ctx: ManifestContext;
21
24
  #server: http.Server;
22
25
  #listenersAll = new Set<http.ServerResponse>();
23
- #listeners: Partial<Record<CompilerEventType | 'all', Record<string, http.ServerResponse>>> = {};
26
+ #listeners: Partial<Record<CompilerEventType, Record<string, http.ServerResponse>>> = {};
24
27
  #shutdown = new AbortController();
25
28
  info: CompilerServerInfo;
26
29
  #client: CompilerClient;
@@ -98,7 +101,7 @@ export class CompilerServer {
98
101
  return output;
99
102
  }
100
103
 
101
- #addListener(type: CompilerEventType | 'all', response: http.ServerResponse): void {
104
+ #addListener(type: CompilerEventType, response: http.ServerResponse): void {
102
105
  response.writeHead(200);
103
106
  const id = `id_${Date.now()}_${Math.random()}`.replace('.', '1');
104
107
  (this.#listeners[type] ??= {})[id] = response;
@@ -109,7 +112,6 @@ export class CompilerServer {
109
112
  response.write('\n'); // Send at least one byte on listen
110
113
  }
111
114
 
112
- // Do not wait on it
113
115
  response.on('close', () => {
114
116
  delete this.#listeners[type]?.[id];
115
117
  this.#listenersAll.delete(response);
@@ -168,11 +170,10 @@ export class CompilerServer {
168
170
  let close = false;
169
171
  switch (action) {
170
172
  case 'event': {
171
- switch (subAction) {
172
- case 'change': case 'log': case 'progress': case 'state': case 'all':
173
- return this.#addListener(subAction, response);
174
- default: return;
173
+ if (isComplilerEventType(subAction)) {
174
+ this.#addListener(subAction, response);
175
175
  }
176
+ return;
176
177
  }
177
178
  case 'clean': out = await this.#clean(); break;
178
179
  case 'stop': out = JSON.stringify({ closing: true }); close = true; break;
package/support/types.ts CHANGED
@@ -8,14 +8,18 @@ export type CompilerLogLevel = 'info' | 'debug' | 'warn' | 'error';
8
8
  export type CompilerLogEvent = { level: CompilerLogLevel, message: string, time?: number, args?: unknown[], scope?: string };
9
9
  export type CompilerProgressEvent = { idx: number, total: number, message: string, operation: 'compile', complete?: boolean };
10
10
  export type CompilerStateEvent = { state: CompilerStateType, extra?: Record<string, unknown> };
11
+ export type FileChangeEvent = { files: { file: string, action: ChangeEventType }[], time: number };
11
12
 
12
13
  export type CompilerEvent =
14
+ { type: 'file', payload: FileChangeEvent } |
13
15
  { type: 'change', payload: CompilerChangeEvent } |
14
16
  { type: 'log', payload: CompilerLogEvent } |
15
17
  { type: 'progress', payload: CompilerProgressEvent } |
16
- { type: 'state', payload: CompilerStateEvent };
18
+ { type: 'state', payload: CompilerStateEvent } |
19
+ { type: 'all', payload: unknown };
17
20
 
18
21
  export type CompilerEventType = CompilerEvent['type'];
22
+ export type CompilerEventPayload<V> = (CompilerEvent & { type: V })['payload'];
19
23
 
20
24
  export type CompilerServerInfo = {
21
25
  path: string;
@@ -27,3 +31,7 @@ export type CompilerServerInfo = {
27
31
  url: string;
28
32
  env?: Record<string, string>;
29
33
  };
34
+
35
+ const VALID_EVENT_TYPES = new Set<CompilerEventType>(['change', 'log', 'progress', 'state', 'all', 'file']);
36
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
37
+ export const isComplilerEventType = (value: string): value is CompilerEventType => VALID_EVENT_TYPES.has(value as CompilerEventType);
package/support/util.ts CHANGED
@@ -38,12 +38,12 @@ export class CommonUtil {
38
38
  const kill = (): void => controller.abort();
39
39
  parent.addEventListener('abort', kill);
40
40
 
41
- const comp = input(controller.signal);
41
+ const stream = 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 event of comp) {
46
+ for await (const event of stream) {
47
47
  yield event;
48
48
  if (shouldRestart(event)) {
49
49
  log.debug('Restarting stream');