Sign In

@tanstack/router-core

Package Overview
Dependencies
Maintainers
3
Versions
489
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tanstack/router-core - npm Package Compare versions

Comparing version
1.171.23
to
1.171.24
+3
-11
dist/cjs/new-process-route-tree.cjs

@@ -6,10 +6,2 @@ const require_utils = require("./utils.cjs");

const SEGMENT_TYPE_PATHLESS = 5;
function getOpenAndCloseBraces(part) {
const openBrace = part.indexOf("{");
if (openBrace === -1) return null;
const closeBrace = part.indexOf("}", openBrace);
if (closeBrace === -1) return null;
if (openBrace + 1 >= part.length) return null;
return [openBrace, closeBrace];
}
/**

@@ -63,5 +55,5 @@ * Populates the `output` array with the parsed representation of the given `segment` string.

}
const braces = getOpenAndCloseBraces(part);
if (braces) {
const [openBrace, closeBrace] = braces;
const openBrace = part.indexOf("{");
let closeBrace;
if (openBrace !== -1 && openBrace + 1 < part.length && (closeBrace = part.indexOf("}", openBrace)) !== -1) {
const firstChar = part.charCodeAt(openBrace + 1);

@@ -68,0 +60,0 @@ if (firstChar === 45) {

@@ -1,1 +0,1 @@

{"version":3,"file":"new-process-route-tree.cjs","names":[],"sources":["../../src/new-process-route-tree.ts"],"sourcesContent":["import { invariant } from './invariant'\nimport { createLRUCache } from './lru-cache'\nimport { last } from './utils'\nimport type { LRUCache } from './lru-cache'\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\nfunction getOpenAndCloseBraces(\n part: string,\n): [openBrace: number, closeBrace: number] | null {\n const openBrace = part.indexOf('{')\n if (openBrace === -1) return null\n const closeBrace = part.indexOf('}', openBrace)\n if (closeBrace === -1) return null\n const afterOpen = openBrace + 1\n if (afterOpen >= part.length) return null\n return [openBrace, closeBrace]\n}\n\ntype ParsedSegment = Uint16Array & {\n /** segment type (0 = pathname, 1 = param, 2 = wildcard, 3 = optional param) */\n 0: SegmentKind\n /** index of the end of the prefix */\n 1: number\n /** index of the start of the value */\n 2: number\n /** index of the end of the value */\n 3: number\n /** index of the start of the suffix */\n 4: number\n /** index of the end of the segment */\n 5: number\n}\n\n/**\n * Populates the `output` array with the parsed representation of the given `segment` string.\n *\n * Usage:\n * ```ts\n * let output\n * let cursor = 0\n * while (cursor < path.length) {\n * output = parseSegment(path, cursor, output)\n * const end = output[5]\n * cursor = end + 1\n * ```\n *\n * `output` is stored outside to avoid allocations during repeated calls. It doesn't need to be typed\n * or initialized, it will be done automatically.\n */\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 /** A Uint16Array (length: 6) to populate with the parsed segment data. */\n output: Uint16Array = new Uint16Array(6),\n): ParsedSegment {\n const next = path.indexOf('/', start)\n const end = next === -1 ? path.length : next\n const part = path.substring(start, end)\n\n if (!part || !part.includes('$')) {\n // early escape for static pathname\n output[0] = SEGMENT_TYPE_PATHNAME\n output[1] = start\n output[2] = start\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n }\n\n // $ (wildcard)\n if (part === '$') {\n const total = path.length\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start\n output[2] = start\n output[3] = total\n output[4] = total\n output[5] = total\n return output as ParsedSegment\n }\n\n // $paramName\n if (part.charCodeAt(0) === 36) {\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start\n output[2] = start + 1 // skip '$'\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n }\n\n const braces = getOpenAndCloseBraces(part)\n if (braces) {\n const [openBrace, closeBrace] = braces\n const firstChar = part.charCodeAt(openBrace + 1)\n\n // Check for {-$...} (optional param)\n // prefix{-$paramName}suffix\n // /^([^{]*)\\{-\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/\n if (firstChar === 45) {\n // '-'\n if (\n openBrace + 2 < part.length &&\n part.charCodeAt(openBrace + 2) === 36 // '$'\n ) {\n const paramStart = openBrace + 3\n const paramEnd = closeBrace\n // Validate param name exists\n if (paramStart < paramEnd) {\n output[0] = SEGMENT_TYPE_OPTIONAL_PARAM\n output[1] = start + openBrace\n output[2] = start + paramStart\n output[3] = start + paramEnd\n output[4] = start + closeBrace + 1\n output[5] = end\n return output as ParsedSegment\n }\n }\n } else if (firstChar === 36) {\n // '$'\n const dollarPos = openBrace + 1\n const afterDollar = openBrace + 2\n // Check for {$} (wildcard)\n if (afterDollar === closeBrace) {\n // For wildcard, value should be '$' (from dollarPos to afterDollar)\n // prefix{$}suffix\n // /^([^{]*)\\{\\$\\}([^}]*)$/\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start + openBrace\n output[2] = start + dollarPos\n output[3] = start + afterDollar\n output[4] = start + closeBrace + 1\n output[5] = path.length\n return output as ParsedSegment\n }\n // Regular param {$paramName} - value is the param name (after $)\n // prefix{$paramName}suffix\n // /^([^{]*)\\{\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start + openBrace\n output[2] = start + afterDollar\n output[3] = start + closeBrace\n output[4] = start + closeBrace + 1\n output[5] = end\n return output as ParsedSegment\n }\n }\n\n // fallback to static pathname (should never happen)\n output[0] = SEGMENT_TYPE_PATHNAME\n output[1] = start\n output[2] = start\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n}\n\n/**\n * Recursively parses the segments of the given route tree and populates a segment trie.\n *\n * @param data A reusable Uint16Array for parsing segments. (non important, we're just avoiding allocations)\n * @param route The current route to parse.\n * @param start The starting index for parsing within the route's full path.\n * @param node The current segment node in the trie to populate.\n * @param onRoute Callback invoked for each route processed.\n */\nfunction parseSegments<TRouteLike extends RouteLike>(\n defaultCaseSensitive: boolean,\n data: Uint16Array,\n route: TRouteLike,\n start: number,\n node: AnySegmentNode<TRouteLike>,\n depth: number,\n /** Each dynamic sibling list is recorded once, when it first needs sorting. */\n dynamicListsToSort?: Array<Array<DynamicSegmentNode<TRouteLike>>>,\n onRoute?: (route: TRouteLike) => void,\n) {\n onRoute?.(route)\n let cursor = start\n {\n const path = route.fullPath ?? route.from\n const options = route.options\n const length = path.length\n const caseSensitive = options?.caseSensitive ?? defaultCaseSensitive\n const parseParams = options?.params?.parse ?? options?.parseParams\n while (cursor < length) {\n const segment = parseSegment(path, cursor, data)\n let nextNode: AnySegmentNode<TRouteLike>\n const start = cursor\n const end = segment[5]\n cursor = end + 1\n depth++\n const kind = segment[0]\n switch (kind) {\n case SEGMENT_TYPE_PATHNAME: {\n const value = path.substring(segment[2], segment[3])\n let name = value\n let staticChildren: Map<string, StaticSegmentNode<TRouteLike>>\n if (caseSensitive) {\n staticChildren = node.static ??= new Map()\n } else {\n name = value.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 = createStaticNode<TRouteLike>(path)\n next.parent = node\n next.depth = depth\n nextNode = next\n staticChildren.set(name, next)\n }\n break\n }\n case SEGMENT_TYPE_PARAM:\n case SEGMENT_TYPE_OPTIONAL_PARAM:\n case SEGMENT_TYPE_WILDCARD: {\n const prefix_raw = path.substring(start, segment[1])\n const suffix_raw = path.substring(segment[4], end)\n const actuallyCaseSensitive =\n caseSensitive && !!(prefix_raw || suffix_raw)\n const prefix = !prefix_raw\n ? undefined\n : actuallyCaseSensitive\n ? prefix_raw\n : prefix_raw.toLowerCase()\n const suffix = !suffix_raw\n ? undefined\n : actuallyCaseSensitive\n ? suffix_raw\n : suffix_raw.toLowerCase()\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 = createDynamicNode<TRouteLike>(\n kind,\n path,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.parent = node\n next.depth = depth\n let nodes: Array<DynamicSegmentNode<TRouteLike>>\n if (kind === SEGMENT_TYPE_PARAM) {\n nodes = node.dynamic ??= []\n } else if (kind === SEGMENT_TYPE_OPTIONAL_PARAM) {\n nodes = node.optional ??= []\n } else {\n nodes = node.wildcard ??= []\n }\n nodes.push(next)\n if (nodes.length === 2) {\n dynamicListsToSort?.push(nodes)\n }\n }\n break\n }\n }\n node = nextNode\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 = createStaticNode<TRouteLike>(path)\n pathlessNode.kind = SEGMENT_TYPE_PATHLESS\n pathlessNode.parent = node\n depth++\n pathlessNode.depth = depth\n node.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 && path.endsWith('/')) {\n const indexNode = createStaticNode<TRouteLike>(path)\n indexNode.kind = SEGMENT_TYPE_INDEX\n indexNode.parent = node\n depth++\n indexNode.depth = depth\n node.index = indexNode\n node = indexNode\n }\n\n node.parse = parseParams ?? null\n node.priority = options?.params?.priority ?? 0\n\n // make node \"matchable\"\n if (isLeaf && !node.route) {\n node.route = route\n node.fullPath = path\n }\n }\n if (route.children)\n for (const child of route.children) {\n parseSegments(\n defaultCaseSensitive,\n data,\n child as TRouteLike,\n cursor,\n node,\n depth,\n dynamicListsToSort,\n onRoute,\n )\n }\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 createStaticNode<T extends RouteLike>(\n fullPath: string,\n): StaticSegmentNode<T> {\n return {\n kind: SEGMENT_TYPE_PATHNAME,\n depth: 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 fullPath,\n parent: null,\n parse: null,\n priority: 0,\n }\n}\n\n/**\n * Keys must be declared in the same order as in `SegmentNode` type,\n * to ensure they are represented as the same object class in the engine.\n */\nfunction createDynamicNode<T extends RouteLike>(\n kind:\n | typeof SEGMENT_TYPE_PARAM\n | typeof SEGMENT_TYPE_WILDCARD\n | typeof SEGMENT_TYPE_OPTIONAL_PARAM,\n fullPath: string,\n caseSensitive: boolean,\n prefix?: string,\n suffix?: string,\n): DynamicSegmentNode<T> {\n return {\n kind,\n depth: 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 fullPath,\n parent: null,\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\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 /** The full path for this segment node (will only be valid on leaf nodes) */\n fullPath: string\n\n parent: AnySegmentNode<T> | null\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 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: LRUCache<string, AnySegmentNode<TSingle>>\n /** a cache of route matches from the `segmentTree` */\n matchCache: LRUCache<string, RouteMatch<TTree> | null>\n /** a cache of route matches from the `masksTree` */\n flatCache: LRUCache<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 = createStaticNode<TRouteLike>('/')\n const data = new Uint16Array(6)\n const dynamicListsToSort: Array<Array<DynamicSegmentNode<TRouteLike>>> = []\n for (const route of routeList) {\n parseSegments(false, data, route, 1, segmentTree, 0, dynamicListsToSort)\n }\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n processedTree.masksTree = segmentTree\n processedTree.flatCache = createLRUCache<\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) 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 = createStaticNode<{ from: string }>('/')\n const data = new Uint16Array(6)\n parseSegments(caseSensitive, data, { from }, 1, tree, 0)\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\n/** Trim trailing slashes (except preserving root '/'). */\nexport function trimPathRight(path: string) {\n return path === '/' ? path : path.replace(/\\/{1,}$/, '')\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 }> & { id: string },\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 /** Optional callback invoked for each route during processing. */\n initRoute?: (route: TRouteLike, index: number) => void,\n): ProcessRouteTreeResult<TRouteLike> {\n const segmentTree = createStaticNode<TRouteLike>(routeTree.fullPath)\n const data = new Uint16Array(6)\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 parseSegments(\n caseSensitive,\n data,\n routeTree,\n 1,\n segmentTree,\n 0,\n dynamicListsToSort,\n (route) => {\n initRoute?.(route, 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\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\n index++\n },\n )\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n const processedTree: ProcessedTree<TRouteLike, any, any> = {\n segmentTree,\n singleCache: createLRUCache<string, AnySegmentNode<any>>(1000),\n matchCache: createLRUCache<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 segment: 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 let nodeParts: Array<string> | null = null\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 /** which fullPath segment we're currently processing */\n let segmentCount = leaf.extract?.segment ?? 0\n for (\n ;\n nodeIndex < list.length;\n partIndex++, nodeIndex++, pathIndex++, segmentCount++\n ) {\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 segmentCount--\n partIndex--\n pathIndex--\n continue\n }\n const part = parts[partIndex]\n const currentPathIndex = pathIndex\n if (part) pathIndex += part.length\n if (node.kind === SEGMENT_TYPE_PARAM) {\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[segmentCount]!\n const preLength = node.prefix?.length ?? 0\n // we can't rely on the presence of prefix/suffix to know whether it's curly-braced or not, because `/{$param}/` is valid, but has no prefix/suffix\n const isCurlyBraced = nodePart.charCodeAt(preLength) === 123 // '{'\n // param name is extracted at match-time so that tree nodes that are identical except for param name can share the same node\n if (isCurlyBraced) {\n const sufLength = node.suffix?.length ?? 0\n const name = nodePart.substring(\n preLength + 2,\n nodePart.length - sufLength - 1,\n )\n const value = part!.substring(preLength, part!.length - sufLength)\n rawParams[name] = decodeURIComponent(value)\n } else {\n const name = nodePart.substring(1)\n rawParams[name] = decodeURIComponent(part!)\n }\n } else if (node.kind === SEGMENT_TYPE_OPTIONAL_PARAM) {\n if (leaf.skipped & (1 << nodeIndex)) {\n partIndex-- // stay on the same part\n pathIndex = currentPathIndex - 1 // undo pathIndex advancement; -1 to account for loop increment\n continue\n }\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[segmentCount]!\n const preLength = node.prefix?.length ?? 0\n const sufLength = node.suffix?.length ?? 0\n const name = nodePart.substring(\n preLength + 3,\n nodePart.length - sufLength - 1,\n )\n const value =\n node.suffix || node.prefix\n ? part!.substring(preLength, part!.length - sufLength)\n : part\n if (value) rawParams[name] = decodeURIComponent(value)\n } else if (node.kind === SEGMENT_TYPE_WILDCARD) {\n const n = node\n const value = path.substring(\n currentPathIndex + (n.prefix?.length ?? 0),\n path.length - (n.suffix?.length ?? 0),\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 segment: segmentCount,\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('/').slice(-suffix.length)\n const casePart = segment.caseSensitive ? end : end.toLowerCase()\n if (casePart !== suffix) continue\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 (suffix && !casePart.endsWith(suffix)) continue\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 (suffix && !casePart.endsWith(suffix)) continue\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":";;;AASA,MAAM,qBAAqB;AAC3B,MAAM,wBAAwB;AAmB9B,SAAS,sBACP,MACgD;CAChD,MAAM,YAAY,KAAK,QAAQ,GAAG;CAClC,IAAI,cAAc,IAAI,OAAO;CAC7B,MAAM,aAAa,KAAK,QAAQ,KAAK,SAAS;CAC9C,IAAI,eAAe,IAAI,OAAO;CAE9B,IADkB,YAAY,KACb,KAAK,QAAQ,OAAO;CACrC,OAAO,CAAC,WAAW,UAAU;AAC/B;;;;;;;;;;;;;;;;;AAiCA,SAAgB,aAEd,MAEA,OAEA,SAAsB,IAAI,YAAY,CAAC,GACxB;CACf,MAAM,OAAO,KAAK,QAAQ,KAAK,KAAK;CACpC,MAAM,MAAM,SAAS,KAAK,KAAK,SAAS;CACxC,MAAM,OAAO,KAAK,UAAU,OAAO,GAAG;CAEtC,IAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,GAAG,GAAG;EAEhC,OAAO,KAAA;EACP,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO;CACT;CAGA,IAAI,SAAS,KAAK;EAChB,MAAM,QAAQ,KAAK;EACnB,OAAO,KAAA;EACP,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO;CACT;CAGA,IAAI,KAAK,WAAW,CAAC,MAAM,IAAI;EAC7B,OAAO,KAAA;EACP,OAAO,KAAK;EACZ,OAAO,KAAK,QAAQ;EACpB,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO;CACT;CAEA,MAAM,SAAS,sBAAsB,IAAI;CACzC,IAAI,QAAQ;EACV,MAAM,CAAC,WAAW,cAAc;EAChC,MAAM,YAAY,KAAK,WAAW,YAAY,CAAC;EAK/C,IAAI,cAAc;OAGd,YAAY,IAAI,KAAK,UACrB,KAAK,WAAW,YAAY,CAAC,MAAM,IACnC;IACA,MAAM,aAAa,YAAY;IAC/B,MAAM,WAAW;IAEjB,IAAI,aAAa,UAAU;KACzB,OAAO,KAAA;KACP,OAAO,KAAK,QAAQ;KACpB,OAAO,KAAK,QAAQ;KACpB,OAAO,KAAK,QAAQ;KACpB,OAAO,KAAK,QAAQ,aAAa;KACjC,OAAO,KAAK;KACZ,OAAO;IACT;GACF;SACK,IAAI,cAAc,IAAI;GAE3B,MAAM,YAAY,YAAY;GAC9B,MAAM,cAAc,YAAY;GAEhC,IAAI,gBAAgB,YAAY;IAI9B,OAAO,KAAA;IACP,OAAO,KAAK,QAAQ;IACpB,OAAO,KAAK,QAAQ;IACpB,OAAO,KAAK,QAAQ;IACpB,OAAO,KAAK,QAAQ,aAAa;IACjC,OAAO,KAAK,KAAK;IACjB,OAAO;GACT;GAIA,OAAO,KAAA;GACP,OAAO,KAAK,QAAQ;GACpB,OAAO,KAAK,QAAQ;GACpB,OAAO,KAAK,QAAQ;GACpB,OAAO,KAAK,QAAQ,aAAa;GACjC,OAAO,KAAK;GACZ,OAAO;EACT;CACF;CAGA,OAAO,KAAA;CACP,OAAO,KAAK;CACZ,OAAO,KAAK;CACZ,OAAO,KAAK;CACZ,OAAO,KAAK;CACZ,OAAO,KAAK;CACZ,OAAO;AACT;;;;;;;;;;AAWA,SAAS,cACP,sBACA,MACA,OACA,OACA,MACA,OAEA,oBACA,SACA;CACA,UAAU,KAAK;CACf,IAAI,SAAS;CACb;EACE,MAAM,OAAO,MAAM,YAAY,MAAM;EACrC,MAAM,UAAU,MAAM;EACtB,MAAM,SAAS,KAAK;EACpB,MAAM,gBAAgB,SAAS,iBAAiB;EAChD,MAAM,cAAc,SAAS,QAAQ,SAAS,SAAS;EACvD,OAAO,SAAS,QAAQ;GACtB,MAAM,UAAU,aAAa,MAAM,QAAQ,IAAI;GAC/C,IAAI;GACJ,MAAM,QAAQ;GACd,MAAM,MAAM,QAAQ;GACpB,SAAS,MAAM;GACf;GACA,MAAM,OAAO,QAAQ;GACrB,QAAQ,MAAR;IACE,KAAA,GAA4B;KAC1B,MAAM,QAAQ,KAAK,UAAU,QAAQ,IAAI,QAAQ,EAAE;KACnD,IAAI,OAAO;KACX,IAAI;KACJ,IAAI,eACF,iBAAiB,KAAK,2BAAW,IAAI,IAAI;UACpC;MACL,OAAO,MAAM,YAAY;MACzB,iBAAiB,KAAK,sCAAsB,IAAI,IAAI;KACtD;KACA,MAAM,eAAe,eAAe,IAAI,IAAI;KAC5C,IAAI,cACF,WAAW;UACN;MACL,MAAM,OAAO,iBAA6B,IAAI;MAC9C,KAAK,SAAS;MACd,KAAK,QAAQ;MACb,WAAW;MACX,eAAe,IAAI,MAAM,IAAI;KAC/B;KACA;IACF;IACA,KAAA;IACA,KAAA;IACA,KAAA,GAA4B;KAC1B,MAAM,aAAa,KAAK,UAAU,OAAO,QAAQ,EAAE;KACnD,MAAM,aAAa,KAAK,UAAU,QAAQ,IAAI,GAAG;KACjD,MAAM,wBACJ,iBAAiB,CAAC,EAAE,cAAc;KACpC,MAAM,SAAS,CAAC,aACZ,KAAA,IACA,wBACE,aACA,WAAW,YAAY;KAC7B,MAAM,SAAS,CAAC,aACZ,KAAA,IACA,wBACE,aACA,WAAW,YAAY;KAC7B,MAAM,WACJ,SAAA,IACI,KAAK,UACL,SAAA,IACE,KAAK,WACL,KAAK;KACb,MAAM,eAGJ,SAAA,KACA,CAAC,eACD,UAAU,MACP,MACC,CAAC,EAAE,SACH,EAAE,kBAAkB,yBACpB,EAAE,WAAW,UACb,EAAE,WAAW,MACjB;KACF,IAAI,cACF,WAAW;UACN;MACL,MAAM,OAAO,kBACX,MACA,MACA,uBACA,QACA,MACF;MACA,WAAW;MACX,KAAK,SAAS;MACd,KAAK,QAAQ;MACb,IAAI;MACJ,IAAI,SAAA,GACF,QAAQ,KAAK,YAAY,CAAC;WACrB,IAAI,SAAA,GACT,QAAQ,KAAK,aAAa,CAAC;WAE3B,QAAQ,KAAK,aAAa,CAAC;MAE7B,MAAM,KAAK,IAAI;MACf,IAAI,MAAM,WAAW,GACnB,oBAAoB,KAAK,KAAK;KAElC;KACA;IACF;GACF;GACA,OAAO;EACT;EAGA,IACE,eACA,MAAM,YACN,CAAC,MAAM,UACP,MAAM,MACN,MAAM,GAAG,WAAW,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC,MAAM,IACvD;GACA,MAAM,eAAe,iBAA6B,IAAI;GACtD,aAAa,OAAO;GACpB,aAAa,SAAS;GACtB;GACA,aAAa,QAAQ;GACrB,KAAK,aAAa,CAAC;GACnB,KAAK,SAAS,KAAK,YAAY;GAC/B,OAAO;EACT;EAEA,MAAM,UAAU,MAAM,QAAQ,CAAC,MAAM,aAAa,CAAC,MAAM;EAEzD,IAAI,UAAU,KAAK,SAAS,GAAG,GAAG;GAChC,MAAM,YAAY,iBAA6B,IAAI;GACnD,UAAU,OAAO;GACjB,UAAU,SAAS;GACnB;GACA,UAAU,QAAQ;GAClB,KAAK,QAAQ;GACb,OAAO;EACT;EAEA,KAAK,QAAQ,eAAe;EAC5B,KAAK,WAAW,SAAS,QAAQ,YAAY;EAG7C,IAAI,UAAU,CAAC,KAAK,OAAO;GACzB,KAAK,QAAQ;GACb,KAAK,WAAW;EAClB;CACF;CACA,IAAI,MAAM,UACR,KAAK,MAAM,SAAS,MAAM,UACxB,cACE,sBACA,MACA,OACA,QACA,MACA,OACA,oBACA,OACF;AAEN;AAEA,SAAS,YACP,GAOA,GAOA;CACA,IAAI,EAAE,SAAS,CAAC,EAAE,OAAO,OAAO;CAChC,IAAI,CAAC,EAAE,SAAS,EAAE,OAAO,OAAO;CAChC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,WACzC,OAAO,EAAE,WAAW,EAAE;CACxB,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ;EACjD,IAAI,EAAE,OAAO,WAAW,EAAE,MAAM,GAAG,OAAO;EAC1C,IAAI,EAAE,OAAO,WAAW,EAAE,MAAM,GAAG,OAAO;CAC5C;CACA,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ;EACjD,IAAI,EAAE,OAAO,SAAS,EAAE,MAAM,GAAG,OAAO;EACxC,IAAI,EAAE,OAAO,SAAS,EAAE,MAAM,GAAG,OAAO;CAC1C;CACA,IAAI,EAAE,UAAU,CAAC,EAAE,QAAQ,OAAO;CAClC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,OAAO;CAClC,IAAI,EAAE,UAAU,CAAC,EAAE,QAAQ,OAAO;CAClC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,OAAO;CAClC,IAAI,EAAE,iBAAiB,CAAC,EAAE,eAAe,OAAO;CAChD,IAAI,CAAC,EAAE,iBAAiB,EAAE,eAAe,OAAO;CAGhD,OAAO;AACT;AAEA,SAAS,iBACP,UACsB;CACtB,OAAO;EACL,MAAA;EACA,OAAO;EACP,UAAU;EACV,OAAO;EACP,QAAQ;EACR,mBAAmB;EACnB,SAAS;EACT,UAAU;EACV,UAAU;EACV,OAAO;EACP;EACA,QAAQ;EACR,OAAO;EACP,UAAU;CACZ;AACF;;;;;AAMA,SAAS,kBACP,MAIA,UACA,eACA,QACA,QACuB;CACvB,OAAO;EACL;EACA,OAAO;EACP,UAAU;EACV,OAAO;EACP,QAAQ;EACR,mBAAmB;EACnB,SAAS;EACT,UAAU;EACV,UAAU;EACV,OAAO;EACP;EACA,QAAQ;EACR,OAAO;EACP,UAAU;EACV;EACA;EACA;CACF;AACF;AAqGA,SAAgB,kBAGd,WACA,eACA;CACA,MAAM,cAAc,iBAA6B,GAAG;CACpD,MAAM,OAAO,IAAI,YAAY,CAAC;CAC9B,MAAM,qBAAmE,CAAC;CAC1E,KAAK,MAAM,SAAS,WAClB,cAAc,OAAO,MAAM,OAAO,GAAG,aAAa,GAAG,kBAAkB;CAEzE,KAAK,MAAM,SAAS,oBAClB,MAAM,KAAK,WAAW;CAExB,cAAc,YAAY;CAC1B,cAAc,YAAY,kBAAA,eAGxB,GAAI;AACR;;;;AAKA,SAAgB,cAEd,MAEA,eACA;CACA,SAAS;CACT,MAAM,SAAS,cAAc,UAAW,IAAI,IAAI;CAChD,IAAI,QAAQ,OAAO;CACnB,MAAM,SAAS,UAAU,MAAM,cAAc,SAAU;CACvD,cAAc,UAAW,IAAI,MAAM,MAAM;CACzC,OAAO;AACT;;;;AAKA,SAAgB,gBACd,MACA,eACA,OACA,MACA,eACA;CACA,SAAS;CACT,SAAS;CACT,MAAM,MAAM,gBAAgB,SAAS,SAAS;CAC9C,IAAI,OAAO,cAAc,YAAY,IAAI,GAAG;CAC5C,IAAI,CAAC,MAAM;EAGT,OAAO,iBAAmC,GAAG;EAE7C,cAAc,eAAe,IADZ,YAAY,CACA,GAAM,EAAE,KAAK,GAAG,GAAG,MAAM,CAAC;EACvD,cAAc,YAAY,IAAI,KAAK,IAAI;CACzC;CACA,OAAO,UAAU,MAAM,MAAM,KAAK;AACpC;AAQA,SAAgB,eAId,MAEA,eAEA,QAAQ,OACc;CACtB,MAAM,MAAM,QAAQ,OAAO,WAAW;CACtC,MAAM,SAAS,cAAc,WAAW,IAAI,GAAG;CAC/C,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,SAAS;CACT,IAAI;CAEJ,IAAI;EACF,SAAS,UACP,MACA,cAAc,aACd,KACF;CACF,SAAS,KAAK;EACZ,IAAI,eAAe,UACjB,SAAS;OAET,MAAM;CAEV;CAEA,IAAI,QAAQ,OAAO,SAAS,iBAAiB,OAAO,KAAK;CACzD,cAAc,WAAW,IAAI,KAAK,MAAM;CACxC,OAAO;AACT;;AAGA,SAAgB,cAAc,MAAc;CAC1C,OAAO,SAAS,MAAM,OAAO,KAAK,QAAQ,WAAW,EAAE;AACzD;;;;;AAiBA,SAAgB,iBAId,WAEA,gBAAyB,OAEzB,WACoC;CACpC,MAAM,cAAc,iBAA6B,UAAU,QAAQ;CACnE,MAAM,OAAO,IAAI,YAAY,CAAC;CAC9B,MAAM,qBAAmE,CAAC;CAC1E,MAAM,aAAa,CAAC;CACpB,MAAM,eAAe,CAAC;CACtB,IAAI,QAAQ;CACZ,cACE,eACA,MACA,WACA,GACA,aACA,GACA,qBACC,UAAU;EACT,YAAY,OAAO,KAAK;EAExB,IAAI,MAAM,MAAM,YAAY;GAC1B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,qDAAqD,OAAO,MAAM,EAAE,GACtE;GAGF,kBAAA,UAAU;EACZ;EAEA,WAAW,MAAM,MAAM;EAEvB,IAAI,UAAU,KAAK,MAAM,MAAM;GAC7B,MAAM,kBAAkB,cAAc,MAAM,QAAQ;GACpD,IAAI,CAAC,aAAa,oBAAoB,MAAM,SAAS,SAAS,GAAG,GAC/D,aAAa,mBAAmB;EAEpC;EAEA;CACF,CACF;CACA,KAAK,MAAM,SAAS,oBAClB,MAAM,KAAK,WAAW;CASxB,OAAO;EACL,eAAA;GAPA;GACA,aAAa,kBAAA,eAA4C,GAAI;GAC7D,YAAY,kBAAA,eAAsD,GAAI;GACtE,WAAW;GACX,WAAW;EAGX;EACA;EACA;CACF;AACF;AAEA,SAAS,UACP,MACA,aACA,QAAQ,OAQD;CACP,MAAM,QAAQ,KAAK,MAAM,GAAG;CAC5B,MAAM,OAAO,aAAa,MAAM,OAAO,aAAa,KAAK;CACzD,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,CAAC,aAAa,cAAc,MAAM,OAAO,IAAI;CACnD,OAAO;EACL,OAAO,KAAK,KAAK;EACjB;CACF;AACF;;;;;;;;AAgBA,SAAS,cACP,MACA,OACA,MAMkE;CAClE,MAAM,OAAO,YAAY,KAAK,IAAI;CAClC,IAAI,YAAkC;CACtC,MAAM,YAAoC,OAAO,OAAO,IAAI;;CAE5D,IAAI,YAAY,KAAK,SAAS,QAAQ;;CAEtC,IAAI,YAAY,KAAK,SAAS,QAAQ;;CAEtC,IAAI,YAAY,KAAK,SAAS,QAAQ;;CAEtC,IAAI,eAAe,KAAK,SAAS,WAAW;CAC5C,OAEE,YAAY,KAAK,QACjB,aAAa,aAAa,aAAa,gBACvC;EACA,MAAM,OAAO,KAAK;EAElB,IAAI,KAAK,SAAS,oBAAoB;EAEtC,IAAI,KAAK,SAAS,uBAAuB;GACvC;GACA;GACA;GACA;EACF;EACA,MAAM,OAAO,MAAM;EACnB,MAAM,mBAAmB;EACzB,IAAI,MAAM,aAAa,KAAK;EAC5B,IAAI,KAAK,SAAA,GAA6B;GACpC,cAAc,KAAK,KAAK,SAAS,MAAM,GAAG;GAC1C,MAAM,WAAW,UAAU;GAC3B,MAAM,YAAY,KAAK,QAAQ,UAAU;GAIzC,IAFsB,SAAS,WAAW,SAAS,MAAM,KAEtC;IACjB,MAAM,YAAY,KAAK,QAAQ,UAAU;IACzC,MAAM,OAAO,SAAS,UACpB,YAAY,GACZ,SAAS,SAAS,YAAY,CAChC;IACA,MAAM,QAAQ,KAAM,UAAU,WAAW,KAAM,SAAS,SAAS;IACjE,UAAU,QAAQ,mBAAmB,KAAK;GAC5C,OAAO;IACL,MAAM,OAAO,SAAS,UAAU,CAAC;IACjC,UAAU,QAAQ,mBAAmB,IAAK;GAC5C;EACF,OAAO,IAAI,KAAK,SAAA,GAAsC;GACpD,IAAI,KAAK,UAAW,KAAK,WAAY;IACnC;IACA,YAAY,mBAAmB;IAC/B;GACF;GACA,cAAc,KAAK,KAAK,SAAS,MAAM,GAAG;GAC1C,MAAM,WAAW,UAAU;GAC3B,MAAM,YAAY,KAAK,QAAQ,UAAU;GACzC,MAAM,YAAY,KAAK,QAAQ,UAAU;GACzC,MAAM,OAAO,SAAS,UACpB,YAAY,GACZ,SAAS,SAAS,YAAY,CAChC;GACA,MAAM,QACJ,KAAK,UAAU,KAAK,SAChB,KAAM,UAAU,WAAW,KAAM,SAAS,SAAS,IACnD;GACN,IAAI,OAAO,UAAU,QAAQ,mBAAmB,KAAK;EACvD,OAAO,IAAI,KAAK,SAAA,GAAgC;GAC9C,MAAM,IAAI;GACV,MAAM,QAAQ,KAAK,UACjB,oBAAoB,EAAE,QAAQ,UAAU,IACxC,KAAK,UAAU,EAAE,QAAQ,UAAU,EACrC;GACA,MAAM,QAAQ,mBAAmB,KAAK;GAEtC,UAAU,OAAO;GACjB,UAAU,SAAS;GACnB;EACF;CACF;CACA,IAAI,KAAK,WAAW,OAAO,OAAO,WAAW,KAAK,SAAS;CAC3D,OAAO,CACL,WACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;EACN,SAAS;CACX,CACF;AACF;AAEA,SAAgB,iBAAsC,OAAU;CAC9D,MAAM,OAAO,CAAC,KAAK;CACnB,OAAO,MAAM,aAAa;EACxB,QAAQ,MAAM;EACd,KAAK,KAAK,KAAK;CACjB;CACA,KAAK,QAAQ;CACb,OAAO;AACT;AAEA,SAAS,YAAiC,MAAyB;CACjE,MAAM,OAAiC,MAAM,KAAK,QAAQ,CAAC;CAC3D,GAAG;EACD,KAAK,KAAK,SAAS;EACnB,OAAO,KAAK;CACd,SAAS;CACT,OAAO;AACT;AAuBA,SAAS,aACP,MACA,OACA,aACA,OACA;CAGA,IAAI,SAAS,OAAO,YAAY,OAC9B,OAAO;EAAE,MAAM,YAAY;EAAO,SAAS;CAAE;CAK/C,MAAM,gBAAgB,CAAC,cAAA,KAAK,KAAK;CACjC,MAAM,cAAc,iBAAiB,SAAS;CAC9C,MAAM,cAAc,MAAM,UAAU,gBAAgB,IAAI;CAWxD,MAAM,QAAsB,CAC1B;EACE,MAAM;EACN,OAAO;EACP,SAAS;EACT,SAAS;EACT,UAAU;EACV,WAAW;CACb,CACF;CAEA,IAAI,YAA0B;CAC9B,IAAI,YAA0B;CAE9B,OAAO,MAAM,QAAQ;EACnB,MAAM,QAAQ,MAAM,IAAI;EACxB,MAAM,EAAE,MAAM,OAAO,SAAS,SAAS,UAAU,cAAc;EAC/D,IAAI,EAAE,SAAS,cAAc;EAM7B,IACE,KAAK,SAAA,KACL,KAAK,SACL,CAAC,oBAAoB,WAAW,KAAK,GAErC;EAGF,IAAI,KAAK,OAAO;GAEd,IAAI,CADW,oBAAoB,MAAM,OAAO,KAC3C,GAAQ;GACb,YAAY,MAAM;GAClB,UAAU,MAAM;EAClB;EAGA,IACE,SACA,KAAK,SACL,KAAK,SAAS,sBACd,oBAAoB,WAAW,KAAK,GAEpC,YAAY;EAGd,MAAM,eAAe,UAAU;EAC/B,IAAI,cAAc;GAChB,IACE,KAAK,UACJ,CAAC,eACA,KAAK,SAAS,sBACd,KAAK,SAAA,MACP,oBAAoB,WAAW,KAAK,GAEpC,YAAY;GAGd,IAAI,CAAC,KAAK,YAAY,CAAC,KAAK,YAAY,CAAC,KAAK,SAAS,CAAC,KAAK,UAC3D;EACJ;EAEA,MAAM,OAAO,eAAe,KAAA,IAAY,MAAM;EAC9C,IAAI;EAGJ,IAAI,gBAAgB,KAAK,OAAO;GAC9B,MAAM,aAAa;IACjB,MAAM,KAAK;IACX;IACA;IACA;IACA;IACA;IACA;IACA;GACF;GACA,IAAI,aAAa;GACjB,IAAI,KAAK,MAAM;QAET,CADW,oBAAoB,MAAM,OAAO,UAC3C,GAAQ,aAAa;GAAA;GAE5B,IAAI,YAAY;IAGd,IACE,CAAC,YACD,CAAC,aACD,CAAC,WACD,qBAAqB,SAAS,WAAW,GAEzC,OAAO;IAET,IAAI,oBAAoB,WAAW,UAAU,GAE3C,YAAY;GAEhB;EACF;EAGA,IAAI,KAAK,UACP,KAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;GAClD,MAAM,UAAU,KAAK,SAAS;GAC9B,MAAM,EAAE,QAAQ,WAAW;GAC3B,IAAI,QAAQ;IACV,IAAI,cAAc;IAIlB,IAAI,EAHa,QAAQ,gBACrB,OACC,cAAc,KAAM,YAAY,GACtB,WAAW,MAAM,GAAG;GACrC;GACA,IAAI,QAAQ;IACV,IAAI,cAAc;IAClB,MAAM,MAAM,MAAM,MAAM,KAAK,EAAE,KAAK,GAAG,EAAE,MAAM,CAAC,OAAO,MAAM;IAE7D,KADiB,QAAQ,gBAAgB,MAAM,IAAI,YAAY,OAC9C,QAAQ;GAC3B;GAEA,MAAM,KAAK;IACT,MAAM;IACN,OAAO;IACP;IACA;IACA;IACA;IACA;IACA;GACF,CAAC;EACH;EAIF,IAAI,KAAK,UAAU;GAEjB,MAAM,cAAc,UAAW,KAAM,KAAK,QAAQ;GAClD,KAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;IAClD,MAAM,UAAU,KAAK,SAAS;IAE9B,MAAM,KAAK;KACT,MAAM;KACN;KACA,SAAS;KACT;KACA;KACA;KACA;KACA;IACF,CAAC;GACH;GACA,IAAI,CAAC,cACH,KAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;IAClD,MAAM,UAAU,KAAK,SAAS;IAC9B,MAAM,EAAE,QAAQ,WAAW;IAC3B,IAAI,UAAU,QAAQ;KACpB,MAAM,WAAW,QAAQ,gBACrB,OACC,cAAc,KAAM,YAAY;KACrC,IAAI,UAAU,CAAC,SAAS,WAAW,MAAM,GAAG;KAC5C,IAAI,UAAU,CAAC,SAAS,SAAS,MAAM,GAAG;IAC5C;IACA,MAAM,KAAK;KACT,MAAM;KACN,OAAO,QAAQ;KACf;KACA;KACA;KACA,WAAW,YAAY,aAAa,aAAa,KAAK;KACtD;KACA;IACF,CAAC;GACH;EAEJ;EAGA,IAAI,CAAC,gBAAgB,KAAK,WAAW,MACnC,KAAK,IAAI,IAAI,KAAK,QAAQ,SAAS,GAAG,KAAK,GAAG,KAAK;GACjD,MAAM,UAAU,KAAK,QAAQ;GAC7B,MAAM,EAAE,QAAQ,WAAW;GAC3B,IAAI,UAAU,QAAQ;IACpB,MAAM,WAAW,QAAQ,gBACrB,OACC,cAAc,KAAK,YAAY;IACpC,IAAI,UAAU,CAAC,SAAS,WAAW,MAAM,GAAG;IAC5C,IAAI,UAAU,CAAC,SAAS,SAAS,MAAM,GAAG;GAC5C;GACA,MAAM,KAAK;IACT,MAAM;IACN,OAAO,QAAQ;IACf;IACA;IACA,UAAU,WAAW,aAAa,aAAa,KAAK;IACpD;IACA;IACA;GACF,CAAC;EACH;EAIF,IAAI,CAAC,gBAAgB,KAAK,mBAAmB;GAC3C,MAAM,QAAQ,KAAK,kBAAkB,IAClC,cAAc,KAAM,YAAY,CACnC;GACA,IAAI,OACF,MAAM,KAAK;IACT,MAAM;IACN,OAAO,QAAQ;IACf;IACA,SAAS,UAAU,aAAa,aAAa,KAAK;IAClD;IACA;IACA;IACA;GACF,CAAC;EAEL;EAGA,IAAI,CAAC,gBAAgB,KAAK,QAAQ;GAChC,MAAM,QAAQ,KAAK,OAAO,IAAI,IAAK;GACnC,IAAI,OACF,MAAM,KAAK;IACT,MAAM;IACN,OAAO,QAAQ;IACf;IACA,SAAS,UAAU,aAAa,aAAa,KAAK;IAClD;IACA;IACA;IACA;GACF,CAAC;EAEL;EAGA,IAAI,KAAK,UACP,KAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;GAClD,MAAM,UAAU,KAAK,SAAS;GAC9B,MAAM,KAAK;IACT,MAAM;IACN;IACA;IACA;IACA;IACA;IACA;IACA;GACF,CAAC;EACH;CAEJ;CAEA,IAAI,WAAW,OAAO;CAEtB,IAAI,SAAS,WAAW;EACtB,IAAI,aAAa,UAAU;EAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,OAAO,KACnC,cAAc,MAAM,GAAI;EAE1B,MAAM,QAAQ,eAAe,KAAK,SAAS,MAAM,KAAK,MAAM,UAAU;EACtE,UAAU,cAAc,OAAO,OAAO,IAAI;EAC1C,UAAU,UAAW,QAAQ,mBAAmB,KAAK;EACrD,OAAO;CACT;CAEA,OAAO;AACT;AAEA,SAAS,aAAa,aAAqB,OAAuB;CAMhE,OAAO,MAAM,cAAc,QAAQ;AACrC;AAEA,SAAS,qBAAqB,SAAiB,aAA8B;CAC3E,OAAO,YAAY,MAAM,cAAc,KAAK;AAC9C;AAEA,SAAS,oBACP,MACA,OACA,OACA;CACA,IAAI;CACJ,IAAI;CAEJ,IAAI;EACD,CAAC,WAAW,SAAS,cAAc,MAAM,OAAO,KAAK;CACxD,QAAQ;EACN,OAAO;CACT;CAEA,MAAM,YAAY;CAClB,MAAM,UAAU;CAEhB,IAAI,CAAC,MAAM,KAAK,OAAO,OAAO;CAE9B,IAAI;EACF,IAAI,MAAM,KAAK,MAAM,SAAS,MAAM,OAAO,OAAO;CACpD,QAAQ,CAGR;CAEA,OAAO;AACT;AAEA,SAAS,oBAEP,MAEA,MACS;CACT,IAAI,CAAC,MAAM,OAAO;CAClB,OACE,KAAK,UAAU,KAAK,WACnB,KAAK,YAAY,KAAK,YACpB,KAAK,WAAW,KAAK,YACnB,KAAK,aAAa,KAAK,aACrB,KAAK,YAAY,KAAK,aACpB,KAAK,cAAc,KAAK,eACrB,KAAK,KAAK,SAAS,uBAClB,KAAK,KAAK,SAAS,uBAClB,KAAK,KAAK,SAAS,wBAClB,KAAK,KAAK,SAAS,uBACpB,KAAK,KAAK,QAAQ,KAAK,KAAK;AAE9C"}
{"version":3,"file":"new-process-route-tree.cjs","names":[],"sources":["../../src/new-process-route-tree.ts"],"sourcesContent":["import { invariant } from './invariant'\nimport { createLRUCache } from './lru-cache'\nimport { last } from './utils'\nimport type { LRUCache } from './lru-cache'\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\ntype ParsedSegment = Uint16Array & {\n /** segment type (0 = pathname, 1 = param, 2 = wildcard, 3 = optional param) */\n 0: SegmentKind\n /** index of the end of the prefix */\n 1: number\n /** index of the start of the value */\n 2: number\n /** index of the end of the value */\n 3: number\n /** index of the start of the suffix */\n 4: number\n /** index of the end of the segment */\n 5: number\n}\n\n/**\n * Populates the `output` array with the parsed representation of the given `segment` string.\n *\n * Usage:\n * ```ts\n * let output\n * let cursor = 0\n * while (cursor < path.length) {\n * output = parseSegment(path, cursor, output)\n * const end = output[5]\n * cursor = end + 1\n * ```\n *\n * `output` is stored outside to avoid allocations during repeated calls. It doesn't need to be typed\n * or initialized, it will be done automatically.\n */\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 /** A Uint16Array (length: 6) to populate with the parsed segment data. */\n output: Uint16Array = new Uint16Array(6),\n): ParsedSegment {\n const next = path.indexOf('/', start)\n const end = next === -1 ? path.length : next\n const part = path.substring(start, end)\n\n if (!part || !part.includes('$')) {\n // early escape for static pathname\n output[0] = SEGMENT_TYPE_PATHNAME\n output[1] = start\n output[2] = start\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n }\n\n // $ (wildcard)\n if (part === '$') {\n const total = path.length\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start\n output[2] = start\n output[3] = total\n output[4] = total\n output[5] = total\n return output as ParsedSegment\n }\n\n // $paramName\n if (part.charCodeAt(0) === 36) {\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start\n output[2] = start + 1 // skip '$'\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n }\n\n const openBrace = part.indexOf('{')\n let closeBrace\n if (\n openBrace !== -1 &&\n openBrace + 1 < part.length &&\n (closeBrace = part.indexOf('}', openBrace)) !== -1\n ) {\n const firstChar = part.charCodeAt(openBrace + 1)\n\n // Check for {-$...} (optional param)\n // prefix{-$paramName}suffix\n // /^([^{]*)\\{-\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/\n if (firstChar === 45) {\n // '-'\n if (\n openBrace + 2 < part.length &&\n part.charCodeAt(openBrace + 2) === 36 // '$'\n ) {\n const paramStart = openBrace + 3\n const paramEnd = closeBrace\n // Validate param name exists\n if (paramStart < paramEnd) {\n output[0] = SEGMENT_TYPE_OPTIONAL_PARAM\n output[1] = start + openBrace\n output[2] = start + paramStart\n output[3] = start + paramEnd\n output[4] = start + closeBrace + 1\n output[5] = end\n return output as ParsedSegment\n }\n }\n } else if (firstChar === 36) {\n // '$'\n const dollarPos = openBrace + 1\n const afterDollar = openBrace + 2\n // Check for {$} (wildcard)\n if (afterDollar === closeBrace) {\n // For wildcard, value should be '$' (from dollarPos to afterDollar)\n // prefix{$}suffix\n // /^([^{]*)\\{\\$\\}([^}]*)$/\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start + openBrace\n output[2] = start + dollarPos\n output[3] = start + afterDollar\n output[4] = start + closeBrace + 1\n output[5] = path.length\n return output as ParsedSegment\n }\n // Regular param {$paramName} - value is the param name (after $)\n // prefix{$paramName}suffix\n // /^([^{]*)\\{\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start + openBrace\n output[2] = start + afterDollar\n output[3] = start + closeBrace\n output[4] = start + closeBrace + 1\n output[5] = end\n return output as ParsedSegment\n }\n }\n\n // fallback to static pathname (should never happen)\n output[0] = SEGMENT_TYPE_PATHNAME\n output[1] = start\n output[2] = start\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n}\n\n/**\n * Recursively parses the segments of the given route tree and populates a segment trie.\n *\n * @param data A reusable Uint16Array for parsing segments. (non important, we're just avoiding allocations)\n * @param route The current route to parse.\n * @param start The starting index for parsing within the route's full path.\n * @param node The current segment node in the trie to populate.\n * @param onRoute Callback invoked for each route processed.\n */\nfunction parseSegments<TRouteLike extends RouteLike>(\n defaultCaseSensitive: boolean,\n data: Uint16Array,\n route: TRouteLike,\n start: number,\n node: AnySegmentNode<TRouteLike>,\n depth: number,\n /** Each dynamic sibling list is recorded once, when it first needs sorting. */\n dynamicListsToSort?: Array<Array<DynamicSegmentNode<TRouteLike>>>,\n onRoute?: (route: TRouteLike) => void,\n) {\n onRoute?.(route)\n let cursor = start\n {\n const path = route.fullPath ?? route.from\n const options = route.options\n const length = path.length\n const caseSensitive = options?.caseSensitive ?? defaultCaseSensitive\n const parseParams = options?.params?.parse ?? options?.parseParams\n while (cursor < length) {\n const segment = parseSegment(path, cursor, data)\n let nextNode: AnySegmentNode<TRouteLike>\n const start = cursor\n const end = segment[5]\n cursor = end + 1\n depth++\n const kind = segment[0]\n switch (kind) {\n case SEGMENT_TYPE_PATHNAME: {\n const value = path.substring(segment[2], segment[3])\n let name = value\n let staticChildren: Map<string, StaticSegmentNode<TRouteLike>>\n if (caseSensitive) {\n staticChildren = node.static ??= new Map()\n } else {\n name = value.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 = createStaticNode<TRouteLike>(path)\n next.parent = node\n next.depth = depth\n nextNode = next\n staticChildren.set(name, next)\n }\n break\n }\n case SEGMENT_TYPE_PARAM:\n case SEGMENT_TYPE_OPTIONAL_PARAM:\n case SEGMENT_TYPE_WILDCARD: {\n const prefix_raw = path.substring(start, segment[1])\n const suffix_raw = path.substring(segment[4], end)\n const actuallyCaseSensitive =\n caseSensitive && !!(prefix_raw || suffix_raw)\n const prefix = !prefix_raw\n ? undefined\n : actuallyCaseSensitive\n ? prefix_raw\n : prefix_raw.toLowerCase()\n const suffix = !suffix_raw\n ? undefined\n : actuallyCaseSensitive\n ? suffix_raw\n : suffix_raw.toLowerCase()\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 = createDynamicNode<TRouteLike>(\n kind,\n path,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.parent = node\n next.depth = depth\n let nodes: Array<DynamicSegmentNode<TRouteLike>>\n if (kind === SEGMENT_TYPE_PARAM) {\n nodes = node.dynamic ??= []\n } else if (kind === SEGMENT_TYPE_OPTIONAL_PARAM) {\n nodes = node.optional ??= []\n } else {\n nodes = node.wildcard ??= []\n }\n nodes.push(next)\n if (nodes.length === 2) {\n dynamicListsToSort?.push(nodes)\n }\n }\n break\n }\n }\n node = nextNode\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 = createStaticNode<TRouteLike>(path)\n pathlessNode.kind = SEGMENT_TYPE_PATHLESS\n pathlessNode.parent = node\n depth++\n pathlessNode.depth = depth\n node.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 && path.endsWith('/')) {\n const indexNode = createStaticNode<TRouteLike>(path)\n indexNode.kind = SEGMENT_TYPE_INDEX\n indexNode.parent = node\n depth++\n indexNode.depth = depth\n node.index = indexNode\n node = indexNode\n }\n\n node.parse = parseParams ?? null\n node.priority = options?.params?.priority ?? 0\n\n // make node \"matchable\"\n if (isLeaf && !node.route) {\n node.route = route\n node.fullPath = path\n }\n }\n if (route.children)\n for (const child of route.children) {\n parseSegments(\n defaultCaseSensitive,\n data,\n child as TRouteLike,\n cursor,\n node,\n depth,\n dynamicListsToSort,\n onRoute,\n )\n }\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 createStaticNode<T extends RouteLike>(\n fullPath: string,\n): StaticSegmentNode<T> {\n return {\n kind: SEGMENT_TYPE_PATHNAME,\n depth: 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 fullPath,\n parent: null,\n parse: null,\n priority: 0,\n }\n}\n\n/**\n * Keys must be declared in the same order as in `SegmentNode` type,\n * to ensure they are represented as the same object class in the engine.\n */\nfunction createDynamicNode<T extends RouteLike>(\n kind:\n | typeof SEGMENT_TYPE_PARAM\n | typeof SEGMENT_TYPE_WILDCARD\n | typeof SEGMENT_TYPE_OPTIONAL_PARAM,\n fullPath: string,\n caseSensitive: boolean,\n prefix?: string,\n suffix?: string,\n): DynamicSegmentNode<T> {\n return {\n kind,\n depth: 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 fullPath,\n parent: null,\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\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 /** The full path for this segment node (will only be valid on leaf nodes) */\n fullPath: string\n\n parent: AnySegmentNode<T> | null\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 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: LRUCache<string, AnySegmentNode<TSingle>>\n /** a cache of route matches from the `segmentTree` */\n matchCache: LRUCache<string, RouteMatch<TTree> | null>\n /** a cache of route matches from the `masksTree` */\n flatCache: LRUCache<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 = createStaticNode<TRouteLike>('/')\n const data = new Uint16Array(6)\n const dynamicListsToSort: Array<Array<DynamicSegmentNode<TRouteLike>>> = []\n for (const route of routeList) {\n parseSegments(false, data, route, 1, segmentTree, 0, dynamicListsToSort)\n }\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n processedTree.masksTree = segmentTree\n processedTree.flatCache = createLRUCache<\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) 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 = createStaticNode<{ from: string }>('/')\n const data = new Uint16Array(6)\n parseSegments(caseSensitive, data, { from }, 1, tree, 0)\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\n/** Trim trailing slashes (except preserving root '/'). */\nexport function trimPathRight(path: string) {\n return path === '/' ? path : path.replace(/\\/{1,}$/, '')\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 }> & { id: string },\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 /** Optional callback invoked for each route during processing. */\n initRoute?: (route: TRouteLike, index: number) => void,\n): ProcessRouteTreeResult<TRouteLike> {\n const segmentTree = createStaticNode<TRouteLike>(routeTree.fullPath)\n const data = new Uint16Array(6)\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 parseSegments(\n caseSensitive,\n data,\n routeTree,\n 1,\n segmentTree,\n 0,\n dynamicListsToSort,\n (route) => {\n initRoute?.(route, 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\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\n index++\n },\n )\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n const processedTree: ProcessedTree<TRouteLike, any, any> = {\n segmentTree,\n singleCache: createLRUCache<string, AnySegmentNode<any>>(1000),\n matchCache: createLRUCache<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 segment: 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 let nodeParts: Array<string> | null = null\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 /** which fullPath segment we're currently processing */\n let segmentCount = leaf.extract?.segment ?? 0\n for (\n ;\n nodeIndex < list.length;\n partIndex++, nodeIndex++, pathIndex++, segmentCount++\n ) {\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 segmentCount--\n partIndex--\n pathIndex--\n continue\n }\n const part = parts[partIndex]\n const currentPathIndex = pathIndex\n if (part) pathIndex += part.length\n if (node.kind === SEGMENT_TYPE_PARAM) {\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[segmentCount]!\n const preLength = node.prefix?.length ?? 0\n // we can't rely on the presence of prefix/suffix to know whether it's curly-braced or not, because `/{$param}/` is valid, but has no prefix/suffix\n const isCurlyBraced = nodePart.charCodeAt(preLength) === 123 // '{'\n // param name is extracted at match-time so that tree nodes that are identical except for param name can share the same node\n if (isCurlyBraced) {\n const sufLength = node.suffix?.length ?? 0\n const name = nodePart.substring(\n preLength + 2,\n nodePart.length - sufLength - 1,\n )\n const value = part!.substring(preLength, part!.length - sufLength)\n rawParams[name] = decodeURIComponent(value)\n } else {\n const name = nodePart.substring(1)\n rawParams[name] = decodeURIComponent(part!)\n }\n } else if (node.kind === SEGMENT_TYPE_OPTIONAL_PARAM) {\n if (leaf.skipped & (1 << nodeIndex)) {\n partIndex-- // stay on the same part\n pathIndex = currentPathIndex - 1 // undo pathIndex advancement; -1 to account for loop increment\n continue\n }\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[segmentCount]!\n const preLength = node.prefix?.length ?? 0\n const sufLength = node.suffix?.length ?? 0\n const name = nodePart.substring(\n preLength + 3,\n nodePart.length - sufLength - 1,\n )\n const value =\n node.suffix || node.prefix\n ? part!.substring(preLength, part!.length - sufLength)\n : part\n if (value) rawParams[name] = decodeURIComponent(value)\n } else if (node.kind === SEGMENT_TYPE_WILDCARD) {\n const n = node\n const value = path.substring(\n currentPathIndex + (n.prefix?.length ?? 0),\n path.length - (n.suffix?.length ?? 0),\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 segment: segmentCount,\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('/').slice(-suffix.length)\n const casePart = segment.caseSensitive ? end : end.toLowerCase()\n if (casePart !== suffix) continue\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 (suffix && !casePart.endsWith(suffix)) continue\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 (suffix && !casePart.endsWith(suffix)) continue\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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"}

@@ -348,30 +348,21 @@ const require_utils = require("./utils.cjs");

};
const buildWithMatches = (dest = {}, maskedDest) => {
const next = build(dest);
let maskedNext = maskedDest ? build(maskedDest) : void 0;
if (!maskedNext) {
const params = Object.create(null);
if (this.options.routeMasks) {
const match = require_new_process_route_tree.findFlatMatch(next.pathname, this.processedTree);
if (match) {
Object.assign(params, match.rawParams);
const { from: _from, params: maskParams, ...maskProps } = match.route;
const nextParams = resolveNextParams(maskParams, params);
maskedDest = {
from: opts.from,
...maskProps,
params: nextParams
};
maskedNext = build(maskedDest);
}
}
}
if (maskedNext) next.maskedLocation = maskedNext;
return next;
};
if (opts.mask) return buildWithMatches(opts, {
const next = build(opts);
if (opts.mask) next.maskedLocation = build({
from: opts.from,
...opts.mask
});
return buildWithMatches(opts);
else if (this.options.routeMasks) {
const match = require_new_process_route_tree.findFlatMatch(next.pathname, this.processedTree);
if (match) {
const params = Object.assign(Object.create(null), match.rawParams);
const { from: _from, params: maskParams, ...maskProps } = match.route;
const nextParams = resolveNextParams(maskParams, params);
next.maskedLocation = build({
from: opts.from,
...maskProps,
params: nextParams
});
}
}
return next;
};

@@ -378,0 +369,0 @@ this.commitLocation = async ({ viewTransition, ignoreBlocker, ...next }) => {

@@ -10,5 +10,2 @@ let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer");

}
function isFunction(d) {
return typeof d === "function";
}
/**

@@ -19,3 +16,3 @@ * Apply a value-or-updater to a previous value.

function functionalUpdate(updater, previous) {
if (isFunction(updater)) return updater(previous);
if (typeof updater === "function") return updater(previous);
return updater;

@@ -22,0 +19,0 @@ }

@@ -1,1 +0,1 @@

{"version":3,"file":"utils.cjs","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["import { isServer } from '@tanstack/router-core/isServer'\nimport type { RouteIds } from './routeInfo'\nimport type { AnyRouter } from './router'\n\nexport type Awaitable<T> = T | Promise<T>\nexport type NoInfer<T> = [T][T extends any ? 0 : never]\nexport type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue\n ? TYesResult\n : TNoResult\n\nexport type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<\n TValue,\n TKey\n> &\n Required<Pick<TValue, TKey>>\n\nexport type PickRequired<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K]\n}\n\nexport type PickOptional<T> = {\n [K in keyof T as undefined extends T[K] ? K : never]: T[K]\n}\n\n// from https://stackoverflow.com/a/76458160\nexport type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never\n\nexport type Expand<T> = T extends object\n ? T extends infer O\n ? O extends Function\n ? O\n : { [K in keyof O]: O[K] }\n : never\n : T\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nexport type MakeDifferenceOptional<TLeft, TRight> = keyof TLeft &\n keyof TRight extends never\n ? TRight\n : Omit<TRight, keyof TLeft & keyof TRight> & {\n [K in keyof TLeft & keyof TRight]?: TRight[K]\n }\n\n// from https://stackoverflow.com/a/53955431\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type IsUnion<T, U extends T = T> = (\n T extends any ? (U extends T ? false : true) : never\n) extends false\n ? false\n : true\n\nexport type IsNonEmptyObject<T> = T extends object\n ? keyof T extends never\n ? false\n : true\n : false\n\nexport type Assign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : keyof TLeft & keyof TRight extends never\n ? TLeft & TRight\n : Omit<TLeft, keyof TRight> & TRight\n : never\n : never\n\nexport type IntersectAssign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : TRight & TLeft\n : never\n : never\n\nexport type Timeout = ReturnType<typeof setTimeout>\n\nexport type Updater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev?: TPrevious) => TResult)\n\nexport type NonNullableUpdater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev: TPrevious) => TResult)\n\nexport type ExtractObjects<TUnion> = TUnion extends MergeAllPrimitive\n ? never\n : TUnion\n\nexport type PartialMergeAllObject<TUnion> =\n ExtractObjects<TUnion> extends infer TObj\n ? [TObj] extends [never]\n ? never\n : {\n [TKey in TObj extends any ? keyof TObj : never]?: TObj extends any\n ? TKey extends keyof TObj\n ? TObj[TKey]\n : never\n : never\n }\n : never\n\nexport type MergeAllPrimitive =\n | ReadonlyArray<any>\n | number\n | string\n | bigint\n | boolean\n | symbol\n | undefined\n | null\n\nexport type ExtractPrimitives<TUnion> = TUnion extends MergeAllPrimitive\n ? TUnion\n : TUnion extends object\n ? never\n : TUnion\n\nexport type PartialMergeAll<TUnion> =\n | ExtractPrimitives<TUnion>\n | PartialMergeAllObject<TUnion>\n\nexport type Constrain<T, TConstraint, TDefault = TConstraint> =\n | (T extends TConstraint ? T : never)\n | TDefault\n\nexport type ConstrainLiteral<T, TConstraint, TDefault = TConstraint> =\n | (T & TConstraint)\n | TDefault\n\n/**\n * To be added to router types\n */\nexport type UnionToIntersection<T> = (\n T extends any ? (arg: T) => any : never\n) extends (arg: infer T) => any\n ? T\n : never\n\n/**\n * Merges everything in a union into one object.\n * This mapped type is homomorphic which means it preserves stuff! :)\n */\nexport type MergeAllObjects<\n TUnion,\n TIntersected = UnionToIntersection<ExtractObjects<TUnion>>,\n> = [keyof TIntersected] extends [never]\n ? never\n : {\n [TKey in keyof TIntersected]: TUnion extends any\n ? TUnion[TKey & keyof TUnion]\n : never\n }\n\nexport type MergeAll<TUnion> =\n | MergeAllObjects<TUnion>\n | ExtractPrimitives<TUnion>\n\nexport type ValidateJSON<T> = ((...args: Array<any>) => any) extends T\n ? unknown extends T\n ? never\n : 'Function is not serializable'\n : { [K in keyof T]: ValidateJSON<T[K]> }\n\nexport type LooseReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn\n : never\n\nexport type LooseAsyncReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn extends Promise<infer TReturn>\n ? TReturn\n : TReturn\n : never\n\n/**\n * Return the last element of an array.\n * Intended for non-empty arrays used within router internals.\n */\nexport function last<T>(arr: ReadonlyArray<T>) {\n return arr[arr.length - 1]\n}\n\nfunction isFunction(d: any): d is Function {\n return typeof d === 'function'\n}\n\n/**\n * Apply a value-or-updater to a previous value.\n * Accepts either a literal value or a function of the previous value.\n */\nexport function functionalUpdate<TPrevious, TResult = TPrevious>(\n updater: Updater<TPrevious, TResult> | NonNullableUpdater<TPrevious, TResult>,\n previous: TPrevious,\n): TResult {\n if (isFunction(updater)) {\n return updater(previous)\n }\n\n return updater\n}\n\nexport const hasOwn = Object.prototype.hasOwnProperty\nconst isEnumerable = Object.prototype.propertyIsEnumerable\n\nexport function hasKeys(obj: Record<string, unknown>) {\n for (const key in obj) {\n if (hasOwn.call(obj, key)) return true\n }\n return false\n}\n\nexport const createNull = () => Object.create(null)\nexport const nullReplaceEqualDeep: typeof replaceEqualDeep = (prev, next) =>\n replaceEqualDeep(prev, next, createNull)\n\n/**\n * This function returns `prev` if `_next` is deeply equal.\n * If not, it will replace any deeply equal children of `b` with those of `a`.\n * This can be used for structural sharing between immutable JSON values for example.\n * Do not use this with signals\n */\nexport function replaceEqualDeep<T>(\n prev: any,\n _next: T,\n _makeObj = () => ({}),\n _depth = 0,\n): T {\n if (isServer) {\n return _next\n }\n if (prev === _next) {\n return prev\n }\n\n if (_depth > 500) return _next\n\n const next = _next as any\n\n const array = isPlainArray(prev) && isPlainArray(next)\n\n if (!array && !(isPlainObject(prev) && isPlainObject(next))) return next\n\n const prevItems = array ? prev : getEnumerableOwnKeys(prev)\n if (!prevItems) return next\n const nextItems = array ? next : getEnumerableOwnKeys(next)\n if (!nextItems) return next\n const prevSize = prevItems.length\n const nextSize = nextItems.length\n const copy: any = array ? new Array(nextSize) : _makeObj()\n\n let equalItems = 0\n\n for (let i = 0; i < nextSize; i++) {\n const key = array ? i : (nextItems[i] as any)\n const p = prev[key]\n const n = next[key]\n\n if (p === n) {\n copy[key] = p\n if (array ? i < prevSize : hasOwn.call(prev, key)) equalItems++\n continue\n }\n\n if (\n p === null ||\n n === null ||\n typeof p !== 'object' ||\n typeof n !== 'object'\n ) {\n copy[key] = n\n continue\n }\n\n const v = replaceEqualDeep(p, n, _makeObj, _depth + 1)\n copy[key] = v\n if (v === p) equalItems++\n }\n\n return prevSize === nextSize && equalItems === prevSize ? prev : copy\n}\n\n/**\n * Equivalent to `Reflect.ownKeys`, but ensures that objects are \"clone-friendly\":\n * will return false if object has any non-enumerable properties.\n *\n * Optimized for the common case where objects have no symbol properties.\n */\nfunction getEnumerableOwnKeys(o: object) {\n // `Object.keys` returns only enumerable own string keys natively (no per-key\n // JS callback). If it has fewer entries than `getOwnPropertyNames` (all own\n // string keys), the object has a non-enumerable own string prop and is not\n // \"clone-friendly\" -> bail. This replaces an O(n) loop of\n // `propertyIsEnumerable` calls with two native calls.\n const keys = Object.keys(o)\n if (keys.length !== Object.getOwnPropertyNames(o).length) {\n return false\n }\n\n // Only check symbols if the object has any (most plain objects don't)\n const symbols = Object.getOwnPropertySymbols(o)\n\n // Fast path: no symbols, return enumerable string keys directly\n if (symbols.length === 0) {\n return keys\n }\n\n // Slow path: has symbols, include only enumerable ones, bail on any\n // non-enumerable symbol so it round-trips like the string-key check above.\n for (const symbol of symbols) {\n if (!isEnumerable.call(o, symbol)) {\n return false\n }\n ;(keys as Array<string | symbol>).push(symbol)\n }\n return keys\n}\n\n// Copied from: https://github.com/jonschlinkert/is-plain-object\nexport function isPlainObject(o: any) {\n if (!hasObjectPrototype(o)) {\n return false\n }\n\n // If has modified constructor\n const ctor = o.constructor\n if (typeof ctor === 'undefined') {\n return true\n }\n\n // If has modified prototype\n const prot = ctor.prototype\n if (!hasObjectPrototype(prot)) {\n return false\n }\n\n // If constructor does not have an Object-specific method\n if (!prot.hasOwnProperty('isPrototypeOf')) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n\nfunction hasObjectPrototype(o: any) {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\n/**\n * Check if a value is a \"plain\" array (no extra enumerable keys).\n */\nexport function isPlainArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value) && value.length === Object.keys(value).length\n}\n\n/**\n * Perform a deep equality check with options for partial comparison and\n * ignoring `undefined` values. Optimized for router state comparisons.\n */\nexport function deepEqual(\n a: any,\n b: any,\n opts?: { partial?: boolean; ignoreUndefined?: boolean },\n): boolean {\n if (a === b) {\n return true\n }\n\n if (typeof a !== typeof b) {\n return false\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0, l = a.length; i < l; i++) {\n if (!deepEqual(a[i], b[i], opts)) return false\n }\n return true\n }\n\n if (isPlainObject(a) && isPlainObject(b)) {\n const ignoreUndefined = opts?.ignoreUndefined ?? true\n\n if (opts?.partial) {\n for (const k in b) {\n if (!ignoreUndefined || b[k] !== undefined) {\n if (!deepEqual(a[k], b[k], opts)) return false\n }\n }\n return true\n }\n\n let aCount = 0\n if (!ignoreUndefined) {\n aCount = Object.keys(a).length\n } else {\n for (const k in a) {\n if (a[k] !== undefined) aCount++\n }\n }\n\n let bCount = 0\n for (const k in b) {\n if (!ignoreUndefined || b[k] !== undefined) {\n bCount++\n if (bCount > aCount || !deepEqual(a[k], b[k], opts)) return false\n }\n }\n\n return aCount === bCount\n }\n\n return false\n}\n\nexport type StringLiteral<T> = T extends string\n ? string extends T\n ? string\n : T\n : never\n\nexport type ThrowOrOptional<T, TThrow extends boolean> = TThrow extends true\n ? T\n : T | undefined\n\nexport type StrictOrFrom<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean = true,\n> = TStrict extends false\n ? {\n from?: never\n strict: TStrict\n }\n : {\n from: ConstrainLiteral<TFrom, RouteIds<TRouter['routeTree']>>\n strict?: TStrict\n }\n\nexport type ThrowConstraint<\n TStrict extends boolean,\n TThrow extends boolean,\n> = TStrict extends false ? (TThrow extends true ? never : TThrow) : TThrow\n\nexport type ControlledPromise<T> = Promise<T> & {\n resolve: (value: T) => void\n reject: (value: any) => void\n status: 'pending' | 'resolved' | 'rejected'\n value?: T\n}\n\n/**\n * Create a promise with exposed resolve/reject and status fields.\n * Useful for coordinating async router lifecycle operations.\n */\nexport function createControlledPromise<T>(onResolve?: (value: T) => void) {\n let resolveLoadPromise!: (value: T) => void\n let rejectLoadPromise!: (value: any) => void\n\n const controlledPromise = new Promise<T>((resolve, reject) => {\n resolveLoadPromise = resolve\n rejectLoadPromise = reject\n }) as ControlledPromise<T>\n\n controlledPromise.status = 'pending'\n\n controlledPromise.resolve = (value: T) => {\n controlledPromise.status = 'resolved'\n controlledPromise.value = value\n resolveLoadPromise(value)\n onResolve?.(value)\n }\n\n controlledPromise.reject = (e) => {\n controlledPromise.status = 'rejected'\n rejectLoadPromise(e)\n }\n\n return controlledPromise\n}\n\n/**\n * Heuristically detect dynamic import \"module not found\" errors\n * across major browsers for lazy route component handling.\n */\nexport function isModuleNotFoundError(error: any): boolean {\n // chrome: \"Failed to fetch dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split\"\n // firefox: \"error loading dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split\"\n // safari: \"Importing a module script failed.\"\n if (typeof error?.message !== 'string') return false\n return (\n error.message.startsWith('Failed to fetch dynamically imported module') ||\n error.message.startsWith('error loading dynamically imported module') ||\n error.message.startsWith('Importing a module script failed')\n )\n}\n\nexport function isPromise<T>(\n value: Promise<Awaited<T>> | T,\n): value is Promise<Awaited<T>> {\n return Boolean(\n value &&\n typeof value === 'object' &&\n typeof (value as Promise<T>).then === 'function',\n )\n}\n\nexport function findLast<T>(\n array: ReadonlyArray<T>,\n predicate: (item: T) => boolean,\n): T | undefined {\n for (let i = array.length - 1; i >= 0; i--) {\n const item = array[i]!\n if (predicate(item)) return item\n }\n return undefined\n}\n\n/**\n * Re-encode characters that are unsafe in URL paths.\n * Includes ASCII control characters (0x00-0x1F, 0x7F) and a subset of the\n * WHATWG URL \"path percent-encode set\" (\", <, >, `, {, }).\n *\n * Space (0x20) is intentionally excluded — decodeURI decodes %20 to space\n * and the router stores decoded spaces in location.pathname. The existing\n * encodePathLikeUrl already handles re-encoding spaces for outgoing URLs.\n *\n * These characters are decoded by decodeURI but must remain percent-encoded\n * in paths to match how upstream layers (CDNs, edge middleware, browsers)\n * interpret the URL, preventing infinite redirect loops and path mismatches.\n */\n// eslint-disable-next-line no-control-regex\nconst PATH_UNSAFE_RE = /[\\x00-\\x1f\\x7f\"<>`{}]/g\n\nfunction sanitizePathSegment(segment: string): string {\n return segment.replace(\n PATH_UNSAFE_RE,\n (ch) => '%' + ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'),\n )\n}\n\nfunction decodeSegment(segment: string): string {\n let decoded: string\n try {\n decoded = decodeURI(segment)\n } catch {\n // if the decoding fails, try to decode the various parts leaving the malformed tags in place\n decoded = segment.replaceAll(/%[0-9A-F]{2}/gi, (match) => {\n try {\n return decodeURI(match)\n } catch {\n return match\n }\n })\n }\n return sanitizePathSegment(decoded)\n}\n\n/**\n * Default list of URL protocols to allow in links, redirects, and navigation.\n * Any absolute URL protocol not in this list is treated as dangerous by default.\n */\nexport const DEFAULT_PROTOCOL_ALLOWLIST = [\n // Standard web navigation\n 'http:',\n 'https:',\n\n // Common browser-safe actions\n 'mailto:',\n 'tel:',\n]\n\n/**\n * Check if a URL string uses a protocol that is not in the allowlist.\n * Returns true for blocked protocols like javascript:, blob:, data:, etc.\n *\n * The URL constructor correctly normalizes:\n * - Mixed case (JavaScript: → javascript:)\n * - Whitespace/control characters (java\\nscript: → javascript:)\n * - Leading whitespace\n *\n * For relative URLs (no protocol), returns false (safe).\n *\n * @param url - The URL string to check\n * @param allowlist - Set of protocols to allow\n * @returns true if the URL uses a protocol that is not allowed\n */\nexport function isDangerousProtocol(\n url: string,\n allowlist: Set<string>,\n): boolean {\n if (!url) return false\n\n try {\n // Use the URL constructor - it correctly normalizes protocols\n // per WHATWG URL spec, handling all bypass attempts automatically\n const parsed = new URL(url)\n return !allowlist.has(parsed.protocol)\n } catch {\n // URL constructor throws for relative URLs (no protocol)\n // These are safe - they can't execute scripts\n return false\n }\n}\n\n// This utility is based on https://github.com/zertosh/htmlescape\n// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE\nconst HTML_ESCAPE_LOOKUP: { [match: string]: string } = {\n '&': '\\\\u0026',\n '>': '\\\\u003e',\n '<': '\\\\u003c',\n '\\u2028': '\\\\u2028',\n '\\u2029': '\\\\u2029',\n}\n\nconst HTML_ESCAPE_REGEX = /[&><\\u2028\\u2029]/g\n\n/**\n * Escape HTML special characters in a string to prevent XSS attacks\n * when embedding strings in script tags during SSR.\n *\n * This is essential for preventing XSS vulnerabilities when user-controlled\n * content is embedded in inline scripts.\n */\nexport function escapeHtml(str: string): string {\n return str.replace(HTML_ESCAPE_REGEX, (match) => HTML_ESCAPE_LOOKUP[match]!)\n}\n\nexport function decodePath(path: string) {\n if (!path) return { path, handledProtocolRelativeURL: false }\n\n // Fast path: most paths are already decoded and safe.\n // Only fall back to the slower scan/regex path when we see a '%' (encoded),\n // a backslash (explicitly handled), a control character, or a protocol-relative\n // prefix which needs collapsing.\n // eslint-disable-next-line no-control-regex\n if (!/[%\\\\\\x00-\\x1f\\x7f]/.test(path) && !path.startsWith('//')) {\n return { path, handledProtocolRelativeURL: false }\n }\n\n const re = /%25|%5C/gi\n let cursor = 0\n let result = ''\n let match\n while (null !== (match = re.exec(path))) {\n result += decodeSegment(path.slice(cursor, match.index)) + match[0]\n cursor = re.lastIndex\n }\n result = result + decodeSegment(cursor ? path.slice(cursor) : path)\n\n // Prevent open redirect via protocol-relative URLs (e.g. \"//evil.com\")\n // This is defense-in-depth: since control characters are no longer decoded,\n // paths like \"/%0d/evil.com\" can no longer become \"//evil.com\". But we keep\n // this check to guard against other edge cases.\n let handledProtocolRelativeURL = false\n if (result.startsWith('//')) {\n handledProtocolRelativeURL = true\n result = '/' + result.replace(/^\\/+/, '')\n }\n\n return { path: result, handledProtocolRelativeURL }\n}\n\n/**\n * Encodes a path the same way `new URL()` would, but without the overhead of full URL parsing.\n *\n * This function encodes:\n * - Whitespace characters (spaces → %20, tabs → %09, etc.)\n * - Non-ASCII/Unicode characters (emojis, accented characters, etc.)\n *\n * It preserves:\n * - Already percent-encoded sequences (won't double-encode %2F, %25, etc.)\n * - ASCII special characters valid in URL paths (@, $, &, +, etc.)\n * - Forward slashes as path separators\n *\n * Used to generate proper href values for SSR without constructing URL objects.\n *\n * @example\n * encodePathLikeUrl('/path/file name.pdf') // '/path/file%20name.pdf'\n * encodePathLikeUrl('/path/日本語') // '/path/%E6%97%A5%E6%9C%AC%E8%AA%9E'\n * encodePathLikeUrl('/path/already%20encoded') // '/path/already%20encoded' (preserved)\n */\nexport function encodePathLikeUrl(path: string): string {\n // Encode whitespace and non-ASCII characters that browsers encode in URLs\n\n // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ASCII range check\n // eslint-disable-next-line no-control-regex\n if (!/\\s|[^\\u0000-\\u007F]/.test(path)) return path\n // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ASCII range check\n // eslint-disable-next-line no-control-regex\n return path.replace(/\\s|[^\\u0000-\\u007F]/gu, encodeURIComponent)\n}\n\n/**\n * Builds the dev-mode CSS styles URL for route-scoped CSS collection.\n * Used by HeadContent components in all framework implementations to construct\n * the URL for the `/@tanstack-start/styles.css` endpoint.\n *\n * @param basepath - The router's basepath (may or may not have leading slash)\n * @param routeIds - Array of matched route IDs to include in the CSS collection\n * @returns The full URL path for the dev styles CSS endpoint\n */\nexport function buildDevStylesUrl(\n basepath: string,\n routeIds: Array<string>,\n): string {\n // Trim all leading and trailing slashes from basepath\n const trimmedBasepath = basepath.replace(/^\\/+|\\/+$/g, '')\n // Build normalized basepath: empty string for root, or '/path' for non-root\n const normalizedBasepath = trimmedBasepath === '' ? '' : `/${trimmedBasepath}`\n return `${normalizedBasepath}/@tanstack-start/styles.css?routes=${encodeURIComponent(routeIds.join(','))}`\n}\n\nexport function arraysEqual<T>(a: Array<T>, b: Array<T>) {\n if (a === b) return true\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false\n }\n return true\n}\n"],"mappings":"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"}
{"version":3,"file":"utils.cjs","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["import { isServer } from '@tanstack/router-core/isServer'\nimport type { RouteIds } from './routeInfo'\nimport type { AnyRouter } from './router'\n\nexport type Awaitable<T> = T | Promise<T>\nexport type NoInfer<T> = [T][T extends any ? 0 : never]\nexport type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue\n ? TYesResult\n : TNoResult\n\nexport type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<\n TValue,\n TKey\n> &\n Required<Pick<TValue, TKey>>\n\nexport type PickRequired<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K]\n}\n\nexport type PickOptional<T> = {\n [K in keyof T as undefined extends T[K] ? K : never]: T[K]\n}\n\n// from https://stackoverflow.com/a/76458160\nexport type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never\n\nexport type Expand<T> = T extends object\n ? T extends infer O\n ? O extends Function\n ? O\n : { [K in keyof O]: O[K] }\n : never\n : T\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nexport type MakeDifferenceOptional<TLeft, TRight> = keyof TLeft &\n keyof TRight extends never\n ? TRight\n : Omit<TRight, keyof TLeft & keyof TRight> & {\n [K in keyof TLeft & keyof TRight]?: TRight[K]\n }\n\n// from https://stackoverflow.com/a/53955431\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type IsUnion<T, U extends T = T> = (\n T extends any ? (U extends T ? false : true) : never\n) extends false\n ? false\n : true\n\nexport type IsNonEmptyObject<T> = T extends object\n ? keyof T extends never\n ? false\n : true\n : false\n\nexport type Assign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : keyof TLeft & keyof TRight extends never\n ? TLeft & TRight\n : Omit<TLeft, keyof TRight> & TRight\n : never\n : never\n\nexport type IntersectAssign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : TRight & TLeft\n : never\n : never\n\nexport type Timeout = ReturnType<typeof setTimeout>\n\nexport type Updater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev?: TPrevious) => TResult)\n\nexport type NonNullableUpdater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev: TPrevious) => TResult)\n\nexport type ExtractObjects<TUnion> = TUnion extends MergeAllPrimitive\n ? never\n : TUnion\n\nexport type PartialMergeAllObject<TUnion> =\n ExtractObjects<TUnion> extends infer TObj\n ? [TObj] extends [never]\n ? never\n : {\n [TKey in TObj extends any ? keyof TObj : never]?: TObj extends any\n ? TKey extends keyof TObj\n ? TObj[TKey]\n : never\n : never\n }\n : never\n\nexport type MergeAllPrimitive =\n | ReadonlyArray<any>\n | number\n | string\n | bigint\n | boolean\n | symbol\n | undefined\n | null\n\nexport type ExtractPrimitives<TUnion> = TUnion extends MergeAllPrimitive\n ? TUnion\n : TUnion extends object\n ? never\n : TUnion\n\nexport type PartialMergeAll<TUnion> =\n | ExtractPrimitives<TUnion>\n | PartialMergeAllObject<TUnion>\n\nexport type Constrain<T, TConstraint, TDefault = TConstraint> =\n | (T extends TConstraint ? T : never)\n | TDefault\n\nexport type ConstrainLiteral<T, TConstraint, TDefault = TConstraint> =\n | (T & TConstraint)\n | TDefault\n\n/**\n * To be added to router types\n */\nexport type UnionToIntersection<T> = (\n T extends any ? (arg: T) => any : never\n) extends (arg: infer T) => any\n ? T\n : never\n\n/**\n * Merges everything in a union into one object.\n * This mapped type is homomorphic which means it preserves stuff! :)\n */\nexport type MergeAllObjects<\n TUnion,\n TIntersected = UnionToIntersection<ExtractObjects<TUnion>>,\n> = [keyof TIntersected] extends [never]\n ? never\n : {\n [TKey in keyof TIntersected]: TUnion extends any\n ? TUnion[TKey & keyof TUnion]\n : never\n }\n\nexport type MergeAll<TUnion> =\n | MergeAllObjects<TUnion>\n | ExtractPrimitives<TUnion>\n\nexport type ValidateJSON<T> = ((...args: Array<any>) => any) extends T\n ? unknown extends T\n ? never\n : 'Function is not serializable'\n : { [K in keyof T]: ValidateJSON<T[K]> }\n\nexport type LooseReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn\n : never\n\nexport type LooseAsyncReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn extends Promise<infer TReturn>\n ? TReturn\n : TReturn\n : never\n\n/**\n * Return the last element of an array.\n * Intended for non-empty arrays used within router internals.\n */\nexport function last<T>(arr: ReadonlyArray<T>) {\n return arr[arr.length - 1]\n}\n\n/**\n * Apply a value-or-updater to a previous value.\n * Accepts either a literal value or a function of the previous value.\n */\nexport function functionalUpdate<TPrevious, TResult = TPrevious>(\n updater: Updater<TPrevious, TResult> | NonNullableUpdater<TPrevious, TResult>,\n previous: TPrevious,\n): TResult {\n if (typeof updater === 'function') {\n return (updater as Function)(previous)\n }\n\n return updater\n}\n\nexport const hasOwn = Object.prototype.hasOwnProperty\nconst isEnumerable = Object.prototype.propertyIsEnumerable\n\nexport function hasKeys(obj: Record<string, unknown>) {\n for (const key in obj) {\n if (hasOwn.call(obj, key)) return true\n }\n return false\n}\n\nexport const createNull = () => Object.create(null)\nexport const nullReplaceEqualDeep: typeof replaceEqualDeep = (prev, next) =>\n replaceEqualDeep(prev, next, createNull)\n\n/**\n * This function returns `prev` if `_next` is deeply equal.\n * If not, it will replace any deeply equal children of `b` with those of `a`.\n * This can be used for structural sharing between immutable JSON values for example.\n * Do not use this with signals\n */\nexport function replaceEqualDeep<T>(\n prev: any,\n _next: T,\n _makeObj = () => ({}),\n _depth = 0,\n): T {\n if (isServer) {\n return _next\n }\n if (prev === _next) {\n return prev\n }\n\n if (_depth > 500) return _next\n\n const next = _next as any\n\n const array = isPlainArray(prev) && isPlainArray(next)\n\n if (!array && !(isPlainObject(prev) && isPlainObject(next))) return next\n\n const prevItems = array ? prev : getEnumerableOwnKeys(prev)\n if (!prevItems) return next\n const nextItems = array ? next : getEnumerableOwnKeys(next)\n if (!nextItems) return next\n const prevSize = prevItems.length\n const nextSize = nextItems.length\n const copy: any = array ? new Array(nextSize) : _makeObj()\n\n let equalItems = 0\n\n for (let i = 0; i < nextSize; i++) {\n const key = array ? i : (nextItems[i] as any)\n const p = prev[key]\n const n = next[key]\n\n if (p === n) {\n copy[key] = p\n if (array ? i < prevSize : hasOwn.call(prev, key)) equalItems++\n continue\n }\n\n if (\n p === null ||\n n === null ||\n typeof p !== 'object' ||\n typeof n !== 'object'\n ) {\n copy[key] = n\n continue\n }\n\n const v = replaceEqualDeep(p, n, _makeObj, _depth + 1)\n copy[key] = v\n if (v === p) equalItems++\n }\n\n return prevSize === nextSize && equalItems === prevSize ? prev : copy\n}\n\n/**\n * Equivalent to `Reflect.ownKeys`, but ensures that objects are \"clone-friendly\":\n * will return false if object has any non-enumerable properties.\n *\n * Optimized for the common case where objects have no symbol properties.\n */\nfunction getEnumerableOwnKeys(o: object) {\n // `Object.keys` returns only enumerable own string keys natively (no per-key\n // JS callback). If it has fewer entries than `getOwnPropertyNames` (all own\n // string keys), the object has a non-enumerable own string prop and is not\n // \"clone-friendly\" -> bail. This replaces an O(n) loop of\n // `propertyIsEnumerable` calls with two native calls.\n const keys = Object.keys(o)\n if (keys.length !== Object.getOwnPropertyNames(o).length) {\n return false\n }\n\n // Only check symbols if the object has any (most plain objects don't)\n const symbols = Object.getOwnPropertySymbols(o)\n\n // Fast path: no symbols, return enumerable string keys directly\n if (symbols.length === 0) {\n return keys\n }\n\n // Slow path: has symbols, include only enumerable ones, bail on any\n // non-enumerable symbol so it round-trips like the string-key check above.\n for (const symbol of symbols) {\n if (!isEnumerable.call(o, symbol)) {\n return false\n }\n ;(keys as Array<string | symbol>).push(symbol)\n }\n return keys\n}\n\n// Copied from: https://github.com/jonschlinkert/is-plain-object\nexport function isPlainObject(o: any) {\n if (!hasObjectPrototype(o)) {\n return false\n }\n\n // If has modified constructor\n const ctor = o.constructor\n if (typeof ctor === 'undefined') {\n return true\n }\n\n // If has modified prototype\n const prot = ctor.prototype\n if (!hasObjectPrototype(prot)) {\n return false\n }\n\n // If constructor does not have an Object-specific method\n if (!prot.hasOwnProperty('isPrototypeOf')) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n\nfunction hasObjectPrototype(o: any) {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\n/**\n * Check if a value is a \"plain\" array (no extra enumerable keys).\n */\nexport function isPlainArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value) && value.length === Object.keys(value).length\n}\n\n/**\n * Perform a deep equality check with options for partial comparison and\n * ignoring `undefined` values. Optimized for router state comparisons.\n */\nexport function deepEqual(\n a: any,\n b: any,\n opts?: { partial?: boolean; ignoreUndefined?: boolean },\n): boolean {\n if (a === b) {\n return true\n }\n\n if (typeof a !== typeof b) {\n return false\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0, l = a.length; i < l; i++) {\n if (!deepEqual(a[i], b[i], opts)) return false\n }\n return true\n }\n\n if (isPlainObject(a) && isPlainObject(b)) {\n const ignoreUndefined = opts?.ignoreUndefined ?? true\n\n if (opts?.partial) {\n for (const k in b) {\n if (!ignoreUndefined || b[k] !== undefined) {\n if (!deepEqual(a[k], b[k], opts)) return false\n }\n }\n return true\n }\n\n let aCount = 0\n if (!ignoreUndefined) {\n aCount = Object.keys(a).length\n } else {\n for (const k in a) {\n if (a[k] !== undefined) aCount++\n }\n }\n\n let bCount = 0\n for (const k in b) {\n if (!ignoreUndefined || b[k] !== undefined) {\n bCount++\n if (bCount > aCount || !deepEqual(a[k], b[k], opts)) return false\n }\n }\n\n return aCount === bCount\n }\n\n return false\n}\n\nexport type StringLiteral<T> = T extends string\n ? string extends T\n ? string\n : T\n : never\n\nexport type ThrowOrOptional<T, TThrow extends boolean> = TThrow extends true\n ? T\n : T | undefined\n\nexport type StrictOrFrom<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean = true,\n> = TStrict extends false\n ? {\n from?: never\n strict: TStrict\n }\n : {\n from: ConstrainLiteral<TFrom, RouteIds<TRouter['routeTree']>>\n strict?: TStrict\n }\n\nexport type ThrowConstraint<\n TStrict extends boolean,\n TThrow extends boolean,\n> = TStrict extends false ? (TThrow extends true ? never : TThrow) : TThrow\n\nexport type ControlledPromise<T> = Promise<T> & {\n resolve: (value: T) => void\n reject: (value: any) => void\n status: 'pending' | 'resolved' | 'rejected'\n value?: T\n}\n\n/**\n * Create a promise with exposed resolve/reject and status fields.\n * Useful for coordinating async router lifecycle operations.\n */\nexport function createControlledPromise<T>(onResolve?: (value: T) => void) {\n let resolveLoadPromise!: (value: T) => void\n let rejectLoadPromise!: (value: any) => void\n\n const controlledPromise = new Promise<T>((resolve, reject) => {\n resolveLoadPromise = resolve\n rejectLoadPromise = reject\n }) as ControlledPromise<T>\n\n controlledPromise.status = 'pending'\n\n controlledPromise.resolve = (value: T) => {\n controlledPromise.status = 'resolved'\n controlledPromise.value = value\n resolveLoadPromise(value)\n onResolve?.(value)\n }\n\n controlledPromise.reject = (e) => {\n controlledPromise.status = 'rejected'\n rejectLoadPromise(e)\n }\n\n return controlledPromise\n}\n\n/**\n * Heuristically detect dynamic import \"module not found\" errors\n * across major browsers for lazy route component handling.\n */\nexport function isModuleNotFoundError(error: any): boolean {\n // chrome: \"Failed to fetch dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split\"\n // firefox: \"error loading dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split\"\n // safari: \"Importing a module script failed.\"\n if (typeof error?.message !== 'string') return false\n return (\n error.message.startsWith('Failed to fetch dynamically imported module') ||\n error.message.startsWith('error loading dynamically imported module') ||\n error.message.startsWith('Importing a module script failed')\n )\n}\n\nexport function isPromise<T>(\n value: Promise<Awaited<T>> | T,\n): value is Promise<Awaited<T>> {\n return Boolean(\n value &&\n typeof value === 'object' &&\n typeof (value as Promise<T>).then === 'function',\n )\n}\n\nexport function findLast<T>(\n array: ReadonlyArray<T>,\n predicate: (item: T) => boolean,\n): T | undefined {\n for (let i = array.length - 1; i >= 0; i--) {\n const item = array[i]!\n if (predicate(item)) return item\n }\n return undefined\n}\n\n/**\n * Re-encode characters that are unsafe in URL paths.\n * Includes ASCII control characters (0x00-0x1F, 0x7F) and a subset of the\n * WHATWG URL \"path percent-encode set\" (\", <, >, `, {, }).\n *\n * Space (0x20) is intentionally excluded — decodeURI decodes %20 to space\n * and the router stores decoded spaces in location.pathname. The existing\n * encodePathLikeUrl already handles re-encoding spaces for outgoing URLs.\n *\n * These characters are decoded by decodeURI but must remain percent-encoded\n * in paths to match how upstream layers (CDNs, edge middleware, browsers)\n * interpret the URL, preventing infinite redirect loops and path mismatches.\n */\n// eslint-disable-next-line no-control-regex\nconst PATH_UNSAFE_RE = /[\\x00-\\x1f\\x7f\"<>`{}]/g\n\nfunction sanitizePathSegment(segment: string): string {\n return segment.replace(\n PATH_UNSAFE_RE,\n (ch) => '%' + ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'),\n )\n}\n\nfunction decodeSegment(segment: string): string {\n let decoded: string\n try {\n decoded = decodeURI(segment)\n } catch {\n // if the decoding fails, try to decode the various parts leaving the malformed tags in place\n decoded = segment.replaceAll(/%[0-9A-F]{2}/gi, (match) => {\n try {\n return decodeURI(match)\n } catch {\n return match\n }\n })\n }\n return sanitizePathSegment(decoded)\n}\n\n/**\n * Default list of URL protocols to allow in links, redirects, and navigation.\n * Any absolute URL protocol not in this list is treated as dangerous by default.\n */\nexport const DEFAULT_PROTOCOL_ALLOWLIST = [\n // Standard web navigation\n 'http:',\n 'https:',\n\n // Common browser-safe actions\n 'mailto:',\n 'tel:',\n]\n\n/**\n * Check if a URL string uses a protocol that is not in the allowlist.\n * Returns true for blocked protocols like javascript:, blob:, data:, etc.\n *\n * The URL constructor correctly normalizes:\n * - Mixed case (JavaScript: → javascript:)\n * - Whitespace/control characters (java\\nscript: → javascript:)\n * - Leading whitespace\n *\n * For relative URLs (no protocol), returns false (safe).\n *\n * @param url - The URL string to check\n * @param allowlist - Set of protocols to allow\n * @returns true if the URL uses a protocol that is not allowed\n */\nexport function isDangerousProtocol(\n url: string,\n allowlist: Set<string>,\n): boolean {\n if (!url) return false\n\n try {\n // Use the URL constructor - it correctly normalizes protocols\n // per WHATWG URL spec, handling all bypass attempts automatically\n const parsed = new URL(url)\n return !allowlist.has(parsed.protocol)\n } catch {\n // URL constructor throws for relative URLs (no protocol)\n // These are safe - they can't execute scripts\n return false\n }\n}\n\n// This utility is based on https://github.com/zertosh/htmlescape\n// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE\nconst HTML_ESCAPE_LOOKUP: { [match: string]: string } = {\n '&': '\\\\u0026',\n '>': '\\\\u003e',\n '<': '\\\\u003c',\n '\\u2028': '\\\\u2028',\n '\\u2029': '\\\\u2029',\n}\n\nconst HTML_ESCAPE_REGEX = /[&><\\u2028\\u2029]/g\n\n/**\n * Escape HTML special characters in a string to prevent XSS attacks\n * when embedding strings in script tags during SSR.\n *\n * This is essential for preventing XSS vulnerabilities when user-controlled\n * content is embedded in inline scripts.\n */\nexport function escapeHtml(str: string): string {\n return str.replace(HTML_ESCAPE_REGEX, (match) => HTML_ESCAPE_LOOKUP[match]!)\n}\n\nexport function decodePath(path: string) {\n if (!path) return { path, handledProtocolRelativeURL: false }\n\n // Fast path: most paths are already decoded and safe.\n // Only fall back to the slower scan/regex path when we see a '%' (encoded),\n // a backslash (explicitly handled), a control character, or a protocol-relative\n // prefix which needs collapsing.\n // eslint-disable-next-line no-control-regex\n if (!/[%\\\\\\x00-\\x1f\\x7f]/.test(path) && !path.startsWith('//')) {\n return { path, handledProtocolRelativeURL: false }\n }\n\n const re = /%25|%5C/gi\n let cursor = 0\n let result = ''\n let match\n while (null !== (match = re.exec(path))) {\n result += decodeSegment(path.slice(cursor, match.index)) + match[0]\n cursor = re.lastIndex\n }\n result = result + decodeSegment(cursor ? path.slice(cursor) : path)\n\n // Prevent open redirect via protocol-relative URLs (e.g. \"//evil.com\")\n // This is defense-in-depth: since control characters are no longer decoded,\n // paths like \"/%0d/evil.com\" can no longer become \"//evil.com\". But we keep\n // this check to guard against other edge cases.\n let handledProtocolRelativeURL = false\n if (result.startsWith('//')) {\n handledProtocolRelativeURL = true\n result = '/' + result.replace(/^\\/+/, '')\n }\n\n return { path: result, handledProtocolRelativeURL }\n}\n\n/**\n * Encodes a path the same way `new URL()` would, but without the overhead of full URL parsing.\n *\n * This function encodes:\n * - Whitespace characters (spaces → %20, tabs → %09, etc.)\n * - Non-ASCII/Unicode characters (emojis, accented characters, etc.)\n *\n * It preserves:\n * - Already percent-encoded sequences (won't double-encode %2F, %25, etc.)\n * - ASCII special characters valid in URL paths (@, $, &, +, etc.)\n * - Forward slashes as path separators\n *\n * Used to generate proper href values for SSR without constructing URL objects.\n *\n * @example\n * encodePathLikeUrl('/path/file name.pdf') // '/path/file%20name.pdf'\n * encodePathLikeUrl('/path/日本語') // '/path/%E6%97%A5%E6%9C%AC%E8%AA%9E'\n * encodePathLikeUrl('/path/already%20encoded') // '/path/already%20encoded' (preserved)\n */\nexport function encodePathLikeUrl(path: string): string {\n // Encode whitespace and non-ASCII characters that browsers encode in URLs\n\n // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ASCII range check\n // eslint-disable-next-line no-control-regex\n if (!/\\s|[^\\u0000-\\u007F]/.test(path)) return path\n // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ASCII range check\n // eslint-disable-next-line no-control-regex\n return path.replace(/\\s|[^\\u0000-\\u007F]/gu, encodeURIComponent)\n}\n\n/**\n * Builds the dev-mode CSS styles URL for route-scoped CSS collection.\n * Used by HeadContent components in all framework implementations to construct\n * the URL for the `/@tanstack-start/styles.css` endpoint.\n *\n * @param basepath - The router's basepath (may or may not have leading slash)\n * @param routeIds - Array of matched route IDs to include in the CSS collection\n * @returns The full URL path for the dev styles CSS endpoint\n */\nexport function buildDevStylesUrl(\n basepath: string,\n routeIds: Array<string>,\n): string {\n // Trim all leading and trailing slashes from basepath\n const trimmedBasepath = basepath.replace(/^\\/+|\\/+$/g, '')\n // Build normalized basepath: empty string for root, or '/path' for non-root\n const normalizedBasepath = trimmedBasepath === '' ? '' : `/${trimmedBasepath}`\n return `${normalizedBasepath}/@tanstack-start/styles.css?routes=${encodeURIComponent(routeIds.join(','))}`\n}\n\nexport function arraysEqual<T>(a: Array<T>, b: Array<T>) {\n if (a === b) return true\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false\n }\n return true\n}\n"],"mappings":"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"}

@@ -6,10 +6,2 @@ import { last } from "./utils.js";

const SEGMENT_TYPE_PATHLESS = 5;
function getOpenAndCloseBraces(part) {
const openBrace = part.indexOf("{");
if (openBrace === -1) return null;
const closeBrace = part.indexOf("}", openBrace);
if (closeBrace === -1) return null;
if (openBrace + 1 >= part.length) return null;
return [openBrace, closeBrace];
}
/**

@@ -63,5 +55,5 @@ * Populates the `output` array with the parsed representation of the given `segment` string.

}
const braces = getOpenAndCloseBraces(part);
if (braces) {
const [openBrace, closeBrace] = braces;
const openBrace = part.indexOf("{");
let closeBrace;
if (openBrace !== -1 && openBrace + 1 < part.length && (closeBrace = part.indexOf("}", openBrace)) !== -1) {
const firstChar = part.charCodeAt(openBrace + 1);

@@ -68,0 +60,0 @@ if (firstChar === 45) {

@@ -1,1 +0,1 @@

{"version":3,"file":"new-process-route-tree.js","names":[],"sources":["../../src/new-process-route-tree.ts"],"sourcesContent":["import { invariant } from './invariant'\nimport { createLRUCache } from './lru-cache'\nimport { last } from './utils'\nimport type { LRUCache } from './lru-cache'\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\nfunction getOpenAndCloseBraces(\n part: string,\n): [openBrace: number, closeBrace: number] | null {\n const openBrace = part.indexOf('{')\n if (openBrace === -1) return null\n const closeBrace = part.indexOf('}', openBrace)\n if (closeBrace === -1) return null\n const afterOpen = openBrace + 1\n if (afterOpen >= part.length) return null\n return [openBrace, closeBrace]\n}\n\ntype ParsedSegment = Uint16Array & {\n /** segment type (0 = pathname, 1 = param, 2 = wildcard, 3 = optional param) */\n 0: SegmentKind\n /** index of the end of the prefix */\n 1: number\n /** index of the start of the value */\n 2: number\n /** index of the end of the value */\n 3: number\n /** index of the start of the suffix */\n 4: number\n /** index of the end of the segment */\n 5: number\n}\n\n/**\n * Populates the `output` array with the parsed representation of the given `segment` string.\n *\n * Usage:\n * ```ts\n * let output\n * let cursor = 0\n * while (cursor < path.length) {\n * output = parseSegment(path, cursor, output)\n * const end = output[5]\n * cursor = end + 1\n * ```\n *\n * `output` is stored outside to avoid allocations during repeated calls. It doesn't need to be typed\n * or initialized, it will be done automatically.\n */\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 /** A Uint16Array (length: 6) to populate with the parsed segment data. */\n output: Uint16Array = new Uint16Array(6),\n): ParsedSegment {\n const next = path.indexOf('/', start)\n const end = next === -1 ? path.length : next\n const part = path.substring(start, end)\n\n if (!part || !part.includes('$')) {\n // early escape for static pathname\n output[0] = SEGMENT_TYPE_PATHNAME\n output[1] = start\n output[2] = start\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n }\n\n // $ (wildcard)\n if (part === '$') {\n const total = path.length\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start\n output[2] = start\n output[3] = total\n output[4] = total\n output[5] = total\n return output as ParsedSegment\n }\n\n // $paramName\n if (part.charCodeAt(0) === 36) {\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start\n output[2] = start + 1 // skip '$'\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n }\n\n const braces = getOpenAndCloseBraces(part)\n if (braces) {\n const [openBrace, closeBrace] = braces\n const firstChar = part.charCodeAt(openBrace + 1)\n\n // Check for {-$...} (optional param)\n // prefix{-$paramName}suffix\n // /^([^{]*)\\{-\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/\n if (firstChar === 45) {\n // '-'\n if (\n openBrace + 2 < part.length &&\n part.charCodeAt(openBrace + 2) === 36 // '$'\n ) {\n const paramStart = openBrace + 3\n const paramEnd = closeBrace\n // Validate param name exists\n if (paramStart < paramEnd) {\n output[0] = SEGMENT_TYPE_OPTIONAL_PARAM\n output[1] = start + openBrace\n output[2] = start + paramStart\n output[3] = start + paramEnd\n output[4] = start + closeBrace + 1\n output[5] = end\n return output as ParsedSegment\n }\n }\n } else if (firstChar === 36) {\n // '$'\n const dollarPos = openBrace + 1\n const afterDollar = openBrace + 2\n // Check for {$} (wildcard)\n if (afterDollar === closeBrace) {\n // For wildcard, value should be '$' (from dollarPos to afterDollar)\n // prefix{$}suffix\n // /^([^{]*)\\{\\$\\}([^}]*)$/\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start + openBrace\n output[2] = start + dollarPos\n output[3] = start + afterDollar\n output[4] = start + closeBrace + 1\n output[5] = path.length\n return output as ParsedSegment\n }\n // Regular param {$paramName} - value is the param name (after $)\n // prefix{$paramName}suffix\n // /^([^{]*)\\{\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start + openBrace\n output[2] = start + afterDollar\n output[3] = start + closeBrace\n output[4] = start + closeBrace + 1\n output[5] = end\n return output as ParsedSegment\n }\n }\n\n // fallback to static pathname (should never happen)\n output[0] = SEGMENT_TYPE_PATHNAME\n output[1] = start\n output[2] = start\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n}\n\n/**\n * Recursively parses the segments of the given route tree and populates a segment trie.\n *\n * @param data A reusable Uint16Array for parsing segments. (non important, we're just avoiding allocations)\n * @param route The current route to parse.\n * @param start The starting index for parsing within the route's full path.\n * @param node The current segment node in the trie to populate.\n * @param onRoute Callback invoked for each route processed.\n */\nfunction parseSegments<TRouteLike extends RouteLike>(\n defaultCaseSensitive: boolean,\n data: Uint16Array,\n route: TRouteLike,\n start: number,\n node: AnySegmentNode<TRouteLike>,\n depth: number,\n /** Each dynamic sibling list is recorded once, when it first needs sorting. */\n dynamicListsToSort?: Array<Array<DynamicSegmentNode<TRouteLike>>>,\n onRoute?: (route: TRouteLike) => void,\n) {\n onRoute?.(route)\n let cursor = start\n {\n const path = route.fullPath ?? route.from\n const options = route.options\n const length = path.length\n const caseSensitive = options?.caseSensitive ?? defaultCaseSensitive\n const parseParams = options?.params?.parse ?? options?.parseParams\n while (cursor < length) {\n const segment = parseSegment(path, cursor, data)\n let nextNode: AnySegmentNode<TRouteLike>\n const start = cursor\n const end = segment[5]\n cursor = end + 1\n depth++\n const kind = segment[0]\n switch (kind) {\n case SEGMENT_TYPE_PATHNAME: {\n const value = path.substring(segment[2], segment[3])\n let name = value\n let staticChildren: Map<string, StaticSegmentNode<TRouteLike>>\n if (caseSensitive) {\n staticChildren = node.static ??= new Map()\n } else {\n name = value.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 = createStaticNode<TRouteLike>(path)\n next.parent = node\n next.depth = depth\n nextNode = next\n staticChildren.set(name, next)\n }\n break\n }\n case SEGMENT_TYPE_PARAM:\n case SEGMENT_TYPE_OPTIONAL_PARAM:\n case SEGMENT_TYPE_WILDCARD: {\n const prefix_raw = path.substring(start, segment[1])\n const suffix_raw = path.substring(segment[4], end)\n const actuallyCaseSensitive =\n caseSensitive && !!(prefix_raw || suffix_raw)\n const prefix = !prefix_raw\n ? undefined\n : actuallyCaseSensitive\n ? prefix_raw\n : prefix_raw.toLowerCase()\n const suffix = !suffix_raw\n ? undefined\n : actuallyCaseSensitive\n ? suffix_raw\n : suffix_raw.toLowerCase()\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 = createDynamicNode<TRouteLike>(\n kind,\n path,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.parent = node\n next.depth = depth\n let nodes: Array<DynamicSegmentNode<TRouteLike>>\n if (kind === SEGMENT_TYPE_PARAM) {\n nodes = node.dynamic ??= []\n } else if (kind === SEGMENT_TYPE_OPTIONAL_PARAM) {\n nodes = node.optional ??= []\n } else {\n nodes = node.wildcard ??= []\n }\n nodes.push(next)\n if (nodes.length === 2) {\n dynamicListsToSort?.push(nodes)\n }\n }\n break\n }\n }\n node = nextNode\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 = createStaticNode<TRouteLike>(path)\n pathlessNode.kind = SEGMENT_TYPE_PATHLESS\n pathlessNode.parent = node\n depth++\n pathlessNode.depth = depth\n node.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 && path.endsWith('/')) {\n const indexNode = createStaticNode<TRouteLike>(path)\n indexNode.kind = SEGMENT_TYPE_INDEX\n indexNode.parent = node\n depth++\n indexNode.depth = depth\n node.index = indexNode\n node = indexNode\n }\n\n node.parse = parseParams ?? null\n node.priority = options?.params?.priority ?? 0\n\n // make node \"matchable\"\n if (isLeaf && !node.route) {\n node.route = route\n node.fullPath = path\n }\n }\n if (route.children)\n for (const child of route.children) {\n parseSegments(\n defaultCaseSensitive,\n data,\n child as TRouteLike,\n cursor,\n node,\n depth,\n dynamicListsToSort,\n onRoute,\n )\n }\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 createStaticNode<T extends RouteLike>(\n fullPath: string,\n): StaticSegmentNode<T> {\n return {\n kind: SEGMENT_TYPE_PATHNAME,\n depth: 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 fullPath,\n parent: null,\n parse: null,\n priority: 0,\n }\n}\n\n/**\n * Keys must be declared in the same order as in `SegmentNode` type,\n * to ensure they are represented as the same object class in the engine.\n */\nfunction createDynamicNode<T extends RouteLike>(\n kind:\n | typeof SEGMENT_TYPE_PARAM\n | typeof SEGMENT_TYPE_WILDCARD\n | typeof SEGMENT_TYPE_OPTIONAL_PARAM,\n fullPath: string,\n caseSensitive: boolean,\n prefix?: string,\n suffix?: string,\n): DynamicSegmentNode<T> {\n return {\n kind,\n depth: 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 fullPath,\n parent: null,\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\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 /** The full path for this segment node (will only be valid on leaf nodes) */\n fullPath: string\n\n parent: AnySegmentNode<T> | null\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 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: LRUCache<string, AnySegmentNode<TSingle>>\n /** a cache of route matches from the `segmentTree` */\n matchCache: LRUCache<string, RouteMatch<TTree> | null>\n /** a cache of route matches from the `masksTree` */\n flatCache: LRUCache<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 = createStaticNode<TRouteLike>('/')\n const data = new Uint16Array(6)\n const dynamicListsToSort: Array<Array<DynamicSegmentNode<TRouteLike>>> = []\n for (const route of routeList) {\n parseSegments(false, data, route, 1, segmentTree, 0, dynamicListsToSort)\n }\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n processedTree.masksTree = segmentTree\n processedTree.flatCache = createLRUCache<\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) 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 = createStaticNode<{ from: string }>('/')\n const data = new Uint16Array(6)\n parseSegments(caseSensitive, data, { from }, 1, tree, 0)\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\n/** Trim trailing slashes (except preserving root '/'). */\nexport function trimPathRight(path: string) {\n return path === '/' ? path : path.replace(/\\/{1,}$/, '')\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 }> & { id: string },\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 /** Optional callback invoked for each route during processing. */\n initRoute?: (route: TRouteLike, index: number) => void,\n): ProcessRouteTreeResult<TRouteLike> {\n const segmentTree = createStaticNode<TRouteLike>(routeTree.fullPath)\n const data = new Uint16Array(6)\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 parseSegments(\n caseSensitive,\n data,\n routeTree,\n 1,\n segmentTree,\n 0,\n dynamicListsToSort,\n (route) => {\n initRoute?.(route, 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\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\n index++\n },\n )\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n const processedTree: ProcessedTree<TRouteLike, any, any> = {\n segmentTree,\n singleCache: createLRUCache<string, AnySegmentNode<any>>(1000),\n matchCache: createLRUCache<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 segment: 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 let nodeParts: Array<string> | null = null\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 /** which fullPath segment we're currently processing */\n let segmentCount = leaf.extract?.segment ?? 0\n for (\n ;\n nodeIndex < list.length;\n partIndex++, nodeIndex++, pathIndex++, segmentCount++\n ) {\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 segmentCount--\n partIndex--\n pathIndex--\n continue\n }\n const part = parts[partIndex]\n const currentPathIndex = pathIndex\n if (part) pathIndex += part.length\n if (node.kind === SEGMENT_TYPE_PARAM) {\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[segmentCount]!\n const preLength = node.prefix?.length ?? 0\n // we can't rely on the presence of prefix/suffix to know whether it's curly-braced or not, because `/{$param}/` is valid, but has no prefix/suffix\n const isCurlyBraced = nodePart.charCodeAt(preLength) === 123 // '{'\n // param name is extracted at match-time so that tree nodes that are identical except for param name can share the same node\n if (isCurlyBraced) {\n const sufLength = node.suffix?.length ?? 0\n const name = nodePart.substring(\n preLength + 2,\n nodePart.length - sufLength - 1,\n )\n const value = part!.substring(preLength, part!.length - sufLength)\n rawParams[name] = decodeURIComponent(value)\n } else {\n const name = nodePart.substring(1)\n rawParams[name] = decodeURIComponent(part!)\n }\n } else if (node.kind === SEGMENT_TYPE_OPTIONAL_PARAM) {\n if (leaf.skipped & (1 << nodeIndex)) {\n partIndex-- // stay on the same part\n pathIndex = currentPathIndex - 1 // undo pathIndex advancement; -1 to account for loop increment\n continue\n }\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[segmentCount]!\n const preLength = node.prefix?.length ?? 0\n const sufLength = node.suffix?.length ?? 0\n const name = nodePart.substring(\n preLength + 3,\n nodePart.length - sufLength - 1,\n )\n const value =\n node.suffix || node.prefix\n ? part!.substring(preLength, part!.length - sufLength)\n : part\n if (value) rawParams[name] = decodeURIComponent(value)\n } else if (node.kind === SEGMENT_TYPE_WILDCARD) {\n const n = node\n const value = path.substring(\n currentPathIndex + (n.prefix?.length ?? 0),\n path.length - (n.suffix?.length ?? 0),\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 segment: segmentCount,\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('/').slice(-suffix.length)\n const casePart = segment.caseSensitive ? end : end.toLowerCase()\n if (casePart !== suffix) continue\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 (suffix && !casePart.endsWith(suffix)) continue\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 (suffix && !casePart.endsWith(suffix)) continue\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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"}
{"version":3,"file":"new-process-route-tree.js","names":[],"sources":["../../src/new-process-route-tree.ts"],"sourcesContent":["import { invariant } from './invariant'\nimport { createLRUCache } from './lru-cache'\nimport { last } from './utils'\nimport type { LRUCache } from './lru-cache'\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\ntype ParsedSegment = Uint16Array & {\n /** segment type (0 = pathname, 1 = param, 2 = wildcard, 3 = optional param) */\n 0: SegmentKind\n /** index of the end of the prefix */\n 1: number\n /** index of the start of the value */\n 2: number\n /** index of the end of the value */\n 3: number\n /** index of the start of the suffix */\n 4: number\n /** index of the end of the segment */\n 5: number\n}\n\n/**\n * Populates the `output` array with the parsed representation of the given `segment` string.\n *\n * Usage:\n * ```ts\n * let output\n * let cursor = 0\n * while (cursor < path.length) {\n * output = parseSegment(path, cursor, output)\n * const end = output[5]\n * cursor = end + 1\n * ```\n *\n * `output` is stored outside to avoid allocations during repeated calls. It doesn't need to be typed\n * or initialized, it will be done automatically.\n */\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 /** A Uint16Array (length: 6) to populate with the parsed segment data. */\n output: Uint16Array = new Uint16Array(6),\n): ParsedSegment {\n const next = path.indexOf('/', start)\n const end = next === -1 ? path.length : next\n const part = path.substring(start, end)\n\n if (!part || !part.includes('$')) {\n // early escape for static pathname\n output[0] = SEGMENT_TYPE_PATHNAME\n output[1] = start\n output[2] = start\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n }\n\n // $ (wildcard)\n if (part === '$') {\n const total = path.length\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start\n output[2] = start\n output[3] = total\n output[4] = total\n output[5] = total\n return output as ParsedSegment\n }\n\n // $paramName\n if (part.charCodeAt(0) === 36) {\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start\n output[2] = start + 1 // skip '$'\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n }\n\n const openBrace = part.indexOf('{')\n let closeBrace\n if (\n openBrace !== -1 &&\n openBrace + 1 < part.length &&\n (closeBrace = part.indexOf('}', openBrace)) !== -1\n ) {\n const firstChar = part.charCodeAt(openBrace + 1)\n\n // Check for {-$...} (optional param)\n // prefix{-$paramName}suffix\n // /^([^{]*)\\{-\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/\n if (firstChar === 45) {\n // '-'\n if (\n openBrace + 2 < part.length &&\n part.charCodeAt(openBrace + 2) === 36 // '$'\n ) {\n const paramStart = openBrace + 3\n const paramEnd = closeBrace\n // Validate param name exists\n if (paramStart < paramEnd) {\n output[0] = SEGMENT_TYPE_OPTIONAL_PARAM\n output[1] = start + openBrace\n output[2] = start + paramStart\n output[3] = start + paramEnd\n output[4] = start + closeBrace + 1\n output[5] = end\n return output as ParsedSegment\n }\n }\n } else if (firstChar === 36) {\n // '$'\n const dollarPos = openBrace + 1\n const afterDollar = openBrace + 2\n // Check for {$} (wildcard)\n if (afterDollar === closeBrace) {\n // For wildcard, value should be '$' (from dollarPos to afterDollar)\n // prefix{$}suffix\n // /^([^{]*)\\{\\$\\}([^}]*)$/\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start + openBrace\n output[2] = start + dollarPos\n output[3] = start + afterDollar\n output[4] = start + closeBrace + 1\n output[5] = path.length\n return output as ParsedSegment\n }\n // Regular param {$paramName} - value is the param name (after $)\n // prefix{$paramName}suffix\n // /^([^{]*)\\{\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start + openBrace\n output[2] = start + afterDollar\n output[3] = start + closeBrace\n output[4] = start + closeBrace + 1\n output[5] = end\n return output as ParsedSegment\n }\n }\n\n // fallback to static pathname (should never happen)\n output[0] = SEGMENT_TYPE_PATHNAME\n output[1] = start\n output[2] = start\n output[3] = end\n output[4] = end\n output[5] = end\n return output as ParsedSegment\n}\n\n/**\n * Recursively parses the segments of the given route tree and populates a segment trie.\n *\n * @param data A reusable Uint16Array for parsing segments. (non important, we're just avoiding allocations)\n * @param route The current route to parse.\n * @param start The starting index for parsing within the route's full path.\n * @param node The current segment node in the trie to populate.\n * @param onRoute Callback invoked for each route processed.\n */\nfunction parseSegments<TRouteLike extends RouteLike>(\n defaultCaseSensitive: boolean,\n data: Uint16Array,\n route: TRouteLike,\n start: number,\n node: AnySegmentNode<TRouteLike>,\n depth: number,\n /** Each dynamic sibling list is recorded once, when it first needs sorting. */\n dynamicListsToSort?: Array<Array<DynamicSegmentNode<TRouteLike>>>,\n onRoute?: (route: TRouteLike) => void,\n) {\n onRoute?.(route)\n let cursor = start\n {\n const path = route.fullPath ?? route.from\n const options = route.options\n const length = path.length\n const caseSensitive = options?.caseSensitive ?? defaultCaseSensitive\n const parseParams = options?.params?.parse ?? options?.parseParams\n while (cursor < length) {\n const segment = parseSegment(path, cursor, data)\n let nextNode: AnySegmentNode<TRouteLike>\n const start = cursor\n const end = segment[5]\n cursor = end + 1\n depth++\n const kind = segment[0]\n switch (kind) {\n case SEGMENT_TYPE_PATHNAME: {\n const value = path.substring(segment[2], segment[3])\n let name = value\n let staticChildren: Map<string, StaticSegmentNode<TRouteLike>>\n if (caseSensitive) {\n staticChildren = node.static ??= new Map()\n } else {\n name = value.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 = createStaticNode<TRouteLike>(path)\n next.parent = node\n next.depth = depth\n nextNode = next\n staticChildren.set(name, next)\n }\n break\n }\n case SEGMENT_TYPE_PARAM:\n case SEGMENT_TYPE_OPTIONAL_PARAM:\n case SEGMENT_TYPE_WILDCARD: {\n const prefix_raw = path.substring(start, segment[1])\n const suffix_raw = path.substring(segment[4], end)\n const actuallyCaseSensitive =\n caseSensitive && !!(prefix_raw || suffix_raw)\n const prefix = !prefix_raw\n ? undefined\n : actuallyCaseSensitive\n ? prefix_raw\n : prefix_raw.toLowerCase()\n const suffix = !suffix_raw\n ? undefined\n : actuallyCaseSensitive\n ? suffix_raw\n : suffix_raw.toLowerCase()\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 = createDynamicNode<TRouteLike>(\n kind,\n path,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.parent = node\n next.depth = depth\n let nodes: Array<DynamicSegmentNode<TRouteLike>>\n if (kind === SEGMENT_TYPE_PARAM) {\n nodes = node.dynamic ??= []\n } else if (kind === SEGMENT_TYPE_OPTIONAL_PARAM) {\n nodes = node.optional ??= []\n } else {\n nodes = node.wildcard ??= []\n }\n nodes.push(next)\n if (nodes.length === 2) {\n dynamicListsToSort?.push(nodes)\n }\n }\n break\n }\n }\n node = nextNode\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 = createStaticNode<TRouteLike>(path)\n pathlessNode.kind = SEGMENT_TYPE_PATHLESS\n pathlessNode.parent = node\n depth++\n pathlessNode.depth = depth\n node.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 && path.endsWith('/')) {\n const indexNode = createStaticNode<TRouteLike>(path)\n indexNode.kind = SEGMENT_TYPE_INDEX\n indexNode.parent = node\n depth++\n indexNode.depth = depth\n node.index = indexNode\n node = indexNode\n }\n\n node.parse = parseParams ?? null\n node.priority = options?.params?.priority ?? 0\n\n // make node \"matchable\"\n if (isLeaf && !node.route) {\n node.route = route\n node.fullPath = path\n }\n }\n if (route.children)\n for (const child of route.children) {\n parseSegments(\n defaultCaseSensitive,\n data,\n child as TRouteLike,\n cursor,\n node,\n depth,\n dynamicListsToSort,\n onRoute,\n )\n }\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 createStaticNode<T extends RouteLike>(\n fullPath: string,\n): StaticSegmentNode<T> {\n return {\n kind: SEGMENT_TYPE_PATHNAME,\n depth: 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 fullPath,\n parent: null,\n parse: null,\n priority: 0,\n }\n}\n\n/**\n * Keys must be declared in the same order as in `SegmentNode` type,\n * to ensure they are represented as the same object class in the engine.\n */\nfunction createDynamicNode<T extends RouteLike>(\n kind:\n | typeof SEGMENT_TYPE_PARAM\n | typeof SEGMENT_TYPE_WILDCARD\n | typeof SEGMENT_TYPE_OPTIONAL_PARAM,\n fullPath: string,\n caseSensitive: boolean,\n prefix?: string,\n suffix?: string,\n): DynamicSegmentNode<T> {\n return {\n kind,\n depth: 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 fullPath,\n parent: null,\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\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 /** The full path for this segment node (will only be valid on leaf nodes) */\n fullPath: string\n\n parent: AnySegmentNode<T> | null\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 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: LRUCache<string, AnySegmentNode<TSingle>>\n /** a cache of route matches from the `segmentTree` */\n matchCache: LRUCache<string, RouteMatch<TTree> | null>\n /** a cache of route matches from the `masksTree` */\n flatCache: LRUCache<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 = createStaticNode<TRouteLike>('/')\n const data = new Uint16Array(6)\n const dynamicListsToSort: Array<Array<DynamicSegmentNode<TRouteLike>>> = []\n for (const route of routeList) {\n parseSegments(false, data, route, 1, segmentTree, 0, dynamicListsToSort)\n }\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n processedTree.masksTree = segmentTree\n processedTree.flatCache = createLRUCache<\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) 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 = createStaticNode<{ from: string }>('/')\n const data = new Uint16Array(6)\n parseSegments(caseSensitive, data, { from }, 1, tree, 0)\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\n/** Trim trailing slashes (except preserving root '/'). */\nexport function trimPathRight(path: string) {\n return path === '/' ? path : path.replace(/\\/{1,}$/, '')\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 }> & { id: string },\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 /** Optional callback invoked for each route during processing. */\n initRoute?: (route: TRouteLike, index: number) => void,\n): ProcessRouteTreeResult<TRouteLike> {\n const segmentTree = createStaticNode<TRouteLike>(routeTree.fullPath)\n const data = new Uint16Array(6)\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 parseSegments(\n caseSensitive,\n data,\n routeTree,\n 1,\n segmentTree,\n 0,\n dynamicListsToSort,\n (route) => {\n initRoute?.(route, 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\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\n index++\n },\n )\n for (const nodes of dynamicListsToSort) {\n nodes.sort(sortDynamic)\n }\n const processedTree: ProcessedTree<TRouteLike, any, any> = {\n segmentTree,\n singleCache: createLRUCache<string, AnySegmentNode<any>>(1000),\n matchCache: createLRUCache<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 segment: 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 let nodeParts: Array<string> | null = null\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 /** which fullPath segment we're currently processing */\n let segmentCount = leaf.extract?.segment ?? 0\n for (\n ;\n nodeIndex < list.length;\n partIndex++, nodeIndex++, pathIndex++, segmentCount++\n ) {\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 segmentCount--\n partIndex--\n pathIndex--\n continue\n }\n const part = parts[partIndex]\n const currentPathIndex = pathIndex\n if (part) pathIndex += part.length\n if (node.kind === SEGMENT_TYPE_PARAM) {\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[segmentCount]!\n const preLength = node.prefix?.length ?? 0\n // we can't rely on the presence of prefix/suffix to know whether it's curly-braced or not, because `/{$param}/` is valid, but has no prefix/suffix\n const isCurlyBraced = nodePart.charCodeAt(preLength) === 123 // '{'\n // param name is extracted at match-time so that tree nodes that are identical except for param name can share the same node\n if (isCurlyBraced) {\n const sufLength = node.suffix?.length ?? 0\n const name = nodePart.substring(\n preLength + 2,\n nodePart.length - sufLength - 1,\n )\n const value = part!.substring(preLength, part!.length - sufLength)\n rawParams[name] = decodeURIComponent(value)\n } else {\n const name = nodePart.substring(1)\n rawParams[name] = decodeURIComponent(part!)\n }\n } else if (node.kind === SEGMENT_TYPE_OPTIONAL_PARAM) {\n if (leaf.skipped & (1 << nodeIndex)) {\n partIndex-- // stay on the same part\n pathIndex = currentPathIndex - 1 // undo pathIndex advancement; -1 to account for loop increment\n continue\n }\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[segmentCount]!\n const preLength = node.prefix?.length ?? 0\n const sufLength = node.suffix?.length ?? 0\n const name = nodePart.substring(\n preLength + 3,\n nodePart.length - sufLength - 1,\n )\n const value =\n node.suffix || node.prefix\n ? part!.substring(preLength, part!.length - sufLength)\n : part\n if (value) rawParams[name] = decodeURIComponent(value)\n } else if (node.kind === SEGMENT_TYPE_WILDCARD) {\n const n = node\n const value = path.substring(\n currentPathIndex + (n.prefix?.length ?? 0),\n path.length - (n.suffix?.length ?? 0),\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 segment: segmentCount,\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('/').slice(-suffix.length)\n const casePart = segment.caseSensitive ? end : end.toLowerCase()\n if (casePart !== suffix) continue\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 (suffix && !casePart.endsWith(suffix)) continue\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 (suffix && !casePart.endsWith(suffix)) continue\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":";;;AASA,MAAM,qBAAqB;AAC3B,MAAM,wBAAwB;;;;;;;;;;;;;;;;;AAkD9B,SAAgB,aAEd,MAEA,OAEA,SAAsB,IAAI,YAAY,CAAC,GACxB;CACf,MAAM,OAAO,KAAK,QAAQ,KAAK,KAAK;CACpC,MAAM,MAAM,SAAS,KAAK,KAAK,SAAS;CACxC,MAAM,OAAO,KAAK,UAAU,OAAO,GAAG;CAEtC,IAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,GAAG,GAAG;EAEhC,OAAO,KAAA;EACP,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO;CACT;CAGA,IAAI,SAAS,KAAK;EAChB,MAAM,QAAQ,KAAK;EACnB,OAAO,KAAA;EACP,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO;CACT;CAGA,IAAI,KAAK,WAAW,CAAC,MAAM,IAAI;EAC7B,OAAO,KAAA;EACP,OAAO,KAAK;EACZ,OAAO,KAAK,QAAQ;EACpB,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO;CACT;CAEA,MAAM,YAAY,KAAK,QAAQ,GAAG;CAClC,IAAI;CACJ,IACE,cAAc,MACd,YAAY,IAAI,KAAK,WACpB,aAAa,KAAK,QAAQ,KAAK,SAAS,OAAO,IAChD;EACA,MAAM,YAAY,KAAK,WAAW,YAAY,CAAC;EAK/C,IAAI,cAAc;OAGd,YAAY,IAAI,KAAK,UACrB,KAAK,WAAW,YAAY,CAAC,MAAM,IACnC;IACA,MAAM,aAAa,YAAY;IAC/B,MAAM,WAAW;IAEjB,IAAI,aAAa,UAAU;KACzB,OAAO,KAAA;KACP,OAAO,KAAK,QAAQ;KACpB,OAAO,KAAK,QAAQ;KACpB,OAAO,KAAK,QAAQ;KACpB,OAAO,KAAK,QAAQ,aAAa;KACjC,OAAO,KAAK;KACZ,OAAO;IACT;GACF;SACK,IAAI,cAAc,IAAI;GAE3B,MAAM,YAAY,YAAY;GAC9B,MAAM,cAAc,YAAY;GAEhC,IAAI,gBAAgB,YAAY;IAI9B,OAAO,KAAA;IACP,OAAO,KAAK,QAAQ;IACpB,OAAO,KAAK,QAAQ;IACpB,OAAO,KAAK,QAAQ;IACpB,OAAO,KAAK,QAAQ,aAAa;IACjC,OAAO,KAAK,KAAK;IACjB,OAAO;GACT;GAIA,OAAO,KAAA;GACP,OAAO,KAAK,QAAQ;GACpB,OAAO,KAAK,QAAQ;GACpB,OAAO,KAAK,QAAQ;GACpB,OAAO,KAAK,QAAQ,aAAa;GACjC,OAAO,KAAK;GACZ,OAAO;EACT;CACF;CAGA,OAAO,KAAA;CACP,OAAO,KAAK;CACZ,OAAO,KAAK;CACZ,OAAO,KAAK;CACZ,OAAO,KAAK;CACZ,OAAO,KAAK;CACZ,OAAO;AACT;;;;;;;;;;AAWA,SAAS,cACP,sBACA,MACA,OACA,OACA,MACA,OAEA,oBACA,SACA;CACA,UAAU,KAAK;CACf,IAAI,SAAS;CACb;EACE,MAAM,OAAO,MAAM,YAAY,MAAM;EACrC,MAAM,UAAU,MAAM;EACtB,MAAM,SAAS,KAAK;EACpB,MAAM,gBAAgB,SAAS,iBAAiB;EAChD,MAAM,cAAc,SAAS,QAAQ,SAAS,SAAS;EACvD,OAAO,SAAS,QAAQ;GACtB,MAAM,UAAU,aAAa,MAAM,QAAQ,IAAI;GAC/C,IAAI;GACJ,MAAM,QAAQ;GACd,MAAM,MAAM,QAAQ;GACpB,SAAS,MAAM;GACf;GACA,MAAM,OAAO,QAAQ;GACrB,QAAQ,MAAR;IACE,KAAA,GAA4B;KAC1B,MAAM,QAAQ,KAAK,UAAU,QAAQ,IAAI,QAAQ,EAAE;KACnD,IAAI,OAAO;KACX,IAAI;KACJ,IAAI,eACF,iBAAiB,KAAK,2BAAW,IAAI,IAAI;UACpC;MACL,OAAO,MAAM,YAAY;MACzB,iBAAiB,KAAK,sCAAsB,IAAI,IAAI;KACtD;KACA,MAAM,eAAe,eAAe,IAAI,IAAI;KAC5C,IAAI,cACF,WAAW;UACN;MACL,MAAM,OAAO,iBAA6B,IAAI;MAC9C,KAAK,SAAS;MACd,KAAK,QAAQ;MACb,WAAW;MACX,eAAe,IAAI,MAAM,IAAI;KAC/B;KACA;IACF;IACA,KAAA;IACA,KAAA;IACA,KAAA,GAA4B;KAC1B,MAAM,aAAa,KAAK,UAAU,OAAO,QAAQ,EAAE;KACnD,MAAM,aAAa,KAAK,UAAU,QAAQ,IAAI,GAAG;KACjD,MAAM,wBACJ,iBAAiB,CAAC,EAAE,cAAc;KACpC,MAAM,SAAS,CAAC,aACZ,KAAA,IACA,wBACE,aACA,WAAW,YAAY;KAC7B,MAAM,SAAS,CAAC,aACZ,KAAA,IACA,wBACE,aACA,WAAW,YAAY;KAC7B,MAAM,WACJ,SAAA,IACI,KAAK,UACL,SAAA,IACE,KAAK,WACL,KAAK;KACb,MAAM,eAGJ,SAAA,KACA,CAAC,eACD,UAAU,MACP,MACC,CAAC,EAAE,SACH,EAAE,kBAAkB,yBACpB,EAAE,WAAW,UACb,EAAE,WAAW,MACjB;KACF,IAAI,cACF,WAAW;UACN;MACL,MAAM,OAAO,kBACX,MACA,MACA,uBACA,QACA,MACF;MACA,WAAW;MACX,KAAK,SAAS;MACd,KAAK,QAAQ;MACb,IAAI;MACJ,IAAI,SAAA,GACF,QAAQ,KAAK,YAAY,CAAC;WACrB,IAAI,SAAA,GACT,QAAQ,KAAK,aAAa,CAAC;WAE3B,QAAQ,KAAK,aAAa,CAAC;MAE7B,MAAM,KAAK,IAAI;MACf,IAAI,MAAM,WAAW,GACnB,oBAAoB,KAAK,KAAK;KAElC;KACA;IACF;GACF;GACA,OAAO;EACT;EAGA,IACE,eACA,MAAM,YACN,CAAC,MAAM,UACP,MAAM,MACN,MAAM,GAAG,WAAW,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC,MAAM,IACvD;GACA,MAAM,eAAe,iBAA6B,IAAI;GACtD,aAAa,OAAO;GACpB,aAAa,SAAS;GACtB;GACA,aAAa,QAAQ;GACrB,KAAK,aAAa,CAAC;GACnB,KAAK,SAAS,KAAK,YAAY;GAC/B,OAAO;EACT;EAEA,MAAM,UAAU,MAAM,QAAQ,CAAC,MAAM,aAAa,CAAC,MAAM;EAEzD,IAAI,UAAU,KAAK,SAAS,GAAG,GAAG;GAChC,MAAM,YAAY,iBAA6B,IAAI;GACnD,UAAU,OAAO;GACjB,UAAU,SAAS;GACnB;GACA,UAAU,QAAQ;GAClB,KAAK,QAAQ;GACb,OAAO;EACT;EAEA,KAAK,QAAQ,eAAe;EAC5B,KAAK,WAAW,SAAS,QAAQ,YAAY;EAG7C,IAAI,UAAU,CAAC,KAAK,OAAO;GACzB,KAAK,QAAQ;GACb,KAAK,WAAW;EAClB;CACF;CACA,IAAI,MAAM,UACR,KAAK,MAAM,SAAS,MAAM,UACxB,cACE,sBACA,MACA,OACA,QACA,MACA,OACA,oBACA,OACF;AAEN;AAEA,SAAS,YACP,GAOA,GAOA;CACA,IAAI,EAAE,SAAS,CAAC,EAAE,OAAO,OAAO;CAChC,IAAI,CAAC,EAAE,SAAS,EAAE,OAAO,OAAO;CAChC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,WACzC,OAAO,EAAE,WAAW,EAAE;CACxB,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ;EACjD,IAAI,EAAE,OAAO,WAAW,EAAE,MAAM,GAAG,OAAO;EAC1C,IAAI,EAAE,OAAO,WAAW,EAAE,MAAM,GAAG,OAAO;CAC5C;CACA,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ;EACjD,IAAI,EAAE,OAAO,SAAS,EAAE,MAAM,GAAG,OAAO;EACxC,IAAI,EAAE,OAAO,SAAS,EAAE,MAAM,GAAG,OAAO;CAC1C;CACA,IAAI,EAAE,UAAU,CAAC,EAAE,QAAQ,OAAO;CAClC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,OAAO;CAClC,IAAI,EAAE,UAAU,CAAC,EAAE,QAAQ,OAAO;CAClC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,OAAO;CAClC,IAAI,EAAE,iBAAiB,CAAC,EAAE,eAAe,OAAO;CAChD,IAAI,CAAC,EAAE,iBAAiB,EAAE,eAAe,OAAO;CAGhD,OAAO;AACT;AAEA,SAAS,iBACP,UACsB;CACtB,OAAO;EACL,MAAA;EACA,OAAO;EACP,UAAU;EACV,OAAO;EACP,QAAQ;EACR,mBAAmB;EACnB,SAAS;EACT,UAAU;EACV,UAAU;EACV,OAAO;EACP;EACA,QAAQ;EACR,OAAO;EACP,UAAU;CACZ;AACF;;;;;AAMA,SAAS,kBACP,MAIA,UACA,eACA,QACA,QACuB;CACvB,OAAO;EACL;EACA,OAAO;EACP,UAAU;EACV,OAAO;EACP,QAAQ;EACR,mBAAmB;EACnB,SAAS;EACT,UAAU;EACV,UAAU;EACV,OAAO;EACP;EACA,QAAQ;EACR,OAAO;EACP,UAAU;EACV;EACA;EACA;CACF;AACF;AAqGA,SAAgB,kBAGd,WACA,eACA;CACA,MAAM,cAAc,iBAA6B,GAAG;CACpD,MAAM,OAAO,IAAI,YAAY,CAAC;CAC9B,MAAM,qBAAmE,CAAC;CAC1E,KAAK,MAAM,SAAS,WAClB,cAAc,OAAO,MAAM,OAAO,GAAG,aAAa,GAAG,kBAAkB;CAEzE,KAAK,MAAM,SAAS,oBAClB,MAAM,KAAK,WAAW;CAExB,cAAc,YAAY;CAC1B,cAAc,YAAY,eAGxB,GAAI;AACR;;;;AAKA,SAAgB,cAEd,MAEA,eACA;CACA,SAAS;CACT,MAAM,SAAS,cAAc,UAAW,IAAI,IAAI;CAChD,IAAI,QAAQ,OAAO;CACnB,MAAM,SAAS,UAAU,MAAM,cAAc,SAAU;CACvD,cAAc,UAAW,IAAI,MAAM,MAAM;CACzC,OAAO;AACT;;;;AAKA,SAAgB,gBACd,MACA,eACA,OACA,MACA,eACA;CACA,SAAS;CACT,SAAS;CACT,MAAM,MAAM,gBAAgB,SAAS,SAAS;CAC9C,IAAI,OAAO,cAAc,YAAY,IAAI,GAAG;CAC5C,IAAI,CAAC,MAAM;EAGT,OAAO,iBAAmC,GAAG;EAE7C,cAAc,eAAe,IADZ,YAAY,CACA,GAAM,EAAE,KAAK,GAAG,GAAG,MAAM,CAAC;EACvD,cAAc,YAAY,IAAI,KAAK,IAAI;CACzC;CACA,OAAO,UAAU,MAAM,MAAM,KAAK;AACpC;AAQA,SAAgB,eAId,MAEA,eAEA,QAAQ,OACc;CACtB,MAAM,MAAM,QAAQ,OAAO,WAAW;CACtC,MAAM,SAAS,cAAc,WAAW,IAAI,GAAG;CAC/C,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,SAAS;CACT,IAAI;CAEJ,IAAI;EACF,SAAS,UACP,MACA,cAAc,aACd,KACF;CACF,SAAS,KAAK;EACZ,IAAI,eAAe,UACjB,SAAS;OAET,MAAM;CAEV;CAEA,IAAI,QAAQ,OAAO,SAAS,iBAAiB,OAAO,KAAK;CACzD,cAAc,WAAW,IAAI,KAAK,MAAM;CACxC,OAAO;AACT;;AAGA,SAAgB,cAAc,MAAc;CAC1C,OAAO,SAAS,MAAM,OAAO,KAAK,QAAQ,WAAW,EAAE;AACzD;;;;;AAiBA,SAAgB,iBAId,WAEA,gBAAyB,OAEzB,WACoC;CACpC,MAAM,cAAc,iBAA6B,UAAU,QAAQ;CACnE,MAAM,OAAO,IAAI,YAAY,CAAC;CAC9B,MAAM,qBAAmE,CAAC;CAC1E,MAAM,aAAa,CAAC;CACpB,MAAM,eAAe,CAAC;CACtB,IAAI,QAAQ;CACZ,cACE,eACA,MACA,WACA,GACA,aACA,GACA,qBACC,UAAU;EACT,YAAY,OAAO,KAAK;EAExB,IAAI,MAAM,MAAM,YAAY;GAC1B,IAAA,QAAA,IAAA,aAA6B,cAC3B,MAAM,IAAI,MACR,qDAAqD,OAAO,MAAM,EAAE,GACtE;GAGF,UAAU;EACZ;EAEA,WAAW,MAAM,MAAM;EAEvB,IAAI,UAAU,KAAK,MAAM,MAAM;GAC7B,MAAM,kBAAkB,cAAc,MAAM,QAAQ;GACpD,IAAI,CAAC,aAAa,oBAAoB,MAAM,SAAS,SAAS,GAAG,GAC/D,aAAa,mBAAmB;EAEpC;EAEA;CACF,CACF;CACA,KAAK,MAAM,SAAS,oBAClB,MAAM,KAAK,WAAW;CASxB,OAAO;EACL,eAAA;GAPA;GACA,aAAa,eAA4C,GAAI;GAC7D,YAAY,eAAsD,GAAI;GACtE,WAAW;GACX,WAAW;EAGX;EACA;EACA;CACF;AACF;AAEA,SAAS,UACP,MACA,aACA,QAAQ,OAQD;CACP,MAAM,QAAQ,KAAK,MAAM,GAAG;CAC5B,MAAM,OAAO,aAAa,MAAM,OAAO,aAAa,KAAK;CACzD,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,CAAC,aAAa,cAAc,MAAM,OAAO,IAAI;CACnD,OAAO;EACL,OAAO,KAAK,KAAK;EACjB;CACF;AACF;;;;;;;;AAgBA,SAAS,cACP,MACA,OACA,MAMkE;CAClE,MAAM,OAAO,YAAY,KAAK,IAAI;CAClC,IAAI,YAAkC;CACtC,MAAM,YAAoC,OAAO,OAAO,IAAI;;CAE5D,IAAI,YAAY,KAAK,SAAS,QAAQ;;CAEtC,IAAI,YAAY,KAAK,SAAS,QAAQ;;CAEtC,IAAI,YAAY,KAAK,SAAS,QAAQ;;CAEtC,IAAI,eAAe,KAAK,SAAS,WAAW;CAC5C,OAEE,YAAY,KAAK,QACjB,aAAa,aAAa,aAAa,gBACvC;EACA,MAAM,OAAO,KAAK;EAElB,IAAI,KAAK,SAAS,oBAAoB;EAEtC,IAAI,KAAK,SAAS,uBAAuB;GACvC;GACA;GACA;GACA;EACF;EACA,MAAM,OAAO,MAAM;EACnB,MAAM,mBAAmB;EACzB,IAAI,MAAM,aAAa,KAAK;EAC5B,IAAI,KAAK,SAAA,GAA6B;GACpC,cAAc,KAAK,KAAK,SAAS,MAAM,GAAG;GAC1C,MAAM,WAAW,UAAU;GAC3B,MAAM,YAAY,KAAK,QAAQ,UAAU;GAIzC,IAFsB,SAAS,WAAW,SAAS,MAAM,KAEtC;IACjB,MAAM,YAAY,KAAK,QAAQ,UAAU;IACzC,MAAM,OAAO,SAAS,UACpB,YAAY,GACZ,SAAS,SAAS,YAAY,CAChC;IACA,MAAM,QAAQ,KAAM,UAAU,WAAW,KAAM,SAAS,SAAS;IACjE,UAAU,QAAQ,mBAAmB,KAAK;GAC5C,OAAO;IACL,MAAM,OAAO,SAAS,UAAU,CAAC;IACjC,UAAU,QAAQ,mBAAmB,IAAK;GAC5C;EACF,OAAO,IAAI,KAAK,SAAA,GAAsC;GACpD,IAAI,KAAK,UAAW,KAAK,WAAY;IACnC;IACA,YAAY,mBAAmB;IAC/B;GACF;GACA,cAAc,KAAK,KAAK,SAAS,MAAM,GAAG;GAC1C,MAAM,WAAW,UAAU;GAC3B,MAAM,YAAY,KAAK,QAAQ,UAAU;GACzC,MAAM,YAAY,KAAK,QAAQ,UAAU;GACzC,MAAM,OAAO,SAAS,UACpB,YAAY,GACZ,SAAS,SAAS,YAAY,CAChC;GACA,MAAM,QACJ,KAAK,UAAU,KAAK,SAChB,KAAM,UAAU,WAAW,KAAM,SAAS,SAAS,IACnD;GACN,IAAI,OAAO,UAAU,QAAQ,mBAAmB,KAAK;EACvD,OAAO,IAAI,KAAK,SAAA,GAAgC;GAC9C,MAAM,IAAI;GACV,MAAM,QAAQ,KAAK,UACjB,oBAAoB,EAAE,QAAQ,UAAU,IACxC,KAAK,UAAU,EAAE,QAAQ,UAAU,EACrC;GACA,MAAM,QAAQ,mBAAmB,KAAK;GAEtC,UAAU,OAAO;GACjB,UAAU,SAAS;GACnB;EACF;CACF;CACA,IAAI,KAAK,WAAW,OAAO,OAAO,WAAW,KAAK,SAAS;CAC3D,OAAO,CACL,WACA;EACE,MAAM;EACN,MAAM;EACN,MAAM;EACN,SAAS;CACX,CACF;AACF;AAEA,SAAgB,iBAAsC,OAAU;CAC9D,MAAM,OAAO,CAAC,KAAK;CACnB,OAAO,MAAM,aAAa;EACxB,QAAQ,MAAM;EACd,KAAK,KAAK,KAAK;CACjB;CACA,KAAK,QAAQ;CACb,OAAO;AACT;AAEA,SAAS,YAAiC,MAAyB;CACjE,MAAM,OAAiC,MAAM,KAAK,QAAQ,CAAC;CAC3D,GAAG;EACD,KAAK,KAAK,SAAS;EACnB,OAAO,KAAK;CACd,SAAS;CACT,OAAO;AACT;AAuBA,SAAS,aACP,MACA,OACA,aACA,OACA;CAGA,IAAI,SAAS,OAAO,YAAY,OAC9B,OAAO;EAAE,MAAM,YAAY;EAAO,SAAS;CAAE;CAK/C,MAAM,gBAAgB,CAAC,KAAK,KAAK;CACjC,MAAM,cAAc,iBAAiB,SAAS;CAC9C,MAAM,cAAc,MAAM,UAAU,gBAAgB,IAAI;CAWxD,MAAM,QAAsB,CAC1B;EACE,MAAM;EACN,OAAO;EACP,SAAS;EACT,SAAS;EACT,UAAU;EACV,WAAW;CACb,CACF;CAEA,IAAI,YAA0B;CAC9B,IAAI,YAA0B;CAE9B,OAAO,MAAM,QAAQ;EACnB,MAAM,QAAQ,MAAM,IAAI;EACxB,MAAM,EAAE,MAAM,OAAO,SAAS,SAAS,UAAU,cAAc;EAC/D,IAAI,EAAE,SAAS,cAAc;EAM7B,IACE,KAAK,SAAA,KACL,KAAK,SACL,CAAC,oBAAoB,WAAW,KAAK,GAErC;EAGF,IAAI,KAAK,OAAO;GAEd,IAAI,CADW,oBAAoB,MAAM,OAAO,KAC3C,GAAQ;GACb,YAAY,MAAM;GAClB,UAAU,MAAM;EAClB;EAGA,IACE,SACA,KAAK,SACL,KAAK,SAAS,sBACd,oBAAoB,WAAW,KAAK,GAEpC,YAAY;EAGd,MAAM,eAAe,UAAU;EAC/B,IAAI,cAAc;GAChB,IACE,KAAK,UACJ,CAAC,eACA,KAAK,SAAS,sBACd,KAAK,SAAA,MACP,oBAAoB,WAAW,KAAK,GAEpC,YAAY;GAGd,IAAI,CAAC,KAAK,YAAY,CAAC,KAAK,YAAY,CAAC,KAAK,SAAS,CAAC,KAAK,UAC3D;EACJ;EAEA,MAAM,OAAO,eAAe,KAAA,IAAY,MAAM;EAC9C,IAAI;EAGJ,IAAI,gBAAgB,KAAK,OAAO;GAC9B,MAAM,aAAa;IACjB,MAAM,KAAK;IACX;IACA;IACA;IACA;IACA;IACA;IACA;GACF;GACA,IAAI,aAAa;GACjB,IAAI,KAAK,MAAM;QAET,CADW,oBAAoB,MAAM,OAAO,UAC3C,GAAQ,aAAa;GAAA;GAE5B,IAAI,YAAY;IAGd,IACE,CAAC,YACD,CAAC,aACD,CAAC,WACD,qBAAqB,SAAS,WAAW,GAEzC,OAAO;IAET,IAAI,oBAAoB,WAAW,UAAU,GAE3C,YAAY;GAEhB;EACF;EAGA,IAAI,KAAK,UACP,KAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;GAClD,MAAM,UAAU,KAAK,SAAS;GAC9B,MAAM,EAAE,QAAQ,WAAW;GAC3B,IAAI,QAAQ;IACV,IAAI,cAAc;IAIlB,IAAI,EAHa,QAAQ,gBACrB,OACC,cAAc,KAAM,YAAY,GACtB,WAAW,MAAM,GAAG;GACrC;GACA,IAAI,QAAQ;IACV,IAAI,cAAc;IAClB,MAAM,MAAM,MAAM,MAAM,KAAK,EAAE,KAAK,GAAG,EAAE,MAAM,CAAC,OAAO,MAAM;IAE7D,KADiB,QAAQ,gBAAgB,MAAM,IAAI,YAAY,OAC9C,QAAQ;GAC3B;GAEA,MAAM,KAAK;IACT,MAAM;IACN,OAAO;IACP;IACA;IACA;IACA;IACA;IACA;GACF,CAAC;EACH;EAIF,IAAI,KAAK,UAAU;GAEjB,MAAM,cAAc,UAAW,KAAM,KAAK,QAAQ;GAClD,KAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;IAClD,MAAM,UAAU,KAAK,SAAS;IAE9B,MAAM,KAAK;KACT,MAAM;KACN;KACA,SAAS;KACT;KACA;KACA;KACA;KACA;IACF,CAAC;GACH;GACA,IAAI,CAAC,cACH,KAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;IAClD,MAAM,UAAU,KAAK,SAAS;IAC9B,MAAM,EAAE,QAAQ,WAAW;IAC3B,IAAI,UAAU,QAAQ;KACpB,MAAM,WAAW,QAAQ,gBACrB,OACC,cAAc,KAAM,YAAY;KACrC,IAAI,UAAU,CAAC,SAAS,WAAW,MAAM,GAAG;KAC5C,IAAI,UAAU,CAAC,SAAS,SAAS,MAAM,GAAG;IAC5C;IACA,MAAM,KAAK;KACT,MAAM;KACN,OAAO,QAAQ;KACf;KACA;KACA;KACA,WAAW,YAAY,aAAa,aAAa,KAAK;KACtD;KACA;IACF,CAAC;GACH;EAEJ;EAGA,IAAI,CAAC,gBAAgB,KAAK,WAAW,MACnC,KAAK,IAAI,IAAI,KAAK,QAAQ,SAAS,GAAG,KAAK,GAAG,KAAK;GACjD,MAAM,UAAU,KAAK,QAAQ;GAC7B,MAAM,EAAE,QAAQ,WAAW;GAC3B,IAAI,UAAU,QAAQ;IACpB,MAAM,WAAW,QAAQ,gBACrB,OACC,cAAc,KAAK,YAAY;IACpC,IAAI,UAAU,CAAC,SAAS,WAAW,MAAM,GAAG;IAC5C,IAAI,UAAU,CAAC,SAAS,SAAS,MAAM,GAAG;GAC5C;GACA,MAAM,KAAK;IACT,MAAM;IACN,OAAO,QAAQ;IACf;IACA;IACA,UAAU,WAAW,aAAa,aAAa,KAAK;IACpD;IACA;IACA;GACF,CAAC;EACH;EAIF,IAAI,CAAC,gBAAgB,KAAK,mBAAmB;GAC3C,MAAM,QAAQ,KAAK,kBAAkB,IAClC,cAAc,KAAM,YAAY,CACnC;GACA,IAAI,OACF,MAAM,KAAK;IACT,MAAM;IACN,OAAO,QAAQ;IACf;IACA,SAAS,UAAU,aAAa,aAAa,KAAK;IAClD;IACA;IACA;IACA;GACF,CAAC;EAEL;EAGA,IAAI,CAAC,gBAAgB,KAAK,QAAQ;GAChC,MAAM,QAAQ,KAAK,OAAO,IAAI,IAAK;GACnC,IAAI,OACF,MAAM,KAAK;IACT,MAAM;IACN,OAAO,QAAQ;IACf;IACA,SAAS,UAAU,aAAa,aAAa,KAAK;IAClD;IACA;IACA;IACA;GACF,CAAC;EAEL;EAGA,IAAI,KAAK,UACP,KAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;GAClD,MAAM,UAAU,KAAK,SAAS;GAC9B,MAAM,KAAK;IACT,MAAM;IACN;IACA;IACA;IACA;IACA;IACA;IACA;GACF,CAAC;EACH;CAEJ;CAEA,IAAI,WAAW,OAAO;CAEtB,IAAI,SAAS,WAAW;EACtB,IAAI,aAAa,UAAU;EAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,OAAO,KACnC,cAAc,MAAM,GAAI;EAE1B,MAAM,QAAQ,eAAe,KAAK,SAAS,MAAM,KAAK,MAAM,UAAU;EACtE,UAAU,cAAc,OAAO,OAAO,IAAI;EAC1C,UAAU,UAAW,QAAQ,mBAAmB,KAAK;EACrD,OAAO;CACT;CAEA,OAAO;AACT;AAEA,SAAS,aAAa,aAAqB,OAAuB;CAMhE,OAAO,MAAM,cAAc,QAAQ;AACrC;AAEA,SAAS,qBAAqB,SAAiB,aAA8B;CAC3E,OAAO,YAAY,MAAM,cAAc,KAAK;AAC9C;AAEA,SAAS,oBACP,MACA,OACA,OACA;CACA,IAAI;CACJ,IAAI;CAEJ,IAAI;EACD,CAAC,WAAW,SAAS,cAAc,MAAM,OAAO,KAAK;CACxD,QAAQ;EACN,OAAO;CACT;CAEA,MAAM,YAAY;CAClB,MAAM,UAAU;CAEhB,IAAI,CAAC,MAAM,KAAK,OAAO,OAAO;CAE9B,IAAI;EACF,IAAI,MAAM,KAAK,MAAM,SAAS,MAAM,OAAO,OAAO;CACpD,QAAQ,CAGR;CAEA,OAAO;AACT;AAEA,SAAS,oBAEP,MAEA,MACS;CACT,IAAI,CAAC,MAAM,OAAO;CAClB,OACE,KAAK,UAAU,KAAK,WACnB,KAAK,YAAY,KAAK,YACpB,KAAK,WAAW,KAAK,YACnB,KAAK,aAAa,KAAK,aACrB,KAAK,YAAY,KAAK,aACpB,KAAK,cAAc,KAAK,eACrB,KAAK,KAAK,SAAS,uBAClB,KAAK,KAAK,SAAS,uBAClB,KAAK,KAAK,SAAS,wBAClB,KAAK,KAAK,SAAS,uBACpB,KAAK,KAAK,QAAQ,KAAK,KAAK;AAE9C"}

@@ -348,30 +348,21 @@ import { DEFAULT_PROTOCOL_ALLOWLIST, decodePath, deepEqual, encodePathLikeUrl, findLast, functionalUpdate, hasKeys, isDangerousProtocol, last, nullReplaceEqualDeep, replaceEqualDeep } from "./utils.js";

};
const buildWithMatches = (dest = {}, maskedDest) => {
const next = build(dest);
let maskedNext = maskedDest ? build(maskedDest) : void 0;
if (!maskedNext) {
const params = Object.create(null);
if (this.options.routeMasks) {
const match = findFlatMatch(next.pathname, this.processedTree);
if (match) {
Object.assign(params, match.rawParams);
const { from: _from, params: maskParams, ...maskProps } = match.route;
const nextParams = resolveNextParams(maskParams, params);
maskedDest = {
from: opts.from,
...maskProps,
params: nextParams
};
maskedNext = build(maskedDest);
}
}
}
if (maskedNext) next.maskedLocation = maskedNext;
return next;
};
if (opts.mask) return buildWithMatches(opts, {
const next = build(opts);
if (opts.mask) next.maskedLocation = build({
from: opts.from,
...opts.mask
});
return buildWithMatches(opts);
else if (this.options.routeMasks) {
const match = findFlatMatch(next.pathname, this.processedTree);
if (match) {
const params = Object.assign(Object.create(null), match.rawParams);
const { from: _from, params: maskParams, ...maskProps } = match.route;
const nextParams = resolveNextParams(maskParams, params);
next.maskedLocation = build({
from: opts.from,
...maskProps,
params: nextParams
});
}
}
return next;
};

@@ -378,0 +369,0 @@ this.commitLocation = async ({ viewTransition, ignoreBlocker, ...next }) => {

@@ -10,5 +10,2 @@ import { isServer } from "@tanstack/router-core/isServer";

}
function isFunction(d) {
return typeof d === "function";
}
/**

@@ -19,3 +16,3 @@ * Apply a value-or-updater to a previous value.

function functionalUpdate(updater, previous) {
if (isFunction(updater)) return updater(previous);
if (typeof updater === "function") return updater(previous);
return updater;

@@ -22,0 +19,0 @@ }

@@ -1,1 +0,1 @@

{"version":3,"file":"utils.js","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["import { isServer } from '@tanstack/router-core/isServer'\nimport type { RouteIds } from './routeInfo'\nimport type { AnyRouter } from './router'\n\nexport type Awaitable<T> = T | Promise<T>\nexport type NoInfer<T> = [T][T extends any ? 0 : never]\nexport type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue\n ? TYesResult\n : TNoResult\n\nexport type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<\n TValue,\n TKey\n> &\n Required<Pick<TValue, TKey>>\n\nexport type PickRequired<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K]\n}\n\nexport type PickOptional<T> = {\n [K in keyof T as undefined extends T[K] ? K : never]: T[K]\n}\n\n// from https://stackoverflow.com/a/76458160\nexport type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never\n\nexport type Expand<T> = T extends object\n ? T extends infer O\n ? O extends Function\n ? O\n : { [K in keyof O]: O[K] }\n : never\n : T\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nexport type MakeDifferenceOptional<TLeft, TRight> = keyof TLeft &\n keyof TRight extends never\n ? TRight\n : Omit<TRight, keyof TLeft & keyof TRight> & {\n [K in keyof TLeft & keyof TRight]?: TRight[K]\n }\n\n// from https://stackoverflow.com/a/53955431\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type IsUnion<T, U extends T = T> = (\n T extends any ? (U extends T ? false : true) : never\n) extends false\n ? false\n : true\n\nexport type IsNonEmptyObject<T> = T extends object\n ? keyof T extends never\n ? false\n : true\n : false\n\nexport type Assign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : keyof TLeft & keyof TRight extends never\n ? TLeft & TRight\n : Omit<TLeft, keyof TRight> & TRight\n : never\n : never\n\nexport type IntersectAssign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : TRight & TLeft\n : never\n : never\n\nexport type Timeout = ReturnType<typeof setTimeout>\n\nexport type Updater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev?: TPrevious) => TResult)\n\nexport type NonNullableUpdater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev: TPrevious) => TResult)\n\nexport type ExtractObjects<TUnion> = TUnion extends MergeAllPrimitive\n ? never\n : TUnion\n\nexport type PartialMergeAllObject<TUnion> =\n ExtractObjects<TUnion> extends infer TObj\n ? [TObj] extends [never]\n ? never\n : {\n [TKey in TObj extends any ? keyof TObj : never]?: TObj extends any\n ? TKey extends keyof TObj\n ? TObj[TKey]\n : never\n : never\n }\n : never\n\nexport type MergeAllPrimitive =\n | ReadonlyArray<any>\n | number\n | string\n | bigint\n | boolean\n | symbol\n | undefined\n | null\n\nexport type ExtractPrimitives<TUnion> = TUnion extends MergeAllPrimitive\n ? TUnion\n : TUnion extends object\n ? never\n : TUnion\n\nexport type PartialMergeAll<TUnion> =\n | ExtractPrimitives<TUnion>\n | PartialMergeAllObject<TUnion>\n\nexport type Constrain<T, TConstraint, TDefault = TConstraint> =\n | (T extends TConstraint ? T : never)\n | TDefault\n\nexport type ConstrainLiteral<T, TConstraint, TDefault = TConstraint> =\n | (T & TConstraint)\n | TDefault\n\n/**\n * To be added to router types\n */\nexport type UnionToIntersection<T> = (\n T extends any ? (arg: T) => any : never\n) extends (arg: infer T) => any\n ? T\n : never\n\n/**\n * Merges everything in a union into one object.\n * This mapped type is homomorphic which means it preserves stuff! :)\n */\nexport type MergeAllObjects<\n TUnion,\n TIntersected = UnionToIntersection<ExtractObjects<TUnion>>,\n> = [keyof TIntersected] extends [never]\n ? never\n : {\n [TKey in keyof TIntersected]: TUnion extends any\n ? TUnion[TKey & keyof TUnion]\n : never\n }\n\nexport type MergeAll<TUnion> =\n | MergeAllObjects<TUnion>\n | ExtractPrimitives<TUnion>\n\nexport type ValidateJSON<T> = ((...args: Array<any>) => any) extends T\n ? unknown extends T\n ? never\n : 'Function is not serializable'\n : { [K in keyof T]: ValidateJSON<T[K]> }\n\nexport type LooseReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn\n : never\n\nexport type LooseAsyncReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn extends Promise<infer TReturn>\n ? TReturn\n : TReturn\n : never\n\n/**\n * Return the last element of an array.\n * Intended for non-empty arrays used within router internals.\n */\nexport function last<T>(arr: ReadonlyArray<T>) {\n return arr[arr.length - 1]\n}\n\nfunction isFunction(d: any): d is Function {\n return typeof d === 'function'\n}\n\n/**\n * Apply a value-or-updater to a previous value.\n * Accepts either a literal value or a function of the previous value.\n */\nexport function functionalUpdate<TPrevious, TResult = TPrevious>(\n updater: Updater<TPrevious, TResult> | NonNullableUpdater<TPrevious, TResult>,\n previous: TPrevious,\n): TResult {\n if (isFunction(updater)) {\n return updater(previous)\n }\n\n return updater\n}\n\nexport const hasOwn = Object.prototype.hasOwnProperty\nconst isEnumerable = Object.prototype.propertyIsEnumerable\n\nexport function hasKeys(obj: Record<string, unknown>) {\n for (const key in obj) {\n if (hasOwn.call(obj, key)) return true\n }\n return false\n}\n\nexport const createNull = () => Object.create(null)\nexport const nullReplaceEqualDeep: typeof replaceEqualDeep = (prev, next) =>\n replaceEqualDeep(prev, next, createNull)\n\n/**\n * This function returns `prev` if `_next` is deeply equal.\n * If not, it will replace any deeply equal children of `b` with those of `a`.\n * This can be used for structural sharing between immutable JSON values for example.\n * Do not use this with signals\n */\nexport function replaceEqualDeep<T>(\n prev: any,\n _next: T,\n _makeObj = () => ({}),\n _depth = 0,\n): T {\n if (isServer) {\n return _next\n }\n if (prev === _next) {\n return prev\n }\n\n if (_depth > 500) return _next\n\n const next = _next as any\n\n const array = isPlainArray(prev) && isPlainArray(next)\n\n if (!array && !(isPlainObject(prev) && isPlainObject(next))) return next\n\n const prevItems = array ? prev : getEnumerableOwnKeys(prev)\n if (!prevItems) return next\n const nextItems = array ? next : getEnumerableOwnKeys(next)\n if (!nextItems) return next\n const prevSize = prevItems.length\n const nextSize = nextItems.length\n const copy: any = array ? new Array(nextSize) : _makeObj()\n\n let equalItems = 0\n\n for (let i = 0; i < nextSize; i++) {\n const key = array ? i : (nextItems[i] as any)\n const p = prev[key]\n const n = next[key]\n\n if (p === n) {\n copy[key] = p\n if (array ? i < prevSize : hasOwn.call(prev, key)) equalItems++\n continue\n }\n\n if (\n p === null ||\n n === null ||\n typeof p !== 'object' ||\n typeof n !== 'object'\n ) {\n copy[key] = n\n continue\n }\n\n const v = replaceEqualDeep(p, n, _makeObj, _depth + 1)\n copy[key] = v\n if (v === p) equalItems++\n }\n\n return prevSize === nextSize && equalItems === prevSize ? prev : copy\n}\n\n/**\n * Equivalent to `Reflect.ownKeys`, but ensures that objects are \"clone-friendly\":\n * will return false if object has any non-enumerable properties.\n *\n * Optimized for the common case where objects have no symbol properties.\n */\nfunction getEnumerableOwnKeys(o: object) {\n // `Object.keys` returns only enumerable own string keys natively (no per-key\n // JS callback). If it has fewer entries than `getOwnPropertyNames` (all own\n // string keys), the object has a non-enumerable own string prop and is not\n // \"clone-friendly\" -> bail. This replaces an O(n) loop of\n // `propertyIsEnumerable` calls with two native calls.\n const keys = Object.keys(o)\n if (keys.length !== Object.getOwnPropertyNames(o).length) {\n return false\n }\n\n // Only check symbols if the object has any (most plain objects don't)\n const symbols = Object.getOwnPropertySymbols(o)\n\n // Fast path: no symbols, return enumerable string keys directly\n if (symbols.length === 0) {\n return keys\n }\n\n // Slow path: has symbols, include only enumerable ones, bail on any\n // non-enumerable symbol so it round-trips like the string-key check above.\n for (const symbol of symbols) {\n if (!isEnumerable.call(o, symbol)) {\n return false\n }\n ;(keys as Array<string | symbol>).push(symbol)\n }\n return keys\n}\n\n// Copied from: https://github.com/jonschlinkert/is-plain-object\nexport function isPlainObject(o: any) {\n if (!hasObjectPrototype(o)) {\n return false\n }\n\n // If has modified constructor\n const ctor = o.constructor\n if (typeof ctor === 'undefined') {\n return true\n }\n\n // If has modified prototype\n const prot = ctor.prototype\n if (!hasObjectPrototype(prot)) {\n return false\n }\n\n // If constructor does not have an Object-specific method\n if (!prot.hasOwnProperty('isPrototypeOf')) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n\nfunction hasObjectPrototype(o: any) {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\n/**\n * Check if a value is a \"plain\" array (no extra enumerable keys).\n */\nexport function isPlainArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value) && value.length === Object.keys(value).length\n}\n\n/**\n * Perform a deep equality check with options for partial comparison and\n * ignoring `undefined` values. Optimized for router state comparisons.\n */\nexport function deepEqual(\n a: any,\n b: any,\n opts?: { partial?: boolean; ignoreUndefined?: boolean },\n): boolean {\n if (a === b) {\n return true\n }\n\n if (typeof a !== typeof b) {\n return false\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0, l = a.length; i < l; i++) {\n if (!deepEqual(a[i], b[i], opts)) return false\n }\n return true\n }\n\n if (isPlainObject(a) && isPlainObject(b)) {\n const ignoreUndefined = opts?.ignoreUndefined ?? true\n\n if (opts?.partial) {\n for (const k in b) {\n if (!ignoreUndefined || b[k] !== undefined) {\n if (!deepEqual(a[k], b[k], opts)) return false\n }\n }\n return true\n }\n\n let aCount = 0\n if (!ignoreUndefined) {\n aCount = Object.keys(a).length\n } else {\n for (const k in a) {\n if (a[k] !== undefined) aCount++\n }\n }\n\n let bCount = 0\n for (const k in b) {\n if (!ignoreUndefined || b[k] !== undefined) {\n bCount++\n if (bCount > aCount || !deepEqual(a[k], b[k], opts)) return false\n }\n }\n\n return aCount === bCount\n }\n\n return false\n}\n\nexport type StringLiteral<T> = T extends string\n ? string extends T\n ? string\n : T\n : never\n\nexport type ThrowOrOptional<T, TThrow extends boolean> = TThrow extends true\n ? T\n : T | undefined\n\nexport type StrictOrFrom<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean = true,\n> = TStrict extends false\n ? {\n from?: never\n strict: TStrict\n }\n : {\n from: ConstrainLiteral<TFrom, RouteIds<TRouter['routeTree']>>\n strict?: TStrict\n }\n\nexport type ThrowConstraint<\n TStrict extends boolean,\n TThrow extends boolean,\n> = TStrict extends false ? (TThrow extends true ? never : TThrow) : TThrow\n\nexport type ControlledPromise<T> = Promise<T> & {\n resolve: (value: T) => void\n reject: (value: any) => void\n status: 'pending' | 'resolved' | 'rejected'\n value?: T\n}\n\n/**\n * Create a promise with exposed resolve/reject and status fields.\n * Useful for coordinating async router lifecycle operations.\n */\nexport function createControlledPromise<T>(onResolve?: (value: T) => void) {\n let resolveLoadPromise!: (value: T) => void\n let rejectLoadPromise!: (value: any) => void\n\n const controlledPromise = new Promise<T>((resolve, reject) => {\n resolveLoadPromise = resolve\n rejectLoadPromise = reject\n }) as ControlledPromise<T>\n\n controlledPromise.status = 'pending'\n\n controlledPromise.resolve = (value: T) => {\n controlledPromise.status = 'resolved'\n controlledPromise.value = value\n resolveLoadPromise(value)\n onResolve?.(value)\n }\n\n controlledPromise.reject = (e) => {\n controlledPromise.status = 'rejected'\n rejectLoadPromise(e)\n }\n\n return controlledPromise\n}\n\n/**\n * Heuristically detect dynamic import \"module not found\" errors\n * across major browsers for lazy route component handling.\n */\nexport function isModuleNotFoundError(error: any): boolean {\n // chrome: \"Failed to fetch dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split\"\n // firefox: \"error loading dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split\"\n // safari: \"Importing a module script failed.\"\n if (typeof error?.message !== 'string') return false\n return (\n error.message.startsWith('Failed to fetch dynamically imported module') ||\n error.message.startsWith('error loading dynamically imported module') ||\n error.message.startsWith('Importing a module script failed')\n )\n}\n\nexport function isPromise<T>(\n value: Promise<Awaited<T>> | T,\n): value is Promise<Awaited<T>> {\n return Boolean(\n value &&\n typeof value === 'object' &&\n typeof (value as Promise<T>).then === 'function',\n )\n}\n\nexport function findLast<T>(\n array: ReadonlyArray<T>,\n predicate: (item: T) => boolean,\n): T | undefined {\n for (let i = array.length - 1; i >= 0; i--) {\n const item = array[i]!\n if (predicate(item)) return item\n }\n return undefined\n}\n\n/**\n * Re-encode characters that are unsafe in URL paths.\n * Includes ASCII control characters (0x00-0x1F, 0x7F) and a subset of the\n * WHATWG URL \"path percent-encode set\" (\", <, >, `, {, }).\n *\n * Space (0x20) is intentionally excluded — decodeURI decodes %20 to space\n * and the router stores decoded spaces in location.pathname. The existing\n * encodePathLikeUrl already handles re-encoding spaces for outgoing URLs.\n *\n * These characters are decoded by decodeURI but must remain percent-encoded\n * in paths to match how upstream layers (CDNs, edge middleware, browsers)\n * interpret the URL, preventing infinite redirect loops and path mismatches.\n */\n// eslint-disable-next-line no-control-regex\nconst PATH_UNSAFE_RE = /[\\x00-\\x1f\\x7f\"<>`{}]/g\n\nfunction sanitizePathSegment(segment: string): string {\n return segment.replace(\n PATH_UNSAFE_RE,\n (ch) => '%' + ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'),\n )\n}\n\nfunction decodeSegment(segment: string): string {\n let decoded: string\n try {\n decoded = decodeURI(segment)\n } catch {\n // if the decoding fails, try to decode the various parts leaving the malformed tags in place\n decoded = segment.replaceAll(/%[0-9A-F]{2}/gi, (match) => {\n try {\n return decodeURI(match)\n } catch {\n return match\n }\n })\n }\n return sanitizePathSegment(decoded)\n}\n\n/**\n * Default list of URL protocols to allow in links, redirects, and navigation.\n * Any absolute URL protocol not in this list is treated as dangerous by default.\n */\nexport const DEFAULT_PROTOCOL_ALLOWLIST = [\n // Standard web navigation\n 'http:',\n 'https:',\n\n // Common browser-safe actions\n 'mailto:',\n 'tel:',\n]\n\n/**\n * Check if a URL string uses a protocol that is not in the allowlist.\n * Returns true for blocked protocols like javascript:, blob:, data:, etc.\n *\n * The URL constructor correctly normalizes:\n * - Mixed case (JavaScript: → javascript:)\n * - Whitespace/control characters (java\\nscript: → javascript:)\n * - Leading whitespace\n *\n * For relative URLs (no protocol), returns false (safe).\n *\n * @param url - The URL string to check\n * @param allowlist - Set of protocols to allow\n * @returns true if the URL uses a protocol that is not allowed\n */\nexport function isDangerousProtocol(\n url: string,\n allowlist: Set<string>,\n): boolean {\n if (!url) return false\n\n try {\n // Use the URL constructor - it correctly normalizes protocols\n // per WHATWG URL spec, handling all bypass attempts automatically\n const parsed = new URL(url)\n return !allowlist.has(parsed.protocol)\n } catch {\n // URL constructor throws for relative URLs (no protocol)\n // These are safe - they can't execute scripts\n return false\n }\n}\n\n// This utility is based on https://github.com/zertosh/htmlescape\n// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE\nconst HTML_ESCAPE_LOOKUP: { [match: string]: string } = {\n '&': '\\\\u0026',\n '>': '\\\\u003e',\n '<': '\\\\u003c',\n '\\u2028': '\\\\u2028',\n '\\u2029': '\\\\u2029',\n}\n\nconst HTML_ESCAPE_REGEX = /[&><\\u2028\\u2029]/g\n\n/**\n * Escape HTML special characters in a string to prevent XSS attacks\n * when embedding strings in script tags during SSR.\n *\n * This is essential for preventing XSS vulnerabilities when user-controlled\n * content is embedded in inline scripts.\n */\nexport function escapeHtml(str: string): string {\n return str.replace(HTML_ESCAPE_REGEX, (match) => HTML_ESCAPE_LOOKUP[match]!)\n}\n\nexport function decodePath(path: string) {\n if (!path) return { path, handledProtocolRelativeURL: false }\n\n // Fast path: most paths are already decoded and safe.\n // Only fall back to the slower scan/regex path when we see a '%' (encoded),\n // a backslash (explicitly handled), a control character, or a protocol-relative\n // prefix which needs collapsing.\n // eslint-disable-next-line no-control-regex\n if (!/[%\\\\\\x00-\\x1f\\x7f]/.test(path) && !path.startsWith('//')) {\n return { path, handledProtocolRelativeURL: false }\n }\n\n const re = /%25|%5C/gi\n let cursor = 0\n let result = ''\n let match\n while (null !== (match = re.exec(path))) {\n result += decodeSegment(path.slice(cursor, match.index)) + match[0]\n cursor = re.lastIndex\n }\n result = result + decodeSegment(cursor ? path.slice(cursor) : path)\n\n // Prevent open redirect via protocol-relative URLs (e.g. \"//evil.com\")\n // This is defense-in-depth: since control characters are no longer decoded,\n // paths like \"/%0d/evil.com\" can no longer become \"//evil.com\". But we keep\n // this check to guard against other edge cases.\n let handledProtocolRelativeURL = false\n if (result.startsWith('//')) {\n handledProtocolRelativeURL = true\n result = '/' + result.replace(/^\\/+/, '')\n }\n\n return { path: result, handledProtocolRelativeURL }\n}\n\n/**\n * Encodes a path the same way `new URL()` would, but without the overhead of full URL parsing.\n *\n * This function encodes:\n * - Whitespace characters (spaces → %20, tabs → %09, etc.)\n * - Non-ASCII/Unicode characters (emojis, accented characters, etc.)\n *\n * It preserves:\n * - Already percent-encoded sequences (won't double-encode %2F, %25, etc.)\n * - ASCII special characters valid in URL paths (@, $, &, +, etc.)\n * - Forward slashes as path separators\n *\n * Used to generate proper href values for SSR without constructing URL objects.\n *\n * @example\n * encodePathLikeUrl('/path/file name.pdf') // '/path/file%20name.pdf'\n * encodePathLikeUrl('/path/日本語') // '/path/%E6%97%A5%E6%9C%AC%E8%AA%9E'\n * encodePathLikeUrl('/path/already%20encoded') // '/path/already%20encoded' (preserved)\n */\nexport function encodePathLikeUrl(path: string): string {\n // Encode whitespace and non-ASCII characters that browsers encode in URLs\n\n // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ASCII range check\n // eslint-disable-next-line no-control-regex\n if (!/\\s|[^\\u0000-\\u007F]/.test(path)) return path\n // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ASCII range check\n // eslint-disable-next-line no-control-regex\n return path.replace(/\\s|[^\\u0000-\\u007F]/gu, encodeURIComponent)\n}\n\n/**\n * Builds the dev-mode CSS styles URL for route-scoped CSS collection.\n * Used by HeadContent components in all framework implementations to construct\n * the URL for the `/@tanstack-start/styles.css` endpoint.\n *\n * @param basepath - The router's basepath (may or may not have leading slash)\n * @param routeIds - Array of matched route IDs to include in the CSS collection\n * @returns The full URL path for the dev styles CSS endpoint\n */\nexport function buildDevStylesUrl(\n basepath: string,\n routeIds: Array<string>,\n): string {\n // Trim all leading and trailing slashes from basepath\n const trimmedBasepath = basepath.replace(/^\\/+|\\/+$/g, '')\n // Build normalized basepath: empty string for root, or '/path' for non-root\n const normalizedBasepath = trimmedBasepath === '' ? '' : `/${trimmedBasepath}`\n return `${normalizedBasepath}/@tanstack-start/styles.css?routes=${encodeURIComponent(routeIds.join(','))}`\n}\n\nexport function arraysEqual<T>(a: Array<T>, b: Array<T>) {\n if (a === b) return true\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false\n }\n return true\n}\n"],"mappings":"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"}
{"version":3,"file":"utils.js","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["import { isServer } from '@tanstack/router-core/isServer'\nimport type { RouteIds } from './routeInfo'\nimport type { AnyRouter } from './router'\n\nexport type Awaitable<T> = T | Promise<T>\nexport type NoInfer<T> = [T][T extends any ? 0 : never]\nexport type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue\n ? TYesResult\n : TNoResult\n\nexport type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<\n TValue,\n TKey\n> &\n Required<Pick<TValue, TKey>>\n\nexport type PickRequired<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K]\n}\n\nexport type PickOptional<T> = {\n [K in keyof T as undefined extends T[K] ? K : never]: T[K]\n}\n\n// from https://stackoverflow.com/a/76458160\nexport type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never\n\nexport type Expand<T> = T extends object\n ? T extends infer O\n ? O extends Function\n ? O\n : { [K in keyof O]: O[K] }\n : never\n : T\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nexport type MakeDifferenceOptional<TLeft, TRight> = keyof TLeft &\n keyof TRight extends never\n ? TRight\n : Omit<TRight, keyof TLeft & keyof TRight> & {\n [K in keyof TLeft & keyof TRight]?: TRight[K]\n }\n\n// from https://stackoverflow.com/a/53955431\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport type IsUnion<T, U extends T = T> = (\n T extends any ? (U extends T ? false : true) : never\n) extends false\n ? false\n : true\n\nexport type IsNonEmptyObject<T> = T extends object\n ? keyof T extends never\n ? false\n : true\n : false\n\nexport type Assign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : keyof TLeft & keyof TRight extends never\n ? TLeft & TRight\n : Omit<TLeft, keyof TRight> & TRight\n : never\n : never\n\nexport type IntersectAssign<TLeft, TRight> = TLeft extends any\n ? TRight extends any\n ? IsNonEmptyObject<TLeft> extends false\n ? TRight\n : IsNonEmptyObject<TRight> extends false\n ? TLeft\n : TRight & TLeft\n : never\n : never\n\nexport type Timeout = ReturnType<typeof setTimeout>\n\nexport type Updater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev?: TPrevious) => TResult)\n\nexport type NonNullableUpdater<TPrevious, TResult = TPrevious> =\n | TResult\n | ((prev: TPrevious) => TResult)\n\nexport type ExtractObjects<TUnion> = TUnion extends MergeAllPrimitive\n ? never\n : TUnion\n\nexport type PartialMergeAllObject<TUnion> =\n ExtractObjects<TUnion> extends infer TObj\n ? [TObj] extends [never]\n ? never\n : {\n [TKey in TObj extends any ? keyof TObj : never]?: TObj extends any\n ? TKey extends keyof TObj\n ? TObj[TKey]\n : never\n : never\n }\n : never\n\nexport type MergeAllPrimitive =\n | ReadonlyArray<any>\n | number\n | string\n | bigint\n | boolean\n | symbol\n | undefined\n | null\n\nexport type ExtractPrimitives<TUnion> = TUnion extends MergeAllPrimitive\n ? TUnion\n : TUnion extends object\n ? never\n : TUnion\n\nexport type PartialMergeAll<TUnion> =\n | ExtractPrimitives<TUnion>\n | PartialMergeAllObject<TUnion>\n\nexport type Constrain<T, TConstraint, TDefault = TConstraint> =\n | (T extends TConstraint ? T : never)\n | TDefault\n\nexport type ConstrainLiteral<T, TConstraint, TDefault = TConstraint> =\n | (T & TConstraint)\n | TDefault\n\n/**\n * To be added to router types\n */\nexport type UnionToIntersection<T> = (\n T extends any ? (arg: T) => any : never\n) extends (arg: infer T) => any\n ? T\n : never\n\n/**\n * Merges everything in a union into one object.\n * This mapped type is homomorphic which means it preserves stuff! :)\n */\nexport type MergeAllObjects<\n TUnion,\n TIntersected = UnionToIntersection<ExtractObjects<TUnion>>,\n> = [keyof TIntersected] extends [never]\n ? never\n : {\n [TKey in keyof TIntersected]: TUnion extends any\n ? TUnion[TKey & keyof TUnion]\n : never\n }\n\nexport type MergeAll<TUnion> =\n | MergeAllObjects<TUnion>\n | ExtractPrimitives<TUnion>\n\nexport type ValidateJSON<T> = ((...args: Array<any>) => any) extends T\n ? unknown extends T\n ? never\n : 'Function is not serializable'\n : { [K in keyof T]: ValidateJSON<T[K]> }\n\nexport type LooseReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn\n : never\n\nexport type LooseAsyncReturnType<T> = T extends (\n ...args: Array<any>\n) => infer TReturn\n ? TReturn extends Promise<infer TReturn>\n ? TReturn\n : TReturn\n : never\n\n/**\n * Return the last element of an array.\n * Intended for non-empty arrays used within router internals.\n */\nexport function last<T>(arr: ReadonlyArray<T>) {\n return arr[arr.length - 1]\n}\n\n/**\n * Apply a value-or-updater to a previous value.\n * Accepts either a literal value or a function of the previous value.\n */\nexport function functionalUpdate<TPrevious, TResult = TPrevious>(\n updater: Updater<TPrevious, TResult> | NonNullableUpdater<TPrevious, TResult>,\n previous: TPrevious,\n): TResult {\n if (typeof updater === 'function') {\n return (updater as Function)(previous)\n }\n\n return updater\n}\n\nexport const hasOwn = Object.prototype.hasOwnProperty\nconst isEnumerable = Object.prototype.propertyIsEnumerable\n\nexport function hasKeys(obj: Record<string, unknown>) {\n for (const key in obj) {\n if (hasOwn.call(obj, key)) return true\n }\n return false\n}\n\nexport const createNull = () => Object.create(null)\nexport const nullReplaceEqualDeep: typeof replaceEqualDeep = (prev, next) =>\n replaceEqualDeep(prev, next, createNull)\n\n/**\n * This function returns `prev` if `_next` is deeply equal.\n * If not, it will replace any deeply equal children of `b` with those of `a`.\n * This can be used for structural sharing between immutable JSON values for example.\n * Do not use this with signals\n */\nexport function replaceEqualDeep<T>(\n prev: any,\n _next: T,\n _makeObj = () => ({}),\n _depth = 0,\n): T {\n if (isServer) {\n return _next\n }\n if (prev === _next) {\n return prev\n }\n\n if (_depth > 500) return _next\n\n const next = _next as any\n\n const array = isPlainArray(prev) && isPlainArray(next)\n\n if (!array && !(isPlainObject(prev) && isPlainObject(next))) return next\n\n const prevItems = array ? prev : getEnumerableOwnKeys(prev)\n if (!prevItems) return next\n const nextItems = array ? next : getEnumerableOwnKeys(next)\n if (!nextItems) return next\n const prevSize = prevItems.length\n const nextSize = nextItems.length\n const copy: any = array ? new Array(nextSize) : _makeObj()\n\n let equalItems = 0\n\n for (let i = 0; i < nextSize; i++) {\n const key = array ? i : (nextItems[i] as any)\n const p = prev[key]\n const n = next[key]\n\n if (p === n) {\n copy[key] = p\n if (array ? i < prevSize : hasOwn.call(prev, key)) equalItems++\n continue\n }\n\n if (\n p === null ||\n n === null ||\n typeof p !== 'object' ||\n typeof n !== 'object'\n ) {\n copy[key] = n\n continue\n }\n\n const v = replaceEqualDeep(p, n, _makeObj, _depth + 1)\n copy[key] = v\n if (v === p) equalItems++\n }\n\n return prevSize === nextSize && equalItems === prevSize ? prev : copy\n}\n\n/**\n * Equivalent to `Reflect.ownKeys`, but ensures that objects are \"clone-friendly\":\n * will return false if object has any non-enumerable properties.\n *\n * Optimized for the common case where objects have no symbol properties.\n */\nfunction getEnumerableOwnKeys(o: object) {\n // `Object.keys` returns only enumerable own string keys natively (no per-key\n // JS callback). If it has fewer entries than `getOwnPropertyNames` (all own\n // string keys), the object has a non-enumerable own string prop and is not\n // \"clone-friendly\" -> bail. This replaces an O(n) loop of\n // `propertyIsEnumerable` calls with two native calls.\n const keys = Object.keys(o)\n if (keys.length !== Object.getOwnPropertyNames(o).length) {\n return false\n }\n\n // Only check symbols if the object has any (most plain objects don't)\n const symbols = Object.getOwnPropertySymbols(o)\n\n // Fast path: no symbols, return enumerable string keys directly\n if (symbols.length === 0) {\n return keys\n }\n\n // Slow path: has symbols, include only enumerable ones, bail on any\n // non-enumerable symbol so it round-trips like the string-key check above.\n for (const symbol of symbols) {\n if (!isEnumerable.call(o, symbol)) {\n return false\n }\n ;(keys as Array<string | symbol>).push(symbol)\n }\n return keys\n}\n\n// Copied from: https://github.com/jonschlinkert/is-plain-object\nexport function isPlainObject(o: any) {\n if (!hasObjectPrototype(o)) {\n return false\n }\n\n // If has modified constructor\n const ctor = o.constructor\n if (typeof ctor === 'undefined') {\n return true\n }\n\n // If has modified prototype\n const prot = ctor.prototype\n if (!hasObjectPrototype(prot)) {\n return false\n }\n\n // If constructor does not have an Object-specific method\n if (!prot.hasOwnProperty('isPrototypeOf')) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n\nfunction hasObjectPrototype(o: any) {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\n/**\n * Check if a value is a \"plain\" array (no extra enumerable keys).\n */\nexport function isPlainArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value) && value.length === Object.keys(value).length\n}\n\n/**\n * Perform a deep equality check with options for partial comparison and\n * ignoring `undefined` values. Optimized for router state comparisons.\n */\nexport function deepEqual(\n a: any,\n b: any,\n opts?: { partial?: boolean; ignoreUndefined?: boolean },\n): boolean {\n if (a === b) {\n return true\n }\n\n if (typeof a !== typeof b) {\n return false\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n for (let i = 0, l = a.length; i < l; i++) {\n if (!deepEqual(a[i], b[i], opts)) return false\n }\n return true\n }\n\n if (isPlainObject(a) && isPlainObject(b)) {\n const ignoreUndefined = opts?.ignoreUndefined ?? true\n\n if (opts?.partial) {\n for (const k in b) {\n if (!ignoreUndefined || b[k] !== undefined) {\n if (!deepEqual(a[k], b[k], opts)) return false\n }\n }\n return true\n }\n\n let aCount = 0\n if (!ignoreUndefined) {\n aCount = Object.keys(a).length\n } else {\n for (const k in a) {\n if (a[k] !== undefined) aCount++\n }\n }\n\n let bCount = 0\n for (const k in b) {\n if (!ignoreUndefined || b[k] !== undefined) {\n bCount++\n if (bCount > aCount || !deepEqual(a[k], b[k], opts)) return false\n }\n }\n\n return aCount === bCount\n }\n\n return false\n}\n\nexport type StringLiteral<T> = T extends string\n ? string extends T\n ? string\n : T\n : never\n\nexport type ThrowOrOptional<T, TThrow extends boolean> = TThrow extends true\n ? T\n : T | undefined\n\nexport type StrictOrFrom<\n TRouter extends AnyRouter,\n TFrom,\n TStrict extends boolean = true,\n> = TStrict extends false\n ? {\n from?: never\n strict: TStrict\n }\n : {\n from: ConstrainLiteral<TFrom, RouteIds<TRouter['routeTree']>>\n strict?: TStrict\n }\n\nexport type ThrowConstraint<\n TStrict extends boolean,\n TThrow extends boolean,\n> = TStrict extends false ? (TThrow extends true ? never : TThrow) : TThrow\n\nexport type ControlledPromise<T> = Promise<T> & {\n resolve: (value: T) => void\n reject: (value: any) => void\n status: 'pending' | 'resolved' | 'rejected'\n value?: T\n}\n\n/**\n * Create a promise with exposed resolve/reject and status fields.\n * Useful for coordinating async router lifecycle operations.\n */\nexport function createControlledPromise<T>(onResolve?: (value: T) => void) {\n let resolveLoadPromise!: (value: T) => void\n let rejectLoadPromise!: (value: any) => void\n\n const controlledPromise = new Promise<T>((resolve, reject) => {\n resolveLoadPromise = resolve\n rejectLoadPromise = reject\n }) as ControlledPromise<T>\n\n controlledPromise.status = 'pending'\n\n controlledPromise.resolve = (value: T) => {\n controlledPromise.status = 'resolved'\n controlledPromise.value = value\n resolveLoadPromise(value)\n onResolve?.(value)\n }\n\n controlledPromise.reject = (e) => {\n controlledPromise.status = 'rejected'\n rejectLoadPromise(e)\n }\n\n return controlledPromise\n}\n\n/**\n * Heuristically detect dynamic import \"module not found\" errors\n * across major browsers for lazy route component handling.\n */\nexport function isModuleNotFoundError(error: any): boolean {\n // chrome: \"Failed to fetch dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split\"\n // firefox: \"error loading dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split\"\n // safari: \"Importing a module script failed.\"\n if (typeof error?.message !== 'string') return false\n return (\n error.message.startsWith('Failed to fetch dynamically imported module') ||\n error.message.startsWith('error loading dynamically imported module') ||\n error.message.startsWith('Importing a module script failed')\n )\n}\n\nexport function isPromise<T>(\n value: Promise<Awaited<T>> | T,\n): value is Promise<Awaited<T>> {\n return Boolean(\n value &&\n typeof value === 'object' &&\n typeof (value as Promise<T>).then === 'function',\n )\n}\n\nexport function findLast<T>(\n array: ReadonlyArray<T>,\n predicate: (item: T) => boolean,\n): T | undefined {\n for (let i = array.length - 1; i >= 0; i--) {\n const item = array[i]!\n if (predicate(item)) return item\n }\n return undefined\n}\n\n/**\n * Re-encode characters that are unsafe in URL paths.\n * Includes ASCII control characters (0x00-0x1F, 0x7F) and a subset of the\n * WHATWG URL \"path percent-encode set\" (\", <, >, `, {, }).\n *\n * Space (0x20) is intentionally excluded — decodeURI decodes %20 to space\n * and the router stores decoded spaces in location.pathname. The existing\n * encodePathLikeUrl already handles re-encoding spaces for outgoing URLs.\n *\n * These characters are decoded by decodeURI but must remain percent-encoded\n * in paths to match how upstream layers (CDNs, edge middleware, browsers)\n * interpret the URL, preventing infinite redirect loops and path mismatches.\n */\n// eslint-disable-next-line no-control-regex\nconst PATH_UNSAFE_RE = /[\\x00-\\x1f\\x7f\"<>`{}]/g\n\nfunction sanitizePathSegment(segment: string): string {\n return segment.replace(\n PATH_UNSAFE_RE,\n (ch) => '%' + ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'),\n )\n}\n\nfunction decodeSegment(segment: string): string {\n let decoded: string\n try {\n decoded = decodeURI(segment)\n } catch {\n // if the decoding fails, try to decode the various parts leaving the malformed tags in place\n decoded = segment.replaceAll(/%[0-9A-F]{2}/gi, (match) => {\n try {\n return decodeURI(match)\n } catch {\n return match\n }\n })\n }\n return sanitizePathSegment(decoded)\n}\n\n/**\n * Default list of URL protocols to allow in links, redirects, and navigation.\n * Any absolute URL protocol not in this list is treated as dangerous by default.\n */\nexport const DEFAULT_PROTOCOL_ALLOWLIST = [\n // Standard web navigation\n 'http:',\n 'https:',\n\n // Common browser-safe actions\n 'mailto:',\n 'tel:',\n]\n\n/**\n * Check if a URL string uses a protocol that is not in the allowlist.\n * Returns true for blocked protocols like javascript:, blob:, data:, etc.\n *\n * The URL constructor correctly normalizes:\n * - Mixed case (JavaScript: → javascript:)\n * - Whitespace/control characters (java\\nscript: → javascript:)\n * - Leading whitespace\n *\n * For relative URLs (no protocol), returns false (safe).\n *\n * @param url - The URL string to check\n * @param allowlist - Set of protocols to allow\n * @returns true if the URL uses a protocol that is not allowed\n */\nexport function isDangerousProtocol(\n url: string,\n allowlist: Set<string>,\n): boolean {\n if (!url) return false\n\n try {\n // Use the URL constructor - it correctly normalizes protocols\n // per WHATWG URL spec, handling all bypass attempts automatically\n const parsed = new URL(url)\n return !allowlist.has(parsed.protocol)\n } catch {\n // URL constructor throws for relative URLs (no protocol)\n // These are safe - they can't execute scripts\n return false\n }\n}\n\n// This utility is based on https://github.com/zertosh/htmlescape\n// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE\nconst HTML_ESCAPE_LOOKUP: { [match: string]: string } = {\n '&': '\\\\u0026',\n '>': '\\\\u003e',\n '<': '\\\\u003c',\n '\\u2028': '\\\\u2028',\n '\\u2029': '\\\\u2029',\n}\n\nconst HTML_ESCAPE_REGEX = /[&><\\u2028\\u2029]/g\n\n/**\n * Escape HTML special characters in a string to prevent XSS attacks\n * when embedding strings in script tags during SSR.\n *\n * This is essential for preventing XSS vulnerabilities when user-controlled\n * content is embedded in inline scripts.\n */\nexport function escapeHtml(str: string): string {\n return str.replace(HTML_ESCAPE_REGEX, (match) => HTML_ESCAPE_LOOKUP[match]!)\n}\n\nexport function decodePath(path: string) {\n if (!path) return { path, handledProtocolRelativeURL: false }\n\n // Fast path: most paths are already decoded and safe.\n // Only fall back to the slower scan/regex path when we see a '%' (encoded),\n // a backslash (explicitly handled), a control character, or a protocol-relative\n // prefix which needs collapsing.\n // eslint-disable-next-line no-control-regex\n if (!/[%\\\\\\x00-\\x1f\\x7f]/.test(path) && !path.startsWith('//')) {\n return { path, handledProtocolRelativeURL: false }\n }\n\n const re = /%25|%5C/gi\n let cursor = 0\n let result = ''\n let match\n while (null !== (match = re.exec(path))) {\n result += decodeSegment(path.slice(cursor, match.index)) + match[0]\n cursor = re.lastIndex\n }\n result = result + decodeSegment(cursor ? path.slice(cursor) : path)\n\n // Prevent open redirect via protocol-relative URLs (e.g. \"//evil.com\")\n // This is defense-in-depth: since control characters are no longer decoded,\n // paths like \"/%0d/evil.com\" can no longer become \"//evil.com\". But we keep\n // this check to guard against other edge cases.\n let handledProtocolRelativeURL = false\n if (result.startsWith('//')) {\n handledProtocolRelativeURL = true\n result = '/' + result.replace(/^\\/+/, '')\n }\n\n return { path: result, handledProtocolRelativeURL }\n}\n\n/**\n * Encodes a path the same way `new URL()` would, but without the overhead of full URL parsing.\n *\n * This function encodes:\n * - Whitespace characters (spaces → %20, tabs → %09, etc.)\n * - Non-ASCII/Unicode characters (emojis, accented characters, etc.)\n *\n * It preserves:\n * - Already percent-encoded sequences (won't double-encode %2F, %25, etc.)\n * - ASCII special characters valid in URL paths (@, $, &, +, etc.)\n * - Forward slashes as path separators\n *\n * Used to generate proper href values for SSR without constructing URL objects.\n *\n * @example\n * encodePathLikeUrl('/path/file name.pdf') // '/path/file%20name.pdf'\n * encodePathLikeUrl('/path/日本語') // '/path/%E6%97%A5%E6%9C%AC%E8%AA%9E'\n * encodePathLikeUrl('/path/already%20encoded') // '/path/already%20encoded' (preserved)\n */\nexport function encodePathLikeUrl(path: string): string {\n // Encode whitespace and non-ASCII characters that browsers encode in URLs\n\n // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ASCII range check\n // eslint-disable-next-line no-control-regex\n if (!/\\s|[^\\u0000-\\u007F]/.test(path)) return path\n // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ASCII range check\n // eslint-disable-next-line no-control-regex\n return path.replace(/\\s|[^\\u0000-\\u007F]/gu, encodeURIComponent)\n}\n\n/**\n * Builds the dev-mode CSS styles URL for route-scoped CSS collection.\n * Used by HeadContent components in all framework implementations to construct\n * the URL for the `/@tanstack-start/styles.css` endpoint.\n *\n * @param basepath - The router's basepath (may or may not have leading slash)\n * @param routeIds - Array of matched route IDs to include in the CSS collection\n * @returns The full URL path for the dev styles CSS endpoint\n */\nexport function buildDevStylesUrl(\n basepath: string,\n routeIds: Array<string>,\n): string {\n // Trim all leading and trailing slashes from basepath\n const trimmedBasepath = basepath.replace(/^\\/+|\\/+$/g, '')\n // Build normalized basepath: empty string for root, or '/path' for non-root\n const normalizedBasepath = trimmedBasepath === '' ? '' : `/${trimmedBasepath}`\n return `${normalizedBasepath}/@tanstack-start/styles.css?routes=${encodeURIComponent(routeIds.join(','))}`\n}\n\nexport function arraysEqual<T>(a: Array<T>, b: Array<T>) {\n if (a === b) return true\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false\n }\n return true\n}\n"],"mappings":"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"}
{
"name": "@tanstack/router-core",
"version": "1.171.23",
"version": "1.171.24",
"description": "Modern and scalable routing for React applications",

@@ -5,0 +5,0 @@ "author": "Tanner Linsley",

@@ -30,14 +30,2 @@ import { invariant } from './invariant'

function getOpenAndCloseBraces(
part: string,
): [openBrace: number, closeBrace: number] | null {
const openBrace = part.indexOf('{')
if (openBrace === -1) return null
const closeBrace = part.indexOf('}', openBrace)
if (closeBrace === -1) return null
const afterOpen = openBrace + 1
if (afterOpen >= part.length) return null
return [openBrace, closeBrace]
}
type ParsedSegment = Uint16Array & {

@@ -120,5 +108,9 @@ /** segment type (0 = pathname, 1 = param, 2 = wildcard, 3 = optional param) */

const braces = getOpenAndCloseBraces(part)
if (braces) {
const [openBrace, closeBrace] = braces
const openBrace = part.indexOf('{')
let closeBrace
if (
openBrace !== -1 &&
openBrace + 1 < part.length &&
(closeBrace = part.indexOf('}', openBrace)) !== -1
) {
const firstChar = part.charCodeAt(openBrace + 1)

@@ -125,0 +117,0 @@

@@ -196,6 +196,2 @@ import { isServer } from '@tanstack/router-core/isServer'

function isFunction(d: any): d is Function {
return typeof d === 'function'
}
/**

@@ -209,4 +205,4 @@ * Apply a value-or-updater to a previous value.

): TResult {
if (isFunction(updater)) {
return updater(previous)
if (typeof updater === 'function') {
return (updater as Function)(previous)
}

@@ -213,0 +209,0 @@

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display