Rebasely Beta: data may be purged

examples/storefront Public

TypeScript · 50 lines · 1.6 KiB · at f6403bb

// A small method and path router. Patterns use :name for one segment and a final * for the// rest of the path, which arrives as params.rest.export type Params = Record<string, string>;export type Handler = (req: Request, params: Params) => Promise<Response> | Response;type Route = { method: string; re: RegExp; keys: string[]; handler: Handler };export type Match = { handler: Handler; params: Params } | "method_not_allowed" | null;export class Router {  private readonly routes: Route[] = [];  on(method: string, pattern: string, handler: Handler): this {    const keys: string[] = [];    const source = pattern      .split("/")      .map((seg) => {        if (seg === "*") {          keys.push("rest");          return "(.+)";        }        if (seg.startsWith(":")) {          keys.push(seg.slice(1));          return "([^/]+)";        }        return seg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");      })      .join("/");    this.routes.push({ method, re: new RegExp(`^${source}$`), keys, handler });    return this;  }  // Throws URIError when a segment is not valid percent-encoding.  match(method: string, path: string): Match {    let pathMatched = false;    for (const r of this.routes) {      const m = r.re.exec(path);      if (!m) continue;      pathMatched = true;      if (r.method !== method && !(method === "HEAD" && r.method === "GET")) continue;      const params: Params = {};      r.keys.forEach((k, i) => {        params[k] = decodeURIComponent(m[i + 1]!);      });      return { handler: r.handler, params };    }    return pathMatched ? "method_not_allowed" : null;  }}