UNPKG

@wroud/navigation

Version:

A flexible, pattern-matching navigation system for JavaScript applications with built-in routing, browser integration, and navigation state management

130 lines 3.64 kB
import {} from "./IRoute.js"; export class Router { get routesList() { return Array.from(this.routes.values()); } routes; matcher; constructor(options = {}) { this.routes = new Map(); this.matcher = options.matcher || null; } /** * Add a route to the router */ addRoute(route) { if (!route.id) { throw new Error("Route ID is required"); } if (this.routes.has(route.id)) { throw new Error(`Route ${route.id} already exists`); } // If a matcher is provided, register the pattern and use it for finding parents if (this.matcher) { this.matcher.addPattern(route.id); } this.routes.set(route.id, { ...route, parents: this.getParentsForRoute(route.id), }); } /** * Get a route's parent */ getParentRoute(routeId) { const route = this.routes.get(routeId); if (!route || route.parents.length === 0) { return undefined; } const parentId = route.parents[route.parents.length - 1]; return parentId ? this.routes.get(parentId) : undefined; } /** * Get the full route hierarchy for a route */ getRouteTree(routeId) { const tree = []; const route = this.routes.get(routeId); if (!route) { throw new Error(`Route ${routeId} not found`); } for (const parentId of route.parents) { const parentRoute = this.routes.get(parentId); if (parentRoute) { tree.push(parentRoute); } } tree.push(route); return tree; } /** * Get a route by ID */ getRoute(routeId) { return this.routes.get(routeId); } /** * Match a URL to a route */ matchUrl(url) { if (!this.matcher) { return null; } return this.matcher.match(url); } /** * Build a URL from a route ID and parameters */ buildUrl(routeId, params) { if (!this.matcher || !this.routes.has(routeId)) { return null; } const state = { id: routeId, params: params, }; // Special case for root path if (routeId === "/") { return "/"; } return this.matcher.stateToUrl(state); } /** * Convert a route state to a URL */ stateToUrl(state) { if (!this.matcher) { return null; } return this.matcher.stateToUrl(state); } /** * Convert a URL to a route state */ urlToState(url) { if (!this.matcher) { return null; } return this.matcher.urlToState(url); } /** * Calculates parent route IDs for a given route ID */ getParentsForRoute(id) { // If a pattern matcher is available, use it for parents if (this.matcher) { const ancestors = this.matcher.getPatternAncestors(id); // Find routes that exist for these ancestors const existingAncestors = ancestors.filter((ancestor) => this.routes.has(ancestor)); // Always include the root path first if it exists in routes and isn't already included if (this.routes.has("/") && id !== "/" && !existingAncestors.includes("/")) { existingAncestors.unshift("/"); } return existingAncestors; } return []; } } //# sourceMappingURL=Router.js.map