UNPKG

@xoid/feature

Version:

A plugin system to compose JavaScript classes

57 lines (55 loc) 2 kB
const defaultFrom = (a) => { throw new Error('`this.from` cannot be used outside the `compose` context.'); }; const current = { from: defaultFrom, }; class Feature { constructor(options, from) { this.from = function (a) { return current.from(a); }; this.getOptions = (defaultOptions) => (Object.assign(Object.assign({}, defaultOptions), this.externalOptions)); this.options = options; this.externalOptions = options; if (from) this.from = from; } } const traversePrototypeChain = (instance, fn) => { const prototype = Object.getPrototypeOf(instance); const { constructor } = prototype; if (constructor === Feature || constructor === Function) return; fn(constructor); traversePrototypeChain(prototype, fn); }; function registerFeature(contextMap, instance) { traversePrototypeChain(instance, (ctor) => contextMap.set(ctor, instance)); if (instance.id) contextMap.set(instance.id, instance); } const compose = (config, getResult) => (options, overrides) => { const contextMap = new Map(); function from(input) { const output = contextMap.get(typeof input === 'object' ? input.id : input); if (!output) { throw new Error(`Dependency '${input.name}' was not found in '${this.constructor.name}'.`); } return output; } current.from = from; // @ts-ignore if (overrides) config = [...config, ...overrides]; config .map((item) => { const instance = new item(options, from); registerFeature(contextMap, instance); return instance; }) .forEach((instance) => { var _a; return (_a = instance === null || instance === void 0 ? void 0 : instance.main) === null || _a === void 0 ? void 0 : _a.call(instance); }); current.from = defaultFrom; return getResult(from, {}); }; export { Feature, compose };