proxydi 0.0.3 → 0.0.4
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/dist/Proxy.utils.d.ts +3 -0
- package/dist/ProxyDI.d.ts +11 -16
- package/dist/index.cjs +149 -132
- package/dist/index.d.ts +1 -0
- package/dist/index.js +149 -133
- package/dist/index.umd.js +149 -132
- package/dist/inject.d.ts +0 -1
- package/dist/presets.d.ts +3 -0
- package/dist/types.d.ts +32 -2
- package/package.json +1 -1
package/dist/ProxyDI.d.ts
CHANGED
|
@@ -1,32 +1,27 @@
|
|
|
1
|
+
import { ProxyDI as IProxyDI, ProxydiedInstance } from './types';
|
|
1
2
|
import { ProxyDISettings, ServiceClass, ServiceId } from './types';
|
|
2
|
-
export declare
|
|
3
|
-
export declare const PROXYDI_ID: unique symbol;
|
|
4
|
-
export declare class ProxyDI {
|
|
3
|
+
export declare class ProxyDI implements IProxyDI {
|
|
5
4
|
private static idCounter;
|
|
6
5
|
readonly id: number;
|
|
7
6
|
readonly parent?: ProxyDI;
|
|
8
7
|
private children;
|
|
9
|
-
private
|
|
10
|
-
private
|
|
11
|
-
private
|
|
12
|
-
|
|
13
|
-
protected allowRewriteClasses: boolean;
|
|
14
|
-
protected allowRewriteInstances: boolean;
|
|
15
|
-
constructor(settings?: ProxyDISettings);
|
|
8
|
+
private serviceInstances;
|
|
9
|
+
private serviceClasses;
|
|
10
|
+
private settings;
|
|
11
|
+
constructor(settings?: ProxyDISettings, parent?: ProxyDI);
|
|
16
12
|
registerInstance<T>(serviceId: ServiceId, instance: T extends {
|
|
17
13
|
new (...args: any[]): any;
|
|
18
14
|
} ? never : T): void;
|
|
19
15
|
registerClass<T>(serviceId: ServiceId, serviceClass: ServiceClass<T>): void;
|
|
20
|
-
private findInstance;
|
|
21
16
|
isKnown(serviceId: ServiceId): boolean;
|
|
22
17
|
resolve<T>(serviceId: ServiceId): T;
|
|
23
|
-
private findDefiner;
|
|
24
18
|
injectDependencies(instance: any): void;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
removeInstance(serviceId: ServiceId): void;
|
|
19
|
+
createChildContainer(): ProxyDI;
|
|
20
|
+
removeInstance(serviceId: ServiceId | ProxydiedInstance): void;
|
|
28
21
|
removeClass(serviceId: ServiceId): void;
|
|
29
22
|
destroy(): void;
|
|
30
|
-
|
|
23
|
+
private findInstance;
|
|
24
|
+
private findServiceClass;
|
|
25
|
+
private addChild;
|
|
31
26
|
private removeChild;
|
|
32
27
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -1,122 +1,119 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const INJECTS = Symbol('injects');
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const PROXYDI = Symbol('ProxyDI');
|
|
5
|
+
const SERVICE_ID = Symbol('ServiceId');
|
|
6
|
+
const IS_PROXY = Symbol('isProxy');
|
|
7
|
+
const INSTANCE = Symbol('instance');
|
|
8
|
+
|
|
9
|
+
const injectableClasses = {};
|
|
10
|
+
const injectable = (serviceId) => {
|
|
11
|
+
return function (value, context) {
|
|
12
|
+
if ((context === null || context === undefined ? undefined : context.kind) === 'class') {
|
|
7
13
|
const name = serviceId ? serviceId : context.name;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
this[INJECTS] = [];
|
|
16
|
-
}
|
|
17
|
-
this[INJECTS].push(inject);
|
|
18
|
-
});
|
|
14
|
+
if (injectableClasses[name]) {
|
|
15
|
+
throw new Error(`ProxyDI injectable classes already has service ID: ${name}`);
|
|
16
|
+
}
|
|
17
|
+
injectableClasses[name] = value;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
throw new Error('@injectable decorator should decorate classes');
|
|
19
21
|
}
|
|
20
22
|
};
|
|
21
23
|
};
|
|
22
24
|
|
|
23
|
-
const
|
|
25
|
+
const DEFAULT_SETTINGS = {
|
|
26
|
+
allowRegisterAnythingAsInstance: false,
|
|
27
|
+
allowRewriteClasses: false,
|
|
28
|
+
allowRewriteInstances: false,
|
|
29
|
+
};
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
class
|
|
27
|
-
constructor(
|
|
28
|
-
this
|
|
29
|
-
|
|
30
|
-
makeProxy(serviceId) {
|
|
31
|
-
const self = this;
|
|
32
|
-
const proxy = new Proxy({ [IS_PROXY]: true }, {
|
|
33
|
-
get: function (target, prop, receiver) {
|
|
34
|
-
if (target[prop]) {
|
|
35
|
-
return target[prop];
|
|
36
|
-
}
|
|
37
|
-
if (self.container.isKnown(serviceId)) {
|
|
38
|
-
const instance = self.container.resolve(serviceId);
|
|
39
|
-
return Reflect.get(instance, prop, receiver);
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
set: function (target, prop, value) {
|
|
46
|
-
if (self.container.isKnown(serviceId)) {
|
|
47
|
-
const instance = self.container.resolve(serviceId);
|
|
48
|
-
return Reflect.set(instance, prop, value);
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
has: function (target, prop) {
|
|
55
|
-
if (self.container.isKnown(serviceId)) {
|
|
56
|
-
const instance = self.container.resolve(serviceId);
|
|
57
|
-
return Reflect.has(instance, prop);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
return proxy;
|
|
31
|
+
var _a;
|
|
32
|
+
class InstanceProxy {
|
|
33
|
+
constructor(instance) {
|
|
34
|
+
this[_a] = true;
|
|
35
|
+
this[INSTANCE] = instance;
|
|
65
36
|
}
|
|
66
37
|
}
|
|
38
|
+
_a = IS_PROXY;
|
|
39
|
+
const makeProxy = (serviceId, instance) => {
|
|
40
|
+
return new Proxy(new InstanceProxy(instance), {
|
|
41
|
+
get: function (target, prop, receiver) {
|
|
42
|
+
if (target[prop]) {
|
|
43
|
+
return target[prop];
|
|
44
|
+
}
|
|
45
|
+
const container = target[INSTANCE][PROXYDI];
|
|
46
|
+
if (container.isKnown(serviceId)) {
|
|
47
|
+
const instance = container.resolve(serviceId);
|
|
48
|
+
return Reflect.get(instance, prop, receiver);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
set: function (target, prop, value) {
|
|
55
|
+
const container = target[INSTANCE][PROXYDI];
|
|
56
|
+
if (container.isKnown(serviceId)) {
|
|
57
|
+
const instance = container.resolve(serviceId);
|
|
58
|
+
return Reflect.set(instance, prop, value);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
has: function (target, prop) {
|
|
65
|
+
const container = target[INSTANCE][PROXYDI];
|
|
66
|
+
if (container.isKnown(serviceId)) {
|
|
67
|
+
const instance = container.resolve(serviceId);
|
|
68
|
+
return Reflect.has(instance, prop);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
};
|
|
67
76
|
|
|
68
|
-
const PROXYDI = Symbol('ProxyDI');
|
|
69
|
-
const PROXYDI_ID = Symbol('ProxyDI_ID');
|
|
70
77
|
class ProxyDI {
|
|
71
|
-
constructor(settings) {
|
|
78
|
+
constructor(settings, parent) {
|
|
72
79
|
this.children = {};
|
|
73
|
-
this.
|
|
74
|
-
this.
|
|
75
|
-
this.proxies = {};
|
|
76
|
-
this.allowRewriteClasses = false;
|
|
77
|
-
this.allowRewriteInstances = false;
|
|
78
|
-
this.proxyFactory = new ProxyFactory(this);
|
|
80
|
+
this.serviceInstances = {};
|
|
81
|
+
this.serviceClasses = {};
|
|
79
82
|
this.id = ProxyDI.idCounter++;
|
|
80
|
-
if (
|
|
81
|
-
this.parent =
|
|
83
|
+
if (parent) {
|
|
84
|
+
this.parent = parent;
|
|
82
85
|
this.parent.addChild(this);
|
|
83
86
|
}
|
|
84
|
-
|
|
85
|
-
this.allowRewriteClasses = settings.allowRewriteClasses;
|
|
86
|
-
}
|
|
87
|
-
if ((settings === null || settings === undefined ? undefined : settings.allowRewriteInstances) !== undefined) {
|
|
88
|
-
this.allowRewriteInstances = settings.allowRewriteInstances;
|
|
89
|
-
}
|
|
87
|
+
this.settings = Object.assign(Object.assign({}, DEFAULT_SETTINGS), settings);
|
|
90
88
|
}
|
|
91
89
|
registerInstance(serviceId, instance) {
|
|
92
|
-
if (this.
|
|
93
|
-
if (!this.allowRewriteInstances) {
|
|
90
|
+
if (this.serviceInstances[serviceId]) {
|
|
91
|
+
if (!this.settings.allowRewriteInstances) {
|
|
94
92
|
throw new Error(`ProxyDI already has registered instance for ${serviceId}`);
|
|
95
93
|
}
|
|
96
94
|
}
|
|
95
|
+
const isObject = typeof instance === 'object';
|
|
96
|
+
if (!isObject && !this.settings.allowRegisterAnythingAsInstance) {
|
|
97
|
+
throw new Error(`Can't register as instance (allowRegisterAnythingAsInstance is off for this ProxyDI contatiner): ${instance}`);
|
|
98
|
+
}
|
|
97
99
|
this.injectDependencies(instance);
|
|
98
|
-
if (
|
|
99
|
-
instance[
|
|
100
|
+
if (isObject) {
|
|
101
|
+
instance[SERVICE_ID] = serviceId;
|
|
100
102
|
}
|
|
101
|
-
this.
|
|
103
|
+
this.serviceInstances[serviceId] = instance;
|
|
102
104
|
}
|
|
103
105
|
registerClass(serviceId, serviceClass) {
|
|
104
|
-
if (this.
|
|
105
|
-
if (!this.allowRewriteClasses) {
|
|
106
|
+
if (this.serviceClasses[serviceId]) {
|
|
107
|
+
if (!this.settings.allowRewriteClasses) {
|
|
106
108
|
throw new Error(`ProxyDI already has registered class for ${serviceId}`);
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
|
-
this.
|
|
110
|
-
}
|
|
111
|
-
findInstance(serviceId) {
|
|
112
|
-
const instance = this.instances[serviceId];
|
|
113
|
-
if (!instance && this.parent) {
|
|
114
|
-
return this.parent.findInstance(serviceId);
|
|
115
|
-
}
|
|
116
|
-
return instance;
|
|
111
|
+
this.serviceClasses[serviceId] = serviceClass;
|
|
117
112
|
}
|
|
118
113
|
isKnown(serviceId) {
|
|
119
|
-
return !!(this.findInstance(serviceId) ||
|
|
114
|
+
return !!(this.findInstance(serviceId) ||
|
|
115
|
+
this.findServiceClass(serviceId) ||
|
|
116
|
+
injectableClasses[serviceId]);
|
|
120
117
|
}
|
|
121
118
|
resolve(serviceId) {
|
|
122
119
|
if (!this.isKnown(serviceId)) {
|
|
@@ -126,34 +123,21 @@ class ProxyDI {
|
|
|
126
123
|
if (instance) {
|
|
127
124
|
return instance;
|
|
128
125
|
}
|
|
129
|
-
const definer = this.findDefiner(serviceId);
|
|
130
|
-
if (definer) {
|
|
131
|
-
let instance = new definer();
|
|
132
|
-
this.injectDependencies(instance);
|
|
133
|
-
instance[PROXYDI_ID] = serviceId;
|
|
134
|
-
this.instances[serviceId] = instance;
|
|
135
|
-
return instance;
|
|
136
|
-
}
|
|
137
126
|
else {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
let definer = this.classes[serviceId];
|
|
143
|
-
if (!definer && this.parent) {
|
|
144
|
-
return this.parent.findDefiner(serviceId);
|
|
145
|
-
}
|
|
146
|
-
if (!definer) {
|
|
147
|
-
return injectableClasses[serviceId];
|
|
127
|
+
const ServiceClass = this.findServiceClass(serviceId);
|
|
128
|
+
const newInstance = new ServiceClass();
|
|
129
|
+
this.registerInstance(serviceId, newInstance);
|
|
130
|
+
return newInstance;
|
|
148
131
|
}
|
|
149
|
-
return definer;
|
|
150
132
|
}
|
|
151
133
|
injectDependencies(instance) {
|
|
152
134
|
const serviceInjects = instance[INJECTS] || [];
|
|
153
135
|
serviceInjects.forEach((inject) => {
|
|
136
|
+
// TODO: Return only proxies
|
|
137
|
+
//const value = makeProxy(inject.serviceId, instance);
|
|
154
138
|
let value = this.findInstance(inject.serviceId);
|
|
155
139
|
if (!value) {
|
|
156
|
-
value =
|
|
140
|
+
value = makeProxy(inject.serviceId, instance);
|
|
157
141
|
}
|
|
158
142
|
inject.set(instance, value);
|
|
159
143
|
});
|
|
@@ -161,56 +145,62 @@ class ProxyDI {
|
|
|
161
145
|
instance[PROXYDI] = this;
|
|
162
146
|
}
|
|
163
147
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (!proxy) {
|
|
167
|
-
proxy = this.proxyFactory.makeProxy(serviceId);
|
|
168
|
-
this.proxies[serviceId] = proxy;
|
|
169
|
-
}
|
|
170
|
-
return proxy;
|
|
171
|
-
}
|
|
172
|
-
createChildContainer(settings) {
|
|
173
|
-
const childSettings = Object.assign(Object.assign({}, settings), { parent: this });
|
|
174
|
-
return new ProxyDI(childSettings);
|
|
148
|
+
createChildContainer() {
|
|
149
|
+
return new ProxyDI(this.settings, this);
|
|
175
150
|
}
|
|
176
151
|
removeInstance(serviceId) {
|
|
177
|
-
const id = serviceId[
|
|
178
|
-
|
|
179
|
-
: serviceId;
|
|
180
|
-
const instance = this.instances[id];
|
|
152
|
+
const id = isInstance(serviceId) ? serviceId[SERVICE_ID] : serviceId;
|
|
153
|
+
const instance = this.serviceInstances[id];
|
|
181
154
|
if (instance) {
|
|
182
155
|
const serviceInjects = instance[INJECTS] || [];
|
|
183
156
|
serviceInjects.forEach((inject) => {
|
|
184
157
|
inject.set(instance, undefined);
|
|
185
158
|
});
|
|
186
159
|
delete instance[PROXYDI];
|
|
187
|
-
delete instance[
|
|
188
|
-
delete this.
|
|
160
|
+
delete instance[SERVICE_ID];
|
|
161
|
+
delete this.serviceInstances[id];
|
|
189
162
|
}
|
|
190
163
|
}
|
|
191
164
|
removeClass(serviceId) {
|
|
192
|
-
delete this.
|
|
165
|
+
delete this.serviceClasses[serviceId];
|
|
193
166
|
}
|
|
194
167
|
destroy() {
|
|
195
|
-
const allServices = Object.keys(this.
|
|
168
|
+
const allServices = Object.keys(this.serviceInstances);
|
|
196
169
|
for (const serviceId of allServices) {
|
|
197
|
-
const instance = this.
|
|
170
|
+
const instance = this.serviceInstances[serviceId];
|
|
198
171
|
this.removeInstance(instance);
|
|
199
172
|
}
|
|
200
|
-
this.
|
|
201
|
-
this.
|
|
202
|
-
this.classes = {};
|
|
173
|
+
this.serviceInstances = {};
|
|
174
|
+
this.serviceClasses = {};
|
|
203
175
|
for (const id of Object.keys(this.children)) {
|
|
204
176
|
const child = this.children[+id];
|
|
205
177
|
child.destroy();
|
|
206
178
|
}
|
|
207
179
|
this.children = {};
|
|
208
|
-
this.proxyFactory = undefined;
|
|
209
180
|
if (this.parent) {
|
|
210
181
|
this.parent.removeChild(this.id);
|
|
211
182
|
this.parent = undefined;
|
|
212
183
|
}
|
|
213
184
|
}
|
|
185
|
+
findInstance(serviceId) {
|
|
186
|
+
const instance = this.serviceInstances[serviceId];
|
|
187
|
+
if (!instance && this.parent) {
|
|
188
|
+
const parentInstance = this.parent.findInstance(serviceId);
|
|
189
|
+
// TODO: Make copy, inject container dependencies?
|
|
190
|
+
return parentInstance;
|
|
191
|
+
}
|
|
192
|
+
return instance;
|
|
193
|
+
}
|
|
194
|
+
findServiceClass(serviceId) {
|
|
195
|
+
let ServiceClass = this.serviceClasses[serviceId];
|
|
196
|
+
if (!ServiceClass && !!this.parent) {
|
|
197
|
+
return this.parent.findServiceClass(serviceId);
|
|
198
|
+
}
|
|
199
|
+
if (!ServiceClass) {
|
|
200
|
+
return injectableClasses[serviceId];
|
|
201
|
+
}
|
|
202
|
+
return ServiceClass;
|
|
203
|
+
}
|
|
214
204
|
addChild(child) {
|
|
215
205
|
if (this.children[child.id]) {
|
|
216
206
|
throw new Error(`ProxyDI already has child with id ${child.id}`);
|
|
@@ -225,6 +215,33 @@ class ProxyDI {
|
|
|
225
215
|
}
|
|
226
216
|
}
|
|
227
217
|
ProxyDI.idCounter = 0;
|
|
218
|
+
function isInstance(service) {
|
|
219
|
+
return (typeof service === 'object' &&
|
|
220
|
+
!!service[SERVICE_ID]);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const inject = (serviceId) => {
|
|
224
|
+
return function (_value, context) {
|
|
225
|
+
if ((context === null || context === undefined ? undefined : context.kind) === 'field') {
|
|
226
|
+
const name = serviceId ? serviceId : context.name;
|
|
227
|
+
const inject = {
|
|
228
|
+
property: context.name,
|
|
229
|
+
serviceId: name,
|
|
230
|
+
set: context.access.set,
|
|
231
|
+
};
|
|
232
|
+
context.addInitializer(function () {
|
|
233
|
+
if (!this[INJECTS]) {
|
|
234
|
+
this[INJECTS] = [];
|
|
235
|
+
}
|
|
236
|
+
this[INJECTS].push(inject);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
throw new Error('@inject decorator should decorate fields');
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
};
|
|
228
244
|
|
|
229
245
|
exports.ProxyDI = ProxyDI;
|
|
230
246
|
exports.inject = inject;
|
|
247
|
+
exports.injectable = injectable;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,120 +1,117 @@
|
|
|
1
1
|
const INJECTS = Symbol('injects');
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
const PROXYDI = Symbol('ProxyDI');
|
|
3
|
+
const SERVICE_ID = Symbol('ServiceId');
|
|
4
|
+
const IS_PROXY = Symbol('isProxy');
|
|
5
|
+
const INSTANCE = Symbol('instance');
|
|
6
|
+
|
|
7
|
+
const injectableClasses = {};
|
|
8
|
+
const injectable = (serviceId) => {
|
|
9
|
+
return function (value, context) {
|
|
10
|
+
if ((context === null || context === undefined ? undefined : context.kind) === 'class') {
|
|
5
11
|
const name = serviceId ? serviceId : context.name;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this[INJECTS] = [];
|
|
14
|
-
}
|
|
15
|
-
this[INJECTS].push(inject);
|
|
16
|
-
});
|
|
12
|
+
if (injectableClasses[name]) {
|
|
13
|
+
throw new Error(`ProxyDI injectable classes already has service ID: ${name}`);
|
|
14
|
+
}
|
|
15
|
+
injectableClasses[name] = value;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
throw new Error('@injectable decorator should decorate classes');
|
|
17
19
|
}
|
|
18
20
|
};
|
|
19
21
|
};
|
|
20
22
|
|
|
21
|
-
const
|
|
23
|
+
const DEFAULT_SETTINGS = {
|
|
24
|
+
allowRegisterAnythingAsInstance: false,
|
|
25
|
+
allowRewriteClasses: false,
|
|
26
|
+
allowRewriteInstances: false,
|
|
27
|
+
};
|
|
22
28
|
|
|
23
|
-
|
|
24
|
-
class
|
|
25
|
-
constructor(
|
|
26
|
-
this
|
|
27
|
-
|
|
28
|
-
makeProxy(serviceId) {
|
|
29
|
-
const self = this;
|
|
30
|
-
const proxy = new Proxy({ [IS_PROXY]: true }, {
|
|
31
|
-
get: function (target, prop, receiver) {
|
|
32
|
-
if (target[prop]) {
|
|
33
|
-
return target[prop];
|
|
34
|
-
}
|
|
35
|
-
if (self.container.isKnown(serviceId)) {
|
|
36
|
-
const instance = self.container.resolve(serviceId);
|
|
37
|
-
return Reflect.get(instance, prop, receiver);
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
set: function (target, prop, value) {
|
|
44
|
-
if (self.container.isKnown(serviceId)) {
|
|
45
|
-
const instance = self.container.resolve(serviceId);
|
|
46
|
-
return Reflect.set(instance, prop, value);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
has: function (target, prop) {
|
|
53
|
-
if (self.container.isKnown(serviceId)) {
|
|
54
|
-
const instance = self.container.resolve(serviceId);
|
|
55
|
-
return Reflect.has(instance, prop);
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
return proxy;
|
|
29
|
+
var _a;
|
|
30
|
+
class InstanceProxy {
|
|
31
|
+
constructor(instance) {
|
|
32
|
+
this[_a] = true;
|
|
33
|
+
this[INSTANCE] = instance;
|
|
63
34
|
}
|
|
64
35
|
}
|
|
36
|
+
_a = IS_PROXY;
|
|
37
|
+
const makeProxy = (serviceId, instance) => {
|
|
38
|
+
return new Proxy(new InstanceProxy(instance), {
|
|
39
|
+
get: function (target, prop, receiver) {
|
|
40
|
+
if (target[prop]) {
|
|
41
|
+
return target[prop];
|
|
42
|
+
}
|
|
43
|
+
const container = target[INSTANCE][PROXYDI];
|
|
44
|
+
if (container.isKnown(serviceId)) {
|
|
45
|
+
const instance = container.resolve(serviceId);
|
|
46
|
+
return Reflect.get(instance, prop, receiver);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
set: function (target, prop, value) {
|
|
53
|
+
const container = target[INSTANCE][PROXYDI];
|
|
54
|
+
if (container.isKnown(serviceId)) {
|
|
55
|
+
const instance = container.resolve(serviceId);
|
|
56
|
+
return Reflect.set(instance, prop, value);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
has: function (target, prop) {
|
|
63
|
+
const container = target[INSTANCE][PROXYDI];
|
|
64
|
+
if (container.isKnown(serviceId)) {
|
|
65
|
+
const instance = container.resolve(serviceId);
|
|
66
|
+
return Reflect.has(instance, prop);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
};
|
|
65
74
|
|
|
66
|
-
const PROXYDI = Symbol('ProxyDI');
|
|
67
|
-
const PROXYDI_ID = Symbol('ProxyDI_ID');
|
|
68
75
|
class ProxyDI {
|
|
69
|
-
constructor(settings) {
|
|
76
|
+
constructor(settings, parent) {
|
|
70
77
|
this.children = {};
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
73
|
-
this.proxies = {};
|
|
74
|
-
this.allowRewriteClasses = false;
|
|
75
|
-
this.allowRewriteInstances = false;
|
|
76
|
-
this.proxyFactory = new ProxyFactory(this);
|
|
78
|
+
this.serviceInstances = {};
|
|
79
|
+
this.serviceClasses = {};
|
|
77
80
|
this.id = ProxyDI.idCounter++;
|
|
78
|
-
if (
|
|
79
|
-
this.parent =
|
|
81
|
+
if (parent) {
|
|
82
|
+
this.parent = parent;
|
|
80
83
|
this.parent.addChild(this);
|
|
81
84
|
}
|
|
82
|
-
|
|
83
|
-
this.allowRewriteClasses = settings.allowRewriteClasses;
|
|
84
|
-
}
|
|
85
|
-
if ((settings === null || settings === undefined ? undefined : settings.allowRewriteInstances) !== undefined) {
|
|
86
|
-
this.allowRewriteInstances = settings.allowRewriteInstances;
|
|
87
|
-
}
|
|
85
|
+
this.settings = Object.assign(Object.assign({}, DEFAULT_SETTINGS), settings);
|
|
88
86
|
}
|
|
89
87
|
registerInstance(serviceId, instance) {
|
|
90
|
-
if (this.
|
|
91
|
-
if (!this.allowRewriteInstances) {
|
|
88
|
+
if (this.serviceInstances[serviceId]) {
|
|
89
|
+
if (!this.settings.allowRewriteInstances) {
|
|
92
90
|
throw new Error(`ProxyDI already has registered instance for ${serviceId}`);
|
|
93
91
|
}
|
|
94
92
|
}
|
|
93
|
+
const isObject = typeof instance === 'object';
|
|
94
|
+
if (!isObject && !this.settings.allowRegisterAnythingAsInstance) {
|
|
95
|
+
throw new Error(`Can't register as instance (allowRegisterAnythingAsInstance is off for this ProxyDI contatiner): ${instance}`);
|
|
96
|
+
}
|
|
95
97
|
this.injectDependencies(instance);
|
|
96
|
-
if (
|
|
97
|
-
instance[
|
|
98
|
+
if (isObject) {
|
|
99
|
+
instance[SERVICE_ID] = serviceId;
|
|
98
100
|
}
|
|
99
|
-
this.
|
|
101
|
+
this.serviceInstances[serviceId] = instance;
|
|
100
102
|
}
|
|
101
103
|
registerClass(serviceId, serviceClass) {
|
|
102
|
-
if (this.
|
|
103
|
-
if (!this.allowRewriteClasses) {
|
|
104
|
+
if (this.serviceClasses[serviceId]) {
|
|
105
|
+
if (!this.settings.allowRewriteClasses) {
|
|
104
106
|
throw new Error(`ProxyDI already has registered class for ${serviceId}`);
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
|
-
this.
|
|
108
|
-
}
|
|
109
|
-
findInstance(serviceId) {
|
|
110
|
-
const instance = this.instances[serviceId];
|
|
111
|
-
if (!instance && this.parent) {
|
|
112
|
-
return this.parent.findInstance(serviceId);
|
|
113
|
-
}
|
|
114
|
-
return instance;
|
|
109
|
+
this.serviceClasses[serviceId] = serviceClass;
|
|
115
110
|
}
|
|
116
111
|
isKnown(serviceId) {
|
|
117
|
-
return !!(this.findInstance(serviceId) ||
|
|
112
|
+
return !!(this.findInstance(serviceId) ||
|
|
113
|
+
this.findServiceClass(serviceId) ||
|
|
114
|
+
injectableClasses[serviceId]);
|
|
118
115
|
}
|
|
119
116
|
resolve(serviceId) {
|
|
120
117
|
if (!this.isKnown(serviceId)) {
|
|
@@ -124,34 +121,21 @@ class ProxyDI {
|
|
|
124
121
|
if (instance) {
|
|
125
122
|
return instance;
|
|
126
123
|
}
|
|
127
|
-
const definer = this.findDefiner(serviceId);
|
|
128
|
-
if (definer) {
|
|
129
|
-
let instance = new definer();
|
|
130
|
-
this.injectDependencies(instance);
|
|
131
|
-
instance[PROXYDI_ID] = serviceId;
|
|
132
|
-
this.instances[serviceId] = instance;
|
|
133
|
-
return instance;
|
|
134
|
-
}
|
|
135
124
|
else {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
let definer = this.classes[serviceId];
|
|
141
|
-
if (!definer && this.parent) {
|
|
142
|
-
return this.parent.findDefiner(serviceId);
|
|
143
|
-
}
|
|
144
|
-
if (!definer) {
|
|
145
|
-
return injectableClasses[serviceId];
|
|
125
|
+
const ServiceClass = this.findServiceClass(serviceId);
|
|
126
|
+
const newInstance = new ServiceClass();
|
|
127
|
+
this.registerInstance(serviceId, newInstance);
|
|
128
|
+
return newInstance;
|
|
146
129
|
}
|
|
147
|
-
return definer;
|
|
148
130
|
}
|
|
149
131
|
injectDependencies(instance) {
|
|
150
132
|
const serviceInjects = instance[INJECTS] || [];
|
|
151
133
|
serviceInjects.forEach((inject) => {
|
|
134
|
+
// TODO: Return only proxies
|
|
135
|
+
//const value = makeProxy(inject.serviceId, instance);
|
|
152
136
|
let value = this.findInstance(inject.serviceId);
|
|
153
137
|
if (!value) {
|
|
154
|
-
value =
|
|
138
|
+
value = makeProxy(inject.serviceId, instance);
|
|
155
139
|
}
|
|
156
140
|
inject.set(instance, value);
|
|
157
141
|
});
|
|
@@ -159,56 +143,62 @@ class ProxyDI {
|
|
|
159
143
|
instance[PROXYDI] = this;
|
|
160
144
|
}
|
|
161
145
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (!proxy) {
|
|
165
|
-
proxy = this.proxyFactory.makeProxy(serviceId);
|
|
166
|
-
this.proxies[serviceId] = proxy;
|
|
167
|
-
}
|
|
168
|
-
return proxy;
|
|
169
|
-
}
|
|
170
|
-
createChildContainer(settings) {
|
|
171
|
-
const childSettings = Object.assign(Object.assign({}, settings), { parent: this });
|
|
172
|
-
return new ProxyDI(childSettings);
|
|
146
|
+
createChildContainer() {
|
|
147
|
+
return new ProxyDI(this.settings, this);
|
|
173
148
|
}
|
|
174
149
|
removeInstance(serviceId) {
|
|
175
|
-
const id = serviceId[
|
|
176
|
-
|
|
177
|
-
: serviceId;
|
|
178
|
-
const instance = this.instances[id];
|
|
150
|
+
const id = isInstance(serviceId) ? serviceId[SERVICE_ID] : serviceId;
|
|
151
|
+
const instance = this.serviceInstances[id];
|
|
179
152
|
if (instance) {
|
|
180
153
|
const serviceInjects = instance[INJECTS] || [];
|
|
181
154
|
serviceInjects.forEach((inject) => {
|
|
182
155
|
inject.set(instance, undefined);
|
|
183
156
|
});
|
|
184
157
|
delete instance[PROXYDI];
|
|
185
|
-
delete instance[
|
|
186
|
-
delete this.
|
|
158
|
+
delete instance[SERVICE_ID];
|
|
159
|
+
delete this.serviceInstances[id];
|
|
187
160
|
}
|
|
188
161
|
}
|
|
189
162
|
removeClass(serviceId) {
|
|
190
|
-
delete this.
|
|
163
|
+
delete this.serviceClasses[serviceId];
|
|
191
164
|
}
|
|
192
165
|
destroy() {
|
|
193
|
-
const allServices = Object.keys(this.
|
|
166
|
+
const allServices = Object.keys(this.serviceInstances);
|
|
194
167
|
for (const serviceId of allServices) {
|
|
195
|
-
const instance = this.
|
|
168
|
+
const instance = this.serviceInstances[serviceId];
|
|
196
169
|
this.removeInstance(instance);
|
|
197
170
|
}
|
|
198
|
-
this.
|
|
199
|
-
this.
|
|
200
|
-
this.classes = {};
|
|
171
|
+
this.serviceInstances = {};
|
|
172
|
+
this.serviceClasses = {};
|
|
201
173
|
for (const id of Object.keys(this.children)) {
|
|
202
174
|
const child = this.children[+id];
|
|
203
175
|
child.destroy();
|
|
204
176
|
}
|
|
205
177
|
this.children = {};
|
|
206
|
-
this.proxyFactory = undefined;
|
|
207
178
|
if (this.parent) {
|
|
208
179
|
this.parent.removeChild(this.id);
|
|
209
180
|
this.parent = undefined;
|
|
210
181
|
}
|
|
211
182
|
}
|
|
183
|
+
findInstance(serviceId) {
|
|
184
|
+
const instance = this.serviceInstances[serviceId];
|
|
185
|
+
if (!instance && this.parent) {
|
|
186
|
+
const parentInstance = this.parent.findInstance(serviceId);
|
|
187
|
+
// TODO: Make copy, inject container dependencies?
|
|
188
|
+
return parentInstance;
|
|
189
|
+
}
|
|
190
|
+
return instance;
|
|
191
|
+
}
|
|
192
|
+
findServiceClass(serviceId) {
|
|
193
|
+
let ServiceClass = this.serviceClasses[serviceId];
|
|
194
|
+
if (!ServiceClass && !!this.parent) {
|
|
195
|
+
return this.parent.findServiceClass(serviceId);
|
|
196
|
+
}
|
|
197
|
+
if (!ServiceClass) {
|
|
198
|
+
return injectableClasses[serviceId];
|
|
199
|
+
}
|
|
200
|
+
return ServiceClass;
|
|
201
|
+
}
|
|
212
202
|
addChild(child) {
|
|
213
203
|
if (this.children[child.id]) {
|
|
214
204
|
throw new Error(`ProxyDI already has child with id ${child.id}`);
|
|
@@ -223,5 +213,31 @@ class ProxyDI {
|
|
|
223
213
|
}
|
|
224
214
|
}
|
|
225
215
|
ProxyDI.idCounter = 0;
|
|
216
|
+
function isInstance(service) {
|
|
217
|
+
return (typeof service === 'object' &&
|
|
218
|
+
!!service[SERVICE_ID]);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const inject = (serviceId) => {
|
|
222
|
+
return function (_value, context) {
|
|
223
|
+
if ((context === null || context === undefined ? undefined : context.kind) === 'field') {
|
|
224
|
+
const name = serviceId ? serviceId : context.name;
|
|
225
|
+
const inject = {
|
|
226
|
+
property: context.name,
|
|
227
|
+
serviceId: name,
|
|
228
|
+
set: context.access.set,
|
|
229
|
+
};
|
|
230
|
+
context.addInitializer(function () {
|
|
231
|
+
if (!this[INJECTS]) {
|
|
232
|
+
this[INJECTS] = [];
|
|
233
|
+
}
|
|
234
|
+
this[INJECTS].push(inject);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
throw new Error('@inject decorator should decorate fields');
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
};
|
|
226
242
|
|
|
227
|
-
export { ProxyDI, inject };
|
|
243
|
+
export { ProxyDI, inject, injectable };
|
package/dist/index.umd.js
CHANGED
|
@@ -5,122 +5,119 @@
|
|
|
5
5
|
})(this, (function (exports) { 'use strict';
|
|
6
6
|
|
|
7
7
|
const INJECTS = Symbol('injects');
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
const PROXYDI = Symbol('ProxyDI');
|
|
9
|
+
const SERVICE_ID = Symbol('ServiceId');
|
|
10
|
+
const IS_PROXY = Symbol('isProxy');
|
|
11
|
+
const INSTANCE = Symbol('instance');
|
|
12
|
+
|
|
13
|
+
const injectableClasses = {};
|
|
14
|
+
const injectable = (serviceId) => {
|
|
15
|
+
return function (value, context) {
|
|
16
|
+
if ((context === null || context === undefined ? undefined : context.kind) === 'class') {
|
|
11
17
|
const name = serviceId ? serviceId : context.name;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this[INJECTS] = [];
|
|
20
|
-
}
|
|
21
|
-
this[INJECTS].push(inject);
|
|
22
|
-
});
|
|
18
|
+
if (injectableClasses[name]) {
|
|
19
|
+
throw new Error(`ProxyDI injectable classes already has service ID: ${name}`);
|
|
20
|
+
}
|
|
21
|
+
injectableClasses[name] = value;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
throw new Error('@injectable decorator should decorate classes');
|
|
23
25
|
}
|
|
24
26
|
};
|
|
25
27
|
};
|
|
26
28
|
|
|
27
|
-
const
|
|
29
|
+
const DEFAULT_SETTINGS = {
|
|
30
|
+
allowRegisterAnythingAsInstance: false,
|
|
31
|
+
allowRewriteClasses: false,
|
|
32
|
+
allowRewriteInstances: false,
|
|
33
|
+
};
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
class
|
|
31
|
-
constructor(
|
|
32
|
-
this
|
|
33
|
-
|
|
34
|
-
makeProxy(serviceId) {
|
|
35
|
-
const self = this;
|
|
36
|
-
const proxy = new Proxy({ [IS_PROXY]: true }, {
|
|
37
|
-
get: function (target, prop, receiver) {
|
|
38
|
-
if (target[prop]) {
|
|
39
|
-
return target[prop];
|
|
40
|
-
}
|
|
41
|
-
if (self.container.isKnown(serviceId)) {
|
|
42
|
-
const instance = self.container.resolve(serviceId);
|
|
43
|
-
return Reflect.get(instance, prop, receiver);
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
set: function (target, prop, value) {
|
|
50
|
-
if (self.container.isKnown(serviceId)) {
|
|
51
|
-
const instance = self.container.resolve(serviceId);
|
|
52
|
-
return Reflect.set(instance, prop, value);
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
has: function (target, prop) {
|
|
59
|
-
if (self.container.isKnown(serviceId)) {
|
|
60
|
-
const instance = self.container.resolve(serviceId);
|
|
61
|
-
return Reflect.has(instance, prop);
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
return proxy;
|
|
35
|
+
var _a;
|
|
36
|
+
class InstanceProxy {
|
|
37
|
+
constructor(instance) {
|
|
38
|
+
this[_a] = true;
|
|
39
|
+
this[INSTANCE] = instance;
|
|
69
40
|
}
|
|
70
41
|
}
|
|
42
|
+
_a = IS_PROXY;
|
|
43
|
+
const makeProxy = (serviceId, instance) => {
|
|
44
|
+
return new Proxy(new InstanceProxy(instance), {
|
|
45
|
+
get: function (target, prop, receiver) {
|
|
46
|
+
if (target[prop]) {
|
|
47
|
+
return target[prop];
|
|
48
|
+
}
|
|
49
|
+
const container = target[INSTANCE][PROXYDI];
|
|
50
|
+
if (container.isKnown(serviceId)) {
|
|
51
|
+
const instance = container.resolve(serviceId);
|
|
52
|
+
return Reflect.get(instance, prop, receiver);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
set: function (target, prop, value) {
|
|
59
|
+
const container = target[INSTANCE][PROXYDI];
|
|
60
|
+
if (container.isKnown(serviceId)) {
|
|
61
|
+
const instance = container.resolve(serviceId);
|
|
62
|
+
return Reflect.set(instance, prop, value);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
has: function (target, prop) {
|
|
69
|
+
const container = target[INSTANCE][PROXYDI];
|
|
70
|
+
if (container.isKnown(serviceId)) {
|
|
71
|
+
const instance = container.resolve(serviceId);
|
|
72
|
+
return Reflect.has(instance, prop);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
throw new Error(`Unknown ProxyDI-service: ${serviceId}`);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
};
|
|
71
80
|
|
|
72
|
-
const PROXYDI = Symbol('ProxyDI');
|
|
73
|
-
const PROXYDI_ID = Symbol('ProxyDI_ID');
|
|
74
81
|
class ProxyDI {
|
|
75
|
-
constructor(settings) {
|
|
82
|
+
constructor(settings, parent) {
|
|
76
83
|
this.children = {};
|
|
77
|
-
this.
|
|
78
|
-
this.
|
|
79
|
-
this.proxies = {};
|
|
80
|
-
this.allowRewriteClasses = false;
|
|
81
|
-
this.allowRewriteInstances = false;
|
|
82
|
-
this.proxyFactory = new ProxyFactory(this);
|
|
84
|
+
this.serviceInstances = {};
|
|
85
|
+
this.serviceClasses = {};
|
|
83
86
|
this.id = ProxyDI.idCounter++;
|
|
84
|
-
if (
|
|
85
|
-
this.parent =
|
|
87
|
+
if (parent) {
|
|
88
|
+
this.parent = parent;
|
|
86
89
|
this.parent.addChild(this);
|
|
87
90
|
}
|
|
88
|
-
|
|
89
|
-
this.allowRewriteClasses = settings.allowRewriteClasses;
|
|
90
|
-
}
|
|
91
|
-
if ((settings === null || settings === undefined ? undefined : settings.allowRewriteInstances) !== undefined) {
|
|
92
|
-
this.allowRewriteInstances = settings.allowRewriteInstances;
|
|
93
|
-
}
|
|
91
|
+
this.settings = Object.assign(Object.assign({}, DEFAULT_SETTINGS), settings);
|
|
94
92
|
}
|
|
95
93
|
registerInstance(serviceId, instance) {
|
|
96
|
-
if (this.
|
|
97
|
-
if (!this.allowRewriteInstances) {
|
|
94
|
+
if (this.serviceInstances[serviceId]) {
|
|
95
|
+
if (!this.settings.allowRewriteInstances) {
|
|
98
96
|
throw new Error(`ProxyDI already has registered instance for ${serviceId}`);
|
|
99
97
|
}
|
|
100
98
|
}
|
|
99
|
+
const isObject = typeof instance === 'object';
|
|
100
|
+
if (!isObject && !this.settings.allowRegisterAnythingAsInstance) {
|
|
101
|
+
throw new Error(`Can't register as instance (allowRegisterAnythingAsInstance is off for this ProxyDI contatiner): ${instance}`);
|
|
102
|
+
}
|
|
101
103
|
this.injectDependencies(instance);
|
|
102
|
-
if (
|
|
103
|
-
instance[
|
|
104
|
+
if (isObject) {
|
|
105
|
+
instance[SERVICE_ID] = serviceId;
|
|
104
106
|
}
|
|
105
|
-
this.
|
|
107
|
+
this.serviceInstances[serviceId] = instance;
|
|
106
108
|
}
|
|
107
109
|
registerClass(serviceId, serviceClass) {
|
|
108
|
-
if (this.
|
|
109
|
-
if (!this.allowRewriteClasses) {
|
|
110
|
+
if (this.serviceClasses[serviceId]) {
|
|
111
|
+
if (!this.settings.allowRewriteClasses) {
|
|
110
112
|
throw new Error(`ProxyDI already has registered class for ${serviceId}`);
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
|
-
this.
|
|
114
|
-
}
|
|
115
|
-
findInstance(serviceId) {
|
|
116
|
-
const instance = this.instances[serviceId];
|
|
117
|
-
if (!instance && this.parent) {
|
|
118
|
-
return this.parent.findInstance(serviceId);
|
|
119
|
-
}
|
|
120
|
-
return instance;
|
|
115
|
+
this.serviceClasses[serviceId] = serviceClass;
|
|
121
116
|
}
|
|
122
117
|
isKnown(serviceId) {
|
|
123
|
-
return !!(this.findInstance(serviceId) ||
|
|
118
|
+
return !!(this.findInstance(serviceId) ||
|
|
119
|
+
this.findServiceClass(serviceId) ||
|
|
120
|
+
injectableClasses[serviceId]);
|
|
124
121
|
}
|
|
125
122
|
resolve(serviceId) {
|
|
126
123
|
if (!this.isKnown(serviceId)) {
|
|
@@ -130,34 +127,21 @@
|
|
|
130
127
|
if (instance) {
|
|
131
128
|
return instance;
|
|
132
129
|
}
|
|
133
|
-
const definer = this.findDefiner(serviceId);
|
|
134
|
-
if (definer) {
|
|
135
|
-
let instance = new definer();
|
|
136
|
-
this.injectDependencies(instance);
|
|
137
|
-
instance[PROXYDI_ID] = serviceId;
|
|
138
|
-
this.instances[serviceId] = instance;
|
|
139
|
-
return instance;
|
|
140
|
-
}
|
|
141
130
|
else {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
let definer = this.classes[serviceId];
|
|
147
|
-
if (!definer && this.parent) {
|
|
148
|
-
return this.parent.findDefiner(serviceId);
|
|
149
|
-
}
|
|
150
|
-
if (!definer) {
|
|
151
|
-
return injectableClasses[serviceId];
|
|
131
|
+
const ServiceClass = this.findServiceClass(serviceId);
|
|
132
|
+
const newInstance = new ServiceClass();
|
|
133
|
+
this.registerInstance(serviceId, newInstance);
|
|
134
|
+
return newInstance;
|
|
152
135
|
}
|
|
153
|
-
return definer;
|
|
154
136
|
}
|
|
155
137
|
injectDependencies(instance) {
|
|
156
138
|
const serviceInjects = instance[INJECTS] || [];
|
|
157
139
|
serviceInjects.forEach((inject) => {
|
|
140
|
+
// TODO: Return only proxies
|
|
141
|
+
//const value = makeProxy(inject.serviceId, instance);
|
|
158
142
|
let value = this.findInstance(inject.serviceId);
|
|
159
143
|
if (!value) {
|
|
160
|
-
value =
|
|
144
|
+
value = makeProxy(inject.serviceId, instance);
|
|
161
145
|
}
|
|
162
146
|
inject.set(instance, value);
|
|
163
147
|
});
|
|
@@ -165,56 +149,62 @@
|
|
|
165
149
|
instance[PROXYDI] = this;
|
|
166
150
|
}
|
|
167
151
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (!proxy) {
|
|
171
|
-
proxy = this.proxyFactory.makeProxy(serviceId);
|
|
172
|
-
this.proxies[serviceId] = proxy;
|
|
173
|
-
}
|
|
174
|
-
return proxy;
|
|
175
|
-
}
|
|
176
|
-
createChildContainer(settings) {
|
|
177
|
-
const childSettings = Object.assign(Object.assign({}, settings), { parent: this });
|
|
178
|
-
return new ProxyDI(childSettings);
|
|
152
|
+
createChildContainer() {
|
|
153
|
+
return new ProxyDI(this.settings, this);
|
|
179
154
|
}
|
|
180
155
|
removeInstance(serviceId) {
|
|
181
|
-
const id = serviceId[
|
|
182
|
-
|
|
183
|
-
: serviceId;
|
|
184
|
-
const instance = this.instances[id];
|
|
156
|
+
const id = isInstance(serviceId) ? serviceId[SERVICE_ID] : serviceId;
|
|
157
|
+
const instance = this.serviceInstances[id];
|
|
185
158
|
if (instance) {
|
|
186
159
|
const serviceInjects = instance[INJECTS] || [];
|
|
187
160
|
serviceInjects.forEach((inject) => {
|
|
188
161
|
inject.set(instance, undefined);
|
|
189
162
|
});
|
|
190
163
|
delete instance[PROXYDI];
|
|
191
|
-
delete instance[
|
|
192
|
-
delete this.
|
|
164
|
+
delete instance[SERVICE_ID];
|
|
165
|
+
delete this.serviceInstances[id];
|
|
193
166
|
}
|
|
194
167
|
}
|
|
195
168
|
removeClass(serviceId) {
|
|
196
|
-
delete this.
|
|
169
|
+
delete this.serviceClasses[serviceId];
|
|
197
170
|
}
|
|
198
171
|
destroy() {
|
|
199
|
-
const allServices = Object.keys(this.
|
|
172
|
+
const allServices = Object.keys(this.serviceInstances);
|
|
200
173
|
for (const serviceId of allServices) {
|
|
201
|
-
const instance = this.
|
|
174
|
+
const instance = this.serviceInstances[serviceId];
|
|
202
175
|
this.removeInstance(instance);
|
|
203
176
|
}
|
|
204
|
-
this.
|
|
205
|
-
this.
|
|
206
|
-
this.classes = {};
|
|
177
|
+
this.serviceInstances = {};
|
|
178
|
+
this.serviceClasses = {};
|
|
207
179
|
for (const id of Object.keys(this.children)) {
|
|
208
180
|
const child = this.children[+id];
|
|
209
181
|
child.destroy();
|
|
210
182
|
}
|
|
211
183
|
this.children = {};
|
|
212
|
-
this.proxyFactory = undefined;
|
|
213
184
|
if (this.parent) {
|
|
214
185
|
this.parent.removeChild(this.id);
|
|
215
186
|
this.parent = undefined;
|
|
216
187
|
}
|
|
217
188
|
}
|
|
189
|
+
findInstance(serviceId) {
|
|
190
|
+
const instance = this.serviceInstances[serviceId];
|
|
191
|
+
if (!instance && this.parent) {
|
|
192
|
+
const parentInstance = this.parent.findInstance(serviceId);
|
|
193
|
+
// TODO: Make copy, inject container dependencies?
|
|
194
|
+
return parentInstance;
|
|
195
|
+
}
|
|
196
|
+
return instance;
|
|
197
|
+
}
|
|
198
|
+
findServiceClass(serviceId) {
|
|
199
|
+
let ServiceClass = this.serviceClasses[serviceId];
|
|
200
|
+
if (!ServiceClass && !!this.parent) {
|
|
201
|
+
return this.parent.findServiceClass(serviceId);
|
|
202
|
+
}
|
|
203
|
+
if (!ServiceClass) {
|
|
204
|
+
return injectableClasses[serviceId];
|
|
205
|
+
}
|
|
206
|
+
return ServiceClass;
|
|
207
|
+
}
|
|
218
208
|
addChild(child) {
|
|
219
209
|
if (this.children[child.id]) {
|
|
220
210
|
throw new Error(`ProxyDI already has child with id ${child.id}`);
|
|
@@ -229,8 +219,35 @@
|
|
|
229
219
|
}
|
|
230
220
|
}
|
|
231
221
|
ProxyDI.idCounter = 0;
|
|
222
|
+
function isInstance(service) {
|
|
223
|
+
return (typeof service === 'object' &&
|
|
224
|
+
!!service[SERVICE_ID]);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const inject = (serviceId) => {
|
|
228
|
+
return function (_value, context) {
|
|
229
|
+
if ((context === null || context === undefined ? undefined : context.kind) === 'field') {
|
|
230
|
+
const name = serviceId ? serviceId : context.name;
|
|
231
|
+
const inject = {
|
|
232
|
+
property: context.name,
|
|
233
|
+
serviceId: name,
|
|
234
|
+
set: context.access.set,
|
|
235
|
+
};
|
|
236
|
+
context.addInitializer(function () {
|
|
237
|
+
if (!this[INJECTS]) {
|
|
238
|
+
this[INJECTS] = [];
|
|
239
|
+
}
|
|
240
|
+
this[INJECTS].push(inject);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
throw new Error('@inject decorator should decorate fields');
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
};
|
|
232
248
|
|
|
233
249
|
exports.ProxyDI = ProxyDI;
|
|
234
250
|
exports.inject = inject;
|
|
251
|
+
exports.injectable = injectable;
|
|
235
252
|
|
|
236
253
|
}));
|
package/dist/inject.d.ts
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ProxyDI } from './ProxyDI';
|
|
2
1
|
export type ServiceId = any;
|
|
3
2
|
export type ServiceConstructor<T extends unknown> = new () => T;
|
|
4
3
|
export type Setter = (object: unknown, value: unknown) => void;
|
|
@@ -7,9 +6,40 @@ export type Inject = {
|
|
|
7
6
|
serviceId: ServiceId;
|
|
8
7
|
set: Setter;
|
|
9
8
|
};
|
|
9
|
+
export type ProxyDI = {
|
|
10
|
+
isKnown: (serviceId: ServiceId) => boolean;
|
|
11
|
+
injectDependencies: (instance: any) => void;
|
|
12
|
+
registerInstance: <T>(serviceId: ServiceId, instance: T extends {
|
|
13
|
+
new (...args: any[]): any;
|
|
14
|
+
} ? never : T) => void;
|
|
15
|
+
registerClass: <T>(serviceId: ServiceId, serviceClass: ServiceClass<T>) => void;
|
|
16
|
+
resolve: <T>(serviceId: ServiceId) => T;
|
|
17
|
+
createChildContainer: () => ProxyDI;
|
|
18
|
+
removeInstance: (serviceId: ServiceId | ProxydiedInstance) => void;
|
|
19
|
+
removeClass: (serviceId: ServiceId) => void;
|
|
20
|
+
destroy: () => void;
|
|
21
|
+
};
|
|
22
|
+
export declare const INJECTS: unique symbol;
|
|
23
|
+
export declare const PROXYDI: unique symbol;
|
|
24
|
+
export declare const SERVICE_ID: unique symbol;
|
|
25
|
+
export type ReadyForProxidyInstance = {
|
|
26
|
+
[INJECTS]: Inject[];
|
|
27
|
+
};
|
|
28
|
+
export type InjectedInstance = ReadyForProxidyInstance & {
|
|
29
|
+
[PROXYDI]: ProxyDI;
|
|
30
|
+
};
|
|
31
|
+
export type ProxydiedInstance = InjectedInstance & {
|
|
32
|
+
[SERVICE_ID]: ServiceId;
|
|
33
|
+
};
|
|
10
34
|
export type ServiceClass<T> = new (...args: any[]) => T;
|
|
11
35
|
export type ProxyDISettings = {
|
|
12
|
-
|
|
36
|
+
allowRegisterAnythingAsInstance?: boolean;
|
|
13
37
|
allowRewriteClasses?: boolean;
|
|
14
38
|
allowRewriteInstances?: boolean;
|
|
15
39
|
};
|
|
40
|
+
export declare const IS_PROXY: unique symbol;
|
|
41
|
+
export declare const INSTANCE: unique symbol;
|
|
42
|
+
export type InstanceProxy = {
|
|
43
|
+
[IS_PROXY]: true;
|
|
44
|
+
[INSTANCE]: ProxydiedInstance;
|
|
45
|
+
};
|