UNPKG

@injectable-ts/core

Version:

Purely-functional strictly-typed IoC/DI for TypeScript

113 lines (107 loc) 3.66 kB
import { memoMany } from '@frp-ts/utils'; const isRecord = /* @__NO_SIDE_EFFECTS__ */ (input) => typeof input === 'object' && input !== null && !Array.isArray(input) && !(input instanceof Date) && !(input instanceof Map) && !(input instanceof Set) && !(input instanceof WeakSet) && !(input instanceof WeakMap); const isPropertyKey = /* @__NO_SIDE_EFFECTS__ */ (input) => typeof input === 'string' || typeof input === 'number' || typeof input === 'symbol'; /* @__NO_SIDE_EFFECTS__ */ function injectable(...args) { return isRecord(args[0]) || (isPropertyKey(args[0]) && isRecord(args[1])) ? createRecordInjectable(args) : createListInjectable(args); } function createRecordInjectable(args) { const name = isPropertyKey(args[0]) ? args[0] : undefined; let injectables; let project; if (isRecord(args[0])) { // eslint-disable-next-line no-restricted-syntax injectables = args[0]; // eslint-disable-next-line no-restricted-syntax project = args[1]; } else { // eslint-disable-next-line no-restricted-syntax injectables = args[1]; // eslint-disable-next-line no-restricted-syntax project = args[2]; } let cachedResult; let cachedArg; let hasValue = false; const keys = Object.keys(injectables); const update = (arg) => { cachedResult = project(arg); hasValue = true; cachedArg = arg; }; const f = (dependencies) => { if (name !== undefined) { const override = dependencies[name]; if (override !== undefined) { return override; } } const values = {}; for (const key of keys) { values[key] = injectables[key](dependencies); } if (hasValue) { for (const key of keys) { if (cachedArg[key] !== values[key]) { update(values); return cachedResult; } } return cachedResult; } else { update(values); return cachedResult; } }; f.key = name; return f; } function createListInjectable(args) { const name = isPropertyKey(args[0]) ? args[0] : undefined; const injectables = // eslint-disable-next-line no-restricted-syntax args.slice(name !== undefined ? 1 : 0, args.length - 1); // eslint-disable-next-line no-restricted-syntax const project = args[args.length - 1]; const memoizedProject = memoMany(project); const f = (dependencies) => { if (name !== undefined) { const override = dependencies[name]; if (override !== undefined) { return override; } } const values = injectables.map((injectable) => injectable(dependencies)); return memoizedProject(...values); }; f.key = name; return f; } const provide = /* @__NO_SIDE_EFFECTS__ */ (input) => () => (outerDependencies) => (innerDependencies) => // eslint-disable-next-line no-restricted-syntax input(Object.assign(Object.assign({}, outerDependencies), innerDependencies)); const TOKEN_ACCESSOR_KEY = '@injectable-ts/core//TOKEN_ACCESSOR'; /* @__NO_SIDE_EFFECTS__ */ function token(name) { return () => { const f = (dependencies) => { const accessor = dependencies[TOKEN_ACCESSOR_KEY]; return accessor ? accessor(dependencies, name) : dependencies[name]; }; f.key = name; return f; }; } export { TOKEN_ACCESSOR_KEY, injectable, provide, token };