@tanstack/router-core 1.145.7 → 1.146.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.
@@ -6,6 +6,7 @@ const SEGMENT_TYPE_PARAM = 1;
6
6
  const SEGMENT_TYPE_WILDCARD = 2;
7
7
  const SEGMENT_TYPE_OPTIONAL_PARAM = 3;
8
8
  const SEGMENT_TYPE_INDEX = 4;
9
+ const SEGMENT_TYPE_PATHLESS = 5;
9
10
  const PARAM_W_CURLY_BRACES_RE = /^([^{]*)\{\$([a-zA-Z_$][a-zA-Z0-9_$]*)\}([^}]*)$/;
10
11
  const OPTIONAL_PARAM_W_CURLY_BRACES_RE = /^([^{]*)\{-\$([a-zA-Z_$][a-zA-Z0-9_$]*)\}([^}]*)$/;
11
12
  const WILDCARD_W_CURLY_BRACES_RE = /^([^{]*)\{\$\}([^}]*)$/;
@@ -96,6 +97,7 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
96
97
  const path = route.fullPath ?? route.from;
97
98
  const length = path.length;
98
99
  const caseSensitive = route.options?.caseSensitive ?? defaultCaseSensitive;
100
+ const skipOnParamError = !!(route.options?.params?.parse && route.options?.skipRouteOnParseError?.params);
99
101
  while (cursor < length) {
100
102
  const segment = parseSegment(path, cursor, data);
101
103
  let nextNode;
@@ -145,8 +147,8 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
145
147
  const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
146
148
  const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
147
149
  const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
148
- const existingNode = node.dynamic?.find(
149
- (s) => s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix
150
+ const existingNode = !skipOnParamError && node.dynamic?.find(
151
+ (s) => !s.skipOnParamError && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix
150
152
  );
151
153
  if (existingNode) {
152
154
  nextNode = existingNode;
@@ -172,8 +174,8 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
172
174
  const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
173
175
  const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
174
176
  const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
175
- const existingNode = node.optional?.find(
176
- (s) => s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix
177
+ const existingNode = !skipOnParamError && node.optional?.find(
178
+ (s) => !s.skipOnParamError && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix
177
179
  );
178
180
  if (existingNode) {
179
181
  nextNode = existingNode;
@@ -215,6 +217,18 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
215
217
  }
216
218
  node = nextNode;
217
219
  }
220
+ if (skipOnParamError && route.children && !route.isRoot && route.id && route.id.charCodeAt(route.id.lastIndexOf("/") + 1) === 95) {
221
+ const pathlessNode = createStaticNode(
222
+ route.fullPath ?? route.from
223
+ );
224
+ pathlessNode.kind = SEGMENT_TYPE_PATHLESS;
225
+ pathlessNode.parent = node;
226
+ depth++;
227
+ pathlessNode.depth = depth;
228
+ node.pathless ??= [];
229
+ node.pathless.push(pathlessNode);
230
+ node = pathlessNode;
231
+ }
218
232
  const isLeaf = (route.path || !route.children) && !route.isRoot;
219
233
  if (isLeaf && path.endsWith("/")) {
220
234
  const indexNode = createStaticNode(
@@ -227,6 +241,9 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
227
241
  node.index = indexNode;
228
242
  node = indexNode;
229
243
  }
244
+ node.parse = route.options?.params?.parse ?? null;
245
+ node.skipOnParamError = skipOnParamError;
246
+ node.parsingPriority = route.options?.skipRouteOnParseError?.priority ?? 0;
230
247
  if (isLeaf && !node.route) {
231
248
  node.route = route;
232
249
  node.fullPath = route.fullPath ?? route.from;
@@ -246,6 +263,10 @@ function parseSegments(defaultCaseSensitive, data, route, start, node, depth, on
246
263
  }
247
264
  }
248
265
  function sortDynamic(a, b) {
266
+ if (a.skipOnParamError && !b.skipOnParamError) return -1;
267
+ if (!a.skipOnParamError && b.skipOnParamError) return 1;
268
+ if (a.skipOnParamError && b.skipOnParamError && (a.parsingPriority || b.parsingPriority))
269
+ return b.parsingPriority - a.parsingPriority;
249
270
  if (a.prefix && b.prefix && a.prefix !== b.prefix) {
250
271
  if (a.prefix.startsWith(b.prefix)) return -1;
251
272
  if (b.prefix.startsWith(a.prefix)) return 1;
@@ -263,6 +284,11 @@ function sortDynamic(a, b) {
263
284
  return 0;
264
285
  }
265
286
  function sortTreeNodes(node) {
287
+ if (node.pathless) {
288
+ for (const child of node.pathless) {
289
+ sortTreeNodes(child);
290
+ }
291
+ }
266
292
  if (node.static) {
267
293
  for (const child of node.static.values()) {
268
294
  sortTreeNodes(child);
@@ -296,6 +322,7 @@ function createStaticNode(fullPath) {
296
322
  return {
297
323
  kind: SEGMENT_TYPE_PATHNAME,
298
324
  depth: 0,
325
+ pathless: null,
299
326
  index: null,
300
327
  static: null,
301
328
  staticInsensitive: null,
@@ -304,13 +331,17 @@ function createStaticNode(fullPath) {
304
331
  wildcard: null,
305
332
  route: null,
306
333
  fullPath,
307
- parent: null
334
+ parent: null,
335
+ parse: null,
336
+ skipOnParamError: false,
337
+ parsingPriority: 0
308
338
  };
309
339
  }
310
340
  function createDynamicNode(kind, fullPath, caseSensitive, prefix, suffix) {
311
341
  return {
312
342
  kind,
313
343
  depth: 0,
344
+ pathless: null,
314
345
  index: null,
315
346
  static: null,
316
347
  staticInsensitive: null,
@@ -320,6 +351,9 @@ function createDynamicNode(kind, fullPath, caseSensitive, prefix, suffix) {
320
351
  route: null,
321
352
  fullPath,
322
353
  parent: null,
354
+ parse: null,
355
+ skipOnParamError: false,
356
+ parsingPriority: 0,
323
357
  caseSensitive,
324
358
  prefix,
325
359
  suffix
@@ -412,19 +446,21 @@ function findMatch(path, segmentTree, fuzzy = false) {
412
446
  const parts = path.split("/");
413
447
  const leaf = getNodeMatch(path, parts, segmentTree, fuzzy);
414
448
  if (!leaf) return null;
415
- const params = extractParams(path, parts, leaf);
416
- if ("**" in leaf) params["**"] = leaf["**"];
417
- const route = leaf.node.route;
449
+ const [rawParams] = extractParams(path, parts, leaf);
418
450
  return {
419
- route,
420
- params
451
+ route: leaf.node.route,
452
+ rawParams,
453
+ parsedParams: leaf.parsedParams
421
454
  };
422
455
  }
423
456
  function extractParams(path, parts, leaf) {
424
457
  const list = buildBranch(leaf.node);
425
458
  let nodeParts = null;
426
- const params = {};
427
- for (let partIndex = 0, nodeIndex = 0, pathIndex = 0; nodeIndex < list.length; partIndex++, nodeIndex++, pathIndex++) {
459
+ const rawParams = {};
460
+ let partIndex = leaf.extract?.part ?? 0;
461
+ let nodeIndex = leaf.extract?.node ?? 0;
462
+ let pathIndex = leaf.extract?.path ?? 0;
463
+ for (; nodeIndex < list.length; partIndex++, nodeIndex++, pathIndex++) {
428
464
  const node = list[nodeIndex];
429
465
  const part = parts[partIndex];
430
466
  const currentPathIndex = pathIndex;
@@ -441,10 +477,10 @@ function extractParams(path, parts, leaf) {
441
477
  nodePart.length - sufLength - 1
442
478
  );
443
479
  const value = part.substring(preLength, part.length - sufLength);
444
- params[name] = decodeURIComponent(value);
480
+ rawParams[name] = decodeURIComponent(value);
445
481
  } else {
446
482
  const name = nodePart.substring(1);
447
- params[name] = decodeURIComponent(part);
483
+ rawParams[name] = decodeURIComponent(part);
448
484
  }
449
485
  } else if (node.kind === SEGMENT_TYPE_OPTIONAL_PARAM) {
450
486
  if (leaf.skipped & 1 << nodeIndex) {
@@ -460,7 +496,7 @@ function extractParams(path, parts, leaf) {
460
496
  nodePart.length - sufLength - 1
461
497
  );
462
498
  const value = node.suffix || node.prefix ? part.substring(preLength, part.length - sufLength) : part;
463
- if (value) params[name] = decodeURIComponent(value);
499
+ if (value) rawParams[name] = decodeURIComponent(value);
464
500
  } else if (node.kind === SEGMENT_TYPE_WILDCARD) {
465
501
  const n = node;
466
502
  const value = path.substring(
@@ -468,12 +504,13 @@ function extractParams(path, parts, leaf) {
468
504
  path.length - (n.suffix?.length ?? 0)
469
505
  );
470
506
  const splat = decodeURIComponent(value);
471
- params["*"] = splat;
472
- params._splat = splat;
507
+ rawParams["*"] = splat;
508
+ rawParams._splat = splat;
473
509
  break;
474
510
  }
475
511
  }
476
- return params;
512
+ if (leaf.rawParams) Object.assign(rawParams, leaf.rawParams);
513
+ return [rawParams, { part: partIndex, node: nodeIndex, path: pathIndex }];
477
514
  }
478
515
  function buildRouteBranch(route) {
479
516
  const list = [route];
@@ -514,7 +551,15 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
514
551
  let bestMatch = null;
515
552
  while (stack.length) {
516
553
  const frame = stack.pop();
517
- let { node, index, skipped, depth, statics, dynamics, optionals } = frame;
554
+ const { node, index, skipped, depth, statics, dynamics, optionals } = frame;
555
+ let { extract, rawParams, parsedParams } = frame;
556
+ if (node.skipOnParamError) {
557
+ const result = validateMatchParams(path, parts, frame);
558
+ if (!result) continue;
559
+ rawParams = frame.rawParams;
560
+ extract = frame.extract;
561
+ parsedParams = frame.parsedParams;
562
+ }
518
563
  if (fuzzy && node.route && node.kind !== SEGMENT_TYPE_INDEX && isFrameMoreSpecific(bestFuzzy, frame)) {
519
564
  bestFuzzy = frame;
520
565
  }
@@ -523,7 +568,8 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
523
568
  if (node.route && !pathIsIndex && isFrameMoreSpecific(bestMatch, frame)) {
524
569
  bestMatch = frame;
525
570
  }
526
- if (!node.optional && !node.wildcard && !node.index) continue;
571
+ if (!node.optional && !node.wildcard && !node.index && !node.pathless)
572
+ continue;
527
573
  }
528
574
  const part = isBeyondPath ? void 0 : parts[index];
529
575
  let lowerPart;
@@ -535,8 +581,15 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
535
581
  depth: depth + 1,
536
582
  statics,
537
583
  dynamics,
538
- optionals
584
+ optionals,
585
+ extract,
586
+ rawParams,
587
+ parsedParams
539
588
  };
589
+ if (node.index.skipOnParamError) {
590
+ const result = validateMatchParams(path, parts, indexFrame);
591
+ if (!result) continue;
592
+ }
540
593
  if (statics === partsLength && !dynamics && !optionals && !skipped) {
541
594
  return indexFrame;
542
595
  }
@@ -558,15 +611,23 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
558
611
  const casePart = segment.caseSensitive ? end : end.toLowerCase();
559
612
  if (casePart !== suffix) continue;
560
613
  }
561
- wildcardMatch = {
614
+ const frame2 = {
562
615
  node: segment,
563
616
  index: partsLength,
564
617
  skipped,
565
618
  depth,
566
619
  statics,
567
620
  dynamics,
568
- optionals
621
+ optionals,
622
+ extract,
623
+ rawParams,
624
+ parsedParams
569
625
  };
626
+ if (segment.skipOnParamError) {
627
+ const result = validateMatchParams(path, parts, frame2);
628
+ if (!result) continue;
629
+ }
630
+ wildcardMatch = frame2;
570
631
  break;
571
632
  }
572
633
  }
@@ -582,7 +643,10 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
582
643
  depth: nextDepth,
583
644
  statics,
584
645
  dynamics,
585
- optionals
646
+ optionals,
647
+ extract,
648
+ rawParams,
649
+ parsedParams
586
650
  });
587
651
  }
588
652
  if (!isBeyondPath) {
@@ -601,7 +665,10 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
601
665
  depth: nextDepth,
602
666
  statics,
603
667
  dynamics,
604
- optionals: optionals + 1
668
+ optionals: optionals + 1,
669
+ extract,
670
+ rawParams,
671
+ parsedParams
605
672
  });
606
673
  }
607
674
  }
@@ -622,7 +689,10 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
622
689
  depth: depth + 1,
623
690
  statics,
624
691
  dynamics: dynamics + 1,
625
- optionals
692
+ optionals,
693
+ extract,
694
+ rawParams,
695
+ parsedParams
626
696
  });
627
697
  }
628
698
  }
@@ -638,7 +708,10 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
638
708
  depth: depth + 1,
639
709
  statics: statics + 1,
640
710
  dynamics,
641
- optionals
711
+ optionals,
712
+ extract,
713
+ rawParams,
714
+ parsedParams
642
715
  });
