@akala/core
Version:
95 lines • 3.88 kB
JavaScript
import { NotHandled } from '../middlewares/shared.js';
import { MiddlewareCompositeAsync } from '../middlewares/composite-async.js';
import { match, parse } from '../uri-template/index.js';
/**
* Represents an asynchronous route handler for URI template matching in middleware chains.
*
* This middleware class processes routes using URI templates and manages asynchronous middleware execution.
*
* @template T - The context type containing the routable request and parameters.
* @template TSpecialNextParam - The type for special next parameters (defaults to {@link SpecialNextParam})
*/
export class MiddlewareRouteAsync extends MiddlewareCompositeAsync {
/**
* Creates an instance of MiddlewareRouteAsync with a route path or URI template.
* @template T - The context type containing the routable request and parameters.
* @template TSpecialNextParam - The type for special next parameters (defaults to SpecialNextParam)
* @param {string | UriTemplate} route - The route path or URI template defining the route.
*/
constructor(route) {
super(route.toString());
this.routePath = Array.isArray(route) ? route : parse(route);
}
/**
* Parsed URI template used for route matching
*
* @type {UriTemplate}
*/
routePath;
/**
* Creates a new route configuration chain with optional parameters.
*
* @function route
* @param {...RouteBuilderArguments} args - Route configuration parameters (method, path, etc.)
* @returns {MiddlewareRouteAsync<T, TSpecialNextParam>} Newly created route instance
*/
route(...args) {
return new MiddlewareRouteAsync(...args);
}
/**
* Optional predicate to determine route applicability
*
* A function that checks if the route should handle the current request
*
* @type {(x: T[0]) => boolean}
*/
isApplicable;
/**
* Executes the route's middleware chain asynchronously.
*
* @param {...T} context - Execution context containing the routable request and parameters
* @returns {MiddlewarePromise<TSpecialNextParam>} Resolution promise indicating completion
*/
async handle(...context) {
const req = context[0];
const isMatch = match(req.path, this.routePath);
if (isMatch && (!this.isApplicable || this.isApplicable(req))) {
const oldPath = req.path;
const c = oldPath[oldPath.length - isMatch.remainder.length];
if (c && c !== '/')
return NotHandled;
req.path = isMatch.remainder || '/';
const oldParams = req.params;
req.params = isMatch.variables;
try {
return await super.handle(...context);
}
finally {
req.params = oldParams;
req.path = oldPath;
}
}
return NotHandled;
}
useMiddleware(routeOrMiddleware, ...middlewares) {
if (typeof routeOrMiddleware === 'string' || Array.isArray(routeOrMiddleware)) {
const routed = new MiddlewareRouteAsync(routeOrMiddleware);
routed.useMiddleware(...middlewares);
super.useMiddleware(routed);
}
else
super.useMiddleware(routeOrMiddleware, ...middlewares);
return this;
}
use(routeOrHandler, ...handlers) {
if (typeof routeOrHandler == 'undefined')
throw new Error('At least 1 route or middleware needs to be provided.');
if (typeof routeOrHandler === 'string' || Array.isArray(routeOrHandler)) {
const routed = new MiddlewareRouteAsync(routeOrHandler);
routed.use(...handlers);
return super.useMiddleware(routed);
}
return super.use(routeOrHandler, ...handlers);
}
}
//# sourceMappingURL=route-async.js.map