@tanstack/router-core 1.167.1 → 1.167.3

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.
Files changed (164) hide show
  1. package/dist/cjs/Matches.cjs +15 -12
  2. package/dist/cjs/Matches.cjs.map +1 -1
  3. package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
  4. package/dist/cjs/config.cjs +9 -8
  5. package/dist/cjs/config.cjs.map +1 -1
  6. package/dist/cjs/defer.cjs +37 -21
  7. package/dist/cjs/defer.cjs.map +1 -1
  8. package/dist/cjs/index.cjs +87 -89
  9. package/dist/cjs/isServer/client.cjs +5 -3
  10. package/dist/cjs/isServer/client.cjs.map +1 -1
  11. package/dist/cjs/isServer/development.cjs +5 -3
  12. package/dist/cjs/isServer/development.cjs.map +1 -1
  13. package/dist/cjs/isServer/server.cjs +5 -3
  14. package/dist/cjs/isServer/server.cjs.map +1 -1
  15. package/dist/cjs/link.cjs +5 -4
  16. package/dist/cjs/link.cjs.map +1 -1
  17. package/dist/cjs/load-matches.cjs +622 -766
  18. package/dist/cjs/load-matches.cjs.map +1 -1
  19. package/dist/cjs/lru-cache.cjs +67 -64
  20. package/dist/cjs/lru-cache.cjs.map +1 -1
  21. package/dist/cjs/new-process-route-tree.cjs +707 -792
  22. package/dist/cjs/new-process-route-tree.cjs.map +1 -1
  23. package/dist/cjs/not-found.cjs +20 -7
  24. package/dist/cjs/not-found.cjs.map +1 -1
  25. package/dist/cjs/path.cjs +221 -232
  26. package/dist/cjs/path.cjs.map +1 -1
  27. package/dist/cjs/qss.cjs +62 -28
  28. package/dist/cjs/qss.cjs.map +1 -1
  29. package/dist/cjs/redirect.cjs +44 -30
  30. package/dist/cjs/redirect.cjs.map +1 -1
  31. package/dist/cjs/rewrite.cjs +56 -56
  32. package/dist/cjs/rewrite.cjs.map +1 -1
  33. package/dist/cjs/root.cjs +6 -4
  34. package/dist/cjs/root.cjs.map +1 -1
  35. package/dist/cjs/route.cjs +96 -105
  36. package/dist/cjs/route.cjs.map +1 -1
  37. package/dist/cjs/router.cjs +1154 -1524
  38. package/dist/cjs/router.cjs.map +1 -1
  39. package/dist/cjs/scroll-restoration.cjs +189 -207
  40. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  41. package/dist/cjs/searchMiddleware.cjs +48 -37
  42. package/dist/cjs/searchMiddleware.cjs.map +1 -1
  43. package/dist/cjs/searchParams.cjs +57 -45
  44. package/dist/cjs/searchParams.cjs.map +1 -1
  45. package/dist/cjs/ssr/client.cjs +6 -8
  46. package/dist/cjs/ssr/constants.cjs +6 -5
  47. package/dist/cjs/ssr/constants.cjs.map +1 -1
  48. package/dist/cjs/ssr/createRequestHandler.cjs +41 -59
  49. package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
  50. package/dist/cjs/ssr/handlerCallback.cjs +5 -4
  51. package/dist/cjs/ssr/handlerCallback.cjs.map +1 -1
  52. package/dist/cjs/ssr/headers.cjs +17 -26
  53. package/dist/cjs/ssr/headers.cjs.map +1 -1
  54. package/dist/cjs/ssr/json.cjs +8 -4
  55. package/dist/cjs/ssr/json.cjs.map +1 -1
  56. package/dist/cjs/ssr/serializer/RawStream.cjs +268 -268
  57. package/dist/cjs/ssr/serializer/RawStream.cjs.map +1 -1
  58. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs +31 -32
  59. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs.map +1 -1
  60. package/dist/cjs/ssr/serializer/seroval-plugins.cjs +12 -12
  61. package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -1
  62. package/dist/cjs/ssr/serializer/transformer.cjs +45 -41
  63. package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -1
  64. package/dist/cjs/ssr/server.cjs +12 -14
  65. package/dist/cjs/ssr/ssr-client.cjs +173 -211
  66. package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
  67. package/dist/cjs/ssr/ssr-match-id.cjs +6 -5
  68. package/dist/cjs/ssr/ssr-match-id.cjs.map +1 -1
  69. package/dist/cjs/ssr/ssr-server.cjs +266 -300
  70. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  71. package/dist/cjs/ssr/transformStreamWithRouter.cjs +317 -337
  72. package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
  73. package/dist/cjs/ssr/tsrScript.cjs +6 -4
  74. package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
  75. package/dist/cjs/utils/batch.cjs +13 -13
  76. package/dist/cjs/utils/batch.cjs.map +1 -1
  77. package/dist/cjs/utils.cjs +274 -208
  78. package/dist/cjs/utils.cjs.map +1 -1
  79. package/dist/esm/Matches.js +16 -13
  80. package/dist/esm/Matches.js.map +1 -1
  81. package/dist/esm/config.js +10 -9
  82. package/dist/esm/config.js.map +1 -1
  83. package/dist/esm/defer.js +37 -22
  84. package/dist/esm/defer.js.map +1 -1
  85. package/dist/esm/index.js +12 -82
  86. package/dist/esm/isServer/client.js +6 -5
  87. package/dist/esm/isServer/client.js.map +1 -1
  88. package/dist/esm/isServer/development.js +6 -5
  89. package/dist/esm/isServer/development.js.map +1 -1
  90. package/dist/esm/isServer/server.js +6 -5
  91. package/dist/esm/isServer/server.js.map +1 -1
  92. package/dist/esm/link.js +6 -5
  93. package/dist/esm/link.js.map +1 -1
  94. package/dist/esm/load-matches.js +617 -765
  95. package/dist/esm/load-matches.js.map +1 -1
  96. package/dist/esm/lru-cache.js +68 -65
  97. package/dist/esm/lru-cache.js.map +1 -1
  98. package/dist/esm/new-process-route-tree.js +705 -797
  99. package/dist/esm/new-process-route-tree.js.map +1 -1
  100. package/dist/esm/not-found.js +21 -9
  101. package/dist/esm/not-found.js.map +1 -1
  102. package/dist/esm/path.js +220 -241
  103. package/dist/esm/path.js.map +1 -1
  104. package/dist/esm/qss.js +63 -30
  105. package/dist/esm/qss.js.map +1 -1
  106. package/dist/esm/redirect.js +45 -34
  107. package/dist/esm/redirect.js.map +1 -1
  108. package/dist/esm/rewrite.js +57 -60
  109. package/dist/esm/rewrite.js.map +1 -1
  110. package/dist/esm/root.js +7 -5
  111. package/dist/esm/root.js.map +1 -1
  112. package/dist/esm/route.js +92 -105
  113. package/dist/esm/route.js.map +1 -1
  114. package/dist/esm/router.js +1148 -1527
  115. package/dist/esm/router.js.map +1 -1
  116. package/dist/esm/scroll-restoration.js +188 -213
  117. package/dist/esm/scroll-restoration.js.map +1 -1
  118. package/dist/esm/searchMiddleware.js +48 -38
  119. package/dist/esm/searchMiddleware.js.map +1 -1
  120. package/dist/esm/searchParams.js +57 -48
  121. package/dist/esm/searchParams.js.map +1 -1
  122. package/dist/esm/ssr/client.js +1 -6
  123. package/dist/esm/ssr/constants.js +7 -7
  124. package/dist/esm/ssr/constants.js.map +1 -1
  125. package/dist/esm/ssr/createRequestHandler.js +39 -58
  126. package/dist/esm/ssr/createRequestHandler.js.map +1 -1
  127. package/dist/esm/ssr/handlerCallback.js +6 -5
  128. package/dist/esm/ssr/handlerCallback.js.map +1 -1
  129. package/dist/esm/ssr/headers.js +16 -26
  130. package/dist/esm/ssr/headers.js.map +1 -1
  131. package/dist/esm/ssr/json.js +9 -5
  132. package/dist/esm/ssr/json.js.map +1 -1
  133. package/dist/esm/ssr/serializer/RawStream.js +267 -273
  134. package/dist/esm/ssr/serializer/RawStream.js.map +1 -1
  135. package/dist/esm/ssr/serializer/ShallowErrorPlugin.js +31 -32
  136. package/dist/esm/ssr/serializer/ShallowErrorPlugin.js.map +1 -1
  137. package/dist/esm/ssr/serializer/seroval-plugins.js +10 -11
  138. package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -1
  139. package/dist/esm/ssr/serializer/transformer.js +44 -43
  140. package/dist/esm/ssr/serializer/transformer.js.map +1 -1
  141. package/dist/esm/ssr/server.js +2 -12
  142. package/dist/esm/ssr/ssr-client.js +169 -209
  143. package/dist/esm/ssr/ssr-client.js.map +1 -1
  144. package/dist/esm/ssr/ssr-match-id.js +7 -7
  145. package/dist/esm/ssr/ssr-match-id.js.map +1 -1
  146. package/dist/esm/ssr/ssr-server.js +262 -300
  147. package/dist/esm/ssr/ssr-server.js.map +1 -1
  148. package/dist/esm/ssr/transformStreamWithRouter.js +315 -338
  149. package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
  150. package/dist/esm/ssr/tsrScript.js +6 -5
  151. package/dist/esm/ssr/tsrScript.js.map +1 -1
  152. package/dist/esm/utils/batch.js +13 -14
  153. package/dist/esm/utils/batch.js.map +1 -1
  154. package/dist/esm/utils.js +273 -224
  155. package/dist/esm/utils.js.map +1 -1
  156. package/package.json +2 -2
  157. package/src/load-matches.ts +4 -1
  158. package/src/router.ts +2 -1
  159. package/dist/cjs/index.cjs.map +0 -1
  160. package/dist/cjs/ssr/client.cjs.map +0 -1
  161. package/dist/cjs/ssr/server.cjs.map +0 -1
  162. package/dist/esm/index.js.map +0 -1
  163. package/dist/esm/ssr/client.js.map +0 -1
  164. package/dist/esm/ssr/server.js.map +0 -1
