@travetto/registry 3.4.2 → 4.0.0-rc.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 CHANGED
@@ -112,8 +112,8 @@ As mentioned in [Manifest](https://github.com/travetto/travetto/tree/main/module
112
112
  changes += 1;
113
113
  this.emit({ type: 'added', curr: next.get(k)! });
114
114
  } else {
115
- const prevMeta = RootIndex.getFunctionMetadataFromClass(prev.get(k));
116
- const nextMeta = RootIndex.getFunctionMetadataFromClass(next.get(k));
115
+ const prevMeta = RuntimeIndex.getFunctionMetadataFromClass(prev.get(k));
116
+ const nextMeta = RuntimeIndex.getFunctionMetadataFromClass(next.get(k));
117
117
  if (prevMeta?.hash !== nextMeta?.hash) {
118
118
  changes += 1;
119
119
  this.emit({ type: 'changed', curr: next.get(k)!, prev: prev.get(k) });
package/__index__.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './src/registry';
2
2
  export * from './src/service/metadata';
3
3
  export * from './src/service/root';
4
+ export * from './src/proxy';
4
5
  export * from './src/registry';
5
6
  export * from './src/source/class-source';
6
7
  export * from './src/source/method-source';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/registry",
3
- "version": "3.4.2",
3
+ "version": "4.0.0-rc.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,11 +27,11 @@
27
27
  "directory": "module/registry"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/base": "^3.4.2"
30
+ "@travetto/base": "^4.0.0-rc.0"
31
31
  },
32
32
  "peerDependencies": {
33
- "@travetto/cli": "^3.4.7",
34
- "@travetto/transformer": "^3.4.2"
33
+ "@travetto/cli": "^4.0.0-rc.0",
34
+ "@travetto/transformer": "^4.0.0-rc.0"
35
35
  },
36
36
  "peerDependenciesMeta": {
37
37
  "@travetto/transformer": {
package/src/decorator.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Class } from '@travetto/base';
2
- import { RootIndex } from '@travetto/manifest';
2
+ import { RuntimeIndex } from '@travetto/manifest';
3
3
 
4
4
  /**
5
5
  * Register a class as pending
@@ -12,7 +12,7 @@ class $PendingRegister {
12
12
  * Register class as pending
13
13
  */
14
14
  add(cls: Class): void {
15
- const src = RootIndex.getFunctionMetadata(cls)!.source;
15
+ const src = RuntimeIndex.getFunctionMetadata(cls)!.source;
16
16
  if (!this.map.has(src)) {
17
17
  const sub: Class[] = [];
18
18
  this.map.set(src, sub);
@@ -1,7 +1,9 @@
1
- import { Module } from 'module';
1
+ import { Module } from 'node:module';
2
2
 
3
- import { RootIndex, path } from '@travetto/manifest';
4
- import { RetargettingProxy, GlobalEnv } from '@travetto/base';
3
+ import { RuntimeIndex, path } from '@travetto/manifest';
4
+ import { Env } from '@travetto/base';
5
+
6
+ import { RetargettingProxy } from '../proxy';
5
7
 
6
8
  declare module 'module' {
7
9
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -30,7 +32,7 @@ export class DynamicCommonjsLoader {
30
32
  mod = moduleLoad.apply(null, [request, parent]);
31
33
  } catch (err: unknown) {
32
34
  const name = Module._resolveFilename!(request, parent);
33
- if (err instanceof Error && GlobalEnv.dynamic && !name.startsWith('test/')) {
35
+ if (err instanceof Error && Env.dynamic && !name.startsWith('test/')) {
34
36
  const errMsg = err.message;
35
37
  console.debug(`Unable to load ${name}: stubbing out with error proxy.`, errMsg);
36
38
  const e = (): never => { throw new Error(errMsg); };
@@ -42,7 +44,7 @@ export class DynamicCommonjsLoader {
42
44
 
43
45
  const fileName = Module._resolveFilename!(request, parent);
44
46
  // Only proxy local modules
45
- if (RootIndex.getModuleFromSource(fileName)?.local) {
47
+ if (RuntimeIndex.getModuleFromSource(fileName)?.local) {
46
48
  return proxyModuleLoad ? proxyModuleLoad(fileName, mod) : mod;
47
49
  } else {
48
50
  return mod;
@@ -1,30 +1,30 @@
1
- import { ManifestModuleUtil, RootIndex } from '@travetto/manifest';
2
- import { ShutdownManager, CompilerClient } from '@travetto/base';
1
+ import { ManifestModuleUtil, RuntimeIndex, RuntimeContext } from '@travetto/manifest';
2
+ import { watchCompiler, FullWatchEvent, WatchEvent } from '@travetto/base';
3
3
 
4
- type WatchHandler = Parameters<CompilerClient['onFileChange']>[0];
5
- type CompilerWatchEvent = Parameters<WatchHandler>[0];
6
4
  interface ModuleLoader {
7
5
  init?(): Promise<void>;
8
6
  load(file: string): Promise<void>;
9
7
  unload(file: string): Promise<void>;
10
8
  }
11
9
 
10
+ type Handler = (ev: WatchEvent) => unknown;
11
+
12
12
  const VALID_FILE_TYPES = new Set(['js', 'ts']);
13
13
 
14
14
  /**
15
15
  * Listens to file changes, and provides a unified interface for watching file changes, reloading files as needed
16
16
  */
17
17
  class $DynamicFileLoader {
18
- #handlers: WatchHandler[] = [];
18
+ #handlers: Handler[] = [];
19
19
  #loader: ModuleLoader;
20
20
  #initialized = false;
21
21
 
22
- async dispatch(ev: CompilerWatchEvent): Promise<void> {
22
+ async dispatch(ev: FullWatchEvent): Promise<void> {
23
23
  if (ev.action === 'update' || ev.action === 'delete') {
24
24
  await this.#loader.unload(ev.output);
25
25
  }
26
26
  if (ev.action === 'create' || ev.action === 'delete') {
27
- RootIndex.reinitForModule(RootIndex.mainModuleName);
27
+ RuntimeIndex.reinitForModule(RuntimeContext.main.name);
28
28
  }
29
29
  if (ev.action === 'create' || ev.action === 'update') {
30
30
  await this.#loader.load(ev.output);
@@ -35,7 +35,7 @@ class $DynamicFileLoader {
35
35
  }
36
36
  }
37
37
 
38
- onLoadEvent(handler: WatchHandler): void {
38
+ onLoadEvent(handler: Handler): void {
39
39
  this.#handlers.push(handler);
40
40
  }
41
41
 
@@ -52,20 +52,24 @@ class $DynamicFileLoader {
52
52
 
53
53
  await this.#loader.init?.();
54
54
 
55
- ShutdownManager.onUnhandled(err => {
55
+ const handle = (err: Error): void => {
56
56
  if (err && (err.message ?? '').includes('Cannot find module')) { // Handle module reloading
57
57
  console.error('Cannot find module', { error: err });
58
- return true;
58
+ } else {
59
+ throw err;
59
60
  }
60
- }, 0);
61
+ };
61
62
 
63
+ process
64
+ .on('unhandledRejection', handle)
65
+ .on('uncaughtException', handle);
62
66
 
63
67
  // Fire off, and let it run in the bg. Restart on exit
64
- new CompilerClient().onFileChange(async ev => {
65
- if (ev.file && RootIndex.hasModule(ev.module) && VALID_FILE_TYPES.has(ManifestModuleUtil.getFileType(ev.file))) {
66
- await this.dispatch(ev);
68
+ watchCompiler<FullWatchEvent>(ev => {
69
+ if (ev.file && RuntimeIndex.hasModule(ev.module) && VALID_FILE_TYPES.has(ManifestModuleUtil.getFileType(ev.file))) {
70
+ return this.dispatch(ev);
67
71
  }
68
- }, true);
72
+ }, { restartOnExit: true });
69
73
  }
70
74
  }
71
75
 
package/src/proxy.ts ADDED
@@ -0,0 +1,137 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ type ConcreteClass<T = any> = new (...args: any[]) => T;
3
+ const ProxyTargetⲐ = Symbol.for('@travetto/base:proxy-target');
4
+
5
+ const AsyncGeneratorFunction = Object.getPrototypeOf(async function* () { });
6
+ const GeneratorFunction = Object.getPrototypeOf(function* () { });
7
+ const AsyncFunction = Object.getPrototypeOf(async function () { });
8
+
9
+ function isFunction(o: unknown): o is Function {
10
+ const proto = o && Object.getPrototypeOf(o);
11
+ return proto && (proto === Function.prototype || proto === AsyncFunction || proto === AsyncGeneratorFunction || proto === GeneratorFunction);
12
+ }
13
+
14
+ /**
15
+ * Handler for for proxying modules while watching
16
+ */
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ export class RetargettingHandler<T> implements ProxyHandler<any> {
19
+ constructor(public target: T) { }
20
+
21
+ isExtensible(target: T): boolean {
22
+ return !Object.isFrozen(this.target);
23
+ }
24
+
25
+ getOwnPropertyDescriptor(target: T, property: PropertyKey): PropertyDescriptor | undefined {
26
+ if (property === '__esModule') {
27
+ return undefined;
28
+ } else {
29
+ return Object.getOwnPropertyDescriptor(this.target, property);
30
+ }
31
+ }
32
+
33
+ preventExtensions(target: T): boolean {
34
+ return !!Object.preventExtensions(this.target);
35
+ }
36
+
37
+ apply(target: T, thisArg: T, argArray?: unknown[]): unknown {
38
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
39
+ return (this.target as unknown as Function).apply(this.target, argArray);
40
+ }
41
+
42
+ construct(target: T, argArray: unknown[], newTarget?: unknown): object {
43
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
44
+ return new (this.target as unknown as ConcreteClass)(...argArray);
45
+ }
46
+
47
+ setPrototypeOf(target: T, v: unknown): boolean {
48
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
49
+ return Object.setPrototypeOf(this.target, v as Record<string, unknown>);
50
+ }
51
+
52
+ getPrototypeOf(target: T): object | null {
53
+ return Object.getPrototypeOf(this.target);
54
+ }
55
+
56
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
+ get(target: T, prop: PropertyKey, receiver: unknown): any {
58
+ if (prop === ProxyTargetⲐ) {
59
+ return this.target;
60
+ }
61
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
62
+ let ret = this.target[prop as keyof T];
63
+ if (isFunction(ret) && !/^class\s/.test(Function.prototype.toString.call(ret))) {
64
+ // Bind class members to class instance instead of proxy propagating
65
+ ret = ret.bind(this.target);
66
+ }
67
+ return ret;
68
+ }
69
+
70
+ has(target: T, prop: PropertyKey): boolean {
71
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
72
+ return (this.target as Object).hasOwnProperty(prop);
73
+ }
74
+
75
+ set(target: T, prop: PropertyKey, value: unknown): boolean {
76
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/consistent-type-assertions
77
+ this.target[prop as keyof T] = value as any;
78
+ return true;
79
+ }
80
+
81
+ ownKeys(target: T): (string | symbol)[] {
82
+ const keys: (string | symbol)[] = [];
83
+ return keys
84
+ .concat(Object.getOwnPropertyNames(this.target))
85
+ .concat(Object.getOwnPropertySymbols(this.target));
86
+ }
87
+
88
+ deleteProperty(target: T, p: PropertyKey): boolean {
89
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
90
+ return delete this.target[p as keyof T];
91
+ }
92
+
93
+ defineProperty(target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean {
94
+ Object.defineProperty(this.target, p, attributes);
95
+ return true;
96
+ }
97
+ }
98
+
99
+ interface Proxy<T> { }
100
+
101
+ /**
102
+ * Generate Retargetting Proxy
103
+ */
104
+ export class RetargettingProxy<T> {
105
+
106
+ /**
107
+ * Unwrap proxy
108
+ */
109
+ static unwrap<U>(el: U): U {
110
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/consistent-type-assertions
111
+ return (el ? ((el as any)[ProxyTargetⲐ] ?? el) : el) as U;
112
+ }
113
+
114
+ #handler: RetargettingHandler<T>;
115
+ #instance: Proxy<T>;
116
+
117
+ constructor(initial: T) {
118
+ this.#handler = new RetargettingHandler(initial);
119
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
120
+ this.#instance = new Proxy({}, this.#handler as ProxyHandler<object>);
121
+ }
122
+
123
+ setTarget(next: T): void {
124
+ if (next !== this.#handler.target) {
125
+ this.#handler.target = next;
126
+ }
127
+ }
128
+
129
+ getTarget(): T {
130
+ return this.#handler.target;
131
+ }
132
+
133
+ get(): T {
134
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
135
+ return this.#instance as T;
136
+ }
137
+ }
package/src/registry.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { EventEmitter } from 'events';
1
+ import { EventEmitter } from 'node:events';
2
2
  import { Class } from '@travetto/base';
3
3
  import { ChangeSource, ChangeEvent, ChangeHandler } from './types';
4
4
 
@@ -1,18 +1,20 @@
1
- import { EventEmitter } from 'events';
1
+ import { EventEmitter } from 'node:events';
2
2
 
3
- import { FindConfig, RootIndex } from '@travetto/manifest';
4
- import { Class, GlobalEnv } from '@travetto/base';
3
+ import { FindConfig, RuntimeIndex } from '@travetto/manifest';
4
+ import { Class, Env } from '@travetto/base';
5
5
 
6
6
  import { DynamicFileLoader } from '../internal/file-loader';
7
7
  import { ChangeSource, ChangeEvent, ChangeHandler } from '../types';
8
8
  import { PendingRegister } from '../decorator';
9
9
 
10
10
  const moduleFindConfig: FindConfig = {
11
- module: (m) =>
12
- m.roles.includes('std') && (
13
- GlobalEnv.devMode || m.prod ||
14
- (GlobalEnv.envName === 'doc' || GlobalEnv.envName === 'test') && m.roles.includes(GlobalEnv.envName)
15
- ),
11
+ module: (m) => {
12
+ const role = Env.TRV_ROLE.val;
13
+ return m.roles.includes('std') && (
14
+ !Env.production || m.prod ||
15
+ ((role === 'doc' || role === 'test') && m.roles.includes(role))
16
+ );
17
+ },
16
18
  folder: f => f === 'src' || f === '$index'
17
19
  };
18
20
 
@@ -36,7 +38,7 @@ export class ClassSource implements ChangeSource<Class> {
36
38
  }
37
39
  this.#classes.set(file, new Map());
38
40
  for (const cls of classes) {
39
- const src = RootIndex.getFunctionMetadata(cls)!.source;
41
+ const src = RuntimeIndex.getFunctionMetadata(cls)!.source;
40
42
  this.#classes.get(src)!.set(cls.Ⲑid, cls);
41
43
  this.emit({ type: 'added', curr: cls });
42
44
  }
@@ -76,8 +78,8 @@ export class ClassSource implements ChangeSource<Class> {
76
78
  changes += 1;
77
79
  this.emit({ type: 'added', curr: next.get(k)! });
78
80
  } else {
79
- const prevMeta = RootIndex.getFunctionMetadataFromClass(prev.get(k));
80
- const nextMeta = RootIndex.getFunctionMetadataFromClass(next.get(k));
81
+ const prevMeta = RuntimeIndex.getFunctionMetadataFromClass(prev.get(k));
82
+ const nextMeta = RuntimeIndex.getFunctionMetadataFromClass(next.get(k));
81
83
  if (prevMeta?.hash !== nextMeta?.hash) {
82
84
  changes += 1;
83
85
  this.emit({ type: 'changed', curr: next.get(k)!, prev: prev.get(k) });
@@ -102,7 +104,7 @@ export class ClassSource implements ChangeSource<Class> {
102
104
  * Initialize
103
105
  */
104
106
  async init(): Promise<void> {
105
- if (GlobalEnv.dynamic) {
107
+ if (Env.dynamic) {
106
108
  DynamicFileLoader.onLoadEvent(ev => {
107
109
  for (const [file, classes] of PendingRegister.flush(true)) {
108
110
  this.#handleFileChanges(file, classes);
@@ -115,7 +117,7 @@ export class ClassSource implements ChangeSource<Class> {
115
117
  }
116
118
 
117
119
  // Ensure everything is loaded
118
- for (const mod of RootIndex.find(moduleFindConfig)) {
120
+ for (const mod of RuntimeIndex.find(moduleFindConfig)) {
119
121
  await import(mod.import);
120
122
  }
121
123
 
@@ -1,7 +1,7 @@
1
- import { EventEmitter } from 'events';
1
+ import { EventEmitter } from 'node:events';
2
2
 
3
3
  import { Class } from '@travetto/base';
4
- import { RootIndex } from '@travetto/manifest';
4
+ import { RuntimeIndex } from '@travetto/manifest';
5
5
 
6
6
  import { ChangeSource, ChangeEvent, ChangeHandler } from '../types';
7
7
 
@@ -30,8 +30,8 @@ export class MethodSource implements ChangeSource<[Class, Function]> {
30
30
  * On a class being emitted, check methods
31
31
  */
32
32
  onClassEvent(e: ChangeEvent<Class>): void {
33
- const next = RootIndex.getFunctionMetadataFromClass(e.curr!)?.methods ?? {};
34
- const prev = RootIndex.getFunctionMetadataFromClass(e.prev!)?.methods ?? {};
33
+ const next = RuntimeIndex.getFunctionMetadataFromClass(e.curr!)?.methods ?? {};
34
+ const prev = RuntimeIndex.getFunctionMetadataFromClass(e.prev!)?.methods ?? {};
35
35
 
36
36
  /**
37
37
  * Go through each method, comparing hashes. To see added/removed and changed