@travetto/registry 3.0.0-rc.9 → 3.0.0
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 +61 -4
- package/package.json +3 -3
- package/src/service/root.ts +8 -0
- package/src/source/class-source.ts +18 -3
- package/src/source/method-source.ts +5 -5
package/README.md
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
**Install: @travetto/registry**
|
|
7
7
|
```bash
|
|
8
8
|
npm install @travetto/registry
|
|
9
|
+
|
|
10
|
+
# or
|
|
11
|
+
|
|
12
|
+
yarn add @travetto/registry
|
|
9
13
|
```
|
|
10
14
|
|
|
11
15
|
This module is the backbone for all "discovered" and "registered" behaviors within the framework. This is primarily used for building modules within the framework and not directly useful for application development.
|
|
@@ -39,12 +43,21 @@ interface Child {
|
|
|
39
43
|
method: Function;
|
|
40
44
|
}
|
|
41
45
|
|
|
46
|
+
function isComplete(o: Partial<Group>): o is Group {
|
|
47
|
+
return !!o;
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
export class SampleRegistry extends MetadataRegistry<Group, Child> {
|
|
43
51
|
/**
|
|
44
52
|
* Finalize class after all metadata is collected
|
|
45
53
|
*/
|
|
46
54
|
onInstallFinalize<T>(cls: Class<T>): Group {
|
|
47
|
-
|
|
55
|
+
const pending: Partial<Group> = this.getOrCreatePending(cls);
|
|
56
|
+
if (isComplete(pending)) {
|
|
57
|
+
return pending;
|
|
58
|
+
} else {
|
|
59
|
+
throw new Error('Invalid Group');
|
|
60
|
+
}
|
|
48
61
|
}
|
|
49
62
|
|
|
50
63
|
/**
|
|
@@ -68,7 +81,51 @@ As the [DynamicFileLoader](https://github.com/travetto/travetto/tree/main/module
|
|
|
68
81
|
|
|
69
82
|
## Supporting Metadata
|
|
70
83
|
|
|
71
|
-
|
|
84
|
+
As mentioned in [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching")'s readme, the framework produces hashes of methods, classes, and functions, to allow for detecting changes to individual parts of the codebase. During the live flow, various registries will inspect this information to determine if action should be taken.
|
|
72
85
|
|
|
73
|
-
|
|
74
|
-
|
|
86
|
+
**Code: Sample Class Diffing**
|
|
87
|
+
```typescript
|
|
88
|
+
#handleFileChanges(file: string, classes: Class[] = []): void {
|
|
89
|
+
const next = new Map<string, Class>(classes.map(cls => [cls.Ⲑid, cls] as const));
|
|
90
|
+
|
|
91
|
+
let prev = new Map<string, Class>();
|
|
92
|
+
if (this.#classes.has(file)) {
|
|
93
|
+
prev = new Map(this.#classes.get(file)!.entries());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const keys = new Set([...Array.from(prev.keys()), ...Array.from(next.keys())]);
|
|
97
|
+
|
|
98
|
+
if (!this.#classes.has(file)) {
|
|
99
|
+
this.#classes.set(file, new Map());
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let changes = 0;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Determine delta based on the various classes (if being added, removed or updated)
|
|
106
|
+
*/
|
|
107
|
+
for (const k of keys) {
|
|
108
|
+
if (!next.has(k)) {
|
|
109
|
+
changes += 1;
|
|
110
|
+
this.emit({ type: 'removing', prev: prev.get(k)! });
|
|
111
|
+
this.#classes.get(file)!.delete(k);
|
|
112
|
+
} else {
|
|
113
|
+
this.#classes.get(file)!.set(k, next.get(k)!);
|
|
114
|
+
if (!prev.has(k)) {
|
|
115
|
+
changes += 1;
|
|
116
|
+
this.emit({ type: 'added', curr: next.get(k)! });
|
|
117
|
+
} else {
|
|
118
|
+
const prevMeta = RootIndex.getFunctionMetadataFromClass(prev.get(k));
|
|
119
|
+
const nextMeta = RootIndex.getFunctionMetadataFromClass(next.get(k));
|
|
120
|
+
if (prevMeta?.hash !== nextMeta?.hash) {
|
|
121
|
+
changes += 1;
|
|
122
|
+
this.emit({ type: 'changed', curr: next.get(k)!, prev: prev.get(k) });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!changes) {
|
|
128
|
+
this.#emitter.emit('unchanged-file', file);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/registry",
|
|
3
|
-
"version": "3.0.0
|
|
3
|
+
"version": "3.0.0",
|
|
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,10 +27,10 @@
|
|
|
27
27
|
"directory": "module/registry"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@travetto/base": "^3.0.0
|
|
30
|
+
"@travetto/base": "^3.0.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@travetto/transformer": "^3.0.0
|
|
33
|
+
"@travetto/transformer": "^3.0.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|
|
36
36
|
"@travetto/transformer": {
|
package/src/service/root.ts
CHANGED
|
@@ -19,6 +19,14 @@ 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
|
+
* Registers a listener to be notified when a file changes, but no
|
|
25
|
+
* classes are modified
|
|
26
|
+
*/
|
|
27
|
+
onNonClassChanges(handler: (file: string) => void): void {
|
|
28
|
+
this.parent(ClassSource)!.onNonClassChanges(handler);
|
|
29
|
+
}
|
|
22
30
|
}
|
|
23
31
|
|
|
24
32
|
export const RootRegistry = new $RootRegistry();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
2
|
|
|
3
|
-
import { RootIndex } from '@travetto/manifest';
|
|
4
|
-
import { Class,
|
|
3
|
+
import { WatchEvent, RootIndex } from '@travetto/manifest';
|
|
4
|
+
import { Class, GlobalEnv } from '@travetto/base';
|
|
5
5
|
import { DynamicFileLoader } from '@travetto/base/src/internal/file-loader';
|
|
6
6
|
|
|
7
7
|
import { ChangeSource, ChangeEvent, ChangeHandler } from '../types';
|
|
@@ -51,32 +51,40 @@ export class ClassSource implements ChangeSource<Class> {
|
|
|
51
51
|
this.#classes.set(file, new Map());
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
let changes = 0;
|
|
55
|
+
|
|
54
56
|
/**
|
|
55
57
|
* Determine delta based on the various classes (if being added, removed or updated)
|
|
56
58
|
*/
|
|
57
59
|
for (const k of keys) {
|
|
58
60
|
if (!next.has(k)) {
|
|
61
|
+
changes += 1;
|
|
59
62
|
this.emit({ type: 'removing', prev: prev.get(k)! });
|
|
60
63
|
this.#classes.get(file)!.delete(k);
|
|
61
64
|
} else {
|
|
62
65
|
this.#classes.get(file)!.set(k, next.get(k)!);
|
|
63
66
|
if (!prev.has(k)) {
|
|
67
|
+
changes += 1;
|
|
64
68
|
this.emit({ type: 'added', curr: next.get(k)! });
|
|
65
69
|
} else {
|
|
66
70
|
const prevMeta = RootIndex.getFunctionMetadataFromClass(prev.get(k));
|
|
67
71
|
const nextMeta = RootIndex.getFunctionMetadataFromClass(next.get(k));
|
|
68
72
|
if (prevMeta?.hash !== nextMeta?.hash) {
|
|
73
|
+
changes += 1;
|
|
69
74
|
this.emit({ type: 'changed', curr: next.get(k)!, prev: prev.get(k) });
|
|
70
75
|
}
|
|
71
76
|
}
|
|
72
77
|
}
|
|
73
78
|
}
|
|
79
|
+
if (!changes) {
|
|
80
|
+
this.#emitter.emit('unchanged-file', file);
|
|
81
|
+
}
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
/**
|
|
77
85
|
* Handle when a file watch event happens
|
|
78
86
|
*/
|
|
79
|
-
async onLoadEvent(ev:
|
|
87
|
+
async onLoadEvent(ev: WatchEvent): Promise<void> {
|
|
80
88
|
console.debug('Pending changes', { changes: PendingRegister.ordered.map(([, x]) => x.map(y => y.Ⲑid)) });
|
|
81
89
|
for (const [file, classes] of PendingRegister.flush()) {
|
|
82
90
|
this.#handleFileChanges(file, classes);
|
|
@@ -116,4 +124,11 @@ export class ClassSource implements ChangeSource<Class> {
|
|
|
116
124
|
on(callback: ChangeHandler<Class>): void {
|
|
117
125
|
this.#emitter.on('change', callback);
|
|
118
126
|
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Add callback for when a file is changed, but emits no class changes
|
|
130
|
+
*/
|
|
131
|
+
onNonClassChanges(callback: (file: string) => void): void {
|
|
132
|
+
this.#emitter.on('unchanged-file', callback);
|
|
133
|
+
}
|
|
119
134
|
}
|
|
@@ -37,19 +37,19 @@ export class MethodSource implements ChangeSource<[Class, Function]> {
|
|
|
37
37
|
* Go through each method, comparing hashes. To see added/removed and changed
|
|
38
38
|
*/
|
|
39
39
|
for (const k of Object.keys(next)) {
|
|
40
|
-
if (!prev[k]) {
|
|
40
|
+
if (!prev[k] || !e.prev) {
|
|
41
41
|
this.emit({ type: 'added', curr: [e.curr!, e.curr!.prototype[k]] });
|
|
42
|
-
} else if (next[k].hash !== prev[k].hash) {
|
|
42
|
+
} else if (next[k].hash !== prev[k].hash && e.curr) {
|
|
43
43
|
// FIXME: Why is e.prev undefined sometimes?
|
|
44
|
-
this.emit({ type: 'changed', curr: [e.curr
|
|
44
|
+
this.emit({ type: 'changed', curr: [e.curr, e.curr.prototype[k]], prev: [e.prev, e.prev.prototype[k]] });
|
|
45
45
|
} else {
|
|
46
46
|
// Method Unchanged
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
for (const k of Object.keys(prev)) {
|
|
51
|
-
if (!next[k]) {
|
|
52
|
-
this.emit({ type: 'removing', prev: [e.prev
|
|
51
|
+
if (!next[k] && e.prev) {
|
|
52
|
+
this.emit({ type: 'removing', prev: [e.prev, e.prev.prototype[k]] });
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
}
|