UNPKG

di-tory

Version:

Compose applications with dependency injection

92 lines (91 loc) 4.15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createModule = void 0; const Stack_js_1 = require("./stack/Stack.js"); const DependencyResolutionError_js_1 = require("./DependencyResolutionError.js"); const async_scope_js_1 = require("./async-scope.js"); const objects_js_1 = require("./objects.js"); const scope_js_1 = require("./scope.js"); const singletonInstances = new Map(); const createModule = (privateResolvers, publicResolvers, initializers, params = {}) => { const resolvers = Object.assign(Object.assign({}, privateResolvers), publicResolvers); const resolutionStack = new Stack_js_1.Stack(); const moduleInstances = new Map(); const publicNames = new Set((0, objects_js_1.propertyKeys)(publicResolvers)); const self = new Proxy(Object.create(null), { get(_, prop) { return resolve(prop); }, }); const ensureAsyncInstances = () => { const store = (0, async_scope_js_1.getStore)(); const asyncInstances = store.get(self); if (asyncInstances != null) return asyncInstances; const newInstances = new Map(); store.set(self, newInstances); return newInstances; }; let transientInstances; const getInstances = ({ scope }) => { const normalizedScope = (0, scope_js_1.normalizeScope)(scope); return ( // prettier-ignore normalizedScope === 'async' ? ensureAsyncInstances() : normalizedScope === 'singleton' ? singletonInstances : normalizedScope === 'transient' ? transientInstances : moduleInstances); }; const updateParentScope = (scope) => { const parentItem = resolutionStack.peek(); if (parentItem == null) return; const parent = resolvers[parentItem]; const newParentScope = (0, scope_js_1.overrideScope)(parent.scope, scope); if (newParentScope != null) parent.scope = newParentScope; }; const resolve = (item) => { var _a; if (resolutionStack.length === 0) { transientInstances = new Map(); } const resolver = resolvers[item]; if (resolver == null) throw new DependencyResolutionError_js_1.DependencyResolutionError(DependencyResolutionError_js_1.DependencyResolutionErrorCode.ResolverIsNotDefined, resolutionStack.toStringArray(), String(item)); const instances = getInstances(resolver); if (instances.has(item)) return instances.get(item); const currentStack = resolutionStack.toStringArray(); try { resolutionStack.push(item); } catch (_b) { throw new DependencyResolutionError_js_1.DependencyResolutionError(DependencyResolutionError_js_1.DependencyResolutionErrorCode.CircularDependencyFailure, resolutionStack.toStringArray(), String(item)); } let instance; try { instance = resolver(self, params); } catch (err) { if (err instanceof DependencyResolutionError_js_1.DependencyResolutionError) throw err; throw new DependencyResolutionError_js_1.DependencyResolutionError(DependencyResolutionError_js_1.DependencyResolutionErrorCode.InstantiationFailure, currentStack, String(item), err); } resolutionStack.pop(); updateParentScope(resolver.scope); getInstances(resolver).set(item, instance); if (resolutionStack.length === 0) { (_a = initializers === null || initializers === void 0 ? void 0 : initializers[item]) === null || _a === void 0 ? void 0 : _a.call(instance, self, params); } return instance; }; return new Proxy(Object.create(null), { get(_, prop) { if (publicNames.has(prop)) return resolve(prop); throw new DependencyResolutionError_js_1.DependencyResolutionError(DependencyResolutionError_js_1.DependencyResolutionErrorCode.PrivateMemberAccessFailure, [], String(prop)); }, }); }; exports.createModule = createModule;