contexify
Version:
A TypeScript library providing a powerful dependency injection container with context-based IoC capabilities, inspired by LoopBack's Context system.
128 lines • 5.09 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import assert from "assert";
import { DecoratorFactory } from "metarize";
import { isBindingAddress } from "../binding/binding-filter.js";
import { describeInjectedArguments, describeInjectedProperties } from "../inject/inject.js";
import createDebugger from "../utils/debug.js";
import { resolveList, resolveMap, transformValueOrPromise } from "../utils/value-promise.js";
import { ResolutionError, ResolutionSession } from "./resolution-session.js";
const debug = createDebugger("contexify:resolver");
const getTargetName = DecoratorFactory.getTargetName;
function instantiateClass(ctor, ctx, session, nonInjectedArgs) {
if (debug.enabled) {
debug("Instantiating %s", getTargetName(ctor));
if (nonInjectedArgs?.length) {
debug("Non-injected arguments:", nonInjectedArgs);
}
}
const argsOrPromise = resolveInjectedArguments(ctor, "", ctx, session, nonInjectedArgs);
const propertiesOrPromise = resolveInjectedProperties(ctor, ctx, session);
const inst = transformValueOrPromise(argsOrPromise, (args) => {
if (debug.enabled) {
debug("Injected arguments for %s():", ctor.name, args);
}
return new ctor(...args);
});
return transformValueOrPromise(propertiesOrPromise, (props) => {
if (debug.enabled) {
debug("Injected properties for %s:", ctor.name, props);
}
return transformValueOrPromise(inst, (obj) => Object.assign(obj, props));
});
}
__name(instantiateClass, "instantiateClass");
function resolveContext(ctx, injection, session) {
const currentBinding = session?.currentBinding;
if (currentBinding == null) {
return ctx;
}
const isConstructorOrPropertyInjection = (
// constructor injection
!injection.member || // property injection
typeof injection.methodDescriptorOrParameterIndex !== "number"
);
if (isConstructorOrPropertyInjection) {
ctx = ctx.getResolutionContext(currentBinding);
}
return ctx;
}
__name(resolveContext, "resolveContext");
function resolve(ctx, injection, session) {
if (debug.enabled) {
debug("Resolving an injection:", ResolutionSession.describeInjection(injection));
}
ctx = resolveContext(ctx, injection, session);
const resolved = ResolutionSession.runWithInjection((s) => {
if (injection.resolve) {
return injection.resolve(ctx, injection, s);
}
assert(isBindingAddress(injection.bindingSelector), "The binding selector must be an address (string or BindingKey)");
const key = injection.bindingSelector;
const options = {
session: s,
...injection.metadata
};
return ctx.getValueOrPromise(key, options);
}, injection, session);
return resolved;
}
__name(resolve, "resolve");
function resolveInjectedArguments(target, method, ctx, session, nonInjectedArgs) {
if (debug.enabled) {
debug("Resolving injected arguments for %s", getTargetName(target, method));
}
const targetWithMethods = target;
if (method) {
assert(typeof targetWithMethods[method] === "function", `Method ${method} not found`);
}
const injectedArgs = describeInjectedArguments(target, method);
const extraArgs = nonInjectedArgs ?? [];
let argLength = DecoratorFactory.getNumberOfParameters(target, method);
const numberOfInjected = injectedArgs.filter((i) => i != null).length;
if (argLength < numberOfInjected + extraArgs.length) {
argLength = numberOfInjected + extraArgs.length;
}
let nonInjectedIndex = 0;
return resolveList(new Array(argLength), (_val, ix) => {
const injection = ix < injectedArgs.length ? injectedArgs[ix] : void 0;
if (injection == null || !injection.bindingSelector && !injection.resolve) {
if (nonInjectedIndex < extraArgs.length) {
return extraArgs[nonInjectedIndex++];
}
const name = getTargetName(target, method, ix);
throw new ResolutionError(`The argument '${name}' is not decorated for dependency injection but no value was supplied by the caller. Did you forget to apply @inject() to the argument?`, {
context: ctx,
options: {
session
}
});
}
return resolve(
ctx,
injection,
// Clone the session so that multiple arguments can be resolved in parallel
ResolutionSession.fork(session)
);
});
}
__name(resolveInjectedArguments, "resolveInjectedArguments");
function resolveInjectedProperties(constructor, ctx, session) {
if (debug.enabled) {
debug("Resolving injected properties for %s", getTargetName(constructor));
}
const injectedProperties = describeInjectedProperties(constructor.prototype);
return resolveMap(injectedProperties, (injection) => resolve(
ctx,
injection,
// Clone the session so that multiple properties can be resolved in parallel
ResolutionSession.fork(session)
));
}
__name(resolveInjectedProperties, "resolveInjectedProperties");
export {
instantiateClass,
resolveInjectedArguments,
resolveInjectedProperties
};
//# sourceMappingURL=resolver.js.map