UNPKG

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
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