proxydi 0.0.12 → 0.1.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/CHANGELOG.md +107 -91
- package/LICENSE +21 -21
- package/README.md +358 -358
- package/dist/ProxyDI.d.ts +27 -0
- package/dist/ProxyDiContainer.d.ts +7 -3
- package/dist/ProxyFactory.d.ts +8 -0
- package/dist/__tests__/TestableProxyDiContainer.mock.d.ts +5 -0
- package/dist/__tests__/mock/King.d.ts +6 -0
- package/dist/__tests__/mock/Queen.d.ts +6 -0
- package/dist/autoInjectable.d.ts +3 -3
- package/dist/autoInjectableService.d.ts +13 -0
- package/dist/index.cjs +150 -104
- package/dist/index.d.ts +4 -4
- package/dist/index.js +150 -104
- package/dist/index.umd.js +150 -104
- package/dist/inject.decorator.d.ts +10 -0
- package/dist/injectable.d.ts +3 -17
- package/dist/injectable.decorator.d.ts +17 -0
- package/dist/makeDependencyProxy.d.ts +2 -0
- package/dist/makeInjectionProxy.d.ts +9 -0
- package/dist/middleware/MiddlewaresManager.d.ts +13 -0
- package/dist/middleware/middleware.api.d.ts +27 -0
- package/package.json +59 -59
- package/dist/middleware/MiddlewareListener.d.ts +0 -29
- /package/dist/{proxy.constuctor.d.ts → makeConstructorDependencyProxy.d.ts} +0 -0
- /package/dist/middleware/{middleware.d.ts → middleware.decorator.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
const injectableClasses = {};
|
|
2
|
+
const constructorInjections = {};
|
|
3
|
+
function injectable(dependencyOrDependencies, autoInjecions) {
|
|
4
|
+
return function (value, context) {
|
|
5
|
+
if ((context === null || context === undefined ? undefined : context.kind) !== 'class') {
|
|
6
|
+
throw new Error('@injectable decorator should decorate classes');
|
|
7
|
+
}
|
|
8
|
+
const name = dependencyOrDependencies
|
|
9
|
+
? Array.isArray(dependencyOrDependencies)
|
|
10
|
+
? context.name
|
|
11
|
+
: dependencyOrDependencies
|
|
12
|
+
: context.name;
|
|
13
|
+
const injectToConstructor = dependencyOrDependencies
|
|
14
|
+
? Array.isArray(dependencyOrDependencies)
|
|
15
|
+
? dependencyOrDependencies
|
|
16
|
+
: autoInjecions
|
|
17
|
+
: autoInjecions;
|
|
18
|
+
if (injectableClasses[name]) {
|
|
19
|
+
throw new Error(`ProxyDi has already regisered dependency ${String(name)} by @injectable`);
|
|
20
|
+
}
|
|
21
|
+
injectableClasses[name] = value;
|
|
22
|
+
if (injectToConstructor) {
|
|
23
|
+
constructorInjections[name] = injectToConstructor;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function findInjectableId(injectable) {
|
|
28
|
+
for (const [id, DependencyClass] of Object.entries(injectableClasses)) {
|
|
29
|
+
if (DependencyClass === injectable) {
|
|
30
|
+
return id;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`Class is not @injectable: ${injectable.name}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
1
36
|
const INJECTIONS = Symbol('injections');
|
|
2
37
|
/**
|
|
3
38
|
* This symbol constant defines a property name.
|
|
@@ -26,7 +61,11 @@ const IS_INSTANCE_PROXY = Symbol('isInstanceProxy');
|
|
|
26
61
|
const inject = (dependencyId) => {
|
|
27
62
|
return function (_value, context) {
|
|
28
63
|
if ((context === null || context === undefined ? undefined : context.kind) === 'field') {
|
|
29
|
-
const id = dependencyId
|
|
64
|
+
const id = dependencyId
|
|
65
|
+
? typeof dependencyId === 'function'
|
|
66
|
+
? findInjectableId(dependencyId)
|
|
67
|
+
: dependencyId
|
|
68
|
+
: context.name;
|
|
30
69
|
const injection = {
|
|
31
70
|
property: context.name,
|
|
32
71
|
dependencyId: id,
|
|
@@ -45,41 +84,6 @@ const inject = (dependencyId) => {
|
|
|
45
84
|
};
|
|
46
85
|
};
|
|
47
86
|
|
|
48
|
-
const injectableClasses = {};
|
|
49
|
-
const constructorInjections = {};
|
|
50
|
-
function injectable(dependencyOrDependencies, autoInjecions) {
|
|
51
|
-
return function (value, context) {
|
|
52
|
-
if ((context === null || context === undefined ? undefined : context.kind) !== 'class') {
|
|
53
|
-
throw new Error('@injectable decorator should decorate classes');
|
|
54
|
-
}
|
|
55
|
-
const name = dependencyOrDependencies
|
|
56
|
-
? Array.isArray(dependencyOrDependencies)
|
|
57
|
-
? context.name
|
|
58
|
-
: dependencyOrDependencies
|
|
59
|
-
: context.name;
|
|
60
|
-
const injectToConstructor = dependencyOrDependencies
|
|
61
|
-
? Array.isArray(dependencyOrDependencies)
|
|
62
|
-
? dependencyOrDependencies
|
|
63
|
-
: autoInjecions
|
|
64
|
-
: autoInjecions;
|
|
65
|
-
if (injectableClasses[name]) {
|
|
66
|
-
throw new Error(`ProxyDi has already regisered dependency ${String(name)} by @injectable`);
|
|
67
|
-
}
|
|
68
|
-
injectableClasses[name] = value;
|
|
69
|
-
if (injectToConstructor) {
|
|
70
|
-
constructorInjections[name] = injectToConstructor;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
function findInjectableId(injectable) {
|
|
75
|
-
for (const [id, DependencyClass] of Object.entries(injectableClasses)) {
|
|
76
|
-
if (DependencyClass === injectable) {
|
|
77
|
-
return id;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
throw new Error(`Class is not @injectable: ${injectable.name}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
87
|
const DEFAULT_SETTINGS = {
|
|
84
88
|
allowRegisterAnything: false,
|
|
85
89
|
allowRewriteDependencies: false,
|
|
@@ -126,6 +130,7 @@ const makeInjectionProxy = (injection, injectionOwner, container) => {
|
|
|
126
130
|
},
|
|
127
131
|
});
|
|
128
132
|
};
|
|
133
|
+
|
|
129
134
|
function makeDependencyProxy(dependency) {
|
|
130
135
|
const injectionValues = {};
|
|
131
136
|
return new Proxy(dependency, {
|
|
@@ -146,18 +151,9 @@ function makeDependencyProxy(dependency) {
|
|
|
146
151
|
}
|
|
147
152
|
|
|
148
153
|
function makeConstructorDependencyProxy(container, dependencyId) {
|
|
149
|
-
// let values: Record<string | symbol, any> = {};
|
|
150
|
-
// let wasResolved = false;
|
|
151
154
|
function getDependency() {
|
|
152
155
|
if (container.isKnown(dependencyId)) {
|
|
153
156
|
const dependency = container.resolve(dependencyId);
|
|
154
|
-
// if (!wasResolved) {
|
|
155
|
-
// for (const key in values) {
|
|
156
|
-
// dependency[key] = values[key];
|
|
157
|
-
// }
|
|
158
|
-
// values = {};
|
|
159
|
-
// wasResolved = true;
|
|
160
|
-
// }
|
|
161
157
|
return dependency;
|
|
162
158
|
}
|
|
163
159
|
else {
|
|
@@ -166,20 +162,12 @@ function makeConstructorDependencyProxy(container, dependencyId) {
|
|
|
166
162
|
}
|
|
167
163
|
return new Proxy({}, {
|
|
168
164
|
get: function (target, prop, receiver) {
|
|
169
|
-
// if (values[prop]) {
|
|
170
|
-
// return values[prop];
|
|
171
|
-
// }
|
|
172
165
|
const dependency = getDependency();
|
|
173
166
|
return Reflect.get(dependency, prop, receiver);
|
|
174
167
|
},
|
|
175
168
|
set: function (_target, prop, value) {
|
|
176
|
-
// if (!container.isKnown(dependencyId)) {
|
|
177
|
-
// values[prop] = value;
|
|
178
|
-
// return true;
|
|
179
|
-
// } else {
|
|
180
169
|
const dependency = getDependency();
|
|
181
170
|
return Reflect.set(dependency, prop, value);
|
|
182
|
-
//}
|
|
183
171
|
},
|
|
184
172
|
has: function (_target, prop) {
|
|
185
173
|
const dependency = getDependency();
|
|
@@ -202,56 +190,73 @@ function middleware() {
|
|
|
202
190
|
};
|
|
203
191
|
}
|
|
204
192
|
|
|
205
|
-
class
|
|
193
|
+
class MiddlewareManager {
|
|
206
194
|
constructor(parent) {
|
|
207
195
|
this.parent = parent;
|
|
208
|
-
this.
|
|
196
|
+
this.handlers = {
|
|
209
197
|
register: [],
|
|
210
198
|
remove: [],
|
|
199
|
+
resolve: [],
|
|
211
200
|
};
|
|
212
201
|
}
|
|
213
202
|
add(middleware) {
|
|
214
|
-
if (
|
|
203
|
+
if (isRegistrator(middleware)) {
|
|
215
204
|
middleware.onRegister && this.on('register', middleware.onRegister);
|
|
216
205
|
}
|
|
217
|
-
if (
|
|
206
|
+
if (isRemover(middleware)) {
|
|
218
207
|
middleware.onRemove && this.on('remove', middleware.onRemove);
|
|
219
208
|
}
|
|
209
|
+
if (isResolver(middleware)) {
|
|
210
|
+
middleware.onResolve && this.on('resolve', middleware.onResolve);
|
|
211
|
+
}
|
|
220
212
|
}
|
|
221
213
|
remove(middleware) {
|
|
222
|
-
if (
|
|
214
|
+
if (isRegistrator(middleware)) {
|
|
223
215
|
middleware.onRegister &&
|
|
224
216
|
this.off('register', middleware.onRegister);
|
|
225
217
|
}
|
|
226
|
-
if (
|
|
218
|
+
if (isRemover(middleware)) {
|
|
227
219
|
middleware.onRemove && this.off('remove', middleware.onRemove);
|
|
228
220
|
}
|
|
221
|
+
if (isResolver(middleware)) {
|
|
222
|
+
middleware.onResolve && this.off('resolve', middleware.onResolve);
|
|
223
|
+
}
|
|
229
224
|
}
|
|
230
225
|
on(event, listener) {
|
|
231
|
-
this.
|
|
226
|
+
this.handlers[event].push(listener);
|
|
232
227
|
}
|
|
233
|
-
onRegister(
|
|
228
|
+
onRegister(context) {
|
|
234
229
|
var _a;
|
|
235
|
-
this.
|
|
236
|
-
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRegister(
|
|
230
|
+
this.handlers.register.forEach((listener) => listener(context));
|
|
231
|
+
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRegister(context);
|
|
237
232
|
}
|
|
238
|
-
onRemove(
|
|
233
|
+
onRemove(context) {
|
|
239
234
|
var _a;
|
|
240
|
-
this.
|
|
241
|
-
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRemove(
|
|
235
|
+
this.handlers.remove.forEach((listener) => listener(context));
|
|
236
|
+
(_a = this.parent) === null || _a === undefined ? undefined : _a.onRemove(context);
|
|
237
|
+
}
|
|
238
|
+
onResolve(context) {
|
|
239
|
+
let result = context;
|
|
240
|
+
this.handlers.resolve.forEach((listener) => {
|
|
241
|
+
result = listener(result);
|
|
242
|
+
});
|
|
243
|
+
return result;
|
|
242
244
|
}
|
|
243
245
|
off(event, listener) {
|
|
244
|
-
const index = this.
|
|
246
|
+
const index = this.handlers[event].indexOf(listener);
|
|
245
247
|
if (index !== -1) {
|
|
246
|
-
this.
|
|
248
|
+
this.handlers[event].splice(index, 1);
|
|
247
249
|
}
|
|
248
250
|
}
|
|
249
251
|
}
|
|
250
|
-
function
|
|
251
|
-
return middleware.onRegister;
|
|
252
|
+
function isRegistrator(middleware) {
|
|
253
|
+
return !!middleware.onRegister;
|
|
252
254
|
}
|
|
253
|
-
function
|
|
254
|
-
return middleware.onRemove;
|
|
255
|
+
function isRemover(middleware) {
|
|
256
|
+
return !!middleware.onRemove;
|
|
257
|
+
}
|
|
258
|
+
function isResolver(middleware) {
|
|
259
|
+
return !!middleware.onResolve;
|
|
255
260
|
}
|
|
256
261
|
|
|
257
262
|
/**
|
|
@@ -272,26 +277,63 @@ class ProxyDiContainer {
|
|
|
272
277
|
/**
|
|
273
278
|
* Holds proxies for dependencies registered in parent containers to provide for it dependencies from this container
|
|
274
279
|
*/
|
|
275
|
-
this.
|
|
280
|
+
this.inContextProxies = {};
|
|
281
|
+
this.resolveImpl = (dependencyId) => {
|
|
282
|
+
const proxy = this.inContextProxies[dependencyId];
|
|
283
|
+
if (proxy) {
|
|
284
|
+
return proxy;
|
|
285
|
+
}
|
|
286
|
+
const instance = this.findDependency(dependencyId);
|
|
287
|
+
if (instance) {
|
|
288
|
+
if (instance[PROXYDI_CONTAINER] !== this &&
|
|
289
|
+
typeof instance === 'object' &&
|
|
290
|
+
this.settings.resolveInContainerContext) {
|
|
291
|
+
const proxy = makeDependencyProxy(instance);
|
|
292
|
+
this.injectDependenciesTo(proxy);
|
|
293
|
+
this.inContextProxies[dependencyId] = proxy;
|
|
294
|
+
return proxy;
|
|
295
|
+
}
|
|
296
|
+
return instance;
|
|
297
|
+
}
|
|
298
|
+
const InjectableClass = injectableClasses[dependencyId];
|
|
299
|
+
return this.register(InjectableClass, dependencyId);
|
|
300
|
+
};
|
|
276
301
|
this.id = ProxyDiContainer.idCounter++;
|
|
277
|
-
this.
|
|
302
|
+
this.middlewareManager = new MiddlewareManager(parent === null || parent === undefined ? undefined : parent.middlewareManager);
|
|
278
303
|
if (parent) {
|
|
279
304
|
this.parent = parent;
|
|
280
305
|
this.parent.addChild(this);
|
|
281
306
|
}
|
|
282
307
|
this.settings = Object.assign(Object.assign({}, DEFAULT_SETTINGS), settings);
|
|
283
308
|
}
|
|
284
|
-
|
|
309
|
+
registerMiddleware(middleware) {
|
|
310
|
+
this.middlewareManager.add(middleware);
|
|
311
|
+
}
|
|
312
|
+
removeMiddleware(middleware) {
|
|
313
|
+
this.middlewareManager.remove(middleware);
|
|
314
|
+
}
|
|
315
|
+
register(dependency, dependecyId) {
|
|
285
316
|
var _a;
|
|
286
|
-
|
|
317
|
+
let id = dependecyId;
|
|
318
|
+
if (!id) {
|
|
319
|
+
if (typeof dependency === 'function') {
|
|
320
|
+
try {
|
|
321
|
+
id = findInjectableId(dependency);
|
|
322
|
+
}
|
|
323
|
+
catch (_b) {
|
|
324
|
+
id = dependency.name;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (this.dependencies[id]) {
|
|
287
329
|
if (!this.settings.allowRewriteDependencies) {
|
|
288
|
-
throw new Error(`ProxyDi already has dependency for ${String(
|
|
330
|
+
throw new Error(`ProxyDi already has dependency for ${String(id)}`);
|
|
289
331
|
}
|
|
290
332
|
}
|
|
291
333
|
let instance;
|
|
292
334
|
const isClass = typeof dependency === 'function';
|
|
293
335
|
if (isClass) {
|
|
294
|
-
instance = this.createInstance(dependency,
|
|
336
|
+
instance = this.createInstance(dependency, id);
|
|
295
337
|
}
|
|
296
338
|
else {
|
|
297
339
|
instance = dependency;
|
|
@@ -302,15 +344,20 @@ class ProxyDiContainer {
|
|
|
302
344
|
}
|
|
303
345
|
if (isObject) {
|
|
304
346
|
instance[PROXYDI_CONTAINER] = this;
|
|
305
|
-
instance[DEPENDENCY_ID] =
|
|
347
|
+
instance[DEPENDENCY_ID] = id;
|
|
306
348
|
}
|
|
307
349
|
this.injectDependenciesTo(instance);
|
|
308
|
-
this.dependencies[
|
|
350
|
+
this.dependencies[id] = instance;
|
|
309
351
|
const constructorName = (_a = instance.constructor) === null || _a === undefined ? undefined : _a.name;
|
|
310
352
|
if (constructorName && middlewaresClasses[constructorName]) {
|
|
311
|
-
this.
|
|
353
|
+
this.middlewareManager.add(instance);
|
|
312
354
|
}
|
|
313
|
-
|
|
355
|
+
let context = {
|
|
356
|
+
container: this,
|
|
357
|
+
dependencyId: id,
|
|
358
|
+
dependency: instance,
|
|
359
|
+
};
|
|
360
|
+
this.middlewareManager.onRegister(context);
|
|
314
361
|
return instance;
|
|
315
362
|
}
|
|
316
363
|
createInstance(Dependency, dependencyId) {
|
|
@@ -328,37 +375,32 @@ class ProxyDiContainer {
|
|
|
328
375
|
* @returns True if the dependency is known, false otherwise.
|
|
329
376
|
*/
|
|
330
377
|
isKnown(dependencyId) {
|
|
331
|
-
return !!(this.
|
|
378
|
+
return !!(this.inContextProxies[dependencyId] ||
|
|
332
379
|
this.dependencies[dependencyId] ||
|
|
333
380
|
(this.parent && this.parent.isKnown(dependencyId)) ||
|
|
334
381
|
injectableClasses[dependencyId]);
|
|
335
382
|
}
|
|
336
383
|
resolve(dependency) {
|
|
337
384
|
if (typeof dependency === 'function') {
|
|
338
|
-
|
|
385
|
+
let id;
|
|
386
|
+
try {
|
|
387
|
+
id = findInjectableId(dependency);
|
|
388
|
+
}
|
|
389
|
+
catch (_a) {
|
|
390
|
+
id = dependency.name;
|
|
391
|
+
}
|
|
339
392
|
return this.resolve(id);
|
|
340
393
|
}
|
|
341
394
|
if (!this.isKnown(dependency)) {
|
|
342
395
|
throw new Error(`Can't resolve unknown dependency: ${String(dependency)}`);
|
|
343
396
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
typeof instance === 'object' &&
|
|
352
|
-
this.settings.resolveInContainerContext) {
|
|
353
|
-
const proxy = makeDependencyProxy(instance);
|
|
354
|
-
this.injectDependenciesTo(proxy);
|
|
355
|
-
this.parentDependencyProxies[dependency] = proxy;
|
|
356
|
-
return proxy;
|
|
357
|
-
}
|
|
358
|
-
return instance;
|
|
359
|
-
}
|
|
360
|
-
const InjectableClass = injectableClasses[dependency];
|
|
361
|
-
return this.register(InjectableClass, dependency);
|
|
397
|
+
let context = {
|
|
398
|
+
container: this,
|
|
399
|
+
dependencyId: dependency,
|
|
400
|
+
dependency: this.resolveImpl(dependency),
|
|
401
|
+
};
|
|
402
|
+
context = this.middlewareManager.onResolve(context);
|
|
403
|
+
return context.dependency;
|
|
362
404
|
}
|
|
363
405
|
/**
|
|
364
406
|
* Injects dependencies to the given object based on its defined injections metadata. Does not affect the container.
|
|
@@ -418,7 +460,7 @@ class ProxyDiContainer {
|
|
|
418
460
|
if (dependency) {
|
|
419
461
|
const constructorName = (_a = dependency.constructor) === null || _a === undefined ? undefined : _a.name;
|
|
420
462
|
if (constructorName && middlewaresClasses[constructorName]) {
|
|
421
|
-
this.
|
|
463
|
+
this.middlewareManager.remove(dependency);
|
|
422
464
|
}
|
|
423
465
|
const dependencyInjects = dependency[INJECTIONS]
|
|
424
466
|
? dependency[INJECTIONS]
|
|
@@ -428,7 +470,11 @@ class ProxyDiContainer {
|
|
|
428
470
|
});
|
|
429
471
|
delete dependency[DEPENDENCY_ID];
|
|
430
472
|
delete this.dependencies[id];
|
|
431
|
-
this.
|
|
473
|
+
this.middlewareManager.onRemove({
|
|
474
|
+
container: this,
|
|
475
|
+
dependencyId: id,
|
|
476
|
+
dependency,
|
|
477
|
+
});
|
|
432
478
|
}
|
|
433
479
|
}
|
|
434
480
|
/**
|