@injectable-ts/core
Version:
Purely-functional strictly-typed IoC/DI for TypeScript
113 lines (107 loc) • 3.66 kB
JavaScript
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 };