@edgeone/vite-core 1.0.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.
- package/dist/bundler.d.ts +13 -0
- package/dist/bundler.d.ts.map +1 -0
- package/dist/bundler.js +101 -0
- package/dist/bundler.js.map +1 -0
- package/dist/core.d.ts +11 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +330 -0
- package/dist/core.js.map +1 -0
- package/dist/factory/detectors.d.ts +13 -0
- package/dist/factory/detectors.d.ts.map +1 -0
- package/dist/factory/detectors.js +46 -0
- package/dist/factory/detectors.js.map +1 -0
- package/dist/factory/hooks.d.ts +29 -0
- package/dist/factory/hooks.d.ts.map +1 -0
- package/dist/factory/hooks.js +158 -0
- package/dist/factory/hooks.js.map +1 -0
- package/dist/factory/index.d.ts +24 -0
- package/dist/factory/index.d.ts.map +1 -0
- package/dist/factory/index.js +47 -0
- package/dist/factory/index.js.map +1 -0
- package/dist/factory/presets.d.ts +27 -0
- package/dist/factory/presets.d.ts.map +1 -0
- package/dist/factory/presets.js +186 -0
- package/dist/factory/presets.js.map +1 -0
- package/dist/factory.d.ts +183 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +482 -0
- package/dist/factory.js.map +1 -0
- package/dist/helpers.d.ts +53 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +177 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/route/index.d.ts +7 -0
- package/dist/route/index.d.ts.map +1 -0
- package/dist/route/index.js +6 -0
- package/dist/route/index.js.map +1 -0
- package/dist/route/parser.d.ts +18 -0
- package/dist/route/parser.d.ts.map +1 -0
- package/dist/route/parser.js +187 -0
- package/dist/route/parser.js.map +1 -0
- package/dist/route/regex.d.ts +31 -0
- package/dist/route/regex.d.ts.map +1 -0
- package/dist/route/regex.js +140 -0
- package/dist/route/regex.js.map +1 -0
- package/dist/route/regex.test.d.ts +7 -0
- package/dist/route/regex.test.d.ts.map +1 -0
- package/dist/route/regex.test.js +662 -0
- package/dist/route/regex.test.js.map +1 -0
- package/dist/route/types.d.ts +58 -0
- package/dist/route/types.d.ts.map +1 -0
- package/dist/route/types.js +5 -0
- package/dist/route/types.js.map +1 -0
- package/dist/route-parser.d.ts +8 -0
- package/dist/route-parser.d.ts.map +1 -0
- package/dist/route-parser.js +8 -0
- package/dist/route-parser.js.map +1 -0
- package/dist/types.d.ts +160 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +40 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +242 -0
- package/dist/utils.js.map +1 -0
- package/dist/vite-config-parser.d.ts +62 -0
- package/dist/vite-config-parser.d.ts.map +1 -0
- package/dist/vite-config-parser.js +229 -0
- package/dist/vite-config-parser.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route Regex Tests
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive test suite for route regex conversion and matching
|
|
5
|
+
*/
|
|
6
|
+
import { isDynamicRoute, isCatchAllRoute, routeToRegex, addRegexToRoutes, convertRoutesToMetaFormat, sortRoutesByPriority, } from "./regex.js";
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Test Utilities
|
|
9
|
+
// ============================================================================
|
|
10
|
+
function testMatch(regex, path) {
|
|
11
|
+
return new RegExp(regex).test(path);
|
|
12
|
+
}
|
|
13
|
+
function assertMatch(regex, path, expected, message) {
|
|
14
|
+
const result = testMatch(regex, path);
|
|
15
|
+
const status = result === expected ? "✓" : "✗";
|
|
16
|
+
const msg = message || `${path} should ${expected ? "" : "not "}match ${regex}`;
|
|
17
|
+
console.log(` ${status} ${msg}`);
|
|
18
|
+
if (result !== expected) {
|
|
19
|
+
throw new Error(`Assertion failed: ${msg}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function runTestGroup(name, fn) {
|
|
23
|
+
console.log(`\n${name}`);
|
|
24
|
+
console.log("─".repeat(60));
|
|
25
|
+
fn();
|
|
26
|
+
}
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// isDynamicRoute Tests
|
|
29
|
+
// ============================================================================
|
|
30
|
+
function testIsDynamicRoute() {
|
|
31
|
+
runTestGroup("isDynamicRoute - Colon Syntax", () => {
|
|
32
|
+
console.log(" ✓ Static routes:");
|
|
33
|
+
console.assert(!isDynamicRoute("/"), "/ should be static");
|
|
34
|
+
console.assert(!isDynamicRoute("/about"), "/about should be static");
|
|
35
|
+
console.assert(!isDynamicRoute("/api/users"), "/api/users should be static");
|
|
36
|
+
console.log(" / , /about, /api/users → false");
|
|
37
|
+
console.log(" ✓ Dynamic routes:");
|
|
38
|
+
console.assert(isDynamicRoute("/:id"), "/:id should be dynamic");
|
|
39
|
+
console.assert(isDynamicRoute("/blog/:slug"), "/blog/:slug should be dynamic");
|
|
40
|
+
console.assert(isDynamicRoute("/user/:id/posts"), "/user/:id/posts should be dynamic");
|
|
41
|
+
console.log(" /:id, /blog/:slug, /user/:id/posts → true");
|
|
42
|
+
console.log(" ✓ Optional parameters:");
|
|
43
|
+
console.assert(isDynamicRoute("/:id?"), "/:id? should be dynamic");
|
|
44
|
+
console.assert(isDynamicRoute("/blog/:slug?"), "/blog/:slug? should be dynamic");
|
|
45
|
+
console.log(" /:id?, /blog/:slug? → true");
|
|
46
|
+
console.log(" ✓ Wildcard:");
|
|
47
|
+
console.assert(isDynamicRoute("/*"), "/* should be dynamic");
|
|
48
|
+
console.assert(isDynamicRoute("/files/*"), "/files/* should be dynamic");
|
|
49
|
+
console.log(" /*, /files/* → true");
|
|
50
|
+
});
|
|
51
|
+
runTestGroup("isDynamicRoute - Dollar Syntax (TanStack)", () => {
|
|
52
|
+
console.log(" ✓ Dynamic routes:");
|
|
53
|
+
console.assert(isDynamicRoute("/$id"), "/$id should be dynamic");
|
|
54
|
+
console.assert(isDynamicRoute("/blog/$slug"), "/blog/$slug should be dynamic");
|
|
55
|
+
console.log(" /$id, /blog/$slug → true");
|
|
56
|
+
console.log(" ✓ Splat routes:");
|
|
57
|
+
console.assert(isDynamicRoute("/$"), "/$ should be dynamic");
|
|
58
|
+
console.assert(isDynamicRoute("/files/$"), "/files/$ should be dynamic");
|
|
59
|
+
console.log(" /$, /files/$ → true");
|
|
60
|
+
});
|
|
61
|
+
runTestGroup("isDynamicRoute - At Syntax (Vike)", () => {
|
|
62
|
+
console.log(" ✓ Dynamic routes:");
|
|
63
|
+
console.assert(isDynamicRoute("/@id"), "/@id should be dynamic");
|
|
64
|
+
console.assert(isDynamicRoute("/user/@id"), "/user/@id should be dynamic");
|
|
65
|
+
console.assert(isDynamicRoute("/blog/@slug"), "/blog/@slug should be dynamic");
|
|
66
|
+
console.assert(isDynamicRoute("/api/@version/@endpoint"), "/api/@version/@endpoint should be dynamic");
|
|
67
|
+
console.log(" /@id, /user/@id, /blog/@slug, /api/@version/@endpoint → true");
|
|
68
|
+
console.log(" ✓ Mixed with static segments:");
|
|
69
|
+
console.assert(isDynamicRoute("/product/@category/@id"), "/product/@category/@id should be dynamic");
|
|
70
|
+
console.assert(isDynamicRoute("/shop/@shopId/item/@itemId"), "/shop/@shopId/item/@itemId should be dynamic");
|
|
71
|
+
console.log(" /product/@category/@id, /shop/@shopId/item/@itemId → true");
|
|
72
|
+
});
|
|
73
|
+
runTestGroup("isDynamicRoute - Bracket Syntax (Next.js/Nuxt)", () => {
|
|
74
|
+
console.log(" ✓ Dynamic routes:");
|
|
75
|
+
console.assert(isDynamicRoute("/[id]"), "/[id] should be dynamic");
|
|
76
|
+
console.assert(isDynamicRoute("/blog/[slug]"), "/blog/[slug] should be dynamic");
|
|
77
|
+
console.log(" /[id], /blog/[slug] → true");
|
|
78
|
+
console.log(" ✓ Optional routes:");
|
|
79
|
+
console.assert(isDynamicRoute("/[[id]]"), "/[[id]] should be dynamic");
|
|
80
|
+
console.assert(isDynamicRoute("/blog/[[slug]]"), "/blog/[[slug]] should be dynamic");
|
|
81
|
+
console.log(" /[[id]], /blog/[[slug]] → true");
|
|
82
|
+
console.log(" ✓ Catch-all routes:");
|
|
83
|
+
console.assert(isDynamicRoute("/[...path]"), "/[...path] should be dynamic");
|
|
84
|
+
console.assert(isDynamicRoute("/docs/[...slug]"), "/docs/[...slug] should be dynamic");
|
|
85
|
+
console.log(" /[...path], /docs/[...slug] → true");
|
|
86
|
+
console.log(" ✓ Optional catch-all routes:");
|
|
87
|
+
console.assert(isDynamicRoute("/[[...path]]"), "/[[...path]] should be dynamic");
|
|
88
|
+
console.log(" /[[...path]] → true");
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// isCatchAllRoute Tests
|
|
93
|
+
// ============================================================================
|
|
94
|
+
function testIsCatchAllRoute() {
|
|
95
|
+
runTestGroup("isCatchAllRoute", () => {
|
|
96
|
+
console.log(" ✓ Not catch-all:");
|
|
97
|
+
console.assert(!isCatchAllRoute("/"), "/ should not be catch-all");
|
|
98
|
+
console.assert(!isCatchAllRoute("/about"), "/about should not be catch-all");
|
|
99
|
+
console.assert(!isCatchAllRoute("/:id"), "/:id should not be catch-all");
|
|
100
|
+
console.assert(!isCatchAllRoute("/[id]"), "/[id] should not be catch-all");
|
|
101
|
+
console.assert(!isCatchAllRoute("/$id"), "/$id should not be catch-all");
|
|
102
|
+
console.log(" /, /about, /:id, /[id], /$id → false");
|
|
103
|
+
console.log(" ✓ Catch-all (colon syntax):");
|
|
104
|
+
console.assert(isCatchAllRoute("/*"), "/* should be catch-all");
|
|
105
|
+
console.assert(isCatchAllRoute("/files/*"), "/files/* should be catch-all");
|
|
106
|
+
console.log(" /*, /files/* → true");
|
|
107
|
+
console.log(" ✓ Catch-all (dollar syntax):");
|
|
108
|
+
console.assert(isCatchAllRoute("/$"), "/$ should be catch-all");
|
|
109
|
+
console.assert(isCatchAllRoute("/files/$"), "/files/$ should be catch-all");
|
|
110
|
+
console.log(" /$, /files/$ → true");
|
|
111
|
+
console.log(" ✓ Catch-all (bracket syntax):");
|
|
112
|
+
console.assert(isCatchAllRoute("/[...path]"), "/[...path] should be catch-all");
|
|
113
|
+
console.assert(isCatchAllRoute("/[[...path]]"), "/[[...path]] should be catch-all");
|
|
114
|
+
console.log(" /[...path], /[[...path]] → true");
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// ============================================================================
|
|
118
|
+
// routeToRegex Tests - Colon Syntax
|
|
119
|
+
// ============================================================================
|
|
120
|
+
function testColonSyntax() {
|
|
121
|
+
runTestGroup("routeToRegex - Colon Syntax (React Router/Remix/Express)", () => {
|
|
122
|
+
// Root route
|
|
123
|
+
const rootRegex = routeToRegex("/");
|
|
124
|
+
console.log(` "/" → ${rootRegex}`);
|
|
125
|
+
assertMatch(rootRegex, "/", true, "Root should match /");
|
|
126
|
+
assertMatch(rootRegex, "/about", false, "Root should not match /about");
|
|
127
|
+
// Static route
|
|
128
|
+
const aboutRegex = routeToRegex("/about");
|
|
129
|
+
console.log(` "/about" → ${aboutRegex}`);
|
|
130
|
+
assertMatch(aboutRegex, "/about", true);
|
|
131
|
+
assertMatch(aboutRegex, "/about/", true, "Should match with trailing slash");
|
|
132
|
+
assertMatch(aboutRegex, "/about/more", false);
|
|
133
|
+
// Single dynamic parameter
|
|
134
|
+
const idRegex = routeToRegex("/user/:id");
|
|
135
|
+
console.log(` "/user/:id" → ${idRegex}`);
|
|
136
|
+
assertMatch(idRegex, "/user/123", true);
|
|
137
|
+
assertMatch(idRegex, "/user/abc", true);
|
|
138
|
+
assertMatch(idRegex, "/user/", false, "Should not match empty param");
|
|
139
|
+
assertMatch(idRegex, "/user/123/extra", false);
|
|
140
|
+
// Multiple dynamic parameters
|
|
141
|
+
const multiRegex = routeToRegex("/user/:org/:repo");
|
|
142
|
+
console.log(` "/user/:org/:repo" → ${multiRegex}`);
|
|
143
|
+
assertMatch(multiRegex, "/user/facebook/react", true);
|
|
144
|
+
assertMatch(multiRegex, "/user/google/angular", true);
|
|
145
|
+
assertMatch(multiRegex, "/user/only-one", false);
|
|
146
|
+
// Mixed static and dynamic
|
|
147
|
+
const mixedRegex = routeToRegex("/api/v1/:id/details");
|
|
148
|
+
console.log(` "/api/v1/:id/details" → ${mixedRegex}`);
|
|
149
|
+
assertMatch(mixedRegex, "/api/v1/123/details", true);
|
|
150
|
+
assertMatch(mixedRegex, "/api/v1/abc/details", true);
|
|
151
|
+
assertMatch(mixedRegex, "/api/v1/details", false);
|
|
152
|
+
// Optional parameter
|
|
153
|
+
const optionalRegex = routeToRegex("/blog/:slug?");
|
|
154
|
+
console.log(` "/blog/:slug?" → ${optionalRegex}`);
|
|
155
|
+
assertMatch(optionalRegex, "/blog/my-post", true);
|
|
156
|
+
assertMatch(optionalRegex, "/blog", true, "Optional param can be absent");
|
|
157
|
+
// Note: /blog/ with trailing slash may or may not match depending on implementation
|
|
158
|
+
// The key is that /blog works without the parameter
|
|
159
|
+
// Wildcard/splat
|
|
160
|
+
const wildcardRegex = routeToRegex("/files/*");
|
|
161
|
+
console.log(` "/files/*" → ${wildcardRegex}`);
|
|
162
|
+
assertMatch(wildcardRegex, "/files/", true);
|
|
163
|
+
assertMatch(wildcardRegex, "/files/doc.txt", true);
|
|
164
|
+
assertMatch(wildcardRegex, "/files/nested/path/file.txt", true);
|
|
165
|
+
assertMatch(wildcardRegex, "/files", true);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
// ============================================================================
|
|
169
|
+
// routeToRegex Tests - Dollar Syntax
|
|
170
|
+
// ============================================================================
|
|
171
|
+
function testDollarSyntax() {
|
|
172
|
+
runTestGroup("routeToRegex - Dollar Syntax (TanStack Start)", () => {
|
|
173
|
+
// Single dynamic parameter
|
|
174
|
+
const idRegex = routeToRegex("/user/$id");
|
|
175
|
+
console.log(` "/user/$id" → ${idRegex}`);
|
|
176
|
+
assertMatch(idRegex, "/user/123", true);
|
|
177
|
+
assertMatch(idRegex, "/user/abc", true);
|
|
178
|
+
assertMatch(idRegex, "/user/", false);
|
|
179
|
+
// Multiple dynamic parameters
|
|
180
|
+
const multiRegex = routeToRegex("/user/$org/$repo");
|
|
181
|
+
console.log(` "/user/$org/$repo" → ${multiRegex}`);
|
|
182
|
+
assertMatch(multiRegex, "/user/facebook/react", true);
|
|
183
|
+
assertMatch(multiRegex, "/user/only-one", false);
|
|
184
|
+
// Splat route
|
|
185
|
+
const splatRegex = routeToRegex("/files/$");
|
|
186
|
+
console.log(` "/files/$" → ${splatRegex}`);
|
|
187
|
+
assertMatch(splatRegex, "/files/", true);
|
|
188
|
+
assertMatch(splatRegex, "/files/doc.txt", true);
|
|
189
|
+
assertMatch(splatRegex, "/files/nested/path/file.txt", true);
|
|
190
|
+
assertMatch(splatRegex, "/files", true);
|
|
191
|
+
// Mixed static and dynamic
|
|
192
|
+
const mixedRegex = routeToRegex("/api/v1/$id/details");
|
|
193
|
+
console.log(` "/api/v1/$id/details" → ${mixedRegex}`);
|
|
194
|
+
assertMatch(mixedRegex, "/api/v1/123/details", true);
|
|
195
|
+
assertMatch(mixedRegex, "/api/v1/details", false);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
// ============================================================================
|
|
199
|
+
// routeToRegex Tests - At Syntax (Vike)
|
|
200
|
+
// ============================================================================
|
|
201
|
+
function testAtSyntax() {
|
|
202
|
+
runTestGroup("routeToRegex - At Syntax (Vike)", () => {
|
|
203
|
+
// Single dynamic parameter
|
|
204
|
+
const idRegex = routeToRegex("/user/@id");
|
|
205
|
+
console.log(` "/user/@id" → ${idRegex}`);
|
|
206
|
+
assertMatch(idRegex, "/user/123", true);
|
|
207
|
+
assertMatch(idRegex, "/user/abc", true);
|
|
208
|
+
assertMatch(idRegex, "/user/john-doe", true);
|
|
209
|
+
assertMatch(idRegex, "/user/", false, "Should not match empty param");
|
|
210
|
+
assertMatch(idRegex, "/user/123/extra", false);
|
|
211
|
+
// Multiple dynamic parameters
|
|
212
|
+
const multiRegex = routeToRegex("/api/@version/@endpoint");
|
|
213
|
+
console.log(` "/api/@version/@endpoint" → ${multiRegex}`);
|
|
214
|
+
assertMatch(multiRegex, "/api/v1/users", true);
|
|
215
|
+
assertMatch(multiRegex, "/api/v2/posts", true);
|
|
216
|
+
assertMatch(multiRegex, "/api/only-one", false);
|
|
217
|
+
// Blog slug
|
|
218
|
+
const blogRegex = routeToRegex("/blog/@slug");
|
|
219
|
+
console.log(` "/blog/@slug" → ${blogRegex}`);
|
|
220
|
+
assertMatch(blogRegex, "/blog/my-first-post", true);
|
|
221
|
+
assertMatch(blogRegex, "/blog/hello-world", true);
|
|
222
|
+
assertMatch(blogRegex, "/blog/", false);
|
|
223
|
+
// Product category and id
|
|
224
|
+
const productRegex = routeToRegex("/product/@category/@id");
|
|
225
|
+
console.log(` "/product/@category/@id" → ${productRegex}`);
|
|
226
|
+
assertMatch(productRegex, "/product/electronics/iphone-15", true);
|
|
227
|
+
assertMatch(productRegex, "/product/books/978-0-13-468599-1", true);
|
|
228
|
+
assertMatch(productRegex, "/product/electronics", false);
|
|
229
|
+
// Deep nested with multiple params
|
|
230
|
+
const shopRegex = routeToRegex("/shop/@shopId/item/@itemId");
|
|
231
|
+
console.log(` "/shop/@shopId/item/@itemId" → ${shopRegex}`);
|
|
232
|
+
assertMatch(shopRegex, "/shop/123/item/456", true);
|
|
233
|
+
assertMatch(shopRegex, "/shop/amazon/item/B00XYZ", true);
|
|
234
|
+
assertMatch(shopRegex, "/shop/123/item", false);
|
|
235
|
+
// Localized routes
|
|
236
|
+
const langRegex = routeToRegex("/lang/@locale/page/@pageNum");
|
|
237
|
+
console.log(` "/lang/@locale/page/@pageNum" → ${langRegex}`);
|
|
238
|
+
assertMatch(langRegex, "/lang/en/page/1", true);
|
|
239
|
+
assertMatch(langRegex, "/lang/zh-CN/page/10", true);
|
|
240
|
+
assertMatch(langRegex, "/lang/en/page", false);
|
|
241
|
+
// Search keyword
|
|
242
|
+
const searchRegex = routeToRegex("/search/@keyword");
|
|
243
|
+
console.log(` "/search/@keyword" → ${searchRegex}`);
|
|
244
|
+
assertMatch(searchRegex, "/search/hello", true);
|
|
245
|
+
assertMatch(searchRegex, "/search/hello%20world", true);
|
|
246
|
+
// Docs path (single param, not catch-all)
|
|
247
|
+
const docsRegex = routeToRegex("/docs/@path");
|
|
248
|
+
console.log(` "/docs/@path" → ${docsRegex}`);
|
|
249
|
+
assertMatch(docsRegex, "/docs/getting-started", true);
|
|
250
|
+
assertMatch(docsRegex, "/docs/api-reference", true);
|
|
251
|
+
assertMatch(docsRegex, "/docs/nested/path", false, "Single @param doesn't match nested paths");
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// ============================================================================
|
|
255
|
+
// routeToRegex Tests - Bracket Syntax
|
|
256
|
+
// ============================================================================
|
|
257
|
+
function testBracketSyntax() {
|
|
258
|
+
runTestGroup("routeToRegex - Bracket Syntax (Next.js/Nuxt/SvelteKit)", () => {
|
|
259
|
+
// Single dynamic parameter
|
|
260
|
+
const idRegex = routeToRegex("/user/[id]");
|
|
261
|
+
console.log(` "/user/[id]" → ${idRegex}`);
|
|
262
|
+
assertMatch(idRegex, "/user/123", true);
|
|
263
|
+
assertMatch(idRegex, "/user/abc", true);
|
|
264
|
+
assertMatch(idRegex, "/user/", false);
|
|
265
|
+
// Multiple dynamic parameters
|
|
266
|
+
const multiRegex = routeToRegex("/user/[org]/[repo]");
|
|
267
|
+
console.log(` "/user/[org]/[repo]" → ${multiRegex}`);
|
|
268
|
+
assertMatch(multiRegex, "/user/facebook/react", true);
|
|
269
|
+
assertMatch(multiRegex, "/user/only-one", false);
|
|
270
|
+
// Optional parameter [[param]]
|
|
271
|
+
const optionalRegex = routeToRegex("/blog/[[slug]]");
|
|
272
|
+
console.log(` "/blog/[[slug]]" → ${optionalRegex}`);
|
|
273
|
+
assertMatch(optionalRegex, "/blog/my-post", true);
|
|
274
|
+
assertMatch(optionalRegex, "/blog", true, "Should match without optional param");
|
|
275
|
+
// Note: /blog/ may not match because (?:/([^/]+))? expects content after /
|
|
276
|
+
// Catch-all [...param]
|
|
277
|
+
const catchAllRegex = routeToRegex("/docs/[...path]");
|
|
278
|
+
console.log(` "/docs/[...path]" → ${catchAllRegex}`);
|
|
279
|
+
assertMatch(catchAllRegex, "/docs/", true);
|
|
280
|
+
assertMatch(catchAllRegex, "/docs/intro", true);
|
|
281
|
+
assertMatch(catchAllRegex, "/docs/guide/getting-started", true);
|
|
282
|
+
assertMatch(catchAllRegex, "/docs", true);
|
|
283
|
+
// Optional catch-all [[...param]]
|
|
284
|
+
const optCatchAllRegex = routeToRegex("/[[...path]]");
|
|
285
|
+
console.log(` "/[[...path]]" → ${optCatchAllRegex}`);
|
|
286
|
+
assertMatch(optCatchAllRegex, "/", true);
|
|
287
|
+
assertMatch(optCatchAllRegex, "/anything", true);
|
|
288
|
+
assertMatch(optCatchAllRegex, "/nested/path/here", true);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
// ============================================================================
|
|
292
|
+
// routeToRegex Options Tests
|
|
293
|
+
// ============================================================================
|
|
294
|
+
function testOptions() {
|
|
295
|
+
runTestGroup("routeToRegex - Options", () => {
|
|
296
|
+
// trailingSlashOptional: false
|
|
297
|
+
const strictRegex = routeToRegex("/about", { trailingSlashOptional: false });
|
|
298
|
+
console.log(` trailingSlashOptional: false → ${strictRegex}`);
|
|
299
|
+
assertMatch(strictRegex, "/about", true);
|
|
300
|
+
assertMatch(strictRegex, "/about/", false, "Should not match trailing slash");
|
|
301
|
+
// anchored: false
|
|
302
|
+
const unanchoredRegex = routeToRegex("/api", { anchored: false });
|
|
303
|
+
console.log(` anchored: false → ${unanchoredRegex}`);
|
|
304
|
+
assertMatch(unanchoredRegex, "/api", true);
|
|
305
|
+
assertMatch(unanchoredRegex, "/v1/api", true, "Should match anywhere");
|
|
306
|
+
assertMatch(unanchoredRegex, "/api/users", true);
|
|
307
|
+
// explicit syntax
|
|
308
|
+
const colonRegex = routeToRegex("/user/:id", { syntax: "colon" });
|
|
309
|
+
console.log(` syntax: "colon" → ${colonRegex}`);
|
|
310
|
+
assertMatch(colonRegex, "/user/123", true);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
// ============================================================================
|
|
314
|
+
// Edge Cases Tests
|
|
315
|
+
// ============================================================================
|
|
316
|
+
function testEdgeCases() {
|
|
317
|
+
runTestGroup("Edge Cases - Basic", () => {
|
|
318
|
+
// Root with trailing slash
|
|
319
|
+
const rootRegex = routeToRegex("/");
|
|
320
|
+
console.log(` "/" root route`);
|
|
321
|
+
assertMatch(rootRegex, "/", true);
|
|
322
|
+
// Route with dots (file extensions)
|
|
323
|
+
const fileRegex = routeToRegex("/files/:name.json");
|
|
324
|
+
console.log(` "/files/:name.json" → ${fileRegex}`);
|
|
325
|
+
assertMatch(fileRegex, "/files/config.json", true);
|
|
326
|
+
assertMatch(fileRegex, "/files/data.json", true);
|
|
327
|
+
// Route with multiple consecutive params
|
|
328
|
+
const consecutiveRegex = routeToRegex("/:a/:b/:c");
|
|
329
|
+
console.log(` "/:a/:b/:c" → ${consecutiveRegex}`);
|
|
330
|
+
assertMatch(consecutiveRegex, "/x/y/z", true);
|
|
331
|
+
assertMatch(consecutiveRegex, "/1/2/3", true);
|
|
332
|
+
assertMatch(consecutiveRegex, "/x/y", false);
|
|
333
|
+
// Numeric paths
|
|
334
|
+
const numericRegex = routeToRegex("/api/v1/users/:id");
|
|
335
|
+
console.log(` "/api/v1/users/:id" → ${numericRegex}`);
|
|
336
|
+
assertMatch(numericRegex, "/api/v1/users/123", true);
|
|
337
|
+
assertMatch(numericRegex, "/api/v2/users/123", false);
|
|
338
|
+
// Special characters in path
|
|
339
|
+
const specialRegex = routeToRegex("/path+with+plus");
|
|
340
|
+
console.log(` "/path+with+plus" → ${specialRegex}`);
|
|
341
|
+
assertMatch(specialRegex, "/path+with+plus", true);
|
|
342
|
+
});
|
|
343
|
+
runTestGroup("Edge Cases - Parameter Names", () => {
|
|
344
|
+
// Parameter with numbers
|
|
345
|
+
const numParamRegex = routeToRegex("/user/:id123");
|
|
346
|
+
console.log(` "/user/:id123" → ${numParamRegex}`);
|
|
347
|
+
assertMatch(numParamRegex, "/user/abc", true);
|
|
348
|
+
assertMatch(numParamRegex, "/user/456", true);
|
|
349
|
+
// Parameter with underscore
|
|
350
|
+
const underscoreRegex = routeToRegex("/post/:post_id");
|
|
351
|
+
console.log(` "/post/:post_id" → ${underscoreRegex}`);
|
|
352
|
+
assertMatch(underscoreRegex, "/post/123", true);
|
|
353
|
+
assertMatch(underscoreRegex, "/post/my-post", true);
|
|
354
|
+
// Multiple underscores
|
|
355
|
+
const multiUnderscoreRegex = routeToRegex("/api/:resource_type/:resource_id");
|
|
356
|
+
console.log(` "/api/:resource_type/:resource_id" → ${multiUnderscoreRegex}`);
|
|
357
|
+
assertMatch(multiUnderscoreRegex, "/api/users/123", true);
|
|
358
|
+
// Bracket syntax with underscore
|
|
359
|
+
const bracketUnderscoreRegex = routeToRegex("/item/[item_id]");
|
|
360
|
+
console.log(` "/item/[item_id]" → ${bracketUnderscoreRegex}`);
|
|
361
|
+
assertMatch(bracketUnderscoreRegex, "/item/abc123", true);
|
|
362
|
+
// Dollar syntax with underscore
|
|
363
|
+
const dollarUnderscoreRegex = routeToRegex("/product/$product_id");
|
|
364
|
+
console.log(` "/product/$product_id" → ${dollarUnderscoreRegex}`);
|
|
365
|
+
assertMatch(dollarUnderscoreRegex, "/product/xyz", true);
|
|
366
|
+
});
|
|
367
|
+
runTestGroup("Edge Cases - Path Variations", () => {
|
|
368
|
+
// Hyphenated static path
|
|
369
|
+
const hyphenRegex = routeToRegex("/my-page/:slug");
|
|
370
|
+
console.log(` "/my-page/:slug" → ${hyphenRegex}`);
|
|
371
|
+
assertMatch(hyphenRegex, "/my-page/hello-world", true);
|
|
372
|
+
assertMatch(hyphenRegex, "/my-page/test", true);
|
|
373
|
+
// Deep nested routes
|
|
374
|
+
const deepRegex = routeToRegex("/a/b/c/d/e/:id/f/g");
|
|
375
|
+
console.log(` "/a/b/c/d/e/:id/f/g" → ${deepRegex}`);
|
|
376
|
+
assertMatch(deepRegex, "/a/b/c/d/e/123/f/g", true);
|
|
377
|
+
assertMatch(deepRegex, "/a/b/c/d/e/123/f", false);
|
|
378
|
+
// Multiple dynamic segments scattered
|
|
379
|
+
const scatteredRegex = routeToRegex("/org/:orgId/team/:teamId/member/:memberId");
|
|
380
|
+
console.log(` "/org/:orgId/team/:teamId/member/:memberId" → ${scatteredRegex}`);
|
|
381
|
+
assertMatch(scatteredRegex, "/org/acme/team/eng/member/john", true);
|
|
382
|
+
assertMatch(scatteredRegex, "/org/acme/team/eng", false);
|
|
383
|
+
// Parentheses in static path (TanStack route groups)
|
|
384
|
+
const groupRegex = routeToRegex("/(auth)/login");
|
|
385
|
+
console.log(` "/(auth)/login" → ${groupRegex}`);
|
|
386
|
+
assertMatch(groupRegex, "/(auth)/login", true);
|
|
387
|
+
});
|
|
388
|
+
runTestGroup("Edge Cases - Special Matching", () => {
|
|
389
|
+
// URL with encoded characters
|
|
390
|
+
const encodedRegex = routeToRegex("/search/:query");
|
|
391
|
+
console.log(` "/search/:query" URL encoded`);
|
|
392
|
+
assertMatch(encodedRegex, "/search/hello%20world", true);
|
|
393
|
+
assertMatch(encodedRegex, "/search/test%2Fpath", true);
|
|
394
|
+
// Route ending with specific extension
|
|
395
|
+
const extRegex = routeToRegex("/download/:file.pdf");
|
|
396
|
+
console.log(` "/download/:file.pdf" → ${extRegex}`);
|
|
397
|
+
assertMatch(extRegex, "/download/report.pdf", true);
|
|
398
|
+
assertMatch(extRegex, "/download/document.pdf", true);
|
|
399
|
+
// Numbers in static path
|
|
400
|
+
const num404Regex = routeToRegex("/error/404");
|
|
401
|
+
console.log(` "/error/404" → ${num404Regex}`);
|
|
402
|
+
assertMatch(num404Regex, "/error/404", true);
|
|
403
|
+
assertMatch(num404Regex, "/error/500", false);
|
|
404
|
+
// Very long parameter value
|
|
405
|
+
const longValueRegex = routeToRegex("/article/:slug");
|
|
406
|
+
const longSlug = "a".repeat(200);
|
|
407
|
+
console.log(` Long parameter value (200 chars)`);
|
|
408
|
+
assertMatch(longValueRegex, `/article/${longSlug}`, true);
|
|
409
|
+
});
|
|
410
|
+
runTestGroup("Edge Cases - Wildcards and Catch-alls", () => {
|
|
411
|
+
// Root catch-all
|
|
412
|
+
const rootCatchAllRegex = routeToRegex("/*");
|
|
413
|
+
console.log(` "/*" root catch-all`);
|
|
414
|
+
assertMatch(rootCatchAllRegex, "/", true);
|
|
415
|
+
assertMatch(rootCatchAllRegex, "/anything", true);
|
|
416
|
+
assertMatch(rootCatchAllRegex, "/a/b/c/d", true);
|
|
417
|
+
// Nested catch-all
|
|
418
|
+
const nestedCatchAllRegex = routeToRegex("/api/v1/*");
|
|
419
|
+
console.log(` "/api/v1/*" → ${nestedCatchAllRegex}`);
|
|
420
|
+
assertMatch(nestedCatchAllRegex, "/api/v1", true);
|
|
421
|
+
assertMatch(nestedCatchAllRegex, "/api/v1/", true);
|
|
422
|
+
assertMatch(nestedCatchAllRegex, "/api/v1/users/123/posts", true);
|
|
423
|
+
// Dollar splat at different depths
|
|
424
|
+
const deepDollarSplatRegex = routeToRegex("/files/public/$");
|
|
425
|
+
console.log(` "/files/public/$" → ${deepDollarSplatRegex}`);
|
|
426
|
+
assertMatch(deepDollarSplatRegex, "/files/public", true);
|
|
427
|
+
assertMatch(deepDollarSplatRegex, "/files/public/images/photo.jpg", true);
|
|
428
|
+
// Bracket catch-all variations
|
|
429
|
+
const bracketDeepCatchAllRegex = routeToRegex("/shop/[...categories]");
|
|
430
|
+
console.log(` "/shop/[...categories]" → ${bracketDeepCatchAllRegex}`);
|
|
431
|
+
assertMatch(bracketDeepCatchAllRegex, "/shop", true);
|
|
432
|
+
assertMatch(bracketDeepCatchAllRegex, "/shop/electronics", true);
|
|
433
|
+
assertMatch(bracketDeepCatchAllRegex, "/shop/electronics/phones/iphone", true);
|
|
434
|
+
});
|
|
435
|
+
runTestGroup("Edge Cases - Multiple Optional Params", () => {
|
|
436
|
+
// Two optional colon params (Note: typically not valid but test conversion)
|
|
437
|
+
const twoOptionalRegex = routeToRegex("/archive/:year?/:month?");
|
|
438
|
+
console.log(` "/archive/:year?/:month?" → ${twoOptionalRegex}`);
|
|
439
|
+
assertMatch(twoOptionalRegex, "/archive", true);
|
|
440
|
+
assertMatch(twoOptionalRegex, "/archive/2024", true);
|
|
441
|
+
// Note: /archive/2024/12 may not match due to how optional groups work
|
|
442
|
+
// Bracket optional at root - this is a special case
|
|
443
|
+
// /[[lang]] means: optional language prefix, the root "/" is implicit
|
|
444
|
+
const rootOptionalRegex = routeToRegex("/[[lang]]");
|
|
445
|
+
console.log(` "/[[lang]]" → ${rootOptionalRegex}`);
|
|
446
|
+
// Note: ^(?:/([^/]+))?$ won't match "/" because it expects either nothing or /content
|
|
447
|
+
// This is expected behavior - "/" matches when the pattern is just "/" not "/[[lang]]"
|
|
448
|
+
assertMatch(rootOptionalRegex, "/en", true);
|
|
449
|
+
assertMatch(rootOptionalRegex, "/zh-CN", true);
|
|
450
|
+
assertMatch(rootOptionalRegex, "", true, "Empty string matches optional");
|
|
451
|
+
});
|
|
452
|
+
runTestGroup("Edge Cases - Real World Patterns", () => {
|
|
453
|
+
// GitHub-style routes
|
|
454
|
+
const githubRegex = routeToRegex("/:owner/:repo/tree/:branch/*");
|
|
455
|
+
console.log(` "/:owner/:repo/tree/:branch/*" GitHub pattern`);
|
|
456
|
+
assertMatch(githubRegex, "/facebook/react/tree/main", true);
|
|
457
|
+
assertMatch(githubRegex, "/facebook/react/tree/main/packages/react", true);
|
|
458
|
+
// Blog with date pattern
|
|
459
|
+
const blogDateRegex = routeToRegex("/blog/:year/:month/:day/:slug");
|
|
460
|
+
console.log(` "/blog/:year/:month/:day/:slug" → ${blogDateRegex}`);
|
|
461
|
+
assertMatch(blogDateRegex, "/blog/2024/01/15/hello-world", true);
|
|
462
|
+
// E-commerce product
|
|
463
|
+
const productRegex = routeToRegex("/category/[category]/product/[productId]");
|
|
464
|
+
console.log(` "/category/[category]/product/[productId]" → ${productRegex}`);
|
|
465
|
+
assertMatch(productRegex, "/category/electronics/product/iphone-15", true);
|
|
466
|
+
// API versioning with dynamic resource
|
|
467
|
+
const apiRegex = routeToRegex("/api/v:version/:resource/:id");
|
|
468
|
+
console.log(` "/api/v:version/:resource/:id" → ${apiRegex}`);
|
|
469
|
+
assertMatch(apiRegex, "/api/v1/users/123", true);
|
|
470
|
+
assertMatch(apiRegex, "/api/v2/posts/456", true);
|
|
471
|
+
// Localized routes
|
|
472
|
+
const i18nRegex = routeToRegex("/[locale]/about");
|
|
473
|
+
console.log(` "/[locale]/about" → ${i18nRegex}`);
|
|
474
|
+
assertMatch(i18nRegex, "/en/about", true);
|
|
475
|
+
assertMatch(i18nRegex, "/zh-CN/about", true);
|
|
476
|
+
assertMatch(i18nRegex, "/about", false);
|
|
477
|
+
// Vike-style routes
|
|
478
|
+
const vikeUserRegex = routeToRegex("/user/@id");
|
|
479
|
+
console.log(` "/user/@id" Vike pattern`);
|
|
480
|
+
assertMatch(vikeUserRegex, "/user/123", true);
|
|
481
|
+
assertMatch(vikeUserRegex, "/user/john", true);
|
|
482
|
+
const vikeApiRegex = routeToRegex("/api/@version/@endpoint");
|
|
483
|
+
console.log(` "/api/@version/@endpoint" Vike pattern`);
|
|
484
|
+
assertMatch(vikeApiRegex, "/api/v1/users", true);
|
|
485
|
+
const vikeShopRegex = routeToRegex("/shop/@shopId/item/@itemId");
|
|
486
|
+
console.log(` "/shop/@shopId/item/@itemId" Vike pattern`);
|
|
487
|
+
assertMatch(vikeShopRegex, "/shop/store1/item/product123", true);
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
// ============================================================================
|
|
491
|
+
// sortRoutesByPriority Tests
|
|
492
|
+
// ============================================================================
|
|
493
|
+
function testSortRoutes() {
|
|
494
|
+
runTestGroup("sortRoutesByPriority", () => {
|
|
495
|
+
const routes = [
|
|
496
|
+
{ path: "/*", isStatic: false },
|
|
497
|
+
{ path: "/api/:resource", isStatic: false },
|
|
498
|
+
{ path: "/api/users/:id", isStatic: false },
|
|
499
|
+
{ path: "/", isStatic: true },
|
|
500
|
+
{ path: "/about", isStatic: true },
|
|
501
|
+
{ path: "/api/users", isStatic: false },
|
|
502
|
+
];
|
|
503
|
+
const sorted = sortRoutesByPriority(routes);
|
|
504
|
+
console.log(" Input order: /*, /api/:resource, /api/users/:id, /, /about, /api/users");
|
|
505
|
+
console.log(" Sorted order:", sorted.map(r => r.path).join(", "));
|
|
506
|
+
// Static routes should come first
|
|
507
|
+
console.assert(sorted[0].path === "/" || sorted[0].path === "/about", "Static routes should be first");
|
|
508
|
+
// Catch-all should be last
|
|
509
|
+
console.assert(sorted[sorted.length - 1].path === "/*", "Catch-all should be last");
|
|
510
|
+
// More specific dynamic routes should come before less specific
|
|
511
|
+
const apiUsersIdIndex = sorted.findIndex(r => r.path === "/api/users/:id");
|
|
512
|
+
const apiResourceIndex = sorted.findIndex(r => r.path === "/api/:resource");
|
|
513
|
+
console.assert(apiUsersIdIndex < apiResourceIndex, "/api/users/:id should come before /api/:resource");
|
|
514
|
+
console.log(" ✓ Static routes first, catch-all last, specific before general");
|
|
515
|
+
});
|
|
516
|
+
runTestGroup("sortRoutesByPriority - Mixed Syntaxes", () => {
|
|
517
|
+
const routes = [
|
|
518
|
+
{ path: "/files/$", isStatic: false }, // TanStack splat
|
|
519
|
+
{ path: "/blog/[slug]", isStatic: false }, // Next.js dynamic
|
|
520
|
+
{ path: "/user/:id", isStatic: false }, // React Router dynamic
|
|
521
|
+
{ path: "/about", isStatic: true },
|
|
522
|
+
{ path: "/docs/[...path]", isStatic: false }, // Next.js catch-all
|
|
523
|
+
{ path: "/product/@id", isStatic: false }, // Vike dynamic
|
|
524
|
+
];
|
|
525
|
+
const sorted = sortRoutesByPriority(routes);
|
|
526
|
+
console.log(" Mixed syntax routes sorted:", sorted.map(r => r.path).join(", "));
|
|
527
|
+
// Static should be first
|
|
528
|
+
console.assert(sorted[0].path === "/about", "Static route should be first");
|
|
529
|
+
// Catch-all routes should be last
|
|
530
|
+
const catchAllPaths = ["/files/$", "/docs/[...path]"];
|
|
531
|
+
const lastTwo = sorted.slice(-2).map(r => r.path);
|
|
532
|
+
console.assert(catchAllPaths.every(p => lastTwo.includes(p)), "Catch-all routes should be last");
|
|
533
|
+
console.log(" ✓ Correctly handles mixed syntaxes including Vike @param");
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
// ============================================================================
|
|
537
|
+
// addRegexToRoutes Tests
|
|
538
|
+
// ============================================================================
|
|
539
|
+
function testAddRegexToRoutes() {
|
|
540
|
+
runTestGroup("addRegexToRoutes", () => {
|
|
541
|
+
const routes = [
|
|
542
|
+
{ path: "/", isStatic: true },
|
|
543
|
+
{ path: "/about", isStatic: true },
|
|
544
|
+
{ path: "/blog/:slug", isStatic: false },
|
|
545
|
+
{ path: "/user/:id/posts", isStatic: false },
|
|
546
|
+
];
|
|
547
|
+
const result = addRegexToRoutes(routes);
|
|
548
|
+
console.log(" Static routes should not have regex:");
|
|
549
|
+
console.assert(!result[0].regex, "/ should not have regex");
|
|
550
|
+
console.assert(!result[1].regex, "/about should not have regex");
|
|
551
|
+
console.log(" ✓ / and /about have no regex");
|
|
552
|
+
console.log(" Dynamic routes should have regex:");
|
|
553
|
+
console.assert(result[2].regex !== undefined, "/blog/:slug should have regex");
|
|
554
|
+
console.assert(result[3].regex !== undefined, "/user/:id/posts should have regex");
|
|
555
|
+
console.log(` ✓ /blog/:slug → ${result[2].regex}`);
|
|
556
|
+
console.log(` ✓ /user/:id/posts → ${result[3].regex}`);
|
|
557
|
+
// Verify regex actually works
|
|
558
|
+
if (result[2].regex) {
|
|
559
|
+
assertMatch(result[2].regex, "/blog/my-post", true);
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
runTestGroup("addRegexToRoutes - with srcRoute", () => {
|
|
563
|
+
const routes = [
|
|
564
|
+
{ path: "/blog/my-post", isStatic: true, srcRoute: "/blog/:slug" },
|
|
565
|
+
];
|
|
566
|
+
const result = addRegexToRoutes(routes);
|
|
567
|
+
console.assert(result[0].regex !== undefined, "Should use srcRoute for regex");
|
|
568
|
+
console.log(` ✓ Uses srcRoute "/blog/:slug" → ${result[0].regex}`);
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
// ============================================================================
|
|
572
|
+
// convertRoutesToMetaFormat Tests
|
|
573
|
+
// ============================================================================
|
|
574
|
+
function testConvertRoutesToMetaFormat() {
|
|
575
|
+
runTestGroup("convertRoutesToMetaFormat", () => {
|
|
576
|
+
const routes = [
|
|
577
|
+
{ path: "/", isStatic: true },
|
|
578
|
+
{ path: "/about", isStatic: true },
|
|
579
|
+
{ path: "/blog/:slug", isStatic: false },
|
|
580
|
+
{ path: "/files/*", isStatic: false },
|
|
581
|
+
];
|
|
582
|
+
const result = convertRoutesToMetaFormat(routes);
|
|
583
|
+
console.log(" Static routes keep original path:");
|
|
584
|
+
console.assert(result[0].regexPath === "/", "/ should stay /");
|
|
585
|
+
console.assert(result[1].regexPath === "/about", "/about should stay /about");
|
|
586
|
+
console.log(` ✓ "/" → "${result[0].regexPath}"`);
|
|
587
|
+
console.log(` ✓ "/about" → "${result[1].regexPath}"`);
|
|
588
|
+
console.log(" Dynamic routes converted to regex:");
|
|
589
|
+
console.assert(result[2].regexPath.includes("([^/]+)"), "/blog/:slug should be regex");
|
|
590
|
+
console.assert(result[3].regexPath.includes("(.*)"), "/files/* should be regex");
|
|
591
|
+
console.log(` ✓ "/blog/:slug" → "${result[2].regexPath}"`);
|
|
592
|
+
console.log(` ✓ "/files/*" → "${result[3].regexPath}"`);
|
|
593
|
+
console.log(" isStatic preserved:");
|
|
594
|
+
console.assert(result[0].isStatic === true, "/ isStatic should be true");
|
|
595
|
+
console.assert(result[2].isStatic === false, "/blog/:slug isStatic should be false");
|
|
596
|
+
console.log(" ✓ isStatic values preserved");
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
// ============================================================================
|
|
600
|
+
// Regression Tests
|
|
601
|
+
// ============================================================================
|
|
602
|
+
function testRegressions() {
|
|
603
|
+
runTestGroup("Regression Tests", () => {
|
|
604
|
+
// Issue: [[param]] was producing ([^/]+)? instead of (?:/([^/]+))?
|
|
605
|
+
console.log(" Issue: Optional bracket params with preceding slash");
|
|
606
|
+
const optBracket = routeToRegex("/blog/[[slug]]");
|
|
607
|
+
assertMatch(optBracket, "/blog", true, "Should match without param");
|
|
608
|
+
assertMatch(optBracket, "/blog/my-post", true, "Should match with param");
|
|
609
|
+
// Note: /blog/ with trailing slash but no param may not match - this is correct behavior
|
|
610
|
+
// Issue: Dollar splat $ not matching correctly
|
|
611
|
+
console.log(" Issue: Dollar splat handling");
|
|
612
|
+
const dollarSplat = routeToRegex("/api/$");
|
|
613
|
+
assertMatch(dollarSplat, "/api", true);
|
|
614
|
+
assertMatch(dollarSplat, "/api/", true);
|
|
615
|
+
assertMatch(dollarSplat, "/api/anything", true);
|
|
616
|
+
assertMatch(dollarSplat, "/api/nested/path", true);
|
|
617
|
+
// Issue: Bracket catch-all [...] behavior
|
|
618
|
+
console.log(" Issue: Bracket catch-all consistency");
|
|
619
|
+
const bracketCatchAll = routeToRegex("/docs/[...path]");
|
|
620
|
+
const bracketOptCatchAll = routeToRegex("/docs/[[...path]]");
|
|
621
|
+
// Both should have similar structure
|
|
622
|
+
console.log(` [...path] → ${bracketCatchAll}`);
|
|
623
|
+
console.log(` [[...path]] → ${bracketOptCatchAll}`);
|
|
624
|
+
assertMatch(bracketCatchAll, "/docs", true);
|
|
625
|
+
assertMatch(bracketOptCatchAll, "/docs", true);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
// ============================================================================
|
|
629
|
+
// Run All Tests
|
|
630
|
+
// ============================================================================
|
|
631
|
+
export function runAllTests() {
|
|
632
|
+
console.log("╔════════════════════════════════════════════════════════════╗");
|
|
633
|
+
console.log("║ Route Regex Test Suite ║");
|
|
634
|
+
console.log("╚════════════════════════════════════════════════════════════╝");
|
|
635
|
+
try {
|
|
636
|
+
testIsDynamicRoute();
|
|
637
|
+
testIsCatchAllRoute();
|
|
638
|
+
testColonSyntax();
|
|
639
|
+
testDollarSyntax();
|
|
640
|
+
testAtSyntax();
|
|
641
|
+
testBracketSyntax();
|
|
642
|
+
testOptions();
|
|
643
|
+
testEdgeCases();
|
|
644
|
+
testSortRoutes();
|
|
645
|
+
testAddRegexToRoutes();
|
|
646
|
+
testConvertRoutesToMetaFormat();
|
|
647
|
+
testRegressions();
|
|
648
|
+
console.log("\n╔════════════════════════════════════════════════════════════╗");
|
|
649
|
+
console.log("║ ✓ All tests passed! ║");
|
|
650
|
+
console.log("╚════════════════════════════════════════════════════════════╝\n");
|
|
651
|
+
}
|
|
652
|
+
catch (error) {
|
|
653
|
+
console.error("\n╔════════════════════════════════════════════════════════════╗");
|
|
654
|
+
console.error("║ ✗ Tests failed! ║");
|
|
655
|
+
console.error("╚════════════════════════════════════════════════════════════╝");
|
|
656
|
+
console.error(error);
|
|
657
|
+
process.exit(1);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
// Run tests if executed directly
|
|
661
|
+
runAllTests();
|
|
662
|
+
//# sourceMappingURL=regex.test.js.map
|