@tanstack/router-core 1.168.18 → 1.169.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -62,6 +62,7 @@ exports.getLocationChangeInfo = require_router.getLocationChangeInfo;
62
62
  exports.getMatchedRoutes = require_router.getMatchedRoutes;
63
63
  exports.getStylesheetHref = require_manifest.getStylesheetHref;
64
64
  exports.handleHashScroll = require_hash_scroll.handleHashScroll;
65
+ exports.hasKeys = require_utils.hasKeys;
65
66
  exports.interpolatePath = require_path.interpolatePath;
66
67
  exports.invariant = require_invariant.invariant;
67
68
  exports.isDangerousProtocol = require_utils.isDangerousProtocol;
@@ -27,7 +27,7 @@ export { retainSearchParams, stripSearchParams } from './searchMiddleware.cjs';
27
27
  export { defaultParseSearch, defaultStringifySearch, parseSearchWith, stringifySearchWith, } from './searchParams.cjs';
28
28
  export type { SearchSerializer, SearchParser } from './searchParams.cjs';
29
29
  export type { OptionalStructuralSharing } from './structuralSharing.cjs';
30
- export { functionalUpdate, replaceEqualDeep, isPlainObject, isPlainArray, deepEqual, createControlledPromise, isModuleNotFoundError, DEFAULT_PROTOCOL_ALLOWLIST, escapeHtml, isDangerousProtocol, buildDevStylesUrl, } from './utils.cjs';
30
+ export { functionalUpdate, hasKeys, replaceEqualDeep, isPlainObject, isPlainArray, deepEqual, createControlledPromise, isModuleNotFoundError, DEFAULT_PROTOCOL_ALLOWLIST, escapeHtml, isDangerousProtocol, buildDevStylesUrl, } from './utils.cjs';
31
31
  export type { NoInfer, IsAny, PickAsRequired, PickRequired, PickOptional, WithoutEmpty, Expand, DeepPartial, MakeDifferenceOptional, IsUnion, IsNonEmptyObject, Assign, IntersectAssign, Timeout, Updater, NonNullableUpdater, StringLiteral, ThrowOrOptional, ThrowConstraint, ControlledPromise, ExtractObjects, PartialMergeAllObject, MergeAllPrimitive, ExtractPrimitives, PartialMergeAll, Constrain, ConstrainLiteral, UnionToIntersection, MergeAllObjects, MergeAll, ValidateJSON, StrictOrFrom, LooseReturnType, LooseAsyncReturnType, Awaitable, } from './utils.cjs';
32
32
  export type { StandardSchemaValidatorProps, StandardSchemaValidator, AnyStandardSchemaValidator, StandardSchemaValidatorTypes, AnyStandardSchemaValidateSuccess, AnyStandardSchemaValidateFailure, AnyStandardSchemaValidateIssue, AnyStandardSchemaValidateInput, AnyStandardSchemaValidate, ValidatorObj, AnyValidatorObj, ValidatorAdapter, AnyValidatorAdapter, AnyValidatorFn, ValidatorFn, Validator, AnyValidator, AnySchema, DefaultValidator, ResolveSearchValidatorInputFn, ResolveSearchValidatorInput, ResolveValidatorInputFn, ResolveValidatorInput, ResolveValidatorOutputFn, ResolveValidatorOutput, } from './validators.cjs';
33
33
  export type { UseRouteContextBaseOptions, UseRouteContextOptions, UseRouteContextResult, } from './useRouteContext.cjs';
@@ -122,7 +122,7 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
122
122
  const path = route.fullPath ?? route.from;
123
123
  const length = path.length;
124
124
  const caseSensitive = route.options?.caseSensitive ?? defaultCaseSensitive;
