@esmx/router 3.0.0-rc.18 → 3.0.0-rc.20

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 (158) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +70 -0
  3. package/README.zh-CN.md +70 -0
  4. package/dist/error.d.ts +23 -0
  5. package/dist/error.mjs +61 -0
  6. package/dist/increment-id.d.ts +7 -0
  7. package/dist/increment-id.mjs +11 -0
  8. package/dist/index.d.ts +5 -3
  9. package/dist/index.mjs +14 -3
  10. package/dist/index.test.mjs +8 -0
  11. package/dist/location.d.ts +15 -0
  12. package/dist/location.mjs +53 -0
  13. package/dist/location.test.d.ts +8 -0
  14. package/dist/location.test.mjs +370 -0
  15. package/dist/matcher.d.ts +3 -0
  16. package/dist/matcher.mjs +44 -0
  17. package/dist/matcher.test.mjs +1492 -0
  18. package/dist/micro-app.d.ts +18 -0
  19. package/dist/micro-app.dom.test.d.ts +1 -0
  20. package/dist/micro-app.dom.test.mjs +532 -0
  21. package/dist/micro-app.mjs +80 -0
  22. package/dist/navigation.d.ts +43 -0
  23. package/dist/navigation.mjs +143 -0
  24. package/dist/navigation.test.d.ts +1 -0
  25. package/dist/navigation.test.mjs +681 -0
  26. package/dist/options.d.ts +4 -0
  27. package/dist/options.mjs +88 -0
  28. package/dist/route-task.d.ts +40 -0
  29. package/dist/route-task.mjs +75 -0
  30. package/dist/route-task.test.d.ts +1 -0
  31. package/dist/route-task.test.mjs +673 -0
  32. package/dist/route-transition.d.ts +53 -0
  33. package/dist/route-transition.mjs +307 -0
  34. package/dist/route-transition.test.d.ts +1 -0
  35. package/dist/route-transition.test.mjs +146 -0
  36. package/dist/route.d.ts +72 -0
  37. package/dist/route.mjs +194 -0
  38. package/dist/route.test.d.ts +1 -0
  39. package/dist/route.test.mjs +1664 -0
  40. package/dist/router-back.test.d.ts +1 -0
  41. package/dist/router-back.test.mjs +361 -0
  42. package/dist/router-forward.test.d.ts +1 -0
  43. package/dist/router-forward.test.mjs +376 -0
  44. package/dist/router-go.test.d.ts +1 -0
  45. package/dist/router-go.test.mjs +73 -0
  46. package/dist/router-guards-cleanup.test.d.ts +1 -0
  47. package/dist/router-guards-cleanup.test.mjs +437 -0
  48. package/dist/router-link.d.ts +10 -0
  49. package/dist/router-link.mjs +126 -0
  50. package/dist/router-push.test.d.ts +1 -0
  51. package/dist/router-push.test.mjs +115 -0
  52. package/dist/router-replace.test.d.ts +1 -0
  53. package/dist/router-replace.test.mjs +114 -0
  54. package/dist/router-resolve.test.d.ts +1 -0
  55. package/dist/router-resolve.test.mjs +393 -0
  56. package/dist/router-restart-app.dom.test.d.ts +1 -0
  57. package/dist/router-restart-app.dom.test.mjs +616 -0
  58. package/dist/router-window-navigation.test.d.ts +1 -0
  59. package/dist/router-window-navigation.test.mjs +359 -0
  60. package/dist/router.d.ts +109 -102
  61. package/dist/router.mjs +260 -361
  62. package/dist/types.d.ts +246 -0
  63. package/dist/types.mjs +18 -0
  64. package/dist/util.d.ts +26 -0
  65. package/dist/util.mjs +53 -0
  66. package/dist/util.test.d.ts +1 -0
  67. package/dist/util.test.mjs +1020 -0
  68. package/package.json +10 -13
  69. package/src/error.ts +84 -0
  70. package/src/increment-id.ts +12 -0
  71. package/src/index.test.ts +9 -0
  72. package/src/index.ts +54 -3
  73. package/src/location.test.ts +406 -0
  74. package/src/location.ts +96 -0
  75. package/src/matcher.test.ts +1685 -0
  76. package/src/matcher.ts +59 -0
  77. package/src/micro-app.dom.test.ts +708 -0
  78. package/src/micro-app.ts +101 -0
  79. package/src/navigation.test.ts +858 -0
  80. package/src/navigation.ts +195 -0
  81. package/src/options.ts +131 -0
  82. package/src/route-task.test.ts +901 -0
  83. package/src/route-task.ts +105 -0
  84. package/src/route-transition.test.ts +178 -0
  85. package/src/route-transition.ts +425 -0
  86. package/src/route.test.ts +2014 -0
  87. package/src/route.ts +308 -0
  88. package/src/router-back.test.ts +487 -0
  89. package/src/router-forward.test.ts +506 -0
  90. package/src/router-go.test.ts +91 -0
  91. package/src/router-guards-cleanup.test.ts +595 -0
  92. package/src/router-link.ts +235 -0
  93. package/src/router-push.test.ts +140 -0
  94. package/src/router-replace.test.ts +139 -0
  95. package/src/router-resolve.test.ts +475 -0
  96. package/src/router-restart-app.dom.test.ts +783 -0
  97. package/src/router-window-navigation.test.ts +457 -0
  98. package/src/router.ts +289 -470
  99. package/src/types.ts +341 -0
  100. package/src/util.test.ts +1262 -0
  101. package/src/util.ts +116 -0
  102. package/dist/history/abstract.d.ts +0 -29
  103. package/dist/history/abstract.mjs +0 -107
  104. package/dist/history/base.d.ts +0 -79
  105. package/dist/history/base.mjs +0 -275
  106. package/dist/history/html.d.ts +0 -30
  107. package/dist/history/html.mjs +0 -183
  108. package/dist/history/index.d.ts +0 -7
  109. package/dist/history/index.mjs +0 -16
  110. package/dist/matcher/create-matcher.d.ts +0 -5
  111. package/dist/matcher/create-matcher.mjs +0 -218
  112. package/dist/matcher/create-matcher.spec.mjs +0 -0
  113. package/dist/matcher/index.d.ts +0 -1
  114. package/dist/matcher/index.mjs +0 -1
  115. package/dist/task-pipe/index.d.ts +0 -1
  116. package/dist/task-pipe/index.mjs +0 -1
  117. package/dist/task-pipe/task.d.ts +0 -30
  118. package/dist/task-pipe/task.mjs +0 -66
  119. package/dist/types/index.d.ts +0 -694
  120. package/dist/types/index.mjs +0 -6
  121. package/dist/utils/bom.d.ts +0 -5
  122. package/dist/utils/bom.mjs +0 -10
  123. package/dist/utils/encoding.d.ts +0 -48
  124. package/dist/utils/encoding.mjs +0 -44
  125. package/dist/utils/guards.d.ts +0 -9
  126. package/dist/utils/guards.mjs +0 -12
  127. package/dist/utils/index.d.ts +0 -7
  128. package/dist/utils/index.mjs +0 -27
  129. package/dist/utils/path.d.ts +0 -60
  130. package/dist/utils/path.mjs +0 -282
  131. package/dist/utils/path.spec.mjs +0 -27
  132. package/dist/utils/scroll.d.ts +0 -25
  133. package/dist/utils/scroll.mjs +0 -59
  134. package/dist/utils/utils.d.ts +0 -16
  135. package/dist/utils/utils.mjs +0 -11
  136. package/dist/utils/warn.d.ts +0 -2
  137. package/dist/utils/warn.mjs +0 -12
  138. package/src/history/abstract.ts +0 -149
  139. package/src/history/base.ts +0 -408
  140. package/src/history/html.ts +0 -228
  141. package/src/history/index.ts +0 -20
  142. package/src/matcher/create-matcher.spec.ts +0 -3
  143. package/src/matcher/create-matcher.ts +0 -292
  144. package/src/matcher/index.ts +0 -1
  145. package/src/task-pipe/index.ts +0 -1
  146. package/src/task-pipe/task.ts +0 -97
  147. package/src/types/index.ts +0 -858
  148. package/src/utils/bom.ts +0 -14
  149. package/src/utils/encoding.ts +0 -153
  150. package/src/utils/guards.ts +0 -25
  151. package/src/utils/index.ts +0 -27
  152. package/src/utils/path.spec.ts +0 -32
  153. package/src/utils/path.ts +0 -418
  154. package/src/utils/scroll.ts +0 -120
  155. package/src/utils/utils.ts +0 -30
  156. package/src/utils/warn.ts +0 -13
  157. /package/dist/{matcher/create-matcher.spec.d.ts → index.test.d.ts} +0 -0
  158. /package/dist/{utils/path.spec.d.ts → matcher.test.d.ts} +0 -0
