@travetto/registry 3.0.0-rc.4 → 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 +4 -5
- package/{index.ts → __index__.ts} +0 -1
- package/package.json +14 -8
- package/src/decorator.ts +8 -42
- package/src/registry.ts +8 -25
- package/src/service/metadata.ts +17 -17
- package/src/service/root.ts +0 -7
- package/src/source/class-source.ts +29 -24
- package/src/source/method-source.ts +5 -4
- package/src/types.ts +0 -1
- package/support/transformer.register.ts +39 -0
- package/src/typings.d.ts +0 -12
- package/support/phase.init.ts +0 -11
- package/support/phase.reset.ts +0 -11
- package/support/transformer.class-metadata.ts +0 -116
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/
|
|
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 [
|
|
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 [
|
|
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
|
-
*
|
|
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;
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/registry",
|
|
3
|
-
"
|
|
4
|
-
"version": "3.0.0-rc.4",
|
|
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
|
-
"
|
|
20
|
+
"__index__.ts",
|
|
22
21
|
"src",
|
|
23
22
|
"support"
|
|
24
23
|
],
|
|
25
|
-
"main": "
|
|
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/
|
|
32
|
-
"@travetto/transformer": "^3.0.0-rc.4"
|
|
30
|
+
"@travetto/base": "^3.0.0-rc.4"
|
|
33
31
|
},
|
|
34
|
-
"
|
|
35
|
-
"@travetto/
|
|
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 {
|
|
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
|
-
|
|
15
|
+
const src = RootIndex.getFunctionMetadata(cls)!.source;
|
|
16
|
+
if (!this.map.has(src)) {
|
|
48
17
|
const sub: Class[] = [];
|
|
49
|
-
this.map.set(
|
|
50
|
-
this.ordered.push([
|
|
18
|
+
this.map.set(src, sub);
|
|
19
|
+
this.ordered.push([src, sub]);
|
|
51
20
|
}
|
|
52
|
-
this.map.get(
|
|
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
|
|
72
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
}
|
package/src/service/metadata.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Class,
|
|
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
|
|
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
|
|
135
|
-
this.pendingFields.get(cls
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
161
|
-
console.debug('Installing', { service: this.constructor.name, id: cls
|
|
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
|
|
164
|
-
this.pending.delete(cls
|
|
163
|
+
this.pendingFields.delete(cls.Ⲑid);
|
|
164
|
+
this.pending.delete(cls.Ⲑid);
|
|
165
165
|
|
|
166
|
-
this.entries.set(cls
|
|
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
|
|
176
|
-
console.debug('Uninstalling', { service: this.constructor.name, id: cls
|
|
177
|
-
this.expired.set(cls
|
|
178
|
-
this.entries.delete(cls
|
|
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
|
|
183
|
+
process.nextTick(() => this.expired.delete(cls.Ⲑid));
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
|
package/src/service/root.ts
CHANGED
|
@@ -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 {
|
|
4
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
45
|
-
const next = new Map<string, Class>(classes.map(cls => [cls
|
|
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
|
|
70
|
-
|
|
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
|
-
*
|
|
77
|
+
* Handle when a file watch event happens
|
|
78
78
|
*/
|
|
79
|
-
|
|
80
|
-
console.debug('Pending changes', { changes: PendingRegister.ordered.map(([, x]) => x.map(y => y
|
|
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
|
|
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
|
|
31
|
-
const prev = e.prev
|
|
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
|
@@ -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
|
-
}
|
package/support/phase.init.ts
DELETED
|
@@ -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
|
-
};
|
package/support/phase.reset.ts
DELETED
|
@@ -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
|
-
}
|