@fluojs/di 1.0.0-beta.1
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/LICENSE +21 -0
- package/README.ko.md +155 -0
- package/README.md +155 -0
- package/dist/container.d.ts +133 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +697 -0
- package/dist/errors.d.ts +62 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +126 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +98 -0
- package/package.json +51 -0
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { FluoCodeError } from '@fluojs/core';
|
|
2
|
+
/**
|
|
3
|
+
* Structured context attached to DI errors so logs and tests can inspect the failing contract.
|
|
4
|
+
*/
|
|
5
|
+
export interface DiErrorContext {
|
|
6
|
+
readonly token?: unknown;
|
|
7
|
+
readonly scope?: string;
|
|
8
|
+
readonly module?: string;
|
|
9
|
+
readonly dependencyChain?: readonly unknown[];
|
|
10
|
+
readonly hint?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Raised when a provider declaration or inject token cannot be normalized into a valid DI registration.
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* This usually points to malformed provider objects, missing `@Inject(...)` tokens, or `null`/
|
|
17
|
+
* `undefined` references that were evaluated before a `forwardRef()` indirection could be applied.
|
|
18
|
+
*/
|
|
19
|
+
export declare class InvalidProviderError extends FluoCodeError {
|
|
20
|
+
constructor(message: string, context?: DiErrorContext);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Raised when the container cannot complete a lifecycle operation such as registration, resolution, or disposal.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* Use the attached context to inspect the token, module, scope, or dependency chain involved in the failed operation.
|
|
27
|
+
*/
|
|
28
|
+
export declare class ContainerResolutionError extends FluoCodeError {
|
|
29
|
+
constructor(message: string, context?: DiErrorContext);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Raised when a request-scoped provider is resolved outside a request container.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* This protects the documented lifecycle guarantee that request-scoped providers are isolated per child scope.
|
|
36
|
+
*/
|
|
37
|
+
export declare class RequestScopeResolutionError extends FluoCodeError {
|
|
38
|
+
constructor(message: string, context?: DiErrorContext);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Raised when a provider scope is registered or consumed from an incompatible container scope.
|
|
42
|
+
*/
|
|
43
|
+
export declare class ScopeMismatchError extends FluoCodeError {
|
|
44
|
+
constructor(message: string, context?: DiErrorContext);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Raised when the container detects a circular dependency chain while resolving providers.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* The formatted message includes the full dependency path plus a first-party hint that points callers toward
|
|
51
|
+
* extracting shared logic or using `forwardRef()` for intentional cycle deferral.
|
|
52
|
+
*/
|
|
53
|
+
export declare class CircularDependencyError extends FluoCodeError {
|
|
54
|
+
constructor(chain: readonly unknown[], detail?: string);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Raised when the same token is registered twice without going through `container.override(...)`.
|
|
58
|
+
*/
|
|
59
|
+
export declare class DuplicateProviderError extends FluoCodeError {
|
|
60
|
+
constructor(token: unknown);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +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;;;;;;GAMG;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
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { FluoCodeError, formatTokenName } from '@fluojs/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Structured context attached to DI errors so logs and tests can inspect the failing contract.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
function formatDiContext(ctx) {
|
|
8
|
+
if (!ctx) return '';
|
|
9
|
+
const parts = [];
|
|
10
|
+
if (ctx.token !== undefined) {
|
|
11
|
+
parts.push(`Token: ${formatTokenName(ctx.token)}`);
|
|
12
|
+
}
|
|
13
|
+
if (ctx.scope) {
|
|
14
|
+
parts.push(`Scope: ${ctx.scope}`);
|
|
15
|
+
}
|
|
16
|
+
if (ctx.module) {
|
|
17
|
+
parts.push(`Module: ${ctx.module}`);
|
|
18
|
+
}
|
|
19
|
+
if (ctx.dependencyChain && ctx.dependencyChain.length > 0) {
|
|
20
|
+
parts.push(`Dependency chain: ${ctx.dependencyChain.map(t => formatTokenName(t)).join(' -> ')}`);
|
|
21
|
+
}
|
|
22
|
+
if (ctx.hint) {
|
|
23
|
+
parts.push(`Hint: ${ctx.hint}`);
|
|
24
|
+
}
|
|
25
|
+
if (parts.length === 0) return '';
|
|
26
|
+
return `\n ${parts.join('\n ')}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Raised when a provider declaration or inject token cannot be normalized into a valid DI registration.
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* This usually points to malformed provider objects, missing `@Inject(...)` tokens, or `null`/
|
|
34
|
+
* `undefined` references that were evaluated before a `forwardRef()` indirection could be applied.
|
|
35
|
+
*/
|
|
36
|
+
export class InvalidProviderError extends FluoCodeError {
|
|
37
|
+
constructor(message, context) {
|
|
38
|
+
super(message + formatDiContext(context), 'INVALID_PROVIDER', context ? {
|
|
39
|
+
meta: buildMeta(context)
|
|
40
|
+
} : undefined);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Raised when the container cannot complete a lifecycle operation such as registration, resolution, or disposal.
|
|
46
|
+
*
|
|
47
|
+
* @remarks
|
|
48
|
+
* Use the attached context to inspect the token, module, scope, or dependency chain involved in the failed operation.
|
|
49
|
+
*/
|
|
50
|
+
export class ContainerResolutionError extends FluoCodeError {
|
|
51
|
+
constructor(message, context) {
|
|
52
|
+
super(message + formatDiContext(context), 'CONTAINER_RESOLUTION_ERROR', context ? {
|
|
53
|
+
meta: buildMeta(context)
|
|
54
|
+
} : undefined);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Raised when a request-scoped provider is resolved outside a request container.
|
|
60
|
+
*
|
|
61
|
+
* @remarks
|
|
62
|
+
* This protects the documented lifecycle guarantee that request-scoped providers are isolated per child scope.
|
|
63
|
+
*/
|
|
64
|
+
export class RequestScopeResolutionError extends FluoCodeError {
|
|
65
|
+
constructor(message, context) {
|
|
66
|
+
super(message + formatDiContext(context), 'REQUEST_SCOPE_RESOLUTION_ERROR', context ? {
|
|
67
|
+
meta: buildMeta(context)
|
|
68
|
+
} : undefined);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Raised when a provider scope is registered or consumed from an incompatible container scope.
|
|
74
|
+
*/
|
|
75
|
+
export class ScopeMismatchError extends FluoCodeError {
|
|
76
|
+
constructor(message, context) {
|
|
77
|
+
super(message + formatDiContext(context), 'SCOPE_MISMATCH', context ? {
|
|
78
|
+
meta: buildMeta(context)
|
|
79
|
+
} : undefined);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Raised when the container detects a circular dependency chain while resolving providers.
|
|
85
|
+
*
|
|
86
|
+
* @remarks
|
|
87
|
+
* The formatted message includes the full dependency path plus a first-party hint that points callers toward
|
|
88
|
+
* extracting shared logic or using `forwardRef()` for intentional cycle deferral.
|
|
89
|
+
*/
|
|
90
|
+
export class CircularDependencyError extends FluoCodeError {
|
|
91
|
+
constructor(chain, detail) {
|
|
92
|
+
const path = chain.map(token => formatTokenName(token)).join(' -> ');
|
|
93
|
+
const hint = 'Break the cycle by extracting shared logic into a separate provider, or use forwardRef() to defer one side of the dependency.';
|
|
94
|
+
super((detail ? `Circular dependency detected: ${path}. ${detail}` : `Circular dependency detected: ${path}`) + `\n Dependency chain: ${path}` + `\n Hint: ${hint}`, 'CIRCULAR_DEPENDENCY', {
|
|
95
|
+
meta: {
|
|
96
|
+
chain: chain.map(t => formatTokenName(t)),
|
|
97
|
+
hint
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Raised when the same token is registered twice without going through `container.override(...)`.
|
|
105
|
+
*/
|
|
106
|
+
export class DuplicateProviderError extends FluoCodeError {
|
|
107
|
+
constructor(token) {
|
|
108
|
+
const name = formatTokenName(token);
|
|
109
|
+
const hint = 'Use container.override() for intentional overrides, or check for accidental double-registration in your module providers array.';
|
|
110
|
+
super(`Token "${name}" is already registered.` + `\n Token: ${name}` + `\n Hint: ${hint}`, 'DUPLICATE_PROVIDER', {
|
|
111
|
+
meta: {
|
|
112
|
+
token: name,
|
|
113
|
+
hint
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function buildMeta(context) {
|
|
119
|
+
const meta = {};
|
|
120
|
+
if (context.token !== undefined) meta.token = formatTokenName(context.token);
|
|
121
|
+
if (context.scope) meta.scope = context.scope;
|
|
122
|
+
if (context.module) meta.module = context.module;
|
|
123
|
+
if (context.dependencyChain) meta.dependencyChain = context.dependencyChain.map(t => formatTokenName(t));
|
|
124
|
+
if (context.hint) meta.hint = context.hint;
|
|
125
|
+
return meta;
|
|
126
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
ADDED
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { Constructor, MaybePromise, Token } from '@fluojs/core';
|
|
2
|
+
/**
|
|
3
|
+
* Lifetime policy understood by the DI container.
|
|
4
|
+
*/
|
|
5
|
+
export type Scope = 'singleton' | 'request' | 'transient';
|
|
6
|
+
/**
|
|
7
|
+
* Namespace helpers for the public DI scope literals.
|
|
8
|
+
*/
|
|
9
|
+
export declare namespace Scope {
|
|
10
|
+
/**
|
|
11
|
+
* Default lifetime used when a provider omits an explicit scope.
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT: Scope;
|
|
14
|
+
/**
|
|
15
|
+
* Scope literal for providers that should be recreated per request container.
|
|
16
|
+
*/
|
|
17
|
+
const REQUEST: Scope;
|
|
18
|
+
/**
|
|
19
|
+
* Scope literal for providers that should be recreated on every resolution.
|
|
20
|
+
*/
|
|
21
|
+
const TRANSIENT: Scope;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Constructable class token used by provider definitions.
|
|
25
|
+
*/
|
|
26
|
+
export type ClassType<T = unknown> = Constructor<T> & Function;
|
|
27
|
+
/**
|
|
28
|
+
* Provider declaration that instantiates a class for a public token.
|
|
29
|
+
*/
|
|
30
|
+
export interface ClassProvider<T = unknown> {
|
|
31
|
+
provide: Token<T>;
|
|
32
|
+
useClass: ClassType<T>;
|
|
33
|
+
inject?: Array<Token | ForwardRefFn | OptionalToken>;
|
|
34
|
+
scope?: Scope;
|
|
35
|
+
multi?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Provider declaration that computes its value through a factory function.
|
|
39
|
+
*/
|
|
40
|
+
export interface FactoryProvider<T = unknown> {
|
|
41
|
+
provide: Token<T>;
|
|
42
|
+
useFactory: (...deps: unknown[]) => MaybePromise<T>;
|
|
43
|
+
inject?: Array<Token | ForwardRefFn | OptionalToken>;
|
|
44
|
+
scope?: Scope;
|
|
45
|
+
multi?: boolean;
|
|
46
|
+
resolverClass?: ClassType;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Provider declaration that binds a token to an already-created value.
|
|
50
|
+
*/
|
|
51
|
+
export interface ValueProvider<T = unknown> {
|
|
52
|
+
provide: Token<T>;
|
|
53
|
+
useValue: T;
|
|
54
|
+
multi?: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Provider declaration that aliases one token to another token's resolved value.
|
|
58
|
+
*/
|
|
59
|
+
export interface ExistingProvider<T = unknown> {
|
|
60
|
+
provide: Token<T>;
|
|
61
|
+
useExisting: Token;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Deferred token resolver used to break declaration-time cycles between providers.
|
|
65
|
+
*/
|
|
66
|
+
export type ForwardRefFn<T = unknown> = {
|
|
67
|
+
__forwardRef__: true;
|
|
68
|
+
forwardRef: () => Token<T>;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Wrapper token that marks a dependency as optional during resolution.
|
|
72
|
+
*/
|
|
73
|
+
export type OptionalToken<T = unknown> = {
|
|
74
|
+
__optional__: true;
|
|
75
|
+
token: Token<T>;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Public provider shape accepted by container registration and override APIs.
|
|
79
|
+
*/
|
|
80
|
+
export type Provider<T = unknown> = ClassType<T> | ClassProvider<T> | FactoryProvider<T> | ValueProvider<T> | ExistingProvider<T>;
|
|
81
|
+
/**
|
|
82
|
+
* Disposable provider contract recognized by container teardown flows.
|
|
83
|
+
*/
|
|
84
|
+
export interface Disposable {
|
|
85
|
+
onDestroy(): MaybePromise<void>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Minimal request-scope facade exposed to helpers that should not depend on the full `Container` implementation.
|
|
89
|
+
*/
|
|
90
|
+
export interface RequestScopeContainer {
|
|
91
|
+
resolve<T>(token: Token<T>): Promise<T>;
|
|
92
|
+
dispose(): Promise<void>;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Internal normalized provider representation used after the container validates public provider inputs.
|
|
96
|
+
*/
|
|
97
|
+
export interface NormalizedProvider<T = unknown> {
|
|
98
|
+
inject: Array<Token | ForwardRefFn | OptionalToken>;
|
|
99
|
+
provide: Token<T>;
|
|
100
|
+
scope: Scope;
|
|
101
|
+
type: 'class' | 'factory' | 'value' | 'existing';
|
|
102
|
+
useClass?: ClassType<T>;
|
|
103
|
+
useFactory?: (...deps: unknown[]) => MaybePromise<T>;
|
|
104
|
+
useValue?: T;
|
|
105
|
+
useExisting?: Token;
|
|
106
|
+
multi?: boolean;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Wraps a token factory so DI metadata can defer token lookup until resolution time.
|
|
110
|
+
*
|
|
111
|
+
* @param fn Lazy token resolver used when the dependency is eventually resolved.
|
|
112
|
+
* @returns A marker object understood by container normalization and resolution helpers.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* @Inject(forwardRef(() => AuthService))
|
|
117
|
+
* class UsersService {
|
|
118
|
+
* constructor(private readonly auth: AuthService) {}
|
|
119
|
+
* }
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export declare function forwardRef<T = unknown>(fn: () => Token<T>): ForwardRefFn<T>;
|
|
123
|
+
/**
|
|
124
|
+
* Returns whether a value is a `forwardRef(...)` token wrapper.
|
|
125
|
+
*
|
|
126
|
+
* @param value Unknown dependency entry being inspected.
|
|
127
|
+
* @returns `true` when the value was produced by {@link forwardRef}.
|
|
128
|
+
*/
|
|
129
|
+
export declare function isForwardRef(value: unknown): value is ForwardRefFn;
|
|
130
|
+
/**
|
|
131
|
+
* Marks a dependency token as optional so missing registrations resolve to `undefined` instead of throwing.
|
|
132
|
+
*
|
|
133
|
+
* @param token Token that may be absent in the current container hierarchy.
|
|
134
|
+
* @returns An optional-token wrapper understood by container resolution.
|
|
135
|
+
*/
|
|
136
|
+
export declare function optional<T = unknown>(token: Token<T>): OptionalToken<T>;
|
|
137
|
+
/**
|
|
138
|
+
* Returns whether a value is an optional-token wrapper created by {@link optional}.
|
|
139
|
+
*
|
|
140
|
+
* @param value Unknown dependency entry being inspected.
|
|
141
|
+
* @returns `true` when the value wraps an optional token.
|
|
142
|
+
*/
|
|
143
|
+
export declare function isOptionalToken(value: unknown): value is OptionalToken;
|
|
144
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifetime policy understood by the DI container.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Namespace helpers for the public DI scope literals.
|
|
6
|
+
*/
|
|
7
|
+
export let Scope;
|
|
8
|
+
(function (_Scope) {
|
|
9
|
+
const DEFAULT = _Scope.DEFAULT = 'singleton';
|
|
10
|
+
const REQUEST = _Scope.REQUEST = 'request';
|
|
11
|
+
const TRANSIENT = _Scope.TRANSIENT = 'transient';
|
|
12
|
+
})(Scope || (Scope = {}));
|
|
13
|
+
/**
|
|
14
|
+
* Constructable class token used by provider definitions.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Provider declaration that instantiates a class for a public token.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Provider declaration that computes its value through a factory function.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Provider declaration that binds a token to an already-created value.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Provider declaration that aliases one token to another token's resolved value.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Deferred token resolver used to break declaration-time cycles between providers.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Wrapper token that marks a dependency as optional during resolution.
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Public provider shape accepted by container registration and override APIs.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* Disposable provider contract recognized by container teardown flows.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Minimal request-scope facade exposed to helpers that should not depend on the full `Container` implementation.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Internal normalized provider representation used after the container validates public provider inputs.
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* Wraps a token factory so DI metadata can defer token lookup until resolution time.
|
|
48
|
+
*
|
|
49
|
+
* @param fn Lazy token resolver used when the dependency is eventually resolved.
|
|
50
|
+
* @returns A marker object understood by container normalization and resolution helpers.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* @Inject(forwardRef(() => AuthService))
|
|
55
|
+
* class UsersService {
|
|
56
|
+
* constructor(private readonly auth: AuthService) {}
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function forwardRef(fn) {
|
|
61
|
+
return {
|
|
62
|
+
__forwardRef__: true,
|
|
63
|
+
forwardRef: fn
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns whether a value is a `forwardRef(...)` token wrapper.
|
|
69
|
+
*
|
|
70
|
+
* @param value Unknown dependency entry being inspected.
|
|
71
|
+
* @returns `true` when the value was produced by {@link forwardRef}.
|
|
72
|
+
*/
|
|
73
|
+
export function isForwardRef(value) {
|
|
74
|
+
return typeof value === 'object' && value !== null && '__forwardRef__' in value && value.__forwardRef__ === true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Marks a dependency token as optional so missing registrations resolve to `undefined` instead of throwing.
|
|
79
|
+
*
|
|
80
|
+
* @param token Token that may be absent in the current container hierarchy.
|
|
81
|
+
* @returns An optional-token wrapper understood by container resolution.
|
|
82
|
+
*/
|
|
83
|
+
export function optional(token) {
|
|
84
|
+
return {
|
|
85
|
+
__optional__: true,
|
|
86
|
+
token
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Returns whether a value is an optional-token wrapper created by {@link optional}.
|
|
92
|
+
*
|
|
93
|
+
* @param value Unknown dependency entry being inspected.
|
|
94
|
+
* @returns `true` when the value wraps an optional token.
|
|
95
|
+
*/
|
|
96
|
+
export function isOptionalToken(value) {
|
|
97
|
+
return typeof value === 'object' && value !== null && '__optional__' in value && value.__optional__ === true;
|
|
98
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluojs/di",
|
|
3
|
+
"description": "Minimal token-based dependency injection container powering every Fluo application.",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"fluo",
|
|
6
|
+
"di",
|
|
7
|
+
"dependency-injection",
|
|
8
|
+
"ioc",
|
|
9
|
+
"container",
|
|
10
|
+
"provider"
|
|
11
|
+
],
|
|
12
|
+
"version": "1.0.0-beta.1",
|
|
13
|
+
"private": false,
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/fluojs/fluo.git",
|
|
18
|
+
"directory": "packages/di"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=20.0.0"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"main": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@fluojs/core": "^1.0.0-beta.1"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"vitest": "^3.2.4"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|
|
46
|
+
"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",
|
|
48
|
+
"test": "pnpm exec vitest run -c vitest.config.ts",
|
|
49
|
+
"test:watch": "pnpm exec vitest -c vitest.config.ts"
|
|
50
|
+
}
|
|
51
|
+
}
|