contexify
Version:
A TypeScript library providing a powerful dependency injection container with context-based IoC capabilities, inspired by LoopBack's Context system.
125 lines • 4.61 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 { Context } from "../context/context.js";
import { resolveInjectedArguments } from "../resolution/resolver.js";
import createDebugger from "../utils/debug.js";
import { transformValueOrPromise } from "../utils/value-promise.js";
import { invokeMethodWithInterceptors } from "./interceptor.js";
const debug = createDebugger("contexify:invocation");
const getTargetName = DecoratorFactory.getTargetName;
class InvocationContext extends Context {
static {
__name(this, "InvocationContext");
}
target;
methodName;
args;
source;
/**
* Construct a new instance of `InvocationContext`
* @param parent - Parent context, such as the RequestContext
* @param target - Target class (for static methods) or prototype/object
* (for instance methods)
* @param methodName - Method name
* @param args - An array of arguments
*/
constructor(parent, target, methodName, args, source) {
super(parent), this.target = target, this.methodName = methodName, this.args = args, this.source = source;
}
/**
* The target class, such as `OrderController`
*/
get targetClass() {
return typeof this.target === "function" ? this.target : this.target.constructor;
}
/**
* The target name, such as `OrderController.prototype.cancelOrder`
*/
get targetName() {
return getTargetName(this.target, this.methodName);
}
/**
* Description of the invocation
*/
get description() {
const source = this.source == null ? "" : `${this.source} => `;
return `InvocationContext(${this.name}): ${source}${this.targetName}`;
}
toString() {
return this.description;
}
/**
* Assert the method exists on the target. An error will be thrown if otherwise.
* @param context - Invocation context
*/
assertMethodExists() {
const targetWithMethods = this.target;
if (typeof targetWithMethods[this.methodName] !== "function") {
const targetName = getTargetName(this.target, this.methodName);
assert(false, `Method ${targetName} not found`);
}
return targetWithMethods;
}
/**
* Invoke the target method with the given context
* @param context - Invocation context
* @param options - Options for the invocation
*/
invokeTargetMethod(options = {
skipParameterInjection: true
}) {
const targetWithMethods = this.assertMethodExists();
if (!options.skipParameterInjection) {
return invokeTargetMethodWithInjection(this, targetWithMethods, this.methodName, this.args, options.session);
}
return invokeTargetMethod(this, targetWithMethods, this.methodName, this.args);
}
}
function invokeMethod(target, method, ctx, nonInjectedArgs = [], options = {}) {
if (options.skipInterceptors) {
if (options.skipParameterInjection) {
return invokeTargetMethod(ctx, target, method, nonInjectedArgs);
}
return invokeTargetMethodWithInjection(ctx, target, method, nonInjectedArgs, options.session);
}
return invokeMethodWithInterceptors(ctx, target, method, nonInjectedArgs, options);
}
__name(invokeMethod, "invokeMethod");
function invokeTargetMethodWithInjection(ctx, target, method, nonInjectedArgs, session) {
const methodName = getTargetName(target, method);
if (debug.enabled) {
debug("Invoking method %s", methodName);
if (nonInjectedArgs?.length) {
debug("Non-injected arguments:", nonInjectedArgs);
}
}
const argsOrPromise = resolveInjectedArguments(target, method, ctx, session, nonInjectedArgs);
const targetWithMethods = target;
assert(typeof targetWithMethods[method] === "function", `Method ${method} not found`);
return transformValueOrPromise(argsOrPromise, (args) => {
if (debug.enabled) {
debug("Injected arguments for %s:", methodName, args);
}
return invokeTargetMethod(ctx, targetWithMethods, method, args);
});
}
__name(invokeTargetMethodWithInjection, "invokeTargetMethodWithInjection");
function invokeTargetMethod(_ctx, target, methodName, args) {
const targetWithMethods = target;
if (debug.enabled) {
debug("Invoking method %s", getTargetName(target, methodName), args);
}
const result = targetWithMethods[methodName](...args);
if (debug.enabled) {
debug("Method invoked: %s", getTargetName(target, methodName), result);
}
return result;
}
__name(invokeTargetMethod, "invokeTargetMethod");
export {
InvocationContext,
invokeMethod
};
//# sourceMappingURL=invocation.js.map