643
716
  }
644
717
  }
@@ -652,7 +725,28 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
652
725
  depth: depth + 1,
653
726
  statics: statics + 1,
654
727
  dynamics,
655
- optionals
728
+ optionals,
729
+ extract,
730
+ rawParams,
731
+ parsedParams
732
+ });
733
+ }
734
+ }
735
+ if (node.pathless) {
736
+ const nextDepth = depth + 1;
737
+ for (let i = node.pathless.length - 1; i >= 0; i--) {
738
+ const segment = node.pathless[i];
739
+ stack.push({
740
+ node: segment,
741
+ index,
742
+ skipped,
743
+ depth: nextDepth,
744
+ statics,
745
+ dynamics,
746
+ optionals,
747
+ extract,
748
+ rawParams,
749
+ parsedParams
656
750
  });
657
751
  }
658
752
  }
@@ -668,14 +762,24 @@ function getNodeMatch(path, parts, segmentTree, fuzzy) {
668
762
  sliceIndex += parts[i].length;
669
763
  }
670
764
  const splat = sliceIndex === path.length ? "/" : path.slice(sliceIndex);
671
- return {
672
- node: bestFuzzy.node,
673
- skipped: bestFuzzy.skipped,
674
- "**": decodeURIComponent(splat)
675
- };
765
+ bestFuzzy.rawParams ??= {};
766
+ bestFuzzy.rawParams["**"] = decodeURIComponent(splat);
767
+ return bestFuzzy;
676
768
  }
