UNPKG

@izzyjs/route

Version:

Use your AdonisJs routes in your Inertia.js application

221 lines (220 loc) 6.83 kB
import { isBrowser } from './utils/is_browser.js'; export class Route extends String { /** * The complete URL with protocol and domain when baseUrl is configured * @example * ```ts * const route = Route.new('user.show', { id: '1' }) * console.log(route.url) // https://example.com/users/1 * ``` */ url; /** * The HTTP method for the route */ method; /** * The route parameters as an array * @example * ```ts * const route = Route.new('user.show', { id: '1' }) * console.log(route.params) // ['id'] * ``` */ params; /** * The route name as a string * @example * ```ts * const route = Route.new('user.show', { id: '1' }) * console.log(route.name) // user.show * ``` */ name; /** * The route pattern * @example * ```ts * const route = Route.new('user.show', { id: '1' }) * console.log(route.pattern) // /users/:id * ``` */ pattern; /** * The route path with parameters replaced * @example * ```ts * const route = Route.new('user.show', { id: '1' }) * console.log(route.path) // /users/1 * ``` */ path; /** * The query string * @example * ```ts * const route = Route.new('user.show', { id: '1' }, { page: 1 }) * console.log(route.qs.toString()) // page=1 * ``` */ qs; constructor(routeName, params, qs = {}, prefix = '') { const { routes } = Route.izzy(); const exist = routes.find((r) => 'name' in r && r.name === routeName); if (!exist) { throw new Error(`Route with name "${routeName}" not found`); } const searchParams = new URLSearchParams(qs); let pattern; if ('params' in exist && exist.params) { if (!params) { throw new Error(`Route "${routeName}" requires parameters: ${exist.params.map((p) => `"${p}"`).join(', ')}`); } pattern = Route.replaceRouteParams(exist.path, params); } else { pattern = exist.path; } if (searchParams.toString()) { pattern += `?${searchParams.toString()}`; } if (prefix) { pattern = prefix + pattern; } super(pattern); this.path = pattern; this.name = exist.name; this.method = exist.method; this.params = exist.params; this.pattern = exist.path; this.qs = searchParams; // Generate complete URL with protocol and domain if baseUrl is configured this.url = this.generateCompleteUrl(pattern, exist.domain); } /** * Generate complete URL with protocol and domain when baseUrl is configured */ generateCompleteUrl(path, routeDomain) { try { const config = Route.getConfig(); if (config?.baseUrl) { const baseUrl = new URL(config.baseUrl); // If route has a specific domain (not 'root'), use that domain // Otherwise use the baseUrl.host const host = routeDomain && routeDomain !== 'root' ? routeDomain : baseUrl.host; return `${baseUrl.protocol}//${host}${path}`; } } catch (error) { // If baseUrl is invalid, fallback to path only console.warn('Invalid baseUrl configuration, falling back to path only'); } return path; } /** * Get the configuration from the global Izzy object */ static getConfig() { try { if (isBrowser()) { return window.__izzy_route__?.config || null; } else { return globalThis.__izzy_route__?.config || null; } } catch { return null; } } static replaceRouteParams(routePath, params) { return Object.entries(params).reduce((acc, [key, value]) => acc.replace(`:${key}`, value), routePath); } static new(routeName, params, qs, prefix) { if (!routeName) { return new Routes(); } return new Route(routeName, params, qs, prefix); } /** * Get the `Route` instance from the global Izzy object * @returns { GlobalIzzyJs } */ static izzy() { let routes; let currentRoute; if (isBrowser()) { routes = window.__izzy_route__.routes; currentRoute = window.location.pathname; } else { routes = globalThis.__izzy_route__.routes; currentRoute = globalThis.__izzy_route__.current; } return { routes, current: currentRoute }; } toString() { return this.path; } } export class Routes { currentRoute; routes; constructor() { const { routes, current: currentRoute } = Route.izzy(); this.routes = routes; this.currentRoute = currentRoute; } current(routeName, params) { if (!routeName) { return this.currentRoute; } if (routeName.includes('*')) { const regex = new RegExp(routeName.replace(/\*/g, '.*')); return regex.test(this.currentRoute); } const route = Route.new(routeName, params); return this.currentRoute === route.toString(); } /** * Check if the current route has the given route name * @summary unstable * @param routeName route name * @example * ```ts * route().has('users.index') // => true or false * route().has('user.*') // => true or false * ``` */ has(routeName) { if (routeName.includes('*')) { const regex = new RegExp(routeName.replace(/\*/g, '.*')); return this.routes.some((r) => 'name' in r && regex.test(r.name)); } return this.routes.some((r) => 'name' in r && r.name === routeName); } get params() { const route = this.routes.find(({ path }) => { const regex = new RegExp(path .split('/') .map((p) => (p.startsWith(':') ? '([^/]+)' : p)) .join('/')); return regex.test(this.currentRoute); }); if (route && route.params) { const regex = new RegExp(route.path .split('/') .map((p) => (p.startsWith(':') ? '([^/]+)' : p)) .join('/')); const values = this.currentRoute.match(regex); if (!values) { return {}; } return route.params.reduce((acc, param, index) => ({ ...acc, [param]: values[index + 1], }), {}); } return {}; } }