125
- const skipOnParamError = !!(route.options?.params?.parse && route.options?.skipRouteOnParseError?.params);
125
+ const parseParams = route.options?.params?.parse ?? route.options?.parseParams;
126
126
  while (cursor < length) {
127
127
  const segment = parseSegment(path, cursor, data);
128
128
  let nextNode;
@@ -165,7 +165,7 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
165
165
  const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
166
166
  const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
167
167
  const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
168
- const existingNode = !skipOnParamError && node.dynamic?.find((s) => !s.skipOnParamError && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix);
168
+ const existingNode = !parseParams && node.dynamic?.find((s) => !s.parse && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix);
169
169
  if (existingNode) nextNode = existingNode;
170
170
  else {
171
171
  const next = createDynamicNode(1, route.fullPath ?? route.from, actuallyCaseSensitive, prefix, suffix);
@@ -183,7 +183,7 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
183
183
  const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
184
184
  const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
185
185
  const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
186
- const existingNode = !skipOnParamError && node.optional?.find((s) => !s.skipOnParamError && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix);
186
+ const existingNode = !parseParams && node.optional?.find((s) => !s.parse && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix);
187
187
  if (existingNode) nextNode = existingNode;
188
188
  else {
189
189
  const next = createDynamicNode(3, route.fullPath ?? route.from, actuallyCaseSensitive, prefix, suffix);
@@ -211,7 +211,7 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
211
211
  }
212
212
  node = nextNode;
213
213
  }
214
- if (skipOnParamError && route.children && !route.isRoot && route.id && route.id.charCodeAt(route.id.lastIndexOf("/") + 1) === 95) {
214
+ if (parseParams && route.children && !route.isRoot && route.id && route.id.charCodeAt(route.id.lastIndexOf("/") + 1) === 95) {
215
215
  const pathlessNode = createStaticNode(route.fullPath ?? route.from);
216
216
  pathlessNode.kind = SEGMENT_TYPE_PATHLESS;
217
217
  pathlessNode.parent = node;
@@ -231,9 +231,7 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
231
231
  node.index = indexNode;
232
232
  node = indexNode;
233
233
  }
234
- node.parse = route.options?.params?.parse ?? null;
235
- node.skipOnParamError = skipOnParamError;
236
- node.parsingPriority = route.options?.skipRouteOnParseError?.priority ?? 0;
234
+ node.parse = parseParams ?? null;
237
235
  if (isLeaf && !node.route) {
238
236
  node.route = route;
239
237
  node.fullPath = route.fullPath ?? route.from;
@@ -242,9 +240,8 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
242
240
  if (route.children) for (const child of route.children) parseSegments(defaultCaseSensitive, data, child, cursor, node, depth, onRoute);
243
241
  }
244
242
  function sortDynamic(a, b) {
245
- if (a.skipOnParamError && !b.skipOnParamError) return -1;
246
- if (!a.skipOnParamError && b.skipOnParamError) return 1;
247
- if (a.skipOnParamError && b.skipOnParamError && (a.parsingPriority || b.parsingPriority)) return b.parsingPriority - a.parsingPriority;
243
+ if (a.parse && !b.parse) return -1;
244
+ if (!a.parse && b.parse) return 1;
248
245
  if (a.prefix && b.prefix && a.prefix !== b.prefix) {
249
246
  if (a.prefix.startsWith(b.prefix)) return -1;
250
247
  if (b.prefix.startsWith(a.prefix)) return 1;
@@ -292,9 +289,7 @@ function createStaticNode(fullPath) {
292
289
  route: null,
293
290
  fullPath,
294
291
  parent: null,
295
- parse: null,
296
- skipOnParamError: false,
297
- parsingPriority: 0
292
+ parse: null
298
293
  };
299
294
  }
300
295
  /**
@@ -316,8 +311,6 @@ function createDynamicNode(kind, fullPath, caseSensitive, prefix, suffix) {
316
311
  fullPath,
317
312
  parent: null,
318
313
  parse: null,
319
- skipOnParamError: false,
320
- parsingPriority: 0,
321
314
  caseSensitive,
322
315
  prefix,
323
316
  suffix
@@ -420,8 +413,7 @@ function findMatch(path, segmentTree, fuzzy = false) {
420
413
  const [rawParams] = extractParams(path, parts, leaf);
421
414
  return {
422
415
  route: leaf.node.route,
423
- rawParams,
424
- parsedParams: leaf.parsedParams
416
+ rawParams
425
417
  };
426
418
  }
427
419
  /**
@@ -537,13 +529,12 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
537
529
  while (stack.length) {
538
530
  const frame = stack.pop();
539
531
  const { node, index, skipped, depth, statics, dynamics, optionals } = frame;
540
- let { extract, rawParams, parsedParams } = frame;
532
+ let { extract, rawParams } = frame;
541
533
  if (node.kind === 2 && node.route && !isFrameMoreSpecific(bestMatch, frame)) continue;
542
- if (node.skipOnParamError) {
543
- if (!validateMatchParams(path, parts, frame)) continue;
534
+ if (node.parse) {
535
+ if (!validateParseParams(path, parts, frame)) continue;
544
536
  rawParams = frame.rawParams;
545
537
  extract = frame.extract;
546
- parsedParams = frame.parsedParams;
547
538
  }
548
539
  if (fuzzy && node.route && node.kind !== SEGMENT_TYPE_INDEX && isFrameMoreSpecific(bestFuzzy, frame)) bestFuzzy = frame;
549
540
  const isBeyondPath = index === partsLength;
@@ -563,12 +554,11 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
563
554
  dynamics,
564
555
  optionals,
565
556
  extract,
566
- rawParams,
567
- parsedParams
557
+ rawParams
568
558
  };
569
559
  let indexValid = true;
570
- if (node.index.skipOnParamError) {
571
- if (!validateMatchParams(path, parts, indexFrame)) indexValid = false;
560
+ if (node.index.parse) {
561
+ if (!validateParseParams(path, parts, indexFrame)) indexValid = false;
572
562
  }
573
563
  if (indexValid) {
574
564
  if (!dynamics && !optionals && !skipped && isPerfectStaticMatch(statics, partsLength)) return indexFrame;
@@ -596,8 +586,7 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
596
586
  dynamics,
597
587
  optionals,
598
588
  extract,
599
- rawParams,
600
- parsedParams
589
+ rawParams
601
590
  });
602
591
  }
603
592
  if (node.optional) {
@@ -614,8 +603,7 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
614
603
  dynamics,
615
604
  optionals,
616
605
  extract,
617
- rawParams,
618
- parsedParams
606
+ rawParams
619
607
  });
620
608
  }
621
609
  if (!isBeyondPath) for (let i = node.optional.length - 1; i >= 0; i--) {
@@ -635,8 +623,7 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
635
623
  dynamics,
636
624
  optionals: optionals + segmentScore(partsLength, index),
637
625
  extract,
638
- rawParams,
639
- parsedParams
626
+ rawParams
640
627
  });
641
628
  }
642
629
  }
@@ -657,8 +644,7 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
657
644
  dynamics: dynamics + segmentScore(partsLength, index),
658
645
  optionals,
659
646
  extract,
660
- rawParams,
661
- parsedParams
647
+ rawParams
662
648
  });
663
649
  }
664
650
  if (!isBeyondPath && node.staticInsensitive) {
@@ -672,8 +658,7 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
672
658
  dynamics,
673
659
  optionals,
674
660
  extract,
675
- rawParams,
676
- parsedParams
661
+ rawParams
677
662
  });
678
663
  }
679
664
  if (!isBeyondPath && node.static) {
@@ -687,8 +672,7 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
687
672
  dynamics,
688
673
  optionals,
689
674
  extract,
690
- rawParams,
691
- parsedParams
675
+ rawParams
692
676
  });
693
677
  }
694
678
  if (node.pathless) {
@@ -704,8 +688,7 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
704
688
  dynamics,
705
689
  optionals,
706
690
  extract,
707
- rawParams,
708
- parsedParams
691
+ rawParams
709
692
  });
710
693
  }
711
694
  }
@@ -727,23 +710,28 @@ function segmentScore(partsLength, index) {
727
710
  function isPerfectStaticMatch(statics, partsLength) {
728
711
  return statics === 2 ** (partsLength - 1) - 1;
729
712
  }
730
- function validateMatchParams(path, parts, frame) {
713
+ function validateParseParams(path, parts, frame) {
714
+ let rawParams;
715
+ let state;
731
716
  try {
732
- const [rawParams, state] = extractParams(path, parts, frame);
733
- frame.rawParams = rawParams;
734
- frame.extract = state;
735
- const parsed = frame.node.parse(rawParams);
736
- frame.parsedParams = Object.assign(Object.create(null), frame.parsedParams, parsed);
737
- return true;
717
+ [rawParams, state] = extractParams(path, parts, frame);
738
718
  } catch {
739
719
  return null;
740
720
  }
721
+ frame.rawParams = rawParams;
722
+ frame.extract = state;
723
+ if (!frame.node.parse) return true;
724
+ try {
725
+ if (frame.node.parse(rawParams) === false) return null;
726
+ } catch {}
727
+ return true;
741
728
  }
742
729
  function isFrameMoreSpecific(prev, next) {
743
730
  if (!prev) return true;
744
731
  return next.statics > prev.statics || next.statics === prev.statics && (next.dynamics > prev.dynamics || next.dynamics === prev.dynamics && (next.optionals > prev.optionals || next.optionals === prev.optionals && ((next.node.kind === SEGMENT_TYPE_INDEX) > (prev.node.kind === SEGMENT_TYPE_INDEX) || next.node.kind === SEGMENT_TYPE_INDEX === (prev.node.kind === SEGMENT_TYPE_INDEX) && next.depth > prev.depth)));
745
732
  }
746
733
  //#endregion
734
+ exports.buildRouteBranch = buildRouteBranch;
747
735
  exports.findFlatMatch = findFlatMatch;
748
736
  exports.findRouteMatch = findRouteMatch;
749
737
  exports.findSingleMatch = findSingleMatch;
@@ -1 +1 @@
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 onRoute?: (route: TRouteLike) => void,\n) {\n onRoute?.(route)\n let cursor = start\n {\n const path = route.fullPath ?? route.from\n const length = path.length\n const caseSensitive = route.options?.caseSensitive ?? defaultCaseSensitive\n const skipOnParamError = !!(\n route.options?.params?.parse &&\n route.options?.skipRouteOnParseError?.params\n )\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 if (caseSensitive) {\n const existingNode = node.static?.get(value)\n if (existingNode) {\n nextNode = existingNode\n } else {\n node.static ??= new Map()\n const next = createStaticNode<TRouteLike>(\n route.fullPath ?? route.from,\n )\n next.parent = node\n next.depth = depth\n nextNode = next\n node.static.set(value, next)\n }\n } else {\n const name = value.toLowerCase()\n const existingNode = node.staticInsensitive?.get(name)\n if (existingNode) {\n nextNode = existingNode\n } else {\n node.staticInsensitive ??= new Map()\n const next = createStaticNode<TRouteLike>(\n route.fullPath ?? route.from,\n )\n next.parent = node\n next.depth = depth\n nextNode = next\n node.staticInsensitive.set(name, next)\n }\n }\n break\n }\n case SEGMENT_TYPE_PARAM: {\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 existingNode =\n !skipOnParamError &&\n node.dynamic?.find(\n (s) =>\n !s.skipOnParamError &&\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 SEGMENT_TYPE_PARAM,\n route.fullPath ?? route.from,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.depth = depth\n next.parent = node\n node.dynamic ??= []\n node.dynamic.push(next)\n }\n break\n }\n case SEGMENT_TYPE_OPTIONAL_PARAM: {\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 existingNode =\n !skipOnParamError &&\n node.optional?.find(\n (s) =>\n !s.skipOnParamError &&\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 SEGMENT_TYPE_OPTIONAL_PARAM,\n route.fullPath ?? route.from,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.parent = node\n next.depth = depth\n node.optional ??= []\n node.optional.push(next)\n }\n break\n }\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 next = createDynamicNode<TRouteLike>(\n SEGMENT_TYPE_WILDCARD,\n route.fullPath ?? route.from,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.parent = node\n next.depth = depth\n node.wildcard ??= []\n node.wildcard.push(next)\n }\n }\n node = nextNode\n }\n\n // create pathless node\n if (\n skipOnParamError &&\n route.children &&\n !route.isRoot &&\n route.id &&\n route.id.charCodeAt(route.id.lastIndexOf('/') + 1) === 95 /* '_' */\n ) {\n const pathlessNode = createStaticNode<TRouteLike>(\n route.fullPath ?? route.from,\n )\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>(\n route.fullPath ?? route.from,\n )\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 = route.options?.params?.parse ?? null\n node.skipOnParamError = skipOnParamError\n node.parsingPriority = route.options?.skipRouteOnParseError?.priority ?? 0\n\n // make node \"matchable\"\n if (isLeaf && !node.route) {\n node.route = route\n node.fullPath = route.fullPath ?? route.from\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 onRoute,\n )\n }\n}\n\nfunction sortDynamic(\n a: {\n prefix?: string\n suffix?: string\n caseSensitive: boolean\n skipOnParamError: boolean\n parsingPriority: number\n },\n b: {\n prefix?: string\n suffix?: string\n caseSensitive: boolean\n skipOnParamError: boolean\n parsingPriority: number\n },\n) {\n if (a.skipOnParamError && !b.skipOnParamError) return -1\n if (!a.skipOnParamError && b.skipOnParamError) return 1\n if (\n a.skipOnParamError &&\n b.skipOnParamError &&\n (a.parsingPriority || b.parsingPriority)\n )\n return b.parsingPriority - a.parsingPriority\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 // we don't need a tiebreaker here\n // at this point the 2 nodes cannot conflict during matching\n return 0\n}\n\nfunction sortTreeNodes(node: SegmentNode<RouteLike>) {\n if (node.pathless) {\n for (const child of node.pathless) {\n sortTreeNodes(child)\n }\n }\n if (node.static) {\n for (const child of node.static.values()) {\n sortTreeNodes(child)\n }\n }\n if (node.staticInsensitive) {\n for (const child of node.staticInsensitive.values()) {\n sortTreeNodes(child)\n }\n }\n if (node.dynamic?.length) {\n node.dynamic.sort(sortDynamic)\n for (const child of node.dynamic) {\n sortTreeNodes(child)\n }\n }\n if (node.optional?.length) {\n node.optional.sort(sortDynamic)\n for (const child of node.optional) {\n sortTreeNodes(child)\n }\n }\n if (node.wildcard?.length) {\n node.wildcard.sort(sortDynamic)\n for (const child of node.wildcard) {\n sortTreeNodes(child)\n }\n }\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 skipOnParamError: false,\n parsingPriority: 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 skipOnParamError: false,\n parsingPriority: 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>) => any)\n\n /** options.skipRouteOnParseError.params ?? false */\n skipOnParamError: boolean\n\n /** options.skipRouteOnParseError.priority ?? 0 */\n parsingPriority: 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 skipRouteOnParseError?: {\n params?: boolean\n priority?: number\n }\n caseSensitive?: boolean\n params?: {\n parse?: (params: Record<string, string>) => any\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 for (const route of routeList) {\n parseSegments(false, data, route, 1, segmentTree, 0)\n }\n sortTreeNodes(segmentTree)\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 parsedParams?: Record<string, unknown>\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 routesById = {} as Record<string, TRouteLike>\n const routesByPath = {} as Record<string, TRouteLike>\n let index = 0\n parseSegments(caseSensitive, data, routeTree, 1, segmentTree, 0, (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 sortTreeNodes(segmentTree)\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 /**\n * The accumlulated parsed params of each route in the branch that had `skipRouteOnParseError` enabled.\n * Will not contain all params defined in the route's path. Those w/ a `params.parse` but no `skipRouteOnParseError` will need to be parsed separately.\n */\n parsedParams?: Record<string, unknown>\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 parsedParams: leaf.parsedParams,\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\nfunction 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 /** how many nodes between `node` and the root of the segment tree */\n depth: 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 parsedParams?: Record<string, unknown>\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' | 'parsedParams'\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 depth: 1,\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, depth, statics, dynamics, optionals } = frame\n let { extract, rawParams, parsedParams } = 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.skipOnParamError) {\n const result = validateMatchParams(path, parts, frame)\n if (!result) continue\n rawParams = frame.rawParams\n extract = frame.extract\n parsedParams = frame.parsedParams\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 depth: depth + 1,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n parsedParams,\n }\n let indexValid = true\n if (node.index.skipOnParamError) {\n const result = validateMatchParams(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 depth: depth + 1,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n parsedParams,\n })\n }\n }\n\n // 4. Try optional match\n if (node.optional) {\n const nextSkipped = skipped | (1 << depth)\n const nextDepth = depth + 1\n for (let i = node.optional.length - 1; i >= 0; i--) {\n const segment = node.optional[i]!\n // when skipping, node and depth advance by 1, but index doesn't\n stack.push({\n node: segment,\n index,\n skipped: nextSkipped,\n depth: nextDepth,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n parsedParams,\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 depth: nextDepth,\n statics,\n dynamics,\n optionals: optionals + segmentScore(partsLength, index),\n extract,\n rawParams,\n parsedParams,\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 depth: depth + 1,\n statics,\n dynamics: dynamics + segmentScore(partsLength, index),\n optionals,\n extract,\n rawParams,\n parsedParams,\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 depth: depth + 1,\n statics: statics + segmentScore(partsLength, index),\n dynamics,\n optionals,\n extract,\n rawParams,\n parsedParams,\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 depth: depth + 1,\n statics: statics + segmentScore(partsLength, index),\n dynamics,\n optionals,\n extract,\n rawParams,\n parsedParams,\n })\n }\n }\n\n // 0. Try pathless match\n if (node.pathless) {\n const nextDepth = depth + 1\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 depth: nextDepth,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n parsedParams,\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 validateMatchParams<T extends RouteLike>(\n path: string,\n parts: Array<string>,\n frame: MatchStackFrame<T>,\n) {\n try {\n const [rawParams, state] = extractParams(path, parts, frame)\n frame.rawParams = rawParams\n frame.extract = state\n const parsed = frame.node.parse!(rawParams)\n frame.parsedParams = Object.assign(\n Object.create(null),\n frame.parsedParams,\n parsed,\n )\n return true\n } catch {\n return null\n }\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.depth > prev.depth)))))))\n )\n}\n"],"mappings":"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"}
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 onRoute?: (route: TRouteLike) => void,\n) {\n onRoute?.(route)\n let cursor = start\n {\n const path = route.fullPath ?? route.from\n const length = path.length\n const caseSensitive = route.options?.caseSensitive ?? defaultCaseSensitive\n const parseParams =\n route.options?.params?.parse ?? route.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 if (caseSensitive) {\n const existingNode = node.static?.get(value)\n if (existingNode) {\n nextNode = existingNode\n } else {\n node.static ??= new Map()\n const next = createStaticNode<TRouteLike>(\n route.fullPath ?? route.from,\n )\n next.parent = node\n next.depth = depth\n nextNode = next\n node.static.set(value, next)\n }\n } else {\n const name = value.toLowerCase()\n const existingNode = node.staticInsensitive?.get(name)\n if (existingNode) {\n nextNode = existingNode\n } else {\n node.staticInsensitive ??= new Map()\n const next = createStaticNode<TRouteLike>(\n route.fullPath ?? route.from,\n )\n next.parent = node\n next.depth = depth\n nextNode = next\n node.staticInsensitive.set(name, next)\n }\n }\n break\n }\n case SEGMENT_TYPE_PARAM: {\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 existingNode =\n !parseParams &&\n node.dynamic?.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 SEGMENT_TYPE_PARAM,\n route.fullPath ?? route.from,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.depth = depth\n next.parent = node\n node.dynamic ??= []\n node.dynamic.push(next)\n }\n break\n }\n case SEGMENT_TYPE_OPTIONAL_PARAM: {\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 existingNode =\n !parseParams &&\n node.optional?.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 SEGMENT_TYPE_OPTIONAL_PARAM,\n route.fullPath ?? route.from,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.parent = node\n next.depth = depth\n node.optional ??= []\n node.optional.push(next)\n }\n break\n }\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 next = createDynamicNode<TRouteLike>(\n SEGMENT_TYPE_WILDCARD,\n route.fullPath ?? route.from,\n actuallyCaseSensitive,\n prefix,\n suffix,\n )\n nextNode = next\n next.parent = node\n next.depth = depth\n node.wildcard ??= []\n node.wildcard.push(next)\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>(\n route.fullPath ?? route.from,\n )\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>(\n route.fullPath ?? route.from,\n )\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\n // make node \"matchable\"\n if (isLeaf && !node.route) {\n node.route = route\n node.fullPath = route.fullPath ?? route.from\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 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 },\n b: {\n prefix?: string\n suffix?: string\n caseSensitive: boolean\n parse: null | ((params: Record<string, string>) => unknown)\n },\n) {\n if (a.parse && !b.parse) return -1\n if (!a.parse && b.parse) return 1\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 sortTreeNodes(node: SegmentNode<RouteLike>) {\n if (node.pathless) {\n for (const child of node.pathless) {\n sortTreeNodes(child)\n }\n }\n if (node.static) {\n for (const child of node.static.values()) {\n sortTreeNodes(child)\n }\n }\n if (node.staticInsensitive) {\n for (const child of node.staticInsensitive.values()) {\n sortTreeNodes(child)\n }\n }\n if (node.dynamic?.length) {\n node.dynamic.sort(sortDynamic)\n for (const child of node.dynamic) {\n sortTreeNodes(child)\n }\n }\n if (node.optional?.length) {\n node.optional.sort(sortDynamic)\n for (const child of node.optional) {\n sortTreeNodes(child)\n }\n }\n if (node.wildcard?.length) {\n node.wildcard.sort(sortDynamic)\n for (const child of node.wildcard) {\n sortTreeNodes(child)\n }\n }\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 }\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 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\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 }\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 for (const route of routeList) {\n parseSegments(false, data, route, 1, segmentTree, 0)\n }\n sortTreeNodes(segmentTree)\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 routesById = {} as Record<string, TRouteLike>\n const routesByPath = {} as Record<string, TRouteLike>\n let index = 0\n parseSegments(caseSensitive, data, routeTree, 1, segmentTree, 0, (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 sortTreeNodes(segmentTree)\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 /** how many nodes between `node` and the root of the segment tree */\n depth: 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 depth: 1,\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, depth, 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 depth: depth + 1,\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 depth: depth + 1,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n })\n }\n }\n\n // 4. Try optional match\n if (node.optional) {\n const nextSkipped = skipped | (1 << depth)\n const nextDepth = depth + 1\n for (let i = node.optional.length - 1; i >= 0; i--) {\n const segment = node.optional[i]!\n // when skipping, node and depth advance by 1, but index doesn't\n stack.push({\n node: segment,\n index,\n skipped: nextSkipped,\n depth: nextDepth,\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 depth: nextDepth,\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 depth: depth + 1,\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 depth: depth + 1,\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 depth: depth + 1,\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 const nextDepth = depth + 1\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 depth: nextDepth,\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.depth > prev.depth)))))))\n )\n}\n"],"mappings":"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"}
@@ -82,11 +82,7 @@ type SegmentNode<T extends RouteLike> = {
82
82
  parent: AnySegmentNode<T> | null;
83
83
  depth: number;
84
84
  /** route.options.params.parse function, set on the last node of the route */
85
- parse: null | ((params: Record<string, string>) => any);
86
- /** options.skipRouteOnParseError.params ?? false */
87
- skipOnParamError: boolean;
88
- /** options.skipRouteOnParseError.priority ?? 0 */
89
- parsingPriority: number;
85
+ parse: null | ((params: Record<string, string>) => unknown);
90
86
  };
91
87
  type RouteLike = {
92
88
  id?: string;
@@ -95,13 +91,10 @@ type RouteLike = {
95
91
  parentRoute?: RouteLike;
96
92
  isRoot?: boolean;
97
93
  options?: {
98
- skipRouteOnParseError?: {
99
- params?: boolean;
100
- priority?: number;
101
- };
102
94
  caseSensitive?: boolean;
95
+ parseParams?: (params: Record<string, string>) => unknown;
103
96
  params?: {
104
- parse?: (params: Record<string, string>) => any;
97
+ parse?: (params: Record<string, string>) => unknown;
105
98
  };
106
99
  };
107
100
  } & ({
@@ -148,11 +141,6 @@ processedTree: ProcessedTree<any, T, any>): {
148
141
  * This will be the exhaustive list of all params defined in the route's path.
149
142
  */
150
143
  rawParams: Record<string, string>;
151
- /**
152
- * The accumlulated parsed params of each route in the branch that had `skipRouteOnParseError` enabled.
153
- * Will not contain all params defined in the route's path. Those w/ a `params.parse` but no `skipRouteOnParseError` will need to be parsed separately.
154
- */
155
- parsedParams?: Record<string, unknown>;
156
144
  } | null;
157
145
  /**
158
146
  * @deprecated keep until v2 so that `router.matchRoute` can keep not caring about the actual route tree
@@ -168,18 +156,12 @@ export declare function findSingleMatch(from: string, caseSensitive: boolean, fu
168
156
  * This will be the exhaustive list of all params defined in the route's path.
169
157
  */
170
158
  rawParams: Record<string, string>;
171
- /**
172
- * The accumlulated parsed params of each route in the branch that had `skipRouteOnParseError` enabled.
173
- * Will not contain all params defined in the route's path. Those w/ a `params.parse` but no `skipRouteOnParseError` will need to be parsed separately.
174
- */
175
- parsedParams?: Record<string, unknown>;
176
159
  } | null;
177
160
  type RouteMatch<T extends Extract<RouteLike, {
178
161
  fullPath: string;
179
162
  }>> = {
180
163
  route: T;
181
164
  rawParams: Record<string, string>;
182
- parsedParams?: Record<string, unknown>;
183
165
  branch: ReadonlyArray<T>;
184
166
  };
185
167
  export declare function findRouteMatch<T extends Extract<RouteLike, {
@@ -227,10 +209,6 @@ declare function findMatch<T extends RouteLike>(path: string, segmentTree: AnySe
227
209
  * This will be the exhaustive list of all params defined in the route's path.
228
210
  */
229
211
  rawParams: Record<string, string>;
230
- /**
231
- * The accumlulated parsed params of each route in the branch that had `skipRouteOnParseError` enabled.
232
- * Will not contain all params defined in the route's path. Those w/ a `params.parse` but no `skipRouteOnParseError` will need to be parsed separately.
233
- */
234
- parsedParams?: Record<string, unknown>;
235
212
  } | null;
213
+ export declare function buildRouteBranch<T extends RouteLike>(route: T): T[];
236
214
  export {};
package/dist/cjs/path.cjs CHANGED
@@ -71,28 +71,7 @@ function resolvePath({ base, to, trailingSlash = "never", cache }) {
71
71
  if (trailingSlash === "never") baseSegments.pop();
72
72
  } else if (trailingSlash === "always") baseSegments.push("");
73
73
  }
74
- let segment;
75
- let joined = "";
76
- for (let i = 0; i < baseSegments.length; i++) {
77
- if (i > 0) joined += "/";
78
- const part = baseSegments[i];
79
- if (!part) continue;
80
- segment = require_new_process_route_tree.parseSegment(part, 0, segment);
81
- const kind = segment[0];
82
- if (kind === 0) {
83
- joined += part;
84
- continue;
85
- }
86
- const end = segment[5];
87
- const prefix = part.substring(0, segment[1]);
88
- const suffix = part.substring(segment[4], end);
89
- const value = part.substring(segment[2], segment[3]);
90
- if (kind === 1) joined += prefix || suffix ? `${prefix}{$${value}}${suffix}` : `$${value}`;
91
- else if (kind === 2) joined += prefix || suffix ? `${prefix}{$}${suffix}` : "$";
92
- else joined += `${prefix}{-$${value}}${suffix}`;
93
- }
94
- joined = cleanPath(joined);
95
- const result = joined || "/";
74
+ const result = cleanPath(baseSegments.join("/")) || "/";
96
75
  if (key && cache) cache.set(key, result);
97
76
  return result;
98
77
  }