@codefast/di 0.3.14-canary.1 → 0.3.14
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 +58 -0
- package/README.md +42 -26
- 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 -335
- package/dist/binding.mjs +19 -332
- 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 +43 -122
- package/dist/container.mjs +667 -482
- 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 +70 -189
- package/dist/errors.mjs +92 -219
- package/dist/graph-adapters/cytoscape.d.mts +21 -7
- package/dist/graph-adapters/cytoscape.mjs +18 -35
- package/dist/graph-adapters/dot.d.mts +1 -4
- package/dist/graph-adapters/dot.mjs +6 -86
- package/dist/graph-adapters/reactflow.d.mts +26 -7
- package/dist/graph-adapters/reactflow.mjs +21 -72
- package/dist/graph-adapters/types.d.mts +2 -91
- package/dist/index.d.mts +16 -8
- package/dist/index.mjs +8 -5
- package/dist/inspector.d.mts +35 -74
- package/dist/inspector.mjs +61 -88
- 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 +26 -75
- 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 -96
- 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 -106
- package/dist/scope.mjs +37 -196
- 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 +36 -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
|
@@ -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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
readonly
|
|
11
|
-
readonly
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
readonly token: Token<unknown> | Constructor<unknown>; /** Whether missing binding resolves to `undefined`. */
|
|
30
|
-
readonly optional: boolean; /** Optional named-binding discriminator. */
|
|
31
|
-
readonly name?: string; /** Optional tagged-binding discriminator. */
|
|
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
|
-
/** Token/constructor to resolve. */readonly token: Token<Value> | Constructor<Value>; /** Whether unbound token should resolve as `undefined`. */
|
|
45
|
-
readonly optional: boolean; /** Optional named-binding discriminator. */
|
|
46
|
-
readonly name?: string; /** Optional tagged-binding discriminator. */
|
|
47
|
-
readonly tag?: readonly [tag: string, value: unknown]; /** When true, resolve every binding for {@link InjectionDescriptor.token} into an array. */
|
|
48
|
-
readonly all?: boolean;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* Constructor injection shape stored on the class `Symbol.metadata` object.
|
|
52
|
-
*/
|
|
53
|
-
type ConstructorMetadata = {
|
|
54
|
-
/** Ordered constructor dependency descriptors. */readonly params: readonly ParamMetadata[];
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* Abstraction for reading DI metadata without tying callers to `Symbol.metadata` directly.
|
|
58
|
-
* The {@link DependencyResolver} uses this to instantiate `class` bindings and read lifecycle hooks.
|
|
59
|
-
*
|
|
60
|
-
* The default implementation is {@link SymbolMetadataReader}; consumers can supply a custom
|
|
61
|
-
* reader (e.g. backed by a static config object) via `ResolverDependencies.metadataReader`.
|
|
62
|
-
*/
|
|
63
|
-
type MetadataReader = {
|
|
64
|
-
/**
|
|
65
|
-
* Returns constructor parameter injection metadata for `implementationClass`, or `undefined`
|
|
66
|
-
* if the class has no own `@injectable()` metadata. When a {@link MetadataReader} is
|
|
67
|
-
* configured on the container, `undefined` here combined with `arity > 0` on the class
|
|
68
|
-
* causes {@link MissingMetadataError} during resolution; when no reader is configured, the
|
|
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
|
-
};
|
|
5
|
+
interface ParamMetadata {
|
|
6
|
+
readonly index: number;
|
|
7
|
+
readonly token: Token<unknown> | Constructor;
|
|
8
|
+
readonly optional: boolean;
|
|
9
|
+
readonly multi: boolean;
|
|
10
|
+
readonly name?: string;
|
|
11
|
+
readonly tags?: ReadonlyArray<readonly [string, unknown]>;
|
|
12
|
+
}
|
|
13
|
+
interface ConstructorMetadata {
|
|
14
|
+
readonly params: readonly ParamMetadata[];
|
|
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 };
|
package/dist/module.d.mts
CHANGED
|
@@ -1,104 +1,38 @@
|
|
|
1
|
+
import { Constructor } from "./constructor-type.mjs";
|
|
1
2
|
import { Token } from "./token.mjs";
|
|
2
|
-
import {
|
|
3
|
+
import { BindToBuilder } from "./binding.mjs";
|
|
3
4
|
|
|
4
5
|
//#region src/module.d.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* passing an {@link AsyncModule} throws {@link InternalError}) and `bind()` to register tokens.
|
|
9
|
-
*
|
|
10
|
-
* **Single slot (last-wins)** — `bind(key).to*(...)` with no `whenNamed` / `whenTagged` / `when`
|
|
11
|
-
* *before* the `to*()` call replaces all prior bindings for `key` from this module pass.
|
|
12
|
-
*
|
|
13
|
-
* **Multi-binding** — put at least one disambiguator *before* `to*()` (e.g.
|
|
14
|
-
* `bind(key).whenNamed("a").to*(...)`, `whenTagged` before `to*()`, or `when` before `to*()`).
|
|
15
|
-
* Each such line **appends** another binding so {@link Container.resolveAll} can return every
|
|
16
|
-
* implementation. Use this order in modules; chaining `.to*(...).whenNamed()` only updates that
|
|
17
|
-
* binding in place and does not stack multiple registrations across lines.
|
|
18
|
-
*/
|
|
19
|
-
type ModuleBuilder = {
|
|
20
|
-
/**
|
|
21
|
-
* Declares synchronous module dependencies to load before/alongside current setup.
|
|
22
|
-
*/
|
|
23
|
-
readonly import: (...modules: Module[]) => void;
|
|
24
|
-
/**
|
|
25
|
-
* Starts binding registration for a token/constructor within this module setup pass.
|
|
26
|
-
*/
|
|
27
|
-
readonly bind: <Value>(key: Token<Value> | Constructor<Value>) => BindingBuilder<Value>;
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* Builder passed to the setup callback of an {@link AsyncModule}.
|
|
31
|
-
* Unlike {@link ModuleBuilder}, `import()` accepts both sync and async modules.
|
|
32
|
-
* Async sub-imports are collected and awaited **after** the setup callback returns.
|
|
33
|
-
*/
|
|
34
|
-
type AsyncModuleBuilder = {
|
|
35
|
-
/**
|
|
36
|
-
* Declares sync/async module dependencies to be loaded by the async module loader.
|
|
37
|
-
*/
|
|
38
|
-
readonly import: (...modules: (Module | AsyncModule)[]) => void;
|
|
39
|
-
/**
|
|
40
|
-
* Starts binding registration for a token/constructor within this async module setup pass.
|
|
41
|
-
*/
|
|
42
|
-
readonly bind: <Value>(key: Token<Value> | Constructor<Value>) => BindingBuilder<Value>;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Immutable description of a bundle of bindings. A {@link Module} holds no runtime state and the
|
|
46
|
-
* same instance may be loaded into any number of containers independently (spec §7.3).
|
|
47
|
-
*
|
|
48
|
-
* The owning container is responsible for tracking which modules have been loaded and which
|
|
49
|
-
* binding ids each module produced; the module itself never sees a container reference.
|
|
50
|
-
*/
|
|
51
|
-
declare class Module {
|
|
52
|
-
/**
|
|
53
|
-
* Human-readable label used in error messages, graph output, and module-cycle diagnostics.
|
|
54
|
-
*/
|
|
6
|
+
declare const SYNC_MODULE_BRAND: unique symbol;
|
|
7
|
+
declare const ASYNC_MODULE_BRAND: unique symbol;
|
|
8
|
+
interface SyncModule {
|
|
55
9
|
readonly name: string;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*/
|
|
59
|
-
private readonly syncSetup;
|
|
60
|
-
/**
|
|
61
|
-
* @internal Use {@link Module.create} instead.
|
|
62
|
-
*/
|
|
63
|
-
private constructor();
|
|
64
|
-
/**
|
|
65
|
-
* Defines a synchronous module.
|
|
66
|
-
* @param name - Human-readable label used in error messages and debug output.
|
|
67
|
-
* @param setup - Callback that registers bindings via the {@link ModuleBuilder}.
|
|
68
|
-
*/
|
|
69
|
-
static create(name: string, setup: (builder: ModuleBuilder) => void): Module;
|
|
70
|
-
/**
|
|
71
|
-
* Defines an async module — use when setup requires awaiting (e.g. reading config, dynamic imports).
|
|
72
|
-
* Load with {@link Container.loadAsync} or {@link Container.fromModulesAsync}.
|
|
73
|
-
*/
|
|
74
|
-
static createAsync(name: string, setup: (builder: AsyncModuleBuilder) => Promise<void>): AsyncModule;
|
|
75
|
-
/**
|
|
76
|
-
* @internal Invoked by the container while loading this module.
|
|
77
|
-
*/
|
|
78
|
-
runSyncSetup(builder: ModuleBuilder): void;
|
|
10
|
+
readonly [SYNC_MODULE_BRAND]: true;
|
|
11
|
+
readonly _setup: (builder: ModuleBuilder) => void;
|
|
79
12
|
}
|
|
80
|
-
|
|
81
|
-
* An async module whose setup callback may `await` before registering bindings.
|
|
82
|
-
* Prefer {@link Module.createAsync} over constructing this class directly.
|
|
83
|
-
*
|
|
84
|
-
* Load via `Container.loadAsync()` or `Container.fromModulesAsync()`;
|
|
85
|
-
* passing an `AsyncModule` to the synchronous `Container.load()` throws
|
|
86
|
-
* {@link AsyncModuleLoadError}.
|
|
87
|
-
*/
|
|
88
|
-
declare class AsyncModule {
|
|
89
|
-
/**
|
|
90
|
-
* Human-readable label used in error messages and graph output.
|
|
91
|
-
*/
|
|
13
|
+
interface AsyncModule {
|
|
92
14
|
readonly name: string;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
15
|
+
readonly [ASYNC_MODULE_BRAND]: true;
|
|
16
|
+
readonly _setup: (builder: AsyncModuleBuilder) => Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
interface ModuleBuilder {
|
|
19
|
+
bind<const Value>(token: Token<Value> | Constructor<Value>): BindToBuilder<Value>;
|
|
20
|
+
import(...modules: SyncModule[]): void;
|
|
21
|
+
}
|
|
22
|
+
interface AsyncModuleBuilder {
|
|
23
|
+
bind<const Value>(token: Token<Value> | Constructor<Value>): BindToBuilder<Value>;
|
|
24
|
+
import(...modules: Array<SyncModule | AsyncModule>): void;
|
|
102
25
|
}
|
|
26
|
+
declare const SyncModule: {
|
|
27
|
+
create(name: string, setup: (builder: ModuleBuilder) => void): SyncModule;
|
|
28
|
+
};
|
|
29
|
+
declare const AsyncModule: {
|
|
30
|
+
create(name: string, setup: (builder: AsyncModuleBuilder) => Promise<void>): AsyncModule;
|
|
31
|
+
};
|
|
32
|
+
declare const Module: {
|
|
33
|
+
create(name: string, setup: (builder: ModuleBuilder) => void): SyncModule;
|
|
34
|
+
createAsync(name: string, setup: (builder: AsyncModuleBuilder) => Promise<void>): AsyncModule;
|
|
35
|
+
};
|
|
36
|
+
declare function isSyncModule(m: SyncModule | AsyncModule): m is SyncModule;
|
|
103
37
|
//#endregion
|
|
104
|
-
export { AsyncModule, AsyncModuleBuilder, Module, ModuleBuilder };
|
|
38
|
+
export { AsyncModule, AsyncModuleBuilder, Module, ModuleBuilder, SyncModule, isSyncModule };
|
package/dist/module.mjs
CHANGED
|
@@ -1,76 +1,30 @@
|
|
|
1
1
|
//#region src/module.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Defines a synchronous module.
|
|
27
|
-
* @param name - Human-readable label used in error messages and debug output.
|
|
28
|
-
* @param setup - Callback that registers bindings via the {@link ModuleBuilder}.
|
|
29
|
-
*/
|
|
30
|
-
static create(name, setup) {
|
|
31
|
-
return new Module(name, setup);
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Defines an async module — use when setup requires awaiting (e.g. reading config, dynamic imports).
|
|
35
|
-
* Load with {@link Container.loadAsync} or {@link Container.fromModulesAsync}.
|
|
36
|
-
*/
|
|
37
|
-
static createAsync(name, setup) {
|
|
38
|
-
return new AsyncModule(name, setup);
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* @internal Invoked by the container while loading this module.
|
|
42
|
-
*/
|
|
43
|
-
runSyncSetup(builder) {
|
|
44
|
-
this.syncSetup(builder);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* An async module whose setup callback may `await` before registering bindings.
|
|
49
|
-
* Prefer {@link Module.createAsync} over constructing this class directly.
|
|
50
|
-
*
|
|
51
|
-
* Load via `Container.loadAsync()` or `Container.fromModulesAsync()`;
|
|
52
|
-
* passing an `AsyncModule` to the synchronous `Container.load()` throws
|
|
53
|
-
* {@link AsyncModuleLoadError}.
|
|
54
|
-
*/
|
|
55
|
-
var AsyncModule = class {
|
|
56
|
-
/**
|
|
57
|
-
* Human-readable label used in error messages and graph output.
|
|
58
|
-
*/
|
|
59
|
-
name;
|
|
60
|
-
/**
|
|
61
|
-
* The user-supplied async setup callback; invoked exactly once per `loadAsync()` call.
|
|
62
|
-
*/
|
|
63
|
-
asyncSetup;
|
|
64
|
-
constructor(name, asyncSetup) {
|
|
65
|
-
this.name = name;
|
|
66
|
-
this.asyncSetup = asyncSetup;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* @internal Invoked by the container while loading this module.
|
|
70
|
-
*/
|
|
71
|
-
async runAsyncSetup(builder) {
|
|
72
|
-
await this.asyncSetup(builder);
|
|
2
|
+
const SYNC_MODULE_BRAND = Symbol("di:sync-module");
|
|
3
|
+
const ASYNC_MODULE_BRAND = Symbol("di:async-module");
|
|
4
|
+
const SyncModule = { create(name, setup) {
|
|
5
|
+
return {
|
|
6
|
+
name,
|
|
7
|
+
[SYNC_MODULE_BRAND]: true,
|
|
8
|
+
_setup: setup
|
|
9
|
+
};
|
|
10
|
+
} };
|
|
11
|
+
const AsyncModule = { create(name, setup) {
|
|
12
|
+
return {
|
|
13
|
+
name,
|
|
14
|
+
[ASYNC_MODULE_BRAND]: true,
|
|
15
|
+
_setup: setup
|
|
16
|
+
};
|
|
17
|
+
} };
|
|
18
|
+
const Module = {
|
|
19
|
+
create(name, setup) {
|
|
20
|
+
return SyncModule.create(name, setup);
|
|
21
|
+
},
|
|
22
|
+
createAsync(name, setup) {
|
|
23
|
+
return AsyncModule.create(name, setup);
|
|
73
24
|
}
|
|
74
25
|
};
|
|
26
|
+
function isSyncModule(m) {
|
|
27
|
+
return m[SYNC_MODULE_BRAND] === true;
|
|
28
|
+
}
|
|
75
29
|
//#endregion
|
|
76
|
-
export { AsyncModule, Module };
|
|
30
|
+
export { AsyncModule, Module, SyncModule, isSyncModule };
|
package/dist/registry.d.mts
CHANGED
|
@@ -1,69 +1,38 @@
|
|
|
1
|
+
import { Constructor } from "./constructor-type.mjs";
|
|
1
2
|
import { Token } from "./token.mjs";
|
|
2
|
-
import {
|
|
3
|
+
import { BindingIdentifier } from "./types.mjs";
|
|
4
|
+
import { Binding } from "./binding.mjs";
|
|
3
5
|
|
|
4
6
|
//#region src/registry.d.ts
|
|
5
|
-
/**
|
|
6
|
-
* Key used to group {@link Binding} instances in the registry (reference equality for tokens).
|
|
7
|
-
*/
|
|
8
|
-
type RegistryKey = Token<unknown> | Constructor<unknown>;
|
|
9
|
-
/**
|
|
10
|
-
* Flat, in-memory storage for {@link Binding} entries keyed by {@link RegistryKey}.
|
|
11
|
-
* Each key maps to an ordered list of bindings (multi-binding support).
|
|
12
|
-
*
|
|
13
|
-
* The registry is a "dumb" store — it does not perform selection, scope caching, or
|
|
14
|
-
* lifecycle management. Those concerns live in `DependencyResolver` and `ScopeManager`.
|
|
15
|
-
*
|
|
16
|
-
* Mutation styles:
|
|
17
|
-
* - `add` — append-only; never removes existing entries.
|
|
18
|
-
* - `replaceById` — swaps a single binding in place by ID; no removal callback.
|
|
19
|
-
* - `remove` / `removeById` — delete entries **without** notifying callers; the caller
|
|
20
|
-
* is responsible for draining the scope cache before calling these.
|
|
21
|
-
* - `replaceKeyLastWins` — replaces all bindings for a key with a single new one **and**
|
|
22
|
-
* invokes the `onReplaced` callback for each evicted binding, giving the caller
|
|
23
|
-
* (typically the container or scope manager) a chance to run deactivation.
|
|
24
|
-
*/
|
|
25
7
|
declare class BindingRegistry {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
*/
|
|
55
|
-
removeById(id: BindingIdentifier): void;
|
|
56
|
-
/**
|
|
57
|
-
* Swaps the binding with the given `id` in place, preserving its position in the list.
|
|
58
|
-
*/
|
|
59
|
-
replaceById(id: BindingIdentifier, next: Binding<unknown>): void;
|
|
60
|
-
/**
|
|
61
|
-
* Replaces all bindings for `key` with a single new binding (module "last-wins" semantics).
|
|
62
|
-
* Unlike {@link remove} / {@link removeById}, this method invokes `onReplaced` for every
|
|
63
|
-
* evicted binding **before** inserting the replacement, giving the caller (e.g. the
|
|
64
|
-
* container's scope manager) a chance to release cached instances and run deactivation hooks.
|
|
65
|
-
*/
|
|
66
|
-
replaceKeyLastWins<Value>(key: Token<Value> | Constructor<Value>, binding: Binding<Value>, onReplaced: (removed: Binding<unknown>) => void): void;
|
|
8
|
+
private readonly _bindings;
|
|
9
|
+
private readonly _byId;
|
|
10
|
+
private readonly _simpleNamed;
|
|
11
|
+
private readonly _fastDefault;
|
|
12
|
+
/** Add or replace binding using slot-aware last-wins. */
|
|
13
|
+
add(binding: Binding): void;
|
|
14
|
+
/** Remove all bindings for a token. Returns removed bindings. */
|
|
15
|
+
removeByToken(t: Token<unknown> | Constructor): Binding[];
|
|
16
|
+
/** Remove a specific binding by ID. Returns the removed binding or undefined. */
|
|
17
|
+
removeById(id: BindingIdentifier): Binding | undefined;
|
|
18
|
+
/** Get all bindings for a token. */
|
|
19
|
+
getAll(t: Token<unknown> | Constructor): readonly Binding[];
|
|
20
|
+
/** Get binding by ID. */
|
|
21
|
+
getById(id: BindingIdentifier): Binding | undefined;
|
|
22
|
+
/** Check if any binding exists for token. */
|
|
23
|
+
has(t: Token<unknown> | Constructor): boolean;
|
|
24
|
+
/** All bindings in the registry. */
|
|
25
|
+
allBindings(): readonly Binding[];
|
|
26
|
+
/** Remove all bindings. Returns all removed. */
|
|
27
|
+
clear(): readonly Binding[];
|
|
28
|
+
getSimpleNamed(token: Token<unknown> | Constructor, name: string): Binding | undefined;
|
|
29
|
+
getFastDefault(token: Token<unknown> | Constructor): Binding | undefined;
|
|
30
|
+
/** Summarize available slot strings for a token (for error messages). */
|
|
31
|
+
availableSlotStrings(t: Token<unknown> | Constructor): string[];
|
|
32
|
+
private _isPurePredicateBinding;
|
|
33
|
+
private _indexSimpleNamedBinding;
|
|
34
|
+
private _deindexSimpleNamedBinding;
|
|
35
|
+
private _refreshFastDefaultForToken;
|
|
67
36
|
}
|
|
68
37
|
//#endregion
|
|
69
|
-
export { BindingRegistry
|
|
38
|
+
export { BindingRegistry };
|