@travetto/registry 3.0.0-rc.3 → 3.0.0-rc.6

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
@@ -1,5 +1,5 @@
1
1
  <!-- This file was generated by @travetto/doc and should not be modified directly -->
2
- <!-- Please modify https://github.com/travetto/travetto/tree/main/module/registry/doc.ts and execute "npx trv doc" to rebuild -->
2
+ <!-- Please modify https://github.com/travetto/travetto/tree/main/module/registry/DOC.ts and execute "npx trv doc" to rebuild -->
3
3
  # Registry
4
4
  ## Patterns and utilities for handling registration of metadata and functionality for run-time use
5
5
 
@@ -59,17 +59,16 @@ export class SampleRegistry extends MetadataRegistry<Group, Child> {
59
59
  }
60
60
  ```
61
61
 
62
- The registry is a [MetadataRegistry](https://github.com/travetto/travetto/tree/main/module/registry/src/service/metadata.ts#L13) that similar to the [SchemaRegistry](https://github.com/travetto/travetto/tree/main/module/schema/src/service/registry.ts) and the [DependencyRegistry](https://github.com/travetto/travetto/tree/main/module/di/src/registry.ts).
62
+ The registry is a [MetadataRegistry](https://github.com/travetto/travetto/tree/main/module/registry/src/service/metadata.ts#L13) that similar to the [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.")'s Schema registry and [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support.")'s Dependency registry.
63
63
 
64
64
  ### Live Flow
65
65
  At runtime, the registry is designed to listen for changes and to propagate the changes as necessary. In many cases the same file is handled by multiple registries.
66
66
 
67
- As the [Compiler](https://github.com/travetto/travetto/tree/main/module/compiler#readme "Node-integration of Typescript Compiler with advanced functionality for detecting changes in classes and methods.") notifies that a file has been changed and recompiled, the [RootRegistry](https://github.com/travetto/travetto/tree/main/module/registry/src/service/root.ts) will pick it up, and process it accordingly.
67
+ As the [DynamicFileLoader](https://github.com/travetto/travetto/tree/main/module/base/src/internal/file-loader.ts) notifies that a file has been changed, the [RootRegistry](https://github.com/travetto/travetto/tree/main/module/registry/src/service/root.ts) will pick it up, and process it accordingly.
68
68
 
69
69
  ## Supporting Metadata
70
70
 
71
71
  For the registries to work properly, metadata needs to be collected about files and classes to uniquely identify them, especially across file reloads for the live flow. To achieve this, every `class` is decorated with additional fields. The data that is added is:
72
72
 
73
73
 
74
- * `ᚕfile` denotes the fully qualified path name of the class
75
- * `ᚕid` represents a computed id that is tied to the file/class combination;
74
+ * `Ⲑid` represents a computed id that is tied to the file/class combination;
@@ -1,4 +1,3 @@
1
- /// <reference path="./src/typings.d.ts" />
2
1
  export * from './src/registry';
3
2
  export * from './src/service/metadata';
4
3
  export * from './src/service/root';
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/registry",
3
- "displayName": "Registry",
4
- "version": "3.0.0-rc.3",
3
+ "version": "3.0.0-rc.6",
5
4
  "description": "Patterns and utilities for handling registration of metadata and functionality for run-time use",
6
5
  "keywords": [
7
6
  "ast-transformations",
@@ -18,21 +17,28 @@
18
17
  "name": "Travetto Framework"
19
18
  },
20
19
  "files": [
21
- "index.ts",
20
+ "__index__.ts",
22
21
  "src",
23
22
  "support"
24
23
  ],
25
- "main": "index.ts",
24
+ "main": "__index__.ts",
26
25
  "repository": {
27
26
  "url": "https://github.com/travetto/travetto.git",
28
27
  "directory": "module/registry"
29
28
  },
30
29
  "dependencies": {
31
- "@travetto/compiler": "^3.0.0-rc.3",
32
- "@travetto/transformer": "^3.0.0-rc.3"
30
+ "@travetto/base": "^3.0.0-rc.4"
33
31
  },
34
- "docDependencies": {
35
- "@travetto/di": true
32
+ "peerDependencies": {
33
+ "@travetto/transformer": "^3.0.0-rc.6"
34
+ },
35
+ "peerDependenciesMeta": {
36
+ "@travetto/transformer": {
37
+ "optional": true
38
+ }
39
+ },
40
+ "travetto": {
41
+ "displayName": "Registry"
36
42
  },
37
43
  "publishConfig": {
38
44
  "access": "public"
package/src/decorator.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Class } from '@travetto/base';
2
- import { ModuleUtil } from '@travetto/boot/src/internal/module-util';
2
+ import { RootIndex } from '@travetto/manifest';
3
3
 
4
4
  /**
5
5
  * Register a class as pending
@@ -8,48 +8,17 @@ class $PendingRegister {
8
8
  map = new Map<string, Class[]>();
9
9
  ordered: [string, Class[]][] = [];
10
10
 
11
- /**
12
- * Initialize the meta data for the cls
13
- * @param cls Class
14
- * @param `ᚕfile` Filename
15
- * @param `ᚕhash` Hash of class contents
16
- * @param `ᚕmethods` Methods and their hashes
17
- * @param `ᚕabstract` Is the class abstract
18
- */
19
- initMeta(cls: Class, ᚕfile: string, ᚕhash: number, ᚕmethods: Record<string, { hash: number }>, ᚕabstract: boolean, ᚕsynthetic: boolean): boolean {
20
- const meta = {
21
- ᚕid: ModuleUtil.getId(ᚕfile, cls.name),
22
- ᚕfile,
23
- ᚕhash,
24
- ᚕmethods,
25
- ᚕabstract,
26
- ᚕsynthetic,
27
- };
28
-
29
- const keys = [...Object.keys(meta)];
30
- Object.defineProperties(cls, keys.reduce<Partial<Record<keyof typeof meta, PropertyDescriptor>>>((all, k) => {
31
- all[k] = {
32
- value: meta[k],
33
- enumerable: false,
34
- configurable: false,
35
- writable: false
36
- };
37
- return all;
38
- }, {}));
39
-
40
- return true;
41
- }
42
-
43
11
  /**
44
12
  * Register class as pending
45
13
  */
46
14
  add(cls: Class): void {
47
- if (!this.map.has(cls.ᚕfile)) {
15
+ const src = RootIndex.getFunctionMetadata(cls)!.source;
16
+ if (!this.map.has(src)) {
48
17
  const sub: Class[] = [];
49
- this.map.set(cls.ᚕfile, sub);
50
- this.ordered.push([cls.ᚕfile, sub]);
18
+ this.map.set(src, sub);
19
+ this.ordered.push([src, sub]);
51
20
  }
52
- this.map.get(cls.ᚕfile)!.push(cls);
21
+ this.map.get(src)!.push(cls);
53
22
  }
54
23
 
55
24
  /**
@@ -68,8 +37,5 @@ export const PendingRegister = new $PendingRegister();
68
37
  /**
69
38
  * Decorator to track class as pending
70
39
  */
71
- export function Register() {
72
- return (target: Class): void => PendingRegister.add(target);
73
- }
74
-
75
- Register.initMeta = PendingRegister.initMeta;
40
+ export const Register = () =>
41
+ (target: Class): void => PendingRegister.add(target);
package/src/registry.ts CHANGED
@@ -50,28 +50,20 @@ export abstract class Registry implements ChangeSource<Class> {
50
50
  }
51
51
  }
52
52
 
53
- /**
54
- * Reset parents
55
- */
56
- protected resetParents(): void {
57
- for (const parent of this.#parents) {
58
- parent.reset();
59
- }
60
- }
61
-
62
53
  /**
63
54
  * Run initialization
64
55
  */
65
56
  async #runInit(): Promise<void> {
66
57
  try {
67
58
  this.#resolved = false;
68
- console.debug('Initializing', { id: this.constructor.ᚕid, uid: this.#uid });
59
+ console.debug('Initializing', { id: this.constructor.Ⲑid, uid: this.#uid });
69
60
 
70
61
  // Handle top level when dealing with non-registry
71
62
  const waitFor = this.#parents.filter(x => !(x instanceof Registry));
72
63
  await Promise.all(waitFor.map(x => x.init()));
73
64
 
74
65
  const classes = await this.initialInstall();
66
+
75
67
  if (classes) {
76
68
  for (const cls of classes) {
77
69
  this.install(cls, { type: 'added', curr: cls });
@@ -79,8 +71,6 @@ export abstract class Registry implements ChangeSource<Class> {
79
71
  }
80
72
 
81
73
  await Promise.all(this.#dependents.map(x => x.init()));
82
-
83
- console.debug('Initialized', { id: this.constructor.ᚕid, uid: this.#uid });
84
74
  } finally {
85
75
  this.#resolved = true;
86
76
  }
@@ -110,7 +100,7 @@ export abstract class Registry implements ChangeSource<Class> {
110
100
  * Initialize, with a built-in latch to prevent concurrent initializations
111
101
  */
112
102
  async init(): Promise<unknown> {
113
- console.debug('Trying to initialize', { id: this.constructor.ᚕid, uid: this.#uid, initialized: !!this.#initialized });
103
+ console.debug('Trying to initialize', { id: this.constructor.Ⲑid, uid: this.#uid, initialized: !!this.#initialized });
114
104
 
115
105
  if (!this.#initialized) {
116
106
  this.#initialized = this.#runInit();
@@ -118,6 +108,10 @@ export abstract class Registry implements ChangeSource<Class> {
118
108
  return this.#initialized;
119
109
  }
120
110
 
111
+ parent<T extends ChangeSource<Class>>(type: Class<T>): T | undefined {
112
+ return this.#parents.find((dep: unknown): dep is T => dep instanceof type);
113
+ }
114
+
121
115
  /**
122
116
  * When an installation event occurs
123
117
  */
@@ -156,7 +150,7 @@ export abstract class Registry implements ChangeSource<Class> {
156
150
  * Listen for events from the parent
157
151
  */
158
152
  onEvent(event: ChangeEvent<Class>): void {
159
- console.debug('Received', { id: this.constructor.ᚕid, type: event.type, targetId: (event.curr ?? event.prev)!.ᚕid });
153
+ console.debug('Received', { id: this.constructor.Ⲑid, type: event.type, targetId: (event.curr ?? event.prev)!.Ⲑid });
160
154
 
161
155
  switch (event.type) {
162
156
  case 'removing':
@@ -208,15 +202,4 @@ export abstract class Registry implements ChangeSource<Class> {
208
202
  onReset(): void {
209
203
  this.#resolved = false;
210
204
  }
211
-
212
- /**
213
- * Reset entire registry
214
- */
215
- reset(): void {
216
- this.onReset();
217
- for (const des of this.#dependents) {
218
- des.reset();
219
- }
220
- this.#initialized = undefined;
221
- }
222
205
  }
@@ -1,10 +1,10 @@
1
- import { Class, Util } from '@travetto/base';
1
+ import { Class, DataUtil } from '@travetto/base';
2
2
 
3
3
  import { Registry } from '../registry';
4
4
  import { ChangeEvent } from '../types';
5
5
 
6
6
  function id(cls: string | Class): string {
7
- return cls && typeof cls !== 'string' ? cls.ᚕid : cls;
7
+ return cls && typeof cls !== 'string' ? cls.Ⲑid : cls;
8
8
  }
9
9
 
10
10
  /**
@@ -131,10 +131,10 @@ export abstract class MetadataRegistry<C extends { class: Class }, M = unknown,
131
131
  getOrCreatePendingField(cls: Class, field: F): Partial<M> {
132
132
  this.getOrCreatePending(cls);
133
133
 
134
- if (!this.pendingFields.get(cls.ᚕid)!.has(field)) {
135
- this.pendingFields.get(cls.ᚕid)!.set(field, this.createPendingField(cls, field));
134
+ if (!this.pendingFields.get(cls.Ⲑid)!.has(field)) {
135
+ this.pendingFields.get(cls.Ⲑid)!.set(field, this.createPendingField(cls, field));
136
136
  }
137
- return this.pendingFields.get(cls.ᚕid)!.get(field)!;
137
+ return this.pendingFields.get(cls.Ⲑid)!.get(field)!;
138
138
  }
139
139
 
140
140
  /**
@@ -142,7 +142,7 @@ export abstract class MetadataRegistry<C extends { class: Class }, M = unknown,
142
142
  */
143
143
  register(cls: Class, pConfig: Partial<C> = {}): void {
144
144
  const conf = this.getOrCreatePending(cls);
145
- Util.deepAssign(conf, pConfig);
145
+ DataUtil.deepAssign(conf, pConfig);
146
146
  }
147
147
 
148
148
  /**
@@ -150,20 +150,20 @@ export abstract class MetadataRegistry<C extends { class: Class }, M = unknown,
150
150
  */
151
151
  registerField(cls: Class, field: F, pConfig: Partial<M>): void {
152
152
  const conf = this.getOrCreatePendingField(cls, field);
153
- Util.deepAssign(conf, pConfig);
153
+ DataUtil.deepAssign(conf, pConfig);
154
154
  }
155
155
 
156
156
  /**
157
157
  * On an install event, finalize
158
158
  */
159
159
  onInstall(cls: Class, e: ChangeEvent<Class>): void {
160
- if (this.pending.has(cls.ᚕid) || this.pendingFields.has(cls.ᚕid)) {
161
- console.debug('Installing', { service: this.constructor.name, id: cls.ᚕid });
160
+ if (this.pending.has(cls.Ⲑid) || this.pendingFields.has(cls.Ⲑid)) {
161
+ console.debug('Installing', { service: this.constructor.name, id: cls.Ⲑid });
162
162
  const result = this.onInstallFinalize(cls);
163
- this.pendingFields.delete(cls.ᚕid);
164
- this.pending.delete(cls.ᚕid);
163
+ this.pendingFields.delete(cls.Ⲑid);
164
+ this.pending.delete(cls.Ⲑid);
165
165
 
166
- this.entries.set(cls.ᚕid, result);
166
+ this.entries.set(cls.Ⲑid, result);
167
167
  this.emit(e);
168
168
  }
169
169
  }
@@ -172,15 +172,15 @@ export abstract class MetadataRegistry<C extends { class: Class }, M = unknown,
172
172
  * On an uninstall event, remove
173
173
  */
174
174
  onUninstall(cls: Class, e: ChangeEvent<Class>): void {
175
- if (this.entries.has(cls.ᚕid)) {
176
- console.debug('Uninstalling', { service: this.constructor.name, id: cls.ᚕid });
177
- this.expired.set(cls.ᚕid, this.entries.get(cls.ᚕid)!);
178
- this.entries.delete(cls.ᚕid);
175
+ if (this.entries.has(cls.Ⲑid)) {
176
+ console.debug('Uninstalling', { service: this.constructor.name, id: cls.Ⲑid });
177
+ this.expired.set(cls.Ⲑid, this.entries.get(cls.Ⲑid)!);
178
+ this.entries.delete(cls.Ⲑid);
179
179
  this.onUninstallFinalize(cls);
180
180
  if (e.type === 'removing') {
181
181
  this.emit(e);
182
182
  }
183
- process.nextTick(() => this.expired.delete(cls.ᚕid));
183
+ process.nextTick(() => this.expired.delete(cls.Ⲑid));
184
184
  }
185
185
  }
186
186
 
@@ -19,13 +19,6 @@ class $RootRegistry extends Registry {
19
19
  await super.onEvent(e); // Process event, and
20
20
  this.emit(e); // Send to children
21
21
  }
22
-
23
- /**
24
- * Reset self and parents
25
- */
26
- override onReset(): void {
27
- this.resetParents();
28
- }
29
22
  }
30
23
 
31
24
  export const RootRegistry = new $RootRegistry();
@@ -1,7 +1,8 @@
1
1
  import { EventEmitter } from 'events';
2
2
 
3
- import { Class } from '@travetto/base';
4
- import { Compiler } from '@travetto/compiler';
3
+ import { RootIndex } from '@travetto/manifest';
4
+ import { Class, FileWatchEvent, GlobalEnv } from '@travetto/base';
5
+ import { DynamicFileLoader } from '@travetto/base/src/internal/file-loader';
5
6
 
6
7
  import { ChangeSource, ChangeEvent, ChangeHandler } from '../types';
7
8
  import { PendingRegister } from '../decorator';
@@ -16,12 +17,6 @@ export class ClassSource implements ChangeSource<Class> {
16
17
  #classes = new Map<string, Map<string, Class>>();
17
18
  #emitter = new EventEmitter();
18
19
 
19
- constructor() {
20
- Compiler
21
- .on('added', () => { this.processFiles(); this.#flush(); })
22
- .on('changed', () => this.processFiles());
23
- }
24
-
25
20
  /**
26
21
  * Flush classes
27
22
  */
@@ -32,7 +27,8 @@ export class ClassSource implements ChangeSource<Class> {
32
27
  }
33
28
  this.#classes.set(file, new Map());
34
29
  for (const cls of classes) {
35
- this.#classes.get(cls.ᚕfile)!.set(cls.ᚕid, cls);
30
+ const src = RootIndex.getFunctionMetadata(cls)!.source;
31
+ this.#classes.get(src)!.set(cls.Ⲑid, cls);
36
32
  this.emit({ type: 'added', curr: cls });
37
33
  }
38
34
  }
@@ -41,8 +37,8 @@ export class ClassSource implements ChangeSource<Class> {
41
37
  /**
42
38
  * Listen for a single file, and process all the classes within
43
39
  */
44
- async #handleFileChanges(file: string, classes: Class[] = []): Promise<void> {
45
- const next = new Map<string, Class>(classes.map(cls => [cls.ᚕid, cls] as const));
40
+ #handleFileChanges(file: string, classes: Class[] = []): void {
41
+ const next = new Map<string, Class>(classes.map(cls => [cls.Ⲑid, cls] as const));
46
42
 
47
43
  let prev = new Map<string, Class>();
48
44
  if (this.#classes.has(file)) {
@@ -66,42 +62,51 @@ export class ClassSource implements ChangeSource<Class> {
66
62
  this.#classes.get(file)!.set(k, next.get(k)!);
67
63
  if (!prev.has(k)) {
68
64
  this.emit({ type: 'added', curr: next.get(k)! });
69
- } else if (prev.get(k)!.ᚕhash !== next.get(k)!.ᚕhash) {
70
- this.emit({ type: 'changed', curr: next.get(k)!, prev: prev.get(k) });
65
+ } else {
66
+ const prevMeta = RootIndex.getFunctionMetadataFromClass(prev.get(k));
67
+ const nextMeta = RootIndex.getFunctionMetadataFromClass(next.get(k));
68
+ if (prevMeta?.hash !== nextMeta?.hash) {
69
+ this.emit({ type: 'changed', curr: next.get(k)!, prev: prev.get(k) });
70
+ }
71
71
  }
72
72
  }
73
73
  }
74
74
  }
75
75
 
76
76
  /**
77
- * Flush all pending classes
77
+ * Handle when a file watch event happens
78
78
  */
79
- processFiles(): void {
80
- console.debug('Pending changes', { changes: PendingRegister.ordered.map(([, x]) => x.map(y => y.ᚕid)) });
79
+ async onLoadEvent(ev: FileWatchEvent): Promise<void> {
80
+ console.debug('Pending changes', { changes: PendingRegister.ordered.map(([, x]) => x.map(y => y.Ⲑid)) });
81
81
  for (const [file, classes] of PendingRegister.flush()) {
82
82
  this.#handleFileChanges(file, classes);
83
83
  }
84
+ if (ev.action === 'create') {
85
+ this.#flush();
86
+ }
84
87
  }
85
88
 
86
89
  /**
87
90
  * Emit a change event
88
91
  */
89
92
  emit(e: ChangeEvent<Class>): void {
90
- console.debug('Emitting change', { type: e.type, curr: e.curr?.ᚕid, prev: e.prev?.ᚕid });
93
+ console.debug('Emitting change', { type: e.type, curr: e.curr?.Ⲑid, prev: e.prev?.Ⲑid });
91
94
  this.#emitter.emit('change', e);
92
95
  }
93
96
 
94
- /**
95
- * Clear all classes
96
- */
97
- reset(): void {
98
- this.#classes.clear();
99
- }
100
-
101
97
  /**
102
98
  * Initialize
103
99
  */
104
100
  async init(): Promise<void> {
101
+ if (GlobalEnv.dynamic) {
102
+ DynamicFileLoader.onLoadEvent(ev => this.onLoadEvent(ev));
103
+ await DynamicFileLoader.init();
104
+ }
105
+
106
+ // Ensure everything is loaded
107
+ await RootIndex.loadSource();
108
+
109
+ // Flush all load events
105
110
  this.#flush();
106
111
  }
107
112
 
@@ -1,5 +1,8 @@
1
1
  import { EventEmitter } from 'events';
2
+
2
3
  import { Class } from '@travetto/base';
4
+ import { RootIndex } from '@travetto/manifest';
5
+
3
6
  import { ChangeSource, ChangeEvent, ChangeHandler } from '../types';
4
7
 
5
8
  /**
@@ -27,8 +30,8 @@ export class MethodSource implements ChangeSource<[Class, Function]> {
27
30
  * On a class being emitted, check methods
28
31
  */
29
32
  onClassEvent(e: ChangeEvent<Class>): void {
30
- const next = e.curr?.ᚕmethods ?? {};
31
- const prev = e.prev?.ᚕmethods ?? {};
33
+ const next = RootIndex.getFunctionMetadataFromClass(e.curr!)?.methods ?? {};
34
+ const prev = RootIndex.getFunctionMetadataFromClass(e.prev!)?.methods ?? {};
32
35
 
33
36
  /**
34
37
  * Go through each method, comparing hashes. To see added/removed and changed
@@ -55,6 +58,4 @@ export class MethodSource implements ChangeSource<[Class, Function]> {
55
58
  this.#emitter.on('change', callback);
56
59
  return this;
57
60
  }
58
-
59
- reset(): void { }
60
61
  }
package/src/types.ts CHANGED
@@ -18,5 +18,4 @@ export type ChangeHandler<T> = (e: ChangeEvent<T>) => unknown;
18
18
  export interface ChangeSource<T> {
19
19
  init(): Promise<unknown>;
20
20
  on(callback: ChangeHandler<T>): void;
21
- reset(): void;
22
21
  }
@@ -0,0 +1,39 @@
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 BASE_MOD_SRC = '@travetto/base/src';
7
+ const MANIFEST_MOD = '@travetto/manifest';
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 (state.importName === REGISTER_MOD ||
20
+ (
21
+ state.importName.startsWith(BASE_MOD_SRC) ||
22
+ state.importName.startsWith(MANIFEST_MOD)
23
+ )
24
+ ) { // Cannot process self
25
+ return node;
26
+ }
27
+
28
+ return state.factory.updateClassDeclaration(
29
+ node,
30
+ DecoratorUtil.spliceDecorators(
31
+ node, undefined, [state.createDecorator(REGISTER_MOD, 'Register')], 0
32
+ ),
33
+ node.name,
34
+ node.typeParameters,
35
+ node.heritageClauses,
36
+ node.members
37
+ );
38
+ }
39
+ }
package/src/typings.d.ts DELETED
@@ -1,12 +0,0 @@
1
- /**
2
- * Extensions to the Function interface, to provide common
3
- * information for all registered classes
4
- */
5
- declare interface Function {
6
- ᚕid: string;
7
- ᚕfile: string;
8
- ᚕhash: number;
9
- ᚕmethods: Record<string, { hash: number }>;
10
- ᚕsynthetic: boolean;
11
- ᚕabstract: boolean;
12
- }
@@ -1,11 +0,0 @@
1
- /**
2
- * Initialize the registry after all files have been loaded
3
- */
4
- export const init = {
5
- key: '@trv:registry/init',
6
- after: ['@trv:base/load'],
7
- action: async (): Promise<unknown> => {
8
- const { RootRegistry } = await import('../src/service/root');
9
- return RootRegistry.init();
10
- }
11
- };
@@ -1,11 +0,0 @@
1
- /**
2
- * Reset the registry, and it's children
3
- */
4
- export const init = {
5
- key: '@trv:registry/reset',
6
- before: ['@trv:compiler/reset'],
7
- action: async (): Promise<void> => {
8
- const { RootRegistry } = await import('../src/service/root');
9
- await RootRegistry.reset();
10
- }
11
- };
@@ -1,116 +0,0 @@
1
- import * as ts from 'typescript';
2
-
3
- import { SystemUtil } from '@travetto/boot/src/internal/system';
4
- import {
5
- TransformerState, OnMethod, OnClass, AfterClass,
6
- DecoratorUtil, TransformerId, AfterFunction, CoreUtil
7
- } from '@travetto/transformer';
8
-
9
- const REGISTER_MOD = '@travetto/registry/src/decorator';
10
-
11
- const methods = Symbol.for('@trv:registry/methods');
12
- const cls = Symbol.for('@trv:registry/class');
13
-
14
- interface RegisterInfo {
15
- [methods]?: {
16
- [key: string]: { hash: number };
17
- };
18
- [cls]?: number;
19
- }
20
-
21
- /**
22
- * Registration of all classes to support the registry
23
- */
24
- export class RegisterTransformer {
25
-
26
- static [TransformerId] = '@trv:registry';
27
-
28
- /**
29
- * Hash each class
30
- */
31
- @OnClass()
32
- static preprocessClass(state: TransformerState & RegisterInfo, node: ts.ClassDeclaration): ts.ClassDeclaration {
33
- state[cls] = SystemUtil.naiveHash(node.getText());
34
- return node;
35
- }
36
-
37
- /**
38
- * Hash each method
39
- */
40
- @OnMethod()
41
- static processMethod(state: TransformerState & RegisterInfo, node: ts.MethodDeclaration): ts.MethodDeclaration {
42
- if (ts.isIdentifier(node.name) && !CoreUtil.isAbstract(node) && ts.isClassDeclaration(node.parent)) {
43
- const hash = SystemUtil.naiveHash(node.getText());
44
- const conf = { hash };
45
- state[methods] ??= {};
46
- state[methods]![node.name.escapedText.toString()] = conf;
47
- }
48
- return node;
49
- }
50
-
51
- /**
52
- * After visiting each class, register all the collected metadata
53
- */
54
- @AfterClass()
55
- static registerClass(state: TransformerState & RegisterInfo, node: ts.ClassDeclaration): ts.ClassDeclaration {
56
- if (state.module === REGISTER_MOD) { // Cannot process self
57
- return node;
58
- }
59
-
60
- const ident = state.importDecorator(REGISTER_MOD, 'Register')!;
61
-
62
- const name = node.name?.escapedText.toString() ?? '';
63
-
64
- const meta = state.factory.createCallExpression(
65
- state.createAccess(ident, 'initMeta'),
66
- [],
67
- [
68
- state.createIdentifier(name),
69
- state.getFilenameAsSrc(),
70
- state.fromLiteral(state[cls]!),
71
- state.extendObjectLiteral(state[methods] || {}),
72
- state.fromLiteral(CoreUtil.isAbstract(node)),
73
- state.fromLiteral(name.endsWith(TransformerState.SYNTHETIC_EXT))
74
- ]
75
- );
76
-
77
- state[methods] = {};
78
-
79
- return state.factory.updateClassDeclaration(
80
- node,
81
- DecoratorUtil.spliceDecorators(
82
- node, undefined, [state.createDecorator(REGISTER_MOD, 'Register')], 0
83
- ),
84
- node.name,
85
- node.typeParameters,
86
- node.heritageClauses,
87
- [
88
- state.createStaticField('ᚕinit', meta),
89
- ...node.members
90
- ]
91
- );
92
- }
93
-
94
- /**
95
- * Give proper functions a file name
96
- */
97
- @AfterFunction()
98
- static registerFunction(state: TransformerState & RegisterInfo, node: ts.FunctionDeclaration | ts.FunctionExpression): typeof node {
99
- if (!ts.isFunctionDeclaration(node)) {
100
- return node;
101
- }
102
-
103
- if (node.name && /^[A-Z]/.test(node.name.escapedText.toString())) {
104
- // If we have a class like function
105
- state.addStatement(
106
- state.factory.createExpressionStatement(
107
- state.factory.createAssignment(
108
- state.createAccess(node.name, 'ᚕfile'),
109
- state.getFilenameAsSrc()
110
- )
111
- )
112
- );
113
- }
114
- return node;
115
- }
116
- }