@@ -1,838 +1,746 @@
1
- import invariant from "tiny-invariant";
2
- import { createLRUCache } from "./lru-cache.js";
3
1
  import { last } from "./utils.js";
4
- const SEGMENT_TYPE_PATHNAME = 0;
5
- const SEGMENT_TYPE_PARAM = 1;
6
- const SEGMENT_TYPE_WILDCARD = 2;
7
- const SEGMENT_TYPE_OPTIONAL_PARAM = 3;
8
- const SEGMENT_TYPE_INDEX = 4;
9
- const SEGMENT_TYPE_PATHLESS = 5;
2
+ import { createLRUCache } from "./lru-cache.js";
3
+ import invariant from "tiny-invariant";
4
+ var SEGMENT_TYPE_INDEX = 4;
5
+ var SEGMENT_TYPE_PATHLESS = 5;
10
6
  function getOpenAndCloseBraces(part) {
11
- const openBrace = part.indexOf("{");
12
- if (openBrace === -1) return null;
13
- const closeBrace = part.indexOf("}", openBrace);
14
- if (closeBrace === -1) return null;
15
- const afterOpen = openBrace + 1;
16
- if (afterOpen >= part.length) return null;
17
- return [openBrace, closeBrace];
7
+ const openBrace = part.indexOf("{");
8
+ if (openBrace === -1) return null;
9
+ const closeBrace = part.indexOf("}", openBrace);
10
+ if (closeBrace === -1) return null;
11
+ if (openBrace + 1 >= part.length) return null;
12
+ return [openBrace, closeBrace];
18
13
  }
14
+ /**
15
+ * Populates the `output` array with the parsed representation of the given `segment` string.
16
+ *
17
+ * Usage:
18
+ * ```ts
19
+ * let output
20
+ * let cursor = 0
21
+ * while (cursor < path.length) {
22
+ * output = parseSegment(path, cursor, output)
23
+ * const end = output[5]
24
+ * cursor = end + 1
25
+ * ```
26
+ *
27
+ * `output` is stored outside to avoid allocations during repeated calls. It doesn't need to be typed
28
+ * or initialized, it will be done automatically.
29
+ */
19
30
  function parseSegment(path, start, output = new Uint16Array(6)) {
20
- const next = path.indexOf("/", start);
21
- const end = next === -1 ? path.length : next;
22
- const part = path.substring(start, end);
23
- if (!part || !part.includes("$")) {
24
- output[0] = SEGMENT_TYPE_PATHNAME;
25
- output[1] = start;
26
- output[2] = start;
27
- output[3] = end;
28
- output[4] = end;
29
- output[5] = end;
30
- return output;
31
- }
32
- if (part === "$") {
33
- const total = path.length;
34
- output[0] = SEGMENT_TYPE_WILDCARD;
35
- output[1] = start;
36
- output[2] = start;
37
- output[3] = total;
38
- output[4] = total;
39
- output[5] = total;
40
- return output;
41
- }
42
- if (part.charCodeAt(0) === 36) {
43
- output[0] = SEGMENT_TYPE_PARAM;
44
- output[1] = start;
45
- output[2] = start + 1;
46
- output[3] = end;
47
- output[4] = end;
48
- output[5] = end;
49
- return output;
50
- }
51
- const braces = getOpenAndCloseBraces(part);
52
- if (braces) {
53
- const [openBrace, closeBrace] = braces;
54
- const firstChar = part.charCodeAt(openBrace + 1);
55
- if (firstChar === 45) {
56
- if (openBrace + 2 < part.length && part.charCodeAt(openBrace + 2) === 36) {
57
- const paramStart = openBrace + 3;
58
- const paramEnd = closeBrace;
59
- if (paramStart < paramEnd) {
60
- output[0] = SEGMENT_TYPE_OPTIONAL_PARAM;
61
- output[1] = start + openBrace;
62
- output[2] = start + paramStart;
63
- output[3] = start + paramEnd;
64
- output[4] = start + closeBrace + 1;
65
- output[5] = end;
66
- return output;
67
- }
68
- }
69
- } else if (firstChar === 36) {
70
- const dollarPos = openBrace + 1;
71
- const afterDollar = openBrace + 2;
72
- if (afterDollar === closeBrace) {
73
- output[0] = SEGMENT_TYPE_WILDCARD;
74
- output[1] = start + openBrace;
75
- output[2] = start + dollarPos;
76
- output[3] = start + afterDollar;
77
- output[4] = start + closeBrace + 1;
78
- output[5] = path.length;
79
- return output;
80
- }
81
- output[0] = SEGMENT_TYPE_PARAM;
82
- output[1] = start + openBrace;
83
- output[2] = start + afterDollar;
84
- output[3] = start + closeBrace;
85
- output[4] = start + closeBrace + 1;
86
- output[5] = end;
87
- return output;
88
- }
89
- }
90
- output[0] = SEGMENT_TYPE_PATHNAME;
91
- output[1] = start;
92
- output[2] = start;
93
- output[3] = end;
94
- output[4] = end;
95
- output[5] = end;
96
- return output;
31
+ const next = path.indexOf("/", start);
32
+ const end = next === -1 ? path.length : next;
33
+ const part = path.substring(start, end);
34
+ if (!part || !part.includes("$")) {
35
+ output[0] = 0;
36
+ output[1] = start;
37
+ output[2] = start;
38
+ output[3] = end;
39
+ output[4] = end;
40
+ output[5] = end;
41
+ return output;
42
+ }
43
+ if (part === "$") {
44
+ const total = path.length;
45
+ output[0] = 2;
46
+ output[1] = start;
47
+ output[2] = start;
48
+ output[3] = total;
49
+ output[4] = total;
50
+ output[5] = total;
51
+ return output;
52
+ }
53
+ if (part.charCodeAt(0) === 36) {
54
+ output[0] = 1;
55
+ output[1] = start;
56
+ output[2] = start + 1;
57
+ output[3] = end;
58
+ output[4] = end;
59
+ output[5] = end;
60
+ return output;
61
+ }
62
+ const braces = getOpenAndCloseBraces(part);
63
+ if (braces) {
64
+ const [openBrace, closeBrace] = braces;
65
+ const firstChar = part.charCodeAt(openBrace + 1);
66
+ if (firstChar === 45) {
67
+ if (openBrace + 2 < part.length && part.charCodeAt(openBrace + 2) === 36) {
68
+ const paramStart = openBrace + 3;
69
+ const paramEnd = closeBrace;
70
+ if (paramStart < paramEnd) {
71
+ output[0] = 3;
72
+ output[1] = start + openBrace;
73
+ output[2] = start + paramStart;
74
+ output[3] = start + paramEnd;
75
+ output[4] = start + closeBrace + 1;
76
+ output[5] = end;
77
+ return output;
78
+ }
79
+ }
80
+ } else if (firstChar === 36) {
81
+ const dollarPos = openBrace + 1;
82
+ const afterDollar = openBrace + 2;
83
+ if (afterDollar === closeBrace) {
84
+ output[0] = 2;
85
+ output[1] = start + openBrace;
86
+ output[2] = start + dollarPos;
87
+ output[3] = start + afterDollar;
88
+ output[4] = start + closeBrace + 1;
89
+ output[5] = path.length;
90
+ return output;
91
+ }
92
+ output[0] = 1;
93
+ output[1] = start + openBrace;
94
+ output[2] = start + afterDollar;
95
+ output[3] = start + closeBrace;
96
+ output[4] = start + closeBrace + 1;
97
+ output[5] = end;
98
+ return output;
99
+ }
100
+ }
101
+ output[0] = 0;
102
+ output[1] = start;
103
+ output[2] = start;
104
+ output[3] = end;
105
+ output[4] = end;
106
+ output[5] = end;
107
+ return output;
97
108
  }
