Helper functions for working with dynamic imports, string-based module references, and creating callable functions from class constructors. These utilities enable flexible module loading patterns commonly used in web frameworks.
Creates callable functions from class constructors and method names for dynamic invocation.
/**
* The moduleCaller works around a very specific pattern we use with
* AdonisJS, ie to construct classes and call methods using the
* container.
*/
function moduleCaller(target: Constructor<any>, method: string): {
toCallable<T>(containerOrResolver: Container<any> | ContainerResolver<any>): ModuleCallable<T, any[]>;
toHandleMethod<T>(containerOrResolver: Container<any> | ContainerResolver<any>): ModuleHandler<T, any[]>;
};Usage Examples:
import { moduleCaller, Container, inject } from "@adonisjs/fold";
@inject()
class HomeController {
constructor(private logger: Logger) {}
async index(request: Request) {
this.logger.info("Home page accessed");
return { message: "Welcome to home page" };
}
async show(request: Request, id: string) {
this.logger.info(`Showing item ${id}`);
return { id, item: "details" };
}
}
const container = new Container();
container.singleton("logger", () => new Logger());
// Create callable function
const homeIndexCallable = moduleCaller(HomeController, "index")
.toCallable(container);
// Create handler object
const homeShowHandler = moduleCaller(HomeController, "show")
.toHandleMethod(container);
// Use callable function
const result1 = await homeIndexCallable(request);
// Use handler object
const result2 = await homeShowHandler.handle(request, "123");Creates callable functions from lazy import functions and method names for dynamic module loading.
/**
* The moduleImporter module works around a very specific pattern we use
* with AdonisJS, ie to lazy load modules by wrapping import calls inside
* a callback.
*/
function moduleImporter(
importFn: () => Promise<{ default: Constructor<any> }>,
method: string
): {
toCallable<T>(containerOrResolver: Container<any> | ContainerResolver<any>): ModuleCallable<T, any[]>;
toHandleMethod<T>(containerOrResolver: Container<any> | ContainerResolver<any>): ModuleHandler<T, any[]>;
};Usage Examples:
import { moduleImporter, Container } from "@adonisjs/fold";
const container = new Container();
// Lazy import middleware
const authMiddlewareCallable = moduleImporter(
() => import("#middleware/auth"),
"handle"
).toCallable(container);
const corsMiddlewareHandler = moduleImporter(
() => import("#middleware/cors"),
"handle"
).toHandleMethod(container);
// Dynamic middleware registration
const middlewares = [
() => import("#middleware/auth"),
() => import("#middleware/cors"),
() => import("#middleware/logging")
];
const callableMiddlewares = middlewares.map(importFn =>
moduleImporter(importFn, "handle").toCallable(container)
);
// Execute middleware chain
for (const middleware of callableMiddlewares) {
await middleware(request, response);
}Parses and handles string-based module expressions for dynamic module resolution.
/**
* The moduleExpression module works around a very specific pattern we use
* with AdonisJS, ie to bind modules as string.
*/
function moduleExpression(expression: string, parentURL: URL | string): {
parse(): [string, string];
toCallable<T>(containerOrResolver: Container<any> | ContainerResolver<any>): ModuleCallable<T, any[]>;
toHandleMethod<T>(containerOrResolver: Container<any> | ContainerResolver<any>): ModuleHandler<T, any[]>;
};Usage Examples:
import { moduleExpression, Container } from "@adonisjs/fold";
const container = new Container();
// Parse module expressions
const [modulePath, methodName] = moduleExpression(
"#controllers/users_controller.index",
import.meta.url
).parse();
// Returns: ["#controllers/users_controller", "index"]
// Default method name
const [path, method] = moduleExpression(
"#controllers/users_controller",
import.meta.url
).parse();
// Returns: ["#controllers/users_controller", "handle"]
// Create callable from expression
const userIndexCallable = moduleExpression(
"#controllers/users_controller.index",
import.meta.url
).toCallable(container);
const userCreateHandler = moduleExpression(
"#controllers/users_controller.create",
import.meta.url
).toHandleMethod(container);
// Route binding with expressions
const routes = [
{ path: "/users", handler: "#controllers/users_controller.index" },
{ path: "/users/:id", handler: "#controllers/users_controller.show" },
{ path: "/posts", handler: "#controllers/posts_controller.index" }
];
// Convert expressions to callables
const routeHandlers = routes.map(route => ({
path: route.path,
handler: moduleExpression(route.handler, import.meta.url).toCallable(container)
}));Parses various binding reference formats into normalized module path and method name.
/**
* The "parseBindingReference" method is used to parse binding references
* similar to route controller binding value or event listener binding value.
*/
function parseBindingReference(
binding: string | [LazyImport<Constructor<any>> | Constructor<any>, any?]
): Promise<{ moduleNameOrPath: string; method: string }>;Usage Examples:
import { parseBindingReference } from "@adonisjs/fold";
// Parse magic strings
let result = await parseBindingReference("#controllers/home_controller");
// Returns: { moduleNameOrPath: "#controllers/home_controller", method: "handle" }
result = await parseBindingReference("#controllers/home_controller.index");
// Returns: { moduleNameOrPath: "#controllers/home_controller", method: "index" }
result = await parseBindingReference("#controllers/home.controller.show");
// Returns: { moduleNameOrPath: "#controllers/home.controller", method: "show" }
// Parse class references
class HomeController {
handle() {}
index() {}
}
result = await parseBindingReference([HomeController]);
// Returns: { moduleNameOrPath: "HomeController", method: "handle" }
result = await parseBindingReference([HomeController, "index"]);
// Returns: { moduleNameOrPath: "HomeController", method: "index" }
// Parse lazy import references
const HomeControllerLazy = () => import("#controllers/home_controller");
result = await parseBindingReference([HomeControllerLazy]);
// Returns: { moduleNameOrPath: "#controllers/home_controller", method: "handle" }
result = await parseBindingReference([HomeControllerLazy, "show"]);
// Returns: { moduleNameOrPath: "#controllers/home_controller", method: "show" }Type definitions for module callable functions and handlers.
/**
* The shape of the function that imports a module expression and runs
* it using the container
*/
type ModuleCallable<T, Args extends any[]> = T extends undefined
? (resolver: ContainerResolver<any> | Container<any>, ...args: Args) => Promise<any>
: (...args: Args) => Promise<any>;
/**
* The shape of the handle method object that imports a module expression
* and runs it using the container
*/
type ModuleHandler<T, Args extends any[]> = T extends undefined
? {
name?: string;
handle(resolver: ContainerResolver<any> | Container<any>, ...args: Args): Promise<any>;
}
: {
name?: string;
handle(...args: Args): Promise<any>;
};Usage Examples:
import {
Container,
moduleCaller,
ModuleCallable,
ModuleHandler
} from "@adonisjs/fold";
const container = new Container();
// Typed callable function
const userIndexCallable: ModuleCallable<undefined, [Request]> = moduleCaller(
UserController,
"index"
).toCallable(container);
// Typed handler object
const userShowHandler: ModuleHandler<undefined, [Request, string]> = moduleCaller(
UserController,
"show"
).toHandleMethod(container);
// Using the typed functions
await userIndexCallable(container, request);
await userShowHandler.handle(container, request, "123");Complex patterns for module loading and execution.
Usage Examples:
import {
moduleImporter,
moduleExpression,
parseBindingReference,
Container
} from "@adonisjs/fold";
const container = new Container();
// Dynamic middleware stack
class MiddlewareStack {
private middlewares: Array<() => Promise<any>> = [];
async register(binding: string | [() => Promise<any>, string?]) {
const { moduleNameOrPath, method } = await parseBindingReference(binding);
if (typeof binding === "string") {
// String-based module expression
const callable = moduleExpression(binding, import.meta.url)
.toCallable(container);
this.middlewares.push(callable);
} else {
// Lazy import function
const [importFn, methodName] = binding;
const callable = moduleImporter(importFn, method)
.toCallable(container);
this.middlewares.push(callable);
}
}
async execute(...args: any[]) {
for (const middleware of this.middlewares) {
await middleware(...args);
}
}
}
// Usage
const stack = new MiddlewareStack();
// Register different types of middleware
await stack.register("#middleware/auth.handle");
await stack.register([() => import("#middleware/cors"), "handle"]);
await stack.register("#middleware/logging");
// Execute the stack
await stack.execute(request, response);