@shrub/core 0.5.26
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/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/module.js +247 -0
- package/dist/esm/service-collection.js +382 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +15 -0
- package/dist/module.d.ts +110 -0
- package/dist/module.js +253 -0
- package/dist/service-collection.d.ts +146 -0
- package/dist/service-collection.js +395 -0
- package/package.json +26 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
export const IInstantiationService = createService("instantiation-service");
|
|
2
|
+
export const IOptionsService = createService("options-service");
|
|
3
|
+
export const IServiceCollection = createService("service-collection");
|
|
4
|
+
const dependencies = "__dependencies";
|
|
5
|
+
const scope = "__scope";
|
|
6
|
+
/** Class decorator identifying the required scope for a service as 'scoped'. */
|
|
7
|
+
export function Scoped(ctor) {
|
|
8
|
+
ctor[scope] = "scoped" /* scoped */;
|
|
9
|
+
}
|
|
10
|
+
/** Class decorator identifying the required scope for a service as 'singleton'. */
|
|
11
|
+
export function Singleton(ctor) {
|
|
12
|
+
ctor[scope] = "singleton" /* singleton */;
|
|
13
|
+
}
|
|
14
|
+
/** Class decorator identifying the required scope for a service as 'transient'. */
|
|
15
|
+
export function Transient(ctor) {
|
|
16
|
+
ctor[scope] = "transient" /* transient */;
|
|
17
|
+
}
|
|
18
|
+
export function createInjectable(keyOrOptions) {
|
|
19
|
+
const options = typeof keyOrOptions === "object" ? keyOrOptions : { key: keyOrOptions };
|
|
20
|
+
const injectable = function (target, propertyKey, parameterIndex) {
|
|
21
|
+
if (!isConstructor(target)) {
|
|
22
|
+
throw new Error("An injectable decorator only supports constructor parameters.");
|
|
23
|
+
}
|
|
24
|
+
captureDependency(injectable, target, parameterIndex);
|
|
25
|
+
};
|
|
26
|
+
injectable.key = options.key;
|
|
27
|
+
injectable.factory = options.factory;
|
|
28
|
+
injectable.toString = () => options.key;
|
|
29
|
+
return injectable;
|
|
30
|
+
}
|
|
31
|
+
export function createOptions(key, defaultOptions) {
|
|
32
|
+
const validation = [];
|
|
33
|
+
const options = createInjectable({
|
|
34
|
+
key,
|
|
35
|
+
factory: services => services.get(IOptionsService).getOptions(options)
|
|
36
|
+
});
|
|
37
|
+
options.defaultOptions = defaultOptions;
|
|
38
|
+
options.register = (callback) => validation.push(callback);
|
|
39
|
+
options.require = (...props) => {
|
|
40
|
+
options.register((obj, invalid) => {
|
|
41
|
+
for (const prop of props) {
|
|
42
|
+
if (obj[prop] === undefined) {
|
|
43
|
+
invalid(new OptionsValidationError(`Options (${key}) property (${prop}) is required.`));
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
options.validate = (obj, fail) => {
|
|
50
|
+
let error;
|
|
51
|
+
for (let i = 0; i < validation.length && error === undefined; i++) {
|
|
52
|
+
validation[i](obj, err => error = err);
|
|
53
|
+
}
|
|
54
|
+
if (error) {
|
|
55
|
+
fail(error);
|
|
56
|
+
}
|
|
57
|
+
return error === undefined;
|
|
58
|
+
};
|
|
59
|
+
return options;
|
|
60
|
+
}
|
|
61
|
+
export function createService(key) {
|
|
62
|
+
return createInjectable(key);
|
|
63
|
+
}
|
|
64
|
+
function getDependencies(ctor) {
|
|
65
|
+
return ctor[dependencies] || {};
|
|
66
|
+
}
|
|
67
|
+
function getServiceScope(ctor) {
|
|
68
|
+
const value = ctor[scope];
|
|
69
|
+
if (!value) {
|
|
70
|
+
throw new Error(`Default scope not defined for service (${ctor.name})`);
|
|
71
|
+
}
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
function captureDependency(injectable, target, index) {
|
|
75
|
+
target[dependencies] = target[dependencies] || {};
|
|
76
|
+
target[dependencies][index] = injectable;
|
|
77
|
+
}
|
|
78
|
+
function isConstructor(target) {
|
|
79
|
+
return typeof target === "function" && target === target.prototype.constructor;
|
|
80
|
+
}
|
|
81
|
+
function isDisposable(obj) {
|
|
82
|
+
return obj.dispose !== undefined;
|
|
83
|
+
}
|
|
84
|
+
function isServiceFactory(target) {
|
|
85
|
+
return typeof target === "object" && target.create !== undefined;
|
|
86
|
+
}
|
|
87
|
+
/** Represents an error that has occurred while trying to create an object instance. */
|
|
88
|
+
export class ObjectCreateError extends Error {
|
|
89
|
+
constructor(message, inner) {
|
|
90
|
+
super(message);
|
|
91
|
+
this.inner = inner;
|
|
92
|
+
Object.setPrototypeOf(this, ObjectCreateError.prototype);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A service factory that will create a single instance and return the same instance everytime create is invoked.
|
|
97
|
+
* This is useful for singleton services that implement multiple service interfaces.
|
|
98
|
+
*/
|
|
99
|
+
export class SingletonServiceFactory {
|
|
100
|
+
constructor(ctorOrFactory) {
|
|
101
|
+
this.ctorOrFactory = ctorOrFactory;
|
|
102
|
+
}
|
|
103
|
+
create(services) {
|
|
104
|
+
if (!this.instance) {
|
|
105
|
+
this.instance = isServiceFactory(this.ctorOrFactory)
|
|
106
|
+
? this.ctorOrFactory.create(services)
|
|
107
|
+
: services.get(IInstantiationService).createInstance(this.ctorOrFactory);
|
|
108
|
+
}
|
|
109
|
+
return this.instance;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export class ServiceMap {
|
|
113
|
+
constructor() {
|
|
114
|
+
this.services = new Map();
|
|
115
|
+
// the thisFactory is necessary for scoped collections
|
|
116
|
+
const thisFactory = { create: () => this };
|
|
117
|
+
this.registerService(IInstantiationService, "scoped" /* scoped */, thisFactory);
|
|
118
|
+
this.registerService(IServiceCollection, "scoped" /* scoped */, thisFactory);
|
|
119
|
+
this.registerSingleton(IOptionsService, OptionsService);
|
|
120
|
+
}
|
|
121
|
+
addOptionsProvider(provider) {
|
|
122
|
+
return this.get(IOptionsService).addOptionsProvider(provider);
|
|
123
|
+
}
|
|
124
|
+
configureOptions(options, callback) {
|
|
125
|
+
this.get(IOptionsService).configureOptions(options, callback);
|
|
126
|
+
}
|
|
127
|
+
createInstance(ctor) {
|
|
128
|
+
return this.createObjectInstance(ctor);
|
|
129
|
+
}
|
|
130
|
+
createScope() {
|
|
131
|
+
const parent = this;
|
|
132
|
+
return new class extends ServiceMap {
|
|
133
|
+
constructor() {
|
|
134
|
+
super();
|
|
135
|
+
// The service map registers a few built-in services that need to be handled a little differently
|
|
136
|
+
// -- if the service is singleton/instance it gets copied from the parent
|
|
137
|
+
// -- if the service is scoped/transient do not overwrite the entry from the parent
|
|
138
|
+
for (const entry of parent.services.values()) {
|
|
139
|
+
if (entry.scope === "singleton" /* singleton */ || entry.scope === "instance" /* instance */) {
|
|
140
|
+
// copy the singleton entry directly to the scoped collection - it's possible the instance has not yet been created so the entire entry gets copied down
|
|
141
|
+
this.registerEntry(entry);
|
|
142
|
+
}
|
|
143
|
+
else if (!this.services.has(entry.service.key)) {
|
|
144
|
+
// create a new entry for scoped/transient services
|
|
145
|
+
this.registerEntry({ ...entry, instance: undefined });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this.freeze();
|
|
149
|
+
}
|
|
150
|
+
dispose() {
|
|
151
|
+
for (const service of this.services.values()) {
|
|
152
|
+
// only dispose scoped service instances that were instantiated by the current service scope
|
|
153
|
+
if (service.instance &&
|
|
154
|
+
service.scope === "scoped" /* scoped */ &&
|
|
155
|
+
isDisposable(service.instance)) {
|
|
156
|
+
service.instance.dispose();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
this.services.clear();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
getOptions(options) {
|
|
164
|
+
return this.get(IOptionsService).getOptions(options);
|
|
165
|
+
}
|
|
166
|
+
register(service, ctor) {
|
|
167
|
+
this.registerService(service, getServiceScope(ctor), ctor);
|
|
168
|
+
}
|
|
169
|
+
registerInstance(service, instance) {
|
|
170
|
+
if (instance === undefined) {
|
|
171
|
+
throw new Error("instance undefined");
|
|
172
|
+
}
|
|
173
|
+
// TODO: check if the instance constructor has a required scope - if so, verify its a singleton
|
|
174
|
+
this.services.set(service.key, {
|
|
175
|
+
service,
|
|
176
|
+
scope: "instance" /* instance */,
|
|
177
|
+
instance
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
registerScoped(service, ctorOrFactory) {
|
|
181
|
+
this.registerService(service, "scoped" /* scoped */, ctorOrFactory);
|
|
182
|
+
}
|
|
183
|
+
registerSingleton(service, ctorOrFactory) {
|
|
184
|
+
this.registerService(service, "singleton" /* singleton */, ctorOrFactory);
|
|
185
|
+
}
|
|
186
|
+
registerTransient(service, ctorOrFactory) {
|
|
187
|
+
this.registerService(service, "transient" /* transient */, ctorOrFactory);
|
|
188
|
+
}
|
|
189
|
+
tryRegister(service, ctor) {
|
|
190
|
+
if (!this.services.has(service.key)) {
|
|
191
|
+
this.register(service, ctor);
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
tryRegisterInstance(service, instance) {
|
|
197
|
+
if (!this.services.has(service.key)) {
|
|
198
|
+
this.registerInstance(service, instance);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
tryRegisterScoped(service, ctorOrFactory) {
|
|
204
|
+
if (!this.services.has(service.key)) {
|
|
205
|
+
this.registerScoped(service, ctorOrFactory);
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
tryRegisterSingleton(service, ctorOrFactory) {
|
|
211
|
+
if (!this.services.has(service.key)) {
|
|
212
|
+
this.registerSingleton(service, ctorOrFactory);
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
tryRegisterTransient(service, ctorOrFactory) {
|
|
218
|
+
if (!this.services.has(service.key)) {
|
|
219
|
+
this.registerTransient(service, ctorOrFactory);
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
get(serviceOrKey) {
|
|
225
|
+
const key = typeof serviceOrKey === "string" ? serviceOrKey : serviceOrKey.key;
|
|
226
|
+
return this.getOrCreateServiceInstance(key);
|
|
227
|
+
}
|
|
228
|
+
has(serviceOrKey) {
|
|
229
|
+
const key = typeof serviceOrKey === "string" ? serviceOrKey : serviceOrKey.key;
|
|
230
|
+
return this.services.has(key);
|
|
231
|
+
}
|
|
232
|
+
tryGet(serviceOrKey) {
|
|
233
|
+
if (this.has(serviceOrKey)) {
|
|
234
|
+
return this.get(serviceOrKey);
|
|
235
|
+
}
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
/** Prevents items from being registered with the serivce map. */
|
|
239
|
+
freeze() {
|
|
240
|
+
this.isFrozen = true;
|
|
241
|
+
}
|
|
242
|
+
registerService(service, scope, ctorOrFactory) {
|
|
243
|
+
this.registerEntry({
|
|
244
|
+
service,
|
|
245
|
+
scope,
|
|
246
|
+
ctor: isConstructor(ctorOrFactory) ? ctorOrFactory : undefined,
|
|
247
|
+
factory: isServiceFactory(ctorOrFactory) ? ctorOrFactory : undefined
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
registerEntry(entry) {
|
|
251
|
+
if (this.isFrozen === true) {
|
|
252
|
+
throw new Error("Service collection is frozen");
|
|
253
|
+
}
|
|
254
|
+
if (entry.ctor) {
|
|
255
|
+
this.checkInstanceScope(entry.ctor, entry.scope);
|
|
256
|
+
}
|
|
257
|
+
this.services.set(entry.service.key, entry);
|
|
258
|
+
}
|
|
259
|
+
checkFactoryInstance(instance, scope) {
|
|
260
|
+
if (typeof instance !== "object" && typeof instance !== "function") {
|
|
261
|
+
throw new Error("Instance must be an object or function");
|
|
262
|
+
}
|
|
263
|
+
if (instance.constructor !== Object && instance.constructor !== Function) {
|
|
264
|
+
this.checkInstanceScope(instance.constructor, scope);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
checkInstanceScope(ctor, scope) {
|
|
268
|
+
const requiredScope = ctor[scope];
|
|
269
|
+
if (requiredScope && requiredScope !== scope) {
|
|
270
|
+
throw new Error("Registered service scope is different than the instance required scope");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
getOrCreateServiceInstance(key, ancestors) {
|
|
274
|
+
const entry = this.services.get(key);
|
|
275
|
+
if (!entry) {
|
|
276
|
+
throw new Error(`Service not registered for key '${key}'.`);
|
|
277
|
+
}
|
|
278
|
+
if (entry.instance) {
|
|
279
|
+
return entry.instance;
|
|
280
|
+
}
|
|
281
|
+
const instance = this.createServiceInstance(entry, ancestors);
|
|
282
|
+
if (entry.scope === "scoped" /* scoped */ || entry.scope === "singleton" /* singleton */) {
|
|
283
|
+
entry.instance = instance;
|
|
284
|
+
}
|
|
285
|
+
return instance;
|
|
286
|
+
}
|
|
287
|
+
getOrCreateInjectable(injectable, ancestors) {
|
|
288
|
+
if (this.services.has(injectable.key)) {
|
|
289
|
+
return this.getOrCreateServiceInstance(injectable.key, ancestors);
|
|
290
|
+
}
|
|
291
|
+
if (injectable.factory) {
|
|
292
|
+
return injectable.factory(this);
|
|
293
|
+
}
|
|
294
|
+
throw new Error(`Invalid injectable (${injectable.key}), either a service has not been registered or the injectable does not define a factory.`);
|
|
295
|
+
}
|
|
296
|
+
createServiceInstance(entry, ancestors) {
|
|
297
|
+
if (entry.factory) {
|
|
298
|
+
const instance = entry.factory.create(this);
|
|
299
|
+
// even though the scope cannot be verified until now it is still a good idea to check that the service instance is being properly scoped
|
|
300
|
+
this.checkFactoryInstance(instance, entry.scope);
|
|
301
|
+
return instance;
|
|
302
|
+
}
|
|
303
|
+
if (entry.ctor) {
|
|
304
|
+
return this.createObjectInstance(entry.ctor, ancestors);
|
|
305
|
+
}
|
|
306
|
+
throw new Error("Invalid service entry.");
|
|
307
|
+
}
|
|
308
|
+
createObjectInstance(ctor, ancestors) {
|
|
309
|
+
if (ancestors && ancestors.includes(ctor)) {
|
|
310
|
+
const path = [...ancestors.map(ctor => ctor.name), ctor.name].join(" -> ");
|
|
311
|
+
throw new Error("Circular dependency detected: " + path);
|
|
312
|
+
}
|
|
313
|
+
const dependencies = getDependencies(ctor);
|
|
314
|
+
const keys = Object.keys(dependencies);
|
|
315
|
+
if (ctor.length > keys.length) {
|
|
316
|
+
throw new Error(`Invalid constructor (${ctor.name}), all parameters must be injectable.`);
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
ancestors = ancestors || [];
|
|
320
|
+
ancestors.push(ctor);
|
|
321
|
+
// create/get instances for all the object's constructor parameters
|
|
322
|
+
const args = keys.map(key => this.getOrCreateInjectable(dependencies[key], ancestors));
|
|
323
|
+
ancestors.splice(ancestors.indexOf(ctor), 1);
|
|
324
|
+
return new ctor(...args);
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
throw new ObjectCreateError(`Failed to get dependencies for Constructor (${ctor.name}): ${err.message}`, err);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/** Represents an error for an options object instance that failed validation. */
|
|
332
|
+
export class OptionsValidationError extends Error {
|
|
333
|
+
constructor(message) {
|
|
334
|
+
super(message);
|
|
335
|
+
Object.setPrototypeOf(this, OptionsValidationError.prototype);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
class OptionsService {
|
|
339
|
+
constructor() {
|
|
340
|
+
this.options = new Map();
|
|
341
|
+
this.providers = [];
|
|
342
|
+
}
|
|
343
|
+
addOptionsProvider(provider) {
|
|
344
|
+
this.providers.unshift(provider);
|
|
345
|
+
}
|
|
346
|
+
configureOptions(options, callback) {
|
|
347
|
+
const configure = this.options.get(options.key);
|
|
348
|
+
this.options.set(options.key, options => callback(configure ? configure(options) : options));
|
|
349
|
+
}
|
|
350
|
+
getOptions(options) {
|
|
351
|
+
let result;
|
|
352
|
+
for (const provider of this.providers) {
|
|
353
|
+
const instance = provider.tryGet(options);
|
|
354
|
+
if (instance) {
|
|
355
|
+
result = instance;
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
result = this.mergeWithDefaultOptions(result || {}, options.defaultOptions);
|
|
360
|
+
const configure = this.options.get(options.key);
|
|
361
|
+
result = configure ? configure(result) : result;
|
|
362
|
+
let error;
|
|
363
|
+
if (!options.validate(result, err => error = err)) {
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
mergeWithDefaultOptions(options, defaultOptions) {
|
|
369
|
+
// this allows supporting partial options and will handle merging in any default values that were omitted
|
|
370
|
+
if (defaultOptions) {
|
|
371
|
+
// clone the options object and return a merged options instance
|
|
372
|
+
options = { ...options };
|
|
373
|
+
Object.keys(defaultOptions).forEach(key => {
|
|
374
|
+
if (options[key] === undefined) {
|
|
375
|
+
options[key] = defaultOptions[key];
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
return options;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS1jb2xsZWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZpY2UtY29sbGVjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFzR0EsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsYUFBYSxDQUF3Qix1QkFBdUIsQ0FBQyxDQUFDO0FBQ25HLE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBRyxhQUFhLENBQWtCLGlCQUFpQixDQUFDLENBQUM7QUFDakYsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsYUFBYSxDQUFxQixvQkFBb0IsQ0FBQyxDQUFDO0FBRTFGLE1BQU0sWUFBWSxHQUFHLGdCQUFnQixDQUFDO0FBQ3RDLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQztBQVN4QixnRkFBZ0Y7QUFDaEYsTUFBTSxVQUFVLE1BQU0sQ0FBQyxJQUFTO0lBQzVCLElBQUksQ0FBQyxLQUFLLENBQUMsd0JBQXNCLENBQUM7QUFDdEMsQ0FBQztBQUVELG1GQUFtRjtBQUNuRixNQUFNLFVBQVUsU0FBUyxDQUFDLElBQVM7SUFDL0IsSUFBSSxDQUFDLEtBQUssQ0FBQyw4QkFBeUIsQ0FBQztBQUN6QyxDQUFDO0FBRUQsbUZBQW1GO0FBQ25GLE1BQU0sVUFBVSxTQUFTLENBQUMsSUFBUztJQUMvQixJQUFJLENBQUMsS0FBSyxDQUFDLDhCQUF5QixDQUFDO0FBQ3pDLENBQUM7QUFJRCxNQUFNLFVBQVUsZ0JBQWdCLENBQUksWUFBNEM7SUFDNUUsTUFBTSxPQUFPLEdBQUcsT0FBTyxZQUFZLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLFlBQVksRUFBRSxDQUFDO0lBQ3hGLE1BQU0sVUFBVSxHQUFRLFVBQVUsTUFBVyxFQUFFLFdBQW1CLEVBQUUsY0FBc0I7UUFDdEYsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUN4QixNQUFNLElBQUks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
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
__exportStar(require("./module"), exports);
|
|
14
|
+
__exportStar(require("./service-collection"), exports);
|
|
15
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsMkNBQXlCO0FBQ3pCLHVEQUFxQyJ9
|
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { IOptions, IServiceCollection, IServiceRegistration } from "./service-collection";
|
|
2
|
+
export declare type ModuleConstructor<T extends IModule = IModule> = {
|
|
3
|
+
new (): T;
|
|
4
|
+
};
|
|
5
|
+
export declare type ModuleInstanceOrConstructor = IModule | ModuleConstructor;
|
|
6
|
+
export declare type ModuleDependency = ModuleInstanceOrConstructor | (() => Promise<ModuleInstanceOrConstructor>);
|
|
7
|
+
export declare type SettingsInitializer = {
|
|
8
|
+
/**
|
|
9
|
+
* Binds module settings to an options object; the options object gets bound to the settings path {module-name} or {module-name}/{section-name}.
|
|
10
|
+
* The section name parameter is optional and useful for binding to a section of the module's settings.
|
|
11
|
+
*/
|
|
12
|
+
readonly bindToOptions: <T>(options: IOptions<T>, sectionName?: string) => void;
|
|
13
|
+
};
|
|
14
|
+
declare type ConfigurationInitializer<T> = {
|
|
15
|
+
readonly register: (callback: (configurator: IModuleConfigurator) => T) => void;
|
|
16
|
+
};
|
|
17
|
+
declare type OptionsProvider = {
|
|
18
|
+
/**
|
|
19
|
+
* A helper function for getting an option instance from the current module settings.
|
|
20
|
+
* It's expected that the module also use bindToOptions to bind to the module's settings.
|
|
21
|
+
*/
|
|
22
|
+
readonly get: <T>(options: IOptions<T>) => T;
|
|
23
|
+
};
|
|
24
|
+
/** A collection of settings for one or more module keyed by the module name. */
|
|
25
|
+
export interface IModuleSettingsCollection {
|
|
26
|
+
readonly [name: string]: IModuleSettings | undefined;
|
|
27
|
+
}
|
|
28
|
+
/** A set of key/value settings for a single module. */
|
|
29
|
+
export interface IModuleSettings {
|
|
30
|
+
readonly [key: string]: any;
|
|
31
|
+
}
|
|
32
|
+
export interface IModule {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly dependencies?: ModuleDependency[];
|
|
35
|
+
initialize?(init: IModuleInitializer): void;
|
|
36
|
+
configureServices?(registration: IServiceRegistration): void;
|
|
37
|
+
configure?(configurator: IModuleConfigurator): void | Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export interface IModuleConfigurationType<T> {
|
|
40
|
+
readonly key: symbol;
|
|
41
|
+
}
|
|
42
|
+
export interface IModuleConfiguration {
|
|
43
|
+
get<T>(type: IModuleConfigurationType<T>): T;
|
|
44
|
+
}
|
|
45
|
+
export interface IModuleConfigurator {
|
|
46
|
+
readonly config: IModuleConfiguration;
|
|
47
|
+
readonly options: OptionsProvider;
|
|
48
|
+
readonly services: IServiceCollection;
|
|
49
|
+
readonly settings: IModuleSettings;
|
|
50
|
+
readonly next: () => Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export interface IModuleInitializer {
|
|
53
|
+
/** Gets a configuration initializer for a module configuration type. */
|
|
54
|
+
config<T>(type: IModuleConfigurationType<T>): ConfigurationInitializer<T>;
|
|
55
|
+
/** Gets a settings initializer for the current module. */
|
|
56
|
+
settings: SettingsInitializer;
|
|
57
|
+
}
|
|
58
|
+
/** A collection of loaded modules. */
|
|
59
|
+
export interface IModuleCollection {
|
|
60
|
+
/** The collection of services for the host. */
|
|
61
|
+
readonly services: IServiceCollection;
|
|
62
|
+
/** Gets the loaded module instance for the specified module constructor. */
|
|
63
|
+
getInstance<T extends IModule>(ctor: ModuleConstructor<T>): T;
|
|
64
|
+
}
|
|
65
|
+
export interface ILoadOptions {
|
|
66
|
+
readonly modules: ModuleInstanceOrConstructor[];
|
|
67
|
+
readonly settings?: IModuleSettingsCollection;
|
|
68
|
+
}
|
|
69
|
+
/** Creates a module configuration used to configure a module. */
|
|
70
|
+
export declare function createConfig<T>(): IModuleConfigurationType<T>;
|
|
71
|
+
export declare class ModuleLoadError extends Error {
|
|
72
|
+
constructor(message: string);
|
|
73
|
+
}
|
|
74
|
+
/** Handles initializing and loading modules. */
|
|
75
|
+
export declare class ModuleLoader {
|
|
76
|
+
private readonly services;
|
|
77
|
+
private readonly modules;
|
|
78
|
+
private settings;
|
|
79
|
+
private isLoaded?;
|
|
80
|
+
static load(modules: ModuleInstanceOrConstructor[]): Promise<IModuleCollection>;
|
|
81
|
+
static load(options: ILoadOptions): Promise<IModuleCollection>;
|
|
82
|
+
static configureServices(callback: (registration: IServiceRegistration) => void): ModuleLoader;
|
|
83
|
+
static useModules(modules: ModuleInstanceOrConstructor[]): ModuleLoader;
|
|
84
|
+
static useSettings(settings: IModuleSettingsCollection): ModuleLoader;
|
|
85
|
+
/**
|
|
86
|
+
* Loads the specified core modules into the manager. The load operation will discover
|
|
87
|
+
* the core module dependencies and then initialize/configure each module.
|
|
88
|
+
*
|
|
89
|
+
* This will first discover all dependent modules, create module instances, and sort the
|
|
90
|
+
* list of discovered modules by dependency (note: there is no guarantee of the order when creating
|
|
91
|
+
* module instances but each step against the discovered modules will execute against module dependents first).
|
|
92
|
+
*
|
|
93
|
+
* Module Steps:
|
|
94
|
+
*
|
|
95
|
+
* 1) Initialize
|
|
96
|
+
* 2) Configure Services
|
|
97
|
+
* 3) Configure
|
|
98
|
+
*/
|
|
99
|
+
load(): Promise<IModuleCollection>;
|
|
100
|
+
configureServices(callback: (registration: IServiceRegistration) => void): this;
|
|
101
|
+
useModules(modules: ModuleInstanceOrConstructor[]): this;
|
|
102
|
+
useSettings(settings: IModuleSettingsCollection): this;
|
|
103
|
+
private ensureNotLoaded;
|
|
104
|
+
private getSettingsForModule;
|
|
105
|
+
private expandAndSortModules;
|
|
106
|
+
private merge;
|
|
107
|
+
private isObject;
|
|
108
|
+
private isModule;
|
|
109
|
+
}
|
|
110
|
+
export {};
|