@tanstack/router-core
Version:
Modern and scalable routing for React applications
1 lines • 51.4 kB
Source Map (JSON)
{"version":3,"file":"new-process-route-tree.cjs","names":[],"sources":["../../src/new-process-route-tree.ts"],"sourcesContent":["import { invariant } from './invariant'\nimport { trimPathRight } from './path'\nimport { createSieveCache } from './sieve-cache'\nimport { last } from './utils'\nimport type { SieveCache } from './sieve-cache'\nimport type { InterpolationSegment, RouteInterpolation } from './path'\n\nexport const SEGMENT_TYPE_PATHNAME = 0\nexport const SEGMENT_TYPE_PARAM = 1\nexport const SEGMENT_TYPE_WILDCARD = 2\nexport const SEGMENT_TYPE_OPTIONAL_PARAM = 3\nconst SEGMENT_TYPE_INDEX = 4\nconst SEGMENT_TYPE_PATHLESS = 5 // only used in matching to represent pathless routes that need to carry more information\n\n/**\n * All the kinds of segments that can be present in a route path.\n */\nexport type SegmentKind =\n | typeof SEGMENT_TYPE_PATHNAME\n | typeof SEGMENT_TYPE_PARAM\n | typeof SEGMENT_TYPE_WILDCARD\n | typeof SEGMENT_TYPE_OPTIONAL_PARAM\n\n/**\n * All the kinds of segments that can be present in the segment tree.\n */\ntype ExtendedSegmentKind =\n | SegmentKind\n | typeof SEGMENT_TYPE_INDEX\n | typeof SEGMENT_TYPE_PATHLESS\n\nexport type DynamicPathSegment = [\n kind: Exclude<SegmentKind, typeof SEGMENT_TYPE_PATHNAME>,\n key: string,\n prefix: string,\n /** Undefined marks a bare splat, which discards the remaining template. */\n suffix: string | undefined,\n]\n\nexport function getParamNames(data: RouteInterpolation): Array<string> {\n const cached = data.names\n if (cached) {\n return cached\n }\n const keys: Array<string> = []\n for (const segment of data) {\n if (typeof segment !== 'string') {\n keys.push(segment[1 /* key */])\n }\n }\n return (data.names = keys)\n}\n\n/** Parse one segment for matching and retain the same record for interpolation. */\nexport function parseSegment(\n /** The full path string containing the segment. */\n path: string,\n /** The starting index of the segment within the path. */\n start: number,\n /** The next slash, or the length of the path. */\n end: number,\n): InterpolationSegment {\n const part = path.substring(start, end)\n if (part.charCodeAt(0) === 36) {\n return part.length === 1\n ? [SEGMENT_TYPE_WILDCARD, '_splat', '', undefined]\n : [SEGMENT_TYPE_PARAM, part.substring(1), '', '']\n }\n const open = part.indexOf('{')\n if (open >= 0) {\n const close = part.indexOf('}', open)\n const optional = part.charCodeAt(open + 1) === 45\n const nameStart = open + (optional ? 3 : 2)\n if (\n close >= 0 &&\n part.charCodeAt(nameStart - 1) === 36 &&\n (!optional || nameStart < close)\n ) {\n const key = part.substring(nameStart, close)\n return [\n optional\n ? SEGMENT_TYPE_OPTIONAL_PARAM\n : key\n ? SEGMENT_TYPE_PARAM\n : SEGMENT_TYPE_WILDCARD,\n key || '_splat',\n part.substring(0, open),\n path.substring(start + close + 1, key ? end : path.length),\n ]\n }\n }\n return part\n}\n\ntype ParsedRoute<T extends RouteLike> = [\n node: AnySegmentNode<T>,\n cursor: number,\n segments: RouteInterpolation | undefined,\n]\n\n/** Compile a template, optionally attaching its new segments to the matching trie. */\nexport function parseSegments<TRouteLike extends RouteLike>(\n defaultCaseSensitive: boolean,\n route: TRouteLike,\n start: number,\n): RouteInterpolation\nexport function parseSegments<TRouteLike extends RouteLike>(\n defaultCaseSensitive: boolean,\n route: TRouteLike,\n start: number,\n node: AnySegmentNode<TRouteLike>,\n dynamicListsToSort?: Array<Array<DynamicSegmentNode<TRouteLike>>>,\n parentInterpolation?: RouteInterpolation,\n): ParsedRoute<TRouteLike>\nexport function parseSegments<TRouteLike extends RouteLike>(\n defaultCaseSensitive: boolean,\n route: TRouteLike,\n start: number,\n node?: AnySegmentNode<TRouteLike>,\n /** Each dynamic sibling list is recorded once, when it first needs sorting. */\n dynamicListsToSort?: Array<Array<DynamicSegmentNode<TRouteLike>>>,\n parentInterpolation?: RouteInterpolation,\n): RouteInterpolation | ParsedRoute<TRouteLike> {\n let cursor = start\n const path = route.fullPath ?? route.from\n const options = route.options\n const length = path.length\n const literalEnd = path.endsWith('/') ? length - 1 : length\n const caseSensitive = options?.caseSensitive ?? defaultCaseSensitive\n const parseParams = options?.params?.parse ?? options?.parseParams\n let interpolation: Array<InterpolationSegment> | undefined\n let literalStart = parentInterpolation ? start - 1 : 0\n if (!node || path.includes('$')) {\n interpolation = parentInterpolation?.slice() ?? []\n const tail = last(interpolation)\n if (\n tail &&\n typeof tail !== 'string' &&\n tail[0 /* kind */] === SEGMENT_TYPE_WILDCARD\n ) {\n // A parent's wildcard consumes the child's template too.\n // `start` follows that entire template, including its trailing slash.\n interpolation[interpolation.length - 1] = [\n tail[0 /* kind */],\n tail[1 /* key */],\n tail[2 /* prefix */],\n tail[3 /* suffix */] === undefined\n ? undefined\n : tail[3 /* suffix */] +\n path.substring(\n start - (path[start - 2] === '/' ? 2 : 1),\n literalEnd,\n ),\n ]\n literalStart = length\n }\n }\n while (cursor < length) {\n const start = cursor\n const next = path.indexOf('/', start)\n let end = next === -1 ? length : next\n const segment = parseSegment(path, start, end)\n cursor = end + 1\n let nextNode: AnySegmentNode<TRouteLike>\n if (typeof segment === 'string') {\n if (!node) {\n continue\n }\n let name = segment\n let staticChildren: Map<string, StaticSegmentNode<TRouteLike>>\n if (caseSensitive) {\n staticChildren = node.static ??= new Map()\n } else {\n name = segment.toLowerCase()\n staticChildren = node.staticInsensitive ??= new Map()\n }\n const existingNode = staticChildren.get(name)\n if (existingNode) {\n nextNode = existingNode\n } else {\n const next = createSegmentNode(node)\n nextNode = next\n staticChildren.set(name, next)\n }\n } else {\n const kind = segment[0 /* kind */]\n let prefix = segment[2 /* prefix */]\n let suffix = segment[3 /* suffix */] ?? ''\n if (kind === SEGMENT_TYPE_WILDCARD) {\n end = length\n cursor = end + 1\n }\n if (interpolation && literalStart < end) {\n // Retain original spelling before matcher case folding.\n if (literalStart < start - 1) {\n interpolation.push(path.substring(literalStart, start - 1))\n }\n segment[2 /* prefix */] = '/' + prefix\n if (\n kind === SEGMENT_TYPE_WILDCARD &&\n segment[3 /* suffix */] !== undefined &&\n literalEnd < length\n ) {\n segment[3 /* suffix */] = suffix.slice(0, -1)\n }\n interpolation.push(segment)\n literalStart = end\n }\n if (!node) {\n continue\n }\n const actuallyCaseSensitive = caseSensitive && !!(prefix || suffix)\n if (!caseSensitive) {\n prefix = prefix.toLowerCase()\n suffix = suffix.toLowerCase()\n }\n const siblings =\n kind === SEGMENT_TYPE_PARAM\n ? (node.dynamic ??= [])\n : kind === SEGMENT_TYPE_OPTIONAL_PARAM\n ? (node.optional ??= [])\n : (node.wildcard ??= [])\n const existingNode =\n // Keep wildcard aliases as separate match candidates, even when\n // they have the same shape and no parser.\n kind !== SEGMENT_TYPE_WILDCARD &&\n !parseParams &&\n siblings.find(\n (s) =>\n !s.parse &&\n s.caseSensitive === actuallyCaseSensitive &&\n s.prefix === prefix &&\n s.suffix === suffix,\n )\n if (existingNode) {\n nextNode = existingNode\n } else {\n const next = createSegmentNode(\n node,\n kind,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n siblings.push(next)\n if (siblings.length === 2) {\n dynamicListsToSort?.push(siblings)\n }\n }\n }\n node = nextNode\n }\n\n if (interpolation && literalStart < literalEnd) {\n interpolation.push(path.substring(literalStart, literalEnd))\n }\n // Discard push()'s spare capacity before retaining this array on both owners.\n const segmentData = interpolation?.slice()\n if (!node) {\n return segmentData!\n }\n\n // create pathless node\n if (\n parseParams &&\n route.children &&\n !route.isRoot &&\n route.id &&\n route.id.charCodeAt(route.id.lastIndexOf('/') + 1) === 95 /* '_' */\n ) {\n const pathlessNode = createSegmentNode(node, SEGMENT_TYPE_PATHLESS)\n ;(node.pathless ??= []).push(pathlessNode)\n node = pathlessNode\n }\n\n const isLeaf = (route.path || !route.children) && !route.isRoot\n // create index node\n if (isLeaf && literalEnd < length) {\n const indexNode = createSegmentNode(node, SEGMENT_TYPE_INDEX)\n node.index = indexNode\n node = indexNode\n }\n\n node.parse = parseParams ?? null\n node.priority = options?.params?.priority ?? 0\n // A shared candidate keeps the original names of its first terminal route.\n if (!node.route) {\n node.data = segmentData\n if (isLeaf) {\n node.route = route\n }\n }\n return [node, cursor, segmentData]\n}\n\nfunction sortDynamic(\n a: {\n prefix: string\n suffix: string\n caseSensitive: boolean\n parse: null | ((params: Record<string, string>) => unknown)\n priority: number\n },\n b: {\n prefix: string\n suffix: string\n caseSensitive: boolean\n parse: null | ((params: Record<string, string>) => unknown)\n priority: number\n },\n) {\n if (a.parse && !b.parse) return -1\n if (!a.parse && b.parse) return 1\n if (a.parse && b.parse && (a.priority || b.priority))\n return b.priority - a.priority\n if (a.prefix && b.prefix && a.prefix !== b.prefix) {\n if (a.prefix.startsWith(b.prefix)) return -1\n if (b.prefix.startsWith(a.prefix)) return 1\n }\n if (a.suffix && b.suffix && a.suffix !== b.suffix) {\n if (a.suffix.endsWith(b.suffix)) return -1\n if (b.suffix.endsWith(a.suffix)) return 1\n }\n if (a.prefix && !b.prefix) return -1\n if (!a.prefix && b.prefix) return 1\n if (a.suffix && !b.suffix) return -1\n if (!a.suffix && b.suffix) return 1\n if (a.caseSensitive && !b.caseSensitive) return -1\n if (!a.caseSensitive && b.caseSensitive) return 1\n\n // Equal specificity preserves route declaration order through stable sort.\n return 0\n}\n\nfunction createSegmentNode<T extends RouteLike>(\n parent?: AnySegmentNode<T>,\n kind?: StaticSegmentNode<T>['kind'],\n): StaticSegmentNode<T>\nfunction createSegmentNode<T extends RouteLike>(\n parent: AnySegmentNode<T>,\n kind:\n | typeof SEGMENT_TYPE_PARAM\n | typeof SEGMENT_TYPE_WILDCARD\n | typeof SEGMENT_TYPE_OPTIONAL_PARAM,\n caseSensitive: boolean,\n prefix: string,\n suffix: string,\n): DynamicSegmentNode<T>\nfunction createSegmentNode<T extends RouteLike>(\n parent?: AnySegmentNode<T>,\n kind: ExtendedSegmentKind = SEGMENT_TYPE_PATHNAME,\n caseSensitive?: boolean,\n prefix?: string,\n suffix?: string,\n): SegmentNode<T> {\n return {\n kind,\n depth: parent ? parent.depth + 1 : 0,\n pathless: null,\n index: null,\n static: null,\n staticInsensitive: null,\n dynamic: null,\n optional: null,\n wildcard: null,\n route: null,\n data: undefined,\n parent,\n parse: null,\n priority: 0,\n caseSensitive,\n prefix,\n suffix,\n }\n}\n\ntype StaticSegmentNode<T extends RouteLike> = SegmentNode<T> & {\n kind:\n | typeof SEGMENT_TYPE_PATHNAME\n | typeof SEGMENT_TYPE_PATHLESS\n | typeof SEGMENT_TYPE_INDEX\n}\n\ntype DynamicSegmentNode<T extends RouteLike> = SegmentNode<T> & {\n kind:\n | typeof SEGMENT_TYPE_PARAM\n | typeof SEGMENT_TYPE_WILDCARD\n | typeof SEGMENT_TYPE_OPTIONAL_PARAM\n prefix: string\n suffix: string\n caseSensitive: boolean\n}\n\ntype AnySegmentNode<T extends RouteLike> =\n | StaticSegmentNode<T>\n | DynamicSegmentNode<T>\n\ntype SegmentNode<T extends RouteLike> = {\n kind: ExtendedSegmentKind\n prefix?: string\n suffix?: string\n caseSensitive?: boolean\n\n pathless: Array<StaticSegmentNode<T>> | null\n\n /** Exact index segment (highest priority) */\n index: StaticSegmentNode<T> | null\n\n /** Static segments (2nd priority) */\n static: Map<string, StaticSegmentNode<T>> | null\n\n /** Case insensitive static segments (3rd highest priority) */\n staticInsensitive: Map<string, StaticSegmentNode<T>> | null\n\n /** Dynamic segments ($param) */\n dynamic: Array<DynamicSegmentNode<T>> | null\n\n /** Optional dynamic segments ({-$param}) */\n optional: Array<DynamicSegmentNode<T>> | null\n\n /** Wildcard segments ($ - lowest priority) */\n wildcard: Array<DynamicSegmentNode<T>> | null\n\n /** Terminal route (if this path can end here) */\n route: T | null\n\n /** Original template data for this candidate or parse gate. */\n data: RouteInterpolation | undefined\n\n parent: AnySegmentNode<T> | undefined\n\n depth: number\n\n /** route.options.params.parse function, set on the last node of the route */\n parse: null | ((params: Record<string, string>) => unknown)\n\n /** route.options.params.priority ?? 0 */\n priority: number\n}\n\ntype RouteLike = {\n _interpolation?: RouteInterpolation\n id?: string\n path?: string // relative path from the parent,\n children?: Array<RouteLike> // child routes,\n parentRoute?: RouteLike // parent route,\n isRoot?: boolean\n options?: {\n caseSensitive?: boolean\n parseParams?: (params: Record<string, string>) => unknown\n params?: {\n parse?: (params: Record<string, string>) => unknown\n priority?: number\n }\n }\n} &\n // router tree\n (| { fullPath: string; from?: never } // full path from the root\n // flat route masks list\n | { fullPath?: never; from: string } // full path from the root\n )\n\nexport type ProcessedTree<\n TTree extends Extract<RouteLike, { fullPath: string }>,\n TFlat extends Extract<RouteLike, { from: string }>,\n TSingle extends Extract<RouteLike, { from: string }>,\n> = {\n /** a representation of the `routeTree` as a segment tree */\n segmentTree: AnySegmentNode<TTree>\n /** a mini route tree generated from the flat `routeMasks` list */\n masksTree: AnySegmentNode<TFlat> | null\n /** @deprecated keep until v2 so that `router.matchRoute` can keep not caring about the actual route tree */\n singleCache: SieveCache<string, AnySegmentNode<TSingle>>\n /** a cache of route matches from the `segmentTree` */\n matchCache: SieveCache<string, RouteMatch<TTree> | null>\n /** a cache of route matches from the `masksTree` */\n flatCache: SieveCache<string, ReturnType<typeof findMatch<TFlat>>> | null\n}\n\nexport function processRouteMasks<\n TRouteLike extends Extract<RouteLike, { from: string }>,\n>(\n routeList: Array<TRouteLike>,\n processedTree: ProcessedTree<any, TRouteLike, any>,\n) {\n const segmentTree = createSegmentNode<TRouteLike>()\n const dynamicListsToSort: Array<Array<DynamicSegmentNode<TRouteLike>>> = []\n function visit(\n route: TRouteLike,\n start: number,\n parentNode: AnySegmentNode<TRouteLike>,\n parentInterpolation?: RouteInterpolation,\n ) {\n const [node, cursor, segments] = parseSegments(\n false,\n route,\n start,\n parentNode,\n dynamicListsToSort,\n parentInterpolation,\n )\n if (route.children) {\n for (const child of route.children) {\n visit(child as TRouteLike, cursor, node, segments)\n }\n }\n }\n for (const route of routeList) {\n visit(route, 1, segmentTree)\n }\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n processedTree.masksTree = segmentTree\n processedTree.flatCache = createSieveCache<\n string,\n ReturnType<typeof findMatch<TRouteLike>>\n >(1000)\n}\n\n/**\n * Take an arbitrary list of routes, create a tree from them (if it hasn't been created already), and match a path against it.\n */\nexport function findFlatMatch<T extends Extract<RouteLike, { from: string }>>(\n /** The path to match. */\n path: string,\n /** The `processedTree` returned by the initial `processRouteTree` call. */\n processedTree: ProcessedTree<any, T, any>,\n) {\n path ||= '/'\n const cached = processedTree.flatCache!.get(path)\n if (cached !== undefined) return cached\n const result = findMatch(path, processedTree.masksTree!)\n processedTree.flatCache!.set(path, result)\n return result\n}\n\n/**\n * @deprecated keep until v2 so that `router.matchRoute` can keep not caring about the actual route tree\n */\nexport function findSingleMatch(\n from: string,\n caseSensitive: boolean,\n fuzzy: boolean,\n path: string,\n processedTree: ProcessedTree<any, any, { from: string }>,\n) {\n from ||= '/'\n path ||= '/'\n const key = caseSensitive ? `case\\0${from}` : from\n let tree = processedTree.singleCache.get(key)\n if (!tree) {\n // single flat routes (router.matchRoute) are not eagerly processed,\n // if we haven't seen this route before, process it now\n tree = createSegmentNode<{ from: string }>()\n parseSegments(caseSensitive, { from }, 1, tree)\n processedTree.singleCache.set(key, tree)\n }\n return findMatch(path, tree, fuzzy)\n}\n\ntype RouteMatch<T extends Extract<RouteLike, { fullPath: string }>> = {\n route: T\n rawParams: Record<string, string>\n branch: ReadonlyArray<T>\n}\n\nexport function findRouteMatch<\n T extends Extract<RouteLike, { fullPath: string }>,\n>(\n /** The path to match against the route tree. */\n path: string,\n /** The `processedTree` returned by the initial `processRouteTree` call. */\n processedTree: ProcessedTree<T, any, any>,\n /** If `true`, allows fuzzy matching (partial matches), i.e. which node in the tree would have been an exact match if the `path` had been shorter? */\n fuzzy = false,\n): RouteMatch<T> | null {\n const key = fuzzy ? path : `nofuzz\\0${path}` // the main use for `findRouteMatch` is fuzzy:true, so we optimize for that case\n const cached = processedTree.matchCache.get(key)\n if (cached !== undefined) return cached\n path ||= '/'\n let result: RouteMatch<T> | null\n\n try {\n result = findMatch(\n path,\n processedTree.segmentTree,\n fuzzy,\n ) as RouteMatch<T> | null\n } catch (err) {\n if (err instanceof URIError) {\n result = null\n } else {\n throw err\n }\n }\n\n if (result) result.branch = buildRouteBranch(result.route)\n processedTree.matchCache.set(key, result)\n return result\n}\n\nexport interface ProcessRouteTreeResult<\n TRouteLike extends Extract<RouteLike, { fullPath: string }> & { id: string },\n> {\n /** Should be considered a black box, needs to be provided to all matching functions in this module. */\n processedTree: ProcessedTree<TRouteLike, any, any>\n /** A lookup map of routes by their unique IDs. */\n routesById: Record<string, TRouteLike>\n /** A lookup map of routes by their trimmed full paths. */\n routesByPath: Record<string, TRouteLike>\n}\n\n/**\n * Processes a route tree into a segment trie for efficient path matching.\n * Also builds lookup maps for routes by ID and by trimmed full path.\n */\nexport function processRouteTree<\n TRouteLike extends Extract<RouteLike, { fullPath: string }> & {\n id: string\n init: (originalIndex: number) => void\n },\n>(\n /** The root of the route tree to process. */\n routeTree: TRouteLike,\n /** Whether matching should be case sensitive by default (overridden by individual route options). */\n caseSensitive: boolean = false,\n): ProcessRouteTreeResult<TRouteLike> {\n const segmentTree = createSegmentNode<TRouteLike>()\n const dynamicListsToSort: Array<Array<DynamicSegmentNode<TRouteLike>>> = []\n const routesById = {} as Record<string, TRouteLike>\n const routesByPath = {} as Record<string, TRouteLike>\n let index = 0\n function visit(\n route: TRouteLike,\n start: number,\n parentNode: AnySegmentNode<TRouteLike>,\n parentInterpolation?: RouteInterpolation,\n ) {\n route.init(index)\n\n if (route.id in routesById) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `Invariant failed: Duplicate routes found with id: ${String(route.id)}`,\n )\n }\n\n invariant()\n }\n\n routesById[route.id] = route\n if (index !== 0 && route.path) {\n const trimmedFullPath = trimPathRight(route.fullPath)\n if (!routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {\n routesByPath[trimmedFullPath] = route\n }\n }\n index++\n\n const [node, cursor, segments] = parseSegments(\n caseSensitive,\n route,\n start,\n parentNode,\n dynamicListsToSort,\n parentInterpolation,\n )\n route._interpolation = segments\n if (route.children) {\n for (const child of route.children) {\n visit(child as TRouteLike, cursor, node, segments)\n }\n }\n }\n visit(routeTree, 1, segmentTree)\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n const processedTree: ProcessedTree<TRouteLike, any, any> = {\n segmentTree,\n singleCache: createSieveCache<string, AnySegmentNode<any>>(1000),\n matchCache: createSieveCache<string, RouteMatch<TRouteLike> | null>(1000),\n flatCache: null,\n masksTree: null,\n }\n return {\n processedTree,\n routesById,\n routesByPath,\n }\n}\n\nfunction findMatch<T extends RouteLike>(\n path: string,\n segmentTree: AnySegmentNode<T>,\n fuzzy = false,\n): {\n route: T\n /**\n * The raw (unparsed) params extracted from the path.\n * This will be the exhaustive list of all params defined in the route's path.\n */\n rawParams: Record<string, string>\n} | null {\n const parts = path.split('/')\n const leaf = getNodeMatch(path, parts, segmentTree, fuzzy)\n if (!leaf) return null\n const [rawParams] = extractParams(path, parts, leaf)\n return {\n route: leaf.node.route!,\n rawParams,\n }\n}\n\ntype ParamExtractionState = {\n part: number\n node: number\n path: number\n param: number\n}\n\n/**\n * This function is \"resumable\":\n * - the `leaf` input can contain `extract` and `rawParams` properties from a previous `extractParams` call\n * - the returned `state` can be passed back as `extract` in a future call to continue extracting params from where we left off\n *\n * Inputs are *not* mutated.\n */\nfunction extractParams<T extends RouteLike>(\n path: string,\n parts: Array<string>,\n leaf: {\n node: AnySegmentNode<T>\n skipped: number\n extract?: ParamExtractionState\n rawParams?: Record<string, string>\n },\n): [rawParams: Record<string, string>, state: ParamExtractionState] {\n const list = buildBranch(leaf.node)\n const names = leaf.node.data && getParamNames(leaf.node.data)\n const rawParams: Record<string, string> = Object.create(null)\n /** which segment of the path we're currently processing */\n let partIndex = leaf.extract?.part ?? 0\n /** which node of the route tree branch we're currently processing */\n let nodeIndex = leaf.extract?.node ?? 0\n /** index of the 1st character of the segment we're processing in the path string */\n let pathIndex = leaf.extract?.path ?? 0\n /** Next original parameter name, independent of pathless/static nodes. */\n let paramIndex = leaf.extract?.param ?? 0\n for (; nodeIndex < list.length; partIndex++, nodeIndex++, pathIndex++) {\n const node = list[nodeIndex]!\n // index nodes are terminating nodes, nothing to extract, just leave\n if (node.kind === SEGMENT_TYPE_INDEX) break\n // pathless nodes do not consume a path segment\n if (node.kind === SEGMENT_TYPE_PATHLESS) {\n partIndex--\n pathIndex--\n continue\n }\n const part = parts[partIndex]\n const currentPathIndex = pathIndex\n if (part) pathIndex += part.length\n if (\n node.kind === SEGMENT_TYPE_PARAM ||\n node.kind === SEGMENT_TYPE_OPTIONAL_PARAM\n ) {\n const name = names![paramIndex++]!\n if (\n node.kind === SEGMENT_TYPE_OPTIONAL_PARAM &&\n leaf.skipped & (1 << nodeIndex)\n ) {\n partIndex-- // stay on the same part\n pathIndex = currentPathIndex - 1 // undo pathIndex advancement; -1 to account for loop increment\n continue\n }\n const value =\n node.suffix || node.prefix\n ? part!.substring(\n node.prefix.length,\n part!.length - node.suffix.length,\n )\n : part!\n if (value || node.kind === SEGMENT_TYPE_PARAM) {\n rawParams[name] = decodeURIComponent(value)\n }\n } else if (node.kind === SEGMENT_TYPE_WILDCARD) {\n const n = node\n const value = path.substring(\n currentPathIndex + n.prefix.length,\n path.length - n.suffix.length,\n )\n const splat = decodeURIComponent(value)\n // TODO: Deprecate *\n rawParams['*'] = splat\n rawParams._splat = splat\n break\n }\n }\n if (leaf.rawParams) Object.assign(rawParams, leaf.rawParams)\n return [\n rawParams,\n {\n part: partIndex,\n node: nodeIndex,\n path: pathIndex,\n param: paramIndex,\n },\n ]\n}\n\nexport function buildRouteBranch<T extends RouteLike>(route: T) {\n const list = [route]\n while (route.parentRoute) {\n route = route.parentRoute as T\n list.push(route)\n }\n list.reverse()\n return list\n}\n\nfunction buildBranch<T extends RouteLike>(node: AnySegmentNode<T>) {\n const list: Array<AnySegmentNode<T>> = Array(node.depth + 1)\n do {\n list[node.depth] = node\n node = node.parent!\n } while (node)\n return list\n}\n\ntype MatchStackFrame<T extends RouteLike> = {\n node: AnySegmentNode<T>\n /** index of the segment of path */\n index: number\n /**\n * Bitmask of skipped optional segments.\n *\n * This is a very performant way of storing an \"array of booleans\", but it means beyond 32 segments we can't track skipped optionals.\n * If we really really need to support more than 32 segments we can switch to using a `BigInt` here. It's about 2x slower in worst case scenarios.\n */\n skipped: number\n /** Positional bitmasks tracking which consumed URL segments matched each segment kind. */\n statics: number\n dynamics: number\n optionals: number\n /** intermediary state for param extraction */\n extract?: ParamExtractionState\n /** intermediary params from param extraction */\n rawParams?: Record<string, string>\n}\n\nfunction getNodeMatch<T extends RouteLike>(\n path: string,\n parts: Array<string>,\n segmentTree: AnySegmentNode<T>,\n fuzzy: boolean,\n) {\n // quick check for root index\n // this is an optimization, algorithm should work correctly without this block\n if (path === '/' && segmentTree.index)\n return { node: segmentTree.index, skipped: 0 } as Pick<\n Frame,\n 'node' | 'skipped'\n >\n\n const trailingSlash = !last(parts)\n const pathIsIndex = trailingSlash && path !== '/'\n const partsLength = parts.length - (trailingSlash ? 1 : 0)\n\n type Frame = MatchStackFrame<T>\n\n // use a stack to explore all possible paths (params cause branching)\n // iterate \"backwards\" (low priority first) so that we can push() each candidate, and pop() the highest priority candidate first\n // - pros: it is depth-first, so we find full matches faster\n // - cons: we cannot short-circuit, because highest priority matches are at the end of the loop (for loop with i--) (but we have no good short-circuiting anyway)\n // other possible approaches:\n // - shift instead of pop (measure performance difference), this allows iterating \"forwards\" (effectively breadth-first)\n // - never remove from the stack, keep a cursor instead. Then we can push \"forwards\" and avoid reversing the order of candidates (effectively breadth-first)\n const stack: Array<Frame> = [\n {\n node: segmentTree,\n index: 1,\n skipped: 0,\n statics: 0,\n dynamics: 0,\n optionals: 0,\n },\n ]\n\n let bestFuzzy: Frame | null = null\n let bestMatch: Frame | null = null\n\n while (stack.length) {\n const frame = stack.pop()!\n const { node, index, skipped, statics, dynamics, optionals } = frame\n let { extract, rawParams } = frame\n\n // Wildcard candidates are pushed speculatively as fallbacks in case a\n // higher-priority wildcard later fails params.parse. If a better wildcard\n // has already validated and become bestMatch, lower-priority wildcard\n // fallbacks cannot win anymore and should not run params.parse.\n if (\n node.kind === SEGMENT_TYPE_WILDCARD &&\n node.route &&\n !isFrameMoreSpecific(bestMatch, frame)\n ) {\n continue\n }\n\n if (node.parse) {\n const result = validateParseParams(path, parts, frame)\n if (!result) continue\n rawParams = frame.rawParams\n extract = frame.extract\n }\n\n // In fuzzy mode, track the best partial match we've found so far\n if (\n fuzzy &&\n node.route &&\n node.kind !== SEGMENT_TYPE_INDEX &&\n isFrameMoreSpecific(bestFuzzy, frame)\n ) {\n bestFuzzy = frame\n }\n\n const isBeyondPath = index === partsLength\n if (isBeyondPath) {\n if (\n node.route &&\n (!pathIsIndex ||\n node.kind === SEGMENT_TYPE_INDEX ||\n node.kind === SEGMENT_TYPE_WILDCARD) &&\n isFrameMoreSpecific(bestMatch, frame)\n ) {\n bestMatch = frame\n }\n // beyond the length of the path parts, only some segment types can match\n if (!node.optional && !node.wildcard && !node.index && !node.pathless)\n continue\n }\n\n const part = isBeyondPath ? undefined : parts[index]!\n let lowerPart: string\n\n // 0. Try index match\n if (isBeyondPath && node.index) {\n const indexFrame = {\n node: node.index,\n index,\n skipped,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n }\n let indexValid = true\n if (node.index.parse) {\n const result = validateParseParams(path, parts, indexFrame)\n if (!result) indexValid = false\n }\n if (indexValid) {\n // perfect match, no need to continue\n // this is an optimization, algorithm should work correctly without this block\n if (\n !dynamics &&\n !optionals &&\n !skipped &&\n isPerfectStaticMatch(statics, partsLength)\n ) {\n return indexFrame\n }\n if (isFrameMoreSpecific(bestMatch, indexFrame)) {\n // index matches skip the stack because they cannot have children\n bestMatch = indexFrame\n }\n }\n }\n\n // 5. Try wildcard match\n if (node.wildcard) {\n for (let i = node.wildcard.length - 1; i >= 0; i--) {\n const segment = node.wildcard[i]!\n const { prefix, suffix } = segment\n if (prefix) {\n if (isBeyondPath) continue\n const casePart = segment.caseSensitive\n ? part\n : (lowerPart ??= part!.toLowerCase())\n if (!casePart!.startsWith(prefix)) continue\n }\n if (suffix) {\n if (isBeyondPath) continue\n const end = parts.slice(index).join('/')\n const suffixPart = end.slice(-suffix.length)\n const casePart = segment.caseSensitive\n ? suffixPart\n : suffixPart.toLowerCase()\n if (\n casePart !== suffix ||\n end.length - suffix.length < prefix.length\n ) {\n continue\n }\n }\n // wildcard matches consume the rest of the URL and cannot have children\n stack.push({\n node: segment,\n index: partsLength,\n skipped,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n })\n }\n }\n\n // 4. Try optional match\n if (node.optional) {\n // A skipped optional is keyed by the child node's trie depth.\n const nextSkipped = skipped | (1 << (node.depth + 1))\n for (let i = node.optional.length - 1; i >= 0; i--) {\n const segment = node.optional[i]!\n // when skipping, the node advances by 1, but the index doesn't\n stack.push({\n node: segment,\n index,\n skipped: nextSkipped,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n }) // enqueue skipping the optional\n }\n if (!isBeyondPath) {\n for (let i = node.optional.length - 1; i >= 0; i--) {\n const segment = node.optional[i]!\n const { prefix, suffix } = segment\n if (prefix || suffix) {\n const casePart = segment.caseSensitive\n ? part!\n : (lowerPart ??= part!.toLowerCase())\n if (prefix && !casePart.startsWith(prefix)) continue\n if (\n suffix &&\n casePart.indexOf(suffix, casePart.length - suffix.length) <\n prefix.length\n ) {\n continue\n }\n }\n stack.push({\n node: segment,\n index: index + 1,\n skipped,\n statics,\n dynamics,\n optionals: optionals + segmentScore(partsLength, index),\n extract,\n rawParams,\n })\n }\n }\n }\n\n // 3. Try dynamic match\n if (!isBeyondPath && node.dynamic && part) {\n for (let i = node.dynamic.length - 1; i >= 0; i--) {\n const segment = node.dynamic[i]!\n const { prefix, suffix } = segment\n if (prefix || suffix) {\n const casePart = segment.caseSensitive\n ? part\n : (lowerPart ??= part.toLowerCase())\n if (prefix && !casePart.startsWith(prefix)) continue\n if (\n suffix &&\n casePart.indexOf(suffix, casePart.length - suffix.length) <\n prefix.length\n ) {\n continue\n }\n }\n stack.push({\n node: segment,\n index: index + 1,\n skipped,\n statics,\n dynamics: dynamics + segmentScore(partsLength, index),\n optionals,\n extract,\n rawParams,\n })\n }\n }\n\n // 2. Try case insensitive static match\n if (!isBeyondPath && node.staticInsensitive) {\n const match = node.staticInsensitive.get(\n (lowerPart ??= part!.toLowerCase()),\n )\n if (match) {\n stack.push({\n node: match,\n index: index + 1,\n skipped,\n statics: statics + segmentScore(partsLength, index),\n dynamics,\n optionals,\n extract,\n rawParams,\n })\n }\n }\n\n // 1. Try static match\n if (!isBeyondPath && node.static) {\n const match = node.static.get(part!)\n if (match) {\n stack.push({\n node: match,\n index: index + 1,\n skipped,\n statics: statics + segmentScore(partsLength, index),\n dynamics,\n optionals,\n extract,\n rawParams,\n })\n }\n }\n\n // 0. Try pathless match\n if (node.pathless) {\n for (let i = node.pathless.length - 1; i >= 0; i--) {\n const segment = node.pathless[i]!\n stack.push({\n node: segment,\n index,\n skipped,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n })\n }\n }\n }\n\n if (bestMatch) return bestMatch\n\n if (fuzzy && bestFuzzy) {\n let sliceIndex = bestFuzzy.index\n for (let i = 0; i < bestFuzzy.index; i++) {\n sliceIndex += parts[i]!.length\n }\n const splat = sliceIndex === path.length ? '/' : path.slice(sliceIndex)\n bestFuzzy.rawParams ??= Object.create(null)\n bestFuzzy.rawParams!['**'] = decodeURIComponent(splat)\n return bestFuzzy\n }\n\n return null\n}\n\nfunction segmentScore(partsLength: number, index: number): number {\n // The specificity scores are bitmasks over consumed URL segments. Earlier\n // URL segments should dominate later ones when comparing scores, so the\n // first real segment gets the highest bit and the last gets bit 0. Since\n // `parts[0]` is the empty string before the leading slash, real URL segments\n // are [1, partsLength), making this segment's bit `partsLength - index - 1`.\n return 2 ** (partsLength - index - 1)\n}\n\nfunction isPerfectStaticMatch(statics: number, partsLength: number): boolean {\n return statics === 2 ** (partsLength - 1) - 1\n}\n\nfunction validateParseParams<T extends RouteLike>(\n path: string,\n parts: Array<string>,\n frame: MatchStackFrame<T>,\n) {\n let rawParams: Record<string, string>\n let state: ParamExtractionState\n\n try {\n ;[rawParams, state] = extractParams(path, parts, frame)\n } catch {\n return null\n }\n\n frame.rawParams = rawParams\n frame.extract = state\n\n if (!frame.node.parse) return true\n\n try {\n if (frame.node.parse(rawParams) === false) return null\n } catch {\n // Thrown parse errors should be surfaced on the selected match by\n // extractStrictParams, not used as fallback route selection.\n }\n\n return true\n}\n\nfunction isFrameMoreSpecific(\n // the stack frame previously saved as \"best match\"\n prev: MatchStackFrame<any> | null,\n // the candidate stack frame\n next: MatchStackFrame<any>,\n): boolean {\n if (!prev) return true\n return (\n next.statics > prev.statics ||\n (next.statics === prev.statics &&\n (next.dynamics > prev.dynamics ||\n (next.dynamics === prev.dynamics &&\n (next.optionals > prev.optionals ||\n (next.optionals === prev.optionals &&\n ((next.node.kind === SEGMENT_TYPE_INDEX) >\n (prev.node.kind === SEGMENT_TYPE_INDEX) ||\n ((next.node.kind === SEGMENT_TYPE_INDEX) ===\n (prev.node.kind === SEGMENT_TYPE_INDEX) &&\n next.node.depth > prev.node.depth)))))))\n )\n}\n"],"mappings":"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"}