109
+ /**
110
+ * Recursively parses the segments of the given route tree and populates a segment trie.
111
+ *
112
+ * @param data A reusable Uint16Array for parsing segments. (non important, we're just avoiding allocations)
113
+ * @param route The current route to parse.
114
+ * @param start The starting index for parsing within the route's full path.
115
+ * @param node The current segment node in the trie to populate.
116
+ * @param onRoute Callback invoked for each route processed.
117
+ */
98
118
  function parseSegments(defaultCaseSensitive, data, route, start, node, depth, onRoute) {
99
- onRoute?.(route);
100
- let cursor = start;
101
- {
102
- const path = route.fullPath ?? route.from;
103
- const length = path.length;
104
- const caseSensitive = route.options?.caseSensitive ?? defaultCaseSensitive;
105
- const skipOnParamError = !!(route.options?.params?.parse && route.options?.skipRouteOnParseError?.params);
106
- while (cursor < length) {
107
- const segment = parseSegment(path, cursor, data);
108
- let nextNode;
109
- const start2 = cursor;
110
- const end = segment[5];
111
- cursor = end + 1;
112
- depth++;
113
- const kind = segment[0];
114
- switch (kind) {
115
- case SEGMENT_TYPE_PATHNAME: {
116
- const value = path.substring(segment[2], segment[3]);
117
- if (caseSensitive) {
118
- const existingNode = node.static?.get(value);
119
- if (existingNode) {
120
- nextNode = existingNode;
121
- } else {
122
- node.static ??= /* @__PURE__ */ new Map();
123
- const next = createStaticNode(
124
- route.fullPath ?? route.from
125
- );
126
- next.parent = node;
127
- next.depth = depth;
128
- nextNode = next;
129
- node.static.set(value, next);
130
- }
131
- } else {
132
- const name = value.toLowerCase();
133
- const existingNode = node.staticInsensitive?.get(name);
134
- if (existingNode) {
135
- nextNode = existingNode;
136
- } else {
137
- node.staticInsensitive ??= /* @__PURE__ */ new Map();
138
- const next = createStaticNode(
139
- route.fullPath ?? route.from
140
- );
141
- next.parent = node;
142
- next.depth = depth;
143
- nextNode = next;
144
- node.staticInsensitive.set(name, next);
145
- }
146
- }
147
- break;
148
- }
149
- case SEGMENT_TYPE_PARAM: {
150
- const prefix_raw = path.substring(start2, segment[1]);
151
- const suffix_raw = path.substring(segment[4], end);
152
- const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
153
- const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
154
- const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
155
- const existingNode = !skipOnParamError && node.dynamic?.find(
156
- (s) => !s.skipOnParamError && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix
157
- );
158
- if (existingNode) {
159
- nextNode = existingNode;
160
- } else {
161
- const next = createDynamicNode(
162
- SEGMENT_TYPE_PARAM,
163
- route.fullPath ?? route.from,
164
- actuallyCaseSensitive,
165
- prefix,
166
- suffix
167
- );
168
- nextNode = next;
169
- next.depth = depth;
170
- next.parent = node;
171
- node.dynamic ??= [];
172
- node.dynamic.push(next);
173
- }
174
- break;
175
- }
176
- case SEGMENT_TYPE_OPTIONAL_PARAM: {
177
- const prefix_raw = path.substring(start2, segment[1]);
178
- const suffix_raw = path.substring(segment[4], end);
179
- const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
180
- const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
181
- const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
182
- const existingNode = !skipOnParamError && node.optional?.find(
183
- (s) => !s.skipOnParamError && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix
184
- );
185
- if (existingNode) {
186
- nextNode = existingNode;
187
- } else {
188
- const next = createDynamicNode(
189
- SEGMENT_TYPE_OPTIONAL_PARAM,
190
- route.fullPath ?? route.from,
191
- actuallyCaseSensitive,
192
- prefix,
193
- suffix
194
- );
195
- nextNode = next;
196
- next.parent = node;
197
- next.depth = depth;
198
- node.optional ??= [];
199
- node.optional.push(next);
200
- }
201
- break;
202
- }
203
- case SEGMENT_TYPE_WILDCARD: {
204
- const prefix_raw = path.substring(start2, segment[1]);
205
- const suffix_raw = path.substring(segment[4], end);
206
- const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
207
- const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
208
- const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
209
- const next = createDynamicNode(
210
- SEGMENT_TYPE_WILDCARD,
211
- route.fullPath ?? route.from,
212
- actuallyCaseSensitive,
213
- prefix,
214
- suffix
215
- );
216
- nextNode = next;
217
- next.parent = node;
218
- next.depth = depth;
219
- node.wildcard ??= [];
220
- node.wildcard.push(next);
221
- }
222
- }
223
- node = nextNode;
224
- }
225
- if (skipOnParamError && route.children && !route.isRoot && route.id && route.id.charCodeAt(route.id.lastIndexOf("/") + 1) === 95) {
226
- const pathlessNode = createStaticNode(
227
- route.fullPath ?? route.from
228
- );
229
- pathlessNode.kind = SEGMENT_TYPE_PATHLESS;
230
- pathlessNode.parent = node;
231
- depth++;
232
- pathlessNode.depth = depth;
233
- node.pathless ??= [];
234
- node.pathless.push(pathlessNode);
235
- node = pathlessNode;
236
- }
237
- const isLeaf = (route.path || !route.children) && !route.isRoot;
238
- if (isLeaf && path.endsWith("/")) {
239
- const indexNode = createStaticNode(
240
- route.fullPath ?? route.from
241
- );
242
- indexNode.kind = SEGMENT_TYPE_INDEX;
243
- indexNode.parent = node;
244
- depth++;
245
- indexNode.depth = depth;
246
- node.index = indexNode;
247
- node = indexNode;
248
- }
249
- node.parse = route.options?.params?.parse ?? null;
250
- node.skipOnParamError = skipOnParamError;
251
- node.parsingPriority = route.options?.skipRouteOnParseError?.priority ?? 0;
252
- if (isLeaf && !node.route) {
253
- node.route = route;
254
- node.fullPath = route.fullPath ?? route.from;
255
- }
256
- }
257
- if (route.children)
258
- for (const child of route.children) {
259
- parseSegments(
260
- defaultCaseSensitive,
261
- data,
262
- child,
263
- cursor,
264
- node,
265
- depth,
266
- onRoute
267
- );
268
- }
119
+ onRoute?.(route);
120
+ let cursor = start;
121
+ {
122
+ const path = route.fullPath ?? route.from;
123
+ const length = path.length;
124
+ const caseSensitive = route.options?.caseSensitive ?? defaultCaseSensitive;
125
+ const skipOnParamError = !!(route.options?.params?.parse && route.options?.skipRouteOnParseError?.params);
126
+ while (cursor < length) {
127
+ const segment = parseSegment(path, cursor, data);
128
+ let nextNode;
129
+ const start = cursor;
130
+ const end = segment[5];
131
+ cursor = end + 1;
132
+ depth++;
133
+ switch (segment[0]) {
134
+ case 0: {
135
+ const value = path.substring(segment[2], segment[3]);
136
+ if (caseSensitive) {
137
+ const existingNode = node.static?.get(value);
138
+ if (existingNode) nextNode = existingNode;
139
+ else {
140
+ node.static ??= /* @__PURE__ */ new Map();
141
+ const next = createStaticNode(route.fullPath ?? route.from);
142
+ next.parent = node;
143
+ next.depth = depth;
144
+ nextNode = next;
145
+ node.static.set(value, next);
146
+ }
147
+ } else {
148
+ const name = value.toLowerCase();
149
+ const existingNode = node.staticInsensitive?.get(name);
150
+ if (existingNode) nextNode = existingNode;
151
+ else {
152
+ node.staticInsensitive ??= /* @__PURE__ */ new Map();
153
+ const next = createStaticNode(route.fullPath ?? route.from);
154
+ next.parent = node;
155
+ next.depth = depth;
156
+ nextNode = next;
157
+ node.staticInsensitive.set(name, next);
158
+ }
159
+ }
160
+ break;
161
+ }
162
+ case 1: {
163
+ const prefix_raw = path.substring(start, segment[1]);
164
+ const suffix_raw = path.substring(segment[4], end);
165
+ const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
166
+ const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
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);
169
+ if (existingNode) nextNode = existingNode;
170
+ else {
171
+ const next = createDynamicNode(1, route.fullPath ?? route.from, actuallyCaseSensitive, prefix, suffix);
172
+ nextNode = next;
173
+ next.depth = depth;
174
+ next.parent = node;
175
+ node.dynamic ??= [];
176
+ node.dynamic.push(next);
177
+ }
178
+ break;
179
+ }
180
+ case 3: {
181
+ const prefix_raw = path.substring(start, segment[1]);
182
+ const suffix_raw = path.substring(segment[4], end);
183
+ const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
184
+ const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
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);
187
+ if (existingNode) nextNode = existingNode;
188
+ else {
189
+ const next = createDynamicNode(3, route.fullPath ?? route.from, actuallyCaseSensitive, prefix, suffix);
190
+ nextNode = next;
191
+ next.parent = node;
192
+ next.depth = depth;
193
+ node.optional ??= [];
194
+ node.optional.push(next);
195
+ }
196
+ break;
197
+ }
198
+ case 2: {
199
+ const prefix_raw = path.substring(start, segment[1]);
200
+ const suffix_raw = path.substring(segment[4], end);
201
+ const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
202
+ const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
203
+ const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
204
+ const next = createDynamicNode(2, route.fullPath ?? route.from, actuallyCaseSensitive, prefix, suffix);
205
+ nextNode = next;
206
+ next.parent = node;
207
+ next.depth = depth;
208
+ node.wildcard ??= [];
209
+ node.wildcard.push(next);
210
+ }
211
+ }
212
+ node = nextNode;
213
+ }
214
+ if (skipOnParamError && route.children && !route.isRoot && route.id && route.id.charCodeAt(route.id.lastIndexOf("/") + 1) === 95) {
215
+ const pathlessNode = createStaticNode(route.fullPath ?? route.from);
216
+ pathlessNode.kind = SEGMENT_TYPE_PATHLESS;
217
+ pathlessNode.parent = node;
218
+ depth++;
219
+ pathlessNode.depth = depth;
220
+ node.pathless ??= [];
221
+ node.pathless.push(pathlessNode);
222
+ node = pathlessNode;
223
+ }
224
+ const isLeaf = (route.path || !route.children) && !route.isRoot;
225
+ if (isLeaf && path.endsWith("/")) {
226
+ const indexNode = createStaticNode(route.fullPath ?? route.from);
227
+ indexNode.kind = SEGMENT_TYPE_INDEX;
228
+ indexNode.parent = node;
229
+ depth++;
230
+ indexNode.depth = depth;
231
+ node.index = indexNode;
232
+ node = indexNode;
233
+ }
234
+ node.parse = route.options?.params?.parse ?? null;
235
+ node.skipOnParamError = skipOnParamError;
236
+ node.parsingPriority = route.options?.skipRouteOnParseError?.priority ?? 0;
237
+ if (isLeaf && !node.route) {
238
+ node.route = route;
239
+ node.fullPath = route.fullPath ?? route.from;
240
+ }
241
+ }
242
+ if (route.children) for (const child of route.children) parseSegments(defaultCaseSensitive, data, child, cursor, node, depth, onRoute);
269
243
  }
