UNPKG

@fedify/fedify

Version:

An ActivityPub server framework

115 lines (114 loc) 3.42 kB
import "@js-temporal/polyfill"; import "urlpattern-polyfill"; globalThis.addEventListener = () => {}; import { cloneDeep } from "es-toolkit"; import { Router } from "uri-template-router"; import { parseTemplate } from "url-template"; //#region src/federation/router.ts function cloneInnerRouter(router) { const clone = new Router(); clone.nid = router.nid; clone.fsm = cloneDeep(router.fsm); clone.routeSet = new Set(router.routeSet); clone.templateRouteMap = new Map(router.templateRouteMap); clone.valueRouteMap = new Map(router.valueRouteMap); clone.hierarchy = cloneDeep(router.hierarchy); return clone; } /** * URL router and constructor based on URI Template * ([RFC 6570](https://tools.ietf.org/html/rfc6570)). */ var Router$1 = class Router$1 { #router; #templates; #templateStrings; /** * Whether to ignore trailing slashes when matching paths. * @since 1.6.0 */ trailingSlashInsensitive; /** * Create a new {@link Router}. * @param options Options for the router. */ constructor(options = {}) { this.#router = new Router(); this.#templates = {}; this.#templateStrings = {}; this.trailingSlashInsensitive = options.trailingSlashInsensitive ?? false; } clone() { const clone = new Router$1({ trailingSlashInsensitive: this.trailingSlashInsensitive }); clone.#router = cloneInnerRouter(this.#router); clone.#templates = { ...this.#templates }; clone.#templateStrings = { ...this.#templateStrings }; return clone; } /** * Checks if a path name exists in the router. * @param name The name of the path. * @returns `true` if the path name exists, otherwise `false`. */ has(name) { return name in this.#templates; } /** * Adds a new path rule to the router. * @param template The path pattern. * @param name The name of the path. * @returns The names of the variables in the path pattern. */ add(template, name) { if (!template.startsWith("/")) throw new RouterError("Path must start with a slash."); const rule = this.#router.addTemplate(template, {}, name); this.#templates[name] = parseTemplate(template); this.#templateStrings[name] = template; return new Set(rule.variables.map((v) => v.varname)); } /** * Resolves a path name and values from a URL, if any match. * @param url The URL to resolve. * @returns The name of the path and its values, if any match. Otherwise, * `null`. */ route(url) { let match = this.#router.resolveURI(url); if (match == null) { if (!this.trailingSlashInsensitive) return null; url = url.endsWith("/") ? url.replace(/\/+$/, "") : `${url}/`; match = this.#router.resolveURI(url); if (match == null) return null; } return { name: match.matchValue, template: this.#templateStrings[match.matchValue], values: match.params }; } /** * Constructs a URL/path from a path name and values. * @param name The name of the path. * @param values The values to expand the path with. * @returns The URL/path, if the name exists. Otherwise, `null`. */ build(name, values) { if (name in this.#templates) return this.#templates[name].expand(values); return null; } }; /** * An error thrown by the {@link Router}. */ var RouterError = class extends Error { /** * Create a new {@link RouterError}. * @param message The error message. */ constructor(message) { super(message); this.name = "RouterError"; } }; //#endregion export { RouterError as n, Router$1 as t };