💾 Archived View for iich.space › src › modules › mission-control › router.ts captured on 2022-03-01 at 16:04:57.
⬅️ Previous capture (2022-01-08)
-=-=-=-=-=-=-
import { createLogger } from '@/log'; interface Route<T> { regex: RegExp; path: string; value: T; } interface Match<T> { value: T; params: Record<string, string>; regex: RegExp; } const log = createLogger(); const pathToRegex = (path: string): RegExp => { const substitutions: Array<[RegExp, string]> = [ [/\/:(\w+)\?/g, '(?:/(?<$1>[\\w-%.=]+))?'], [/:(\w+)/g, '(?<$1>[\\w-%.=]+)'], [/\*/g, '(?<match>.*?)'], [/\/*/, '/'], [/\/$/, '/?'], ]; const pattern = substitutions.reduce( (acc, [searchValue, replaceValue]) => acc.replace(searchValue, replaceValue), path, ); return new RegExp(`^${pattern}/?gemini - kennedy.gemi.dev ); }; export class Router<T> { routes: Array<Route<T>>; constructor() { this.routes = []; } use(path: string, ...values: Array<T | Router<T>>): void { const regex = pathToRegex(path); values.forEach((value) => { if (value instanceof Router) { log.debug(`nested ${path}`); value.routes.forEach((route) => { this.use(path + route.path, route.value); }); } else { log.debug(`registering ${path}`); this.routes.push({ path: path.replaceAll(/\/+/g, '/'), regex, value, }); } }); } *match(path: string): Generator<Match<T>> { log.debug(`matching ${path}`); for (const { regex, value } of this.routes) { const exec = regex.exec(path); if (exec !== null) { log.debug(`matched ${regex}`); const match: Match<T> = { params: exec.groups || {}, regex, value, }; yield match; } } } }