katagami 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -68
- package/dist/container/index.d.ts +3 -80
- package/dist/disposable/index.d.ts +4 -4
- package/dist/index.cjs +110 -51
- package/dist/index.d.ts +1 -1
- package/dist/index.js +118 -31
- package/dist/lazy/index.d.ts +5 -7
- package/package.json +3 -8
- package/dist/index-g50fxds1.js +0 -34
- package/dist/scope/index.cjs +0 -212
- package/dist/scope/index.js +0 -153
package/dist/index.cjs
CHANGED
|
@@ -29,12 +29,65 @@ var __export = (target, all) => {
|
|
|
29
29
|
// src/index.ts
|
|
30
30
|
var exports_src = {};
|
|
31
31
|
__export(exports_src, {
|
|
32
|
+
createScope: () => createScope,
|
|
32
33
|
createContainer: () => createContainer,
|
|
34
|
+
Scope: () => Scope,
|
|
33
35
|
ContainerError: () => ContainerError,
|
|
34
36
|
Container: () => Container
|
|
35
37
|
});
|
|
36
38
|
module.exports = __toCommonJS(exports_src);
|
|
37
39
|
|
|
40
|
+
// src/internal.ts
|
|
41
|
+
var INTERNALS = Symbol("katagami.internals");
|
|
42
|
+
|
|
43
|
+
// src/container/index.ts
|
|
44
|
+
function createContainer() {
|
|
45
|
+
return new Container;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
class Container {
|
|
49
|
+
registrations;
|
|
50
|
+
singletonCache;
|
|
51
|
+
disposed = false;
|
|
52
|
+
[INTERNALS];
|
|
53
|
+
constructor() {
|
|
54
|
+
this.registrations = new Map;
|
|
55
|
+
this.singletonCache = new Map;
|
|
56
|
+
this[INTERNALS] = {
|
|
57
|
+
isDisposed: () => this.disposed,
|
|
58
|
+
markDisposed: () => {
|
|
59
|
+
this.disposed = true;
|
|
60
|
+
},
|
|
61
|
+
ownCache: this.singletonCache,
|
|
62
|
+
registrations: this.registrations,
|
|
63
|
+
singletonCache: this.singletonCache
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
registerSingleton(token, factory) {
|
|
67
|
+
return this.addRegistration(token, factory, "singleton");
|
|
68
|
+
}
|
|
69
|
+
registerTransient(token, factory) {
|
|
70
|
+
return this.addRegistration(token, factory, "transient");
|
|
71
|
+
}
|
|
72
|
+
registerScoped(token, factory) {
|
|
73
|
+
return this.addRegistration(token, factory, "scoped");
|
|
74
|
+
}
|
|
75
|
+
use(source) {
|
|
76
|
+
for (const [token, registrations] of source[INTERNALS].registrations) {
|
|
77
|
+
this.registrations.set(token, [...registrations]);
|
|
78
|
+
}
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
addRegistration(token, factory, lifetime) {
|
|
82
|
+
const existing = this.registrations.get(token);
|
|
83
|
+
if (existing !== undefined) {
|
|
84
|
+
existing.push({ factory, lifetime });
|
|
85
|
+
} else {
|
|
86
|
+
this.registrations.set(token, [{ factory, lifetime }]);
|
|
87
|
+
}
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
38
91
|
// src/error/index.ts
|
|
39
92
|
class ContainerError extends Error {
|
|
40
93
|
constructor(message) {
|
|
@@ -42,10 +95,6 @@ class ContainerError extends Error {
|
|
|
42
95
|
this.name = "ContainerError";
|
|
43
96
|
}
|
|
44
97
|
}
|
|
45
|
-
|
|
46
|
-
// src/internal.ts
|
|
47
|
-
var INTERNALS = Symbol("katagami.internals");
|
|
48
|
-
|
|
49
98
|
// src/resolver/index.ts
|
|
50
99
|
function tokenToString(token) {
|
|
51
100
|
if (typeof token === "function") {
|
|
@@ -71,46 +120,38 @@ function buildCircularPath(resolvingTokens, token) {
|
|
|
71
120
|
return path.join(" -> ");
|
|
72
121
|
}
|
|
73
122
|
|
|
74
|
-
// src/
|
|
75
|
-
function
|
|
76
|
-
|
|
123
|
+
// src/scope/index.ts
|
|
124
|
+
function createScope(source) {
|
|
125
|
+
const internals = source[INTERNALS];
|
|
126
|
+
if (internals.isDisposed()) {
|
|
127
|
+
throw new ContainerError("Cannot create a scope from a disposed container.");
|
|
128
|
+
}
|
|
129
|
+
return new Scope(internals.registrations, internals.singletonCache);
|
|
77
130
|
}
|
|
78
131
|
|
|
79
|
-
class
|
|
132
|
+
class Scope {
|
|
80
133
|
registrations;
|
|
81
134
|
singletonCache;
|
|
135
|
+
scopedCache;
|
|
82
136
|
resolvingTokens;
|
|
137
|
+
singletonDepth = 0;
|
|
83
138
|
disposed = false;
|
|
84
139
|
[INTERNALS];
|
|
85
|
-
constructor() {
|
|
86
|
-
this.registrations =
|
|
87
|
-
this.singletonCache =
|
|
140
|
+
constructor(registrations, singletonCache) {
|
|
141
|
+
this.registrations = registrations;
|
|
142
|
+
this.singletonCache = singletonCache;
|
|
143
|
+
this.scopedCache = new Map;
|
|
88
144
|
this.resolvingTokens = new Set;
|
|
89
145
|
this[INTERNALS] = {
|
|
90
146
|
isDisposed: () => this.disposed,
|
|
91
147
|
markDisposed: () => {
|
|
92
148
|
this.disposed = true;
|
|
93
149
|
},
|
|
94
|
-
ownCache: this.
|
|
150
|
+
ownCache: this.scopedCache,
|
|
95
151
|
registrations: this.registrations,
|
|
96
152
|
singletonCache: this.singletonCache
|
|
97
153
|
};
|
|
98
154
|
}
|
|
99
|
-
registerSingleton(token, factory) {
|
|
100
|
-
return this.addRegistration(token, factory, "singleton");
|
|
101
|
-
}
|
|
102
|
-
registerTransient(token, factory) {
|
|
103
|
-
return this.addRegistration(token, factory, "transient");
|
|
104
|
-
}
|
|
105
|
-
registerScoped(token, factory) {
|
|
106
|
-
return this.addRegistration(token, factory, "scoped");
|
|
107
|
-
}
|
|
108
|
-
use(source) {
|
|
109
|
-
for (const [token, registrations] of source[INTERNALS].registrations) {
|
|
110
|
-
this.registrations.set(token, [...registrations]);
|
|
111
|
-
}
|
|
112
|
-
return this;
|
|
113
|
-
}
|
|
114
155
|
resolve(token) {
|
|
115
156
|
return this.resolveToken(token, true);
|
|
116
157
|
}
|
|
@@ -125,7 +166,7 @@ class Container {
|
|
|
125
166
|
}
|
|
126
167
|
resolveToken(token, required) {
|
|
127
168
|
if (this.disposed) {
|
|
128
|
-
throw new ContainerError("Cannot resolve from a disposed
|
|
169
|
+
throw new ContainerError("Cannot resolve from a disposed scope.");
|
|
129
170
|
}
|
|
130
171
|
const registrations = this.registrations.get(token);
|
|
131
172
|
if (registrations === undefined || registrations.length === 0) {
|
|
@@ -135,30 +176,42 @@ class Container {
|
|
|
135
176
|
return;
|
|
136
177
|
}
|
|
137
178
|
const registration = registrations[registrations.length - 1];
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
return
|
|
179
|
+
const singletonCached = this.singletonCache.get(registration);
|
|
180
|
+
if (singletonCached !== undefined) {
|
|
181
|
+
return singletonCached;
|
|
182
|
+
}
|
|
183
|
+
if (registration.lifetime === "scoped" && this.singletonDepth > 0) {
|
|
184
|
+
throw new ContainerError(`Captive dependency detected: scoped token "${tokenToString(token)}" cannot be resolved inside a singleton factory. Scoped instances must not be captured by singletons.`);
|
|
141
185
|
}
|
|
142
|
-
|
|
143
|
-
|
|
186
|
+
const scopedCached = this.scopedCache.get(registration);
|
|
187
|
+
if (scopedCached !== undefined) {
|
|
188
|
+
return scopedCached;
|
|
144
189
|
}
|
|
145
190
|
if (this.resolvingTokens.has(token)) {
|
|
146
191
|
throw new ContainerError(`Circular dependency detected: ${buildCircularPath(this.resolvingTokens, token)}`);
|
|
147
192
|
}
|
|
148
193
|
this.resolvingTokens.add(token);
|
|
194
|
+
if (registration.lifetime === "singleton") {
|
|
195
|
+
this.singletonDepth++;
|
|
196
|
+
}
|
|
149
197
|
try {
|
|
150
198
|
const instance = registration.factory(this);
|
|
151
199
|
if (registration.lifetime === "singleton") {
|
|
152
200
|
this.singletonCache.set(registration, instance);
|
|
201
|
+
} else if (registration.lifetime === "scoped") {
|
|
202
|
+
this.scopedCache.set(registration, instance);
|
|
153
203
|
}
|
|
154
204
|
return instance;
|
|
155
205
|
} finally {
|
|
206
|
+
if (registration.lifetime === "singleton") {
|
|
207
|
+
this.singletonDepth--;
|
|
208
|
+
}
|
|
156
209
|
this.resolvingTokens.delete(token);
|
|
157
210
|
}
|
|
158
211
|
}
|
|
159
212
|
resolveAllTokens(token, required) {
|
|
160
213
|
if (this.disposed) {
|
|
161
|
-
throw new ContainerError("Cannot resolve from a disposed
|
|
214
|
+
throw new ContainerError("Cannot resolve from a disposed scope.");
|
|
162
215
|
}
|
|
163
216
|
const registrations = this.registrations.get(token);
|
|
164
217
|
if (registrations === undefined || registrations.length === 0) {
|
|
@@ -174,30 +227,36 @@ class Container {
|
|
|
174
227
|
try {
|
|
175
228
|
return registrations.map((registration) => {
|
|
176
229
|
const reg = registration;
|
|
177
|
-
const
|
|
178
|
-
if (
|
|
179
|
-
return
|
|
230
|
+
const singletonCached = this.singletonCache.get(registration);
|
|
231
|
+
if (singletonCached !== undefined) {
|
|
232
|
+
return singletonCached;
|
|
180
233
|
}
|
|
181
|
-
if (reg.lifetime === "scoped") {
|
|
182
|
-
throw new ContainerError(`
|
|
234
|
+
if (reg.lifetime === "scoped" && this.singletonDepth > 0) {
|
|
235
|
+
throw new ContainerError(`Captive dependency detected: scoped token "${tokenToString(token)}" cannot be resolved inside a singleton factory. Scoped instances must not be captured by singletons.`);
|
|
236
|
+
}
|
|
237
|
+
const scopedCached = this.scopedCache.get(registration);
|
|
238
|
+
if (scopedCached !== undefined) {
|
|
239
|
+
return scopedCached;
|
|
183
240
|
}
|
|
184
|
-
const instance = reg.factory(this);
|
|
185
241
|
if (reg.lifetime === "singleton") {
|
|
186
|
-
this.
|
|
242
|
+
this.singletonDepth++;
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const instance = reg.factory(this);
|
|
246
|
+
if (reg.lifetime === "singleton") {
|
|
247
|
+
this.singletonCache.set(registration, instance);
|
|
248
|
+
} else if (reg.lifetime === "scoped") {
|
|
249
|
+
this.scopedCache.set(registration, instance);
|
|
250
|
+
}
|
|
251
|
+
return instance;
|
|
252
|
+
} finally {
|
|
253
|
+
if (reg.lifetime === "singleton") {
|
|
254
|
+
this.singletonDepth--;
|
|
255
|
+
}
|
|
187
256
|
}
|
|
188
|
-
return instance;
|
|
189
257
|
});
|
|
190
258
|
} finally {
|
|
191
259
|
this.resolvingTokens.delete(token);
|
|
192
260
|
}
|
|
193
261
|
}
|
|
194
|
-
addRegistration(token, factory, lifetime) {
|
|
195
|
-
const existing = this.registrations.get(token);
|
|
196
|
-
if (existing !== undefined) {
|
|
197
|
-
existing.push({ factory, lifetime });
|
|
198
|
-
} else {
|
|
199
|
-
this.registrations.set(token, [{ factory, lifetime }]);
|
|
200
|
-
}
|
|
201
|
-
return this;
|
|
202
|
-
}
|
|
203
262
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export type { DisposableContainer, DisposableScope, disposable } from './disposa
|
|
|
3
3
|
export { ContainerError } from './error';
|
|
4
4
|
export type { lazy } from './lazy';
|
|
5
5
|
export type { Resolver } from './resolver';
|
|
6
|
-
export
|
|
6
|
+
export { createScope, Scope } from './scope';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ContainerError,
|
|
3
|
-
buildCircularPath,
|
|
4
|
-
tokenToString
|
|
5
|
-
} from "./index-g50fxds1.js";
|
|
6
1
|
import {
|
|
7
2
|
INTERNALS
|
|
8
3
|
} from "./index-jx8b52m0.js";
|
|
@@ -15,13 +10,11 @@ function createContainer() {
|
|
|
15
10
|
class Container {
|
|
16
11
|
registrations;
|
|
17
12
|
singletonCache;
|
|
18
|
-
resolvingTokens;
|
|
19
13
|
disposed = false;
|
|
20
14
|
[INTERNALS];
|
|
21
15
|
constructor() {
|
|
22
16
|
this.registrations = new Map;
|
|
23
17
|
this.singletonCache = new Map;
|
|
24
|
-
this.resolvingTokens = new Set;
|
|
25
18
|
this[INTERNALS] = {
|
|
26
19
|
isDisposed: () => this.disposed,
|
|
27
20
|
markDisposed: () => {
|
|
@@ -47,6 +40,80 @@ class Container {
|
|
|
47
40
|
}
|
|
48
41
|
return this;
|
|
49
42
|
}
|
|
43
|
+
addRegistration(token, factory, lifetime) {
|
|
44
|
+
const existing = this.registrations.get(token);
|
|
45
|
+
if (existing !== undefined) {
|
|
46
|
+
existing.push({ factory, lifetime });
|
|
47
|
+
} else {
|
|
48
|
+
this.registrations.set(token, [{ factory, lifetime }]);
|
|
49
|
+
}
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// src/error/index.ts
|
|
54
|
+
class ContainerError extends Error {
|
|
55
|
+
constructor(message) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = "ContainerError";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// src/resolver/index.ts
|
|
61
|
+
function tokenToString(token) {
|
|
62
|
+
if (typeof token === "function") {
|
|
63
|
+
return token.name || "anonymous function";
|
|
64
|
+
}
|
|
65
|
+
if (typeof token === "symbol") {
|
|
66
|
+
return token.toString();
|
|
67
|
+
}
|
|
68
|
+
return String(token);
|
|
69
|
+
}
|
|
70
|
+
function buildCircularPath(resolvingTokens, token) {
|
|
71
|
+
const path = [];
|
|
72
|
+
let found = false;
|
|
73
|
+
for (const t of resolvingTokens) {
|
|
74
|
+
if (t === token) {
|
|
75
|
+
found = true;
|
|
76
|
+
}
|
|
77
|
+
if (found) {
|
|
78
|
+
path.push(tokenToString(t));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
path.push(tokenToString(token));
|
|
82
|
+
return path.join(" -> ");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/scope/index.ts
|
|
86
|
+
function createScope(source) {
|
|
87
|
+
const internals = source[INTERNALS];
|
|
88
|
+
if (internals.isDisposed()) {
|
|
89
|
+
throw new ContainerError("Cannot create a scope from a disposed container.");
|
|
90
|
+
}
|
|
91
|
+
return new Scope(internals.registrations, internals.singletonCache);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
class Scope {
|
|
95
|
+
registrations;
|
|
96
|
+
singletonCache;
|
|
97
|
+
scopedCache;
|
|
98
|
+
resolvingTokens;
|
|
99
|
+
singletonDepth = 0;
|
|
100
|
+
disposed = false;
|
|
101
|
+
[INTERNALS];
|
|
102
|
+
constructor(registrations, singletonCache) {
|
|
103
|
+
this.registrations = registrations;
|
|
104
|
+
this.singletonCache = singletonCache;
|
|
105
|
+
this.scopedCache = new Map;
|
|
106
|
+
this.resolvingTokens = new Set;
|
|
107
|
+
this[INTERNALS] = {
|
|
108
|
+
isDisposed: () => this.disposed,
|
|
109
|
+
markDisposed: () => {
|
|
110
|
+
this.disposed = true;
|
|
111
|
+
},
|
|
112
|
+
ownCache: this.scopedCache,
|
|
113
|
+
registrations: this.registrations,
|
|
114
|
+
singletonCache: this.singletonCache
|
|
115
|
+
};
|
|
116
|
+
}
|
|
50
117
|
resolve(token) {
|
|
51
118
|
return this.resolveToken(token, true);
|
|
52
119
|
}
|
|
@@ -61,7 +128,7 @@ class Container {
|
|
|
61
128
|
}
|
|
62
129
|
resolveToken(token, required) {
|
|
63
130
|
if (this.disposed) {
|
|
64
|
-
throw new ContainerError("Cannot resolve from a disposed
|
|
131
|
+
throw new ContainerError("Cannot resolve from a disposed scope.");
|
|
65
132
|
}
|
|
66
133
|
const registrations = this.registrations.get(token);
|
|
67
134
|
if (registrations === undefined || registrations.length === 0) {
|
|
@@ -71,30 +138,42 @@ class Container {
|
|
|
71
138
|
return;
|
|
72
139
|
}
|
|
73
140
|
const registration = registrations[registrations.length - 1];
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
76
|
-
return
|
|
141
|
+
const singletonCached = this.singletonCache.get(registration);
|
|
142
|
+
if (singletonCached !== undefined) {
|
|
143
|
+
return singletonCached;
|
|
144
|
+
}
|
|
145
|
+
if (registration.lifetime === "scoped" && this.singletonDepth > 0) {
|
|
146
|
+
throw new ContainerError(`Captive dependency detected: scoped token "${tokenToString(token)}" cannot be resolved inside a singleton factory. Scoped instances must not be captured by singletons.`);
|
|
77
147
|
}
|
|
78
|
-
|
|
79
|
-
|
|
148
|
+
const scopedCached = this.scopedCache.get(registration);
|
|
149
|
+
if (scopedCached !== undefined) {
|
|
150
|
+
return scopedCached;
|
|
80
151
|
}
|
|
81
152
|
if (this.resolvingTokens.has(token)) {
|
|
82
153
|
throw new ContainerError(`Circular dependency detected: ${buildCircularPath(this.resolvingTokens, token)}`);
|
|
83
154
|
}
|
|
84
155
|
this.resolvingTokens.add(token);
|
|
156
|
+
if (registration.lifetime === "singleton") {
|
|
157
|
+
this.singletonDepth++;
|
|
158
|
+
}
|
|
85
159
|
try {
|
|
86
160
|
const instance = registration.factory(this);
|
|
87
161
|
if (registration.lifetime === "singleton") {
|
|
88
162
|
this.singletonCache.set(registration, instance);
|
|
163
|
+
} else if (registration.lifetime === "scoped") {
|
|
164
|
+
this.scopedCache.set(registration, instance);
|
|
89
165
|
}
|
|
90
166
|
return instance;
|
|
91
167
|
} finally {
|
|
168
|
+
if (registration.lifetime === "singleton") {
|
|
169
|
+
this.singletonDepth--;
|
|
170
|
+
}
|
|
92
171
|
this.resolvingTokens.delete(token);
|
|
93
172
|
}
|
|
94
173
|
}
|
|
95
174
|
resolveAllTokens(token, required) {
|
|
96
175
|
if (this.disposed) {
|
|
97
|
-
throw new ContainerError("Cannot resolve from a disposed
|
|
176
|
+
throw new ContainerError("Cannot resolve from a disposed scope.");
|
|
98
177
|
}
|
|
99
178
|
const registrations = this.registrations.get(token);
|
|
100
179
|
if (registrations === undefined || registrations.length === 0) {
|
|
@@ -110,35 +189,43 @@ class Container {
|
|
|
110
189
|
try {
|
|
111
190
|
return registrations.map((registration) => {
|
|
112
191
|
const reg = registration;
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
115
|
-
return
|
|
192
|
+
const singletonCached = this.singletonCache.get(registration);
|
|
193
|
+
if (singletonCached !== undefined) {
|
|
194
|
+
return singletonCached;
|
|
195
|
+
}
|
|
196
|
+
if (reg.lifetime === "scoped" && this.singletonDepth > 0) {
|
|
197
|
+
throw new ContainerError(`Captive dependency detected: scoped token "${tokenToString(token)}" cannot be resolved inside a singleton factory. Scoped instances must not be captured by singletons.`);
|
|
116
198
|
}
|
|
117
|
-
|
|
118
|
-
|
|
199
|
+
const scopedCached = this.scopedCache.get(registration);
|
|
200
|
+
if (scopedCached !== undefined) {
|
|
201
|
+
return scopedCached;
|
|
119
202
|
}
|
|
120
|
-
const instance = reg.factory(this);
|
|
121
203
|
if (reg.lifetime === "singleton") {
|
|
122
|
-
this.
|
|
204
|
+
this.singletonDepth++;
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
const instance = reg.factory(this);
|
|
208
|
+
if (reg.lifetime === "singleton") {
|
|
209
|
+
this.singletonCache.set(registration, instance);
|
|
210
|
+
} else if (reg.lifetime === "scoped") {
|
|
211
|
+
this.scopedCache.set(registration, instance);
|
|
212
|
+
}
|
|
213
|
+
return instance;
|
|
214
|
+
} finally {
|
|
215
|
+
if (reg.lifetime === "singleton") {
|
|
216
|
+
this.singletonDepth--;
|
|
217
|
+
}
|
|
123
218
|
}
|
|
124
|
-
return instance;
|
|
125
219
|
});
|
|
126
220
|
} finally {
|
|
127
221
|
this.resolvingTokens.delete(token);
|
|
128
222
|
}
|
|
129
223
|
}
|
|
130
|
-
addRegistration(token, factory, lifetime) {
|
|
131
|
-
const existing = this.registrations.get(token);
|
|
132
|
-
if (existing !== undefined) {
|
|
133
|
-
existing.push({ factory, lifetime });
|
|
134
|
-
} else {
|
|
135
|
-
this.registrations.set(token, [{ factory, lifetime }]);
|
|
136
|
-
}
|
|
137
|
-
return this;
|
|
138
|
-
}
|
|
139
224
|
}
|
|
140
225
|
export {
|
|
226
|
+
createScope,
|
|
141
227
|
createContainer,
|
|
228
|
+
Scope,
|
|
142
229
|
ContainerError,
|
|
143
230
|
Container
|
|
144
231
|
};
|
package/dist/lazy/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { DisposableContainer, DisposableScope } from '../disposable';
|
|
1
|
+
import type { DisposableScope } from '../disposable';
|
|
3
2
|
import type { AbstractConstructor } from '../resolver';
|
|
4
3
|
import type { Scope } from '../scope';
|
|
5
4
|
/**
|
|
@@ -12,24 +11,23 @@ import type { Scope } from '../scope';
|
|
|
12
11
|
* Only **sync class tokens** are supported. Async tokens and PropertyKey tokens
|
|
13
12
|
* are rejected at the type level.
|
|
14
13
|
*
|
|
15
|
-
* @param source A
|
|
14
|
+
* @param source A Scope or DisposableScope
|
|
16
15
|
* @param token A sync class constructor token
|
|
17
16
|
* @returns A proxy that transparently forwards to the lazily-resolved instance
|
|
18
17
|
*
|
|
19
18
|
* @example
|
|
20
19
|
* ```ts
|
|
21
|
-
* import { createContainer } from 'katagami';
|
|
20
|
+
* import { createContainer, createScope } from 'katagami';
|
|
22
21
|
* import { lazy } from 'katagami/lazy';
|
|
23
22
|
*
|
|
24
23
|
* const container = createContainer()
|
|
25
24
|
* .registerSingleton(HeavyService, () => new HeavyService());
|
|
26
25
|
*
|
|
27
|
-
* const
|
|
26
|
+
* const scope = createScope(container);
|
|
27
|
+
* const service = lazy(scope, HeavyService);
|
|
28
28
|
* // Instance is NOT created yet
|
|
29
29
|
* service.doSomething(); // resolved here, then cached
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
|
-
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: Container<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & Sync): V;
|
|
33
32
|
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & (Sync | ScopedSync)): V;
|
|
34
|
-
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: DisposableContainer<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & Sync): V;
|
|
35
33
|
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: DisposableScope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & (Sync | ScopedSync)): V;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "katagami",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Lightweight DI container for TypeScript and JavaScript — full type inference, no decorators, no reflect-metadata, hybrid class & PropertyKey tokens.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -11,11 +11,6 @@
|
|
|
11
11
|
"import": "./dist/index.js",
|
|
12
12
|
"require": "./dist/index.cjs"
|
|
13
13
|
},
|
|
14
|
-
"./scope": {
|
|
15
|
-
"types": "./dist/scope/index.d.ts",
|
|
16
|
-
"import": "./dist/scope/index.js",
|
|
17
|
-
"require": "./dist/scope/index.cjs"
|
|
18
|
-
},
|
|
19
14
|
"./disposable": {
|
|
20
15
|
"types": "./dist/disposable/index.d.ts",
|
|
21
16
|
"import": "./dist/disposable/index.js",
|
|
@@ -50,8 +45,8 @@
|
|
|
50
45
|
"clean": "rm -rf dist",
|
|
51
46
|
"build": "bun run clean && bun run build:types && bun run build:esm && bun run build:cjs",
|
|
52
47
|
"build:types": "tsc -p tsconfig.build.json",
|
|
53
|
-
"build:esm": "bun build ./src/index.ts ./src/
|
|
54
|
-
"build:cjs": "bun build ./src/index.ts --outfile dist/index.cjs --format cjs && bun build ./src/
|
|
48
|
+
"build:esm": "bun build ./src/index.ts ./src/disposable/index.ts ./src/lazy/index.ts --outdir dist --format esm --splitting",
|
|
49
|
+
"build:cjs": "bun build ./src/index.ts --outfile dist/index.cjs --format cjs && bun build ./src/disposable/index.ts --outfile dist/disposable/index.cjs --format cjs && bun build ./src/lazy/index.ts --outfile dist/lazy/index.cjs --format cjs",
|
|
55
50
|
"prepublishOnly": "bun run build",
|
|
56
51
|
"check": "bun run format",
|
|
57
52
|
"lint": "biome lint .",
|
package/dist/index-g50fxds1.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// src/error/index.ts
|
|
2
|
-
class ContainerError extends Error {
|
|
3
|
-
constructor(message) {
|
|
4
|
-
super(message);
|
|
5
|
-
this.name = "ContainerError";
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// src/resolver/index.ts
|
|
10
|
-
function tokenToString(token) {
|
|
11
|
-
if (typeof token === "function") {
|
|
12
|
-
return token.name || "anonymous function";
|
|
13
|
-
}
|
|
14
|
-
if (typeof token === "symbol") {
|
|
15
|
-
return token.toString();
|
|
16
|
-
}
|
|
17
|
-
return String(token);
|
|
18
|
-
}
|
|
19
|
-
function buildCircularPath(resolvingTokens, token) {
|
|
20
|
-
const path = [];
|
|
21
|
-
let found = false;
|
|
22
|
-
for (const t of resolvingTokens) {
|
|
23
|
-
if (t === token) {
|
|
24
|
-
found = true;
|
|
25
|
-
}
|
|
26
|
-
if (found) {
|
|
27
|
-
path.push(tokenToString(t));
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
path.push(tokenToString(token));
|
|
31
|
-
return path.join(" -> ");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export { ContainerError, tokenToString, buildCircularPath };
|