@devp0nt/route0 1.0.0-next.26 → 1.0.0-next.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +43 -10
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +20 -16
- package/dist/esm/index.d.ts +20 -16
- package/dist/esm/index.js +43 -10
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.test.ts +80 -31
- package/src/index.ts +77 -30
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// TODO: asterisk\n// TODO: when asterisk then query params will be extended also after extend\n// TODO: optional params\n// TODO: required search\n\n// TODO: .extension('.json') to not add additional / but just add some extension\n// TODO: search input can be boolean, or even object with qs\n// TODO: Роут0 три пусть три тоже сам генерится вероятно\n// TODO: Роут0 три мод, тогда там все ноуты кончаются на .селф\n// TODO: use splats in param definition \"*\"\n// TODO: ? check extend for search only .extend('&x&z')\n// TODO: .create(route, {useSearch, useParams})\n// TODO: Из пас экзакт, из пасвизквери экзает, из чилдрен, из парент, из экзактОр\n// TODO: isEqual, isChildren, isParent\n// TODO: extractParams, extractSearch\n// TODO: getPathDefinition respecting definitionParamPrefix, definitionSearchPrefix\n// TODO: prepend\n// TODO: Route0.createTree({base:{self: x, children: ...})\n// TODO: overrideTree\n// TODO: .create(route, {baseUrl, useLocation})\n// TODO: ? optional path params as @\n// TODO: prependMany, extendMany, overrideMany, with types\n// TODO: optional route params /x/:id?\n\nexport class Route0<TDefinition extends string> {\n readonly definition: TDefinition\n readonly pathDefinition: _PathDefinition<TDefinition>\n readonly paramsDefinition: _ParamsDefinition<TDefinition>\n readonly searchDefinition: _SearchDefinition<TDefinition>\n baseUrl: string\n\n private constructor(definition: TDefinition, config: RouteConfigInput = {}) {\n this.definition = definition\n this.pathDefinition = Route0._getPathDefinitionBydefinition(definition)\n this.paramsDefinition = Route0._getParamsDefinitionBydefinition(definition)\n this.searchDefinition = Route0._getSearchDefinitionBydefinition(definition)\n\n const { baseUrl } = config\n if (baseUrl && typeof baseUrl === 'string' && baseUrl.length) {\n this.baseUrl = baseUrl\n } else {\n const g = globalThis as unknown as { location?: { origin?: string } }\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (typeof g?.location?.origin === 'string' && g.location.origin.length > 0) {\n this.baseUrl = g.location.origin\n } else {\n this.baseUrl = 'https://example.com'\n }\n }\n }\n\n static create<TDefinition extends string>(\n definition: TDefinition | AnyRoute<TDefinition>,\n config?: RouteConfigInput,\n ): CallabelRoute<TDefinition> {\n if (typeof definition === 'function') {\n return definition\n }\n const original = typeof definition === 'object' ? definition : new Route0<TDefinition>(definition, config)\n const callable = original.get.bind(original)\n Object.setPrototypeOf(callable, original)\n Object.defineProperty(callable, Symbol.toStringTag, {\n value: original.definition,\n })\n return callable as never\n }\n\n private static _splitPathDefinitionAndSearchTailDefinition(definition: string) {\n const i = definition.indexOf('&')\n if (i === -1) return { pathDefinition: definition, searchTailDefinition: '' }\n return {\n pathDefinition: definition.slice(0, i),\n searchTailDefinition: definition.slice(i),\n }\n }\n\n private static _getAbsPath(baseUrl: string, pathWithSearch: string) {\n return new URL(pathWithSearch, baseUrl).toString().replace(/\\/$/, '')\n }\n\n private static _getPathDefinitionBydefinition<TDefinition extends string>(definition: TDefinition) {\n const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(definition)\n return pathDefinition as _PathDefinition<TDefinition>\n }\n\n private static _getParamsDefinitionBydefinition<TDefinition extends string>(\n definition: TDefinition,\n ): _ParamsDefinition<TDefinition> {\n const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(definition)\n const matches = Array.from(pathDefinition.matchAll(/:([A-Za-z0-9_]+)/g))\n const paramsDefinition = Object.fromEntries(matches.map((m) => [m[1], true]))\n const keysCount = Object.keys(paramsDefinition).length\n if (keysCount === 0) {\n return undefined as _ParamsDefinition<TDefinition>\n }\n return paramsDefinition as _ParamsDefinition<TDefinition>\n }\n\n private static _getSearchDefinitionBydefinition<TDefinition extends string>(\n definition: TDefinition,\n ): _SearchDefinition<TDefinition> {\n const { searchTailDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(definition)\n if (!searchTailDefinition) {\n return undefined as _SearchDefinition<TDefinition>\n }\n const keys = searchTailDefinition.split('&').filter(Boolean)\n const searchDefinition = Object.fromEntries(keys.map((k) => [k, true]))\n const keysCount = Object.keys(searchDefinition).length\n if (keysCount === 0) {\n return undefined as _SearchDefinition<TDefinition>\n }\n return searchDefinition as _SearchDefinition<TDefinition>\n }\n\n extend<TSuffixDefinition extends string>(\n suffixDefinition: TSuffixDefinition,\n ): CallabelRoute<PathExtended<TDefinition, TSuffixDefinition>> {\n const { pathDefinition: parentPathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(this.definition)\n const { pathDefinition: suffixPathDefinition, searchTailDefinition: suffixSearchTailDefinition } =\n Route0._splitPathDefinitionAndSearchTailDefinition(suffixDefinition)\n const pathDefinition = `${parentPathDefinition}/${suffixPathDefinition}`.replace(/\\/{2,}/g, '/')\n const definition = `${pathDefinition}${suffixSearchTailDefinition}` as PathExtended<TDefinition, TSuffixDefinition>\n return Route0.create<PathExtended<TDefinition, TSuffixDefinition>>(definition, { baseUrl: this.baseUrl })\n }\n\n // has params\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TDefinition>,\n WithParamsInput<TDefinition, { search?: undefined; abs?: false }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, PathOnlyRouteValue<TDefinition>>\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TDefinition>,\n WithParamsInput<TDefinition, { search: _SearchInput<TDefinition>; abs?: false }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithSearchRouteValue<TDefinition>>\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TDefinition>,\n WithParamsInput<TDefinition, { search?: undefined; abs: true }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, AbsolutePathOnlyRouteValue<TDefinition>>\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TDefinition>,\n WithParamsInput<TDefinition, { search: _SearchInput<TDefinition>; abs: true }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, AbsoluteWithSearchRouteValue<TDefinition>>\n\n // no params\n get(...args: OnlyIfNoParams<_ParamsDefinition<TDefinition>, [], [never]>): PathOnlyRouteValue<TDefinition>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, { search?: undefined; abs?: false }>,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, PathOnlyRouteValue<TDefinition>>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, { search: _SearchInput<TDefinition>; abs?: false }>,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, WithSearchRouteValue<TDefinition>>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, { search?: undefined; abs: true }>,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsolutePathOnlyRouteValue<TDefinition>>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, { search: _SearchInput<TDefinition>; abs: true }>,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsoluteWithSearchRouteValue<TDefinition>>\n\n // implementation\n get(...args: any[]): string {\n const { searchInput, paramsInput, absInput } = ((): {\n searchInput: Record<string, string | number>\n paramsInput: Record<string, string | number>\n absInput: boolean\n } => {\n if (args.length === 0) {\n return { searchInput: {}, paramsInput: {}, absInput: false }\n }\n const input = args[0]\n if (typeof input !== 'object' || input === null) {\n // throw new Error(\"Invalid get route input: expected object\")\n return { searchInput: {}, paramsInput: {}, absInput: false }\n }\n const { search, abs, ...params } = input\n return { searchInput: search || {}, paramsInput: params, absInput: abs ?? false }\n })()\n\n // validate params\n const neededParamsKeys = this.paramsDefinition ? Object.keys(this.paramsDefinition) : []\n const providedParamsKeys = Object.keys(paramsInput)\n const notProvidedKeys = neededParamsKeys.filter((k) => !providedParamsKeys.includes(k))\n if (notProvidedKeys.length) {\n // throw new Error(`Missing params: not defined keys ${notProvidedKeys.map((k) => `\"${k}\"`).join(\", \")}.`)\n Object.assign(paramsInput, Object.fromEntries(notProvidedKeys.map((k) => [k, 'undefined'])))\n }\n\n // create url\n\n let url = this.pathDefinition as string\n // replace params\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n url = url.replace(/:([A-Za-z0-9_]+)/g, (_m, k) => encodeURIComponent(String(paramsInput?.[k] ?? '')))\n // search params\n const searchInputStringified = Object.fromEntries(Object.entries(searchInput).map(([k, v]) => [k, String(v)]))\n url = [url, new URLSearchParams(searchInputStringified).toString()].filter(Boolean).join('?')\n // dedupe slashes\n url = url.replace(/\\/{2,}/g, '/')\n // absolute\n url = absInput ? Route0._getAbsPath(this.baseUrl, url) : url\n\n return url\n }\n\n // has params\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithParamsInput<TDefinition>>,\n abs?: false,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, PathOnlyRouteValue<TDefinition>>\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithParamsInput<TDefinition, _SearchInput<TDefinition>>>,\n abs?: false,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithSearchRouteValue<TDefinition>>\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithParamsInput<TDefinition>>,\n abs: true,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, AbsolutePathOnlyRouteValue<TDefinition>>\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithParamsInput<TDefinition, _SearchInput<TDefinition>>>,\n abs: true,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, AbsoluteWithSearchRouteValue<TDefinition>>\n\n // no params\n flat(...args: OnlyIfNoParams<_ParamsDefinition<TDefinition>, [], [never]>): PathOnlyRouteValue<TDefinition>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, Record<never, never>>,\n abs?: false,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, PathOnlyRouteValue<TDefinition>>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, _SearchInput<TDefinition>>,\n abs?: false,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, WithSearchRouteValue<TDefinition>>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, Record<never, never>>,\n abs: true,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsolutePathOnlyRouteValue<TDefinition>>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, _SearchInput<TDefinition>>,\n abs: true,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsoluteWithSearchRouteValue<TDefinition>>\n\n // implementation\n flat(...args: any[]): string {\n const { searchInput, paramsInput, absInput } = ((): {\n searchInput: Record<string, string | number>\n paramsInput: Record<string, string | number>\n absInput: boolean\n } => {\n if (args.length === 0) {\n return { searchInput: {}, paramsInput: {}, absInput: false }\n }\n const input = args[0]\n if (typeof input !== 'object' || input === null) {\n // throw new Error(\"Invalid get route input: expected object\")\n return { searchInput: {}, paramsInput: {}, absInput: args[1] ?? false }\n }\n const paramsKeys = this.getParamsKeys()\n const paramsInput = paramsKeys.reduce<Record<string, string | number>>((acc, key) => {\n if (input[key] !== undefined) {\n acc[key] = input[key]\n }\n return acc\n }, {})\n const searchKeys = this.getSearchKeys()\n const searchInput = Object.keys(input)\n .filter((k) => {\n if (searchKeys.includes(k)) {\n return true\n }\n if (paramsKeys.includes(k)) {\n return false\n }\n return true\n })\n .reduce<Record<string, string | number>>((acc, key) => {\n acc[key] = input[key]\n return acc\n }, {})\n return { searchInput, paramsInput, absInput: args[1] ?? false }\n })()\n\n return this.get({ ...paramsInput, search: searchInput, abs: absInput } as never)\n }\n\n getParamsKeys(): string[] {\n return Object.keys(this.paramsDefinition || {})\n }\n getSearchKeys(): string[] {\n return Object.keys(this.searchDefinition || {})\n }\n getFlatKeys(): string[] {\n return [...this.getSearchKeys(), ...this.getParamsKeys()]\n }\n\n getDefinition(): string {\n return this.pathDefinition\n }\n\n clone(config?: RouteConfigInput): Route0<TDefinition> {\n return new Route0(this.definition, config)\n }\n\n getRegexString(): string {\n // Normalize the path definition (remove trailing slash except for root)\n const def =\n this.pathDefinition.length > 1 && this.pathDefinition.endsWith('/')\n ? this.pathDefinition.slice(0, -1)\n : this.pathDefinition\n\n // Replace :param with placeholders, escape regex special chars, then restore capture groups\n const pattern = def\n .replace(/:([A-Za-z0-9_]+)/g, '___PARAM___') // temporarily replace params with placeholder\n .replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&') // escape regex special chars\n .replace(/___PARAM___/g, '([^/]+)') // replace placeholder with capture group\n\n return pattern\n }\n\n getRegex(): RegExp {\n return new RegExp(`^${this.getRegexString()}$`)\n }\n\n static getRegexString(routes: AnyRoute[] | AnyRoute): string {\n const routesArray = Array.isArray(routes) ? routes : [routes]\n return routesArray.map((route) => route.getRegexString()).join('|')\n }\n static getRegex(routes: AnyRoute[] | AnyRoute): RegExp {\n return new RegExp(`^(${Route0.getRegexString(routes)})$`)\n }\n\n static getLocation(href: `${string}://${string}`): UnknownLocation\n static getLocation(hrefRel: `/${string}`): UnknownLocation\n static getLocation(hrefOrHrefRel: string): UnknownLocation\n static getLocation(location: AnyLocation): UnknownLocation\n static getLocation(url: URL): UnknownLocation\n static getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation\n static getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation {\n if (hrefOrHrefRelOrLocation instanceof URL) {\n return Route0.getLocation(hrefOrHrefRelOrLocation.href)\n }\n if (typeof hrefOrHrefRelOrLocation !== 'string') {\n hrefOrHrefRelOrLocation = hrefOrHrefRelOrLocation.href || hrefOrHrefRelOrLocation.hrefRel\n }\n // Check if it's an absolute URL (starts with scheme://)\n const abs = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:\\/\\//.test(hrefOrHrefRelOrLocation)\n\n // Use dummy base only if relative\n const base = abs ? undefined : 'http://example.com'\n const url = new URL(hrefOrHrefRelOrLocation, base)\n\n // Extract search params\n const searchParams = Object.fromEntries(url.searchParams.entries())\n\n // Normalize pathname (remove trailing slash except for root)\n let pathname = url.pathname\n if (pathname.length > 1 && pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1)\n }\n\n // Common derived values\n const hrefRel = pathname + url.search + url.hash\n\n // Build the location object consistent with _GeneralLocation\n const location: UnknownLocation = {\n pathname,\n search: url.search,\n hash: url.hash,\n origin: abs ? url.origin : undefined,\n href: abs ? url.href : undefined,\n hrefRel,\n abs,\n\n // extra host-related fields (available even for relative with dummy base)\n host: abs ? url.host : undefined,\n hostname: abs ? url.hostname : undefined,\n port: abs ? url.port || undefined : undefined,\n\n // specific to UnknownLocation\n searchParams,\n params: undefined,\n route: undefined,\n exact: false,\n parent: false,\n children: false,\n }\n\n return location\n }\n\n getLocation(href: `${string}://${string}`): KnownLocation<TDefinition>\n getLocation(hrefRel: `/${string}`): KnownLocation<TDefinition>\n getLocation(hrefOrHrefRel: string): KnownLocation<TDefinition>\n getLocation(location: AnyLocation): KnownLocation<TDefinition>\n getLocation(url: AnyLocation): KnownLocation<TDefinition>\n getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): KnownLocation<TDefinition>\n getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): KnownLocation<TDefinition> {\n if (hrefOrHrefRelOrLocation instanceof URL) {\n return this.getLocation(hrefOrHrefRelOrLocation.href)\n }\n if (typeof hrefOrHrefRelOrLocation !== 'string') {\n hrefOrHrefRelOrLocation = hrefOrHrefRelOrLocation.href || hrefOrHrefRelOrLocation.hrefRel\n }\n const location = Route0.getLocation(hrefOrHrefRelOrLocation) as never as KnownLocation<TDefinition>\n location.route = this.definition as Definition<TDefinition>\n location.params = {}\n\n // Normalize pathname (no trailing slash except root)\n const pathname =\n location.pathname.length > 1 && location.pathname.endsWith('/')\n ? location.pathname.slice(0, -1)\n : location.pathname\n\n // Use getRegexString() to get the pattern\n const pattern = this.getRegexString()\n\n // Extract param names from the definition\n const paramNames: string[] = []\n const def =\n this.pathDefinition.length > 1 && this.pathDefinition.endsWith('/')\n ? this.pathDefinition.slice(0, -1)\n : this.pathDefinition\n def.replace(/:([A-Za-z0-9_]+)/g, (_m: string, name: string) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n paramNames.push(String(name))\n return ''\n })\n\n const exactRe = new RegExp(`^${pattern}$`)\n const parentRe = new RegExp(`^${pattern}(?:/.*)?$`) // route matches the beginning of the URL (may have more)\n const exactMatch = pathname.match(exactRe)\n\n // Fill params only for exact match (keeps behavior predictable)\n if (exactMatch) {\n const values = exactMatch.slice(1)\n const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? '')]))\n location.params = params\n } else {\n location.params = {}\n }\n\n const exact = !!exactMatch\n const parent = !exact && parentRe.test(pathname)\n\n // \"children\": the URL is a prefix of the route definition (params match any single segment)\n const getParts = (path: string) => (path === '/' ? ['/'] : path.split('/').filter(Boolean))\n const defParts = getParts(def)\n const pathParts = getParts(pathname)\n\n let isPrefix = true\n if (pathParts.length > defParts.length) {\n isPrefix = false\n } else {\n for (let i = 0; i < pathParts.length; i++) {\n const defPart = defParts[i]\n const pathPart = pathParts[i]\n if (!defPart) {\n isPrefix = false\n break\n }\n if (defPart.startsWith(':')) continue\n if (defPart !== pathPart) {\n isPrefix = false\n break\n }\n }\n }\n const children = !exact && isPrefix\n\n return {\n ...location,\n exact,\n parent,\n children,\n } as KnownLocation<TDefinition>\n }\n\n isSame(other: Route0<TDefinition>): boolean {\n return (\n this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__') ===\n other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__')\n )\n }\n static isSame(a: AnyRoute | string | undefined, b: AnyRoute | string | undefined): boolean {\n if ((!a && b) || (a && !b)) return false\n if (!a || !b) return true\n return Route0.create(a).isSame(Route0.create(b))\n }\n\n isChildren(other: Route0<TDefinition>): boolean {\n return (\n this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__') ===\n other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__')\n )\n }\n\n isParent(other: Route0<TDefinition>): boolean {\n return (\n other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__') ===\n this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__')\n )\n }\n\n isConflict(other: Route0<any>): boolean {\n const getParts = (path: string) => {\n if (path === '/') return ['/']\n return path.split('/').filter(Boolean)\n }\n\n const thisParts = getParts(this.pathDefinition)\n const otherParts = getParts(other.pathDefinition)\n\n // Different lengths = no conflict (one is deeper than the other)\n if (thisParts.length !== otherParts.length) {\n return false\n }\n\n // Check if all segments could match\n for (let i = 0; i < thisParts.length; i++) {\n const thisPart = thisParts[i]\n const otherPart = otherParts[i]\n\n // Both params = always match\n if (thisPart.startsWith(':') && otherPart.startsWith(':')) {\n continue\n }\n\n // One is param = can match\n if (thisPart.startsWith(':') || otherPart.startsWith(':')) {\n continue\n }\n\n // Both static = must be same\n if (thisPart !== otherPart) {\n return false\n }\n }\n\n return true\n }\n\n isMoreSpecificThan(other: Route0<any>): boolean {\n // More specific = should come earlier when conflicted\n // Static segments beat param segments at the same position\n const getParts = (path: string) => {\n if (path === '/') return ['/']\n return path.split('/').filter(Boolean)\n }\n\n const thisParts = getParts(this.pathDefinition)\n const otherParts = getParts(other.pathDefinition)\n\n // Compare segment by segment\n for (let i = 0; i < Math.min(thisParts.length, otherParts.length); i++) {\n const thisIsStatic = !thisParts[i].startsWith(':')\n const otherIsStatic = !otherParts[i].startsWith(':')\n\n if (thisIsStatic && !otherIsStatic) return true\n if (!thisIsStatic && otherIsStatic) return false\n }\n\n // All equal, use lexicographic\n return this.pathDefinition < other.pathDefinition\n }\n}\n\nexport class Routes<const T extends RoutesRecord = RoutesRecord> {\n readonly routes: RoutesRecordHydrated<T>\n readonly pathsOrdering: string[]\n readonly keysOrdering: string[]\n readonly ordered: CallabelRoute[]\n\n private constructor({\n routes,\n isHydrated = false,\n pathsOrdering,\n keysOrdering,\n ordered,\n }: {\n routes: RoutesRecordHydrated<T> | T\n isHydrated?: boolean\n pathsOrdering?: string[]\n keysOrdering?: string[]\n ordered?: CallabelRoute[]\n }) {\n this.routes = (\n isHydrated ? (routes as RoutesRecordHydrated<T>) : Routes._hydrate(routes)\n ) as RoutesRecordHydrated<T>\n if (!pathsOrdering || !keysOrdering || !ordered) {\n const ordering = Routes._makeOrdering(this.routes)\n this.pathsOrdering = ordering.pathsOrdering\n this.keysOrdering = ordering.keysOrdering\n this.ordered = this.keysOrdering.map((key) => this.routes[key])\n } else {\n this.pathsOrdering = pathsOrdering\n this.keysOrdering = keysOrdering\n this.ordered = ordered\n }\n }\n\n static create<const T extends RoutesRecord>(routes: T): RoutesPretty<T> {\n const instance = new Routes({ routes })\n return Routes._prettify(instance)\n }\n\n static _prettify<const T extends RoutesRecord>(instance: Routes<T>): RoutesPretty<T> {\n Object.setPrototypeOf(instance, Routes.prototype)\n Object.defineProperty(instance, Symbol.toStringTag, {\n value: 'Routes',\n })\n Object.assign(instance, {\n override: instance.override.bind(instance),\n })\n Object.assign(instance, instance.routes)\n return instance as unknown as RoutesPretty<T>\n }\n\n static _hydrate<const T extends RoutesRecord>(routes: T): RoutesRecordHydrated<T> {\n const result = {} as RoutesRecordHydrated<T>\n for (const key in routes) {\n if (Object.prototype.hasOwnProperty.call(routes, key)) {\n const value = routes[key]\n result[key] = (typeof value === 'string' ? Route0.create(value) : value) as CallabelRoute<T[typeof key]>\n }\n }\n return result\n }\n\n getLocation(href: `${string}://${string}`): UnknownLocation | ExactLocation\n getLocation(hrefRel: `/${string}`): UnknownLocation | ExactLocation\n getLocation(hrefOrHrefRel: string): UnknownLocation | ExactLocation\n getLocation(location: AnyLocation): UnknownLocation | ExactLocation\n getLocation(url: URL): UnknownLocation | ExactLocation\n getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation | ExactLocation\n getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation | ExactLocation {\n // Find the route that exactly matches the given location\n const input = hrefOrHrefRelOrLocation\n for (const route of this.ordered) {\n const loc = route.getLocation(hrefOrHrefRelOrLocation)\n if (loc.exact) {\n return loc\n }\n }\n // No exact match found, return UnknownLocation\n return typeof input === 'string' ? Route0.getLocation(input) : Route0.getLocation(input)\n }\n\n static _makeOrdering(routes: RoutesRecord): { pathsOrdering: string[]; keysOrdering: string[] } {\n const hydrated = Routes._hydrate(routes)\n const entries = Object.entries(hydrated)\n\n const getParts = (path: string) => {\n if (path === '/') return ['/']\n return path.split('/').filter(Boolean)\n }\n\n // Sort: shorter paths first, then by specificity, then alphabetically\n entries.sort(([_keyA, routeA], [_keyB, routeB]) => {\n const partsA = getParts(routeA.pathDefinition)\n const partsB = getParts(routeB.pathDefinition)\n\n // 1. Shorter paths first (by segment count)\n if (partsA.length !== partsB.length) {\n return partsA.length - partsB.length\n }\n\n // 2. Same length: check if they conflict\n if (routeA.isConflict(routeB)) {\n // Conflicting routes: more specific first\n if (routeA.isMoreSpecificThan(routeB)) return -1\n if (routeB.isMoreSpecificThan(routeA)) return 1\n }\n\n // 3. Same length, not conflicting or equal specificity: alphabetically\n return routeA.pathDefinition.localeCompare(routeB.pathDefinition)\n })\n\n const pathsOrdering = entries.map(([_key, route]) => route.definition)\n const keysOrdering = entries.map(([_key, route]) => _key)\n return { pathsOrdering, keysOrdering }\n }\n\n override(config: RouteConfigInput): RoutesPretty<T> {\n const newRoutes = {} as RoutesRecordHydrated<T>\n for (const key in this.routes) {\n if (Object.prototype.hasOwnProperty.call(this.routes, key)) {\n newRoutes[key] = this.routes[key].clone(config) as CallabelRoute<T[typeof key]>\n }\n }\n const instance = new Routes({\n routes: newRoutes,\n isHydrated: true,\n pathsOrdering: this.pathsOrdering,\n keysOrdering: this.keysOrdering,\n ordered: this.keysOrdering.map((key) => newRoutes[key]),\n })\n return Routes._prettify(instance)\n }\n}\n\n// main\n\nexport type AnyRoute<T extends Route0<string> | string = string> = T extends string ? Route0<T> : T\nexport type CallabelRoute<T extends Route0<string> | string = string> = AnyRoute<T> & AnyRoute<T>['get']\nexport type AnyRouteOrDefinition<T extends string = string> = AnyRoute<T> | CallabelRoute<T> | T\nexport type RouteConfigInput = {\n baseUrl?: string\n}\n\n// collection\n\nexport type RoutesRecord = Record<string, AnyRoute | string>\nexport type RoutesRecordHydrated<TRoutesRecord extends RoutesRecord = RoutesRecord> = {\n [K in keyof TRoutesRecord]: CallabelRoute<TRoutesRecord[K]>\n}\nexport type RoutesPretty<TRoutesRecord extends RoutesRecord = RoutesRecord> = RoutesRecordHydrated<TRoutesRecord> &\n Routes<TRoutesRecord>\nexport type ExtractRoutesKeys<TRoutes extends RoutesPretty | RoutesRecord> = TRoutes extends RoutesPretty\n ? keyof TRoutes['routes']\n : TRoutes extends RoutesRecord\n ? keyof TRoutes\n : never\nexport type ExtractRoute<\n TRoutes extends RoutesPretty | RoutesRecord,\n TKey extends keyof ExtractRoutesKeys<TRoutes>,\n> = TKey extends keyof TRoutes ? TRoutes[TKey] : never\n\n// public utils\n\nexport type Definition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['definition']\n : T extends string\n ? T\n : never\nexport type PathDefinition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['pathDefinition']\n : T extends string\n ? _PathDefinition<T>\n : never\nexport type ParamsDefinition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['paramsDefinition']\n : T extends string\n ? _ParamsDefinition<T>\n : undefined\nexport type SearchDefinition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['searchDefinition']\n : T extends string\n ? _SearchDefinition<T>\n : undefined\n\nexport type Extended<T extends AnyRoute | string | undefined, TSuffixDefinition extends string> = T extends AnyRoute\n ? Route0<PathExtended<T['definition'], TSuffixDefinition>>\n : T extends string\n ? Route0<PathExtended<T, TSuffixDefinition>>\n : T extends undefined\n ? Route0<TSuffixDefinition>\n : never\n\nexport type IsParent<T extends AnyRoute | string, TParent extends AnyRoute | string> = _IsParent<\n PathDefinition<T>,\n PathDefinition<TParent>\n>\nexport type IsChildren<T extends AnyRoute | string, TChildren extends AnyRoute | string> = _IsChildren<\n PathDefinition<T>,\n PathDefinition<TChildren>\n>\nexport type IsSame<T extends AnyRoute | string, TExact extends AnyRoute | string> = _IsSame<\n PathDefinition<T>,\n PathDefinition<TExact>\n>\nexport type IsSameParams<T1 extends AnyRoute | string, T2 extends AnyRoute | string> = _IsSameParams<\n ParamsDefinition<T1>,\n ParamsDefinition<T2>\n>\n\nexport type HasParams<T extends AnyRoute | string> =\n ExtractPathParams<PathDefinition<T>> extends infer U ? ([U] extends [never] ? false : true) : false\nexport type HasSearch<T extends AnyRoute | string> =\n NonEmpty<SearchTailDefinitionWithoutFirstAmp<Definition<T>>> extends infer Tail extends string\n ? AmpSplit<Tail> extends infer U\n ? [U] extends [never]\n ? false\n : true\n : false\n : false\n\nexport type ParamsOutput<T extends AnyRoute | string> = {\n [K in keyof ParamsDefinition<T>]: string\n}\nexport type SearchOutput<T extends AnyRoute | string = string> = Partial<\n {\n [K in keyof SearchDefinition<T>]?: string\n } & Record<string, string | undefined>\n>\nexport type StrictSearchOutput<T extends AnyRoute | string> = Partial<{\n [K in keyof SearchDefinition<T>]?: string | undefined\n}>\nexport type FlatOutput<T extends AnyRoute | string = string> =\n HasParams<Definition<T>> extends true ? ParamsOutput<T> & SearchOutput<T> : SearchOutput<T>\nexport type StrictFlatOutput<T extends AnyRoute | string> =\n HasParams<Definition<T>> extends true ? ParamsOutput<T> & StrictSearchOutput<T> : StrictSearchOutput<T>\nexport type ParamsInput<T extends AnyRoute | string = string> = _ParamsInput<PathDefinition<T>>\nexport type SearchInput<T extends AnyRoute | string = string> = _SearchInput<Definition<T>>\nexport type StrictSearchInput<T extends AnyRoute | string> = _StrictSearchInput<Definition<T>>\nexport type FlatInput<T extends AnyRoute | string> = _FlatInput<Definition<T>>\nexport type StrictFlatInput<T extends AnyRoute | string> = _StrictFlatInput<Definition<T>>\nexport type CanInputBeEmpty<T extends AnyRoute | string> = HasParams<Definition<T>> extends true ? false : true\n\n// location\n\nexport type LocationParams<TDefinition extends string> = {\n [K in keyof _ParamsDefinition<TDefinition>]: string\n}\nexport type LocationSearch<TDefinition extends string = string> = {\n [K in keyof _SearchDefinition<TDefinition>]: string | undefined\n} & Record<string, string | undefined>\n\nexport type _GeneralLocation = {\n pathname: string\n search: string\n hash: string\n origin?: string\n href?: string\n hrefRel: string\n abs: boolean\n port?: string\n host?: string\n hostname?: string\n}\nexport type UnknownLocation = _GeneralLocation & {\n params: undefined\n searchParams: SearchOutput\n route: undefined\n exact: false\n parent: false\n children: false\n}\nexport type UnmatchedLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {\n params: Record<never, never>\n searchParams: SearchOutput<TRoute>\n route: Definition<TRoute>\n exact: false\n parent: false\n children: false\n}\nexport type ExactLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {\n params: ParamsOutput<TRoute>\n searchParams: SearchOutput<TRoute>\n route: Definition<TRoute>\n exact: true\n parent: false\n children: false\n}\nexport type ParentLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {\n params: Partial<ParamsOutput<TRoute>> // in fact maybe there will be whole params object, but does not matter now\n searchParams: SearchOutput<TRoute>\n route: Definition<TRoute>\n exact: false\n parent: true\n children: false\n}\nexport type ChildrenLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {\n params: ParamsOutput<TRoute>\n searchParams: SearchOutput<TRoute>\n route: Definition<TRoute>\n exact: false\n parent: false\n children: true\n}\nexport type KnownLocation<TRoute extends AnyRoute | string = AnyRoute | string> =\n | UnmatchedLocation<TRoute>\n | ExactLocation<TRoute>\n | ParentLocation<TRoute>\n | ChildrenLocation<TRoute>\nexport type AnyLocation<TRoute extends AnyRoute = AnyRoute> = UnknownLocation | KnownLocation<TRoute>\n\n// internal utils\n\nexport type _PathDefinition<T extends string> = T extends string ? TrimSearchTailDefinition<T> : never\nexport type _ParamsDefinition<TDefinition extends string> =\n ExtractPathParams<PathDefinition<TDefinition>> extends infer U\n ? [U] extends [never]\n ? undefined\n : { [K in Extract<U, string>]: true }\n : undefined\nexport type _SearchDefinition<TDefinition extends string> =\n NonEmpty<SearchTailDefinitionWithoutFirstAmp<TDefinition>> extends infer Tail extends string\n ? AmpSplit<Tail> extends infer U\n ? [U] extends [never]\n ? undefined\n : { [K in Extract<U, string>]: true }\n : undefined\n : undefined\n\nexport type _ParamsInput<TDefinition extends string> =\n _ParamsDefinition<TDefinition> extends undefined\n ? Record<never, never>\n : {\n [K in keyof _ParamsDefinition<TDefinition>]: string | number\n }\nexport type _SearchInput<TDefinition extends string> =\n _SearchDefinition<TDefinition> extends undefined\n ? Record<string, string | number>\n : Partial<{\n [K in keyof _SearchDefinition<TDefinition>]: string | number\n }> &\n Record<string, string | number>\nexport type _StrictSearchInput<TDefinition extends string> = Partial<{\n [K in keyof _SearchDefinition<TDefinition>]: string | number\n}>\nexport type _FlatInput<TDefinition extends string> =\n HasParams<TDefinition> extends true\n ? _ParamsInput<TDefinition> & _SearchInput<TDefinition>\n : _SearchInput<TDefinition>\nexport type _StrictFlatInput<TDefinition extends string> =\n HasParams<TDefinition> extends true\n ? HasSearch<TDefinition> extends true\n ? _StrictSearchInput<TDefinition> & _ParamsInput<TDefinition>\n : _ParamsInput<TDefinition>\n : HasSearch<TDefinition> extends true\n ? _StrictSearchInput<TDefinition>\n : Record<never, never>\n\nexport type TrimSearchTailDefinition<S extends string> = S extends `${infer P}&${string}` ? P : S\nexport type SearchTailDefinitionWithoutFirstAmp<S extends string> = S extends `${string}&${infer T}` ? T : ''\nexport type SearchTailDefinitionWithFirstAmp<S extends string> = S extends `${string}&${infer T}` ? `&${T}` : ''\nexport type AmpSplit<S extends string> = S extends `${infer A}&${infer B}` ? A | AmpSplit<B> : S\n// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\nexport type NonEmpty<T> = [T] extends ['' | never] ? never : T\nexport type ExtractPathParams<S extends string> = S extends `${string}:${infer After}`\n ? After extends `${infer Name}/${infer Rest}`\n ? Name | ExtractPathParams<`/${Rest}`>\n : After\n : never\nexport type ReplacePathParams<S extends string> = S extends `${infer Head}:${infer Tail}`\n ? // eslint-disable-next-line @typescript-eslint/no-unused-vars\n Tail extends `${infer _Param}/${infer Rest}`\n ? ReplacePathParams<`${Head}${string}/${Rest}`>\n : `${Head}${string}`\n : S\nexport type DedupeSlashes<S extends string> = S extends `${infer A}//${infer B}` ? DedupeSlashes<`${A}/${B}`> : S\nexport type EmptyRecord = Record<never, never>\nexport type JoinPath<Parent extends string, Suffix extends string> = DedupeSlashes<\n PathDefinition<Parent> extends infer A extends string\n ? PathDefinition<Suffix> extends infer B extends string\n ? A extends ''\n ? B extends ''\n ? ''\n : B extends `/${string}`\n ? B\n : `/${B}`\n : B extends ''\n ? A\n : A extends `${string}/`\n ? `${A}${B}`\n : B extends `/${string}`\n ? `${A}${B}`\n : `${A}/${B}`\n : never\n : never\n>\n\nexport type OnlyIfNoParams<TParams extends object | undefined, Yes, No = never> = TParams extends undefined ? Yes : No\nexport type OnlyIfHasParams<TParams extends object | undefined, Yes, No = never> = TParams extends undefined ? No : Yes\n\nexport type PathOnlyRouteValue<TDefinition extends string> = `${ReplacePathParams<PathDefinition<TDefinition>>}`\nexport type WithSearchRouteValue<TDefinition extends string> =\n `${ReplacePathParams<PathDefinition<TDefinition>>}?${string}`\nexport type AbsolutePathOnlyRouteValue<TDefinition extends string> =\n PathOnlyRouteValue<TDefinition> extends '/' ? string : `${string}${PathOnlyRouteValue<TDefinition>}`\nexport type AbsoluteWithSearchRouteValue<TDefinition extends string> = `${string}${WithSearchRouteValue<TDefinition>}`\n\nexport type PathExtended<\n TSourcedefinitionDefinition extends string,\n TSuffixdefinitionDefinition extends string,\n> = `${JoinPath<TSourcedefinitionDefinition, TSuffixdefinitionDefinition>}${SearchTailDefinitionWithFirstAmp<TSuffixdefinitionDefinition>}`\n\nexport type WithParamsInput<\n TDefinition extends string,\n T extends\n | {\n search?: _SearchInput<any>\n abs?: boolean\n }\n | undefined = undefined,\n> = _ParamsInput<TDefinition> & (T extends undefined ? Record<never, never> : T)\n\nexport type _IsSameParams<T1 extends object | undefined, T2 extends object | undefined> = T1 extends undefined\n ? T2 extends undefined\n ? true\n : false\n : T2 extends undefined\n ? false\n : T1 extends T2\n ? T2 extends T1\n ? true\n : false\n : false\n\nexport type _IsParent<T extends string, TParent extends string> = T extends TParent\n ? false\n : T extends `${TParent}${string}`\n ? true\n : false\nexport type _IsChildren<T extends string, TChildren extends string> = TChildren extends T\n ? false\n : TChildren extends `${T}${string}`\n ? true\n : false\nexport type _IsSame<T extends string, TExact extends string> = T extends TExact\n ? TExact extends T\n ? true\n : false\n : false\n"],"mappings":"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","names":["paramsInput","searchInput"]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// TODO: asterisk\n// TODO: when asterisk then query params will be extended also after extend\n// TODO: optional params\n// TODO: required search\n\n// TODO: .extension('.json') to not add additional / but just add some extension\n// TODO: search input can be boolean, or even object with qs\n// TODO: Роут0 три пусть три тоже сам генерится вероятно\n// TODO: Роут0 три мод, тогда там все ноуты кончаются на .селф\n// TODO: use splats in param definition \"*\"\n// TODO: ? check extend for search only .extend('&x&z')\n// TODO: .create(route, {useSearch, useParams})\n// TODO: Из пас экзакт, из пасвизквери экзает, из чилдрен, из парент, из экзактОр\n// TODO: isEqual, isChildren, isParent\n// TODO: extractParams, extractSearch\n// TODO: getPathDefinition respecting definitionParamPrefix, definitionSearchPrefix\n// TODO: prepend\n// TODO: Route0.createTree({base:{self: x, children: ...})\n// TODO: overrideTree\n// TODO: .create(route, {baseUrl, useLocation})\n// TODO: ? optional path params as @\n// TODO: prependMany, extendMany, overrideMany, with types\n// TODO: optional route params /x/:id?\n\nexport class Route0<TDefinition extends string> {\n readonly definition: TDefinition\n readonly pathDefinition: _PathDefinition<TDefinition>\n readonly paramsDefinition: _ParamsDefinition<TDefinition>\n readonly searchDefinition: _SearchDefinition<TDefinition>\n baseUrl: string\n\n private constructor(definition: TDefinition, config: RouteConfigInput = {}) {\n this.definition = definition\n this.pathDefinition = Route0._getPathDefinitionBydefinition(definition)\n this.paramsDefinition = Route0._getParamsDefinitionBydefinition(definition)\n this.searchDefinition = Route0._getSearchDefinitionBydefinition(definition)\n\n const { baseUrl } = config\n if (baseUrl && typeof baseUrl === 'string' && baseUrl.length) {\n this.baseUrl = baseUrl\n } else {\n const g = globalThis as unknown as { location?: { origin?: string } }\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (typeof g?.location?.origin === 'string' && g.location.origin.length > 0) {\n this.baseUrl = g.location.origin\n } else {\n this.baseUrl = 'https://example.com'\n }\n }\n }\n\n static create<TDefinition extends string>(\n definition: TDefinition | AnyRoute<TDefinition>,\n config?: RouteConfigInput,\n ): CallabelRoute<TDefinition> {\n if (typeof definition === 'function') {\n return definition\n }\n const original = typeof definition === 'object' ? definition : new Route0<TDefinition>(definition, config)\n const callable = original.get.bind(original)\n Object.setPrototypeOf(callable, original)\n Object.defineProperty(callable, Symbol.toStringTag, {\n value: original.definition,\n })\n return callable as never\n }\n\n private static _splitPathDefinitionAndSearchTailDefinition(definition: string) {\n const i = definition.indexOf('&')\n if (i === -1) return { pathDefinition: definition, searchTailDefinition: '' }\n return {\n pathDefinition: definition.slice(0, i),\n searchTailDefinition: definition.slice(i),\n }\n }\n\n private static _getAbsPath(baseUrl: string, pathWithSearch: string) {\n return new URL(pathWithSearch, baseUrl).toString().replace(/\\/$/, '')\n }\n\n private static _getPathDefinitionBydefinition<TDefinition extends string>(definition: TDefinition) {\n const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(definition)\n return pathDefinition as _PathDefinition<TDefinition>\n }\n\n private static _getParamsDefinitionBydefinition<TDefinition extends string>(\n definition: TDefinition,\n ): _ParamsDefinition<TDefinition> {\n const { pathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(definition)\n const matches = Array.from(pathDefinition.matchAll(/:([A-Za-z0-9_]+)/g))\n const paramsDefinition = Object.fromEntries(matches.map((m) => [m[1], true]))\n const keysCount = Object.keys(paramsDefinition).length\n if (keysCount === 0) {\n return undefined as _ParamsDefinition<TDefinition>\n }\n return paramsDefinition as _ParamsDefinition<TDefinition>\n }\n\n private static _getSearchDefinitionBydefinition<TDefinition extends string>(\n definition: TDefinition,\n ): _SearchDefinition<TDefinition> {\n const { searchTailDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(definition)\n if (!searchTailDefinition) {\n return undefined as _SearchDefinition<TDefinition>\n }\n const keys = searchTailDefinition.split('&').filter(Boolean)\n const searchDefinition = Object.fromEntries(keys.map((k) => [k, true]))\n const keysCount = Object.keys(searchDefinition).length\n if (keysCount === 0) {\n return undefined as _SearchDefinition<TDefinition>\n }\n return searchDefinition as _SearchDefinition<TDefinition>\n }\n\n extend<TSuffixDefinition extends string>(\n suffixDefinition: TSuffixDefinition,\n ): CallabelRoute<PathExtended<TDefinition, TSuffixDefinition>> {\n const { pathDefinition: parentPathDefinition } = Route0._splitPathDefinitionAndSearchTailDefinition(this.definition)\n const { pathDefinition: suffixPathDefinition, searchTailDefinition: suffixSearchTailDefinition } =\n Route0._splitPathDefinitionAndSearchTailDefinition(suffixDefinition)\n const pathDefinition = `${parentPathDefinition}/${suffixPathDefinition}`.replace(/\\/{2,}/g, '/')\n const definition = `${pathDefinition}${suffixSearchTailDefinition}` as PathExtended<TDefinition, TSuffixDefinition>\n return Route0.create<PathExtended<TDefinition, TSuffixDefinition>>(definition, { baseUrl: this.baseUrl })\n }\n\n // has params\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TDefinition>,\n WithParamsInput<TDefinition, { search?: undefined; abs?: false }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, PathOnlyRouteValue<TDefinition>>\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TDefinition>,\n WithParamsInput<TDefinition, { search: _SearchInput<TDefinition>; abs?: false }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithSearchRouteValue<TDefinition>>\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TDefinition>,\n WithParamsInput<TDefinition, { search?: undefined; abs: true }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, AbsolutePathOnlyRouteValue<TDefinition>>\n get(\n input: OnlyIfHasParams<\n _ParamsDefinition<TDefinition>,\n WithParamsInput<TDefinition, { search: _SearchInput<TDefinition>; abs: true }>\n >,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, AbsoluteWithSearchRouteValue<TDefinition>>\n\n // no params\n get(...args: OnlyIfNoParams<_ParamsDefinition<TDefinition>, [], [never]>): PathOnlyRouteValue<TDefinition>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, { search?: undefined; abs?: false }>,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, PathOnlyRouteValue<TDefinition>>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, { search: _SearchInput<TDefinition>; abs?: false }>,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, WithSearchRouteValue<TDefinition>>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, { search?: undefined; abs: true }>,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsolutePathOnlyRouteValue<TDefinition>>\n get(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, { search: _SearchInput<TDefinition>; abs: true }>,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsoluteWithSearchRouteValue<TDefinition>>\n\n // implementation\n get(...args: any[]): string {\n const { searchInput, paramsInput, absInput } = ((): {\n searchInput: Record<string, string | number>\n paramsInput: Record<string, string | number>\n absInput: boolean\n } => {\n if (args.length === 0) {\n return { searchInput: {}, paramsInput: {}, absInput: false }\n }\n const input = args[0]\n if (typeof input !== 'object' || input === null) {\n // throw new Error(\"Invalid get route input: expected object\")\n return { searchInput: {}, paramsInput: {}, absInput: false }\n }\n const { search, abs, ...params } = input\n return { searchInput: search || {}, paramsInput: params, absInput: abs ?? false }\n })()\n\n // validate params\n const neededParamsKeys = this.paramsDefinition ? Object.keys(this.paramsDefinition) : []\n const providedParamsKeys = Object.keys(paramsInput)\n const notProvidedKeys = neededParamsKeys.filter((k) => !providedParamsKeys.includes(k))\n if (notProvidedKeys.length) {\n // throw new Error(`Missing params: not defined keys ${notProvidedKeys.map((k) => `\"${k}\"`).join(\", \")}.`)\n Object.assign(paramsInput, Object.fromEntries(notProvidedKeys.map((k) => [k, 'undefined'])))\n }\n\n // create url\n\n let url = this.pathDefinition as string\n // replace params\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n url = url.replace(/:([A-Za-z0-9_]+)/g, (_m, k) => encodeURIComponent(String(paramsInput?.[k] ?? '')))\n // search params\n const searchInputStringified = Object.fromEntries(Object.entries(searchInput).map(([k, v]) => [k, String(v)]))\n url = [url, new URLSearchParams(searchInputStringified).toString()].filter(Boolean).join('?')\n // dedupe slashes\n url = url.replace(/\\/{2,}/g, '/')\n // absolute\n url = absInput ? Route0._getAbsPath(this.baseUrl, url) : url\n\n return url\n }\n\n // has params\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithParamsInput<TDefinition>>,\n abs?: false,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, PathOnlyRouteValue<TDefinition>>\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithParamsInput<TDefinition, _SearchInput<TDefinition>>>,\n abs?: false,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithSearchRouteValue<TDefinition>>\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithParamsInput<TDefinition>>,\n abs: true,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, AbsolutePathOnlyRouteValue<TDefinition>>\n flat(\n input: OnlyIfHasParams<_ParamsDefinition<TDefinition>, WithParamsInput<TDefinition, _SearchInput<TDefinition>>>,\n abs: true,\n ): OnlyIfHasParams<_ParamsDefinition<TDefinition>, AbsoluteWithSearchRouteValue<TDefinition>>\n\n // no params\n flat(...args: OnlyIfNoParams<_ParamsDefinition<TDefinition>, [], [never]>): PathOnlyRouteValue<TDefinition>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, Record<never, never>>,\n abs?: false,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, PathOnlyRouteValue<TDefinition>>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, _SearchInput<TDefinition>>,\n abs?: false,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, WithSearchRouteValue<TDefinition>>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, Record<never, never>>,\n abs: true,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsolutePathOnlyRouteValue<TDefinition>>\n flat(\n input: OnlyIfNoParams<_ParamsDefinition<TDefinition>, _SearchInput<TDefinition>>,\n abs: true,\n ): OnlyIfNoParams<_ParamsDefinition<TDefinition>, AbsoluteWithSearchRouteValue<TDefinition>>\n\n // implementation\n flat(...args: any[]): string {\n const { searchInput, paramsInput, absInput } = ((): {\n searchInput: Record<string, string | number>\n paramsInput: Record<string, string | number>\n absInput: boolean\n } => {\n if (args.length === 0) {\n return { searchInput: {}, paramsInput: {}, absInput: false }\n }\n const input = args[0]\n if (typeof input !== 'object' || input === null) {\n // throw new Error(\"Invalid get route input: expected object\")\n return { searchInput: {}, paramsInput: {}, absInput: args[1] ?? false }\n }\n const paramsKeys = this.getParamsKeys()\n const paramsInput = paramsKeys.reduce<Record<string, string | number>>((acc, key) => {\n if (input[key] !== undefined) {\n acc[key] = input[key]\n }\n return acc\n }, {})\n const searchKeys = this.getSearchKeys()\n const searchInput = Object.keys(input)\n .filter((k) => {\n if (searchKeys.includes(k)) {\n return true\n }\n if (paramsKeys.includes(k)) {\n return false\n }\n return true\n })\n .reduce<Record<string, string | number>>((acc, key) => {\n acc[key] = input[key]\n return acc\n }, {})\n return { searchInput, paramsInput, absInput: args[1] ?? false }\n })()\n\n return this.get({ ...paramsInput, search: searchInput, abs: absInput } as never)\n }\n\n getParamsKeys(): string[] {\n return Object.keys(this.paramsDefinition || {})\n }\n getSearchKeys(): string[] {\n return Object.keys(this.searchDefinition || {})\n }\n getFlatKeys(): string[] {\n return [...this.getSearchKeys(), ...this.getParamsKeys()]\n }\n\n getDefinition(): string {\n return this.pathDefinition\n }\n\n clone(config?: RouteConfigInput): Route0<TDefinition> {\n return new Route0(this.definition, config)\n }\n\n getRegexString(): string {\n // Normalize the path definition (remove trailing slash except for root)\n const def =\n this.pathDefinition.length > 1 && this.pathDefinition.endsWith('/')\n ? this.pathDefinition.slice(0, -1)\n : this.pathDefinition\n\n // Replace :param with placeholders, escape regex special chars, then restore capture groups\n const pattern = def\n .replace(/:([A-Za-z0-9_]+)/g, '___PARAM___') // temporarily replace params with placeholder\n .replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&') // escape regex special chars\n .replace(/___PARAM___/g, '([^/]+)') // replace placeholder with capture group\n\n return pattern\n }\n\n getRegex(): RegExp {\n return new RegExp(`^${this.getRegexString()}$`)\n }\n\n static getRegexString(routes: AnyRoute[] | AnyRoute): string {\n const routesArray = Array.isArray(routes) ? routes : [routes]\n return routesArray.map((route) => route.getRegexString()).join('|')\n }\n static getRegex(routes: AnyRoute[] | AnyRoute): RegExp {\n return new RegExp(`^(${Route0.getRegexString(routes)})$`)\n }\n\n static getLocation(href: `${string}://${string}`): UnknownLocation\n static getLocation(hrefRel: `/${string}`): UnknownLocation\n static getLocation(hrefOrHrefRel: string): UnknownLocation\n static getLocation(location: AnyLocation): UnknownLocation\n static getLocation(url: URL): UnknownLocation\n static getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation\n static getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation {\n if (hrefOrHrefRelOrLocation instanceof URL) {\n return Route0.getLocation(hrefOrHrefRelOrLocation.href)\n }\n if (typeof hrefOrHrefRelOrLocation !== 'string') {\n hrefOrHrefRelOrLocation = hrefOrHrefRelOrLocation.href || hrefOrHrefRelOrLocation.hrefRel\n }\n // Check if it's an absolute URL (starts with scheme://)\n const abs = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:\\/\\//.test(hrefOrHrefRelOrLocation)\n\n // Use dummy base only if relative\n const base = abs ? undefined : 'http://example.com'\n const url = new URL(hrefOrHrefRelOrLocation, base)\n\n // Extract search params\n const searchParams = Object.fromEntries(url.searchParams.entries())\n\n // Normalize pathname (remove trailing slash except for root)\n let pathname = url.pathname\n if (pathname.length > 1 && pathname.endsWith('/')) {\n pathname = pathname.slice(0, -1)\n }\n\n // Common derived values\n const hrefRel = pathname + url.search + url.hash\n\n // Build the location object consistent with _GeneralLocation\n const location: UnknownLocation = {\n pathname,\n search: url.search,\n hash: url.hash,\n origin: abs ? url.origin : undefined,\n href: abs ? url.href : undefined,\n hrefRel,\n abs,\n\n // extra host-related fields (available even for relative with dummy base)\n host: abs ? url.host : undefined,\n hostname: abs ? url.hostname : undefined,\n port: abs ? url.port || undefined : undefined,\n\n // specific to UnknownLocation\n searchParams,\n params: undefined,\n route: undefined,\n exact: false,\n parent: false,\n children: false,\n }\n\n return location\n }\n\n getLocation(href: `${string}://${string}`): KnownLocation<TDefinition>\n getLocation(hrefRel: `/${string}`): KnownLocation<TDefinition>\n getLocation(hrefOrHrefRel: string): KnownLocation<TDefinition>\n getLocation(location: AnyLocation): KnownLocation<TDefinition>\n getLocation(url: AnyLocation): KnownLocation<TDefinition>\n getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): KnownLocation<TDefinition>\n getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): KnownLocation<TDefinition> {\n if (hrefOrHrefRelOrLocation instanceof URL) {\n return this.getLocation(hrefOrHrefRelOrLocation.href)\n }\n if (typeof hrefOrHrefRelOrLocation !== 'string') {\n hrefOrHrefRelOrLocation = hrefOrHrefRelOrLocation.href || hrefOrHrefRelOrLocation.hrefRel\n }\n const location = Route0.getLocation(hrefOrHrefRelOrLocation) as never as KnownLocation<TDefinition>\n location.route = this.definition as Definition<TDefinition>\n location.params = {}\n\n // Normalize pathname (no trailing slash except root)\n const pathname =\n location.pathname.length > 1 && location.pathname.endsWith('/')\n ? location.pathname.slice(0, -1)\n : location.pathname\n\n // Use getRegexString() to get the pattern\n const pattern = this.getRegexString()\n\n // Extract param names from the definition\n const paramNames: string[] = []\n const def =\n this.pathDefinition.length > 1 && this.pathDefinition.endsWith('/')\n ? this.pathDefinition.slice(0, -1)\n : this.pathDefinition\n def.replace(/:([A-Za-z0-9_]+)/g, (_m: string, name: string) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n paramNames.push(String(name))\n return ''\n })\n\n const exactRe = new RegExp(`^${pattern}$`)\n const parentRe = new RegExp(`^${pattern}(?:/.*)?$`) // route matches the beginning of the URL (may have more)\n const exactMatch = pathname.match(exactRe)\n\n // Fill params only for exact match (keeps behavior predictable)\n if (exactMatch) {\n const values = exactMatch.slice(1)\n const params = Object.fromEntries(paramNames.map((n, i) => [n, decodeURIComponent(values[i] ?? '')]))\n location.params = params\n } else {\n location.params = {}\n }\n\n const exact = !!exactMatch\n const parent = !exact && parentRe.test(pathname)\n\n // \"children\": the URL is a prefix of the route definition (params match any single segment)\n const getParts = (path: string) => (path === '/' ? ['/'] : path.split('/').filter(Boolean))\n const defParts = getParts(def)\n const pathParts = getParts(pathname)\n\n let isPrefix = true\n if (pathParts.length > defParts.length) {\n isPrefix = false\n } else {\n for (let i = 0; i < pathParts.length; i++) {\n const defPart = defParts[i]\n const pathPart = pathParts[i]\n if (!defPart) {\n isPrefix = false\n break\n }\n if (defPart.startsWith(':')) continue\n if (defPart !== pathPart) {\n isPrefix = false\n break\n }\n }\n }\n const children = !exact && isPrefix\n\n return {\n ...location,\n exact,\n parent,\n children,\n } as KnownLocation<TDefinition>\n }\n\n isSame(other: Route0<TDefinition>): boolean {\n return (\n this.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__') ===\n other.pathDefinition.replace(/:([A-Za-z0-9_]+)/g, '__PARAM__')\n )\n }\n static isSame(a: AnyRoute | string | undefined, b: AnyRoute | string | undefined): boolean {\n if ((!a && b) || (a && !b)) return false\n if (!a || !b) return true\n return Route0.create(a).isSame(Route0.create(b))\n }\n\n isChildren(other: Route0<TDefinition>): boolean {\n // this is a child of other if:\n // - paths are not exactly the same\n // - other's path is a prefix of this path, matching params as wildcards\n const getParts = (path: string) => (path === '/' ? ['/'] : path.split('/').filter(Boolean))\n const thisParts = getParts(this.pathDefinition)\n const otherParts = getParts(other.pathDefinition)\n\n // A child must be deeper\n if (thisParts.length <= otherParts.length) return false\n\n for (let i = 0; i < otherParts.length; i++) {\n const otherPart = otherParts[i]\n const thisPart = thisParts[i]\n if (otherPart.startsWith(':')) continue\n if (otherPart !== thisPart) return false\n }\n // Not equal (depth already ensures not equal)\n return true\n }\n\n isParent(other: Route0<TDefinition>): boolean {\n // this is a parent of other if:\n // - paths are not exactly the same\n // - this path is a prefix of other path, matching params as wildcards\n const getParts = (path: string) => (path === '/' ? ['/'] : path.split('/').filter(Boolean))\n const thisParts = getParts(this.pathDefinition)\n const otherParts = getParts(other.pathDefinition)\n\n // A parent must be shallower\n if (thisParts.length >= otherParts.length) return false\n\n for (let i = 0; i < thisParts.length; i++) {\n const thisPart = thisParts[i]\n const otherPart = otherParts[i]\n if (thisPart.startsWith(':')) continue\n if (thisPart !== otherPart) return false\n }\n // Not equal (depth already ensures not equal)\n return true\n }\n\n isConflict(other: Route0<any>): boolean {\n const getParts = (path: string) => {\n if (path === '/') return ['/']\n return path.split('/').filter(Boolean)\n }\n\n const thisParts = getParts(this.pathDefinition)\n const otherParts = getParts(other.pathDefinition)\n\n // Different lengths = no conflict (one is deeper than the other)\n if (thisParts.length !== otherParts.length) {\n return false\n }\n\n // Check if all segments could match\n for (let i = 0; i < thisParts.length; i++) {\n const thisPart = thisParts[i]\n const otherPart = otherParts[i]\n\n // Both params = always match\n if (thisPart.startsWith(':') && otherPart.startsWith(':')) {\n continue\n }\n\n // One is param = can match\n if (thisPart.startsWith(':') || otherPart.startsWith(':')) {\n continue\n }\n\n // Both static = must be same\n if (thisPart !== otherPart) {\n return false\n }\n }\n\n return true\n }\n\n isMoreSpecificThan(other: Route0<any>): boolean {\n // More specific = should come earlier when conflicted\n // Static segments beat param segments at the same position\n const getParts = (path: string) => {\n if (path === '/') return ['/']\n return path.split('/').filter(Boolean)\n }\n\n const thisParts = getParts(this.pathDefinition)\n const otherParts = getParts(other.pathDefinition)\n\n // Compare segment by segment\n for (let i = 0; i < Math.min(thisParts.length, otherParts.length); i++) {\n const thisIsStatic = !thisParts[i].startsWith(':')\n const otherIsStatic = !otherParts[i].startsWith(':')\n\n if (thisIsStatic && !otherIsStatic) return true\n if (!thisIsStatic && otherIsStatic) return false\n }\n\n // All equal, use lexicographic\n return this.pathDefinition < other.pathDefinition\n }\n}\n\nexport class Routes<const T extends RoutesRecord = RoutesRecord> {\n private readonly routes: RoutesRecordHydrated<T>\n private readonly pathsOrdering: string[]\n private readonly keysOrdering: string[]\n private readonly ordered: CallabelRoute[]\n\n _: {\n getLocation: Routes<T>['getLocation']\n override: Routes<T>['override']\n pathsOrdering: Routes<T>['pathsOrdering']\n keysOrdering: Routes<T>['keysOrdering']\n ordered: Routes<T>['ordered']\n }\n\n private constructor({\n routes,\n isHydrated = false,\n pathsOrdering,\n keysOrdering,\n ordered,\n }: {\n routes: RoutesRecordHydrated<T> | T\n isHydrated?: boolean\n pathsOrdering?: string[]\n keysOrdering?: string[]\n ordered?: CallabelRoute[]\n }) {\n this.routes = (isHydrated ? (routes as RoutesRecordHydrated<T>) : Routes.hydrate(routes)) as RoutesRecordHydrated<T>\n if (!pathsOrdering || !keysOrdering || !ordered) {\n const ordering = Routes.makeOrdering(this.routes)\n this.pathsOrdering = ordering.pathsOrdering\n this.keysOrdering = ordering.keysOrdering\n this.ordered = this.keysOrdering.map((key) => this.routes[key])\n } else {\n this.pathsOrdering = pathsOrdering\n this.keysOrdering = keysOrdering\n this.ordered = ordered\n }\n this._ = {\n getLocation: this.getLocation.bind(this),\n override: this.override.bind(this),\n pathsOrdering: this.pathsOrdering,\n keysOrdering: this.keysOrdering,\n ordered: this.ordered,\n }\n }\n\n static create<const T extends RoutesRecord>(routes: T): RoutesPretty<T> {\n const instance = new Routes({ routes })\n return Routes.prettify(instance)\n }\n\n private static prettify<const T extends RoutesRecord>(instance: Routes<T>): RoutesPretty<T> {\n Object.setPrototypeOf(instance, Routes.prototype)\n Object.defineProperty(instance, Symbol.toStringTag, {\n value: 'Routes',\n })\n Object.assign(instance, {\n override: instance.override.bind(instance),\n })\n Object.assign(instance, instance.routes)\n return instance as unknown as RoutesPretty<T>\n }\n\n private static hydrate<const T extends RoutesRecord>(routes: T): RoutesRecordHydrated<T> {\n const result = {} as RoutesRecordHydrated<T>\n for (const key in routes) {\n if (Object.prototype.hasOwnProperty.call(routes, key)) {\n const value = routes[key]\n result[key] = (typeof value === 'string' ? Route0.create(value) : value) as CallabelRoute<T[typeof key]>\n }\n }\n return result\n }\n\n private getLocation(href: `${string}://${string}`): UnknownLocation | ExactLocation\n private getLocation(hrefRel: `/${string}`): UnknownLocation | ExactLocation\n private getLocation(hrefOrHrefRel: string): UnknownLocation | ExactLocation\n private getLocation(location: AnyLocation): UnknownLocation | ExactLocation\n private getLocation(url: URL): UnknownLocation | ExactLocation\n private getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation | ExactLocation\n private getLocation(hrefOrHrefRelOrLocation: string | AnyLocation | URL): UnknownLocation | ExactLocation {\n // Find the route that exactly matches the given location\n const input = hrefOrHrefRelOrLocation\n for (const route of this.ordered) {\n const loc = route.getLocation(hrefOrHrefRelOrLocation)\n if (loc.exact) {\n return loc\n }\n }\n // No exact match found, return UnknownLocation\n return typeof input === 'string' ? Route0.getLocation(input) : Route0.getLocation(input)\n }\n\n private static makeOrdering(routes: RoutesRecord): { pathsOrdering: string[]; keysOrdering: string[] } {\n const hydrated = Routes.hydrate(routes)\n const entries = Object.entries(hydrated)\n\n const getParts = (path: string) => {\n if (path === '/') return ['/']\n return path.split('/').filter(Boolean)\n }\n\n // Sort: shorter paths first, then by specificity, then alphabetically\n entries.sort(([_keyA, routeA], [_keyB, routeB]) => {\n const partsA = getParts(routeA.pathDefinition)\n const partsB = getParts(routeB.pathDefinition)\n\n // 1. Shorter paths first (by segment count)\n if (partsA.length !== partsB.length) {\n return partsA.length - partsB.length\n }\n\n // 2. Same length: check if they conflict\n if (routeA.isConflict(routeB)) {\n // Conflicting routes: more specific first\n if (routeA.isMoreSpecificThan(routeB)) return -1\n if (routeB.isMoreSpecificThan(routeA)) return 1\n }\n\n // 3. Same length, not conflicting or equal specificity: alphabetically\n return routeA.pathDefinition.localeCompare(routeB.pathDefinition)\n })\n\n const pathsOrdering = entries.map(([_key, route]) => route.definition)\n const keysOrdering = entries.map(([_key, route]) => _key)\n return { pathsOrdering, keysOrdering }\n }\n\n private override(config: RouteConfigInput): RoutesPretty<T> {\n const newRoutes = {} as RoutesRecordHydrated<T>\n for (const key in this.routes) {\n if (Object.prototype.hasOwnProperty.call(this.routes, key)) {\n newRoutes[key] = this.routes[key].clone(config) as CallabelRoute<T[typeof key]>\n }\n }\n const instance = new Routes({\n routes: newRoutes,\n isHydrated: true,\n pathsOrdering: this.pathsOrdering,\n keysOrdering: this.keysOrdering,\n ordered: this.keysOrdering.map((key) => newRoutes[key]),\n })\n return Routes.prettify(instance)\n }\n\n static _ = {\n prettify: Routes.prettify.bind(Routes),\n hydrate: Routes.hydrate.bind(Routes),\n makeOrdering: Routes.makeOrdering.bind(Routes),\n }\n}\n\n// main\n\nexport type AnyRoute<T extends Route0<string> | string = string> = T extends string ? Route0<T> : T\nexport type CallabelRoute<T extends Route0<string> | string = string> = AnyRoute<T> & AnyRoute<T>['get']\nexport type AnyRouteOrDefinition<T extends string = string> = AnyRoute<T> | CallabelRoute<T> | T\nexport type RouteConfigInput = {\n baseUrl?: string\n}\n\n// collection\n\nexport type RoutesRecord = Record<string, AnyRoute | string>\nexport type RoutesRecordHydrated<TRoutesRecord extends RoutesRecord = RoutesRecord> = {\n [K in keyof TRoutesRecord]: CallabelRoute<TRoutesRecord[K]>\n}\nexport type RoutesPretty<TRoutesRecord extends RoutesRecord = RoutesRecord> = RoutesRecordHydrated<TRoutesRecord> &\n Routes<TRoutesRecord>\nexport type ExtractRoutesKeys<TRoutes extends RoutesPretty | RoutesRecord> = TRoutes extends RoutesPretty\n ? keyof TRoutes['routes']\n : TRoutes extends RoutesRecord\n ? keyof TRoutes\n : never\nexport type ExtractRoute<\n TRoutes extends RoutesPretty | RoutesRecord,\n TKey extends keyof ExtractRoutesKeys<TRoutes>,\n> = TKey extends keyof TRoutes ? TRoutes[TKey] : never\n\n// public utils\n\nexport type Definition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['definition']\n : T extends string\n ? T\n : never\nexport type PathDefinition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['pathDefinition']\n : T extends string\n ? _PathDefinition<T>\n : never\nexport type ParamsDefinition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['paramsDefinition']\n : T extends string\n ? _ParamsDefinition<T>\n : undefined\nexport type SearchDefinition<T extends AnyRoute | string> = T extends AnyRoute\n ? T['searchDefinition']\n : T extends string\n ? _SearchDefinition<T>\n : undefined\n\nexport type Extended<T extends AnyRoute | string | undefined, TSuffixDefinition extends string> = T extends AnyRoute\n ? Route0<PathExtended<T['definition'], TSuffixDefinition>>\n : T extends string\n ? Route0<PathExtended<T, TSuffixDefinition>>\n : T extends undefined\n ? Route0<TSuffixDefinition>\n : never\n\nexport type IsParent<T extends AnyRoute | string, TParent extends AnyRoute | string> = _IsParent<\n PathDefinition<T>,\n PathDefinition<TParent>\n>\nexport type IsChildren<T extends AnyRoute | string, TChildren extends AnyRoute | string> = _IsChildren<\n PathDefinition<T>,\n PathDefinition<TChildren>\n>\nexport type IsSame<T extends AnyRoute | string, TExact extends AnyRoute | string> = _IsSame<\n PathDefinition<T>,\n PathDefinition<TExact>\n>\nexport type IsSameParams<T1 extends AnyRoute | string, T2 extends AnyRoute | string> = _IsSameParams<\n ParamsDefinition<T1>,\n ParamsDefinition<T2>\n>\n\nexport type HasParams<T extends AnyRoute | string> =\n ExtractPathParams<PathDefinition<T>> extends infer U ? ([U] extends [never] ? false : true) : false\nexport type HasSearch<T extends AnyRoute | string> =\n NonEmpty<SearchTailDefinitionWithoutFirstAmp<Definition<T>>> extends infer Tail extends string\n ? AmpSplit<Tail> extends infer U\n ? [U] extends [never]\n ? false\n : true\n : false\n : false\n\nexport type ParamsOutput<T extends AnyRoute | string> = {\n [K in keyof ParamsDefinition<T>]: string\n}\nexport type SearchOutput<T extends AnyRoute | string = string> = Partial<\n {\n [K in keyof SearchDefinition<T>]?: string\n } & Record<string, string | undefined>\n>\nexport type StrictSearchOutput<T extends AnyRoute | string> = Partial<{\n [K in keyof SearchDefinition<T>]?: string | undefined\n}>\nexport type FlatOutput<T extends AnyRoute | string = string> =\n HasParams<Definition<T>> extends true ? ParamsOutput<T> & SearchOutput<T> : SearchOutput<T>\nexport type StrictFlatOutput<T extends AnyRoute | string> =\n HasParams<Definition<T>> extends true ? ParamsOutput<T> & StrictSearchOutput<T> : StrictSearchOutput<T>\nexport type ParamsInput<T extends AnyRoute | string = string> = _ParamsInput<PathDefinition<T>>\nexport type SearchInput<T extends AnyRoute | string = string> = _SearchInput<Definition<T>>\nexport type StrictSearchInput<T extends AnyRoute | string> = _StrictSearchInput<Definition<T>>\nexport type FlatInput<T extends AnyRoute | string> = _FlatInput<Definition<T>>\nexport type StrictFlatInput<T extends AnyRoute | string> = _StrictFlatInput<Definition<T>>\nexport type CanInputBeEmpty<T extends AnyRoute | string> = HasParams<Definition<T>> extends true ? false : true\n\n// location\n\nexport type LocationParams<TDefinition extends string> = {\n [K in keyof _ParamsDefinition<TDefinition>]: string\n}\nexport type LocationSearch<TDefinition extends string = string> = {\n [K in keyof _SearchDefinition<TDefinition>]: string | undefined\n} & Record<string, string | undefined>\n\nexport type _GeneralLocation = {\n pathname: string\n search: string\n hash: string\n origin?: string\n href?: string\n hrefRel: string\n abs: boolean\n port?: string\n host?: string\n hostname?: string\n}\nexport type UnknownLocation = _GeneralLocation & {\n params: undefined\n searchParams: SearchOutput\n route: undefined\n exact: false\n parent: false\n children: false\n}\nexport type UnmatchedLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {\n params: Record<never, never>\n searchParams: SearchOutput<TRoute>\n route: Definition<TRoute>\n exact: false\n parent: false\n children: false\n}\nexport type ExactLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {\n params: ParamsOutput<TRoute>\n searchParams: SearchOutput<TRoute>\n route: Definition<TRoute>\n exact: true\n parent: false\n children: false\n}\nexport type ParentLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {\n params: Partial<ParamsOutput<TRoute>> // in fact maybe there will be whole params object, but does not matter now\n searchParams: SearchOutput<TRoute>\n route: Definition<TRoute>\n exact: false\n parent: true\n children: false\n}\nexport type ChildrenLocation<TRoute extends AnyRoute | string = AnyRoute | string> = _GeneralLocation & {\n params: ParamsOutput<TRoute>\n searchParams: SearchOutput<TRoute>\n route: Definition<TRoute>\n exact: false\n parent: false\n children: true\n}\nexport type KnownLocation<TRoute extends AnyRoute | string = AnyRoute | string> =\n | UnmatchedLocation<TRoute>\n | ExactLocation<TRoute>\n | ParentLocation<TRoute>\n | ChildrenLocation<TRoute>\nexport type AnyLocation<TRoute extends AnyRoute = AnyRoute> = UnknownLocation | KnownLocation<TRoute>\n\n// internal utils\n\nexport type _PathDefinition<T extends string> = T extends string ? TrimSearchTailDefinition<T> : never\nexport type _ParamsDefinition<TDefinition extends string> =\n ExtractPathParams<PathDefinition<TDefinition>> extends infer U\n ? [U] extends [never]\n ? undefined\n : { [K in Extract<U, string>]: true }\n : undefined\nexport type _SearchDefinition<TDefinition extends string> =\n NonEmpty<SearchTailDefinitionWithoutFirstAmp<TDefinition>> extends infer Tail extends string\n ? AmpSplit<Tail> extends infer U\n ? [U] extends [never]\n ? undefined\n : { [K in Extract<U, string>]: true }\n : undefined\n : undefined\n\nexport type _ParamsInput<TDefinition extends string> =\n _ParamsDefinition<TDefinition> extends undefined\n ? Record<never, never>\n : {\n [K in keyof _ParamsDefinition<TDefinition>]: string | number\n }\nexport type _SearchInput<TDefinition extends string> =\n _SearchDefinition<TDefinition> extends undefined\n ? Record<string, string | number>\n : Partial<{\n [K in keyof _SearchDefinition<TDefinition>]: string | number\n }> &\n Record<string, string | number>\nexport type _StrictSearchInput<TDefinition extends string> = Partial<{\n [K in keyof _SearchDefinition<TDefinition>]: string | number\n}>\nexport type _FlatInput<TDefinition extends string> =\n HasParams<TDefinition> extends true\n ? _ParamsInput<TDefinition> & _SearchInput<TDefinition>\n : _SearchInput<TDefinition>\nexport type _StrictFlatInput<TDefinition extends string> =\n HasParams<TDefinition> extends true\n ? HasSearch<TDefinition> extends true\n ? _StrictSearchInput<TDefinition> & _ParamsInput<TDefinition>\n : _ParamsInput<TDefinition>\n : HasSearch<TDefinition> extends true\n ? _StrictSearchInput<TDefinition>\n : Record<never, never>\n\nexport type TrimSearchTailDefinition<S extends string> = S extends `${infer P}&${string}` ? P : S\nexport type SearchTailDefinitionWithoutFirstAmp<S extends string> = S extends `${string}&${infer T}` ? T : ''\nexport type SearchTailDefinitionWithFirstAmp<S extends string> = S extends `${string}&${infer T}` ? `&${T}` : ''\nexport type AmpSplit<S extends string> = S extends `${infer A}&${infer B}` ? A | AmpSplit<B> : S\n// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\nexport type NonEmpty<T> = [T] extends ['' | never] ? never : T\nexport type ExtractPathParams<S extends string> = S extends `${string}:${infer After}`\n ? After extends `${infer Name}/${infer Rest}`\n ? Name | ExtractPathParams<`/${Rest}`>\n : After\n : never\nexport type ReplacePathParams<S extends string> = S extends `${infer Head}:${infer Tail}`\n ? // eslint-disable-next-line @typescript-eslint/no-unused-vars\n Tail extends `${infer _Param}/${infer Rest}`\n ? ReplacePathParams<`${Head}${string}/${Rest}`>\n : `${Head}${string}`\n : S\nexport type DedupeSlashes<S extends string> = S extends `${infer A}//${infer B}` ? DedupeSlashes<`${A}/${B}`> : S\nexport type EmptyRecord = Record<never, never>\nexport type JoinPath<Parent extends string, Suffix extends string> = DedupeSlashes<\n PathDefinition<Parent> extends infer A extends string\n ? PathDefinition<Suffix> extends infer B extends string\n ? A extends ''\n ? B extends ''\n ? ''\n : B extends `/${string}`\n ? B\n : `/${B}`\n : B extends ''\n ? A\n : A extends `${string}/`\n ? `${A}${B}`\n : B extends `/${string}`\n ? `${A}${B}`\n : `${A}/${B}`\n : never\n : never\n>\n\nexport type OnlyIfNoParams<TParams extends object | undefined, Yes, No = never> = TParams extends undefined ? Yes : No\nexport type OnlyIfHasParams<TParams extends object | undefined, Yes, No = never> = TParams extends undefined ? No : Yes\n\nexport type PathOnlyRouteValue<TDefinition extends string> = `${ReplacePathParams<PathDefinition<TDefinition>>}`\nexport type WithSearchRouteValue<TDefinition extends string> =\n `${ReplacePathParams<PathDefinition<TDefinition>>}?${string}`\nexport type AbsolutePathOnlyRouteValue<TDefinition extends string> =\n PathOnlyRouteValue<TDefinition> extends '/' ? string : `${string}${PathOnlyRouteValue<TDefinition>}`\nexport type AbsoluteWithSearchRouteValue<TDefinition extends string> = `${string}${WithSearchRouteValue<TDefinition>}`\n\nexport type PathExtended<\n TSourcedefinitionDefinition extends string,\n TSuffixdefinitionDefinition extends string,\n> = `${JoinPath<TSourcedefinitionDefinition, TSuffixdefinitionDefinition>}${SearchTailDefinitionWithFirstAmp<TSuffixdefinitionDefinition>}`\n\nexport type WithParamsInput<\n TDefinition extends string,\n T extends\n | {\n search?: _SearchInput<any>\n abs?: boolean\n }\n | undefined = undefined,\n> = _ParamsInput<TDefinition> & (T extends undefined ? Record<never, never> : T)\n\nexport type _IsSameParams<T1 extends object | undefined, T2 extends object | undefined> = T1 extends undefined\n ? T2 extends undefined\n ? true\n : false\n : T2 extends undefined\n ? false\n : T1 extends T2\n ? T2 extends T1\n ? true\n : false\n : false\n\nexport type _IsParent<T extends string, TParent extends string> = T extends TParent\n ? false\n : T extends `${TParent}${string}`\n ? true\n : false\nexport type _IsChildren<T extends string, TChildren extends string> = TChildren extends T\n ? false\n : TChildren extends `${T}${string}`\n ? true\n : false\nexport type _IsSame<T extends string, TExact extends string> = T extends TExact\n ? TExact extends T\n ? true\n : false\n : false\n"],"mappings":"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","names":["paramsInput","searchInput"]}
|
package/package.json
CHANGED
package/src/index.test.ts
CHANGED
|
@@ -223,7 +223,7 @@ describe('Route0', () => {
|
|
|
223
223
|
// r0: route0,
|
|
224
224
|
// r1: route1,
|
|
225
225
|
// }
|
|
226
|
-
// const routes2 = Route0.overrideMany(routes, { baseUrl: 'https://z.com' })
|
|
226
|
+
// const routes2 = Route0._.overrideMany(routes, { baseUrl: 'https://z.com' })
|
|
227
227
|
// const path = routes2.r1.get({ abs: true })
|
|
228
228
|
// expectTypeOf<typeof path>().toEqualTypeOf<`${string}/path/suffix`>()
|
|
229
229
|
// expect(path).toBe('https://z.com/path/suffix')
|
|
@@ -661,7 +661,7 @@ describe('getLocation', () => {
|
|
|
661
661
|
userDetail: '/users/:id',
|
|
662
662
|
})
|
|
663
663
|
|
|
664
|
-
const loc = routes.getLocation('/users/123')
|
|
664
|
+
const loc = routes._.getLocation('/users/123')
|
|
665
665
|
expect(loc.exact).toBe(true)
|
|
666
666
|
expect(loc.parent).toBe(false)
|
|
667
667
|
expect(loc.children).toBe(false)
|
|
@@ -680,7 +680,7 @@ describe('getLocation', () => {
|
|
|
680
680
|
})
|
|
681
681
|
|
|
682
682
|
// '/users/123/posts' is not an exact match for any route
|
|
683
|
-
const loc = routes.getLocation('/users/123/posts')
|
|
683
|
+
const loc = routes._.getLocation('/users/123/posts')
|
|
684
684
|
expect(loc.exact).toBe(false)
|
|
685
685
|
expect(loc.parent).toBe(false)
|
|
686
686
|
expect(loc.children).toBe(false)
|
|
@@ -695,7 +695,7 @@ describe('getLocation', () => {
|
|
|
695
695
|
})
|
|
696
696
|
|
|
697
697
|
// '/users/123' is not an exact match for any route
|
|
698
|
-
const loc = routes.getLocation('/users/123')
|
|
698
|
+
const loc = routes._.getLocation('/users/123')
|
|
699
699
|
expect(loc.exact).toBe(false)
|
|
700
700
|
expect(loc.parent).toBe(false)
|
|
701
701
|
expect(loc.children).toBe(false)
|
|
@@ -708,7 +708,7 @@ describe('getLocation', () => {
|
|
|
708
708
|
users: '/users',
|
|
709
709
|
})
|
|
710
710
|
|
|
711
|
-
const loc = routes.getLocation('/posts/123')
|
|
711
|
+
const loc = routes._.getLocation('/posts/123')
|
|
712
712
|
expect(loc.exact).toBe(false)
|
|
713
713
|
expect(loc.parent).toBe(false)
|
|
714
714
|
expect(loc.children).toBe(false)
|
|
@@ -724,19 +724,19 @@ describe('getLocation', () => {
|
|
|
724
724
|
})
|
|
725
725
|
|
|
726
726
|
// Should match /users exactly
|
|
727
|
-
const loc1 = routes.getLocation('/users')
|
|
727
|
+
const loc1 = routes._.getLocation('/users')
|
|
728
728
|
expect(loc1.exact).toBe(true)
|
|
729
729
|
expect(loc1.pathname).toBe('/users')
|
|
730
730
|
|
|
731
731
|
// Should match /users/:id exactly
|
|
732
|
-
const loc2 = routes.getLocation('/users/123')
|
|
732
|
+
const loc2 = routes._.getLocation('/users/123')
|
|
733
733
|
expect(loc2.exact).toBe(true)
|
|
734
734
|
if (loc2.exact) {
|
|
735
735
|
expect(loc2.params).toMatchObject({ id: '123' })
|
|
736
736
|
}
|
|
737
737
|
|
|
738
738
|
// Should match /users/:id/posts exactly
|
|
739
|
-
const loc3 = routes.getLocation('/users/123/posts')
|
|
739
|
+
const loc3 = routes._.getLocation('/users/123/posts')
|
|
740
740
|
expect(loc3.exact).toBe(true)
|
|
741
741
|
if (loc3.exact) {
|
|
742
742
|
expect(loc3.params).toMatchObject({ id: '123' })
|
|
@@ -749,7 +749,7 @@ describe('getLocation', () => {
|
|
|
749
749
|
users: '/users',
|
|
750
750
|
})
|
|
751
751
|
|
|
752
|
-
const loc = routes.getLocation('/search?q=test&filter=all')
|
|
752
|
+
const loc = routes._.getLocation('/search?q=test&filter=all')
|
|
753
753
|
expect(loc.exact).toBe(true)
|
|
754
754
|
expect(loc.pathname).toBe('/search')
|
|
755
755
|
expect(loc.search).toBe('?q=test&filter=all')
|
|
@@ -762,7 +762,7 @@ describe('getLocation', () => {
|
|
|
762
762
|
users: '/api/v1/users',
|
|
763
763
|
})
|
|
764
764
|
|
|
765
|
-
const loc = routes.getLocation('https://example.com/api/v1/users')
|
|
765
|
+
const loc = routes._.getLocation('https://example.com/api/v1/users')
|
|
766
766
|
expect(loc.exact).toBe(true)
|
|
767
767
|
expect(loc.abs).toBe(true)
|
|
768
768
|
expect(loc.origin).toBe('https://example.com')
|
|
@@ -775,7 +775,7 @@ describe('getLocation', () => {
|
|
|
775
775
|
userDetail: '/users/:id',
|
|
776
776
|
})
|
|
777
777
|
|
|
778
|
-
const loc = routes.getLocation('/users/123#profile')
|
|
778
|
+
const loc = routes._.getLocation('/users/123#profile')
|
|
779
779
|
expect(loc.exact).toBe(true)
|
|
780
780
|
expect(loc.hash).toBe('#profile')
|
|
781
781
|
expect(loc.pathname).toBe('/users/123')
|
|
@@ -792,7 +792,7 @@ describe('getLocation', () => {
|
|
|
792
792
|
userDetail: api.extend('/users/:id'),
|
|
793
793
|
})
|
|
794
794
|
|
|
795
|
-
const loc = routes.getLocation('/api/v1/users/456')
|
|
795
|
+
const loc = routes._.getLocation('/api/v1/users/456')
|
|
796
796
|
expect(loc.exact).toBe(true)
|
|
797
797
|
if (loc.exact) {
|
|
798
798
|
expect(loc.params).toMatchObject({ id: '456' })
|
|
@@ -805,7 +805,7 @@ describe('getLocation', () => {
|
|
|
805
805
|
about: '/about',
|
|
806
806
|
})
|
|
807
807
|
|
|
808
|
-
const loc = routes.getLocation('/')
|
|
808
|
+
const loc = routes._.getLocation('/')
|
|
809
809
|
expect(loc.exact).toBe(true)
|
|
810
810
|
expect(loc.pathname).toBe('/')
|
|
811
811
|
})
|
|
@@ -816,7 +816,7 @@ describe('getLocation', () => {
|
|
|
816
816
|
})
|
|
817
817
|
|
|
818
818
|
const inputLoc = Route0.getLocation('/users/789')
|
|
819
|
-
const loc = routes.getLocation(inputLoc)
|
|
819
|
+
const loc = routes._.getLocation(inputLoc)
|
|
820
820
|
expect(loc.exact).toBe(true)
|
|
821
821
|
if (loc.exact) {
|
|
822
822
|
expect(loc.params).toMatchObject({ id: '789' })
|
|
@@ -832,7 +832,7 @@ describe('getLocation', () => {
|
|
|
832
832
|
userPosts: api.extend('/users/:id/posts&sort&filter'),
|
|
833
833
|
})
|
|
834
834
|
|
|
835
|
-
const loc = routes.getLocation('/api/v1/users/42/posts?sort=date&filter=published&extra=value')
|
|
835
|
+
const loc = routes._.getLocation('/api/v1/users/42/posts?sort=date&filter=published&extra=value')
|
|
836
836
|
expect(loc.exact).toBe(true)
|
|
837
837
|
expect(loc.pathname).toBe('/api/v1/users/42/posts')
|
|
838
838
|
expect(loc.searchParams).toMatchObject({
|
|
@@ -938,7 +938,7 @@ describe('Routes', () => {
|
|
|
938
938
|
about: '/about',
|
|
939
939
|
})
|
|
940
940
|
|
|
941
|
-
const overridden = collection.override({ baseUrl: 'https://example.com' })
|
|
941
|
+
const overridden = collection._.override({ baseUrl: 'https://example.com' })
|
|
942
942
|
|
|
943
943
|
const home = overridden.home
|
|
944
944
|
const about = overridden.about
|
|
@@ -955,7 +955,7 @@ describe('Routes', () => {
|
|
|
955
955
|
const original = collection.home
|
|
956
956
|
expect(original.get({ abs: true })).toBe('https://example.com')
|
|
957
957
|
|
|
958
|
-
const overridden = collection.override({ baseUrl: 'https://newdomain.com' })
|
|
958
|
+
const overridden = collection._.override({ baseUrl: 'https://newdomain.com' })
|
|
959
959
|
const newRoute = overridden.home
|
|
960
960
|
|
|
961
961
|
expect(original.get({ abs: true })).toBe('https://example.com')
|
|
@@ -975,14 +975,14 @@ describe('Routes', () => {
|
|
|
975
975
|
expect(collection.api({ abs: true })).toBe('https://api.example.com/api')
|
|
976
976
|
expect(collection.users.get({ abs: true })).toBe('https://api.example.com/api/users')
|
|
977
977
|
|
|
978
|
-
const overridden = collection.override({ baseUrl: 'https://new-api.example.com' })
|
|
978
|
+
const overridden = collection._.override({ baseUrl: 'https://new-api.example.com' })
|
|
979
979
|
|
|
980
980
|
expect(overridden.api.get({ abs: true })).toBe('https://new-api.example.com/api')
|
|
981
981
|
expect(overridden.users.get({ abs: true })).toBe('https://new-api.example.com/api/users')
|
|
982
982
|
})
|
|
983
983
|
|
|
984
984
|
it('hydrate static method', () => {
|
|
985
|
-
const hydrated = Routes.
|
|
985
|
+
const hydrated = Routes._.hydrate({
|
|
986
986
|
home: '/',
|
|
987
987
|
user: '/user/:id',
|
|
988
988
|
about: Route0.create('/about'),
|
|
@@ -1312,7 +1312,7 @@ describe('ordering', () => {
|
|
|
1312
1312
|
catchAll: '/:slug',
|
|
1313
1313
|
}
|
|
1314
1314
|
|
|
1315
|
-
const { pathsOrdering: ordering } = Routes.
|
|
1315
|
+
const { pathsOrdering: ordering } = Routes._.makeOrdering(routes)
|
|
1316
1316
|
|
|
1317
1317
|
// Expected order:
|
|
1318
1318
|
// Depth 1: / then /users (static) then /:slug (param)
|
|
@@ -1329,7 +1329,7 @@ describe('ordering', () => {
|
|
|
1329
1329
|
home: '/home',
|
|
1330
1330
|
}
|
|
1331
1331
|
|
|
1332
|
-
const { pathsOrdering: ordering } = Routes.
|
|
1332
|
+
const { pathsOrdering: ordering } = Routes._.makeOrdering(routes)
|
|
1333
1333
|
|
|
1334
1334
|
// All have same depth and don't conflict
|
|
1335
1335
|
// Ordered alphabetically
|
|
@@ -1349,7 +1349,7 @@ describe('ordering', () => {
|
|
|
1349
1349
|
catchAll: '/:slug',
|
|
1350
1350
|
}
|
|
1351
1351
|
|
|
1352
|
-
const { pathsOrdering: ordering } = Routes.
|
|
1352
|
+
const { pathsOrdering: ordering } = Routes._.makeOrdering(routes)
|
|
1353
1353
|
|
|
1354
1354
|
// Expected order:
|
|
1355
1355
|
// Depth 1: / (static), /:slug (param)
|
|
@@ -1377,11 +1377,11 @@ describe('ordering', () => {
|
|
|
1377
1377
|
userDetail: '/users/:id',
|
|
1378
1378
|
})
|
|
1379
1379
|
|
|
1380
|
-
expect(routes.pathsOrdering).toBeDefined()
|
|
1381
|
-
expect(Array.isArray(routes.pathsOrdering)).toBe(true)
|
|
1380
|
+
expect(routes._.pathsOrdering).toBeDefined()
|
|
1381
|
+
expect(Array.isArray(routes._.pathsOrdering)).toBe(true)
|
|
1382
1382
|
// Depth 1: /, /users (alphabetically)
|
|
1383
1383
|
// Depth 2: /users/:id
|
|
1384
|
-
expect(routes.pathsOrdering).toEqual(['/', '/users', '/users/:id'])
|
|
1384
|
+
expect(routes._.pathsOrdering).toEqual(['/', '/users', '/users/:id'])
|
|
1385
1385
|
})
|
|
1386
1386
|
|
|
1387
1387
|
it('ordering is preserved after override', () => {
|
|
@@ -1391,12 +1391,12 @@ describe('ordering', () => {
|
|
|
1391
1391
|
userDetail: '/users/:id',
|
|
1392
1392
|
})
|
|
1393
1393
|
|
|
1394
|
-
const originalOrdering = routes.pathsOrdering
|
|
1394
|
+
const originalOrdering = routes._.pathsOrdering
|
|
1395
1395
|
|
|
1396
|
-
const overridden = routes.override({ baseUrl: 'https://example.com' })
|
|
1396
|
+
const overridden = routes._.override({ baseUrl: 'https://example.com' })
|
|
1397
1397
|
|
|
1398
|
-
expect(overridden.pathsOrdering).toEqual(originalOrdering)
|
|
1399
|
-
expect(overridden.pathsOrdering).toEqual(['/', '/users', '/users/:id'])
|
|
1398
|
+
expect(overridden._.pathsOrdering).toEqual(originalOrdering)
|
|
1399
|
+
expect(overridden._.pathsOrdering).toEqual(['/', '/users', '/users/:id'])
|
|
1400
1400
|
})
|
|
1401
1401
|
|
|
1402
1402
|
it('_makeOrdering: handles single route', () => {
|
|
@@ -1404,14 +1404,63 @@ describe('ordering', () => {
|
|
|
1404
1404
|
home: '/',
|
|
1405
1405
|
}
|
|
1406
1406
|
|
|
1407
|
-
const { pathsOrdering: ordering } = Routes.
|
|
1407
|
+
const { pathsOrdering: ordering } = Routes._.makeOrdering(routes)
|
|
1408
1408
|
expect(ordering).toEqual(['/'])
|
|
1409
1409
|
})
|
|
1410
1410
|
|
|
1411
1411
|
it('_makeOrdering: handles empty object', () => {
|
|
1412
1412
|
const routes = {}
|
|
1413
1413
|
|
|
1414
|
-
const { pathsOrdering: ordering } = Routes.
|
|
1414
|
+
const { pathsOrdering: ordering } = Routes._.makeOrdering(routes)
|
|
1415
1415
|
expect(ordering).toEqual([])
|
|
1416
1416
|
})
|
|
1417
1417
|
})
|
|
1418
|
+
|
|
1419
|
+
describe('relations: isSame, isParent, isChildren', () => {
|
|
1420
|
+
it('isSame: same static path', () => {
|
|
1421
|
+
const a = Route0.create('/a')
|
|
1422
|
+
const b = Route0.create('/a')
|
|
1423
|
+
expect(a.isSame(b)).toBe(true)
|
|
1424
|
+
})
|
|
1425
|
+
|
|
1426
|
+
it('isSame: ignores param names but respects structure', () => {
|
|
1427
|
+
const r1 = Route0.create('/users/:id')
|
|
1428
|
+
const r2 = Route0.create('/users/:userId')
|
|
1429
|
+
const r3 = Route0.create('/users')
|
|
1430
|
+
const r4 = Route0.create('/users/:id/posts')
|
|
1431
|
+
expect((r1 as any).isSame(r2 as any)).toBe(true)
|
|
1432
|
+
expect((r1 as any).isSame(r3 as any)).toBe(false)
|
|
1433
|
+
expect((r1 as any).isSame(r4 as any)).toBe(false)
|
|
1434
|
+
})
|
|
1435
|
+
|
|
1436
|
+
it('isParent: true when left is ancestor of right', () => {
|
|
1437
|
+
expect((Route0.create('/path') as any).isParent(Route0.create('/path/child') as any)).toBe(true)
|
|
1438
|
+
expect((Route0.create('/users/:id') as any).isParent(Route0.create('/users/:id/posts') as any)).toBe(true)
|
|
1439
|
+
})
|
|
1440
|
+
|
|
1441
|
+
it('isParent: false for reverse, equal, or unrelated', () => {
|
|
1442
|
+
expect((Route0.create('/path/child') as any).isParent(Route0.create('/path') as any)).toBe(false)
|
|
1443
|
+
expect((Route0.create('/path') as any).isParent(Route0.create('/path') as any)).toBe(false)
|
|
1444
|
+
expect((Route0.create('/a') as any).isParent(Route0.create('/b') as any)).toBe(false)
|
|
1445
|
+
})
|
|
1446
|
+
|
|
1447
|
+
it('isChildren: true when left is descendant of right', () => {
|
|
1448
|
+
expect((Route0.create('/path/child') as any).isChildren(Route0.create('/path') as any)).toBe(true)
|
|
1449
|
+
expect((Route0.create('/users/:id/posts') as any).isChildren(Route0.create('/users/:id') as any)).toBe(true)
|
|
1450
|
+
})
|
|
1451
|
+
|
|
1452
|
+
it('isChildren: false for reverse, equal, or unrelated', () => {
|
|
1453
|
+
expect((Route0.create('/path') as any).isChildren(Route0.create('/path/child') as any)).toBe(false)
|
|
1454
|
+
expect((Route0.create('/path') as any).isChildren(Route0.create('/path') as any)).toBe(false)
|
|
1455
|
+
expect((Route0.create('/a') as any).isChildren(Route0.create('/b') as any)).toBe(false)
|
|
1456
|
+
})
|
|
1457
|
+
|
|
1458
|
+
it('static isSame: works with strings and undefined', () => {
|
|
1459
|
+
expect(Route0.isSame('/a/:id', Route0.create('/a/:name'))).toBe(true)
|
|
1460
|
+
expect(Route0.isSame('/a', '/a')).toBe(true)
|
|
1461
|
+
expect(Route0.isSame('/a', '/b')).toBe(false)
|
|
1462
|
+
expect(Route0.isSame(undefined, undefined)).toBe(true)
|
|
1463
|
+
expect(Route0.isSame(undefined, '/a')).toBe(false)
|
|
1464
|
+
expect(Route0.isSame('/a', undefined)).toBe(false)
|
|
1465
|
+
})
|
|
1466
|
+
})
|