@travetto/registry 5.0.0-rc.3 → 5.0.0-rc.4

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
@@ -82,32 +82,30 @@ As mentioned in [Manifest](https://github.com/travetto/travetto/tree/main/module
82
82
  **Code: Sample Class Diffing**
83
83
  ```typescript
84
84
 
85
- #handleFileChanges(file: string, classes: Class[] = []): void {
85
+ #handleFileChanges(importFile: string, classes: Class[] = []): number {
86
86
  const next = new Map<string, Class>(classes.map(cls => [cls.Ⲑid, cls] as const));
87
87
 
88
88
  let prev = new Map<string, Class>();
89
- if (this.#classes.has(file)) {
90
- prev = new Map(this.#classes.get(file)!.entries());
89
+ if (this.#classes.has(importFile)) {
90
+ prev = new Map(this.#classes.get(importFile)!.entries());
91
91
  }
92
92
 
93
93
  const keys = new Set([...Array.from(prev.keys()), ...Array.from(next.keys())]);
94
94
 
95
- if (!this.#classes.has(file)) {
96
- this.#classes.set(file, new Map());
95
+ if (!this.#classes.has(importFile)) {
96
+ this.#classes.set(importFile, new Map());
97
97
  }
98
98
 
99
99
  let changes = 0;
100
100
 
101
- /**
102
- * Determine delta based on the various classes (if being added, removed or updated)
103
- */
101
+ // Determine delta based on the various classes (if being added, removed or updated)
104
102
  for (const k of keys) {
105
103
  if (!next.has(k)) {
106
104
  changes += 1;
107
105
  this.emit({ type: 'removing', prev: prev.get(k)! });
108
- this.#classes.get(file)!.delete(k);
106
+ this.#classes.get(importFile)!.delete(k);
109
107
  } else {
110
- this.#classes.get(file)!.set(k, next.get(k)!);
108
+ this.#classes.get(importFile)!.set(k, next.get(k)!);
111
109
  if (!prev.has(k)) {
112
110
  changes += 1;
113
111
  this.emit({ type: 'added', curr: next.get(k)! });
@@ -121,8 +119,6 @@ As mentioned in [Manifest](https://github.com/travetto/travetto/tree/main/module
121
119
  }
122
120
  }
123
121
  }
124
- if (!changes) {
125
- this.#emitter.emit('unchanged-file', file);
126
- }
122
+ return changes;
127
123
  }
128
124
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/registry",
3
- "version": "5.0.0-rc.3",
3
+ "version": "5.0.0-rc.4",
4
4
  "description": "Patterns and utilities for handling registration of metadata and functionality for run-time use",
5
5
  "keywords": [
6
6
  "ast-transformations",
@@ -27,11 +27,11 @@
27
27
  "directory": "module/registry"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/runtime": "^5.0.0-rc.3"
30
+ "@travetto/runtime": "^5.0.0-rc.4"
31
31
  },
32
32
  "peerDependencies": {
33
- "@travetto/cli": "^5.0.0-rc.3",
34
- "@travetto/transformer": "^5.0.0-rc.2"
33
+ "@travetto/cli": "^5.0.0-rc.4",
34
+ "@travetto/transformer": "^5.0.0-rc.3"
35
35
  },
36
36
  "peerDependenciesMeta": {
37
37
  "@travetto/transformer": {
package/src/proxy.ts CHANGED
@@ -1,5 +1,5 @@
1
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
- type ConcreteClass<T = any> = new (...args: any[]) => T;
1
+ import { ConcreteClass } from '@travetto/runtime';
2
+
3
3
  const ProxyTargetⲐ = Symbol.for('@travetto/runtime:proxy-target');
4
4
 
5
5
  const AsyncGeneratorFunction = Object.getPrototypeOf(async function* () { });
@@ -1,11 +1,10 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
 
3
3
  import { type FindConfig } from '@travetto/manifest';
4
- import { Class, Env, Runtime, RuntimeIndex, describeFunction } from '@travetto/runtime';
4
+ import { Class, Env, Runtime, RuntimeIndex, describeFunction, flushPendingFunctions } from '@travetto/runtime';
5
5
 
6
6
  import { DynamicFileLoader } from '../internal/file-loader';
7
7
  import { ChangeSource, ChangeEvent, ChangeHandler } from '../types';
8
- import { PendingRegister } from '../decorator';
9
8
 
10
9
  const moduleFindConfig: FindConfig = {
11
10
  module: (m) => {
@@ -18,6 +17,10 @@ const moduleFindConfig: FindConfig = {
18
17
  folder: f => f === 'src' || f === '$index'
19
18
  };
20
19
 
20
+ function isClass(cls: Function): cls is Class {
21
+ return !!describeFunction(cls).class;
22
+ }
23
+
21
24
  /**
22
25
  * A class change source. Meant to be hooked into the
23
26
  * compiler as a way to listen to changes via the compiler
@@ -37,48 +40,43 @@ export class ClassSource implements ChangeSource<Class> {
37
40
  * Flush classes
38
41
  */
39
42
  #flush(): void {
40
- for (const [file, classes] of PendingRegister.flush()) {
41
- if (!classes || !classes.length) {
42
- continue;
43
- }
44
- this.#classes.set(file, new Map());
45
- for (const cls of classes) {
46
- const src = Runtime.getSource(cls);
47
- this.#classes.get(src)!.set(cls.Ⲑid, cls);
48
- this.emit({ type: 'added', curr: cls });
43
+ for (const cls of flushPendingFunctions().filter(isClass)) {
44
+ const src = Runtime.getImport(cls);
45
+ if (!this.#classes.has(src)) {
46
+ this.#classes.set(src, new Map());
49
47
  }
48
+ this.#classes.get(src)!.set(cls.Ⲑid, cls);
49
+ this.emit({ type: 'added', curr: cls });
50
50
  }
51
51
  }
52
52
 
53
53
  /**
54
- * Listen for a single file, and process all the classes within
54
+ * Process changes for a single file, looking for add/remove/update of classes
55
55
  */
56
- #handleFileChanges(file: string, classes: Class[] = []): void {
56
+ #handleFileChanges(importFile: string, classes: Class[] = []): number {
57
57
  const next = new Map<string, Class>(classes.map(cls => [cls.Ⲑid, cls] as const));
58
58
 
59
59
  let prev = new Map<string, Class>();
60
- if (this.#classes.has(file)) {
61
- prev = new Map(this.#classes.get(file)!.entries());
60
+ if (this.#classes.has(importFile)) {
61
+ prev = new Map(this.#classes.get(importFile)!.entries());
62
62
  }
63
63
 
64
64
  const keys = new Set([...Array.from(prev.keys()), ...Array.from(next.keys())]);
65
65
 
66
- if (!this.#classes.has(file)) {
67
- this.#classes.set(file, new Map());
66
+ if (!this.#classes.has(importFile)) {
67
+ this.#classes.set(importFile, new Map());
68
68
  }
69
69
 
70
70
  let changes = 0;
71
71
 
72
- /**
73
- * Determine delta based on the various classes (if being added, removed or updated)
74
- */
72
+ // Determine delta based on the various classes (if being added, removed or updated)
75
73
  for (const k of keys) {
76
74
  if (!next.has(k)) {
77
75
  changes += 1;
78
76
  this.emit({ type: 'removing', prev: prev.get(k)! });
79
- this.#classes.get(file)!.delete(k);
77
+ this.#classes.get(importFile)!.delete(k);
80
78
  } else {
81
- this.#classes.get(file)!.set(k, next.get(k)!);
79
+ this.#classes.get(importFile)!.set(k, next.get(k)!);
82
80
  if (!prev.has(k)) {
83
81
  changes += 1;
84
82
  this.emit({ type: 'added', curr: next.get(k)! });
@@ -92,8 +90,26 @@ export class ClassSource implements ChangeSource<Class> {
92
90
  }
93
91
  }
94
92
  }
95
- if (!changes) {
96
- this.#emitter.emit('unchanged-file', file);
93
+ return changes;
94
+ }
95
+
96
+ /**
97
+ * Process all class changes
98
+ */
99
+ #handleChanges(classes: Class[] = []): void {
100
+ const classesByFile = new Map<string, Class[]>();
101
+ for (const el of classes) {
102
+ const imp = Runtime.getImport(el);
103
+ if (!classesByFile.has(imp)) {
104
+ classesByFile.set(imp, []);
105
+ }
106
+ classesByFile.get(imp)!.push(el);
107
+ }
108
+
109
+ for (const [imp, els] of classesByFile.entries()) {
110
+ if (!this.#handleFileChanges(imp, els)) {
111
+ this.#emitter.emit('unchanged-import', imp);
112
+ }
97
113
  }
98
114
  }
99
115
 
@@ -113,9 +129,8 @@ export class ClassSource implements ChangeSource<Class> {
113
129
  async init(): Promise<void> {
114
130
  if (Runtime.dynamic) {
115
131
  DynamicFileLoader.onLoadEvent(ev => {
116
- for (const [file, classes] of PendingRegister.flush(true)) {
117
- this.#handleFileChanges(file, classes);
118
- }
132
+ this.#handleChanges(flushPendingFunctions().filter(isClass));
133
+
119
134
  if (ev.action === 'create') {
120
135
  this.#flush();
121
136
  }
@@ -140,9 +155,9 @@ export class ClassSource implements ChangeSource<Class> {
140
155
  }
141
156
 
142
157
  /**
143
- * Add callback for when a file is changed, but emits no class changes
158
+ * Add callback for when a import is changed, but emits no class changes
144
159
  */
145
- onNonClassChanges(callback: (file: string) => void): void {
146
- this.#emitter.on('unchanged-file', callback);
160
+ onNonClassChanges(callback: (imp: string) => void): void {
161
+ this.#emitter.on('unchanged-import', callback);
147
162
  }
148
163
  }
package/src/decorator.ts DELETED
@@ -1,43 +0,0 @@
1
- import { Class, Runtime } from '@travetto/runtime';
2
-
3
- /**
4
- * Register a class as pending
5
- */
6
- class $PendingRegister {
7
- map = new Map<string, Class[]>();
8
- ordered: [string, Class[]][] = [];
9
-
10
- /**
11
- * Register class as pending
12
- */
13
- add(cls: Class): void {
14
- const src = Runtime.getSource(cls);
15
- if (!this.map.has(src)) {
16
- const sub: Class[] = [];
17
- this.map.set(src, sub);
18
- this.ordered.push([src, sub]);
19
- }
20
- this.map.get(src)!.push(cls);
21
- }
22
-
23
- /**
24
- * Clear pending classes
25
- */
26
- flush(log?: boolean): [string, Class[]][] {
27
- if (log) {
28
- console.debug('Pending changes', { changes: this.ordered.map(([, x]) => x.map(y => y.Ⲑid)) });
29
- }
30
- const out = this.ordered.slice(0);
31
- this.map.clear();
32
- this.ordered = [];
33
- return out;
34
- }
35
- }
36
-
37
- export const PendingRegister = new $PendingRegister();
38
-
39
- /**
40
- * Decorator to track class as pending
41
- */
42
- export const Register = () =>
43
- (target: Class): void => PendingRegister.add(target);
@@ -1,38 +0,0 @@
1
- import ts from 'typescript';
2
-
3
- import { TransformerState, AfterClass, DecoratorUtil } from '@travetto/transformer';
4
-
5
- const REGISTER_MOD = '@travetto/registry/src/decorator';
6
- const SKIP_SRC = /^@travetto\/(runtime|manifest)\/(src|support)/;
7
- const SKIP_FUNCTION = /^@travetto\/registry\/src\/function/;
8
-
9
- /**
10
- * Registration of all classes to support the registry
11
- */
12
- export class RegisterTransformer {
13
-
14
- /**
15
- * After visiting each class, register all the collected metadata
16
- */
17
- @AfterClass()
18
- static registerClass(state: TransformerState, node: ts.ClassDeclaration): ts.ClassDeclaration {
19
- if (
20
- state.importName === REGISTER_MOD ||
21
- SKIP_SRC.test(state.importName) ||
22
- SKIP_FUNCTION.test(state.importName)
23
- ) { // Cannot process self
24
- return node;
25
- }
26
-
27
- return state.factory.updateClassDeclaration(
28
- node,
29
- DecoratorUtil.spliceDecorators(
30
- node, undefined, [state.createDecorator(REGISTER_MOD, 'Register')], 0
31
- ),
32
- node.name,
33
- node.typeParameters,
34
- node.heritageClauses,
35
- node.members
36
- );
37
- }
38
- }