@codefast/di 0.3.14-canary.0 → 0.3.14-canary.2
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/CHANGELOG.md +28 -0
- package/README.md +54 -29
- package/dist/binding-scope.d.mts +11 -0
- package/dist/binding-scope.mjs +19 -0
- package/dist/binding-select.d.mts +8 -26
- package/dist/binding-select.mjs +56 -49
- package/dist/binding.d.mts +107 -327
- package/dist/binding.mjs +19 -324
- package/dist/constraints.d.mts +11 -29
- package/dist/constraints.mjs +32 -36
- package/dist/constructor-type.d.mts +17 -0
- package/dist/constructor-type.mjs +1 -0
- package/dist/container.d.mts +44 -128
- package/dist/container.mjs +664 -433
- package/dist/decorators/inject.d.mts +19 -50
- package/dist/decorators/inject.mjs +131 -93
- package/dist/decorators/injectable.d.mts +16 -37
- package/dist/decorators/injectable.mjs +47 -66
- package/dist/decorators/lifecycle-decorators.d.mts +2 -22
- package/dist/decorators/lifecycle-decorators.mjs +81 -37
- package/dist/dependency-graph.d.mts +24 -54
- package/dist/dependency-graph.mjs +51 -153
- package/dist/environment.d.mts +38 -12
- package/dist/environment.mjs +82 -16
- package/dist/errors.d.mts +69 -188
- package/dist/errors.mjs +92 -219
- package/dist/graph-adapters/cytoscape.d.mts +24 -0
- package/dist/graph-adapters/cytoscape.mjs +23 -0
- package/dist/graph-adapters/dot.d.mts +6 -0
- package/dist/graph-adapters/dot.mjs +17 -0
- package/dist/graph-adapters/reactflow.d.mts +29 -0
- package/dist/graph-adapters/reactflow.mjs +29 -0
- package/dist/graph-adapters/types.d.mts +2 -0
- package/dist/graph-adapters/types.mjs +1 -0
- package/dist/index.d.mts +16 -9
- package/dist/index.mjs +8 -5
- package/dist/inspector.d.mts +34 -95
- package/dist/inspector.mjs +57 -256
- package/dist/lifecycle.d.mts +20 -53
- package/dist/lifecycle.mjs +129 -99
- package/dist/metadata/metadata-keys.d.mts +9 -26
- package/dist/metadata/metadata-keys.mjs +7 -28
- package/dist/metadata/metadata-reader-token.d.mts +7 -0
- package/dist/metadata/metadata-reader-token.mjs +5 -0
- package/dist/metadata/metadata-types.d.mts +22 -71
- package/dist/metadata/symbol-metadata-reader.d.mts +10 -26
- package/dist/metadata/symbol-metadata-reader.mjs +32 -45
- package/dist/module.d.mts +30 -84
- package/dist/module.mjs +26 -72
- package/dist/registry.d.mts +32 -63
- package/dist/registry.mjs +131 -82
- package/dist/resolve-options.d.mts +18 -0
- package/dist/resolve-options.mjs +22 -0
- package/dist/resolver.d.mts +67 -190
- package/dist/resolver.mjs +715 -424
- package/dist/scope.d.mts +19 -102
- package/dist/scope.mjs +37 -192
- package/dist/token.d.mts +8 -22
- package/dist/token.mjs +9 -11
- package/dist/types.d.mts +48 -0
- package/dist/types.mjs +1 -0
- package/package.json +52 -14
- package/dist/metadata/param-registry.d.mts +0 -16
- package/dist/metadata/param-registry.mjs +0 -31
- package/dist/scope-validation.d.mts +0 -21
- package/dist/scope-validation.mjs +0 -35
package/dist/lifecycle.d.mts
CHANGED
|
@@ -1,56 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Constructor } from "./constructor-type.mjs";
|
|
2
|
+
import { Token } from "./token.mjs";
|
|
3
|
+
import { ActivationHandler, DeactivationHandler, ResolutionContext } from "./types.mjs";
|
|
4
|
+
import { Binding } from "./binding.mjs";
|
|
5
|
+
import { MetadataReader } from "./metadata/metadata-types.mjs";
|
|
3
6
|
|
|
4
7
|
//#region src/lifecycle.d.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
* Reads lifecycle metadata ({@link LifecycleMetadata}) directly from a constructor's
|
|
20
|
-
* `Symbol.metadata` object. Bypasses the {@link MetadataReader} abstraction —
|
|
21
|
-
* used by the scope manager during deactivation when the reader is not available.
|
|
22
|
-
*/
|
|
23
|
-
declare function readLifecycleMetadataFromCtor(implementationClass: Constructor<unknown>): LifecycleMetadata | undefined;
|
|
24
|
-
/**
|
|
25
|
-
* Runs the `@postConstruct()` method synchronously if present.
|
|
26
|
-
* Throws {@link AsyncResolutionError} if the method returns a Promise — async lifecycle
|
|
27
|
-
* methods require `resolveAsync`.
|
|
28
|
-
*
|
|
29
|
-
* Lifecycle ordering: `construct` → **`@postConstruct`** → `onActivation` → cache.
|
|
30
|
-
*/
|
|
31
|
-
declare function runPostConstruct(implementationClass: Constructor<unknown>, instance: unknown, pathLabels?: string[]): void;
|
|
32
|
-
/**
|
|
33
|
-
* Runs the `@postConstruct()` method, awaiting if it returns a Promise.
|
|
34
|
-
*/
|
|
35
|
-
declare function runPostConstructAsync(implementationClass: Constructor<unknown>, instance: unknown): Promise<void>;
|
|
36
|
-
/**
|
|
37
|
-
* Runs the `@preDestroy()` method synchronously if present.
|
|
38
|
-
* Throws if the method returns a Promise — use `disposeAsync()` / `unloadAsync()` for async teardown.
|
|
39
|
-
*
|
|
40
|
-
* Lifecycle ordering: `onDeactivation` → **`@preDestroy`**.
|
|
41
|
-
*/
|
|
42
|
-
declare function runPreDestroy(implementationClass: Constructor<unknown>, instance: unknown): void;
|
|
43
|
-
/**
|
|
44
|
-
* Runs the `@preDestroy()` method, awaiting if it returns a Promise.
|
|
45
|
-
*
|
|
46
|
-
* Lifecycle ordering: `onDeactivation` → **`@preDestroy`** (async variant).
|
|
47
|
-
*/
|
|
48
|
-
declare function runPreDestroyAsync(implementationClass: Constructor<unknown>, instance: unknown): Promise<void>;
|
|
49
|
-
/**
|
|
50
|
-
* Runs `onActivation`, awaiting if the handler returns a Promise.
|
|
51
|
-
*
|
|
52
|
-
* Lifecycle ordering: `construct` → `@postConstruct` → **`onActivation`** (async variant) → cache.
|
|
53
|
-
*/
|
|
54
|
-
declare function runActivationAsync(binding: Binding<unknown>, instance: unknown, ctx: ResolutionContext, _pathLabels: readonly string[]): Promise<unknown>;
|
|
8
|
+
declare class LifecycleManager {
|
|
9
|
+
private readonly _activationHooks;
|
|
10
|
+
private readonly _deactivationHooks;
|
|
11
|
+
private _activationVersion;
|
|
12
|
+
registerActivation<const Value>(t: Token<Value> | Constructor<Value>, handler: ActivationHandler<Value>): void;
|
|
13
|
+
hasActivationHandlers<const Value>(t: Token<Value> | Constructor<Value>): boolean;
|
|
14
|
+
get activationVersion(): number;
|
|
15
|
+
registerDeactivation<const Value>(t: Token<Value> | Constructor<Value>, handler: DeactivationHandler<Value>): void;
|
|
16
|
+
runActivation<const Value>(ctx: ResolutionContext, binding: Binding<Value>, instance: Value, metadataReader: MetadataReader): Promise<Value>;
|
|
17
|
+
runActivationSync<const Value>(ctx: ResolutionContext, binding: Binding<Value>, instance: Value, metadataReader: MetadataReader): Value;
|
|
18
|
+
runDeactivation<const Value>(binding: Binding<Value>, instance: Value, metadataReader: MetadataReader): Promise<void>;
|
|
19
|
+
runDeactivationSync<const Value>(binding: Binding<Value>, instance: Value, metadataReader: MetadataReader): void;
|
|
20
|
+
hasAsyncDeactivation<const Value>(binding: Binding<Value>, instance: Value, _metadataReader: MetadataReader): boolean;
|
|
21
|
+
}
|
|
55
22
|
//#endregion
|
|
56
|
-
export {
|
|
23
|
+
export { LifecycleManager };
|
package/dist/lifecycle.mjs
CHANGED
|
@@ -1,102 +1,132 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { AsyncDeactivationError } from "./errors.mjs";
|
|
2
|
+
import { tokenName } from "./token.mjs";
|
|
3
3
|
//#region src/lifecycle.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* Lifecycle ordering: `construct` → `@postConstruct` → **`onActivation`** → cache.
|
|
17
|
-
*/
|
|
18
|
-
function runActivation(binding, instance, ctx, pathLabels) {
|
|
19
|
-
const handler = binding.onActivation;
|
|
20
|
-
if (handler === void 0) return instance;
|
|
21
|
-
const bindingLabel = pathLabels[pathLabels.length - 1] ?? "(unknown)";
|
|
22
|
-
const activationResult = handler(ctx, instance);
|
|
23
|
-
if (isPromiseLike(activationResult)) throw new AsyncResolutionError(bindingLabel, pathLabels, "onActivation returned a Promise during synchronous resolution");
|
|
24
|
-
return activationResult;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Reads lifecycle metadata ({@link LifecycleMetadata}) directly from a constructor's
|
|
28
|
-
* `Symbol.metadata` object. Bypasses the {@link MetadataReader} abstraction —
|
|
29
|
-
* used by the scope manager during deactivation when the reader is not available.
|
|
30
|
-
*/
|
|
31
|
-
function readLifecycleMetadataFromCtor(implementationClass) {
|
|
32
|
-
const metadataObject = implementationClass[decoratorMetadataObjectSymbol()];
|
|
33
|
-
if (typeof metadataObject !== "object" || metadataObject === null) return;
|
|
34
|
-
const raw = metadataObject[CODEFAST_DI_LIFECYCLE_METADATA];
|
|
35
|
-
return typeof raw === "object" && raw !== null ? raw : void 0;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Runs the `@postConstruct()` method synchronously if present.
|
|
39
|
-
* Throws {@link AsyncResolutionError} if the method returns a Promise — async lifecycle
|
|
40
|
-
* methods require `resolveAsync`.
|
|
41
|
-
*
|
|
42
|
-
* Lifecycle ordering: `construct` → **`@postConstruct`** → `onActivation` → cache.
|
|
43
|
-
*/
|
|
44
|
-
function runPostConstruct(implementationClass, instance, pathLabels) {
|
|
45
|
-
const meta = readLifecycleMetadataFromCtor(implementationClass);
|
|
46
|
-
if (meta?.postConstruct === void 0) return;
|
|
47
|
-
const methodName = meta.postConstruct;
|
|
48
|
-
const lifecycleMethod = instance[methodName];
|
|
49
|
-
if (typeof lifecycleMethod !== "function") return;
|
|
50
|
-
if (isPromiseLike(lifecycleMethod.call(instance))) {
|
|
51
|
-
const labels = pathLabels ?? [];
|
|
52
|
-
throw new AsyncResolutionError(labels[labels.length - 1] ?? "(unknown)", labels, `@postConstruct() "${methodName}" returned a Promise during synchronous resolution`);
|
|
4
|
+
var LifecycleManager = class {
|
|
5
|
+
_activationHooks = /* @__PURE__ */ new Map();
|
|
6
|
+
_deactivationHooks = /* @__PURE__ */ new Map();
|
|
7
|
+
_activationVersion = 0;
|
|
8
|
+
registerActivation(t, handler) {
|
|
9
|
+
this._activationVersion += 1;
|
|
10
|
+
let list = this._activationHooks.get(t);
|
|
11
|
+
if (list === void 0) {
|
|
12
|
+
list = [];
|
|
13
|
+
this._activationHooks.set(t, list);
|
|
14
|
+
}
|
|
15
|
+
list.push(handler);
|
|
53
16
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
17
|
+
hasActivationHandlers(t) {
|
|
18
|
+
if (this._activationHooks.size === 0) return false;
|
|
19
|
+
const list = this._activationHooks.get(t);
|
|
20
|
+
return list !== void 0 && list.length > 0;
|
|
21
|
+
}
|
|
22
|
+
get activationVersion() {
|
|
23
|
+
return this._activationVersion;
|
|
24
|
+
}
|
|
25
|
+
registerDeactivation(t, handler) {
|
|
26
|
+
let list = this._deactivationHooks.get(t);
|
|
27
|
+
if (list === void 0) {
|
|
28
|
+
list = [];
|
|
29
|
+
this._deactivationHooks.set(t, list);
|
|
30
|
+
}
|
|
31
|
+
list.push(handler);
|
|
32
|
+
}
|
|
33
|
+
async runActivation(ctx, binding, instance, metadataReader) {
|
|
34
|
+
let result = instance;
|
|
35
|
+
if (binding.kind === "class") {
|
|
36
|
+
const lifecycle = metadataReader.getLifecycleMetadata(binding.target);
|
|
37
|
+
if (lifecycle?.postConstruct && lifecycle.postConstruct.length > 0) for (const methodName of lifecycle.postConstruct) {
|
|
38
|
+
const method = result[methodName];
|
|
39
|
+
if (typeof method === "function") {
|
|
40
|
+
const r = method.call(result);
|
|
41
|
+
if (r instanceof Promise) await r;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (binding.kind !== "alias" && binding.onActivation !== void 0) {
|
|
46
|
+
const activated = binding.onActivation(ctx, result);
|
|
47
|
+
result = activated instanceof Promise ? await activated : activated;
|
|
48
|
+
}
|
|
49
|
+
const containerHooks = this._activationHooks.get(binding.token);
|
|
50
|
+
if (containerHooks !== void 0) for (const hook of containerHooks) {
|
|
51
|
+
const activated = hook(ctx, result);
|
|
52
|
+
result = activated instanceof Promise ? await activated : activated;
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
runActivationSync(ctx, binding, instance, metadataReader) {
|
|
57
|
+
let result = instance;
|
|
58
|
+
if (binding.kind === "class") {
|
|
59
|
+
const lifecycle = metadataReader.getLifecycleMetadata(binding.target);
|
|
60
|
+
if (lifecycle?.postConstruct && lifecycle.postConstruct.length > 0) for (const methodName of lifecycle.postConstruct) {
|
|
61
|
+
const method = result[methodName];
|
|
62
|
+
if (typeof method === "function") {
|
|
63
|
+
if (method.call(result) instanceof Promise) throw new Error(`@postConstruct method '${methodName}' returned a Promise. Use resolveAsync() instead.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (binding.kind !== "alias" && binding.onActivation !== void 0) {
|
|
68
|
+
const activated = binding.onActivation(ctx, result);
|
|
69
|
+
if (activated instanceof Promise) throw new Error(`onActivation for '${tokenName(binding.token)}' returned a Promise. Use resolveAsync() instead.`);
|
|
70
|
+
result = activated;
|
|
71
|
+
}
|
|
72
|
+
const key = tokenName(binding.token);
|
|
73
|
+
const containerHooks = this._activationHooks.get(binding.token);
|
|
74
|
+
if (containerHooks !== void 0) for (const hook of containerHooks) {
|
|
75
|
+
const activated = hook(ctx, result);
|
|
76
|
+
if (activated instanceof Promise) throw new Error(`Container-level onActivation for '${key}' returned a Promise. Use resolveAsync() instead.`);
|
|
77
|
+
result = activated;
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
async runDeactivation(binding, instance, metadataReader) {
|
|
82
|
+
const key = binding.token;
|
|
83
|
+
const containerHooks = this._deactivationHooks.get(key);
|
|
84
|
+
if (containerHooks !== void 0) for (const hook of containerHooks) {
|
|
85
|
+
const r = hook(instance);
|
|
86
|
+
if (r instanceof Promise) await r;
|
|
87
|
+
}
|
|
88
|
+
if (binding.kind !== "alias" && binding.onDeactivation !== void 0) {
|
|
89
|
+
const r = binding.onDeactivation(instance);
|
|
90
|
+
if (r instanceof Promise) await r;
|
|
91
|
+
}
|
|
92
|
+
if (binding.kind === "class") {
|
|
93
|
+
const lifecycle = metadataReader.getLifecycleMetadata(binding.target);
|
|
94
|
+
if (lifecycle?.preDestroy && lifecycle.preDestroy.length > 0) for (const methodName of lifecycle.preDestroy) {
|
|
95
|
+
const method = instance[methodName];
|
|
96
|
+
if (typeof method === "function") {
|
|
97
|
+
const r = method.call(instance);
|
|
98
|
+
if (r instanceof Promise) await r;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
runDeactivationSync(binding, instance, metadataReader) {
|
|
104
|
+
const tName = tokenName(binding.token);
|
|
105
|
+
const key = binding.token;
|
|
106
|
+
const containerHooks = this._deactivationHooks.get(key);
|
|
107
|
+
if (containerHooks !== void 0) {
|
|
108
|
+
for (const hook of containerHooks) if (hook(instance) instanceof Promise) throw new AsyncDeactivationError(tName);
|
|
109
|
+
}
|
|
110
|
+
if (binding.kind !== "alias" && binding.onDeactivation !== void 0) {
|
|
111
|
+
if (binding.onDeactivation(instance) instanceof Promise) throw new AsyncDeactivationError(tName);
|
|
112
|
+
}
|
|
113
|
+
if (binding.kind === "class") {
|
|
114
|
+
const lifecycle = metadataReader.getLifecycleMetadata(binding.target);
|
|
115
|
+
if (lifecycle?.preDestroy && lifecycle.preDestroy.length > 0) for (const methodName of lifecycle.preDestroy) {
|
|
116
|
+
const method = instance[methodName];
|
|
117
|
+
if (typeof method === "function") {
|
|
118
|
+
if (method.call(instance) instanceof Promise) throw new AsyncDeactivationError(tName);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
hasAsyncDeactivation(binding, instance, _metadataReader) {
|
|
124
|
+
if (binding.kind === "alias") return false;
|
|
125
|
+
if (binding.onDeactivation !== void 0) {
|
|
126
|
+
if (binding.onDeactivation(instance) instanceof Promise) return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
101
131
|
//#endregion
|
|
102
|
-
export {
|
|
132
|
+
export { LifecycleManager };
|
|
@@ -1,28 +1,11 @@
|
|
|
1
|
+
import { ConstructorMetadata, MutableLifecycleMetadata } from "./metadata-types.mjs";
|
|
2
|
+
|
|
1
3
|
//#region src/metadata/metadata-keys.d.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
declare const
|
|
8
|
-
/**
|
|
9
|
-
* Well-known property key for accessor-field injection metadata on `Symbol.metadata`.
|
|
10
|
-
* Written by `@inject()` when used as an accessor decorator; read during post-construction
|
|
11
|
-
* property injection by the resolver.
|
|
12
|
-
*/
|
|
13
|
-
declare const CODEFAST_DI_ACCESSOR_INJECTIONS = "codefast/di:accessor-injections:v1";
|
|
14
|
-
/**
|
|
15
|
-
* Well-known key for lifecycle method names written by `@postConstruct()` / `@preDestroy()`.
|
|
16
|
-
*/
|
|
17
|
-
declare const CODEFAST_DI_LIFECYCLE_METADATA = "codefast/di:lifecycle-metadata:v1";
|
|
18
|
-
/**
|
|
19
|
-
* Returns the runtime symbol used to access TC39 decorator metadata on a class.
|
|
20
|
-
*
|
|
21
|
-
* Prefers the native `Symbol.metadata` when available (Stage 3 decorators); falls back to
|
|
22
|
-
* `Symbol.for("Symbol.metadata")` for Node/runtime versions that polyfill or partially
|
|
23
|
-
* implement the proposal. The fallback key is the de facto convention used by TypeScript
|
|
24
|
-
* and polyfill libraries.
|
|
25
|
-
*/
|
|
26
|
-
declare function decoratorMetadataObjectSymbol(): symbol;
|
|
4
|
+
declare const INJECTABLE_KEY: unique symbol;
|
|
5
|
+
declare const LIFECYCLE_KEY: unique symbol;
|
|
6
|
+
declare const INJECT_ACCESSOR_KEY: unique symbol;
|
|
7
|
+
declare const constructorMetadataMap: WeakMap<object, ConstructorMetadata>;
|
|
8
|
+
declare const lifecycleMetadataMap: WeakMap<object, MutableLifecycleMetadata>;
|
|
9
|
+
declare const lifecycleByConstructorMetadataMap: WeakMap<object, MutableLifecycleMetadata>;
|
|
27
10
|
//#endregion
|
|
28
|
-
export {
|
|
11
|
+
export { INJECTABLE_KEY, INJECT_ACCESSOR_KEY, LIFECYCLE_KEY, constructorMetadataMap, lifecycleByConstructorMetadataMap, lifecycleMetadataMap };
|
|
@@ -1,30 +1,9 @@
|
|
|
1
1
|
//#region src/metadata/metadata-keys.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
const
|
|
8
|
-
/**
|
|
9
|
-
* Well-known property key for accessor-field injection metadata on `Symbol.metadata`.
|
|
10
|
-
* Written by `@inject()` when used as an accessor decorator; read during post-construction
|
|
11
|
-
* property injection by the resolver.
|
|
12
|
-
*/
|
|
13
|
-
const CODEFAST_DI_ACCESSOR_INJECTIONS = "codefast/di:accessor-injections:v1";
|
|
14
|
-
/**
|
|
15
|
-
* Well-known key for lifecycle method names written by `@postConstruct()` / `@preDestroy()`.
|
|
16
|
-
*/
|
|
17
|
-
const CODEFAST_DI_LIFECYCLE_METADATA = "codefast/di:lifecycle-metadata:v1";
|
|
18
|
-
/**
|
|
19
|
-
* Returns the runtime symbol used to access TC39 decorator metadata on a class.
|
|
20
|
-
*
|
|
21
|
-
* Prefers the native `Symbol.metadata` when available (Stage 3 decorators); falls back to
|
|
22
|
-
* `Symbol.for("Symbol.metadata")` for Node/runtime versions that polyfill or partially
|
|
23
|
-
* implement the proposal. The fallback key is the de facto convention used by TypeScript
|
|
24
|
-
* and polyfill libraries.
|
|
25
|
-
*/
|
|
26
|
-
function decoratorMetadataObjectSymbol() {
|
|
27
|
-
return typeof Symbol.metadata === "symbol" ? Symbol.metadata : Symbol.for("Symbol.metadata");
|
|
28
|
-
}
|
|
2
|
+
const INJECTABLE_KEY = Symbol("di:injectable");
|
|
3
|
+
const LIFECYCLE_KEY = Symbol("di:lifecycle");
|
|
4
|
+
const INJECT_ACCESSOR_KEY = Symbol("di:inject-accessor");
|
|
5
|
+
const constructorMetadataMap = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
const lifecycleMetadataMap = /* @__PURE__ */ new WeakMap();
|
|
7
|
+
const lifecycleByConstructorMetadataMap = /* @__PURE__ */ new WeakMap();
|
|
29
8
|
//#endregion
|
|
30
|
-
export {
|
|
9
|
+
export { INJECTABLE_KEY, INJECT_ACCESSOR_KEY, LIFECYCLE_KEY, constructorMetadataMap, lifecycleByConstructorMetadataMap, lifecycleMetadataMap };
|
|
@@ -1,79 +1,30 @@
|
|
|
1
|
+
import { Constructor } from "../constructor-type.mjs";
|
|
1
2
|
import { Token } from "../token.mjs";
|
|
2
|
-
import { Constructor } from "../binding.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/metadata/metadata-types.d.ts
|
|
5
|
-
|
|
6
|
-
* Metadata written per `accessor` field decorated with `@inject`; collected into `Symbol.metadata`.
|
|
7
|
-
*/
|
|
8
|
-
type AccessorInjectionMetadata = {
|
|
9
|
-
readonly name: string;
|
|
10
|
-
readonly token: Token<unknown> | Constructor<unknown>;
|
|
11
|
-
readonly optional: boolean;
|
|
12
|
-
readonly resolveHint?: {
|
|
13
|
-
readonly name?: string;
|
|
14
|
-
readonly tag?: readonly [tag: string, value: unknown];
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Lifecycle method names written by `@postConstruct()` / `@preDestroy()` into `Symbol.metadata`.
|
|
19
|
-
*/
|
|
20
|
-
type LifecycleMetadata = {
|
|
21
|
-
readonly postConstruct?: string;
|
|
22
|
-
readonly preDestroy?: string;
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* Per-parameter injection description collected by `@injectable()`.
|
|
26
|
-
*/
|
|
27
|
-
type ParamMetadata = {
|
|
5
|
+
interface ParamMetadata {
|
|
28
6
|
readonly index: number;
|
|
29
|
-
readonly token: Token<unknown> | Constructor
|
|
30
|
-
readonly optional: boolean;
|
|
31
|
-
readonly name?: string;
|
|
32
|
-
readonly tag?: readonly [tag: string, value: unknown];
|
|
33
|
-
/**
|
|
34
|
-
* When true, the parameter receives every binding for `token` as an array (same semantics as
|
|
35
|
-
* `Container.resolveAll` / `ResolutionContext.resolveAll`), using `name` / `tag` as a filter when set.
|
|
36
|
-
*/
|
|
37
|
-
readonly all?: boolean;
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* Resolved form of an `inject()` / `optional()` call: token + optional flag + optional resolve hint.
|
|
41
|
-
* Used both as a deps-array entry in `@injectable()` and as accessor-field injection metadata.
|
|
42
|
-
*/
|
|
43
|
-
type InjectionDescriptor<Value = unknown> = {
|
|
44
|
-
readonly token: Token<Value> | Constructor<Value>;
|
|
7
|
+
readonly token: Token<unknown> | Constructor;
|
|
45
8
|
readonly optional: boolean;
|
|
9
|
+
readonly multi: boolean;
|
|
46
10
|
readonly name?: string;
|
|
47
|
-
readonly
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Constructor injection shape stored on the class `Symbol.metadata` object.
|
|
52
|
-
*/
|
|
53
|
-
type ConstructorMetadata = {
|
|
11
|
+
readonly tags?: ReadonlyArray<readonly [string, unknown]>;
|
|
12
|
+
}
|
|
13
|
+
interface ConstructorMetadata {
|
|
54
14
|
readonly params: readonly ParamMetadata[];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
* resolver instantiates with zero arguments instead (see `DependencyResolver` class binding path).
|
|
70
|
-
*/
|
|
71
|
-
getConstructorMetadata(implementationClass: Constructor<unknown>): ConstructorMetadata | undefined;
|
|
72
|
-
/**
|
|
73
|
-
* Returns lifecycle method names (`@postConstruct` / `@preDestroy`), or `undefined` if none.
|
|
74
|
-
* Optional: when absent the resolver skips lifecycle hooks entirely.
|
|
75
|
-
*/
|
|
76
|
-
getLifecycleMetadata?(implementationClass: Constructor<unknown>): LifecycleMetadata | undefined;
|
|
77
|
-
};
|
|
15
|
+
}
|
|
16
|
+
interface LifecycleMetadata {
|
|
17
|
+
readonly postConstruct: readonly string[];
|
|
18
|
+
readonly preDestroy: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
/** Mutable buckets used while aggregating decorator metadata (same keys as {@link LifecycleMetadata}). */
|
|
21
|
+
interface MutableLifecycleMetadata {
|
|
22
|
+
postConstruct: string[];
|
|
23
|
+
preDestroy: string[];
|
|
24
|
+
}
|
|
25
|
+
interface MetadataReader {
|
|
26
|
+
getConstructorMetadata(target: Constructor): ConstructorMetadata | undefined;
|
|
27
|
+
getLifecycleMetadata(target: Constructor): LifecycleMetadata | undefined;
|
|
28
|
+
}
|
|
78
29
|
//#endregion
|
|
79
|
-
export {
|
|
30
|
+
export { ConstructorMetadata, LifecycleMetadata, MetadataReader, MutableLifecycleMetadata, ParamMetadata };
|
|
@@ -1,32 +1,16 @@
|
|
|
1
|
-
import { Constructor } from "../
|
|
1
|
+
import { Constructor } from "../constructor-type.mjs";
|
|
2
|
+
import { InjectionDescriptor } from "../decorators/inject.mjs";
|
|
2
3
|
import { ConstructorMetadata, LifecycleMetadata, MetadataReader } from "./metadata-types.mjs";
|
|
3
4
|
|
|
4
5
|
//#region src/metadata/symbol-metadata-reader.d.ts
|
|
5
|
-
/**
|
|
6
|
-
* Default {@link MetadataReader} implementation backed by TC39 `Symbol.metadata`.
|
|
7
|
-
*
|
|
8
|
-
* Constructor metadata (`@injectable()`) is read with `Object.hasOwn` to prevent
|
|
9
|
-
* a subclass from silently inheriting a parent's dependency list — each class must
|
|
10
|
-
* declare its own `@injectable()` decorator or be constructed with zero arguments.
|
|
11
|
-
*
|
|
12
|
-
* Lifecycle metadata (`@postConstruct` / `@preDestroy`) *is* inherited through the
|
|
13
|
-
* prototype chain, matching the intent that a parent's lifecycle hook applies to children.
|
|
14
|
-
*/
|
|
15
6
|
declare class SymbolMetadataReader implements MetadataReader {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* parent to child, so without this guard a subclass without `@injectable()` would
|
|
23
|
-
* silently inherit the parent's parameter list and inject the wrong dependency count.
|
|
24
|
-
*/
|
|
25
|
-
getConstructorMetadata(implementationClass: Constructor<unknown>): ConstructorMetadata | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* Reads lifecycle method names written by `@postConstruct()` / `@preDestroy()`. Inherits from parent classes.
|
|
28
|
-
*/
|
|
29
|
-
getLifecycleMetadata(implementationClass: Constructor<unknown>): LifecycleMetadata | undefined;
|
|
7
|
+
getConstructorMetadata(target: Constructor): ConstructorMetadata | undefined;
|
|
8
|
+
getLifecycleMetadata(target: Constructor): LifecycleMetadata | undefined;
|
|
9
|
+
getAccessorMetadata(target: Constructor): Array<{
|
|
10
|
+
key: string | symbol;
|
|
11
|
+
descriptor: InjectionDescriptor;
|
|
12
|
+
}> | undefined;
|
|
30
13
|
}
|
|
14
|
+
declare const defaultMetadataReader: SymbolMetadataReader;
|
|
31
15
|
//#endregion
|
|
32
|
-
export { SymbolMetadataReader };
|
|
16
|
+
export { SymbolMetadataReader, defaultMetadataReader };
|
|
@@ -1,51 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { INJECTABLE_KEY, INJECT_ACCESSOR_KEY, LIFECYCLE_KEY, constructorMetadataMap, lifecycleByConstructorMetadataMap, lifecycleMetadataMap } from "./metadata-keys.mjs";
|
|
2
2
|
//#region src/metadata/symbol-metadata-reader.ts
|
|
3
|
-
/**
|
|
4
|
-
* Type guard — returns `true` when `value` has the shape of a {@link ConstructorMetadata} object.
|
|
5
|
-
*/
|
|
6
|
-
function isConstructorMetadata(value) {
|
|
7
|
-
if (typeof value !== "object" || value === null || !("params" in value)) return false;
|
|
8
|
-
return Array.isArray(value.params);
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Default {@link MetadataReader} implementation backed by TC39 `Symbol.metadata`.
|
|
12
|
-
*
|
|
13
|
-
* Constructor metadata (`@injectable()`) is read with `Object.hasOwn` to prevent
|
|
14
|
-
* a subclass from silently inheriting a parent's dependency list — each class must
|
|
15
|
-
* declare its own `@injectable()` decorator or be constructed with zero arguments.
|
|
16
|
-
*
|
|
17
|
-
* Lifecycle metadata (`@postConstruct` / `@preDestroy`) *is* inherited through the
|
|
18
|
-
* prototype chain, matching the intent that a parent's lifecycle hook applies to children.
|
|
19
|
-
*/
|
|
20
3
|
var SymbolMetadataReader = class {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*/
|
|
30
|
-
getConstructorMetadata(implementationClass) {
|
|
31
|
-
const rawMetadata = implementationClass[decoratorMetadataObjectSymbol()];
|
|
32
|
-
if (typeof rawMetadata !== "object" || rawMetadata === null) return;
|
|
33
|
-
const metadataObject = rawMetadata;
|
|
34
|
-
if (!Object.hasOwn(metadataObject, "codefast/di:constructor-metadata:v1")) return;
|
|
35
|
-
const raw = metadataObject[CODEFAST_DI_CONSTRUCTOR_METADATA];
|
|
36
|
-
if (!isConstructorMetadata(raw)) return;
|
|
37
|
-
return raw;
|
|
4
|
+
getConstructorMetadata(target) {
|
|
5
|
+
const fromWeakMap = constructorMetadataMap.get(target);
|
|
6
|
+
if (fromWeakMap !== void 0) return fromWeakMap;
|
|
7
|
+
const own = Object.getOwnPropertyDescriptor(target, Symbol.metadata);
|
|
8
|
+
if (own === void 0) return;
|
|
9
|
+
const meta = own.value;
|
|
10
|
+
if (!meta || typeof meta !== "object" || !Object.hasOwn(meta, INJECTABLE_KEY)) return;
|
|
11
|
+
return meta[INJECTABLE_KEY];
|
|
38
12
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
13
|
+
getLifecycleMetadata(target) {
|
|
14
|
+
const byConstructor = lifecycleByConstructorMetadataMap.get(target);
|
|
15
|
+
if (byConstructor !== void 0) return byConstructor;
|
|
16
|
+
const own = Object.getOwnPropertyDescriptor(target, Symbol.metadata);
|
|
17
|
+
if (own !== void 0) {
|
|
18
|
+
const meta = own.value;
|
|
19
|
+
if (meta && typeof meta === "object" && Object.hasOwn(meta, LIFECYCLE_KEY)) return meta[LIFECYCLE_KEY];
|
|
20
|
+
}
|
|
21
|
+
const classMeta = target[Symbol.metadata];
|
|
22
|
+
if (classMeta !== void 0) {
|
|
23
|
+
const fromWeakMap = lifecycleMetadataMap.get(classMeta);
|
|
24
|
+
if (fromWeakMap !== void 0) return fromWeakMap;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
getAccessorMetadata(target) {
|
|
28
|
+
const own = Object.getOwnPropertyDescriptor(target, Symbol.metadata);
|
|
29
|
+
if (own === void 0) return;
|
|
30
|
+
const meta = own.value;
|
|
31
|
+
if (!meta || typeof meta !== "object") return;
|
|
32
|
+
if (!Object.hasOwn(meta, INJECT_ACCESSOR_KEY)) return;
|
|
33
|
+
return meta[INJECT_ACCESSOR_KEY];
|
|
48
34
|
}
|
|
49
35
|
};
|
|
36
|
+
const defaultMetadataReader = new SymbolMetadataReader();
|
|
50
37
|
//#endregion
|
|
51
|
-
export { SymbolMetadataReader };
|
|
38
|
+
export { SymbolMetadataReader, defaultMetadataReader };
|