@fluojs/di 1.1.0 → 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.ko.md +129 -26
- package/README.md +129 -26
- package/dist/container.d.ts +79 -17
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +564 -197
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -2
- package/dist/internal.d.ts +18 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +26 -0
- package/dist/multi-contribution-registry.d.ts +26 -0
- package/dist/multi-contribution-registry.d.ts.map +1 -0
- package/dist/multi-contribution-registry.js +29 -0
- package/dist/provider-normalization.d.ts +17 -0
- package/dist/provider-normalization.d.ts.map +1 -0
- package/dist/provider-normalization.js +216 -0
- package/dist/types.d.ts +10 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -4
- package/package.json +9 -5
package/dist/errors.d.ts
CHANGED
|
@@ -48,7 +48,8 @@ export declare class ScopeMismatchError extends FluoCodeError {
|
|
|
48
48
|
*
|
|
49
49
|
* @remarks
|
|
50
50
|
* The formatted message includes the full dependency path plus a first-party hint that points callers toward
|
|
51
|
-
* extracting shared logic or
|
|
51
|
+
* extracting shared logic, introducing a mediator, or moving the interaction to a later boundary.
|
|
52
|
+
* `forwardRef()` only defers declaration-time token lookup and cannot resolve a true constructor cycle.
|
|
52
53
|
*/
|
|
53
54
|
export declare class CircularDependencyError extends FluoCodeError {
|
|
54
55
|
constructor(chain: readonly unknown[], detail?: string);
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAmB,MAAM,cAAc,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAgCD;;;;;;GAMG;AACH,qBAAa,oBAAqB,SAAQ,aAAa;gBACzC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc;CAOtD;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,aAAa;gBAC7C,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc;CAOtD;AAED;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,aAAa;gBAChD,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc;CAOtD;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc;CAOtD;AAED
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAmB,MAAM,cAAc,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAgCD;;;;;;GAMG;AACH,qBAAa,oBAAqB,SAAQ,aAAa;gBACzC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc;CAOtD;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,aAAa;gBAC7C,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc;CAOtD;AAED;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,aAAa;gBAChD,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc;CAOtD;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc;CAOtD;AAED;;;;;;;GAOG;AACH,qBAAa,uBAAwB,SAAQ,aAAa;gBAC5C,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM;CAWvD;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,aAAa;gBAC3C,KAAK,EAAE,OAAO;CAW3B"}
|
package/dist/errors.js
CHANGED
|
@@ -85,12 +85,13 @@ export class ScopeMismatchError extends FluoCodeError {
|
|
|
85
85
|
*
|
|
86
86
|
* @remarks
|
|
87
87
|
* The formatted message includes the full dependency path plus a first-party hint that points callers toward
|
|
88
|
-
* extracting shared logic or
|
|
88
|
+
* extracting shared logic, introducing a mediator, or moving the interaction to a later boundary.
|
|
89
|
+
* `forwardRef()` only defers declaration-time token lookup and cannot resolve a true constructor cycle.
|
|
89
90
|
*/
|
|
90
91
|
export class CircularDependencyError extends FluoCodeError {
|
|
91
92
|
constructor(chain, detail) {
|
|
92
93
|
const path = chain.map(token => formatTokenName(token)).join(' -> ');
|
|
93
|
-
const hint = 'Break the cycle by extracting shared logic into a separate provider, or
|
|
94
|
+
const hint = 'Break the constructor cycle by extracting shared logic into a separate provider, introducing a mediator, or moving the interaction to a later boundary. forwardRef() only defers declaration-time token lookup and cannot resolve a true constructor cycle.';
|
|
94
95
|
super((detail ? `Circular dependency detected: ${path}. ${detail}` : `Circular dependency detected: ${path}`) + `\n Dependency chain: ${path}` + `\n Hint: ${hint}`, 'CIRCULAR_DEPENDENCY', {
|
|
95
96
|
meta: {
|
|
96
97
|
chain: chain.map(t => formatTokenName(t)),
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Token } from '@fluojs/core';
|
|
2
|
+
import { type MultiContributionResolverOwner } from './multi-contribution-registry.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves one ordered multi-provider contribution through its owning container.
|
|
5
|
+
*
|
|
6
|
+
* This integration seam is for Fluo packages such as `@fluojs/runtime` and
|
|
7
|
+
* `@fluojs/testing`; application code must use `Container.resolve(...)`.
|
|
8
|
+
*
|
|
9
|
+
* @param container Container that owns the multi-provider registration.
|
|
10
|
+
* @param token Multi-provider token.
|
|
11
|
+
* @param contributionIndex Provider-order index for the contribution.
|
|
12
|
+
* @returns The canonical container-resolved contribution instance.
|
|
13
|
+
* @throws {ContainerResolutionError} When the container has no registered internal resolver.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveMultiContribution(container: MultiContributionResolverOwner, token: Token, contributionIndex: number): Promise<unknown>;
|
|
16
|
+
export { validateProviderInputs } from './provider-normalization.js';
|
|
17
|
+
export type { Provider } from './types.js';
|
|
18
|
+
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,EACL,KAAK,8BAA8B,EAEpC,MAAM,kCAAkC,CAAC;AAE1C;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,8BAA8B,EACzC,KAAK,EAAE,KAAK,EACZ,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,OAAO,CAAC,CAWlB;AAED,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ContainerResolutionError } from './errors.js';
|
|
2
|
+
import { multiContributionResolverFor } from './multi-contribution-registry.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolves one ordered multi-provider contribution through its owning container.
|
|
6
|
+
*
|
|
7
|
+
* This integration seam is for Fluo packages such as `@fluojs/runtime` and
|
|
8
|
+
* `@fluojs/testing`; application code must use `Container.resolve(...)`.
|
|
9
|
+
*
|
|
10
|
+
* @param container Container that owns the multi-provider registration.
|
|
11
|
+
* @param token Multi-provider token.
|
|
12
|
+
* @param contributionIndex Provider-order index for the contribution.
|
|
13
|
+
* @returns The canonical container-resolved contribution instance.
|
|
14
|
+
* @throws {ContainerResolutionError} When the container has no registered internal resolver.
|
|
15
|
+
*/
|
|
16
|
+
export async function resolveMultiContribution(container, token, contributionIndex) {
|
|
17
|
+
const resolver = multiContributionResolverFor(container);
|
|
18
|
+
if (!resolver) {
|
|
19
|
+
throw new ContainerResolutionError('Container does not expose the internal multi-provider contribution resolver.', {
|
|
20
|
+
token,
|
|
21
|
+
hint: 'Create the container through the @fluojs/di Container constructor.'
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return resolver(token, contributionIndex);
|
|
25
|
+
}
|
|
26
|
+
export { validateProviderInputs } from './provider-normalization.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Token } from '@fluojs/core';
|
|
2
|
+
type MultiContributionResolver = (token: Token, contributionIndex: number) => Promise<unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* Object identity that owns a canonical multi-provider contribution resolver.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export type MultiContributionResolverOwner = object;
|
|
9
|
+
/**
|
|
10
|
+
* Associates a container with its canonical multi-provider contribution resolver.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
* @param container Container that owns the resolver.
|
|
14
|
+
* @param resolver Container-bound resolver that preserves DI lifecycle invariants.
|
|
15
|
+
*/
|
|
16
|
+
export declare function registerMultiContributionResolver(container: MultiContributionResolverOwner, resolver: MultiContributionResolver): void;
|
|
17
|
+
/**
|
|
18
|
+
* Retrieves the canonical multi-provider contribution resolver for a container.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
* @param container Container that owns the resolver.
|
|
22
|
+
* @returns The container-bound resolver, if the container registered one.
|
|
23
|
+
*/
|
|
24
|
+
export declare function multiContributionResolverFor(container: MultiContributionResolverOwner): MultiContributionResolver | undefined;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=multi-contribution-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-contribution-registry.d.ts","sourceRoot":"","sources":["../src/multi-contribution-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,KAAK,yBAAyB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE/F;;;;GAIG;AACH,MAAM,MAAM,8BAA8B,GAAG,MAAM,CAAC;AAIpD;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,SAAS,EAAE,8BAA8B,EACzC,QAAQ,EAAE,yBAAyB,GAClC,IAAI,CAEN;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,8BAA8B,GACxC,yBAAyB,GAAG,SAAS,CAEvC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object identity that owns a canonical multi-provider contribution resolver.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const multiContributionResolvers = new WeakMap();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Associates a container with its canonical multi-provider contribution resolver.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
* @param container Container that owns the resolver.
|
|
14
|
+
* @param resolver Container-bound resolver that preserves DI lifecycle invariants.
|
|
15
|
+
*/
|
|
16
|
+
export function registerMultiContributionResolver(container, resolver) {
|
|
17
|
+
multiContributionResolvers.set(container, resolver);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Retrieves the canonical multi-provider contribution resolver for a container.
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
* @param container Container that owns the resolver.
|
|
25
|
+
* @returns The container-bound resolver, if the container registered one.
|
|
26
|
+
*/
|
|
27
|
+
export function multiContributionResolverFor(container) {
|
|
28
|
+
return multiContributionResolvers.get(container);
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { NormalizedProvider, Provider } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validates and snapshots a public provider declaration for container registration.
|
|
4
|
+
*
|
|
5
|
+
* @param provider Provider declaration crossing the container registration boundary.
|
|
6
|
+
* @returns An immutable provider record with normalized injection and scope fields.
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeProvider(provider: Provider): NormalizedProvider;
|
|
9
|
+
/**
|
|
10
|
+
* Validates provider declarations through the same normalization path used by `Container` registration.
|
|
11
|
+
*
|
|
12
|
+
* @param providers Provider declarations crossing an internal framework integration boundary.
|
|
13
|
+
* @returns The original provider list after every declaration has passed canonical normalization.
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export declare function validateProviderInputs(providers: Provider[]): Provider[];
|
|
17
|
+
//# sourceMappingURL=provider-normalization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-normalization.d.ts","sourceRoot":"","sources":["../src/provider-normalization.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAA2B,kBAAkB,EAAiB,QAAQ,EAAE,MAAM,YAAY,CAAC;AA6JvG;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,kBAAkB,CAuFxE;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAMxE"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { getClassDiMetadata } from '@fluojs/core/internal';
|
|
2
|
+
import { InvalidProviderError } from './errors.js';
|
|
3
|
+
import { Scope } from './types.js';
|
|
4
|
+
function isClassConstructor(value) {
|
|
5
|
+
return isConstructableFunction(value);
|
|
6
|
+
}
|
|
7
|
+
function isProviderObject(value) {
|
|
8
|
+
return typeof value === 'object' && value !== null;
|
|
9
|
+
}
|
|
10
|
+
function isClassType(value) {
|
|
11
|
+
return isConstructableFunction(value);
|
|
12
|
+
}
|
|
13
|
+
function isFactoryFunction(value) {
|
|
14
|
+
return typeof value === 'function';
|
|
15
|
+
}
|
|
16
|
+
function isTokenResolver(value) {
|
|
17
|
+
return typeof value === 'function';
|
|
18
|
+
}
|
|
19
|
+
function isConstructableFunction(value) {
|
|
20
|
+
if (typeof value !== 'function') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
Reflect.construct(Object, [], value);
|
|
25
|
+
return true;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (error instanceof TypeError) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function isToken(value) {
|
|
34
|
+
return typeof value === 'string' || typeof value === 'symbol' || isConstructableFunction(value);
|
|
35
|
+
}
|
|
36
|
+
function isScope(value) {
|
|
37
|
+
return value === 'singleton' || value === 'request' || value === 'transient';
|
|
38
|
+
}
|
|
39
|
+
function assertProviderToken(provider) {
|
|
40
|
+
if (!('provide' in provider) || !isToken(provider.provide)) {
|
|
41
|
+
throw new InvalidProviderError('Provider object must include a string, symbol, or constructable class provide token.');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function assertProviderStrategy(provider) {
|
|
45
|
+
const strategyCount = Number('useValue' in provider) + Number('useFactory' in provider) + Number('useClass' in provider) + Number('useExisting' in provider);
|
|
46
|
+
if (strategyCount !== 1) {
|
|
47
|
+
throw new InvalidProviderError('Provider object must declare exactly one of useValue, useFactory, useClass, or useExisting.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function assertObjectProvider(provider) {
|
|
51
|
+
assertProviderToken(provider);
|
|
52
|
+
assertProviderStrategy(provider);
|
|
53
|
+
}
|
|
54
|
+
function normalizeProviderScope(scope, providerToken) {
|
|
55
|
+
if (scope === undefined) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
if (isScope(scope)) {
|
|
59
|
+
return scope;
|
|
60
|
+
}
|
|
61
|
+
throw new InvalidProviderError('Provider scope must be one of singleton, request, or transient.', {
|
|
62
|
+
token: providerToken,
|
|
63
|
+
scope: String(scope),
|
|
64
|
+
hint: 'Use Scope.DEFAULT, Scope.REQUEST, Scope.TRANSIENT, or the matching string literal.'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function normalizeInjectToken(token, providerToken, index) {
|
|
68
|
+
if (typeof token === 'object' && token !== null && '__forwardRef__' in token && token.__forwardRef__ === true) {
|
|
69
|
+
if (!('forwardRef' in token) || !isTokenResolver(token.forwardRef)) {
|
|
70
|
+
throw new InvalidProviderError(`Provider inject forwardRef wrapper at index ${String(index)} must expose a callable forwardRef function.`, {
|
|
71
|
+
token: providerToken
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return Object.freeze({
|
|
75
|
+
__forwardRef__: true,
|
|
76
|
+
forwardRef: token.forwardRef
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (typeof token === 'object' && token !== null && '__optional__' in token && token.__optional__ === true) {
|
|
80
|
+
if (!('token' in token) || !isToken(token.token)) {
|
|
81
|
+
throw new InvalidProviderError(`Provider inject optional wrapper at index ${String(index)} must contain a valid token.`, {
|
|
82
|
+
token: providerToken
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return Object.freeze({
|
|
86
|
+
__optional__: true,
|
|
87
|
+
token: token.token
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (isToken(token)) {
|
|
91
|
+
return token;
|
|
92
|
+
}
|
|
93
|
+
throw new InvalidProviderError(`Provider inject entry at index ${String(index)} must be a string, symbol, class, forwardRef(), or optional() token wrapper.`, {
|
|
94
|
+
token: providerToken,
|
|
95
|
+
hint: 'Check that every dependency token is defined, and use forwardRef() for declaration-order cycles.'
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function normalizeInject(inject, providerToken) {
|
|
99
|
+
if (inject === undefined) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
if (!Array.isArray(inject)) {
|
|
103
|
+
throw new InvalidProviderError('Provider inject must be an array.', {
|
|
104
|
+
token: providerToken,
|
|
105
|
+
hint: 'Pass dependency tokens as inject: [DependencyA, DependencyB].'
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return inject.map((token, index) => normalizeInjectToken(token, providerToken, index));
|
|
109
|
+
}
|
|
110
|
+
function freezeNormalizedProvider(provider) {
|
|
111
|
+
return Object.freeze({
|
|
112
|
+
...provider,
|
|
113
|
+
inject: Object.freeze([...provider.inject])
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Validates and snapshots a public provider declaration for container registration.
|
|
119
|
+
*
|
|
120
|
+
* @param provider Provider declaration crossing the container registration boundary.
|
|
121
|
+
* @returns An immutable provider record with normalized injection and scope fields.
|
|
122
|
+
*/
|
|
123
|
+
export function normalizeProvider(provider) {
|
|
124
|
+
if (isClassConstructor(provider)) {
|
|
125
|
+
const metadata = getClassDiMetadata(provider);
|
|
126
|
+
return freezeNormalizedProvider({
|
|
127
|
+
inject: normalizeInject(metadata?.inject, provider),
|
|
128
|
+
provide: provider,
|
|
129
|
+
scope: normalizeProviderScope(metadata?.scope, provider) ?? Scope.DEFAULT,
|
|
130
|
+
type: 'class',
|
|
131
|
+
useClass: provider
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (!isProviderObject(provider)) {
|
|
135
|
+
throw new InvalidProviderError('Unsupported provider type.');
|
|
136
|
+
}
|
|
137
|
+
const objectProvider = provider;
|
|
138
|
+
assertObjectProvider(objectProvider);
|
|
139
|
+
const explicitScope = normalizeProviderScope(objectProvider.scope, objectProvider.provide);
|
|
140
|
+
if ('useValue' in objectProvider) {
|
|
141
|
+
if (Object.hasOwn(objectProvider, 'inject')) {
|
|
142
|
+
throw new InvalidProviderError('Value providers must not declare inject dependencies.', {
|
|
143
|
+
token: objectProvider.provide
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return freezeNormalizedProvider({
|
|
147
|
+
inject: [],
|
|
148
|
+
multi: objectProvider.multi,
|
|
149
|
+
provide: objectProvider.provide,
|
|
150
|
+
scope: Scope.DEFAULT,
|
|
151
|
+
type: 'value',
|
|
152
|
+
useValue: objectProvider.useValue
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if ('useFactory' in objectProvider) {
|
|
156
|
+
if (!isFactoryFunction(objectProvider.useFactory)) {
|
|
157
|
+
throw new InvalidProviderError('Factory provider useFactory must be a function.', {
|
|
158
|
+
token: objectProvider.provide
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
const metadata = objectProvider.resolverClass ? getClassDiMetadata(objectProvider.resolverClass) : undefined;
|
|
162
|
+
return freezeNormalizedProvider({
|
|
163
|
+
inject: normalizeInject(objectProvider.inject, objectProvider.provide),
|
|
164
|
+
multi: objectProvider.multi,
|
|
165
|
+
provide: objectProvider.provide,
|
|
166
|
+
scope: explicitScope ?? normalizeProviderScope(metadata?.scope, objectProvider.provide) ?? Scope.DEFAULT,
|
|
167
|
+
type: 'factory',
|
|
168
|
+
useFactory: objectProvider.useFactory
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if ('useClass' in objectProvider) {
|
|
172
|
+
if (!isClassType(objectProvider.useClass)) {
|
|
173
|
+
throw new InvalidProviderError('Class provider useClass must be a constructor.', {
|
|
174
|
+
token: objectProvider.provide
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const metadata = getClassDiMetadata(objectProvider.useClass);
|
|
178
|
+
return freezeNormalizedProvider({
|
|
179
|
+
inject: normalizeInject(objectProvider.inject === undefined ? metadata?.inject : objectProvider.inject, objectProvider.provide),
|
|
180
|
+
multi: objectProvider.multi,
|
|
181
|
+
provide: objectProvider.provide,
|
|
182
|
+
scope: explicitScope ?? normalizeProviderScope(metadata?.scope, objectProvider.provide) ?? Scope.DEFAULT,
|
|
183
|
+
type: 'class',
|
|
184
|
+
useClass: objectProvider.useClass
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if ('useExisting' in objectProvider) {
|
|
188
|
+
if (!isToken(objectProvider.useExisting)) {
|
|
189
|
+
throw new InvalidProviderError('Alias provider useExisting must be a string, symbol, or constructable class token.', {
|
|
190
|
+
token: objectProvider.provide
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return freezeNormalizedProvider({
|
|
194
|
+
inject: [],
|
|
195
|
+
provide: objectProvider.provide,
|
|
196
|
+
scope: Scope.DEFAULT,
|
|
197
|
+
type: 'existing',
|
|
198
|
+
useExisting: objectProvider.useExisting
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
throw new InvalidProviderError('Provider object must declare exactly one of useValue, useFactory, useClass, or useExisting.');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Validates provider declarations through the same normalization path used by `Container` registration.
|
|
206
|
+
*
|
|
207
|
+
* @param providers Provider declarations crossing an internal framework integration boundary.
|
|
208
|
+
* @returns The original provider list after every declaration has passed canonical normalization.
|
|
209
|
+
* @internal
|
|
210
|
+
*/
|
|
211
|
+
export function validateProviderInputs(providers) {
|
|
212
|
+
for (const provider of providers) {
|
|
213
|
+
normalizeProvider(provider);
|
|
214
|
+
}
|
|
215
|
+
return providers;
|
|
216
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export interface FactoryProvider<T = unknown> {
|
|
|
43
43
|
inject?: InjectionToken[];
|
|
44
44
|
scope?: Scope;
|
|
45
45
|
multi?: boolean;
|
|
46
|
+
/** Class metadata source used when the factory should inherit `@Scope(...)` metadata. */
|
|
46
47
|
resolverClass?: ClassType;
|
|
47
48
|
}
|
|
48
49
|
/**
|
|
@@ -94,15 +95,15 @@ export interface RequestScopeContainer {
|
|
|
94
95
|
* {@link ValueProvider}, or {@link ExistingProvider}. The container owns construction of normalized records.
|
|
95
96
|
*/
|
|
96
97
|
export interface NormalizedProvider<T = unknown> {
|
|
97
|
-
inject: InjectionToken[];
|
|
98
|
-
provide: Token<T>;
|
|
99
|
-
scope: Scope;
|
|
100
|
-
type: 'class' | 'factory' | 'value' | 'existing';
|
|
101
|
-
useClass?: ClassType<T>;
|
|
102
|
-
useFactory?: (...deps: unknown[]) => MaybePromise<T>;
|
|
103
|
-
useValue?: T;
|
|
104
|
-
useExisting?: Token;
|
|
105
|
-
multi?: boolean;
|
|
98
|
+
readonly inject: readonly InjectionToken[];
|
|
99
|
+
readonly provide: Token<T>;
|
|
100
|
+
readonly scope: Scope;
|
|
101
|
+
readonly type: 'class' | 'factory' | 'value' | 'existing';
|
|
102
|
+
readonly useClass?: ClassType<T>;
|
|
103
|
+
readonly useFactory?: (...deps: unknown[]) => MaybePromise<T>;
|
|
104
|
+
readonly useValue?: T;
|
|
105
|
+
readonly useExisting?: Token;
|
|
106
|
+
readonly multi?: boolean;
|
|
106
107
|
}
|
|
107
108
|
/**
|
|
108
109
|
* Wraps a token factory so DI metadata can defer token lookup until resolution time.
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE3H;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC;AAE1D;;GAEG;AACH,yBAAiB,KAAK,CAAC;IACrB;;OAEG;IACI,MAAM,OAAO,EAAE,KAAmB,CAAC;IAE1C;;OAEG;IACI,MAAM,OAAO,EAAE,KAAiB,CAAC;IAExC;;OAEG;IACI,MAAM,SAAS,EAAE,KAAmB,CAAC;CAC7C;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,GAAG,OAAO,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,SAAS,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,QAAQ,EAAE,CAAC,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,OAAO;IAC3C,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,OAAO,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC;AAE3D;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,OAAO,IAAI,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,GAAG,OAAO,IAC5B,SAAS,CAAC,CAAC,CAAC,GACZ,aAAa,CAAC,CAAC,CAAC,GAChB,eAAe,CAAC,CAAC,CAAC,GAClB,aAAa,CAAC,CAAC,CAAC,GAChB,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAExB;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACxC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,OAAO;IAC7C,MAAM,EAAE,cAAc,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -63,10 +63,10 @@ export let Scope;
|
|
|
63
63
|
* ```
|
|
64
64
|
*/
|
|
65
65
|
export function forwardRef(fn) {
|
|
66
|
-
return {
|
|
66
|
+
return Object.freeze({
|
|
67
67
|
__forwardRef__: true,
|
|
68
68
|
forwardRef: fn
|
|
69
|
-
};
|
|
69
|
+
});
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
@@ -86,10 +86,10 @@ export function isForwardRef(value) {
|
|
|
86
86
|
* @returns An optional-token wrapper understood by container resolution.
|
|
87
87
|
*/
|
|
88
88
|
export function optional(token) {
|
|
89
|
-
return {
|
|
89
|
+
return Object.freeze({
|
|
90
90
|
__optional__: true,
|
|
91
91
|
token
|
|
92
|
-
};
|
|
92
|
+
});
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
/**
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"container",
|
|
10
10
|
"provider"
|
|
11
11
|
],
|
|
12
|
-
"version": "
|
|
12
|
+
"version": "3.0.0",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"directory": "packages/di"
|
|
19
19
|
},
|
|
20
20
|
"engines": {
|
|
21
|
-
"node": ">=
|
|
21
|
+
"node": ">=24.0.0 <27"
|
|
22
22
|
},
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
".": {
|
|
29
29
|
"types": "./dist/index.d.ts",
|
|
30
30
|
"import": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./internal": {
|
|
33
|
+
"types": "./dist/internal.d.ts",
|
|
34
|
+
"import": "./dist/internal.js"
|
|
31
35
|
}
|
|
32
36
|
},
|
|
33
37
|
"main": "./dist/index.js",
|
|
@@ -36,15 +40,15 @@
|
|
|
36
40
|
"dist"
|
|
37
41
|
],
|
|
38
42
|
"dependencies": {
|
|
39
|
-
"@fluojs/core": "^
|
|
43
|
+
"@fluojs/core": "^2.0.0"
|
|
40
44
|
},
|
|
41
45
|
"devDependencies": {
|
|
42
|
-
"vitest": "^
|
|
46
|
+
"vitest": "^4.1.11"
|
|
43
47
|
},
|
|
44
48
|
"scripts": {
|
|
45
49
|
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|
|
46
50
|
"build": "pnpm exec babel src --extensions .ts --ignore 'src/**/*.test.ts' --out-dir dist --config-file ../../tooling/babel/babel.config.cjs && pnpm exec tsc -p tsconfig.build.json",
|
|
47
|
-
"typecheck": "pnpm exec tsc -p tsconfig.json --noEmit",
|
|
51
|
+
"typecheck": "pnpm exec tsc -p tsconfig.typecheck.json --noEmit",
|
|
48
52
|
"test": "pnpm exec vitest run -c vitest.config.ts",
|
|
49
53
|
"test:watch": "pnpm exec vitest -c vitest.config.ts"
|
|
50
54
|
}
|