270
244
  function sortDynamic(a, b) {
271
- if (a.skipOnParamError && !b.skipOnParamError) return -1;
272
- if (!a.skipOnParamError && b.skipOnParamError) return 1;
273
- if (a.skipOnParamError && b.skipOnParamError && (a.parsingPriority || b.parsingPriority))
274
- return b.parsingPriority - a.parsingPriority;
275
- if (a.prefix && b.prefix && a.prefix !== b.prefix) {
276
- if (a.prefix.startsWith(b.prefix)) return -1;
277
- if (b.prefix.startsWith(a.prefix)) return 1;
278
- }
279
- if (a.suffix && b.suffix && a.suffix !== b.suffix) {
280
- if (a.suffix.endsWith(b.suffix)) return -1;
281
- if (b.suffix.endsWith(a.suffix)) return 1;
282
- }
283
- if (a.prefix && !b.prefix) return -1;
284
- if (!a.prefix && b.prefix) return 1;
285
- if (a.suffix && !b.suffix) return -1;
286
- if (!a.suffix && b.suffix) return 1;
287
- if (a.caseSensitive && !b.caseSensitive) return -1;
288
- if (!a.caseSensitive && b.caseSensitive) return 1;
289
- return 0;
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;
248
+ if (a.prefix && b.prefix && a.prefix !== b.prefix) {
249
+ if (a.prefix.startsWith(b.prefix)) return -1;
250
+ if (b.prefix.startsWith(a.prefix)) return 1;
251
+ }
252
+ if (a.suffix && b.suffix && a.suffix !== b.suffix) {
253
+ if (a.suffix.endsWith(b.suffix)) return -1;
254
+ if (b.suffix.endsWith(a.suffix)) return 1;
255
+ }
256
+ if (a.prefix && !b.prefix) return -1;
257
+ if (!a.prefix && b.prefix) return 1;
258
+ if (a.suffix && !b.suffix) return -1;
259
+ if (!a.suffix && b.suffix) return 1;
260
+ if (a.caseSensitive && !b.caseSensitive) return -1;
261
+ if (!a.caseSensitive && b.caseSensitive) return 1;
262
+ return 0;
290
263
  }
291
264
  function sortTreeNodes(node) {
292
- if (node.pathless) {
293
- for (const child of node.pathless) {
294
- sortTreeNodes(child);
295
- }
296
- }
297
- if (node.static) {
298
- for (const child of node.static.values()) {
299
- sortTreeNodes(child);
300
- }
301
- }
302
- if (node.staticInsensitive) {
303
- for (const child of node.staticInsensitive.values()) {
304
- sortTreeNodes(child);
305
- }
306
- }
307
- if (node.dynamic?.length) {
308
- node.dynamic.sort(sortDynamic);
309
- for (const child of node.dynamic) {
310
- sortTreeNodes(child);
311
- }
312
- }
313
- if (node.optional?.length) {
314
- node.optional.sort(sortDynamic);
315
- for (const child of node.optional) {
316
- sortTreeNodes(child);
317
- }
318
- }
319
- if (node.wildcard?.length) {
320
- node.wildcard.sort(sortDynamic);
321
- for (const child of node.wildcard) {
322
- sortTreeNodes(child);
323
- }
324
- }
265
+ if (node.pathless) for (const child of node.pathless) sortTreeNodes(child);
266
+ if (node.static) for (const child of node.static.values()) sortTreeNodes(child);
267
+ if (node.staticInsensitive) for (const child of node.staticInsensitive.values()) sortTreeNodes(child);
268
+ if (node.dynamic?.length) {
269
+ node.dynamic.sort(sortDynamic);
270
+ for (const child of node.dynamic) sortTreeNodes(child);
271
+ }
272
+ if (node.optional?.length) {
273
+ node.optional.sort(sortDynamic);
274
+ for (const child of node.optional) sortTreeNodes(child);
275
+ }
276
+ if (node.wildcard?.length) {
277
+ node.wildcard.sort(sortDynamic);
278
+ for (const child of node.wildcard) sortTreeNodes(child);
279
+ }
325
280
  }
326
281
  function createStaticNode(fullPath) {
327
- return {
328
- kind: SEGMENT_TYPE_PATHNAME,
329
- depth: 0,
330
- pathless: null,
331
- index: null,
332
- static: null,
333
- staticInsensitive: null,
334
- dynamic: null,
335
- optional: null,
336
- wildcard: null,
337
- route: null,
338
- fullPath,
339
- parent: null,
340
- parse: null,
341
- skipOnParamError: false,
342
- parsingPriority: 0
343
- };
282
+ return {
283
+ kind: 0,
284
+ depth: 0,
285
+ pathless: null,
286
+ index: null,
287
+ static: null,
288
+ staticInsensitive: null,
289
+ dynamic: null,
290
+ optional: null,
291
+ wildcard: null,
292
+ route: null,
293
+ fullPath,
294
+ parent: null,
295
+ parse: null,
296
+ skipOnParamError: false,
297
+ parsingPriority: 0
298
+ };
344
299
  }
