@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/dist/module.js ADDED
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ModuleLoader = exports.ModuleLoadError = exports.createConfig = void 0;
4
+ const service_collection_1 = require("./service-collection");
5
+ /** Creates a module configuration used to configure a module. */
6
+ function createConfig() {
7
+ return { key: Symbol() };
8
+ }
9
+ exports.createConfig = createConfig;
10
+ class ModuleLoadError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ Object.setPrototypeOf(this, ModuleLoadError.prototype);
14
+ }
15
+ }
16
+ exports.ModuleLoadError = ModuleLoadError;
17
+ /** Handles initializing and loading modules. */
18
+ class ModuleLoader {
19
+ constructor() {
20
+ this.services = new service_collection_1.ServiceMap();
21
+ this.modules = [];
22
+ this.settings = {};
23
+ }
24
+ static load(modulesOrOptions) {
25
+ const options = Array.isArray(modulesOrOptions) ? { modules: modulesOrOptions } : modulesOrOptions;
26
+ const loader = new ModuleLoader();
27
+ if (options.settings) {
28
+ loader.useSettings(options.settings);
29
+ }
30
+ return loader.useModules(options.modules).load();
31
+ }
32
+ static configureServices(callback) {
33
+ return new ModuleLoader().configureServices(callback);
34
+ }
35
+ static useModules(modules) {
36
+ return new ModuleLoader().useModules(modules);
37
+ }
38
+ static useSettings(settings) {
39
+ return new ModuleLoader().useSettings(settings);
40
+ }
41
+ /**
42
+ * Loads the specified core modules into the manager. The load operation will discover
43
+ * the core module dependencies and then initialize/configure each module.
44
+ *
45
+ * This will first discover all dependent modules, create module instances, and sort the
46
+ * list of discovered modules by dependency (note: there is no guarantee of the order when creating
47
+ * module instances but each step against the discovered modules will execute against module dependents first).
48
+ *
49
+ * Module Steps:
50
+ *
51
+ * 1) Initialize
52
+ * 2) Configure Services
53
+ * 3) Configure
54
+ */
55
+ async load() {
56
+ this.ensureNotLoaded();
57
+ this.isLoaded = true;
58
+ // get all modules and sort by dependencies
59
+ const loadedModules = await this.expandAndSortModules();
60
+ // initialize discovered modules
61
+ const loader = this;
62
+ const configs = new Map();
63
+ loadedModules.forEach(module => {
64
+ if (module.initialize) {
65
+ module.initialize({
66
+ config: type => ({
67
+ register: callback => configs.set(type.key, { callback, module })
68
+ }),
69
+ get settings() {
70
+ return {
71
+ bindToOptions: (options, sectionName) => {
72
+ loader.services.addOptionsProvider({
73
+ tryGet: (opt) => {
74
+ if (options === opt) {
75
+ const settings = loader.getSettingsForModule(module);
76
+ return sectionName ? settings[sectionName] : settings;
77
+ }
78
+ return undefined;
79
+ }
80
+ });
81
+ }
82
+ };
83
+ }
84
+ });
85
+ }
86
+ });
87
+ // configure the module services
88
+ for (const module of loadedModules) {
89
+ if (module.configureServices) {
90
+ module.configureServices(this.services);
91
+ }
92
+ }
93
+ this.services.freeze();
94
+ // lastly, configure the modules
95
+ const iterator = loadedModules[Symbol.iterator]();
96
+ const next = async () => {
97
+ for (const module of iterator) {
98
+ await configure(module);
99
+ }
100
+ };
101
+ const self = this;
102
+ const configure = (module) => module.configure && module.configure({
103
+ services: this.services,
104
+ settings: this.getSettingsForModule(module),
105
+ get options() {
106
+ return {
107
+ get: (options) => self.services.getOptions(options)
108
+ };
109
+ },
110
+ get config() {
111
+ return {
112
+ get: (type) => {
113
+ const item = configs.get(type.key);
114
+ if (!item) {
115
+ throw new Error(`Config ${type.key.toString()} not found`);
116
+ }
117
+ return item.callback({
118
+ ...this,
119
+ // need to grab the module's settings that is being configured
120
+ settings: loader.getSettingsForModule(item.module)
121
+ });
122
+ }
123
+ };
124
+ },
125
+ next
126
+ });
127
+ // invoke the iterator to start configuring the modules
128
+ return next().then(() => ({
129
+ services: this.services,
130
+ getInstance: (ctor) => {
131
+ const result = loadedModules.find(module => module instanceof ctor);
132
+ if (!result) {
133
+ throw new Error("Module instance not found");
134
+ }
135
+ return result;
136
+ }
137
+ }));
138
+ }
139
+ configureServices(callback) {
140
+ this.ensureNotLoaded();
141
+ callback(this.services);
142
+ return this;
143
+ }
144
+ useModules(modules) {
145
+ this.ensureNotLoaded();
146
+ this.modules.push(...modules);
147
+ return this;
148
+ }
149
+ useSettings(settings) {
150
+ this.ensureNotLoaded();
151
+ this.settings = this.merge(settings, this.settings);
152
+ return this;
153
+ }
154
+ ensureNotLoaded() {
155
+ if (this.isLoaded) {
156
+ throw new Error("Modules have already been loaded.");
157
+ }
158
+ }
159
+ getSettingsForModule(module) {
160
+ return this.settings[module.name] || {};
161
+ }
162
+ async expandAndSortModules() {
163
+ const instances = new Map();
164
+ const sorted = [];
165
+ const visited = {};
166
+ const getInstance = async (dependency) => {
167
+ if (typeof dependency === "function") {
168
+ let instance = instances.get(dependency);
169
+ if (!instance) {
170
+ try {
171
+ instance = new dependency();
172
+ if (instance.constructor === dependency) {
173
+ // save the instance if the dependency is a constructor
174
+ instances.set(dependency, instance);
175
+ }
176
+ }
177
+ catch {
178
+ // the dependency is a non-constructble function so invoke and assume the return will be a promise and use Promise.resolve to resolve it
179
+ const instanceOrCtor = await Promise.resolve(dependency());
180
+ instance = await getInstance(instanceOrCtor);
181
+ }
182
+ }
183
+ // resolve incase the dependency is a function that returned a promise
184
+ return instance;
185
+ }
186
+ if (typeof dependency === "object") {
187
+ if (!this.isModule(dependency)) {
188
+ throw new ModuleLoadError(`Object (${dependency.constructor.name}) is not a module.`);
189
+ }
190
+ const ctor = dependency.constructor;
191
+ if (ctor !== Object.prototype.constructor) {
192
+ if (instances.has(ctor)) {
193
+ throw new ModuleLoadError(`Duplicate module instances ${dependency.name}.`);
194
+ }
195
+ instances.set(ctor, dependency);
196
+ }
197
+ return dependency;
198
+ }
199
+ throw new ModuleLoadError(`Invalid dependency type (${typeof dependency}).`);
200
+ };
201
+ const visit = async (dependency, ancestors) => {
202
+ const module = await getInstance(dependency);
203
+ if (visited[module.name]) {
204
+ return;
205
+ }
206
+ if (!ancestors) {
207
+ ancestors = {};
208
+ }
209
+ if (ancestors[module.name]) {
210
+ throw new ModuleLoadError(`Circular dependency has been detected with module ${module.name}`);
211
+ }
212
+ ancestors[module.name] = true;
213
+ if (module.dependencies) {
214
+ for (const dependency of module.dependencies) {
215
+ await visit(dependency, ancestors);
216
+ }
217
+ }
218
+ visited[module.name] = true;
219
+ // this performs a depth-first topological sort but instead of inserting
220
+ // to the front, push the module to the back of the list so that dependencies
221
+ // come first
222
+ sorted.push(module);
223
+ };
224
+ for (const module of this.modules) {
225
+ await visit(module);
226
+ }
227
+ return sorted;
228
+ }
229
+ merge(source, target) {
230
+ if (this.isObject(source) && this.isObject(target)) {
231
+ for (const key in source) {
232
+ if (source[key] === undefined) {
233
+ // do not merge if the source value is undefined
234
+ continue;
235
+ }
236
+ target = {
237
+ ...target,
238
+ [key]: this.isObject(source[key]) ? this.merge(source[key], target[key] || {}) : source[key]
239
+ };
240
+ }
241
+ }
242
+ return target;
243
+ }
244
+ isObject(obj) {
245
+ return typeof obj === "object" && !Array.isArray(obj);
246
+ }
247
+ isModule(obj) {
248
+ // a module only requires a name so that's all we can really check for
249
+ return typeof obj === "object" && obj.name !== undefined;
250
+ }
251
+ }
252
+ exports.ModuleLoader = ModuleLoader;
253
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL21vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2REFBc0c7QUFxRnRHLGlFQUFpRTtBQUNqRSxTQUFnQixZQUFZO0lBQ3hCLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQztBQUM3QixDQUFDO0FBRkQsb0NBRUM7QUFFRCxNQUFhLGVBQWdCLFNBQVEsS0FBSztJQUN0QyxZQUFZLE9BQWU7UUFDdkIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsZUFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzNELENBQUM7Q0FDSjtBQUxELDBDQUtDO0FBRUQsZ0RBQWdEO0FBQ2hELE1BQWEsWUFBWTtJQUF6QjtRQUNxQixhQUFRLEdBQUcsSUFBSSwrQkFBVSxFQUFFLENBQUM7UUFDNUIsWUFBTyxHQUFrQyxFQUFFLENBQUM7UUFDckQsYUFBUSxHQUE4QixFQUFFLENBQUM7SUFvUnJELENBQUM7SUEvUUcsTUFBTSxDQUFDLElBQUksQ0FBQyxnQkFBOEQ7UUFDdEUsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQztRQUNuRyxNQUFNLE1BQU0sR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBRWxDLElBQUksT0FBTyxDQUFDLFFBQVEsRUFBRTtZQUNsQixNQUFNLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztTQUN4QztRQUVELE9BQU8sTUFBTSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDckQsQ0FBQztJQUVELE1BQU0sQ0FBQyxpQkFBaUIs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
@@ -0,0 +1,146 @@
1
+ export declare type ValidateOptionsCallback<T> = (obj: T, invalid: (err: OptionsValidationError) => void) => void;
2
+ export declare type ValidateOptionsFailCallback = (err: OptionsValidationError) => void;
3
+ declare type Constructor<T> = {
4
+ new (...args: any[]): T;
5
+ };
6
+ declare type NonOptionalKeys<T> = {
7
+ [K in keyof T]-?: undefined extends T[K] ? never : K;
8
+ }[keyof T];
9
+ /** Defines an object that supports a dispose function; scoped service instances that implement dispose will get invoked when the scoped container is cleaned up. */
10
+ export interface IDisposable {
11
+ dispose(): void;
12
+ }
13
+ export interface IInjectable<T> {
14
+ readonly key: string;
15
+ readonly factory?: (services: IServiceCollection) => T;
16
+ (...args: any[]): void;
17
+ }
18
+ export interface IInjectableOptions<T> {
19
+ readonly key: string;
20
+ readonly factory?: (services: IServiceCollection) => T;
21
+ }
22
+ export interface IOptions<T> extends IInjectable<T> {
23
+ readonly defaultOptions?: T;
24
+ readonly register: (callback: ValidateOptionsCallback<T>) => void;
25
+ readonly require: (...props: NonOptionalKeys<T>[]) => void;
26
+ readonly validate: (obj: T, fail: ValidateOptionsFailCallback) => boolean;
27
+ }
28
+ export interface IService<T> extends IInjectable<T> {
29
+ }
30
+ export interface IInstantiationService {
31
+ createInstance<T>(ctor: Constructor<T>): T;
32
+ }
33
+ export interface IOptionsService {
34
+ /** Adds an options provider to the service. */
35
+ addOptionsProvider(provider: IOptionsProvider): void;
36
+ /** Registers a callback that gets invoked to configure/modify an options instance when one has been requested. */
37
+ configureOptions<T>(options: IOptions<T>, callback: (options: T) => T): void;
38
+ /** Gets an instance of the specified options. */
39
+ getOptions<T>(options: IOptions<T>): T;
40
+ }
41
+ export interface IOptionsProvider {
42
+ tryGet<T>(id: IOptions<T>): T | undefined;
43
+ }
44
+ export interface IServiceRegistration {
45
+ /** Registers a service using its required scope. Note: a service class must define a required scope decorator. */
46
+ register<T, TInstance extends T>(service: IService<T>, ctor: Constructor<TInstance>): void;
47
+ /** Registers a singleton instance that lives within the collection and is available to all child scopes. Note: if the instance implements IDisposable it will not be disposed automatically. */
48
+ registerInstance<T, TInstance extends T>(service: IService<T>, instance: TInstance): void;
49
+ /** Registers a service that gets created once per service collection scope. */
50
+ registerScoped<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): void;
51
+ /** Registers a service that gets created once and is available to all child scopes. */
52
+ registerSingleton<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): void;
53
+ /** Registers a service that gets created each time the service is requested from a collection. */
54
+ registerTransient<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): void;
55
+ /** Attempts to register a service using its required scope but only if a service has not already been registered. Note: a service class must define a required scope decorator. */
56
+ tryRegister<T, TInstance extends T>(service: IService<T>, ctor: Constructor<TInstance>): boolean;
57
+ /** Attempts to register a singleton instance that lives within the collection and is available to all child scopes. Note: if the instance implements IDisposable it will not be disposed automatically. */
58
+ tryRegisterInstance<T, TInstance extends T>(service: IService<T>, instance: TInstance): boolean;
59
+ /** Attempts to register a service that gets created once per service collection scope. */
60
+ tryRegisterScoped<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): boolean;
61
+ /** Attempts to register a service that gets created once and is available to all child scopes. */
62
+ tryRegisterSingleton<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): boolean;
63
+ /** Attempts to register a service that gets created each time the service is requested from a collection. */
64
+ tryRegisterTransient<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): boolean;
65
+ }
66
+ export interface IServiceCollection {
67
+ /** Creates a scoped collection. */
68
+ createScope(): IScopedServiceCollection;
69
+ /** Gets an instance of the registered service. */
70
+ get<T>(serviceOrKey: IService<T> | string): T;
71
+ /** True if a service has been registered. */
72
+ has<T>(serviceOrKey: IService<T> | string): boolean;
73
+ /** Gets an instance of the specified service if one has been registered or undefined if not. */
74
+ tryGet<T>(serviceOrKey: IService<T> | string): T | undefined;
75
+ }
76
+ export interface IServiceFactory<T> {
77
+ create(services: IServiceCollection): T;
78
+ }
79
+ export interface IScopedServiceCollection extends IServiceCollection, IDisposable {
80
+ }
81
+ export declare const IInstantiationService: IService<IInstantiationService>;
82
+ export declare const IOptionsService: IService<IOptionsService>;
83
+ export declare const IServiceCollection: IService<IServiceCollection>;
84
+ /** Class decorator identifying the required scope for a service as 'scoped'. */
85
+ export declare function Scoped(ctor: any): void;
86
+ /** Class decorator identifying the required scope for a service as 'singleton'. */
87
+ export declare function Singleton(ctor: any): void;
88
+ /** Class decorator identifying the required scope for a service as 'transient'. */
89
+ export declare function Transient(ctor: any): void;
90
+ export declare function createInjectable<T>(key: string): IInjectable<T>;
91
+ export declare function createInjectable<T>(options: IInjectableOptions<T>): IInjectable<T>;
92
+ export declare function createOptions<T>(key: string, defaultOptions?: T): IOptions<T>;
93
+ export declare function createService<T>(key: string): IService<T>;
94
+ /** Represents an error that has occurred while trying to create an object instance. */
95
+ export declare class ObjectCreateError extends Error {
96
+ readonly inner: Error;
97
+ constructor(message: string, inner: Error);
98
+ }
99
+ /**
100
+ * A service factory that will create a single instance and return the same instance everytime create is invoked.
101
+ * This is useful for singleton services that implement multiple service interfaces.
102
+ */
103
+ export declare class SingletonServiceFactory<T> implements IServiceFactory<T> {
104
+ private readonly ctorOrFactory;
105
+ private instance?;
106
+ constructor(ctorOrFactory: Constructor<T> | IServiceFactory<T>);
107
+ create(services: IServiceCollection): T;
108
+ }
109
+ export declare class ServiceMap implements IServiceRegistration, IServiceCollection, IOptionsService, IInstantiationService {
110
+ private readonly services;
111
+ private isFrozen?;
112
+ constructor();
113
+ addOptionsProvider(provider: IOptionsProvider): void;
114
+ configureOptions<T>(options: IOptions<T>, callback: (options: T) => T): void;
115
+ createInstance<T>(ctor: Constructor<T>): T;
116
+ createScope(): IScopedServiceCollection;
117
+ getOptions<T>(options: IOptions<T>): T;
118
+ register<T, TInstance extends T>(service: IService<T>, ctor: Constructor<TInstance>): void;
119
+ registerInstance<T, TInstance extends T>(service: IService<T>, instance: TInstance): void;
120
+ registerScoped<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): void;
121
+ registerSingleton<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): void;
122
+ registerTransient<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): void;
123
+ tryRegister<T, TInstance extends T>(service: IService<T>, ctor: Constructor<TInstance>): boolean;
124
+ tryRegisterInstance<T, TInstance extends T>(service: IService<T>, instance: TInstance): boolean;
125
+ tryRegisterScoped<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): boolean;
126
+ tryRegisterSingleton<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): boolean;
127
+ tryRegisterTransient<T, TInstance extends T>(service: IService<T>, ctorOrFactory: Constructor<TInstance> | IServiceFactory<TInstance>): boolean;
128
+ get<T>(serviceOrKey: IService<T> | string): T;
129
+ has<T>(serviceOrKey: IService<T> | string): boolean;
130
+ tryGet<T>(serviceOrKey: IService<T> | string): T | undefined;
131
+ /** Prevents items from being registered with the serivce map. */
132
+ freeze(): void;
133
+ private registerService;
134
+ private registerEntry;
135
+ private checkFactoryInstance;
136
+ private checkInstanceScope;
137
+ private getOrCreateServiceInstance;
138
+ private getOrCreateInjectable;
139
+ private createServiceInstance;
140
+ private createObjectInstance;
141
+ }
142
+ /** Represents an error for an options object instance that failed validation. */
143
+ export declare class OptionsValidationError extends Error {
144
+ constructor(message: string);
145
+ }
146
+ export {};