@esmx/router 3.0.0-rc.17 → 3.0.0-rc.19

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 (155) 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 -22
  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/utils/bom.d.ts +0 -5
  120. package/dist/utils/bom.mjs +0 -10
  121. package/dist/utils/encoding.d.ts +0 -48
  122. package/dist/utils/encoding.mjs +0 -44
  123. package/dist/utils/guards.d.ts +0 -9
  124. package/dist/utils/guards.mjs +0 -12
  125. package/dist/utils/index.d.ts +0 -7
  126. package/dist/utils/index.mjs +0 -27
  127. package/dist/utils/path.d.ts +0 -60
  128. package/dist/utils/path.mjs +0 -281
  129. package/dist/utils/path.spec.mjs +0 -27
  130. package/dist/utils/scroll.d.ts +0 -25
  131. package/dist/utils/scroll.mjs +0 -59
  132. package/dist/utils/utils.d.ts +0 -16
  133. package/dist/utils/utils.mjs +0 -11
  134. package/dist/utils/warn.d.ts +0 -2
  135. package/dist/utils/warn.mjs +0 -12
  136. package/src/history/abstract.ts +0 -149
  137. package/src/history/base.ts +0 -408
  138. package/src/history/html.ts +0 -228
  139. package/src/history/index.ts +0 -20
  140. package/src/matcher/create-matcher.spec.ts +0 -3
  141. package/src/matcher/create-matcher.ts +0 -293
  142. package/src/matcher/index.ts +0 -1
  143. package/src/task-pipe/index.ts +0 -1
  144. package/src/task-pipe/task.ts +0 -97
  145. package/src/utils/bom.ts +0 -14
  146. package/src/utils/encoding.ts +0 -153
  147. package/src/utils/guards.ts +0 -25
  148. package/src/utils/index.ts +0 -27
  149. package/src/utils/path.spec.ts +0 -32
  150. package/src/utils/path.ts +0 -417
  151. package/src/utils/scroll.ts +0 -120
  152. package/src/utils/utils.ts +0 -30
  153. package/src/utils/warn.ts +0 -13
  154. /package/dist/{matcher/create-matcher.spec.d.ts → index.test.d.ts} +0 -0
  155. /package/dist/{utils/path.spec.d.ts → matcher.test.d.ts} +0 -0
