di-craft 0.0.12 → 0.0.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/README.md +3 -2
- package/dist/index.d.mts +1 -2
- package/dist/index.mjs +267 -2
- package/package.json +3 -10
- package/dist/index.cjs +0 -2
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -99
- package/dist/index.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ framework coupling. You work with just **tokens**, **providers**, a **container*
|
|
|
75
75
|
- Deterministic disposal with `onDispose` hooks
|
|
76
76
|
- Circular dependency detection
|
|
77
77
|
- Tree-shakable, tiny bundle size
|
|
78
|
-
-
|
|
78
|
+
- ESM-only, ships with TypeScript declarations
|
|
79
79
|
|
|
80
80
|
## Install
|
|
81
81
|
|
|
@@ -86,7 +86,8 @@ pnpm add di-craft
|
|
|
86
86
|
yarn add di-craft
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
Requires Node.js `>= 20`.
|
|
89
|
+
Requires Node.js `>= 20`. This package is ESM-only — import it with `import`;
|
|
90
|
+
CommonJS code can load it with a dynamic `import()`.
|
|
90
91
|
|
|
91
92
|
## Core concepts
|
|
92
93
|
|
package/dist/index.d.mts
CHANGED
|
@@ -95,5 +95,4 @@ declare class CircularDependencyError extends DiError {
|
|
|
95
95
|
constructor(tokenNames: string[]);
|
|
96
96
|
}
|
|
97
97
|
//#endregion
|
|
98
|
-
export { CircularDependencyError, type Container, type Dependency, DiError, type DisposeHook, DuplicateProviderError, type FactoryProvider, InvalidDependencyError, InvalidProviderError, MissingProviderError, type OptionalDependency, type Provider, type RegisterOptions, type Scope, Scopes, type Token, type ValueProvider, createChildContainer, createContainer, createToken, optional, provideFactory, provideValue };
|
|
99
|
-
//# sourceMappingURL=index.d.mts.map
|
|
98
|
+
export { CircularDependencyError, type Container, type Dependency, DiError, type DisposeHook, DuplicateProviderError, type FactoryProvider, InvalidDependencyError, InvalidProviderError, MissingProviderError, type OptionalDependency, type Provider, type RegisterOptions, type Scope, Scopes, type Token, type ValueProvider, createChildContainer, createContainer, createToken, optional, provideFactory, provideValue };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,267 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/error/error.ts
|
|
2
|
+
var DiError = class extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "DiError";
|
|
6
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/provider/errors.ts
|
|
12
|
+
var InvalidProviderError = class extends DiError {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "InvalidProviderError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/scope/scope.ts
|
|
21
|
+
const Scopes = {
|
|
22
|
+
Singleton: "singleton",
|
|
23
|
+
Transient: "transient",
|
|
24
|
+
Scoped: "scoped"
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/provider/provider.ts
|
|
29
|
+
const provideValue = (token, useValue) => ({
|
|
30
|
+
provide: token,
|
|
31
|
+
useValue
|
|
32
|
+
});
|
|
33
|
+
const provideFactory = (token, options) => {
|
|
34
|
+
if (options.scope === Scopes.Transient && options.onDispose) throw new InvalidProviderError(`onDispose is not supported for transient providers (token "${token.name}"): transient instances are not tracked, so the hook would never run.`);
|
|
35
|
+
return {
|
|
36
|
+
provide: token,
|
|
37
|
+
useFactory: options.useFactory,
|
|
38
|
+
scope: options.scope ?? Scopes.Singleton,
|
|
39
|
+
...options.deps ? { deps: options.deps } : {},
|
|
40
|
+
...options.onDispose ? { onDispose: options.onDispose } : {}
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
const optional = (token) => ({
|
|
44
|
+
token,
|
|
45
|
+
optional: true
|
|
46
|
+
});
|
|
47
|
+
const isOptionalDependency = (dependency) => {
|
|
48
|
+
return dependency.optional === true;
|
|
49
|
+
};
|
|
50
|
+
const isValueProvider = (provider) => {
|
|
51
|
+
return "useValue" in provider;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/registry/errors.ts
|
|
56
|
+
var DuplicateProviderError = class extends DiError {
|
|
57
|
+
constructor(tokenName) {
|
|
58
|
+
super(`Provider for token "${tokenName}" is already registered`);
|
|
59
|
+
this.name = "DuplicateProviderError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/registry/registry.ts
|
|
65
|
+
var RegistryClass = class {
|
|
66
|
+
providers = /* @__PURE__ */ new Map();
|
|
67
|
+
register(provider, options) {
|
|
68
|
+
const existed = this.providers.has(provider.provide.id);
|
|
69
|
+
if (existed && !options?.allowOverride) throw new DuplicateProviderError(provider.provide.name);
|
|
70
|
+
this.providers.set(provider.provide.id, provider);
|
|
71
|
+
return existed;
|
|
72
|
+
}
|
|
73
|
+
get(token) {
|
|
74
|
+
return this.providers.get(token.id);
|
|
75
|
+
}
|
|
76
|
+
has(token) {
|
|
77
|
+
return this.providers.has(token.id);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const createRegistry = () => new RegistryClass();
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/resolver/errors.ts
|
|
84
|
+
var MissingProviderError = class extends DiError {
|
|
85
|
+
constructor(tokenName) {
|
|
86
|
+
super(`Provider for token "${tokenName}" is not registered`);
|
|
87
|
+
this.name = "MissingProviderError";
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var InvalidDependencyError = class extends DiError {
|
|
91
|
+
constructor(dependencyKey) {
|
|
92
|
+
super(`Invalid dependency "${dependencyKey}"`);
|
|
93
|
+
this.name = "InvalidDependencyError";
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var CircularDependencyError = class extends DiError {
|
|
97
|
+
constructor(tokenNames) {
|
|
98
|
+
super(`Circular dependency detected: ${tokenNames.join(" -> ")}`);
|
|
99
|
+
this.name = "CircularDependencyError";
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/store/store.ts
|
|
105
|
+
var StoreClass = class {
|
|
106
|
+
instances = /* @__PURE__ */ new Map();
|
|
107
|
+
get(token) {
|
|
108
|
+
return this.instances.get(token.id);
|
|
109
|
+
}
|
|
110
|
+
set(token, record) {
|
|
111
|
+
this.instances.set(token.id, record);
|
|
112
|
+
}
|
|
113
|
+
delete(token) {
|
|
114
|
+
this.instances.delete(token.id);
|
|
115
|
+
}
|
|
116
|
+
async dispose() {
|
|
117
|
+
const records = [...this.instances.values()].reverse();
|
|
118
|
+
this.instances.clear();
|
|
119
|
+
for (const record of records) if (record.onDispose) await record.onDispose(record.value);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const createStore = () => new StoreClass();
|
|
123
|
+
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/resolver/context.ts
|
|
126
|
+
var ResolutionContext = class {
|
|
127
|
+
resolving = /* @__PURE__ */ new Set();
|
|
128
|
+
path = [];
|
|
129
|
+
enter(token) {
|
|
130
|
+
if (this.resolving.has(token.id)) {
|
|
131
|
+
const cycleStartIndex = this.path.findIndex((pathToken) => pathToken.id === token.id);
|
|
132
|
+
throw new CircularDependencyError([...this.path.slice(cycleStartIndex), token].map((cycleToken) => cycleToken.name));
|
|
133
|
+
}
|
|
134
|
+
this.resolving.add(token.id);
|
|
135
|
+
this.path.push(token);
|
|
136
|
+
}
|
|
137
|
+
exit(token) {
|
|
138
|
+
this.path.pop();
|
|
139
|
+
this.resolving.delete(token.id);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/resolver/resolver.ts
|
|
145
|
+
const lifetimeRank = (scope) => scope === Scopes.Scoped ? 1 : scope === Scopes.Transient ? 2 : 0;
|
|
146
|
+
var ResolverClass = class {
|
|
147
|
+
registry;
|
|
148
|
+
store = createStore();
|
|
149
|
+
parent;
|
|
150
|
+
constructor(registry, parent) {
|
|
151
|
+
this.registry = registry;
|
|
152
|
+
this.parent = parent;
|
|
153
|
+
}
|
|
154
|
+
resolve(token) {
|
|
155
|
+
return this.resolveToken(token, void 0);
|
|
156
|
+
}
|
|
157
|
+
resolveOptional(token) {
|
|
158
|
+
return this.lookupOptional(token, void 0);
|
|
159
|
+
}
|
|
160
|
+
invalidate(token) {
|
|
161
|
+
this.store.delete(token);
|
|
162
|
+
}
|
|
163
|
+
hasDisposableInstance(token) {
|
|
164
|
+
return this.store.get(token)?.onDispose !== void 0;
|
|
165
|
+
}
|
|
166
|
+
dispose() {
|
|
167
|
+
return this.store.dispose();
|
|
168
|
+
}
|
|
169
|
+
resolveToken(token, context, consumerScope, consumerName) {
|
|
170
|
+
let owner = this;
|
|
171
|
+
let provider;
|
|
172
|
+
while (owner) {
|
|
173
|
+
provider = owner.registry.get(token);
|
|
174
|
+
if (provider) break;
|
|
175
|
+
owner = owner.parent;
|
|
176
|
+
}
|
|
177
|
+
if (!provider || !owner) throw new MissingProviderError(token.name);
|
|
178
|
+
if (isValueProvider(provider)) return provider.useValue;
|
|
179
|
+
if (consumerScope !== void 0 && lifetimeRank(provider.scope) > lifetimeRank(consumerScope)) throw new InvalidProviderError(`"${consumerName}" (${consumerScope}) cannot depend on "${token.name}" (${provider.scope ?? Scopes.Singleton}): a longer-lived provider would capture a shorter-lived one. Widen the dependency's scope or narrow the consumer's.`);
|
|
180
|
+
const host = this.selectHost(provider.scope, owner);
|
|
181
|
+
if (host) {
|
|
182
|
+
const cached = host.store.get(token);
|
|
183
|
+
if (cached) return cached.value;
|
|
184
|
+
}
|
|
185
|
+
const ctx = context ?? new ResolutionContext();
|
|
186
|
+
ctx.enter(token);
|
|
187
|
+
try {
|
|
188
|
+
const deps = (host ?? this).resolveDeps(provider.deps, ctx, provider.scope, token.name);
|
|
189
|
+
const value = provider.useFactory(deps);
|
|
190
|
+
if (host) host.store.set(token, {
|
|
191
|
+
value,
|
|
192
|
+
...provider.onDispose ? { onDispose: provider.onDispose } : {}
|
|
193
|
+
});
|
|
194
|
+
return value;
|
|
195
|
+
} finally {
|
|
196
|
+
ctx.exit(token);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
selectHost(scope, owner) {
|
|
200
|
+
if (scope === Scopes.Transient) return;
|
|
201
|
+
if (scope === Scopes.Scoped) return this;
|
|
202
|
+
return owner;
|
|
203
|
+
}
|
|
204
|
+
resolveDeps(deps, context, consumerScope, consumerName) {
|
|
205
|
+
if (!deps) return {};
|
|
206
|
+
const resolvedDeps = {};
|
|
207
|
+
for (const key of Object.keys(deps)) {
|
|
208
|
+
const dependency = deps[key];
|
|
209
|
+
if (dependency === void 0) throw new InvalidDependencyError(String(key));
|
|
210
|
+
resolvedDeps[key] = isOptionalDependency(dependency) ? this.lookupOptional(dependency.token, context, consumerScope, consumerName) : this.resolveToken(dependency, context, consumerScope, consumerName);
|
|
211
|
+
}
|
|
212
|
+
return resolvedDeps;
|
|
213
|
+
}
|
|
214
|
+
lookupOptional(token, context, consumerScope, consumerName) {
|
|
215
|
+
let owner = this;
|
|
216
|
+
while (owner) {
|
|
217
|
+
if (owner.registry.has(token)) return this.resolveToken(token, context, consumerScope, consumerName);
|
|
218
|
+
owner = owner.parent;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
const createResolver = (registry, parent) => new ResolverClass(registry, parent);
|
|
223
|
+
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region src/container/container.ts
|
|
226
|
+
var ContainerClass = class {
|
|
227
|
+
registry;
|
|
228
|
+
resolver;
|
|
229
|
+
parent;
|
|
230
|
+
constructor(providers = [], parent) {
|
|
231
|
+
this.parent = parent;
|
|
232
|
+
this.registry = createRegistry();
|
|
233
|
+
for (const provider of providers) this.registry.register(provider);
|
|
234
|
+
this.resolver = createResolver(this.registry, parent?.resolver);
|
|
235
|
+
}
|
|
236
|
+
register(provider, options) {
|
|
237
|
+
if (options?.allowOverride && this.resolver.hasDisposableInstance(provider.provide)) throw new InvalidProviderError(`Cannot override token "${provider.provide.name}": its instance was already created and has an onDispose hook. Dispose the container before replacing it.`);
|
|
238
|
+
if (this.registry.register(provider, options)) this.resolver.invalidate(provider.provide);
|
|
239
|
+
}
|
|
240
|
+
get(dependency) {
|
|
241
|
+
if (isOptionalDependency(dependency)) return this.resolver.resolveOptional(dependency.token);
|
|
242
|
+
return this.resolver.resolve(dependency);
|
|
243
|
+
}
|
|
244
|
+
has(token) {
|
|
245
|
+
return this.registry.has(token) || (this.parent?.has(token) ?? false);
|
|
246
|
+
}
|
|
247
|
+
dispose() {
|
|
248
|
+
return this.resolver.dispose();
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const createContainer = (providers = []) => new ContainerClass(providers);
|
|
252
|
+
const createChildContainer = (parent, providers = []) => new ContainerClass(providers, parent);
|
|
253
|
+
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/token/token.ts
|
|
256
|
+
var TokenClass = class {
|
|
257
|
+
name;
|
|
258
|
+
id;
|
|
259
|
+
constructor(name) {
|
|
260
|
+
this.name = name;
|
|
261
|
+
this.id = Symbol(name);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
const createToken = (name) => new TokenClass(name);
|
|
265
|
+
|
|
266
|
+
//#endregion
|
|
267
|
+
export { CircularDependencyError, DiError, DuplicateProviderError, InvalidDependencyError, InvalidProviderError, MissingProviderError, Scopes, createChildContainer, createContainer, createToken, optional, provideFactory, provideValue };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "di-craft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "A tiny, type-safe dependency injection container for TypeScript",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -13,19 +13,12 @@
|
|
|
13
13
|
"engines": {
|
|
14
14
|
"node": ">=20"
|
|
15
15
|
},
|
|
16
|
-
"main": "./dist/index.cjs",
|
|
17
16
|
"module": "./dist/index.mjs",
|
|
18
17
|
"types": "./dist/index.d.mts",
|
|
19
18
|
"exports": {
|
|
20
19
|
".": {
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
"default": "./dist/index.mjs"
|
|
24
|
-
},
|
|
25
|
-
"require": {
|
|
26
|
-
"types": "./dist/index.d.cts",
|
|
27
|
-
"default": "./dist/index.cjs"
|
|
28
|
-
}
|
|
20
|
+
"types": "./dist/index.d.mts",
|
|
21
|
+
"default": "./dist/index.mjs"
|
|
29
22
|
},
|
|
30
23
|
"./package.json": "./package.json"
|
|
31
24
|
},
|
package/dist/index.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class extends Error{constructor(e){super(e),this.name=`DiError`,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}},t=class extends e{constructor(e){super(e),this.name=`InvalidProviderError`}};const n={Singleton:`singleton`,Transient:`transient`,Scoped:`scoped`},r=(e,t)=>({provide:e,useValue:t}),i=(e,r)=>{if(r.scope===n.Transient&&r.onDispose)throw new t(`onDispose is not supported for transient providers (token "${e.name}"): transient instances are not tracked, so the hook would never run.`);return{provide:e,useFactory:r.useFactory,scope:r.scope??n.Singleton,...r.deps?{deps:r.deps}:{},...r.onDispose?{onDispose:r.onDispose}:{}}},a=e=>({token:e,optional:!0}),o=e=>e.optional===!0,s=e=>`useValue`in e;var c=class extends e{constructor(e){super(`Provider for token "${e}" is already registered`),this.name=`DuplicateProviderError`}},l=class{providers=new Map;register(e,t){let n=this.providers.has(e.provide.id);if(n&&!t?.allowOverride)throw new c(e.provide.name);return this.providers.set(e.provide.id,e),n}get(e){return this.providers.get(e.id)}has(e){return this.providers.has(e.id)}};const u=()=>new l;var d=class extends e{constructor(e){super(`Provider for token "${e}" is not registered`),this.name=`MissingProviderError`}},f=class extends e{constructor(e){super(`Invalid dependency "${e}"`),this.name=`InvalidDependencyError`}},p=class extends e{constructor(e){super(`Circular dependency detected: ${e.join(` -> `)}`),this.name=`CircularDependencyError`}},m=class{instances=new Map;get(e){return this.instances.get(e.id)}set(e,t){this.instances.set(e.id,t)}delete(e){this.instances.delete(e.id)}async dispose(){let e=[...this.instances.values()].reverse();this.instances.clear();for(let t of e)t.onDispose&&await t.onDispose(t.value)}};const h=()=>new m;var g=class{resolving=new Set;path=[];enter(e){if(this.resolving.has(e.id)){let t=this.path.findIndex(t=>t.id===e.id);throw new p([...this.path.slice(t),e].map(e=>e.name))}this.resolving.add(e.id),this.path.push(e)}exit(e){this.path.pop(),this.resolving.delete(e.id)}};const _=e=>e===n.Scoped?1:e===n.Transient?2:0;var v=class{registry;store=h();parent;constructor(e,t){this.registry=e,this.parent=t}resolve(e){return this.resolveToken(e,void 0)}resolveOptional(e){return this.lookupOptional(e,void 0)}invalidate(e){this.store.delete(e)}hasDisposableInstance(e){return this.store.get(e)?.onDispose!==void 0}dispose(){return this.store.dispose()}resolveToken(e,r,i,a){let o=this,c;for(;o&&(c=o.registry.get(e),!c);)o=o.parent;if(!c||!o)throw new d(e.name);if(s(c))return c.useValue;if(i!==void 0&&_(c.scope)>_(i))throw new t(`"${a}" (${i}) cannot depend on "${e.name}" (${c.scope??n.Singleton}): a longer-lived provider would capture a shorter-lived one. Widen the dependency's scope or narrow the consumer's.`);let l=this.selectHost(c.scope,o);if(l){let t=l.store.get(e);if(t)return t.value}let u=r??new g;u.enter(e);try{let t=(l??this).resolveDeps(c.deps,u,c.scope,e.name),n=c.useFactory(t);return l&&l.store.set(e,{value:n,...c.onDispose?{onDispose:c.onDispose}:{}}),n}finally{u.exit(e)}}selectHost(e,t){if(e!==n.Transient)return e===n.Scoped?this:t}resolveDeps(e,t,n,r){if(!e)return{};let i={};for(let a of Object.keys(e)){let s=e[a];if(s===void 0)throw new f(String(a));i[a]=o(s)?this.lookupOptional(s.token,t,n,r):this.resolveToken(s,t,n,r)}return i}lookupOptional(e,t,n,r){let i=this;for(;i;){if(i.registry.has(e))return this.resolveToken(e,t,n,r);i=i.parent}}};const y=(e,t)=>new v(e,t);var b=class{registry;resolver;parent;constructor(e=[],t){this.parent=t,this.registry=u();for(let t of e)this.registry.register(t);this.resolver=y(this.registry,t?.resolver)}register(e,n){if(n?.allowOverride&&this.resolver.hasDisposableInstance(e.provide))throw new t(`Cannot override token "${e.provide.name}": its instance was already created and has an onDispose hook. Dispose the container before replacing it.`);this.registry.register(e,n)&&this.resolver.invalidate(e.provide)}get(e){return o(e)?this.resolver.resolveOptional(e.token):this.resolver.resolve(e)}has(e){return this.registry.has(e)||(this.parent?.has(e)??!1)}dispose(){return this.resolver.dispose()}};const x=(e=[])=>new b(e),S=(e,t=[])=>new b(t,e);var C=class{name;id;constructor(e){this.name=e,this.id=Symbol(e)}};const w=e=>new C(e);exports.CircularDependencyError=p,exports.DiError=e,exports.DuplicateProviderError=c,exports.InvalidDependencyError=f,exports.InvalidProviderError=t,exports.MissingProviderError=d,exports.Scopes=n,exports.createChildContainer=S,exports.createContainer=x,exports.createToken=w,exports.optional=a,exports.provideFactory=i,exports.provideValue=r;
|
|
2
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/error/error.ts","../src/provider/errors.ts","../src/scope/scope.ts","../src/provider/provider.ts","../src/registry/errors.ts","../src/registry/registry.ts","../src/resolver/errors.ts","../src/store/store.ts","../src/resolver/context.ts","../src/resolver/resolver.ts","../src/container/container.ts","../src/token/token.ts"],"sourcesContent":["export class DiError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\n\t\tthis.name = \"DiError\";\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, this.constructor);\n\t\t}\n\t}\n}\n","import { DiError } from \"../error\";\n\nexport class InvalidProviderError extends DiError {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\n\t\tthis.name = \"InvalidProviderError\";\n\t}\n}\n","export const Scopes = {\n\tSingleton: \"singleton\",\n\tTransient: \"transient\",\n\tScoped: \"scoped\",\n} as const;\n\nexport type Scope = (typeof Scopes)[keyof typeof Scopes];\n","import { type Scope, Scopes } from \"../scope\";\nimport type { Token } from \"../token\";\nimport { InvalidProviderError } from \"./errors\";\nimport type {\n\tAnyFactoryProvider,\n\tDependency,\n\tDepsMap,\n\tDisposeHook,\n\tFactory,\n\tFactoryProvider,\n\tOptionalDependency,\n\tProvider,\n\tValueProvider,\n} from \"./types\";\n\nexport const provideValue = <T>(\n\ttoken: Token<T>,\n\tuseValue: T,\n): ValueProvider<T> => ({\n\tprovide: token,\n\tuseValue,\n});\n\nexport const provideFactory = <T, TDeps extends DepsMap = Record<never, never>>(\n\ttoken: Token<T>,\n\toptions: {\n\t\treadonly deps?: TDeps;\n\t\treadonly scope?: Scope;\n\t\treadonly useFactory: Factory<T, TDeps>;\n\t\treadonly onDispose?: DisposeHook<T>;\n\t},\n): FactoryProvider<T, TDeps> => {\n\t// Transient instances aren't cached, so onDispose could never run.\n\tif (options.scope === Scopes.Transient && options.onDispose) {\n\t\tthrow new InvalidProviderError(\n\t\t\t`onDispose is not supported for transient providers (token \"${token.name}\"): transient instances are not tracked, so the hook would never run.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tprovide: token,\n\t\tuseFactory: options.useFactory,\n\t\tscope: options.scope ?? Scopes.Singleton,\n\t\t...(options.deps ? { deps: options.deps } : {}),\n\t\t...(options.onDispose ? { onDispose: options.onDispose } : {}),\n\t};\n};\n\n// Marks a dependency optional: resolves to undefined when no provider exists.\nexport const optional = <T>(token: Token<T>): OptionalDependency<T> => ({\n\ttoken,\n\toptional: true,\n});\n\nexport const isOptionalDependency = <T>(\n\tdependency: Dependency<T>,\n): dependency is OptionalDependency<T> => {\n\treturn (dependency as OptionalDependency<T>).optional === true;\n};\n\nexport const isValueProvider = (\n\tprovider: Provider,\n): provider is ValueProvider<unknown> => {\n\treturn \"useValue\" in provider;\n};\n\nexport const isFactoryProvider = (\n\tprovider: Provider,\n): provider is AnyFactoryProvider => {\n\treturn \"useFactory\" in provider;\n};\n","import { DiError } from \"../error\";\n\nexport class DuplicateProviderError extends DiError {\n\tconstructor(tokenName: string) {\n\t\tsuper(`Provider for token \"${tokenName}\" is already registered`);\n\n\t\tthis.name = \"DuplicateProviderError\";\n\t}\n}\n","import type { Provider } from \"../provider\";\nimport type { Token } from \"../token\";\nimport { DuplicateProviderError } from \"./errors\";\nimport type { RegisterOptions, Registry } from \"./types\";\n\nclass RegistryClass implements Registry {\n\tprivate readonly providers = new Map<symbol, Provider>();\n\n\tregister(provider: Provider, options?: RegisterOptions): boolean {\n\t\tconst existed = this.providers.has(provider.provide.id);\n\n\t\tif (existed && !options?.allowOverride) {\n\t\t\tthrow new DuplicateProviderError(provider.provide.name);\n\t\t}\n\n\t\tthis.providers.set(provider.provide.id, provider);\n\n\t\t// true if an existing provider was replaced (override).\n\t\treturn existed;\n\t}\n\n\tget(token: Token<unknown>): Provider | undefined {\n\t\treturn this.providers.get(token.id);\n\t}\n\n\thas(token: Token<unknown>): boolean {\n\t\treturn this.providers.has(token.id);\n\t}\n}\n\nexport const createRegistry = (): Registry => new RegistryClass();\n","import { DiError } from \"../error\";\n\nexport class MissingProviderError extends DiError {\n\tconstructor(tokenName: string) {\n\t\tsuper(`Provider for token \"${tokenName}\" is not registered`);\n\n\t\tthis.name = \"MissingProviderError\";\n\t}\n}\n\nexport class InvalidDependencyError extends DiError {\n\tconstructor(dependencyKey: string) {\n\t\tsuper(`Invalid dependency \"${dependencyKey}\"`);\n\n\t\tthis.name = \"InvalidDependencyError\";\n\t}\n}\n\nexport class CircularDependencyError extends DiError {\n\tconstructor(tokenNames: string[]) {\n\t\tsuper(`Circular dependency detected: ${tokenNames.join(\" -> \")}`);\n\n\t\tthis.name = \"CircularDependencyError\";\n\t}\n}\n","import type { Token } from \"../token\";\nimport type { InstanceRecord, Store } from \"./types\";\n\nclass StoreClass implements Store {\n\tprivate readonly instances = new Map<symbol, InstanceRecord>();\n\n\tget(token: Token<unknown>): InstanceRecord | undefined {\n\t\treturn this.instances.get(token.id);\n\t}\n\n\tset(token: Token<unknown>, record: InstanceRecord): void {\n\t\tthis.instances.set(token.id, record);\n\t}\n\n\tdelete(token: Token<unknown>): void {\n\t\tthis.instances.delete(token.id);\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\t// Snapshot and clear first so dispose() is idempotent and re-entrancy safe.\n\t\tconst records = [...this.instances.values()].reverse();\n\n\t\tthis.instances.clear();\n\n\t\tfor (const record of records) {\n\t\t\tif (record.onDispose) {\n\t\t\t\tawait record.onDispose(record.value);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport const createStore = (): Store => new StoreClass();\n","import type { Token } from \"../token\";\nimport { CircularDependencyError } from \"./errors\";\n\nexport class ResolutionContext {\n\tprivate readonly resolving = new Set<symbol>();\n\tprivate readonly path: Token<unknown>[] = [];\n\n\tenter(token: Token<unknown>): void {\n\t\tif (this.resolving.has(token.id)) {\n\t\t\tconst cycleStartIndex = this.path.findIndex(\n\t\t\t\t(pathToken) => pathToken.id === token.id,\n\t\t\t);\n\n\t\t\tconst cycle = [...this.path.slice(cycleStartIndex), token];\n\n\t\t\tthrow new CircularDependencyError(\n\t\t\t\tcycle.map((cycleToken) => cycleToken.name),\n\t\t\t);\n\t\t}\n\n\t\tthis.resolving.add(token.id);\n\t\tthis.path.push(token);\n\t}\n\n\texit(token: Token<unknown>): void {\n\t\tthis.path.pop();\n\t\tthis.resolving.delete(token.id);\n\t}\n}\n","import type { DepsMap, Provider, ResolveDeps } from \"../provider\";\nimport {\n\tInvalidProviderError,\n\tisOptionalDependency,\n\tisValueProvider,\n} from \"../provider\";\nimport type { Registry } from \"../registry\";\nimport { type Scope, Scopes } from \"../scope\";\nimport { createStore, type Store } from \"../store\";\nimport type { Token } from \"../token\";\nimport { ResolutionContext } from \"./context\";\nimport { InvalidDependencyError, MissingProviderError } from \"./errors\";\nimport type { Resolver } from \"./types\";\n\n// Lifetime ordering: longer-lived scopes rank lower. A provider may only depend\n// on dependencies that live at least as long as itself.\nconst lifetimeRank = (scope: Scope | undefined): number =>\n\tscope === Scopes.Scoped ? 1 : scope === Scopes.Transient ? 2 : 0;\n\nclass ResolverClass implements Resolver {\n\tprivate readonly registry: Registry;\n\tprivate readonly store: Store = createStore();\n\tprivate readonly parent: ResolverClass | undefined;\n\n\tconstructor(registry: Registry, parent?: ResolverClass) {\n\t\tthis.registry = registry;\n\t\tthis.parent = parent;\n\t}\n\n\tresolve<T>(token: Token<T>): T {\n\t\treturn this.resolveToken(token, undefined);\n\t}\n\n\tresolveOptional<T>(token: Token<T>): T | undefined {\n\t\treturn this.lookupOptional(token, undefined);\n\t}\n\n\tinvalidate(token: Token<unknown>): void {\n\t\tthis.store.delete(token);\n\t}\n\n\t// True if a locally-cached instance has an onDispose hook.\n\thasDisposableInstance(token: Token<unknown>): boolean {\n\t\treturn this.store.get(token)?.onDispose !== undefined;\n\t}\n\n\tdispose(): Promise<void> {\n\t\treturn this.store.dispose();\n\t}\n\n\t// context is allocated lazily by the first building factory (zero-alloc cache hits).\n\t// consumerScope/consumerName describe the provider depending on this token, if any.\n\tprivate resolveToken<T>(\n\t\ttoken: Token<T>,\n\t\tcontext: ResolutionContext | undefined,\n\t\tconsumerScope?: Scope,\n\t\tconsumerName?: string,\n\t): T {\n\t\t// Single walk up the parent chain, fetching the provider directly.\n\t\tlet owner: ResolverClass | undefined = this;\n\t\tlet provider: Provider | undefined;\n\n\t\twhile (owner) {\n\t\t\tprovider = owner.registry.get(token);\n\n\t\t\tif (provider) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\towner = owner.parent;\n\t\t}\n\n\t\tif (!provider || !owner) {\n\t\t\tthrow new MissingProviderError(token.name);\n\t\t}\n\n\t\t// Values outlive every scope, so they are always a safe dependency.\n\t\tif (isValueProvider(provider)) {\n\t\t\treturn provider.useValue as T;\n\t\t}\n\n\t\t// Otherwise it is a factory provider (the only remaining variant).\n\t\t// Reject capturing a shorter-lived dependency into a longer-lived consumer.\n\t\tif (\n\t\t\tconsumerScope !== undefined &&\n\t\t\tlifetimeRank(provider.scope) > lifetimeRank(consumerScope)\n\t\t) {\n\t\t\tthrow new InvalidProviderError(\n\t\t\t\t`\"${consumerName}\" (${consumerScope}) cannot depend on \"${token.name}\" (${provider.scope ?? Scopes.Singleton}): a longer-lived provider would capture a shorter-lived one. Widen the dependency's scope or narrow the consumer's.`,\n\t\t\t);\n\t\t}\n\n\t\t// Scope decides the host: singleton on owner, scoped on this, transient nowhere.\n\t\tconst host = this.selectHost(provider.scope, owner);\n\n\t\tif (host) {\n\t\t\tconst cached = host.store.get(token);\n\n\t\t\tif (cached) {\n\t\t\t\treturn cached.value as T;\n\t\t\t}\n\t\t}\n\n\t\t// Allocate cycle detection only now, threading it through the build.\n\t\tconst ctx = context ?? new ResolutionContext();\n\t\tctx.enter(token);\n\n\t\ttry {\n\t\t\t// Resolve deps from the host: scoped sees this container, singleton sees owner.\n\t\t\tconst deps = (host ?? this).resolveDeps(\n\t\t\t\tprovider.deps,\n\t\t\t\tctx,\n\t\t\t\tprovider.scope,\n\t\t\t\ttoken.name,\n\t\t\t);\n\t\t\tconst value = provider.useFactory(deps) as T;\n\n\t\t\tif (host) {\n\t\t\t\thost.store.set(token, {\n\t\t\t\t\tvalue,\n\t\t\t\t\t...(provider.onDispose ? { onDispose: provider.onDispose } : {}),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn value;\n\t\t} finally {\n\t\t\tctx.exit(token);\n\t\t}\n\t}\n\n\tprivate selectHost(\n\t\tscope: Scope | undefined,\n\t\towner: ResolverClass,\n\t): ResolverClass | undefined {\n\t\tif (scope === Scopes.Transient) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (scope === Scopes.Scoped) {\n\t\t\treturn this;\n\t\t}\n\n\t\treturn owner;\n\t}\n\n\tprivate resolveDeps<TDeps extends DepsMap>(\n\t\tdeps: TDeps | undefined,\n\t\tcontext: ResolutionContext,\n\t\tconsumerScope: Scope | undefined,\n\t\tconsumerName: string,\n\t): ResolveDeps<TDeps> {\n\t\tif (!deps) {\n\t\t\treturn {} as ResolveDeps<TDeps>;\n\t\t}\n\n\t\tconst resolvedDeps: Partial<ResolveDeps<TDeps>> = {};\n\n\t\tfor (const key of Object.keys(deps) as Array<keyof TDeps>) {\n\t\t\tconst dependency = deps[key];\n\n\t\t\tif (dependency === undefined) {\n\t\t\t\tthrow new InvalidDependencyError(String(key));\n\t\t\t}\n\n\t\t\tresolvedDeps[key] = (\n\t\t\t\tisOptionalDependency(dependency)\n\t\t\t\t\t? this.lookupOptional(\n\t\t\t\t\t\t\tdependency.token,\n\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\tconsumerScope,\n\t\t\t\t\t\t\tconsumerName,\n\t\t\t\t\t\t)\n\t\t\t\t\t: this.resolveToken(dependency, context, consumerScope, consumerName)\n\t\t\t) as ResolveDeps<TDeps>[typeof key];\n\t\t}\n\n\t\treturn resolvedDeps as ResolveDeps<TDeps>;\n\t}\n\n\t// Absent provider -> undefined; a present one resolves normally (its errors surface).\n\tprivate lookupOptional<T>(\n\t\ttoken: Token<T>,\n\t\tcontext: ResolutionContext | undefined,\n\t\tconsumerScope?: Scope,\n\t\tconsumerName?: string,\n\t): T | undefined {\n\t\tlet owner: ResolverClass | undefined = this;\n\n\t\twhile (owner) {\n\t\t\tif (owner.registry.has(token)) {\n\t\t\t\treturn this.resolveToken(token, context, consumerScope, consumerName);\n\t\t\t}\n\n\t\t\towner = owner.parent;\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n\nexport const createResolver = (\n\tregistry: Registry,\n\tparent?: Resolver,\n): Resolver => new ResolverClass(registry, parent as ResolverClass | undefined);\n","import {\n\ttype Dependency,\n\tInvalidProviderError,\n\tisOptionalDependency,\n\ttype OptionalDependency,\n\ttype Provider,\n} from \"../provider\";\nimport {\n\tcreateRegistry,\n\ttype RegisterOptions,\n\ttype Registry,\n} from \"../registry\";\nimport { createResolver, type Resolver } from \"../resolver\";\nimport type { Token } from \"../token\";\nimport type { Container } from \"./types\";\n\nclass ContainerClass implements Container {\n\tprivate readonly registry: Registry;\n\tprivate readonly resolver: Resolver;\n\tprivate readonly parent: ContainerClass | undefined;\n\n\tconstructor(providers: readonly Provider[] = [], parent?: ContainerClass) {\n\t\tthis.parent = parent;\n\t\tthis.registry = createRegistry();\n\n\t\tfor (const provider of providers) {\n\t\t\tthis.registry.register(provider);\n\t\t}\n\n\t\tthis.resolver = createResolver(this.registry, parent?.resolver);\n\t}\n\n\tregister(provider: Provider, options?: RegisterOptions): void {\n\t\t// Don't silently drop a live disposable instance; require explicit dispose.\n\t\tif (\n\t\t\toptions?.allowOverride &&\n\t\t\tthis.resolver.hasDisposableInstance(provider.provide)\n\t\t) {\n\t\t\tthrow new InvalidProviderError(\n\t\t\t\t`Cannot override token \"${provider.provide.name}\": its instance was already created and has an onDispose hook. Dispose the container before replacing it.`,\n\t\t\t);\n\t\t}\n\n\t\tconst overridden = this.registry.register(provider, options);\n\n\t\tif (overridden) {\n\t\t\tthis.resolver.invalidate(provider.provide);\n\t\t}\n\t}\n\n\tget<T>(token: Token<T>): T;\n\tget<T>(dependency: OptionalDependency<T>): T | undefined;\n\tget<T>(dependency: Dependency<T>): T | undefined {\n\t\tif (isOptionalDependency(dependency)) {\n\t\t\treturn this.resolver.resolveOptional(dependency.token);\n\t\t}\n\n\t\treturn this.resolver.resolve(dependency);\n\t}\n\n\thas(token: Token<unknown>): boolean {\n\t\treturn this.registry.has(token) || (this.parent?.has(token) ?? false);\n\t}\n\n\tdispose(): Promise<void> {\n\t\treturn this.resolver.dispose();\n\t}\n}\n\nexport const createContainer = (\n\tproviders: readonly Provider[] = [],\n): Container => new ContainerClass(providers);\n\nexport const createChildContainer = (\n\tparent: Container,\n\tproviders: readonly Provider[] = [],\n): Container => new ContainerClass(providers, parent as ContainerClass);\n","import type { Token } from \"./types\";\n\nclass TokenClass<T> implements Token<T> {\n\treadonly name: string;\n\treadonly id: symbol;\n\n\tdeclare readonly __type?: T;\n\n\tconstructor(name: string) {\n\t\tthis.name = name;\n\t\tthis.id = Symbol(name);\n\t}\n}\n\nexport const createToken = <T>(name: string): Token<T> =>\n\tnew TokenClass<T>(name);\n"],"mappings":"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"}
|
package/dist/index.d.cts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
//#region src/error/error.d.ts
|
|
2
|
-
declare class DiError extends Error {
|
|
3
|
-
constructor(message: string);
|
|
4
|
-
}
|
|
5
|
-
//#endregion
|
|
6
|
-
//#region src/provider/errors.d.ts
|
|
7
|
-
declare class InvalidProviderError extends DiError {
|
|
8
|
-
constructor(message: string);
|
|
9
|
-
}
|
|
10
|
-
//#endregion
|
|
11
|
-
//#region src/scope/scope.d.ts
|
|
12
|
-
declare const Scopes: {
|
|
13
|
-
readonly Singleton: "singleton";
|
|
14
|
-
readonly Transient: "transient";
|
|
15
|
-
readonly Scoped: "scoped";
|
|
16
|
-
};
|
|
17
|
-
type Scope = (typeof Scopes)[keyof typeof Scopes];
|
|
18
|
-
//#endregion
|
|
19
|
-
//#region src/token/types.d.ts
|
|
20
|
-
type Token<T> = {
|
|
21
|
-
readonly id: symbol;
|
|
22
|
-
readonly name: string;
|
|
23
|
-
readonly __type?: T;
|
|
24
|
-
};
|
|
25
|
-
//#endregion
|
|
26
|
-
//#region src/token/token.d.ts
|
|
27
|
-
declare const createToken: <T>(name: string) => Token<T>;
|
|
28
|
-
//#endregion
|
|
29
|
-
//#region src/provider/types.d.ts
|
|
30
|
-
type OptionalDependency<T> = {
|
|
31
|
-
readonly token: Token<T>;
|
|
32
|
-
readonly optional: true;
|
|
33
|
-
};
|
|
34
|
-
type Dependency<T> = Token<T> | OptionalDependency<T>;
|
|
35
|
-
type DepsMap = Record<string, Dependency<unknown>>;
|
|
36
|
-
type DependencyValue<TDep> = TDep extends OptionalDependency<infer T> ? T | undefined : TDep extends Token<infer T> ? T : never;
|
|
37
|
-
type ResolveDeps<TDeps extends DepsMap> = { readonly [TKey in keyof TDeps]: DependencyValue<TDeps[TKey]> };
|
|
38
|
-
type Factory<T, TDeps extends DepsMap> = (deps: ResolveDeps<TDeps>) => T;
|
|
39
|
-
type DisposeHook<T> = (instance: T) => void | Promise<void>;
|
|
40
|
-
type ValueProvider<T> = {
|
|
41
|
-
readonly provide: Token<T>;
|
|
42
|
-
readonly useValue: T;
|
|
43
|
-
};
|
|
44
|
-
type FactoryProvider<T, TDeps extends DepsMap = Record<never, never>> = {
|
|
45
|
-
readonly provide: Token<T>;
|
|
46
|
-
readonly deps?: TDeps;
|
|
47
|
-
readonly scope?: Scope;
|
|
48
|
-
readonly useFactory: Factory<T, TDeps>;
|
|
49
|
-
readonly onDispose?: DisposeHook<T>;
|
|
50
|
-
};
|
|
51
|
-
type AnyFactoryProvider = FactoryProvider<any, any>;
|
|
52
|
-
type Provider = ValueProvider<unknown> | AnyFactoryProvider;
|
|
53
|
-
//#endregion
|
|
54
|
-
//#region src/provider/provider.d.ts
|
|
55
|
-
declare const provideValue: <T>(token: Token<T>, useValue: T) => ValueProvider<T>;
|
|
56
|
-
declare const provideFactory: <T, TDeps extends DepsMap = Record<never, never>>(token: Token<T>, options: {
|
|
57
|
-
readonly deps?: TDeps;
|
|
58
|
-
readonly scope?: Scope;
|
|
59
|
-
readonly useFactory: Factory<T, TDeps>;
|
|
60
|
-
readonly onDispose?: DisposeHook<T>;
|
|
61
|
-
}) => FactoryProvider<T, TDeps>;
|
|
62
|
-
declare const optional: <T>(token: Token<T>) => OptionalDependency<T>;
|
|
63
|
-
//#endregion
|
|
64
|
-
//#region src/registry/errors.d.ts
|
|
65
|
-
declare class DuplicateProviderError extends DiError {
|
|
66
|
-
constructor(tokenName: string);
|
|
67
|
-
}
|
|
68
|
-
//#endregion
|
|
69
|
-
//#region src/registry/types.d.ts
|
|
70
|
-
type RegisterOptions = {
|
|
71
|
-
readonly allowOverride?: boolean;
|
|
72
|
-
};
|
|
73
|
-
//#endregion
|
|
74
|
-
//#region src/container/types.d.ts
|
|
75
|
-
type Container = {
|
|
76
|
-
register(provider: Provider, options?: RegisterOptions): void;
|
|
77
|
-
get<T>(token: Token<T>): T;
|
|
78
|
-
get<T>(dependency: OptionalDependency<T>): T | undefined;
|
|
79
|
-
has(token: Token<unknown>): boolean;
|
|
80
|
-
dispose(): Promise<void>;
|
|
81
|
-
};
|
|
82
|
-
//#endregion
|
|
83
|
-
//#region src/container/container.d.ts
|
|
84
|
-
declare const createContainer: (providers?: readonly Provider[]) => Container;
|
|
85
|
-
declare const createChildContainer: (parent: Container, providers?: readonly Provider[]) => Container;
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/resolver/errors.d.ts
|
|
88
|
-
declare class MissingProviderError extends DiError {
|
|
89
|
-
constructor(tokenName: string);
|
|
90
|
-
}
|
|
91
|
-
declare class InvalidDependencyError extends DiError {
|
|
92
|
-
constructor(dependencyKey: string);
|
|
93
|
-
}
|
|
94
|
-
declare class CircularDependencyError extends DiError {
|
|
95
|
-
constructor(tokenNames: string[]);
|
|
96
|
-
}
|
|
97
|
-
//#endregion
|
|
98
|
-
export { CircularDependencyError, type Container, type Dependency, DiError, type DisposeHook, DuplicateProviderError, type FactoryProvider, InvalidDependencyError, InvalidProviderError, MissingProviderError, type OptionalDependency, type Provider, type RegisterOptions, type Scope, Scopes, type Token, type ValueProvider, createChildContainer, createContainer, createToken, optional, provideFactory, provideValue };
|
|
99
|
-
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/error/error.ts","../src/provider/errors.ts","../src/scope/scope.ts","../src/provider/provider.ts","../src/registry/errors.ts","../src/registry/registry.ts","../src/resolver/errors.ts","../src/store/store.ts","../src/resolver/context.ts","../src/resolver/resolver.ts","../src/container/container.ts","../src/token/token.ts"],"sourcesContent":["export class DiError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\n\t\tthis.name = \"DiError\";\n\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, this.constructor);\n\t\t}\n\t}\n}\n","import { DiError } from \"../error\";\n\nexport class InvalidProviderError extends DiError {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\n\t\tthis.name = \"InvalidProviderError\";\n\t}\n}\n","export const Scopes = {\n\tSingleton: \"singleton\",\n\tTransient: \"transient\",\n\tScoped: \"scoped\",\n} as const;\n\nexport type Scope = (typeof Scopes)[keyof typeof Scopes];\n","import { type Scope, Scopes } from \"../scope\";\nimport type { Token } from \"../token\";\nimport { InvalidProviderError } from \"./errors\";\nimport type {\n\tAnyFactoryProvider,\n\tDependency,\n\tDepsMap,\n\tDisposeHook,\n\tFactory,\n\tFactoryProvider,\n\tOptionalDependency,\n\tProvider,\n\tValueProvider,\n} from \"./types\";\n\nexport const provideValue = <T>(\n\ttoken: Token<T>,\n\tuseValue: T,\n): ValueProvider<T> => ({\n\tprovide: token,\n\tuseValue,\n});\n\nexport const provideFactory = <T, TDeps extends DepsMap = Record<never, never>>(\n\ttoken: Token<T>,\n\toptions: {\n\t\treadonly deps?: TDeps;\n\t\treadonly scope?: Scope;\n\t\treadonly useFactory: Factory<T, TDeps>;\n\t\treadonly onDispose?: DisposeHook<T>;\n\t},\n): FactoryProvider<T, TDeps> => {\n\t// Transient instances aren't cached, so onDispose could never run.\n\tif (options.scope === Scopes.Transient && options.onDispose) {\n\t\tthrow new InvalidProviderError(\n\t\t\t`onDispose is not supported for transient providers (token \"${token.name}\"): transient instances are not tracked, so the hook would never run.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tprovide: token,\n\t\tuseFactory: options.useFactory,\n\t\tscope: options.scope ?? Scopes.Singleton,\n\t\t...(options.deps ? { deps: options.deps } : {}),\n\t\t...(options.onDispose ? { onDispose: options.onDispose } : {}),\n\t};\n};\n\n// Marks a dependency optional: resolves to undefined when no provider exists.\nexport const optional = <T>(token: Token<T>): OptionalDependency<T> => ({\n\ttoken,\n\toptional: true,\n});\n\nexport const isOptionalDependency = <T>(\n\tdependency: Dependency<T>,\n): dependency is OptionalDependency<T> => {\n\treturn (dependency as OptionalDependency<T>).optional === true;\n};\n\nexport const isValueProvider = (\n\tprovider: Provider,\n): provider is ValueProvider<unknown> => {\n\treturn \"useValue\" in provider;\n};\n\nexport const isFactoryProvider = (\n\tprovider: Provider,\n): provider is AnyFactoryProvider => {\n\treturn \"useFactory\" in provider;\n};\n","import { DiError } from \"../error\";\n\nexport class DuplicateProviderError extends DiError {\n\tconstructor(tokenName: string) {\n\t\tsuper(`Provider for token \"${tokenName}\" is already registered`);\n\n\t\tthis.name = \"DuplicateProviderError\";\n\t}\n}\n","import type { Provider } from \"../provider\";\nimport type { Token } from \"../token\";\nimport { DuplicateProviderError } from \"./errors\";\nimport type { RegisterOptions, Registry } from \"./types\";\n\nclass RegistryClass implements Registry {\n\tprivate readonly providers = new Map<symbol, Provider>();\n\n\tregister(provider: Provider, options?: RegisterOptions): boolean {\n\t\tconst existed = this.providers.has(provider.provide.id);\n\n\t\tif (existed && !options?.allowOverride) {\n\t\t\tthrow new DuplicateProviderError(provider.provide.name);\n\t\t}\n\n\t\tthis.providers.set(provider.provide.id, provider);\n\n\t\t// true if an existing provider was replaced (override).\n\t\treturn existed;\n\t}\n\n\tget(token: Token<unknown>): Provider | undefined {\n\t\treturn this.providers.get(token.id);\n\t}\n\n\thas(token: Token<unknown>): boolean {\n\t\treturn this.providers.has(token.id);\n\t}\n}\n\nexport const createRegistry = (): Registry => new RegistryClass();\n","import { DiError } from \"../error\";\n\nexport class MissingProviderError extends DiError {\n\tconstructor(tokenName: string) {\n\t\tsuper(`Provider for token \"${tokenName}\" is not registered`);\n\n\t\tthis.name = \"MissingProviderError\";\n\t}\n}\n\nexport class InvalidDependencyError extends DiError {\n\tconstructor(dependencyKey: string) {\n\t\tsuper(`Invalid dependency \"${dependencyKey}\"`);\n\n\t\tthis.name = \"InvalidDependencyError\";\n\t}\n}\n\nexport class CircularDependencyError extends DiError {\n\tconstructor(tokenNames: string[]) {\n\t\tsuper(`Circular dependency detected: ${tokenNames.join(\" -> \")}`);\n\n\t\tthis.name = \"CircularDependencyError\";\n\t}\n}\n","import type { Token } from \"../token\";\nimport type { InstanceRecord, Store } from \"./types\";\n\nclass StoreClass implements Store {\n\tprivate readonly instances = new Map<symbol, InstanceRecord>();\n\n\tget(token: Token<unknown>): InstanceRecord | undefined {\n\t\treturn this.instances.get(token.id);\n\t}\n\n\tset(token: Token<unknown>, record: InstanceRecord): void {\n\t\tthis.instances.set(token.id, record);\n\t}\n\n\tdelete(token: Token<unknown>): void {\n\t\tthis.instances.delete(token.id);\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\t// Snapshot and clear first so dispose() is idempotent and re-entrancy safe.\n\t\tconst records = [...this.instances.values()].reverse();\n\n\t\tthis.instances.clear();\n\n\t\tfor (const record of records) {\n\t\t\tif (record.onDispose) {\n\t\t\t\tawait record.onDispose(record.value);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport const createStore = (): Store => new StoreClass();\n","import type { Token } from \"../token\";\nimport { CircularDependencyError } from \"./errors\";\n\nexport class ResolutionContext {\n\tprivate readonly resolving = new Set<symbol>();\n\tprivate readonly path: Token<unknown>[] = [];\n\n\tenter(token: Token<unknown>): void {\n\t\tif (this.resolving.has(token.id)) {\n\t\t\tconst cycleStartIndex = this.path.findIndex(\n\t\t\t\t(pathToken) => pathToken.id === token.id,\n\t\t\t);\n\n\t\t\tconst cycle = [...this.path.slice(cycleStartIndex), token];\n\n\t\t\tthrow new CircularDependencyError(\n\t\t\t\tcycle.map((cycleToken) => cycleToken.name),\n\t\t\t);\n\t\t}\n\n\t\tthis.resolving.add(token.id);\n\t\tthis.path.push(token);\n\t}\n\n\texit(token: Token<unknown>): void {\n\t\tthis.path.pop();\n\t\tthis.resolving.delete(token.id);\n\t}\n}\n","import type { DepsMap, Provider, ResolveDeps } from \"../provider\";\nimport {\n\tInvalidProviderError,\n\tisOptionalDependency,\n\tisValueProvider,\n} from \"../provider\";\nimport type { Registry } from \"../registry\";\nimport { type Scope, Scopes } from \"../scope\";\nimport { createStore, type Store } from \"../store\";\nimport type { Token } from \"../token\";\nimport { ResolutionContext } from \"./context\";\nimport { InvalidDependencyError, MissingProviderError } from \"./errors\";\nimport type { Resolver } from \"./types\";\n\n// Lifetime ordering: longer-lived scopes rank lower. A provider may only depend\n// on dependencies that live at least as long as itself.\nconst lifetimeRank = (scope: Scope | undefined): number =>\n\tscope === Scopes.Scoped ? 1 : scope === Scopes.Transient ? 2 : 0;\n\nclass ResolverClass implements Resolver {\n\tprivate readonly registry: Registry;\n\tprivate readonly store: Store = createStore();\n\tprivate readonly parent: ResolverClass | undefined;\n\n\tconstructor(registry: Registry, parent?: ResolverClass) {\n\t\tthis.registry = registry;\n\t\tthis.parent = parent;\n\t}\n\n\tresolve<T>(token: Token<T>): T {\n\t\treturn this.resolveToken(token, undefined);\n\t}\n\n\tresolveOptional<T>(token: Token<T>): T | undefined {\n\t\treturn this.lookupOptional(token, undefined);\n\t}\n\n\tinvalidate(token: Token<unknown>): void {\n\t\tthis.store.delete(token);\n\t}\n\n\t// True if a locally-cached instance has an onDispose hook.\n\thasDisposableInstance(token: Token<unknown>): boolean {\n\t\treturn this.store.get(token)?.onDispose !== undefined;\n\t}\n\n\tdispose(): Promise<void> {\n\t\treturn this.store.dispose();\n\t}\n\n\t// context is allocated lazily by the first building factory (zero-alloc cache hits).\n\t// consumerScope/consumerName describe the provider depending on this token, if any.\n\tprivate resolveToken<T>(\n\t\ttoken: Token<T>,\n\t\tcontext: ResolutionContext | undefined,\n\t\tconsumerScope?: Scope,\n\t\tconsumerName?: string,\n\t): T {\n\t\t// Single walk up the parent chain, fetching the provider directly.\n\t\tlet owner: ResolverClass | undefined = this;\n\t\tlet provider: Provider | undefined;\n\n\t\twhile (owner) {\n\t\t\tprovider = owner.registry.get(token);\n\n\t\t\tif (provider) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\towner = owner.parent;\n\t\t}\n\n\t\tif (!provider || !owner) {\n\t\t\tthrow new MissingProviderError(token.name);\n\t\t}\n\n\t\t// Values outlive every scope, so they are always a safe dependency.\n\t\tif (isValueProvider(provider)) {\n\t\t\treturn provider.useValue as T;\n\t\t}\n\n\t\t// Otherwise it is a factory provider (the only remaining variant).\n\t\t// Reject capturing a shorter-lived dependency into a longer-lived consumer.\n\t\tif (\n\t\t\tconsumerScope !== undefined &&\n\t\t\tlifetimeRank(provider.scope) > lifetimeRank(consumerScope)\n\t\t) {\n\t\t\tthrow new InvalidProviderError(\n\t\t\t\t`\"${consumerName}\" (${consumerScope}) cannot depend on \"${token.name}\" (${provider.scope ?? Scopes.Singleton}): a longer-lived provider would capture a shorter-lived one. Widen the dependency's scope or narrow the consumer's.`,\n\t\t\t);\n\t\t}\n\n\t\t// Scope decides the host: singleton on owner, scoped on this, transient nowhere.\n\t\tconst host = this.selectHost(provider.scope, owner);\n\n\t\tif (host) {\n\t\t\tconst cached = host.store.get(token);\n\n\t\t\tif (cached) {\n\t\t\t\treturn cached.value as T;\n\t\t\t}\n\t\t}\n\n\t\t// Allocate cycle detection only now, threading it through the build.\n\t\tconst ctx = context ?? new ResolutionContext();\n\t\tctx.enter(token);\n\n\t\ttry {\n\t\t\t// Resolve deps from the host: scoped sees this container, singleton sees owner.\n\t\t\tconst deps = (host ?? this).resolveDeps(\n\t\t\t\tprovider.deps,\n\t\t\t\tctx,\n\t\t\t\tprovider.scope,\n\t\t\t\ttoken.name,\n\t\t\t);\n\t\t\tconst value = provider.useFactory(deps) as T;\n\n\t\t\tif (host) {\n\t\t\t\thost.store.set(token, {\n\t\t\t\t\tvalue,\n\t\t\t\t\t...(provider.onDispose ? { onDispose: provider.onDispose } : {}),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn value;\n\t\t} finally {\n\t\t\tctx.exit(token);\n\t\t}\n\t}\n\n\tprivate selectHost(\n\t\tscope: Scope | undefined,\n\t\towner: ResolverClass,\n\t): ResolverClass | undefined {\n\t\tif (scope === Scopes.Transient) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (scope === Scopes.Scoped) {\n\t\t\treturn this;\n\t\t}\n\n\t\treturn owner;\n\t}\n\n\tprivate resolveDeps<TDeps extends DepsMap>(\n\t\tdeps: TDeps | undefined,\n\t\tcontext: ResolutionContext,\n\t\tconsumerScope: Scope | undefined,\n\t\tconsumerName: string,\n\t): ResolveDeps<TDeps> {\n\t\tif (!deps) {\n\t\t\treturn {} as ResolveDeps<TDeps>;\n\t\t}\n\n\t\tconst resolvedDeps: Partial<ResolveDeps<TDeps>> = {};\n\n\t\tfor (const key of Object.keys(deps) as Array<keyof TDeps>) {\n\t\t\tconst dependency = deps[key];\n\n\t\t\tif (dependency === undefined) {\n\t\t\t\tthrow new InvalidDependencyError(String(key));\n\t\t\t}\n\n\t\t\tresolvedDeps[key] = (\n\t\t\t\tisOptionalDependency(dependency)\n\t\t\t\t\t? this.lookupOptional(\n\t\t\t\t\t\t\tdependency.token,\n\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\tconsumerScope,\n\t\t\t\t\t\t\tconsumerName,\n\t\t\t\t\t\t)\n\t\t\t\t\t: this.resolveToken(dependency, context, consumerScope, consumerName)\n\t\t\t) as ResolveDeps<TDeps>[typeof key];\n\t\t}\n\n\t\treturn resolvedDeps as ResolveDeps<TDeps>;\n\t}\n\n\t// Absent provider -> undefined; a present one resolves normally (its errors surface).\n\tprivate lookupOptional<T>(\n\t\ttoken: Token<T>,\n\t\tcontext: ResolutionContext | undefined,\n\t\tconsumerScope?: Scope,\n\t\tconsumerName?: string,\n\t): T | undefined {\n\t\tlet owner: ResolverClass | undefined = this;\n\n\t\twhile (owner) {\n\t\t\tif (owner.registry.has(token)) {\n\t\t\t\treturn this.resolveToken(token, context, consumerScope, consumerName);\n\t\t\t}\n\n\t\t\towner = owner.parent;\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n\nexport const createResolver = (\n\tregistry: Registry,\n\tparent?: Resolver,\n): Resolver => new ResolverClass(registry, parent as ResolverClass | undefined);\n","import {\n\ttype Dependency,\n\tInvalidProviderError,\n\tisOptionalDependency,\n\ttype OptionalDependency,\n\ttype Provider,\n} from \"../provider\";\nimport {\n\tcreateRegistry,\n\ttype RegisterOptions,\n\ttype Registry,\n} from \"../registry\";\nimport { createResolver, type Resolver } from \"../resolver\";\nimport type { Token } from \"../token\";\nimport type { Container } from \"./types\";\n\nclass ContainerClass implements Container {\n\tprivate readonly registry: Registry;\n\tprivate readonly resolver: Resolver;\n\tprivate readonly parent: ContainerClass | undefined;\n\n\tconstructor(providers: readonly Provider[] = [], parent?: ContainerClass) {\n\t\tthis.parent = parent;\n\t\tthis.registry = createRegistry();\n\n\t\tfor (const provider of providers) {\n\t\t\tthis.registry.register(provider);\n\t\t}\n\n\t\tthis.resolver = createResolver(this.registry, parent?.resolver);\n\t}\n\n\tregister(provider: Provider, options?: RegisterOptions): void {\n\t\t// Don't silently drop a live disposable instance; require explicit dispose.\n\t\tif (\n\t\t\toptions?.allowOverride &&\n\t\t\tthis.resolver.hasDisposableInstance(provider.provide)\n\t\t) {\n\t\t\tthrow new InvalidProviderError(\n\t\t\t\t`Cannot override token \"${provider.provide.name}\": its instance was already created and has an onDispose hook. Dispose the container before replacing it.`,\n\t\t\t);\n\t\t}\n\n\t\tconst overridden = this.registry.register(provider, options);\n\n\t\tif (overridden) {\n\t\t\tthis.resolver.invalidate(provider.provide);\n\t\t}\n\t}\n\n\tget<T>(token: Token<T>): T;\n\tget<T>(dependency: OptionalDependency<T>): T | undefined;\n\tget<T>(dependency: Dependency<T>): T | undefined {\n\t\tif (isOptionalDependency(dependency)) {\n\t\t\treturn this.resolver.resolveOptional(dependency.token);\n\t\t}\n\n\t\treturn this.resolver.resolve(dependency);\n\t}\n\n\thas(token: Token<unknown>): boolean {\n\t\treturn this.registry.has(token) || (this.parent?.has(token) ?? false);\n\t}\n\n\tdispose(): Promise<void> {\n\t\treturn this.resolver.dispose();\n\t}\n}\n\nexport const createContainer = (\n\tproviders: readonly Provider[] = [],\n): Container => new ContainerClass(providers);\n\nexport const createChildContainer = (\n\tparent: Container,\n\tproviders: readonly Provider[] = [],\n): Container => new ContainerClass(providers, parent as ContainerClass);\n","import type { Token } from \"./types\";\n\nclass TokenClass<T> implements Token<T> {\n\treadonly name: string;\n\treadonly id: symbol;\n\n\tdeclare readonly __type?: T;\n\n\tconstructor(name: string) {\n\t\tthis.name = name;\n\t\tthis.id = Symbol(name);\n\t}\n}\n\nexport const createToken = <T>(name: string): Token<T> =>\n\tnew TokenClass<T>(name);\n"],"mappings":"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"}
|