Skip to main content
Module

x/router/mod.js

A high-performance basic router works anywhere.
Go to Latest
File
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This is a specialised implementation of a System module loader.
// @ts-nocheck/* eslint-disable */let System, __instantiateAsync, __instantiate;
(() => { const r = new Map();
System = { register(id, d, f) { r.set(id, { d, f, exp: {} }); }, };
async function dI(mid, src) { let id = mid.replace(/\.\w+$/i, ""); if (id.includes("./")) { const [o, ...ia] = id.split("/").reverse(), [, ...sa] = src.split("/").reverse(), oa = [o]; let s = 0, i; while ((i = ia.shift())) { if (i === "..") s++; else if (i === ".") break; else oa.push(i); } if (s < sa.length) oa.push(...sa.slice(s)); id = oa.reverse().join("/"); } return r.has(id) ? gExpA(id) : import(mid); }
function gC(id, main) { return { id, import: (m) => dI(m, id), meta: { url: id, main }, }; }
function gE(exp) { return (id, v) => { v = typeof id === "string" ? { [id]: v } : id; for (const [id, value] of Object.entries(v)) { Object.defineProperty(exp, id, { value, writable: true, enumerable: true, }); } }; }
function rF(main) { for (const [id, m] of r.entries()) { const { f, exp } = m; const { execute: e, setters: s } = f(gE(exp), gC(id, id === main)); delete m.f; m.e = e; m.s = s; } }
async function gExpA(id) { if (!r.has(id)) return; const m = r.get(id); if (m.s) { const { d, e, s } = m; delete m.s; delete m.e; for (let i = 0; i < s.length; i++) s[i](await gExpA(d[i])); const r = e(); if (r) await r; } return m.exp; }
function gExp(id) { if (!r.has(id)) return; const m = r.get(id); if (m.s) { const { d, e, s } = m; delete m.s; delete m.e; for (let i = 0; i < s.length; i++) s[i](gExp(d[i])); e(); } return m.exp; }
__instantiateAsync = async (m) => { System = __instantiateAsync = __instantiate = undefined; rF(m); return gExpA(m); };
__instantiate = (m) => { System = __instantiateAsync = __instantiate = undefined; rF(m); return gExp(m); };})();
// The following code is based off:// https://github.com/julienschmidt/httprouter//// Copyright (c) 2013, Julien Schmidt// All rights reserved.//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are met://// 1. Redistributions of source code must retain the above copyright notice, this// list of conditions and the following disclaimer.//// 2. Redistributions in binary form must reproduce the above copyright notice,// this list of conditions and the following disclaimer in the documentation// and/or other materials provided with the distribution.//// 3. Neither the name of the copyright holder nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.System.register("node", [], function (exports_1, context_1) { "use strict"; var Node; var __moduleName = context_1 && context_1.id; function countParams(path) { let n = 0; for (let i = 0; i < path.length; ++i) { switch (path[i]) { case ":": case "*": n++; } } if (n >= 255) { return 255; } return n; } exports_1("countParams", countParams); return { setters: [], execute: function () { Node = class Node { constructor() { this.priority = 0; this.children = []; this.path = ""; this.wildChild = false; this.nType = 0 /* Static */; this.indices = ""; this.maxParams = 0; } addRoute(path, handle) { let node = this; const fullPath = path; ++node.priority; let numParams = countParams(path); // non-empty tree if (node.path.length > 0 || node.children.length > 0) { walk: while (true) { // Update maxParams of the current node if (numParams > node.maxParams) { node.maxParams = numParams; } // Find the longest common prefix. // This also implies that the common prefix contains no ':' or '*' // since the existing key can't contain those chars. let i = 0; const max = Math.min(path.length, node.path.length); for (; i < max && path[i] === node.path[i]; ++i); // Split edge if (i < node.path.length) { const child = new Node(); child.path = node.path.slice(i); child.wildChild = node.wildChild; child.nType = 0 /* Static */; child.indices = node.indices; child.children = node.children; child.handle = node.handle; child.priority = node.priority - 1; // Update maxParams (max of all children) for (const cc of child.children) { if (cc.maxParams > child.maxParams) { child.maxParams = cc.maxParams; } } node.children = [child]; node.indices = node.path[i]; node.path = path.slice(0, i); node.handle = undefined; node.wildChild = false; } // Make new node a child of this node if (i < path.length) { path = path.slice(i); if (node.wildChild) { node = node.children[0]; ++node.priority; // Update maxParams of the child node if (numParams > node.maxParams) { node.maxParams = numParams; } --numParams; // Check if the wildcard matches if ( path.length >= node.path.length && node.path === path.slice(0, node.path.length) && node.nType != 3 /* CatchAll */ && // Check for longer wildcard, e.g. :name and :names (node.path.length >= path.length || path[node.path.length] === "/") ) { continue walk; } else { // Wildcard conflict let pathSeg = path; if (node.nType !== 3 /* CatchAll */) { pathSeg = pathSeg.split("/", 1)[0]; } const prefix = fullPath.slice(0, fullPath.indexOf(pathSeg)) + node.path; throw new Error( `'${pathSeg}' in new path '${fullPath}' conflicts with existing wildcard '${node.path}' in existing prefix '${prefix}'`, ); } } const c = path[0]; // slash after param if ( node.nType === 2 /* Param */ && c === "/" && node.children.length === 1 ) { node = node.children[0]; ++node.priority; continue walk; } // Check if a child with the next path byte exists for (let i = 0; i < node.indices.length; ++i) { if (c === node.indices[i]) { i = node.incrementChildPrio(i); node = node.children[i]; continue walk; } } // Otherwise insert it if (c !== ":" && c !== "*") { node.indices += c; const child = new Node(); child.maxParams = numParams; node.children.push(child); node.incrementChildPrio(node.indices.length - 1); node = child; } node.insertChild(numParams, path, fullPath, handle); return; } if (node.handle) { throw new Error( `a handle is already registered for path '${fullPath}'`, ); } node.handle = handle; return; } } else { // Empty tree node.insertChild(numParams, path, fullPath, handle); node.nType = 1 /* Root */; } } // increments priority of the given child and reorders if necessary incrementChildPrio(pos) { const cs = this.children; ++cs[pos].priority; const prio = cs[pos].priority; // adjust position (move to front) let newPos = pos; for (; newPos > 0 && cs[newPos - 1].priority < prio; --newPos) { // swap node positions [cs[newPos - 1], cs[newPos]] = [cs[newPos], cs[newPos - 1]]; } // build new index char string if (newPos !== pos) { this.indices = this.indices.slice(0, newPos) + // unchanged prefix, might be empty this.indices.slice(pos, pos + 1) + // the index char we move this.indices.slice(newPos, pos) + this.indices.slice(pos + 1); // rest without char at 'pos' } return newPos; } insertChild(numParams, path, fullPath, handle) { let node = this; let offset = 0; // already handled bytes of the path // find prefix until first wildcard (beginning with ':'' or '*'') for (let i = 0, max = path.length; numParams > 0; ++i) { const c = path[i]; if (c !== ":" && c !== "*") { continue; } // find wildcard end (either '/' or path end) let end = i + 1; while (end < max && path[end] !== "/") { switch (path[end]) { // the wildcard name must not contain ':' and '*' case ":": case "*": throw new Error( `only one wildcard per path segment is allowed, has: '${ path.slice(i) }' in path '${fullPath}'`, ); default: ++end; } } // check if this Node existing children which would be // unreachable if we insert the wildcard here if (node.children.length > 0) { throw new Error( `wildcard route '${ path.slice(i, end) }' conflicts with existing children in path '${fullPath}'`, ); } // check if the wildcard has a name if (end - i < 2) { throw new Error( `wildcards must be named with a non-empty name in path '${fullPath}'`, ); } if (c === ":") { // param // split path at the beginning of the wildcard if (i > 0) { node.path = path.slice(offset, i); offset = i; } const child = new Node(); child.nType = 2 /* Param */; child.maxParams = numParams; node.children = [child]; node.wildChild = true; node = child; ++node.priority; --numParams; // if the path doesn't end with the wildcard, then there // will be another non-wildcard subpath starting with '/' if (end < max) { node.path = path.slice(offset, end); offset = end; const child = new Node(); child.maxParams = numParams; child.priority = 1; node.children = [child]; node = child; } } else { // catchAll if (end !== max || numParams > 1) { throw new Error( `catch-all routes are only allowed at the end of the path in path '${fullPath}'`, ); } if ( node.path.length > 0 && node.path[node.path.length - 1] === "/" ) { throw new Error( `catch-all conflicts with existing handle for the path segment root in path '${fullPath}'`, ); } // currently fixed width 1 for '/' --i; if (path[i] !== "/") { throw new Error(`no / before catch-all in path '${fullPath}'`); } node.path = path.slice(offset, i); // first node: catchAll node with empty path let child = new Node(); child.wildChild = true; child.nType = 3 /* CatchAll */; child.maxParams = 1; if (node.maxParams < 1) { node.maxParams = 1; } node.children = [child]; node.indices = path[i]; node = child; ++node.priority; // second node: node holding the variable child = new Node(); child.path = path.slice(i); child.nType = 3 /* CatchAll */; child.maxParams = 1; child.handle = handle; child.priority = 1; node.children = [child]; return; } } // insert remaining path part and handle to the leaf node.path = path.slice(offset); node.handle = handle; } getValue(path) { let node = this; let handle, p, tsr = false; // outer loop for walking the tree walk: while (true) { if (path.length > node.path.length) { if (path.slice(0, node.path.length) === node.path) { path = path.slice(node.path.length); // If this node does not have a wildcard (param or catchAll) // child, we can just look up the next child node and continue // to walk down the tree if (!node.wildChild) { const c = path[0]; for (let i = 0; i < node.indices.length; ++i) { if (c === node.indices[i]) { node = node.children[i]; continue walk; } } // Nothing found. // We can recommend to redirect to the same URL without a // trailing slash if a leaf exists for that path. if (node.handle && path === "/") { tsr = true; } break walk; } // handle wildcard child node = node.children[0]; switch (node.nType) { case 2 /* Param */: { // find param end (either '/' or path end) let end = 0; for (; end < path.length && path[end] !== "/"; ++end); // save param value if (!p) { // lazy allocation p = []; } const i = p.length; p[i] = { key: node.path.slice(1), value: path.slice(0, end), }; // we need to go deeper! if (end < path.length) { if (node.children.length > 0) { path = path.slice(end); node = node.children[0]; continue walk; } // ... but we can't tsr = path.length === end + 1; break walk; } handle = node.handle; if (handle) { break walk; } else if (node.children.length === 1) { // No handle found. Check if a handle for this path + a // trailing slash exists for TSR recommendation node = node.children[0]; if (node.handle && node.path === "/") { tsr = true; } } break walk; } case 3 /* CatchAll */: { // save param value if (!p) { // lazy allocation p = []; } const i = p.length; p[i] = { key: node.path.slice(2), value: path, }; handle = node.handle; break walk; } default: { throw new Error("invalid node type"); } } } } else if (path === node.path) { // We should have reached the node containing the handle. // Check if this node has a handle registered. handle = node.handle; if (handle) { break walk; } if ( path === "/" && node.wildChild && node.nType !== 1 /* Root */ ) { tsr = true; break walk; } // No handle found. Check if a handle for this path + a // trailing slash exists for trailing slash recommendation for (let i = 0; i < node.indices.length; ++i) { if (node.indices[i] === "/") { node = node.children[i]; if ( (node.handle && node.path.length === 1) || (node.children[0].handle && node.nType === 3 /* CatchAll */) ) { tsr = true; } break walk; } } break walk; } // Nothing found. We can recommend to redirect to the same URL with an // extra trailing slash if a leaf exists for that path if ( path === "/" || (node.path.length === path.length + 1 && node.path[path.length] === "/" && node.handle && path === node.path.slice(0, node.path.length - 1)) ) { tsr = true; } break walk; } return [handle, p, tsr]; } }; exports_1("Node", Node); }, };});System.register("mod", ["node"], function (exports_2, context_2) { "use strict"; var __moduleName = context_2 && context_2.id; function exportStar_1(m) { var exports = {}; for (var n in m) { if (n !== "default") exports[n] = m[n]; } exports_2(exports); } return { setters: [ function (node_ts_1_1) { exportStar_1(node_ts_1_1); }, ], execute: function () { }, };});
const __exp = __instantiate("mod");export const countParams = __exp["countParams"];export const Node = __exp["Node"];