677
769
  return null;
678
770
  }
771
+ function validateMatchParams(path, parts, frame) {
772
+ try {
773
+ const [rawParams, state] = extractParams(path, parts, frame);
774
+ frame.rawParams = rawParams;
775
+ frame.extract = state;
776
+ const parsed = frame.node.parse(rawParams);
777
+ frame.parsedParams = Object.assign({}, frame.parsedParams, parsed);
778
+ return true;
779
+ } catch {
780
+ return null;
781
+ }
782
+ }
679
783
  function isFrameMoreSpecific(prev, next) {
680
784
  if (!prev) return true;
681
785
  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)));
@@ -1 +1 @@
1
- {"version":3,"file":"new-process-route-tree.js","sources":["../../src/new-process-route-tree.ts"],"sourcesContent":["import invariant from 'tiny-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\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 = SegmentKind | typeof SEGMENT_TYPE_INDEX\n\nconst PARAM_W_CURLY_BRACES_RE =\n /^([^{]*)\\{\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/ // prefix{$paramName}suffix\nconst OPTIONAL_PARAM_W_CURLY_BRACES_RE =\n /^([^{]*)\\{-\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/ // prefix{-$paramName}suffix\nconst WILDCARD_W_CURLY_BRACES_RE = /^([^{]*)\\{\\$\\}([^}]*)$/ // prefix{$}suffix\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 wildcardBracesMatch = part.match(WILDCARD_W_CURLY_BRACES_RE)\n if (wildcardBracesMatch) {\n const prefix = wildcardBracesMatch[1]!\n const pLength = prefix.length\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start + pLength\n output[2] = start + pLength + 1 // skip '{'\n output[3] = start + pLength + 2 // '$'\n output[4] = start + pLength + 3 // skip '}'\n output[5] = path.length\n return output as ParsedSegment\n }\n\n const optionalParamBracesMatch = part.match(OPTIONAL_PARAM_W_CURLY_BRACES_RE)\n if (optionalParamBracesMatch) {\n const prefix = optionalParamBracesMatch[1]!\n const paramName = optionalParamBracesMatch[2]!\n const suffix = optionalParamBracesMatch[3]!\n const pLength = prefix.length\n output[0] = SEGMENT_TYPE_OPTIONAL_PARAM\n output[1] = start + pLength\n output[2] = start + pLength + 3 // skip '{-$'\n output[3] = start + pLength + 3 + paramName.length\n output[4] = end - suffix.length\n output[5] = end\n return output as ParsedSegment\n }\n\n const paramBracesMatch = part.match(PARAM_W_CURLY_BRACES_RE)\n if (paramBracesMatch) {\n const prefix = paramBracesMatch[1]!\n const paramName = paramBracesMatch[2]!\n const suffix = paramBracesMatch[3]!\n const pLength = prefix.length\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start + pLength\n output[2] = start + pLength + 2 // skip '{$'\n output[3] = start + pLength + 2 + paramName.length\n output[4] = end - suffix.length\n output[5] = end\n return output as ParsedSegment\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 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 = node.dynamic?.find(\n (s) =>\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 = node.optional?.find(\n (s) =>\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 const isLeaf = (route.path || !route.children) && !route.isRoot\n\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 // 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: { prefix?: string; suffix?: string; caseSensitive: boolean },\n b: { prefix?: string; suffix?: string; caseSensitive: boolean },\n) {\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.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 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 }\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 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 caseSensitive,\n prefix,\n suffix,\n }\n}\n\ntype StaticSegmentNode<T extends RouteLike> = SegmentNode<T> & {\n kind: typeof SEGMENT_TYPE_PATHNAME | 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 /** 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\ntype RouteLike = {\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 }\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 params: 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 const result = findMatch(\n path,\n processedTree.segmentTree,\n fuzzy,\n ) as RouteMatch<T> | null\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\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): {\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 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 invariant(\n !(route.id in routesById),\n `Duplicate routes found with id: ${String(route.id)}`,\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): { route: T; params: Record<string, string> } | null {\n const parts = path.split('/')\n const leaf = getNodeMatch(path, parts, segmentTree, fuzzy)\n if (!leaf) return null\n const params = extractParams(path, parts, leaf)\n if ('**' in leaf) params['**'] = leaf['**']!\n const route = leaf.node.route!\n return {\n route,\n params,\n }\n}\n\nfunction extractParams<T extends RouteLike>(\n path: string,\n parts: Array<string>,\n leaf: { node: AnySegmentNode<T>; skipped: number },\n) {\n const list = buildBranch(leaf.node)\n let nodeParts: Array<string> | null = null\n const params: Record<string, string> = {}\n for (\n let partIndex = 0, nodeIndex = 0, pathIndex = 0;\n nodeIndex < list.length;\n partIndex++, nodeIndex++, pathIndex++\n ) {\n const node = list[nodeIndex]!\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[nodeIndex]!\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 params[name] = decodeURIComponent(value)\n } else {\n const name = nodePart.substring(1)\n params[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 continue\n }\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[nodeIndex]!\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) params[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 params['*'] = splat\n params._splat = splat\n break\n }\n }\n return params\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 statics: number\n dynamics: number\n optionals: number\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 }\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: 1,\n dynamics: 0,\n optionals: 0,\n },\n ]\n\n let wildcardMatch: Frame | null = null\n let bestFuzzy: Frame | null = null\n let bestMatch: Frame | null = null\n\n while (stack.length) {\n const frame = stack.pop()!\n // eslint-disable-next-line prefer-const\n let { node, index, skipped, depth, statics, dynamics, optionals } = frame\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 (node.route && !pathIsIndex && isFrameMoreSpecific(bestMatch, frame)) {\n bestMatch = frame\n }\n // beyond the length of the path parts, only index segments, or skipped optional segments, or wildcard segments can match\n if (!node.optional && !node.wildcard && !node.index) 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 }\n // perfect match, no need to continue\n // this is an optimization, algorithm should work correctly without this block\n if (statics === partsLength && !dynamics && !optionals && !skipped) {\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 // 5. Try wildcard match\n if (node.wildcard && isFrameMoreSpecific(wildcardMatch, frame)) {\n for (const segment of node.wildcard) {\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 // the first wildcard match is the highest priority one\n // wildcard matches skip the stack because they cannot have children\n wildcardMatch = {\n node: segment,\n index: partsLength,\n skipped,\n depth,\n statics,\n dynamics,\n optionals,\n }\n break\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 }) // 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 + 1,\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 + 1,\n optionals,\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 + 1,\n dynamics,\n optionals,\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 + 1,\n dynamics,\n optionals,\n })\n }\n }\n }\n\n if (bestMatch && wildcardMatch) {\n return isFrameMoreSpecific(wildcardMatch, bestMatch)\n ? bestMatch\n : wildcardMatch\n }\n\n if (bestMatch) return bestMatch\n\n if (wildcardMatch) return wildcardMatch\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 return {\n node: bestFuzzy.node,\n skipped: bestFuzzy.skipped,\n '**': decodeURIComponent(splat),\n }\n }\n\n return null\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"],"names":["start"],"mappings":"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"}
1
+ {"version":3,"file":"new-process-route-tree.js","sources":["../../src/new-process-route-tree.ts"],"sourcesContent":["import invariant from 'tiny-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\nconst PARAM_W_CURLY_BRACES_RE =\n /^([^{]*)\\{\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/ // prefix{$paramName}suffix\nconst OPTIONAL_PARAM_W_CURLY_BRACES_RE =\n /^([^{]*)\\{-\\$([a-zA-Z_$][a-zA-Z0-9_$]*)\\}([^}]*)$/ // prefix{-$paramName}suffix\nconst WILDCARD_W_CURLY_BRACES_RE = /^([^{]*)\\{\\$\\}([^}]*)$/ // prefix{$}suffix\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 wildcardBracesMatch = part.match(WILDCARD_W_CURLY_BRACES_RE)\n if (wildcardBracesMatch) {\n const prefix = wildcardBracesMatch[1]!\n const pLength = prefix.length\n output[0] = SEGMENT_TYPE_WILDCARD\n output[1] = start + pLength\n output[2] = start + pLength + 1 // skip '{'\n output[3] = start + pLength + 2 // '$'\n output[4] = start + pLength + 3 // skip '}'\n output[5] = path.length\n return output as ParsedSegment\n }\n\n const optionalParamBracesMatch = part.match(OPTIONAL_PARAM_W_CURLY_BRACES_RE)\n if (optionalParamBracesMatch) {\n const prefix = optionalParamBracesMatch[1]!\n const paramName = optionalParamBracesMatch[2]!\n const suffix = optionalParamBracesMatch[3]!\n const pLength = prefix.length\n output[0] = SEGMENT_TYPE_OPTIONAL_PARAM\n output[1] = start + pLength\n output[2] = start + pLength + 3 // skip '{-$'\n output[3] = start + pLength + 3 + paramName.length\n output[4] = end - suffix.length\n output[5] = end\n return output as ParsedSegment\n }\n\n const paramBracesMatch = part.match(PARAM_W_CURLY_BRACES_RE)\n if (paramBracesMatch) {\n const prefix = paramBracesMatch[1]!\n const paramName = paramBracesMatch[2]!\n const suffix = paramBracesMatch[3]!\n const pLength = prefix.length\n output[0] = SEGMENT_TYPE_PARAM\n output[1] = start + pLength\n output[2] = start + pLength + 2 // skip '{$'\n output[3] = start + pLength + 2 + paramName.length\n output[4] = end - suffix.length\n output[5] = end\n return output as ParsedSegment\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 const result = findMatch(\n path,\n processedTree.segmentTree,\n fuzzy,\n ) as RouteMatch<T> | null\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\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): {\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 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 invariant(\n !(route.id in routesById),\n `Duplicate routes found with id: ${String(route.id)}`,\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\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?: { part: number; node: number; path: number }\n rawParams?: Record<string, string>\n },\n): [\n rawParams: Record<string, string>,\n state: { part: number; node: number; path: number },\n] {\n const list = buildBranch(leaf.node)\n let nodeParts: Array<string> | null = null\n const rawParams: Record<string, string> = {}\n let partIndex = leaf.extract?.part ?? 0\n let nodeIndex = leaf.extract?.node ?? 0\n let pathIndex = leaf.extract?.path ?? 0\n for (; nodeIndex < list.length; partIndex++, nodeIndex++, pathIndex++) {\n const node = list[nodeIndex]!\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[nodeIndex]!\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 continue\n }\n nodeParts ??= leaf.node.fullPath.split('/')\n const nodePart = nodeParts[nodeIndex]!\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 [rawParams, { part: partIndex, node: nodeIndex, path: pathIndex }]\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 statics: number\n dynamics: number\n optionals: number\n /** intermediary state for param extraction */\n extract?: { part: number; node: number; path: number }\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: 1,\n dynamics: 0,\n optionals: 0,\n },\n ]\n\n let wildcardMatch: Frame | null = null\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 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 (node.route && !pathIsIndex && isFrameMoreSpecific(bestMatch, frame)) {\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 if (node.index.skipOnParamError) {\n const result = validateMatchParams(path, parts, indexFrame)\n if (!result) continue\n }\n // perfect match, no need to continue\n // this is an optimization, algorithm should work correctly without this block\n if (statics === partsLength && !dynamics && !optionals && !skipped) {\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 // 5. Try wildcard match\n if (node.wildcard && isFrameMoreSpecific(wildcardMatch, frame)) {\n for (const segment of node.wildcard) {\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 // the first wildcard match is the highest priority one\n // wildcard matches skip the stack because they cannot have children\n const frame = {\n node: segment,\n index: partsLength,\n skipped,\n depth,\n statics,\n dynamics,\n optionals,\n extract,\n rawParams,\n parsedParams,\n }\n if (segment.skipOnParamError) {\n const result = validateMatchParams(path, parts, frame)\n if (!result) continue\n }\n wildcardMatch = frame\n break\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 + 1,\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 + 1,\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 + 1,\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 + 1,\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 && wildcardMatch) {\n return isFrameMoreSpecific(wildcardMatch, bestMatch)\n ? bestMatch\n : wildcardMatch\n }\n\n if (bestMatch) return bestMatch\n\n if (wildcardMatch) return wildcardMatch\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 ??= {}\n bestFuzzy.rawParams['**'] = decodeURIComponent(splat)\n return bestFuzzy\n }\n\n return null\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({}, frame.parsedParams, parsed)\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"],"names":["start","frame"],"mappings":"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"}