@@ -0,0 +1,370 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { normalizeURL, parseLocation } from "./location.mjs";
3
+ expect.extend({
4
+ toEqURL: (received, expected) => {
5
+ if (!(received instanceof URL)) {
6
+ return {
7
+ message: () => `expected ${received} to be an instance of URL`,
8
+ pass: false
9
+ };
10
+ }
11
+ (received = new URL(received)).searchParams.sort();
12
+ (expected = new URL(expected)).searchParams.sort();
13
+ received.hash = received.hash;
14
+ expected.hash = expected.hash;
15
+ return {
16
+ message: () => `expected ${received.href} to be ${expected.href}`,
17
+ pass: received.href === expected.href
18
+ };
19
+ }
20
+ });
21
+ describe("normalizeURL", () => {
22
+ const testCases = [
23
+ {
24
+ input: "//example.com/path",
25
+ base: "https://github.com",
26
+ expected: "http://example.com/path",
27
+ description: "should handle protocol-relative URLs (starting with //)"
28
+ },
29
+ {
30
+ input: "http://github.com/path?a#h",
31
+ base: "http://example.com",
32
+ expected: "http://github.com/path?a#h",
33
+ description: "should handle absolute URLs"
34
+ },
35
+ {
36
+ input: "/path",
37
+ base: "http://example.com/en/",
38
+ expected: "http://example.com/en/path",
39
+ description: "should handle relative paths with a base URL"
40
+ },
41
+ {
42
+ input: "github.com",
43
+ base: "http://example.com",
44
+ expected: "http://example.com/github.com",
45
+ description: "should treat bare domains as relative paths"
46
+ },
47
+ {
48
+ input: new URL("http://example.com/path"),
49
+ base: "http://example.com",
50
+ expected: "http://example.com/path",
51
+ description: "should handle URL objects"
52
+ },
53
+ {
54
+ input: "-a://example.com",
55
+ base: "http://example.com",
56
+ expected: "http://example.com/-a://example.com",
57
+ description: "should treat strings that fail to parse as a protocol as relative paths"
58
+ }
59
+ ];
60
+ testCases.forEach(({ input, base, expected, description }) => {
61
+ test(description, () => {
62
+ const result = normalizeURL(input, new URL(base));
63
+ expect(result).toEqURL(expected);
64
+ });
65
+ });
66
+ });
67
+ describe("parseLocation", () => {
68
+ const testCases = [
69
+ {
70
+ input: "/products",
71
+ base: "http://example.com",
72
+ expected: "http://example.com/products",
73
+ description: "should handle string paths"
74
+ },
75
+ {
76
+ input: { path: "/products" },
77
+ base: "http://example.com",
78
+ expected: "http://example.com/products",
79
+ description: "should handle objects with a path property"
80
+ },
81
+ {
82
+ input: { url: "/products" },
83
+ base: "http://example.com",
84
+ expected: "http://example.com/products",
85
+ description: "should handle objects with a url property"
86
+ },
87
+ {
88
+ input: {
89
+ path: "/products",
90
+ query: { id: "123", category: "electronics" }
91
+ },
92
+ base: "http://example.com",
93
+ expected: "http://example.com/products?id=123&category=electronics",
94
+ description: "should handle objects with query parameters"
95
+ },
96
+ {
97
+ input: { path: "/products", query: { id: "123" }, hash: "details" },
98
+ base: "http://example.com",
99
+ expected: "http://example.com/products?id=123#details",
100
+ description: "should handle objects with a hash"
101
+ },
102
+ {
103
+ input: { path: "/products", queryArray: { tag: ["new", "sale"] } },
104
+ base: "http://example.com",
105
+ expected: "http://example.com/products?tag=new&tag=sale",
106
+ description: "should handle objects with queryArray"
107
+ },
108
+ {
109
+ input: {
110
+ path: "/products",
111
+ query: { id: "123", category: "electronics" },
112
+ queryArray: { tag: ["new", "sale"] },
113
+ hash: "details"
114
+ },
115
+ base: "http://example.com",
116
+ expected: "http://example.com/products?id=123&category=electronics&tag=new&tag=sale#details",
117
+ description: "should handle complex objects with all properties"
118
+ },
119
+ {
120
+ input: {
121
+ path: "/products",
122
+ hash: "#a?a"
123
+ },
124
+ base: "http://example.com",
125
+ expected: "http://example.com/products#a?a",
126
+ description: "should handle special hash characters correctly"
127
+ },
128
+ {
129
+ input: {
130
+ path: "/products",
131
+ hash: "#a?a#b"
132
+ },
133
+ base: "http://example.com",
134
+ expected: "http://example.com/products#a?a#b",
135
+ description: "should handle special hash characters correctly"
136
+ },
137
+ {
138
+ input: {
139
+ path: "/products",
140
+ query: {
141
+ id: null,
142
+ category: void 0,
143
+ symbol: Symbol(),
144
+ fn: async () => "",
145
+ obj: { a: 10 },
146
+ big: 12345678901234567891234567890123456789n,
147
+ a: Number.NaN,
148
+ b: "",
149
+ c: "0",
150
+ d: 0,
151
+ e: 1
152
+ }
153
+ },
154
+ base: "http://example.com",
155
+ expected: `http://example.com/products?symbol=Symbol()&fn=${String(
156
+ async () => ""
157
+ )}&obj=${String({})}&big=12345678901234567891234567890123456789&b&c=0&d=0&e=1`,
158
+ description: "should ignore null, undefined, and NaN query parameters"
159
+ },
160
+ {
161
+ input: { path: "/products", queryArray: { tag: [] } },
162
+ base: "http://example.com",
163
+ expected: "http://example.com/products",
164
+ description: "should handle empty queryArray"
165
+ },
166
+ {
167
+ input: {
168
+ path: "/products?id=path&a",
169
+ query: { id: "query" }
170
+ },
171
+ base: "http://example.com",
172
+ expected: "http://example.com/products?id=query&a",
173
+ description: "query value should override query parameter in path"
174
+ },
175
+ {
176
+ input: {
177
+ path: "/products?id=path&a",
178
+ query: { id: "query" },
179
+ queryArray: { id: ["queryArray"] }
180
+ },
181
+ base: "http://example.com",
182
+ expected: "http://example.com/products?id=queryArray&a",
183
+ description: "queryArray value should override query and path parameters"
184
+ },
185
+ {
186
+ input: {
187
+ path: "/products?id=path&a",
188
+ queryArray: { id: ["queryArray"] }
189
+ },
190
+ base: "http://example.com",
191
+ expected: "http://example.com/products?id=queryArray&a",
192
+ description: "queryArray value should override query parameter in path"
193
+ },
194
+ {
195
+ input: {
196
+ path: "?a&a=&a&a",
197
+ query: { a: "" },
198
+ queryArray: { a: ["", ""] }
199
+ },
200
+ base: "http://example.com",
201
+ expected: "http://example.com?a&a",
202
+ description: "should handle empty strings and duplicate query parameters correctly"
203
+ },
204
+ {
205
+ input: { path: "/products?id=123", url: "/products?id=456" },
206
+ base: "http://example.com",
207
+ expected: "http://example.com/products?id=123",
208
+ description: "path should take priority over url when both are present"
209
+ },
210
+ {
211
+ input: { url: "/products?id=456" },
212
+ base: "http://example.com",
213
+ expected: "http://example.com/products?id=456",
214
+ description: "url should be used when path is not present"
215
+ },
216
+ {
217
+ input: {},
218
+ base: "http://example.com",
219
+ expected: "http://example.com/",
220
+ description: "empty input object should default to base URL"
221
+ }
222
+ ];
223
+ testCases.forEach(({ input, base, expected, description }) => {
224
+ test(description, () => {
225
+ const result = parseLocation(input, new URL(base));
226
+ expect(result).toEqURL(expected);
227
+ });
228
+ });
229
+ });
230
+ describe("normalizeURL more", () => {
231
+ describe.for(
232
+ // biome-ignore format:
233
+ Object.entries({
234
+ "https://www.esmx.dev": {
235
+ "/": "https://www.esmx.dev/",
236
+ "/new": "https://www.esmx.dev/new",
237
+ "/new/": "https://www.esmx.dev/new/",
238
+ "/new/100": "https://www.esmx.dev/new/100",
239
+ "/new/100/": "https://www.esmx.dev/new/100/",
240
+ "..": "https://www.esmx.dev/",
241
+ "../": "https://www.esmx.dev/",
242
+ "../new": "https://www.esmx.dev/new",
243
+ "../new/": "https://www.esmx.dev/new/",
244
+ "../new/100": "https://www.esmx.dev/new/100",
245
+ "../new/100/": "https://www.esmx.dev/new/100/",
246
+ "": "https://www.esmx.dev/",
247
+ "new": "https://www.esmx.dev/new",
248
+ "new/": "https://www.esmx.dev/new/",
249
+ "new/100": "https://www.esmx.dev/new/100",
250
+ "new/100/": "https://www.esmx.dev/new/100/",
251
+ ".": "https://www.esmx.dev/",
252
+ "./": "https://www.esmx.dev/",
253
+ "./new": "https://www.esmx.dev/new",
254
+ "./new/": "https://www.esmx.dev/new/",
255
+ "./new/100": "https://www.esmx.dev/new/100",
256
+ "./new/100/": "https://www.esmx.dev/new/100/",
257
+ ".a": "https://www.esmx.dev/.a",
258
+ "..a": "https://www.esmx.dev/..a",
259
+ ".a/": "https://www.esmx.dev/.a/",
260
+ "..a/": "https://www.esmx.dev/..a/",
261
+ "new/../.": "https://www.esmx.dev/"
262
+ },
263
+ "https://www.esmx.dev/": {
264
+ "/": "https://www.esmx.dev/",
265
+ "/new": "https://www.esmx.dev/new",
266
+ "/new/": "https://www.esmx.dev/new/",
267
+ "/new/100": "https://www.esmx.dev/new/100",
268
+ "/new/100/": "https://www.esmx.dev/new/100/",
269
+ "..": "https://www.esmx.dev/",
270
+ "../": "https://www.esmx.dev/",
271
+ "../new": "https://www.esmx.dev/new",
272
+ "../new/": "https://www.esmx.dev/new/",
273
+ "../new/100": "https://www.esmx.dev/new/100",
274
+ "../new/100/": "https://www.esmx.dev/new/100/",
275
+ "": "https://www.esmx.dev/",
276
+ "new": "https://www.esmx.dev/new",
277
+ "new/": "https://www.esmx.dev/new/",
278
+ "new/100": "https://www.esmx.dev/new/100",
279
+ "new/100/": "https://www.esmx.dev/new/100/",
280
+ ".": "https://www.esmx.dev/",
281
+ "./": "https://www.esmx.dev/",
282
+ "./new": "https://www.esmx.dev/new",
283
+ "./new/": "https://www.esmx.dev/new/",
284
+ "./new/100": "https://www.esmx.dev/new/100",
285
+ "./new/100/": "https://www.esmx.dev/new/100/",
286
+ ".a": "https://www.esmx.dev/.a",
287
+ "..a": "https://www.esmx.dev/..a",
288
+ ".a/": "https://www.esmx.dev/.a/",
289
+ "..a/": "https://www.esmx.dev/..a/",
290
+ "new/../.": "https://www.esmx.dev/"
291
+ },
292
+ "https://www.esmx.dev/a/b/c": {
293
+ "/": "https://www.esmx.dev/a/b/",
294
+ "/new": "https://www.esmx.dev/a/b/new",
295
+ "/new/": "https://www.esmx.dev/a/b/new/",
296
+ "/new/100": "https://www.esmx.dev/a/b/new/100",
297
+ "/new/100/": "https://www.esmx.dev/a/b/new/100/",
298
+ "..": "https://www.esmx.dev/a/",
299
+ "../": "https://www.esmx.dev/a/",
300
+ "../new": "https://www.esmx.dev/a/new",
301
+ "../new/": "https://www.esmx.dev/a/new/",
302
+ "../new/100": "https://www.esmx.dev/a/new/100",
303
+ "../new/100/": "https://www.esmx.dev/a/new/100/",
304
+ "": "https://www.esmx.dev/a/b/c",
305
+ "new": "https://www.esmx.dev/a/b/new",
306
+ "new/": "https://www.esmx.dev/a/b/new/",
307
+ "new/100": "https://www.esmx.dev/a/b/new/100",
308
+ "new/100/": "https://www.esmx.dev/a/b/new/100/",
309
+ ".": "https://www.esmx.dev/a/b/",
310
+ "./": "https://www.esmx.dev/a/b/",
311
+ "./new": "https://www.esmx.dev/a/b/new",
312
+ "./new/": "https://www.esmx.dev/a/b/new/",
313
+ "./new/100": "https://www.esmx.dev/a/b/new/100",
314
+ "./new/100/": "https://www.esmx.dev/a/b/new/100/",
315
+ ".a": "https://www.esmx.dev/a/b/.a",
316
+ "..a": "https://www.esmx.dev/a/b/..a",
317
+ ".a/": "https://www.esmx.dev/a/b/.a/",
318
+ "..a/": "https://www.esmx.dev/a/b/..a/",
319
+ "new/../.": "https://www.esmx.dev/a/b/",
320
+ "new/.././a/../../x/": "https://www.esmx.dev/a/x/"
321
+ },
322
+ "https://www.esmx.dev/a/b/c/": {
323
+ "/": "https://www.esmx.dev/a/b/c/",
324
+ "/new": "https://www.esmx.dev/a/b/c/new",
325
+ "/new/": "https://www.esmx.dev/a/b/c/new/",
326
+ "/new/100": "https://www.esmx.dev/a/b/c/new/100",
327
+ "/new/100/": "https://www.esmx.dev/a/b/c/new/100/",
328
+ "..": "https://www.esmx.dev/a/b/",
329
+ "../": "https://www.esmx.dev/a/b/",
330
+ "../new": "https://www.esmx.dev/a/b/new",
331
+ "../new/": "https://www.esmx.dev/a/b/new/",
332
+ "../new/100": "https://www.esmx.dev/a/b/new/100",
333
+ "../new/100/": "https://www.esmx.dev/a/b/new/100/",
334
+ "": "https://www.esmx.dev/a/b/c/",
335
+ "new": "https://www.esmx.dev/a/b/c/new",
336
+ "new/": "https://www.esmx.dev/a/b/c/new/",
337
+ "new/100": "https://www.esmx.dev/a/b/c/new/100",
338
+ "new/100/": "https://www.esmx.dev/a/b/c/new/100/",
339
+ ".": "https://www.esmx.dev/a/b/c/",
340
+ "./": "https://www.esmx.dev/a/b/c/",
341
+ "./new": "https://www.esmx.dev/a/b/c/new",
342
+ "./new/": "https://www.esmx.dev/a/b/c/new/",
343
+ "./new/100": "https://www.esmx.dev/a/b/c/new/100",
344
+ "./new/100/": "https://www.esmx.dev/a/b/c/new/100/",
345
+ ".a": "https://www.esmx.dev/a/b/c/.a",
346
+ "..a": "https://www.esmx.dev/a/b/c/..a",
347
+ ".a/": "https://www.esmx.dev/a/b/c/.a/",
348
+ "..a/": "https://www.esmx.dev/a/b/c/..a/",
349
+ "new/.././": "https://www.esmx.dev/a/b/c/",
350
+ "new/.././a/../../x/": "https://www.esmx.dev/a/b/x/"
351
+ }
352
+ })
353
+ )(`base: $0`, ([base, cases]) => {
354
+ test.each(Object.entries(cases))(`input: $0`, (input, expected) => {
355
+ const url = normalizeURL(input, new URL(base));
356
+ expect(url).toEqURL(expected);
357
+ const pathSuffix = "?a&b=1&c=2&a=&a=4&base=10#hash";
358
+ const urlWithSuffix = normalizeURL(
359
+ input + pathSuffix,
360
+ new URL(base)
361
+ );
362
+ expect(urlWithSuffix).toEqURL(expected + pathSuffix);
363
+ const urlWithBaseSuffix = normalizeURL(
364
+ input + pathSuffix,
365
+ new URL(base + "?base=base#base")
366
+ );
367
+ expect(urlWithBaseSuffix).toEqURL(expected + pathSuffix);
368
+ });
369
+ });
370
+ });
@@ -0,0 +1,3 @@
1
+ import type { RouteConfig, RouteMatcher } from './types';
2
+ export declare function createMatcher(routes: RouteConfig[]): RouteMatcher;
3
+ export declare function joinPathname(pathname: string, base?: string): string;
@@ -0,0 +1,44 @@
1
+ import { compile, match } from "path-to-regexp";
2
+ export function createMatcher(routes) {
3
+ const compiledRoutes = createRouteMatches(routes);
4
+ return (toURL, baseURL) => {
5
+ const matchPath = toURL.pathname.substring(baseURL.pathname.length - 1);
6
+ const matches = [];
7
+ const params = {};
8
+ const collectMatchingRoutes = (routes2) => {
9
+ for (const item of routes2) {
10
+ if (item.children.length && collectMatchingRoutes(item.children)) {
11
+ matches.unshift(item);
12
+ return true;
13
+ }
14
+ const result = item.match(matchPath);
15
+ if (result) {
16
+ matches.unshift(item);
17
+ if (typeof result === "object") {
18
+ Object.assign(params, result.params);
19
+ }
20
+ return true;
21
+ }
22
+ }
23
+ return false;
24
+ };
25
+ collectMatchingRoutes(compiledRoutes);
26
+ return { matches: Object.freeze(matches), params };
27
+ };
28
+ }
29
+ function createRouteMatches(routes, base = "") {
30
+ return routes.map((route) => {
31
+ const compilePath = joinPathname(route.path, base);
32
+ return {
33
+ ...route,
34
+ compilePath,
35
+ match: match(compilePath),
36
+ compile: compile(compilePath),
37
+ meta: route.meta || {},
38
+ children: Array.isArray(route.children) ? createRouteMatches(route.children, compilePath) : []
39
+ };
40
+ });
41
+ }
42
+ export function joinPathname(pathname, base = "") {
43
+ return "/" + `${base}/${pathname}`.split("/").filter(Boolean).join("/");
44
+ }