@zudojs/container 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -6
- package/dist/containerCore/containerCore.core.d.ts +32 -7
- package/dist/containerCore/containerCore.core.js +23 -1
- package/dist/containerCore/containerCore.scope.d.ts +0 -1
- package/dist/containerCore/containerCore.scope.js +0 -1
- package/dist/containerCore/containerCore.type.d.ts +0 -1
- package/dist/containerCore/containerCore.type.js +0 -1
- package/dist/containerCore/index.d.ts +0 -1
- package/dist/containerCore/index.js +0 -1
- package/dist/containerLifecycle/containerLifecycle.core.d.ts +0 -1
- package/dist/containerLifecycle/containerLifecycle.core.js +0 -1
- package/dist/containerLifecycle/index.d.ts +0 -1
- package/dist/containerLifecycle/index.js +0 -1
- package/dist/containerOptions/containerOptions.type.d.ts +0 -1
- package/dist/containerOptions/containerOptions.type.js +0 -1
- package/dist/containerOptions/index.d.ts +0 -1
- package/dist/containerOptions/index.js +0 -1
- package/dist/containerProvider/containerProvider.core.d.ts +29 -3
- package/dist/containerProvider/containerProvider.core.js +14 -3
- package/dist/containerProvider/index.d.ts +0 -1
- package/dist/containerProvider/index.js +0 -1
- package/dist/containerRegistration/containerRegistration.core.d.ts +0 -1
- package/dist/containerRegistration/containerRegistration.core.js +0 -1
- package/dist/containerRegistration/index.d.ts +0 -1
- package/dist/containerRegistration/index.js +0 -1
- package/dist/containerRegistry/containerRegistry.core.d.ts +0 -1
- package/dist/containerRegistry/containerRegistry.core.js +0 -1
- package/dist/containerRegistry/containerRegistry.type.d.ts +0 -1
- package/dist/containerRegistry/containerRegistry.type.js +0 -1
- package/dist/containerRegistry/index.d.ts +0 -1
- package/dist/containerRegistry/index.js +0 -1
- package/dist/containerResolution/containerResolution.autoRegister.d.ts +7 -3
- package/dist/containerResolution/containerResolution.autoRegister.js +7 -3
- package/dist/containerResolution/containerResolution.core.d.ts +0 -1
- package/dist/containerResolution/containerResolution.core.js +17 -3
- package/dist/containerResolution/containerResolution.dependents.d.ts +0 -1
- package/dist/containerResolution/containerResolution.dependents.js +0 -1
- package/dist/containerResolution/containerResolution.error.d.ts +0 -1
- package/dist/containerResolution/containerResolution.error.js +0 -1
- package/dist/containerResolution/containerResolution.type.d.ts +10 -2
- package/dist/containerResolution/containerResolution.type.js +0 -1
- package/dist/containerResolution/index.d.ts +0 -1
- package/dist/containerResolution/index.js +0 -1
- package/dist/containerScope/containerScope.type.d.ts +0 -1
- package/dist/containerScope/containerScope.type.js +0 -1
- package/dist/containerScope/index.d.ts +0 -1
- package/dist/containerScope/index.js +0 -1
- package/dist/containerToken/containerToken.type.d.ts +0 -1
- package/dist/containerToken/containerToken.type.js +0 -1
- package/dist/containerToken/index.d.ts +0 -1
- package/dist/containerToken/index.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -47,6 +47,12 @@ container.registerFactory(API, (db) => new Api(db), [DB]); // deps via inject li
|
|
|
47
47
|
container.registerExisting("db-alias", DB); // alias to another token
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
Every `register*` call except `registerValue` defaults to
|
|
51
|
+
**`ContainerScope.TRANSIENT`**: the class or factory runs again on every
|
|
52
|
+
`resolve()`. Pass `{ scope: ContainerScope.SINGLETON }` (the fourth argument
|
|
53
|
+
of `registerFactory`) for a pool, a client or anything else that must be
|
|
54
|
+
shared.
|
|
55
|
+
|
|
50
56
|
A factory's parameters are typed from its `inject` list, in order: with
|
|
51
57
|
`DB = createToken<Db>("Db")`, `(db) => new Api(db)` receives `db: Db`, and a
|
|
52
58
|
factory whose parameters do not match the tokens is a compile error. Class
|
|
@@ -54,6 +60,14 @@ tokens type the same way; plain string and symbol tokens give `unknown`.
|
|
|
54
60
|
`factoryProvider(factory, inject)` and `provideFactory(token, factory,
|
|
55
61
|
inject)` infer the same way.
|
|
56
62
|
|
|
63
|
+
`registerClass(token, Class, { inject })`, `classProvider(Class, inject)` and
|
|
64
|
+
`provideClass(token, Class, inject)` check the constructor the same way:
|
|
65
|
+
`inject: [CLOCK, DB]` against `constructor(db: Db, clock: Clock)` is a compile
|
|
66
|
+
error, and so is omitting `inject` for a constructor with required
|
|
67
|
+
parameters. Untyped string/symbol tokens check nothing for classes, a
|
|
68
|
+
non-tuple `ProviderToken[]` built at runtime accepts any constructor, and
|
|
69
|
+
defaulted parameters beyond the list are fine.
|
|
70
|
+
|
|
57
71
|
```typescript
|
|
58
72
|
container.registerFactory(
|
|
59
73
|
REPORT,
|
|
@@ -164,10 +178,11 @@ container.register(API, {
|
|
|
164
178
|
|
|
165
179
|
Classes without an `inject` list are constructed with zero arguments, so
|
|
166
180
|
only a constructor that declares no parameters may omit it (parameters with
|
|
167
|
-
a default value do not count).
|
|
168
|
-
is
|
|
169
|
-
|
|
170
|
-
|
|
181
|
+
a default value do not count). In TypeScript, registering such a class
|
|
182
|
+
without `inject` is a compile error; at runtime (JavaScript callers, casts)
|
|
183
|
+
registering is allowed but resolving throws a `ProviderResolutionError`
|
|
184
|
+
naming the class and the `inject: [...]` fix, instead of building it with
|
|
185
|
+
`undefined` dependencies. There is no reflection/decorator magic — dependencies are
|
|
171
186
|
exactly the tokens you list, resolved in order.
|
|
172
187
|
|
|
173
188
|
## Duplicate registrations
|
|
@@ -212,8 +227,12 @@ const container = createContainer({
|
|
|
212
227
|
has no inject list, so `resolve(NeedsDep)` for
|
|
213
228
|
`constructor(dep: Dep)` throws `RegistrationNotFoundError` naming the
|
|
214
229
|
class and telling you to register it with an `inject` list, instead of
|
|
215
|
-
building it with `dep = undefined`. Parameters with defaults
|
|
216
|
-
count
|
|
230
|
+
building it with `dep = undefined`. Parameters with defaults and rest
|
|
231
|
+
parameters do not count: `constructor(deps: Deps = {})` has
|
|
232
|
+
`length === 0`, so it _is_ auto-registered and built with no arguments —
|
|
233
|
+
the default applies and nothing is injected. Register such a class with
|
|
234
|
+
an `inject` list when the container should supply those values; the
|
|
235
|
+
container cannot tell "optional" from "please inject" at runtime.
|
|
217
236
|
- `detectCircularDependencies` — circular chains throw
|
|
218
237
|
`CircularDependencyError` with the full chain. When disabled,
|
|
219
238
|
`maxResolutionDepth` still stops runaway recursion.
|
|
@@ -12,20 +12,23 @@
|
|
|
12
12
|
* - TRANSIENT instances are never cached and never tracked — callers own
|
|
13
13
|
* their disposal.
|
|
14
14
|
*/
|
|
15
|
-
import type { ContainerProvider, InjectedFactory, ProviderToken } from "../containerProvider/containerProvider.core.js";
|
|
15
|
+
import type { ContainerProvider, InjectedConstructor, InjectedFactory, ProviderToken } from "../containerProvider/containerProvider.core.js";
|
|
16
16
|
import type { ContainerRegistration, CreateRegistrationOptions, RegistrationToken, ResolvedTokens } from "../containerRegistration/containerRegistration.core.js";
|
|
17
17
|
import type { ResolutionCache, ResolutionResult } from "../containerResolution/containerResolution.type.js";
|
|
18
18
|
import type { ContainerOptions, ResolvedContainerOptions } from "../containerOptions/containerOptions.type.js";
|
|
19
|
-
import type {
|
|
19
|
+
import type { Token } from "../containerToken/containerToken.type.js";
|
|
20
20
|
import type { ContainerLike, ContainerScopeOptions } from "./containerCore.type.js";
|
|
21
21
|
import { ContainerScopeContext } from "./containerCore.scope.js";
|
|
22
|
-
/**
|
|
23
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Options accepted by {@link Container.registerClass}. `Deps` is inferred
|
|
24
|
+
* from the `inject` tuple and checked against the class's constructor.
|
|
25
|
+
*/
|
|
26
|
+
export interface RegisterClassOptions<Deps extends readonly ProviderToken[] = readonly ProviderToken[]> extends CreateRegistrationOptions {
|
|
24
27
|
/**
|
|
25
28
|
* Tokens resolved and passed to the constructor, in order.
|
|
26
29
|
* Omit for zero-argument constructors.
|
|
27
30
|
*/
|
|
28
|
-
readonly inject?:
|
|
31
|
+
readonly inject?: Deps;
|
|
29
32
|
}
|
|
30
33
|
export declare class Container implements ContainerLike {
|
|
31
34
|
#private;
|
|
@@ -41,8 +44,26 @@ export declare class Container implements ContainerLike {
|
|
|
41
44
|
* performed by the first `resolve()` — freezes the registration set.
|
|
42
45
|
*/
|
|
43
46
|
start(): this;
|
|
47
|
+
/**
|
|
48
|
+
* Registers a provider under a token.
|
|
49
|
+
*
|
|
50
|
+
* The default `scope` is **`ContainerScope.TRANSIENT`**: the provider
|
|
51
|
+
* runs on every `resolve()`. Pass `{ scope: ContainerScope.SINGLETON }`
|
|
52
|
+
* for anything that must be shared (a pool, a client, a cache).
|
|
53
|
+
*/
|
|
44
54
|
register<T>(token: RegistrationToken<T>, provider: ContainerProvider<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
|
|
45
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Registers a class. Its constructor parameters are checked against the
|
|
57
|
+
* `inject` tokens, in order: `registerClass(API, Api, { inject: [DB] })`
|
|
58
|
+
* requires `Api`'s constructor to accept a `Db` when `DB` is a
|
|
59
|
+
* `createToken<Db>()` or class token, and swapping two typed tokens is a
|
|
60
|
+
* compile error. String/symbol tokens are untyped and check nothing.
|
|
61
|
+
* Without `inject` the class must be constructible with no arguments.
|
|
62
|
+
*
|
|
63
|
+
* Defaults to **`ContainerScope.TRANSIENT`** (a new instance per
|
|
64
|
+
* resolution) unless `options.scope` says otherwise.
|
|
65
|
+
*/
|
|
66
|
+
registerClass<T, const Deps extends readonly ProviderToken[] = readonly []>(token: RegistrationToken<T>, ctor: InjectedConstructor<T, NoInfer<Deps>>, options?: RegisterClassOptions<Deps>): ContainerRegistration<T>;
|
|
46
67
|
/**
|
|
47
68
|
* Registers a pre-built value.
|
|
48
69
|
*
|
|
@@ -57,6 +78,11 @@ export declare class Container implements ContainerLike {
|
|
|
57
78
|
* as `Db` when `DB` is a `createToken<Db>()` or class token, and rejects a
|
|
58
79
|
* factory whose parameters do not match. String/symbol tokens give
|
|
59
80
|
* `unknown`.
|
|
81
|
+
*
|
|
82
|
+
* **The default scope is `ContainerScope.TRANSIENT`: the factory runs on
|
|
83
|
+
* every `resolve()`.** A database pool or HTTP client registered this way
|
|
84
|
+
* is rebuilt for each consumer unless you pass
|
|
85
|
+
* `{ scope: ContainerScope.SINGLETON }` as the fourth argument.
|
|
60
86
|
*/
|
|
61
87
|
registerFactory<T, const Deps extends readonly ProviderToken[] = readonly []>(token: RegistrationToken<T>, factory: InjectedFactory<T, Deps>, inject?: Deps, options?: CreateRegistrationOptions): ContainerRegistration<T>;
|
|
62
88
|
registerExisting<T>(token: RegistrationToken<T>, existing: ProviderToken<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
|
|
@@ -159,4 +185,3 @@ export declare class Container implements ContainerLike {
|
|
|
159
185
|
}
|
|
160
186
|
export declare function createContainer(options?: ContainerOptions): Container;
|
|
161
187
|
export declare function createStartedContainer(options?: ContainerOptions): Container;
|
|
162
|
-
//# sourceMappingURL=containerCore.core.d.ts.map
|
|
@@ -66,10 +66,28 @@ export class Container {
|
|
|
66
66
|
this.#started = true;
|
|
67
67
|
return this;
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Registers a provider under a token.
|
|
71
|
+
*
|
|
72
|
+
* The default `scope` is **`ContainerScope.TRANSIENT`**: the provider
|
|
73
|
+
* runs on every `resolve()`. Pass `{ scope: ContainerScope.SINGLETON }`
|
|
74
|
+
* for anything that must be shared (a pool, a client, a cache).
|
|
75
|
+
*/
|
|
69
76
|
register(token, provider, options = {}) {
|
|
70
77
|
this.ensureMutable();
|
|
71
78
|
return this.#registry.register(token, provider, options);
|
|
72
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Registers a class. Its constructor parameters are checked against the
|
|
82
|
+
* `inject` tokens, in order: `registerClass(API, Api, { inject: [DB] })`
|
|
83
|
+
* requires `Api`'s constructor to accept a `Db` when `DB` is a
|
|
84
|
+
* `createToken<Db>()` or class token, and swapping two typed tokens is a
|
|
85
|
+
* compile error. String/symbol tokens are untyped and check nothing.
|
|
86
|
+
* Without `inject` the class must be constructible with no arguments.
|
|
87
|
+
*
|
|
88
|
+
* Defaults to **`ContainerScope.TRANSIENT`** (a new instance per
|
|
89
|
+
* resolution) unless `options.scope` says otherwise.
|
|
90
|
+
*/
|
|
73
91
|
registerClass(token, ctor, options = {}) {
|
|
74
92
|
const { inject, ...rest } = options;
|
|
75
93
|
return this.register(token, classProvider(ctor, inject ?? []), rest);
|
|
@@ -93,6 +111,11 @@ export class Container {
|
|
|
93
111
|
* as `Db` when `DB` is a `createToken<Db>()` or class token, and rejects a
|
|
94
112
|
* factory whose parameters do not match. String/symbol tokens give
|
|
95
113
|
* `unknown`.
|
|
114
|
+
*
|
|
115
|
+
* **The default scope is `ContainerScope.TRANSIENT`: the factory runs on
|
|
116
|
+
* every `resolve()`.** A database pool or HTTP client registered this way
|
|
117
|
+
* is rebuilt for each consumer unless you pass
|
|
118
|
+
* `{ scope: ContainerScope.SINGLETON }` as the fourth argument.
|
|
96
119
|
*/
|
|
97
120
|
registerFactory(token, factory, inject = [], options = {}) {
|
|
98
121
|
return this.register(token, factoryProvider(factory, inject), options);
|
|
@@ -346,4 +369,3 @@ export function createContainer(options = {}) {
|
|
|
346
369
|
export function createStartedContainer(options = {}) {
|
|
347
370
|
return new Container(options).start();
|
|
348
371
|
}
|
|
349
|
-
//# sourceMappingURL=containerCore.core.js.map
|
|
@@ -103,4 +103,3 @@ export declare class ContainerLifecycle {
|
|
|
103
103
|
getTrackedTokens(): readonly Token<unknown>[];
|
|
104
104
|
}
|
|
105
105
|
export declare function createContainerLifecycle(options?: ContainerLifecycleOptions): ContainerLifecycle;
|
|
106
|
-
//# sourceMappingURL=containerLifecycle.core.d.ts.map
|
|
@@ -41,4 +41,3 @@ export declare function validateResolutionOptions(options: ContainerResolutionOp
|
|
|
41
41
|
export declare function allowsContainerScopes(options: ResolvedContainerOptions): boolean;
|
|
42
42
|
export declare function shouldAutoDisposeContainer(options: ResolvedContainerOptions): boolean;
|
|
43
43
|
export declare function canModifyRegistrations(options: ResolvedContainerOptions): boolean;
|
|
44
|
-
//# sourceMappingURL=containerOptions.type.d.ts.map
|
|
@@ -15,6 +15,24 @@ export type InjectedDependencies<Deps extends readonly ProviderToken[]> = {
|
|
|
15
15
|
};
|
|
16
16
|
/** A factory whose parameters are typed from its `inject` list. */
|
|
17
17
|
export type InjectedFactory<T, Deps extends readonly ProviderToken[]> = (...dependencies: InjectedDependencies<Deps>) => T;
|
|
18
|
+
/**
|
|
19
|
+
* The constructor parameter list an `inject` list must satisfy. A typed
|
|
20
|
+
* token (`createToken<Db>()`, a class) contributes its type; an untyped
|
|
21
|
+
* string/symbol token contributes `any`, because a class declares its own
|
|
22
|
+
* parameter types and an untyped token carries nothing to check them
|
|
23
|
+
* against. A non-tuple `readonly ProviderToken[]` (a list built at runtime)
|
|
24
|
+
* has no positions to check and accepts any constructor.
|
|
25
|
+
*/
|
|
26
|
+
export type InjectedConstructorArgs<Deps extends readonly ProviderToken[]> = number extends Deps["length"] ? any[] : {
|
|
27
|
+
-readonly [K in keyof Deps]: Deps[K] extends ProviderToken<infer U> ? unknown extends U ? any : U : never;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* A class whose constructor parameters are typed from its `inject` list, in
|
|
31
|
+
* order: `[DB, Clock]` requires `new (db: Db, clock: Clock)`. Swapping two
|
|
32
|
+
* typed tokens, or omitting the list for a constructor with required
|
|
33
|
+
* parameters, is a compile error instead of a runtime `undefined`.
|
|
34
|
+
*/
|
|
35
|
+
export type InjectedConstructor<T, Deps extends readonly ProviderToken[]> = new (...args: InjectedConstructorArgs<Deps>) => T;
|
|
18
36
|
export interface ClassProvider<T> {
|
|
19
37
|
readonly useClass: Constructor<T>;
|
|
20
38
|
/**
|
|
@@ -65,7 +83,12 @@ export declare function isTokenProvider<T = unknown>(provider: ContainerProvider
|
|
|
65
83
|
export declare function hasInjectedDependencies<T = unknown>(provider: Provider<T>): provider is (FactoryProvider<T> | ClassProvider<T>) & {
|
|
66
84
|
readonly inject: readonly ProviderToken[];
|
|
67
85
|
};
|
|
68
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Builds a class provider. The constructor's parameters are checked against
|
|
88
|
+
* the `inject` tokens, in order (see {@link InjectedConstructor}); with no
|
|
89
|
+
* list the class must be constructible with no arguments.
|
|
90
|
+
*/
|
|
91
|
+
export declare function classProvider<T, const Deps extends readonly ProviderToken[] = readonly []>(useClass: InjectedConstructor<T, NoInfer<Deps>>, inject?: Deps): ClassProvider<T>;
|
|
69
92
|
/**
|
|
70
93
|
* Builds a factory provider. The factory's parameters are inferred from the
|
|
71
94
|
* `inject` tokens, in order.
|
|
@@ -73,7 +96,11 @@ export declare function classProvider<T>(useClass: Constructor<T>, inject?: read
|
|
|
73
96
|
export declare function factoryProvider<T, const Deps extends readonly ProviderToken[] = readonly []>(useFactory: InjectedFactory<T, Deps>, inject?: Deps): FactoryProvider<T>;
|
|
74
97
|
export declare function valueProvider<T>(useValue: T): ValueProvider<T>;
|
|
75
98
|
export declare function existingProvider<T>(useExisting: ProviderToken<T>): ExistingProvider<T>;
|
|
76
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Builds a class registration. The constructor's parameters are checked
|
|
101
|
+
* against the `inject` tokens, in order (see {@link InjectedConstructor}).
|
|
102
|
+
*/
|
|
103
|
+
export declare function provideClass<T, const Deps extends readonly ProviderToken[] = readonly []>(provide: ProviderToken<T>, useClass: InjectedConstructor<T, NoInfer<Deps>>, inject?: Deps): ClassRegistration<T>;
|
|
77
104
|
/**
|
|
78
105
|
* Builds a factory registration. The factory's parameters are inferred from
|
|
79
106
|
* the `inject` tokens, in order.
|
|
@@ -83,4 +110,3 @@ export declare function provideValue<T>(provide: ProviderToken<T>, useValue: T):
|
|
|
83
110
|
export declare function provideExisting<T>(provide: ProviderToken<T>, useExisting: ProviderToken<T>): ExistingRegistration<T>;
|
|
84
111
|
export declare function getProviderToken<T>(provider: ContainerProvider<T>): ProviderToken<T> | undefined;
|
|
85
112
|
export declare function normalizeProvider<T>(provider: ContainerProvider<T>): Provider<T>;
|
|
86
|
-
//# sourceMappingURL=containerProvider.core.d.ts.map
|
|
@@ -22,8 +22,16 @@ export function hasInjectedDependencies(provider) {
|
|
|
22
22
|
Array.isArray(provider.inject) &&
|
|
23
23
|
provider.inject.length > 0);
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Builds a class provider. The constructor's parameters are checked against
|
|
27
|
+
* the `inject` tokens, in order (see {@link InjectedConstructor}); with no
|
|
28
|
+
* list the class must be constructible with no arguments.
|
|
29
|
+
*/
|
|
25
30
|
export function classProvider(useClass, inject = []) {
|
|
26
|
-
return Object.freeze({
|
|
31
|
+
return Object.freeze({
|
|
32
|
+
useClass: useClass,
|
|
33
|
+
inject: Object.freeze([...inject]),
|
|
34
|
+
});
|
|
27
35
|
}
|
|
28
36
|
/**
|
|
29
37
|
* Builds a factory provider. The factory's parameters are inferred from the
|
|
@@ -41,10 +49,14 @@ export function valueProvider(useValue) {
|
|
|
41
49
|
export function existingProvider(useExisting) {
|
|
42
50
|
return Object.freeze({ useExisting });
|
|
43
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Builds a class registration. The constructor's parameters are checked
|
|
54
|
+
* against the `inject` tokens, in order (see {@link InjectedConstructor}).
|
|
55
|
+
*/
|
|
44
56
|
export function provideClass(provide, useClass, inject = []) {
|
|
45
57
|
return Object.freeze({
|
|
46
58
|
provide,
|
|
47
|
-
useClass,
|
|
59
|
+
useClass: useClass,
|
|
48
60
|
inject: Object.freeze([...inject]),
|
|
49
61
|
});
|
|
50
62
|
}
|
|
@@ -75,4 +87,3 @@ export function normalizeProvider(provider) {
|
|
|
75
87
|
return provider.provider;
|
|
76
88
|
return provider;
|
|
77
89
|
}
|
|
78
|
-
//# sourceMappingURL=containerProvider.core.js.map
|
|
@@ -57,4 +57,3 @@ export declare function defineRegistration<T>(token: RegistrationToken<T>, provi
|
|
|
57
57
|
export declare const DEFAULT_REGISTRATION_SCOPE: ContainerScope;
|
|
58
58
|
export type RegistrationMap = ReadonlyMap<Token<unknown>, ContainerRegistration<unknown>>;
|
|
59
59
|
export declare function createRegistrationMap(registrations: readonly ContainerRegistration[]): RegistrationMap;
|
|
60
|
-
//# sourceMappingURL=containerRegistration.core.d.ts.map
|
|
@@ -9,8 +9,13 @@
|
|
|
9
9
|
* Whether an unregistered token may be auto-registered: a class whose
|
|
10
10
|
* constructor declares no required parameters (`Class.length === 0`).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* `constructor(value = 7)`
|
|
12
|
+
* `Function.length` counts parameters before the first default or rest
|
|
13
|
+
* parameter, so `constructor(value = 7)`, `constructor(deps: Deps = {})`
|
|
14
|
+
* and `constructor(...rest)` all qualify and are built with **no
|
|
15
|
+
* arguments** — their defaults apply and nothing is injected. A class that
|
|
16
|
+
* expects the container to supply a defaulted parameter must be registered
|
|
17
|
+
* explicitly with an `inject` list; the container cannot tell "optional"
|
|
18
|
+
* from "please inject" at runtime.
|
|
14
19
|
*/
|
|
15
20
|
export declare function isAutoRegistrable(token: unknown): boolean;
|
|
16
21
|
/**
|
|
@@ -39,4 +44,3 @@ export declare function assertClassInjectable(token: string, ctor: {
|
|
|
39
44
|
readonly length: number;
|
|
40
45
|
readonly name: string;
|
|
41
46
|
}, inject: readonly unknown[]): void;
|
|
42
|
-
//# sourceMappingURL=containerResolution.autoRegister.d.ts.map
|
|
@@ -11,8 +11,13 @@ import { describeToken } from "../containerToken/containerToken.type.js";
|
|
|
11
11
|
* Whether an unregistered token may be auto-registered: a class whose
|
|
12
12
|
* constructor declares no required parameters (`Class.length === 0`).
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
* `constructor(value = 7)`
|
|
14
|
+
* `Function.length` counts parameters before the first default or rest
|
|
15
|
+
* parameter, so `constructor(value = 7)`, `constructor(deps: Deps = {})`
|
|
16
|
+
* and `constructor(...rest)` all qualify and are built with **no
|
|
17
|
+
* arguments** — their defaults apply and nothing is injected. A class that
|
|
18
|
+
* expects the container to supply a defaulted parameter must be registered
|
|
19
|
+
* explicitly with an `inject` list; the container cannot tell "optional"
|
|
20
|
+
* from "please inject" at runtime.
|
|
16
21
|
*/
|
|
17
22
|
export function isAutoRegistrable(token) {
|
|
18
23
|
return typeof token === "function" && token.length === 0;
|
|
@@ -59,4 +64,3 @@ export function assertClassInjectable(token, ctor, inject) {
|
|
|
59
64
|
`dependencies. Register it with container.registerClass(${token}, ` +
|
|
60
65
|
`${name}, { inject: [/* one token per parameter */] }).`);
|
|
61
66
|
}
|
|
62
|
-
//# sourceMappingURL=containerResolution.autoRegister.js.map
|
|
@@ -135,7 +135,16 @@ export class ContainerResolver {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
else {
|
|
138
|
-
|
|
138
|
+
// Name the consumer as well as the missing token: as a dependency
|
|
139
|
+
// this error is wrapped by the consumer's DependencyResolutionError,
|
|
140
|
+
// whose chain used to end at the consumer and never say what was
|
|
141
|
+
// missing.
|
|
142
|
+
const name = describeToken(token);
|
|
143
|
+
const requiredBy = state.path[state.path.length - 1];
|
|
144
|
+
throw new RegistrationNotFoundError(name, requiredBy === undefined
|
|
145
|
+
? undefined
|
|
146
|
+
: `No registration found for token "${name}" (required by ` +
|
|
147
|
+
`"${describeToken(requiredBy)}").`);
|
|
139
148
|
}
|
|
140
149
|
}
|
|
141
150
|
const currentPath = [...state.path, token];
|
|
@@ -259,7 +268,13 @@ export class ContainerResolver {
|
|
|
259
268
|
error instanceof MaxResolutionDepthError ||
|
|
260
269
|
error instanceof AsyncProviderError)
|
|
261
270
|
throw error;
|
|
262
|
-
|
|
271
|
+
// A missing dependency is the one failure whose token is not on the
|
|
272
|
+
// path (it never started resolving), so append it: the chain must end
|
|
273
|
+
// at the token that was missing, not at the consumer that needed it.
|
|
274
|
+
const chain = state.path.map((t) => describeToken(t));
|
|
275
|
+
if (error instanceof RegistrationNotFoundError)
|
|
276
|
+
chain.push(error.requestedToken);
|
|
277
|
+
throw new DependencyResolutionError(describeToken(token), error, chain);
|
|
263
278
|
}
|
|
264
279
|
}
|
|
265
280
|
/**
|
|
@@ -373,4 +388,3 @@ function isPromiseLike(value) {
|
|
|
373
388
|
"then" in value &&
|
|
374
389
|
typeof value.then === "function");
|
|
375
390
|
}
|
|
376
|
-
//# sourceMappingURL=containerResolution.core.js.map
|
|
@@ -36,7 +36,16 @@ export interface ResolutionOptions {
|
|
|
36
36
|
readonly cache?: ResolutionCache;
|
|
37
37
|
/** Current dependency resolution path. Normally managed internally. */
|
|
38
38
|
readonly path?: ResolutionPath;
|
|
39
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Whether unregistered class tokens may be resolved. Defaults to true.
|
|
41
|
+
*
|
|
42
|
+
* Only a class whose constructor declares no *required* parameters
|
|
43
|
+
* (`Class.length === 0`) qualifies, and it is built with no arguments.
|
|
44
|
+
* Parameters with defaults and rest parameters do not count, so such a
|
|
45
|
+
* class is auto-registered with its defaults applied and nothing
|
|
46
|
+
* injected; register it with an `inject` list when the container should
|
|
47
|
+
* supply those values. Set to `false` to require explicit registration.
|
|
48
|
+
*/
|
|
40
49
|
readonly autoRegisterClasses?: boolean;
|
|
41
50
|
/**
|
|
42
51
|
* Whether auto-resolved class tokens may be added to the registry.
|
|
@@ -69,4 +78,3 @@ export interface ResolutionResult<T> {
|
|
|
69
78
|
readonly fromCache: boolean;
|
|
70
79
|
readonly path: ResolutionPath;
|
|
71
80
|
}
|
|
72
|
-
//# sourceMappingURL=containerResolution.type.d.ts.map
|
|
@@ -14,4 +14,3 @@ export declare function isScopedScope(scope: ContainerScope): boolean;
|
|
|
14
14
|
export declare function isTransientScope(scope: ContainerScope): boolean;
|
|
15
15
|
export declare function isCachedScope(scope: ContainerScope): boolean;
|
|
16
16
|
export declare function describeContainerScope(scope: ContainerScope): string;
|
|
17
|
-
//# sourceMappingURL=containerScope.type.d.ts.map
|
|
@@ -53,4 +53,3 @@ export declare function isStringToken<T = unknown>(token: Token<T>): token is st
|
|
|
53
53
|
* `Symbol(MissingService)`. A symbol without a description is `Symbol()`.
|
|
54
54
|
*/
|
|
55
55
|
export declare function describeToken<T>(token: Token<T> | InjectionToken<T>): string;
|
|
56
|
-
//# sourceMappingURL=containerToken.type.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -13,4 +13,3 @@ export * from "./containerResolution/index.js";
|
|
|
13
13
|
export * from "./containerScope/index.js";
|
|
14
14
|
export * from "./containerToken/index.js";
|
|
15
15
|
export { CircularDependencyError, DuplicateRegistrationError, RegistrationNotFoundError, ProviderResolutionError, } from "@zudojs/errors";
|
|
16
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -15,4 +15,3 @@ export * from "./containerToken/index.js";
|
|
|
15
15
|
// Error classes the container throws but that live in @zudojs/errors,
|
|
16
16
|
// re-exported so `instanceof` checks need only this package.
|
|
17
17
|
export { CircularDependencyError, DuplicateRegistrationError, RegistrationNotFoundError, ProviderResolutionError, } from "@zudojs/errors";
|
|
18
|
-
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/container",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Token-based dependency injection container for managing application dependencies and service lifetimes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"!dist/.tsbuildinfo"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@zudojs/errors": "1.
|
|
21
|
+
"@zudojs/errors": "1.4.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"typescript": "7.0.2",
|