300
+ /**
301
+ * Keys must be declared in the same order as in `SegmentNode` type,
302
+ * to ensure they are represented as the same object class in the engine.
303
+ */
345
304
  function createDynamicNode(kind, fullPath, caseSensitive, prefix, suffix) {
346
- return {
347
- kind,
348
- depth: 0,
349
- pathless: null,
350
- index: null,
351
- static: null,
352
- staticInsensitive: null,
353
- dynamic: null,
354
- optional: null,
355
- wildcard: null,
356
- route: null,
357
- fullPath,
358
- parent: null,
359
- parse: null,
360
- skipOnParamError: false,
361
- parsingPriority: 0,
362
- caseSensitive,
363
- prefix,
364
- suffix
365
- };
305
+ return {
306
+ kind,
307
+ depth: 0,
308
+ pathless: null,
309
+ index: null,
310
+ static: null,
311
+ staticInsensitive: null,
312
+ dynamic: null,
313
+ optional: null,
314
+ wildcard: null,
315
+ route: null,
316
+ fullPath,
317
+ parent: null,
318
+ parse: null,
319
+ skipOnParamError: false,
320
+ parsingPriority: 0,
321
+ caseSensitive,
322
+ prefix,
323
+ suffix
324
+ };
366
325
  }
367
326
  function processRouteMasks(routeList, processedTree) {
368
- const segmentTree = createStaticNode("/");
369
- const data = new Uint16Array(6);
370
- for (const route of routeList) {
371
- parseSegments(false, data, route, 1, segmentTree, 0);
372
- }
373
- sortTreeNodes(segmentTree);
374
- processedTree.masksTree = segmentTree;
375
- processedTree.flatCache = createLRUCache(1e3);
327
+ const segmentTree = createStaticNode("/");
328
+ const data = new Uint16Array(6);
329
+ for (const route of routeList) parseSegments(false, data, route, 1, segmentTree, 0);
330
+ sortTreeNodes(segmentTree);
331
+ processedTree.masksTree = segmentTree;
332
+ processedTree.flatCache = createLRUCache(1e3);
376
333
  }
334
+ /**
335
+ * Take an arbitrary list of routes, create a tree from them (if it hasn't been created already), and match a path against it.
336
+ */
377
337
  function findFlatMatch(path, processedTree) {
378
- path ||= "/";
379
- const cached = processedTree.flatCache.get(path);
380
- if (cached) return cached;
381
- const result = findMatch(path, processedTree.masksTree);
382
- processedTree.flatCache.set(path, result);
383
- return result;
338
+ path ||= "/";
339
+ const cached = processedTree.flatCache.get(path);
340
+ if (cached) return cached;
341
+ const result = findMatch(path, processedTree.masksTree);
342
+ processedTree.flatCache.set(path, result);
343
+ return result;
384
344
  }
345
+ /**
346
+ * @deprecated keep until v2 so that `router.matchRoute` can keep not caring about the actual route tree
347
+ */
385
348
  function findSingleMatch(from, caseSensitive, fuzzy, path, processedTree) {
386
- from ||= "/";
387
- path ||= "/";
388
- const key = caseSensitive ? `case\0${from}` : from;
389
- let tree = processedTree.singleCache.get(key);
390
- if (!tree) {
391
- tree = createStaticNode("/");
392
- const data = new Uint16Array(6);
393
- parseSegments(caseSensitive, data, { from }, 1, tree, 0);
394
- processedTree.singleCache.set(key, tree);
395
- }
396
- return findMatch(path, tree, fuzzy);
349
+ from ||= "/";
350
+ path ||= "/";
351
+ const key = caseSensitive ? `case\0${from}` : from;
352
+ let tree = processedTree.singleCache.get(key);
353
+ if (!tree) {
354
+ tree = createStaticNode("/");
355
+ parseSegments(caseSensitive, new Uint16Array(6), { from }, 1, tree, 0);
356
+ processedTree.singleCache.set(key, tree);
357
+ }
358
+ return findMatch(path, tree, fuzzy);
397
359
  }
398
360
  function findRouteMatch(path, processedTree, fuzzy = false) {
399
- const key = fuzzy ? path : `nofuzz\0${path}`;
400
- const cached = processedTree.matchCache.get(key);
401
- if (cached !== void 0) return cached;
402
- path ||= "/";
403
- let result;
404
- try {
405
- result = findMatch(
406
- path,
407
- processedTree.segmentTree,
408
- fuzzy
409
- );
410
- } catch (err) {
411
- if (err instanceof URIError) {
412
- result = null;
413
- } else {
414
- throw err;
415
- }
416
- }
417
- if (result) result.branch = buildRouteBranch(result.route);
418
- processedTree.matchCache.set(key, result);
419
- return result;
361
+ const key = fuzzy ? path : `nofuzz\0${path}`;
362
+ const cached = processedTree.matchCache.get(key);
363
+ if (cached !== void 0) return cached;
364
+ path ||= "/";
365
+ let result;
366
+ try {
367
+ result = findMatch(path, processedTree.segmentTree, fuzzy);
368
+ } catch (err) {
369
+ if (err instanceof URIError) result = null;
370
+ else throw err;
371
+ }
372
+ if (result) result.branch = buildRouteBranch(result.route);
373
+ processedTree.matchCache.set(key, result);
374
+ return result;
420
375
  }
376
+ /** Trim trailing slashes (except preserving root '/'). */
421
377
  function trimPathRight(path) {
422
- return path === "/" ? path : path.replace(/\/{1,}$/, "");
378
+ return path === "/" ? path : path.replace(/\/{1,}$/, "");
423
379
  }
380
+ /**
381
+ * Processes a route tree into a segment trie for efficient path matching.
382
+ * Also builds lookup maps for routes by ID and by trimmed full path.
383
+ */
424
384
  function processRouteTree(routeTree, caseSensitive = false, initRoute) {
425
- const segmentTree = createStaticNode(routeTree.fullPath);
426
- const data = new Uint16Array(6);
427
- const routesById = {};
428
- const routesByPath = {};
429
- let index = 0;
430
- parseSegments(caseSensitive, data, routeTree, 1, segmentTree, 0, (route) => {
431
- initRoute?.(route, index);
432
- invariant(
433
- !(route.id in routesById),
434
- `Duplicate routes found with id: ${String(route.id)}`
435
- );
436
- routesById[route.id] = route;
437
- if (index !== 0 && route.path) {
438
- const trimmedFullPath = trimPathRight(route.fullPath);
439
- if (!routesByPath[trimmedFullPath] || route.fullPath.endsWith("/")) {
440
- routesByPath[trimmedFullPath] = route;
441
- }
442
- }
443
- index++;
444
- });
445
- sortTreeNodes(segmentTree);
446
- const processedTree = {
447
- segmentTree,
448
- singleCache: createLRUCache(1e3),
449
- matchCache: createLRUCache(1e3),
450
- flatCache: null,
451
- masksTree: null
452
- };
453
- return {
454
- processedTree,
455
- routesById,
456
- routesByPath
457
- };
385
+ const segmentTree = createStaticNode(routeTree.fullPath);
386
+ const data = new Uint16Array(6);
387
+ const routesById = {};
388
+ const routesByPath = {};
389
+ let index = 0;
390
+ parseSegments(caseSensitive, data, routeTree, 1, segmentTree, 0, (route) => {
391
+ initRoute?.(route, index);
392
+ invariant(!(route.id in routesById), `Duplicate routes found with id: ${String(route.id)}`);
393
+ routesById[route.id] = route;
394
+ if (index !== 0 && route.path) {
395
+ const trimmedFullPath = trimPathRight(route.fullPath);
396
+ if (!routesByPath[trimmedFullPath] || route.fullPath.endsWith("/")) routesByPath[trimmedFullPath] = route;
397
+ }
398
+ index++;
399
+ });
400
+ sortTreeNodes(segmentTree);
401
+ return {
402
+ processedTree: {
403
+ segmentTree,
404
+ singleCache: createLRUCache(1e3),
405
+ matchCache: createLRUCache(1e3),
406
+ flatCache: null,
407
+ masksTree: null
408
+ },
409
+ routesById,
410
+ routesByPath
411
+ };
458
412
  }
459
413
  function findMatch(path, segmentTree, fuzzy = false) {
460
- const parts = path.split("/");
461
- const leaf = getNodeMatch(path, parts, segmentTree, fuzzy);
462
- if (!leaf) return null;
463
- const [rawParams] = extractParams(path, parts, leaf);
464
- return {
465
- route: leaf.node.route,
466
- rawParams,
467
- parsedParams: leaf.parsedParams
468
- };
414
+ const parts = path.split("/");
415
+ const leaf = getNodeMatch(path, parts, segmentTree, fuzzy);
416
+ if (!leaf) return null;
417
+ const [rawParams] = extractParams(path, parts, leaf);
418
+ return {
419
+ route: leaf.node.route,
420
+ rawParams,
421
+ parsedParams: leaf.parsedParams
422
+ };
469
423
  }
