UNPKG

@jsonjoy.com/jit-router

Version:

High-performance JIT router for Node.js

123 lines 4.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Match = exports.Route = exports.Destination = exports.Router = void 0; const JsExpression_1 = require("@jsonjoy.com/util/lib/codegen/util/JsExpression"); const printTree_1 = require("sonic-forest/lib/print/printTree"); const codegen_1 = require("./codegen"); const steps_1 = require("./steps"); const tree_1 = require("./tree"); class Router { constructor(options = {}) { this.options = options; this.destinations = []; } add(route, data) { const destination = Destination.from(route, data, this.options.defaultUntil); this.destinations.push(destination); } addDestination(destination) { this.destinations.push(destination); } tree() { const tree = new tree_1.RoutingTreeNode(); for (const destination of this.destinations) { for (const route of destination.routes) { tree.add(route, 0, destination); } } return tree; } compile() { const ctx = new codegen_1.RouterCodegenCtx(); const node = new codegen_1.RouterCodegenOpts(new JsExpression_1.JsExpression(() => 'str'), '0'); const tree = this.tree(); tree.codegen(ctx, node); return ctx.codegen.compile(); } toString(tab = '') { return (`${this.constructor.name}` + (0, printTree_1.printTree)(tab, [ (tab) => 'Destinations' + (0, printTree_1.printTree)(tab, this.destinations.map((d, i) => (tab) => `[${i}]: ` + d.toString(tab + ' '))), () => '', (tab) => 'RoutingTree' + (0, printTree_1.printTree)(tab, [(tab) => this.tree().toString(tab)]), ])); } } exports.Router = Router; class Destination { static from(def, data, defaultUntil) { const routes = typeof def === 'string' ? [Route.from(def, defaultUntil)] : def.map((r) => Route.from(r)); return new Destination(routes, data); } constructor(routes, data) { this.routes = routes; this.data = data; this.match = new Match(data, []); } toString(tab = '') { return (`${this.constructor.name} ` + (this.routes.length === 1 ? this.routes[0].toString(tab) : (0, printTree_1.printTree)(tab, this.routes.map((r) => (tab) => r.toString(tab))))); } } exports.Destination = Destination; class Route { static from(str, defaultUntil = '/') { const tokens = []; const matches = str.match(/\{[^\}]*\}/g); let i = 0; for (const match of matches ?? []) { const index = str.indexOf(match); if (index > i) tokens.push(str.substring(i, index)); tokens.push(match); i = index + match.length; } if (i < str.length) tokens.push(str.substring(i)); const steps = []; const length = tokens.length; for (let i = 0; i < length; i++) { const token = tokens[i]; const isParameter = token.startsWith('{') && token.endsWith('}'); if (isParameter) { const content = token.substring(1, token.length - 1); const [name = '', regex = '', until = ''] = content.split(':'); if (!regex || regex === '*') { const next = tokens[i + 1]; steps.push(new steps_1.UntilStep(name, until || (next ? next[0] : defaultUntil))); } else { steps.push(new steps_1.RegexStep(name, regex, until)); } } else { steps.push(new steps_1.ExactStep(token)); } } return new Route(steps); } constructor(steps) { this.steps = steps; } toText() { let str = ''; for (const step in this.steps) str += this.steps[step].toText(); return str; } toString(tab = '') { return this.toText(); } } exports.Route = Route; class Match { constructor(data, params) { this.data = data; this.params = params; } } exports.Match = Match; //# sourceMappingURL=router.js.map