@@ -0,0 +1,359 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { Router } from "./router.mjs";
3
+ import { RouteType } from "./types.mjs";
4
+ describe("Router Window Navigation Tests", () => {
5
+ let router;
6
+ let mockApps;
7
+ beforeEach(() => {
8
+ vi.clearAllMocks();
9
+ mockApps = {
10
+ home: vi.fn(() => ({
11
+ mount: vi.fn(),
12
+ unmount: vi.fn(),
13
+ renderToString: vi.fn().mockResolvedValue("<div>Home</div>")
14
+ })),
15
+ about: vi.fn(() => ({
16
+ mount: vi.fn(),
17
+ unmount: vi.fn(),
18
+ renderToString: vi.fn().mockResolvedValue("<div>About</div>")
19
+ })),
20
+ user: vi.fn(() => ({
21
+ mount: vi.fn(),
22
+ unmount: vi.fn(),
23
+ renderToString: vi.fn().mockResolvedValue("<div>User</div>")
24
+ }))
25
+ };
26
+ router = new Router({
27
+ routes: [
28
+ { path: "/", app: "home" },
29
+ { path: "/about", app: "about" },
30
+ { path: "/user/:id", app: "user" }
31
+ ],
32
+ apps: mockApps
33
+ });
34
+ });
35
+ function createWindowNavigationTests(methodName, expectedIsPush) {
36
+ describe(`\u{1FA9F} ${methodName} Core Functionality Tests`, () => {
37
+ it(`should support using current route path`, async () => {
38
+ await router.push("/about");
39
+ const result = await router[methodName]("/about");
40
+ expect(result.type).toBe(RouteType[methodName]);
41
+ expect(result.path).toBe("/about");
42
+ expect(result.isPush).toBe(expectedIsPush);
43
+ expect(result.handle).not.toBeNull();
44
+ });
45
+ it(`should support string path parameters`, async () => {
46
+ const result = await router[methodName]("/user/123");
47
+ expect(result.type).toBe(RouteType[methodName]);
48
+ expect(result.path).toBe("/user/123");
49
+ expect(result.params.id).toBe("123");
50
+ expect(result.isPush).toBe(expectedIsPush);
51
+ expect(result.handle).not.toBeNull();
52
+ });
53
+ it(`should support object parameters`, async () => {
54
+ const result = await router[methodName]({
55
+ path: "/user/456",
56
+ query: { tab: "profile" },
57
+ hash: "section1"
58
+ });
59
+ expect(result.type).toBe(RouteType[methodName]);
60
+ expect(result.path).toBe("/user/456");
61
+ expect(result.params.id).toBe("456");
62
+ expect(result.query.tab).toBe("profile");
63
+ expect(result.url.hash).toBe("#section1");
64
+ expect(result.isPush).toBe(expectedIsPush);
65
+ expect(result.handle).not.toBeNull();
66
+ });
67
+ it(`should correctly handle complete URLs`, async () => {
68
+ const result = await router[methodName](
69
+ "https://example.com/user/789?sort=name#top"
70
+ );
71
+ expect(result.type).toBe(RouteType[methodName]);
72
+ expect(result.url.href).toBe(
73
+ "https://example.com/user/789?sort=name#top"
74
+ );
75
+ expect(result.isPush).toBe(expectedIsPush);
76
+ expect(result.handle).not.toBeNull();
77
+ });
78
+ });
79
+ describe(`\u{1F3AF} ${methodName} Specific Behavior Tests`, () => {
80
+ it(`should set correct isPush flag`, async () => {
81
+ const result = await router[methodName]("/about");
82
+ expect(result.isPush).toBe(expectedIsPush);
83
+ expect(result.type).toBe(RouteType[methodName]);
84
+ });
85
+ it(`should call location handler`, async () => {
86
+ let locationCalled = false;
87
+ let receivedRoute = null;
88
+ const windowRouter = new Router({
89
+ routes: [{ path: "/", app: "home" }],
90
+ apps: mockApps,
91
+ fallback: (to, from) => {
92
+ locationCalled = true;
93
+ receivedRoute = to;
94
+ return { windowNavigation: true };
95
+ }
96
+ });
97
+ await windowRouter.push("/");
98
+ const result = await windowRouter[methodName]("/about");
99
+ expect(locationCalled).toBe(true);
100
+ expect(receivedRoute.isPush).toBe(expectedIsPush);
101
+ expect(result.handleResult).toEqual({ windowNavigation: true });
102
+ windowRouter.destroy();
103
+ });
104
+ it(`should not update current route state`, async () => {
105
+ await router.push("/about");
106
+ const beforeRoute = router.route;
107
+ await router[methodName]("/user/123");
108
+ const afterRoute = router.route;
109
+ expect(afterRoute.path).toBe(beforeRoute.path);
110
+ expect(afterRoute.url.href).toBe(beforeRoute.url.href);
111
+ });
112
+ it(`should not trigger MicroApp update`, async () => {
113
+ const updateSpy = vi.spyOn(router.microApp, "_update");
114
+ await router[methodName]("/user/123");
115
+ expect(updateSpy).not.toHaveBeenCalled();
116
+ });
117
+ });
118
+ describe(`\u{1F6E1}\uFE0F ${methodName} Route Guards Tests`, () => {
119
+ it(`should execute beforeEach guards`, async () => {
120
+ let guardCalled = false;
121
+ const unregister = router.beforeEach(async (to, from) => {
122
+ guardCalled = true;
123
+ expect(to.isPush).toBe(expectedIsPush);
124
+ });
125
+ await router[methodName]("/about");
126
+ expect(guardCalled).toBe(true);
127
+ unregister();
128
+ });
129
+ it(`should abort navigation when guard returns false`, async () => {
130
+ const unregister = router.beforeEach((to, from) => {
131
+ return false;
132
+ });
133
+ await expect(router[methodName]("/about")).rejects.toThrow(
134
+ "Navigation was aborted"
135
+ );
136
+ unregister();
137
+ });
138
+ it(`should support guard redirects`, async () => {
139
+ const unregister = router.beforeEach(async (to) => {
140
+ if (to.path === "/about") {
141
+ return "/user/redirect";
142
+ }
143
+ });
144
+ const result = await router[methodName]("/about");
145
+ expect(result.path).toBe("/user/redirect");
146
+ expect(result.params.id).toBe("redirect");
147
+ unregister();
148
+ });
149
+ it(`should execute afterEach guards`, async () => {
150
+ let guardCalled = false;
151
+ const unregister = router.afterEach((to, from) => {
152
+ guardCalled = true;
153
+ expect(to.isPush).toBe(expectedIsPush);
154
+ });
155
+ await router[methodName]("/about");
156
+ expect(guardCalled).toBe(true);
157
+ unregister();
158
+ });
159
+ });
160
+ describe(`\u{1F3AD} ${methodName} Edge Cases Tests`, () => {
161
+ it(`should handle non-existent routes`, async () => {
162
+ const result = await router[methodName]("/nonexistent");
163
+ expect(result.handle).not.toBeNull();
164
+ expect(result.matched.length).toBe(0);
165
+ expect(result.isPush).toBe(expectedIsPush);
166
+ });
167
+ it(`should handle empty string path`, async () => {
168
+ const result = await router[methodName]("");
169
+ expect(result.handle).not.toBeNull();
170
+ expect(result.isPush).toBe(expectedIsPush);
171
+ });
172
+ it(`should handle special characters`, async () => {
173
+ const result = await router[methodName](
174
+ "/user/\u6D4B\u8BD5\u7528\u6237?name=\u5F20\u4E09&age=25#\u4E2A\u4EBA\u4FE1\u606F"
175
+ );
176
+ expect(result.handle).not.toBeNull();
177
+ expect(result.isPush).toBe(expectedIsPush);
178
+ expect(result.url.pathname).toContain(
179
+ "%E6%B5%8B%E8%AF%95%E7%94%A8%E6%88%B7"
180
+ );
181
+ });
182
+ });
183
+ describe(`\u26A1 ${methodName} Task Cancellation and Concurrency Control`, () => {
184
+ it(`should support concurrent calls`, async () => {
185
+ const promises = [
186
+ router[methodName]("/user/1").catch((err) => err),
187
+ router[methodName]("/user/2").catch((err) => err),
188
+ router[methodName]("/user/3").catch((err) => err)
189
+ ];
190
+ const results = await Promise.all(promises);
191
+ const successResults = results.filter(
192
+ (r) => !(r instanceof Error) && r.handle !== null
193
+ );
194
+ const errorResults = results.filter((r) => r instanceof Error);
195
+ expect(successResults.length).toBeGreaterThan(0);
196
+ expect(successResults.length + errorResults.length).toBe(3);
197
+ successResults.forEach((result) => {
198
+ expect(result.isPush).toBe(expectedIsPush);
199
+ });
200
+ });
201
+ it(`should correctly handle rapid consecutive calls`, async () => {
202
+ const results = [];
203
+ for (let i = 0; i < 5; i++) {
204
+ results.push(await router[methodName](`/user/${i}`));
205
+ }
206
+ results.forEach((result, index) => {
207
+ expect(result.handle).not.toBeNull();
208
+ expect(result.params.id).toBe(String(index));
209
+ expect(result.isPush).toBe(expectedIsPush);
210
+ });
211
+ });
212
+ });
213
+ describe(`\u274C ${methodName} Error Handling`, () => {
214
+ it(`should handle exceptions in guards`, async () => {
215
+ const unregister = router.beforeEach(async () => {
216
+ throw new Error("Guard error");
217
+ });
218
+ await expect(router[methodName]("/about")).rejects.toThrow();
219
+ unregister();
220
+ });
221
+ it(`should handle location handler exceptions`, async () => {
222
+ const windowRouter = new Router({
223
+ routes: [{ path: "/", app: "home" }],
224
+ apps: mockApps,
225
+ fallback: () => {
226
+ throw new Error("Location handler error");
227
+ }
228
+ });
229
+ await windowRouter.push("/");
230
+ await expect(
231
+ windowRouter[methodName]("/about")
232
+ ).rejects.toThrow();
233
+ windowRouter.destroy();
234
+ });
235
+ });
236
+ describe(`\u{1F9E9} ${methodName} Async Component Handling`, () => {
237
+ it(`should correctly handle async components`, async () => {
238
+ const asyncRouter = new Router({
239
+ routes: [
240
+ {
241
+ path: "/async",
242
+ app: "home",
243
+ asyncComponent: async () => {
244
+ await new Promise(
245
+ (resolve) => setTimeout(resolve, 10)
246
+ );
247
+ return () => "AsyncComponent";
248
+ }
249
+ }
250
+ ],
251
+ apps: mockApps,
252
+ fallback: (to, from) => {
253
+ return { windowNavigation: true };
254
+ }
255
+ });
256
+ const result = await asyncRouter[methodName]("/async");
257
+ expect(result.handle).not.toBeNull();
258
+ expect(result.isPush).toBe(expectedIsPush);
259
+ expect(result.matched[0].component).toBeUndefined();
260
+ expect(result.matched[0].asyncComponent).toBeDefined();
261
+ expect(result.handleResult).toEqual({ windowNavigation: true });
262
+ asyncRouter.destroy();
263
+ });
264
+ it(`should handle async component loading failures`, async () => {
265
+ const asyncRouter = new Router({
266
+ routes: [
267
+ {
268
+ path: "/async-error",
269
+ app: "home",
270
+ asyncComponent: async () => {
271
+ throw new Error("Component load failed");
272
+ }
273
+ }
274
+ ],
275
+ apps: mockApps,
276
+ fallback: (to, from) => {
277
+ return { fallbackHandled: true };
278
+ }
279
+ });
280
+ const result = await asyncRouter[methodName]("/async-error");
281
+ expect(result.handle).not.toBeNull();
282
+ expect(result.matched[0].component).toBeUndefined();
283
+ expect(result.matched[0].asyncComponent).toBeDefined();
284
+ expect(result.handleResult).toEqual({ fallbackHandled: true });
285
+ asyncRouter.destroy();
286
+ });
287
+ });
288
+ describe(`\u{1F527} ${methodName} Differences from Other Methods`, () => {
289
+ it(`should behave differently from push/replace methods`, async () => {
290
+ await router.push("/about");
291
+ const pushResult = await router.push("/user/123");
292
+ const windowResult = await router[methodName]("/user/456");
293
+ expect(router.route.path).toBe("/user/123");
294
+ expect(windowResult.isPush).toBe(expectedIsPush);
295
+ expect(windowResult.type).toBe(RouteType[methodName]);
296
+ expect(pushResult.type).toBe(RouteType.push);
297
+ expect(windowResult.type).toBe(RouteType[methodName]);
298
+ });
299
+ it(`should maintain consistency with resolve method in URL parsing`, async () => {
300
+ const resolvedRoute = router.resolve("/user/789");
301
+ const windowRoute = await router[methodName]("/user/789");
302
+ expect(windowRoute.url.href).toBe(resolvedRoute.url.href);
303
+ expect(windowRoute.params).toEqual(resolvedRoute.params);
304
+ expect(windowRoute.matched).toEqual(resolvedRoute.matched);
305
+ expect(windowRoute.type).toBe(RouteType[methodName]);
306
+ expect(resolvedRoute.type).toBe(RouteType.push);
307
+ expect(windowRoute.isPush).toBe(expectedIsPush);
308
+ expect(resolvedRoute.isPush).toBe(true);
309
+ });
310
+ });
311
+ }
312
+ createWindowNavigationTests("pushWindow", true);
313
+ createWindowNavigationTests("replaceWindow", false);
314
+ describe("\u{1F504} pushWindow and replaceWindow Comparison Tests", () => {
315
+ it("the only difference between the two methods should be the isPush flag", async () => {
316
+ const pushResult = await router.pushWindow("/user/123");
317
+ const replaceResult = await router.replaceWindow("/user/123");
318
+ expect(pushResult.url.href).toBe(replaceResult.url.href);
319
+ expect(pushResult.params).toEqual(replaceResult.params);
320
+ expect(pushResult.query).toEqual(replaceResult.query);
321
+ expect(pushResult.url.hash).toBe(replaceResult.url.hash);
322
+ expect(pushResult.matched).toEqual(replaceResult.matched);
323
+ expect(pushResult.isPush).toBe(true);
324
+ expect(replaceResult.isPush).toBe(false);
325
+ expect(pushResult.type).toBe(RouteType.pushWindow);
326
+ expect(replaceResult.type).toBe(RouteType.replaceWindow);
327
+ });
328
+ it("both methods should call the same location handler", async () => {
329
+ const locationCalls = [];
330
+ const windowRouter = new Router({
331
+ routes: [{ path: "/", app: "home" }],
332
+ apps: mockApps,
333
+ fallback: (to, from) => {
334
+ locationCalls.push({
335
+ method: to.type,
336
+ isPush: to.isPush,
337
+ path: to.path
338
+ });
339
+ return { called: true };
340
+ }
341
+ });
342
+ await windowRouter.push("/");
343
+ await windowRouter.pushWindow("/test");
344
+ await windowRouter.replaceWindow("/test");
345
+ expect(locationCalls).toHaveLength(2);
346
+ expect(locationCalls[0]).toEqual({
347
+ method: "pushWindow",
348
+ isPush: true,
349
+ path: "/test"
350
+ });
351
+ expect(locationCalls[1]).toEqual({
352
+ method: "replaceWindow",
353
+ isPush: false,
354
+ path: "/test"
355
+ });
356
+ windowRouter.destroy();
357
+ });
358
+ });
359
+ });
package/dist/router.d.ts CHANGED
@@ -1,111 +1,118 @@
1
- import { type HistoryState, type NavigationGuard, type NavigationGuardAfter, type RegisteredConfig, type RegisteredConfigMap, type Route, type RouteRecord, type RouterBase, type RouterHistory, type RouterInitOptions, type RouterInstance, type RouterMatcher, RouterMode, type RouterOptions, type RouterRawLocation, type RouterScrollBehavior } from './types';
2
- /**
3
- * 路由类
4
- */
5
- export declare class Router implements RouterInstance {
6
- /**
7
- * 当前路由对象的上级路由对象
8
- */
9
- parent: RouterInstance | null;
10
- options: RouterOptions;
11
- /**
12
- * 路由固定前置路径
13
- * 需要注意的是如果使用函数返回 base,需要尽量保证相同的路径返回相同base
14
- */
15
- base: RouterBase;
16
- mode: RouterMode;
17
- matcher: RouterMatcher;
18
- history: RouterHistory;
19
- scrollBehavior: RouterScrollBehavior;
20
- route: Route;
1
+ import { MicroApp } from './micro-app';
2
+ import { Navigation } from './navigation';
3
+ import { Route } from './route';
4
+ import { RouteTransition } from './route-transition';
5
+ import { RouteType } from './types';
6
+ import type { RouteConfirmHook, RouteLayerResult, RouteLocationInput, RouteMatchType, RouteNotifyHook, RouterLinkProps, RouterLinkResolved, RouterOptions, RouterParsedOptions } from './types';
7
+ export declare class Router {
8
+ readonly options: RouterOptions;
9
+ readonly parsedOptions: RouterParsedOptions;
10
+ readonly isLayer: boolean;
11
+ readonly navigation: Navigation;
12
+ readonly microApp: MicroApp;
13
+ readonly transition: RouteTransition;
14
+ get route(): Route;
15
+ get root(): string | HTMLElement;
16
+ get req(): import("http").IncomingMessage | null;
17
+ get res(): import("http").ServerResponse<import("http").IncomingMessage> | null;
21
18
  constructor(options: RouterOptions);
22
- updateRoute(route: RouteRecord): void;
23
- protected applyRoute(route: RouteRecord): void;
24
- resolve(location: RouterRawLocation): RouteRecord;
19
+ push(toInput: RouteLocationInput): Promise<Route>;
20
+ replace(toInput: RouteLocationInput): Promise<Route>;
21
+ pushWindow(toInput: RouteLocationInput): Promise<Route>;
22
+ replaceWindow(toInput: RouteLocationInput): Promise<Route>;
23
+ restartApp(toInput?: RouteLocationInput): Promise<Route>;
24
+ back(): Promise<Route | null>;
25
+ go(index: number): Promise<Route | null>;
26
+ forward(): Promise<Route | null>;
25
27
  /**
26
- * 新增单个路由匹配规则
28
+ * Parse route location without performing actual navigation
29
+ *
30
+ * This method is used to parse route configuration and return the corresponding route object,
31
+ * but does not trigger actual page navigation. It is mainly used for the following scenarios:
32
+ * - Generate link URLs without jumping
33
+ * - Pre-check route matching
34
+ * - Get route parameters, meta information, etc.
35
+ * - Test the validity of route configuration
36
+ *
37
+ * @param toInput Target route location, can be a string path or route configuration object
38
+ * @returns Parsed route object containing complete route information
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * // Parse string path
43
+ * const route = router.resolve('/user/123');
44
+ * const url = route.url.href; // Get complete URL
45
+ *
46
+ * // Parse named route
47
+ * const userRoute = router.resolve({
48
+ * name: 'user',
49
+ * params: { id: '123' }
50
+ * });
51
+ * console.log(userRoute.params.id); // '123'
52
+ *
53
+ * // Check route validity
54
+ * const testRoute = router.resolve('/some/path');
55
+ * if (testRoute.matched.length > 0) {
56
+ * // Route matched successfully
57
+ * }
58
+ * ```
27
59
  */
60
+ resolve(toInput: RouteLocationInput, toType?: RouteType): Route;
28
61
  /**
29
- * 新增多个路由匹配规则
62
+ * Check if the route matches the current route
63
+ *
64
+ * @param targetRoute Target route object to compare
65
+ * @param matchType Match type
66
+ * - 'route': Route-level matching, compare if route configurations are the same
67
+ * - 'exact': Exact matching, compare if paths are completely the same
68
+ * - 'include': Include matching, check if current path contains target path
69
+ * @returns Whether it matches
30
70
  */
31
- init(options?: RouterInitOptions): Promise<void>;
71
+ isRouteMatched(targetRoute: Route, matchType?: RouteMatchType): boolean;
32
72
  /**
33
- * 卸载方法
73
+ * Resolve router link configuration and return complete link data
74
+ *
75
+ * This method analyzes router link properties and returns a comprehensive
76
+ * link resolution result including route information, navigation functions,
77
+ * HTML attributes, and event handlers. It's primarily used for:
78
+ * - Framework-agnostic link component implementation
79
+ * - Generating link attributes and navigation handlers
80
+ * - Computing active states and CSS classes
81
+ * - Creating event handlers for different frameworks
82
+ *
83
+ * @param props Router link configuration properties
84
+ * @returns Complete link resolution result with all necessary data
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * // Basic link resolution
89
+ * const linkData = router.resolveLink({
90
+ * to: '/user/123',
91
+ * type: 'push'
92
+ * });
93
+ *
94
+ * // Access resolved data
95
+ * console.log(linkData.route.path); // '/user/123'
96
+ * console.log(linkData.attributes.href); // Full href URL
97
+ * console.log(linkData.isActive); // Active state
98
+ *
99
+ * // Use navigation function
100
+ * linkData.navigate(); // Programmatic navigation
101
+ *
102
+ * // Get event handlers for React
103
+ * const handlers = linkData.getEventHandlers(name => `on${name.charAt(0).toUpperCase() + name.slice(1)}`);
104
+ * // handlers.onClick for React
105
+ * ```
34
106
  */
35
- destroy(): Promise<void>;
36
- registeredConfigMap: RegisteredConfigMap;
37
- register(name: string, config: (router: RouterInstance) => RegisteredConfig): void;
38
- readonly guards: {
39
- beforeEach: NavigationGuard[];
40
- afterEach: NavigationGuardAfter[];
41
- };
42
- beforeEach(guard: NavigationGuard): void;
43
- unBindBeforeEach(guard: NavigationGuard): void;
44
- afterEach(guard: NavigationGuardAfter): void;
45
- unBindAfterEach(guard: NavigationGuardAfter): void;
46
- push(location: RouterRawLocation): Promise<void>;
47
- replace(location: RouterRawLocation): Promise<void>;
48
- /**
49
- * 当前路由弹层id,用于区分不同的路由弹层
50
- */
51
- layerId: number;
52
- /**
53
- * 路由弹层配置
54
- * key为路由弹层id
55
- */
56
- layerConfigList: Array<{
57
- /**
58
- * 路由弹层id
59
- */
60
- id: number;
61
- /**
62
- * 路由弹层深度
63
- */
64
- depth: number;
65
- }>;
66
- /**
67
- * 路由弹层id与路由实例的map
68
- */
69
- layerMap: Record<number, {
70
- router: RouterInstance;
71
- config: RegisteredConfig;
72
- destroyed: boolean;
107
+ resolveLink(props: RouterLinkProps): RouterLinkResolved;
108
+ createLayer(toInput: RouteLocationInput): Promise<{
109
+ promise: Promise<RouteLayerResult>;
110
+ router: Router;
73
111
  }>;
74
- /**
75
- * 路由是否冻结
76
- */
77
- isFrozen: boolean;
78
- /**
79
- * 路由冻结方法
80
- */
81
- freeze(): void;
82
- /**
83
- * 路由解冻方法
84
- */
85
- unfreeze(): void;
86
- /**
87
- * 打开路由弹层方法,会创建新的路由实例并调用注册的 register 方法
88
- * 服务端会使用 push 作为替代
89
- */
90
- pushLayer(location: RouterRawLocation): Promise<void>;
91
- /**
92
- * 更新路由弹层方法
93
- * @param state 参数为history.state
94
- * @description 没有传入 state 时使用当前配置更新 history.state,传入了 state 时使用传入的 state 更新当前配置
95
- */
96
- checkLayerState(state: HistoryState): boolean;
97
- updateLayerState(route: RouteRecord): void;
98
- /**
99
- * 新开浏览器窗口的方法,在服务端会调用 push 作为替代
100
- */
101
- pushWindow(location: RouterRawLocation): void;
102
- /**
103
- * 替换当前浏览器窗口的方法,在服务端会调用 replace 作为替代
104
- */
105
- replaceWindow(location: RouterRawLocation): void;
106
- go(delta?: number): void;
107
- forward(): void;
108
- back(): void;
109
- getRoutes(): any;
112
+ pushLayer(toInput: RouteLocationInput): Promise<RouteLayerResult>;
113
+ closeLayer(data?: any): void;
114
+ renderToString(throwError?: boolean): Promise<string | null>;
115
+ beforeEach(guard: RouteConfirmHook): () => void;
116
+ afterEach(guard: RouteNotifyHook): () => void;
117
+ destroy(): void;
110
118
  }
111
- export declare function createRouter(options: RouterOptions): RouterInstance;