424
+ /**
425
+ * This function is "resumable":
426
+ * - the `leaf` input can contain `extract` and `rawParams` properties from a previous `extractParams` call
427
+ * - the returned `state` can be passed back as `extract` in a future call to continue extracting params from where we left off
428
+ *
429
+ * Inputs are *not* mutated.
430
+ */
470
431
  function extractParams(path, parts, leaf) {
471
- const list = buildBranch(leaf.node);
472
- let nodeParts = null;
473
- const rawParams = /* @__PURE__ */ Object.create(null);
474
- let partIndex = leaf.extract?.part ?? 0;
475
- let nodeIndex = leaf.extract?.node ?? 0;
476
- let pathIndex = leaf.extract?.path ?? 0;
477
- let segmentCount = leaf.extract?.segment ?? 0;
478
- for (; nodeIndex < list.length; partIndex++, nodeIndex++, pathIndex++, segmentCount++) {
479
- const node = list[nodeIndex];
480
- if (node.kind === SEGMENT_TYPE_INDEX) break;
481
- if (node.kind === SEGMENT_TYPE_PATHLESS) {
482
- segmentCount--;
483
- partIndex--;
484
- pathIndex--;
485
- continue;
486
- }
487
- const part = parts[partIndex];
488
- const currentPathIndex = pathIndex;
489
- if (part) pathIndex += part.length;
490
- if (node.kind === SEGMENT_TYPE_PARAM) {
491
- nodeParts ??= leaf.node.fullPath.split("/");
492
- const nodePart = nodeParts[segmentCount];
493
- const preLength = node.prefix?.length ?? 0;
494
- const isCurlyBraced = nodePart.charCodeAt(preLength) === 123;
495
- if (isCurlyBraced) {
496
- const sufLength = node.suffix?.length ?? 0;
497
- const name = nodePart.substring(
498
- preLength + 2,
499
- nodePart.length - sufLength - 1
500
- );
501
- const value = part.substring(preLength, part.length - sufLength);
502
- rawParams[name] = decodeURIComponent(value);
503
- } else {
504
- const name = nodePart.substring(1);
505
- rawParams[name] = decodeURIComponent(part);
506
- }
507
- } else if (node.kind === SEGMENT_TYPE_OPTIONAL_PARAM) {
508
- if (leaf.skipped & 1 << nodeIndex) {
509
- partIndex--;
510
- pathIndex = currentPathIndex - 1;
511
- continue;
512
- }
513
- nodeParts ??= leaf.node.fullPath.split("/");
514
- const nodePart = nodeParts[segmentCount];
515
- const preLength = node.prefix?.length ?? 0;
516
- const sufLength = node.suffix?.length ?? 0;
517
- const name = nodePart.substring(
518
- preLength + 3,
519
- nodePart.length - sufLength - 1
520
- );
521
- const value = node.suffix || node.prefix ? part.substring(preLength, part.length - sufLength) : part;
522
- if (value) rawParams[name] = decodeURIComponent(value);
523
- } else if (node.kind === SEGMENT_TYPE_WILDCARD) {
524
- const n = node;
525
- const value = path.substring(
526
- currentPathIndex + (n.prefix?.length ?? 0),
527
- path.length - (n.suffix?.length ?? 0)
528
- );
529
- const splat = decodeURIComponent(value);
530
- rawParams["*"] = splat;
531
- rawParams._splat = splat;
532
- break;
533
- }
534
- }
535
- if (leaf.rawParams) Object.assign(rawParams, leaf.rawParams);
536
- return [
537
- rawParams,
538
- {
539
- part: partIndex,
540
- node: nodeIndex,
541
- path: pathIndex,
542
- segment: segmentCount
543
- }
544
- ];
432
+ const list = buildBranch(leaf.node);
433
+ let nodeParts = null;
434
+ const rawParams = Object.create(null);
435
+ /** which segment of the path we're currently processing */
436
+ let partIndex = leaf.extract?.part ?? 0;
437
+ /** which node of the route tree branch we're currently processing */
438
+ let nodeIndex = leaf.extract?.node ?? 0;
439
+ /** index of the 1st character of the segment we're processing in the path string */
440
+ let pathIndex = leaf.extract?.path ?? 0;
441
+ /** which fullPath segment we're currently processing */
442
+ let segmentCount = leaf.extract?.segment ?? 0;
443
+ for (; nodeIndex < list.length; partIndex++, nodeIndex++, pathIndex++, segmentCount++) {
444
+ const node = list[nodeIndex];
445
+ if (node.kind === SEGMENT_TYPE_INDEX) break;
446
+ if (node.kind === SEGMENT_TYPE_PATHLESS) {
447
+ segmentCount--;
448
+ partIndex--;
449
+ pathIndex--;
450
+ continue;
451
+ }
452
+ const part = parts[partIndex];
453
+ const currentPathIndex = pathIndex;
454
+ if (part) pathIndex += part.length;
455
+ if (node.kind === 1) {
456
+ nodeParts ??= leaf.node.fullPath.split("/");
457
+ const nodePart = nodeParts[segmentCount];
458
+ const preLength = node.prefix?.length ?? 0;
459
+ if (nodePart.charCodeAt(preLength) === 123) {
460
+ const sufLength = node.suffix?.length ?? 0;
461
+ const name = nodePart.substring(preLength + 2, nodePart.length - sufLength - 1);
462
+ const value = part.substring(preLength, part.length - sufLength);
463
+ rawParams[name] = decodeURIComponent(value);
464
+ } else {
465
+ const name = nodePart.substring(1);
466
+ rawParams[name] = decodeURIComponent(part);
467
+ }
468
+ } else if (node.kind === 3) {
469
+ if (leaf.skipped & 1 << nodeIndex) {
470
+ partIndex--;
471
+ pathIndex = currentPathIndex - 1;
472
+ continue;
473
+ }
474
+ nodeParts ??= leaf.node.fullPath.split("/");
475
+ const nodePart = nodeParts[segmentCount];
476
+ const preLength = node.prefix?.length ?? 0;
477
+ const sufLength = node.suffix?.length ?? 0;
478
+ const name = nodePart.substring(preLength + 3, nodePart.length - sufLength - 1);
479
+ const value = node.suffix || node.prefix ? part.substring(preLength, part.length - sufLength) : part;
480
+ if (value) rawParams[name] = decodeURIComponent(value);
481
+ } else if (node.kind === 2) {
482
+ const n = node;
483
+ const value = path.substring(currentPathIndex + (n.prefix?.length ?? 0), path.length - (n.suffix?.length ?? 0));
484
+ const splat = decodeURIComponent(value);
485
+ rawParams["*"] = splat;
486
+ rawParams._splat = splat;
487
+ break;
488
+ }
489
+ }
490
+ if (leaf.rawParams) Object.assign(rawParams, leaf.rawParams);
491
+ return [rawParams, {
492
+ part: partIndex,
493
+ node: nodeIndex,
494
+ path: pathIndex,
495
+ segment: segmentCount
496
+ }];
545
497
  }
546
498
  function buildRouteBranch(route) {
547
- const list = [route];
548
- while (route.parentRoute) {
549
- route = route.parentRoute;
550
- list.push(route);
551
- }
552
- list.reverse();
553
- return list;
499
+ const list = [route];
500
+ while (route.parentRoute) {
501
+ route = route.parentRoute;
502
+ list.push(route);
503
+ }
504
+ list.reverse();
505
+ return list;
554
506
  }
555
507
  function buildBranch(node) {
556
- const list = Array(node.depth + 1);
557
- do {
558
- list[node.depth] = node;
559
- node = node.parent;
560
- } while (node);
561
- return list;
508
+ const list = Array(node.depth + 1);
509
+ do {
510
+ list[node.depth] = node;
511
+ node = node.parent;
512
+ } while (node);
513
+ return list;
562
514
  }
