import type { Context, NodeApplication } from 'alp-types'; import type { Router, RouteMatch, LocaleType, RouterBuilder, } from 'router-segments'; import { createRouterBuilder } from 'router-segments'; export type AlpRouteRef = (ctx: Context) => Promise | void; type ReturnType = (app: NodeApplication) => AlpRouteRef; export const createAlpRouterBuilder = < Locales extends LocaleType, >(): RouterBuilder => createRouterBuilder(); export type UrlGenerator =

| undefined>( routeKey: string, params?: P, ) => string; declare module 'alp-types' { // eslint-disable-next-line @typescript-eslint/no-shadow interface NodeApplication { router?: Router; } interface BaseContext { urlGenerator: UrlGenerator; redirectTo:

>( to: string, params?: P, ) => Promise; } // eslint-disable-next-line @typescript-eslint/no-shadow interface Context { route: RouteMatch; } } export default function alpRouter( router: Router, ): ReturnType { return (app: NodeApplication) => { app.router = router; app.context.urlGenerator = function < P extends Record | undefined, >(this: Context, routeKey: string, params?: P): string { return router.toLocalizedPath(this.language as Locales, routeKey, params); }; app.context.redirectTo = function < P extends Record | undefined, >(this: Context, to: string, params?: P): Promise { return this.redirect( router.toLocalizedPath(this.language as Locales, to, params), ); }; return async (ctx: Context): Promise => { // eslint-disable-next-line unicorn/no-array-method-this-argument const routeMatch = router.find(ctx.request.path, ctx.language as Locales); if (!routeMatch) { ctx.status = 404; throw new Error(`Route not found: ${ctx.request.path}`); } ctx.route = routeMatch; await routeMatch.ref(ctx); }; }; }