563
515
  function getNodeMatch(path, parts, segmentTree, fuzzy) {
564
- if (path === "/" && segmentTree.index)
565
- return { node: segmentTree.index, skipped: 0 };
566
- const trailingSlash = !last(parts);
567
- const pathIsIndex = trailingSlash && path !== "/";
568
- const partsLength = parts.length - (trailingSlash ? 1 : 0);
569
- const stack = [
570
- {
571
- node: segmentTree,
572
- index: 1,
573
- skipped: 0,
574
- depth: 1,
575
- statics: 1,
576
- dynamics: 0,
577
- optionals: 0
578
- }
579
- ];
580
- let wildcardMatch = null;
581
- let bestFuzzy = null;
582
- let bestMatch = null;
583
- while (stack.length) {
584
- const frame = stack.pop();
585
- const { node, index, skipped, depth, statics, dynamics, optionals } = frame;
586
- let { extract, rawParams, parsedParams } = frame;
587
- if (node.skipOnParamError) {
588
- const result = validateMatchParams(path, parts, frame);
589
- if (!result) continue;
590
- rawParams = frame.rawParams;
591
- extract = frame.extract;
592
- parsedParams = frame.parsedParams;
593
- }
594
- if (fuzzy && node.route && node.kind !== SEGMENT_TYPE_INDEX && isFrameMoreSpecific(bestFuzzy, frame)) {
595
- bestFuzzy = frame;
596
- }
597
- const isBeyondPath = index === partsLength;
598
- if (isBeyondPath) {
599
- if (node.route && !pathIsIndex && isFrameMoreSpecific(bestMatch, frame)) {
600
- bestMatch = frame;
601
- }
602
- if (!node.optional && !node.wildcard && !node.index && !node.pathless)
603
- continue;
604
- }
605
- const part = isBeyondPath ? void 0 : parts[index];
606
- let lowerPart;
607
- if (isBeyondPath && node.index) {
608
- const indexFrame = {
609
- node: node.index,
610
- index,
611
- skipped,
612
- depth: depth + 1,
613
- statics,
614
- dynamics,
615
- optionals,
616
- extract,
617
- rawParams,
618
- parsedParams
619
- };
620
- let indexValid = true;
621
- if (node.index.skipOnParamError) {
622
- const result = validateMatchParams(path, parts, indexFrame);
623
- if (!result) indexValid = false;
624
- }
625
- if (indexValid) {
626
- if (statics === partsLength && !dynamics && !optionals && !skipped) {
627
- return indexFrame;
628
- }
629
- if (isFrameMoreSpecific(bestMatch, indexFrame)) {
630
- bestMatch = indexFrame;
631
- }
632
- }
633
- }
634
- if (node.wildcard && isFrameMoreSpecific(wildcardMatch, frame)) {
635
- for (const segment of node.wildcard) {
636
- const { prefix, suffix } = segment;
637
- if (prefix) {
638
- if (isBeyondPath) continue;
639
- const casePart = segment.caseSensitive ? part : lowerPart ??= part.toLowerCase();
640
- if (!casePart.startsWith(prefix)) continue;
641
- }
642
- if (suffix) {
643
- if (isBeyondPath) continue;
644
- const end = parts.slice(index).join("/").slice(-suffix.length);
645
- const casePart = segment.caseSensitive ? end : end.toLowerCase();
646
- if (casePart !== suffix) continue;
647
- }
648
- const frame2 = {
649
- node: segment,
650
- index: partsLength,
651
- skipped,
652
- depth,
653
- statics,
654
- dynamics,
655
- optionals,
656
- extract,
657
- rawParams,
658
- parsedParams
659
- };
660
- if (segment.skipOnParamError) {
661
- const result = validateMatchParams(path, parts, frame2);
662
- if (!result) continue;
663
- }
664
- wildcardMatch = frame2;
665
- break;
666
- }
667
- }
668
- if (node.optional) {
669
- const nextSkipped = skipped | 1 << depth;
670
- const nextDepth = depth + 1;
671
- for (let i = node.optional.length - 1; i >= 0; i--) {
672
- const segment = node.optional[i];
673
- stack.push({
674
- node: segment,
675
- index,
676
- skipped: nextSkipped,
677
- depth: nextDepth,
678
- statics,
679
- dynamics,
680
- optionals,
681
- extract,
682
- rawParams,
683
- parsedParams
684
- });
685
- }
686
- if (!isBeyondPath) {
687
- for (let i = node.optional.length - 1; i >= 0; i--) {
688
- const segment = node.optional[i];
689
- const { prefix, suffix } = segment;
690
- if (prefix || suffix) {
691
- const casePart = segment.caseSensitive ? part : lowerPart ??= part.toLowerCase();
692
- if (prefix && !casePart.startsWith(prefix)) continue;
693
- if (suffix && !casePart.endsWith(suffix)) continue;
694
- }
695
- stack.push({
696
- node: segment,
697
- index: index + 1,
698
- skipped,
699
- depth: nextDepth,
700
- statics,
701
- dynamics,
702
- optionals: optionals + 1,
703
- extract,
704
- rawParams,
705
- parsedParams
706
- });
707
- }
708
- }
709
- }
710
- if (!isBeyondPath && node.dynamic && part) {
711
- for (let i = node.dynamic.length - 1; i >= 0; i--) {
712
- const segment = node.dynamic[i];
713
- const { prefix, suffix } = segment;
714
- if (prefix || suffix) {
715
- const casePart = segment.caseSensitive ? part : lowerPart ??= part.toLowerCase();
716
- if (prefix && !casePart.startsWith(prefix)) continue;
717
- if (suffix && !casePart.endsWith(suffix)) continue;
718
- }
719
- stack.push({
720
- node: segment,
721
- index: index + 1,
722
- skipped,
723
- depth: depth + 1,
724
- statics,
725
- dynamics: dynamics + 1,
726
- optionals,
727
- extract,
728
- rawParams,
729
- parsedParams
730
- });
731
- }
732
- }
733
- if (!isBeyondPath && node.staticInsensitive) {
734
- const match = node.staticInsensitive.get(
735
- lowerPart ??= part.toLowerCase()
736
- );
737
- if (match) {
738
- stack.push({
739
- node: match,
740
- index: index + 1,
741
- skipped,
742
- depth: depth + 1,
743
- statics: statics + 1,
744
- dynamics,
745
- optionals,
746
- extract,
747
- rawParams,
748
- parsedParams
749
- });
750
- }
751
- }
752
- if (!isBeyondPath && node.static) {
753
- const match = node.static.get(part);
754
- if (match) {
755
- stack.push({
756
- node: match,
757
- index: index + 1,
758
- skipped,
759
- depth: depth + 1,
760
- statics: statics + 1,
761
- dynamics,
762
- optionals,
763
- extract,
764
- rawParams,
765
- parsedParams
766
- });
767
- }
768
- }
769
- if (node.pathless) {
770
- const nextDepth = depth + 1;
771
- for (let i = node.pathless.length - 1; i >= 0; i--) {
772
- const segment = node.pathless[i];
773
- stack.push({
774
- node: segment,
775
- index,
776
- skipped,
777
- depth: nextDepth,
778
- statics,
779
- dynamics,
780
- optionals,
781
- extract,
782
- rawParams,
783
- parsedParams
784
- });
785
- }
786
- }
787
- }
788
- if (bestMatch && wildcardMatch) {
789
- return isFrameMoreSpecific(wildcardMatch, bestMatch) ? bestMatch : wildcardMatch;
790
- }
791
- if (bestMatch) return bestMatch;
792
- if (wildcardMatch) return wildcardMatch;
793
- if (fuzzy && bestFuzzy) {
794
- let sliceIndex = bestFuzzy.index;
795
- for (let i = 0; i < bestFuzzy.index; i++) {
796
- sliceIndex += parts[i].length;
797
- }
798
- const splat = sliceIndex === path.length ? "/" : path.slice(sliceIndex);
799
- bestFuzzy.rawParams ??= /* @__PURE__ */ Object.create(null);
800
- bestFuzzy.rawParams["**"] = decodeURIComponent(splat);
801
- return bestFuzzy;
802
- }
803
- return null;
516
+ if (path === "/" && segmentTree.index) return {
517
+ node: segmentTree.index,
518
+ skipped: 0
519
+ };
520
+ const trailingSlash = !last(parts);
521
+ const pathIsIndex = trailingSlash && path !== "/";
522
+ const partsLength = parts.length - (trailingSlash ? 1 : 0);
523
+ const stack = [{
524
+ node: segmentTree,
525
+ index: 1,
526
+ skipped: 0,
527
+ depth: 1,
528
+ statics: 1,
529
+ dynamics: 0,
530
+ optionals: 0
531
+ }];
532
+ let wildcardMatch = null;
533
+ let bestFuzzy = null;
534
+ let bestMatch = null;
535
+ while (stack.length) {
536
+ const frame = stack.pop();
537
+ const { node, index, skipped, depth, statics, dynamics, optionals } = frame;
538
+ let { extract, rawParams, parsedParams } = frame;
539
+ if (node.skipOnParamError) {
540
+ if (!validateMatchParams(path, parts, frame)) continue;
541
+ rawParams = frame.rawParams;
542
+ extract = frame.extract;
543
+ parsedParams = frame.parsedParams;
544
+ }
545
+ if (fuzzy && node.route && node.kind !== SEGMENT_TYPE_INDEX && isFrameMoreSpecific(bestFuzzy, frame)) bestFuzzy = frame;
546
+ const isBeyondPath = index === partsLength;
547
+ if (isBeyondPath) {
548
+ if (node.route && !pathIsIndex && isFrameMoreSpecific(bestMatch, frame)) bestMatch = frame;
549
+ if (!node.optional && !node.wildcard && !node.index && !node.pathless) continue;
550
+ }
551
+ const part = isBeyondPath ? void 0 : parts[index];
552
+ let lowerPart;
553
+ if (isBeyondPath && node.index) {
554
+ const indexFrame = {
555
+ node: node.index,
556
+ index,
557
+ skipped,
558
+ depth: depth + 1,
559
+ statics,
560
+ dynamics,
561
+ optionals,
562
+ extract,
563
+ rawParams,
564
+ parsedParams
565
+ };
566
+ let indexValid = true;
567
+ if (node.index.skipOnParamError) {
568
+ if (!validateMatchParams(path, parts, indexFrame)) indexValid = false;
569
+ }
570
+ if (indexValid) {
571
+ if (statics === partsLength && !dynamics && !optionals && !skipped) return indexFrame;
572
+ if (isFrameMoreSpecific(bestMatch, indexFrame)) bestMatch = indexFrame;
573
+ }
574
+ }
575
+ if (node.wildcard && isFrameMoreSpecific(wildcardMatch, frame)) for (const segment of node.wildcard) {
576
+ const { prefix, suffix } = segment;
577
+ if (prefix) {
578
+ if (isBeyondPath) continue;
579
+ if (!(segment.caseSensitive ? part : lowerPart ??= part.toLowerCase()).startsWith(prefix)) continue;
580
+ }
581
+ if (suffix) {
582
+ if (isBeyondPath) continue;
583
+ const end = parts.slice(index).join("/").slice(-suffix.length);
584
+ if ((segment.caseSensitive ? end : end.toLowerCase()) !== suffix) continue;
585
+ }
586
+ const frame = {
587
+ node: segment,
588
+ index: partsLength,
589
+ skipped,
590
+ depth,
591
+ statics,
592
+ dynamics,
593
+ optionals,
594
+ extract,
595
+ rawParams,
596
+ parsedParams
597
+ };
598
+ if (segment.skipOnParamError) {
599
+ if (!validateMatchParams(path, parts, frame)) continue;
600
+ }
601
+ wildcardMatch = frame;
602
+ break;
603
+ }
604
+ if (node.optional) {
605
+ const nextSkipped = skipped | 1 << depth;
606
+ const nextDepth = depth + 1;
607
+ for (let i = node.optional.length - 1; i >= 0; i--) {
608
+ const segment = node.optional[i];
609
+ stack.push({
610
+ node: segment,
611
+ index,
612
+ skipped: nextSkipped,
613
+ depth: nextDepth,
614
+ statics,
615
+ dynamics,
616
+ optionals,
617
+ extract,
618
+ rawParams,
619
+ parsedParams
620
+ });
621
+ }
622
+ if (!isBeyondPath) for (let i = node.optional.length - 1; i >= 0; i--) {
623
+ const segment = node.optional[i];
624
+ const { prefix, suffix } = segment;
625
+ if (prefix || suffix) {
626
+ const casePart = segment.caseSensitive ? part : lowerPart ??= part.toLowerCase();
627
+ if (prefix && !casePart.startsWith(prefix)) continue;
628
+ if (suffix && !casePart.endsWith(suffix)) continue;
629
+ }
630
+ stack.push({
631
+ node: segment,
632
+ index: index + 1,
633
+ skipped,
634
+ depth: nextDepth,
635
+ statics,
636
+ dynamics,
637
+ optionals: optionals + 1,
638
+ extract,
639
+ rawParams,
640
+ parsedParams
641
+ });
642
+ }
643
+ }
644
+ if (!isBeyondPath && node.dynamic && part) for (let i = node.dynamic.length - 1; i >= 0; i--) {
645
+ const segment = node.dynamic[i];
646
+ const { prefix, suffix } = segment;
647
+ if (prefix || suffix) {
648
+ const casePart = segment.caseSensitive ? part : lowerPart ??= part.toLowerCase();
649
+ if (prefix && !casePart.startsWith(prefix)) continue;
650
+ if (suffix && !casePart.endsWith(suffix)) continue;
651
+ }
652
+ stack.push({
653
+ node: segment,
654
+ index: index + 1,
655
+ skipped,
656
+ depth: depth + 1,
657
+ statics,
658
+ dynamics: dynamics + 1,
659
+ optionals,
660
+ extract,
661
+ rawParams,
662
+ parsedParams
663
+ });
664
+ }
665
+ if (!isBeyondPath && node.staticInsensitive) {
666
+ const match = node.staticInsensitive.get(lowerPart ??= part.toLowerCase());
667
+ if (match) stack.push({
668
+ node: match,
669
+ index: index + 1,
670
+ skipped,
671
+ depth: depth + 1,
672
+ statics: statics + 1,
673
+ dynamics,
674
+ optionals,
675
+ extract,
676
+ rawParams,
677
+ parsedParams
678
+ });
679
+ }
680
+ if (!isBeyondPath && node.static) {
681
+ const match = node.static.get(part);
682
+ if (match) stack.push({
683
+ node: match,
684
+ index: index + 1,
685
+ skipped,
686
+ depth: depth + 1,
687
+ statics: statics + 1,
688
+ dynamics,
689
+ optionals,
690
+ extract,
691
+ rawParams,
692
+ parsedParams
693
+ });
694
+ }
695
+ if (node.pathless) {
696
+ const nextDepth = depth + 1;
697
+ for (let i = node.pathless.length - 1; i >= 0; i--) {
698
+ const segment = node.pathless[i];
699
+ stack.push({
700
+ node: segment,
701
+ index,
702
+ skipped,
703
+ depth: nextDepth,
704
+ statics,
705
+ dynamics,
706
+ optionals,
707
+ extract,
708
+ rawParams,
709
+ parsedParams
710
+ });
711
+ }
712
+ }
713
+ }
714
+ if (bestMatch && wildcardMatch) return isFrameMoreSpecific(wildcardMatch, bestMatch) ? bestMatch : wildcardMatch;
715
+ if (bestMatch) return bestMatch;
716
+ if (wildcardMatch) return wildcardMatch;
717
+ if (fuzzy && bestFuzzy) {
718
+ let sliceIndex = bestFuzzy.index;
719
+ for (let i = 0; i < bestFuzzy.index; i++) sliceIndex += parts[i].length;
720
+ const splat = sliceIndex === path.length ? "/" : path.slice(sliceIndex);
721
+ bestFuzzy.rawParams ??= Object.create(null);
722
+ bestFuzzy.rawParams["**"] = decodeURIComponent(splat);
723
+ return bestFuzzy;
724
+ }
725
+ return null;
804
726
  }
805
727
  function validateMatchParams(path, parts, frame) {
806
- try {
807
- const [rawParams, state] = extractParams(path, parts, frame);
808
- frame.rawParams = rawParams;
809
- frame.extract = state;
810
- const parsed = frame.node.parse(rawParams);
811
- frame.parsedParams = Object.assign(
812
- /* @__PURE__ */ Object.create(null),
813
- frame.parsedParams,
814
- parsed
815
- );
816
- return true;
817
- } catch {
818
- return null;
819
- }
728
+ try {
729
+ const [rawParams, state] = extractParams(path, parts, frame);
730
+ frame.rawParams = rawParams;
731
+ frame.extract = state;
732
+ const parsed = frame.node.parse(rawParams);
733
+ frame.parsedParams = Object.assign(Object.create(null), frame.parsedParams, parsed);
734
+ return true;
735
+ } catch {
736
+ return null;
737
+ }
820
738
  }
821
739
  function isFrameMoreSpecific(prev, next) {
822
- if (!prev) return true;
823
- 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)));
740
+ if (!prev) return true;
741
+ 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)));
824
742
  }
825
- export {
826
- SEGMENT_TYPE_OPTIONAL_PARAM,
827
- SEGMENT_TYPE_PARAM,
828
- SEGMENT_TYPE_PATHNAME,
829
- SEGMENT_TYPE_WILDCARD,
830
- findFlatMatch,
831
- findRouteMatch,
832
- findSingleMatch,
833
- parseSegment,
834
- processRouteMasks,
835
- processRouteTree,
836
- trimPathRight
837
- };
838
- //# sourceMappingURL=new-process-route-tree.js.map
743
+ //#endregion
744
+ export { findFlatMatch, findRouteMatch, findSingleMatch, parseSegment, processRouteMasks, processRouteTree };
745
+
746
+ //# sourceMappingURL=new-process-route-tree.js.map