@esmx/router 3.0.0-rc.23 → 3.0.0-rc.25
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/error.mjs +14 -11
- package/dist/increment-id.mjs +6 -1
- package/dist/location.mjs +3 -2
- package/dist/location.test.mjs +7 -7
- package/dist/matcher.mjs +1 -1
- package/dist/matcher.test.mjs +5 -5
- package/dist/micro-app.mjs +9 -4
- package/dist/navigation.mjs +20 -16
- package/dist/options.mjs +13 -12
- package/dist/route-task.mjs +6 -1
- package/dist/route-transition.mjs +17 -13
- package/dist/route-transition.test.mjs +1 -1
- package/dist/route.mjs +31 -28
- package/dist/route.test.mjs +4 -4
- package/dist/router-back.test.mjs +1 -1
- package/dist/router-forward.test.mjs +1 -1
- package/dist/router-restart-app.dom.test.mjs +6 -6
- package/dist/router-window-navigation.test.mjs +32 -32
- package/dist/router.mjs +35 -29
- package/dist/util.test.mjs +18 -18
- package/package.json +8 -8
- package/src/route-transition.ts +1 -1
- package/src/router.ts +1 -1
package/dist/error.mjs
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
export class RouteError extends Error {
|
|
2
|
-
code;
|
|
3
|
-
to;
|
|
4
|
-
from;
|
|
5
5
|
constructor(message, code, to, from = null) {
|
|
6
6
|
super(message);
|
|
7
|
+
__publicField(this, "code");
|
|
8
|
+
__publicField(this, "to");
|
|
9
|
+
__publicField(this, "from");
|
|
7
10
|
this.name = "RouteError";
|
|
8
11
|
this.code = code;
|
|
9
12
|
this.to = to;
|
|
@@ -11,39 +14,39 @@ export class RouteError extends Error {
|
|
|
11
14
|
}
|
|
12
15
|
}
|
|
13
16
|
export class RouteTaskCancelledError extends RouteError {
|
|
14
|
-
taskName;
|
|
15
17
|
constructor(taskName, to, from = null) {
|
|
16
18
|
super(
|
|
17
|
-
|
|
19
|
+
'Route task "'.concat(taskName, '" was cancelled'),
|
|
18
20
|
"ROUTE_TASK_CANCELLED",
|
|
19
21
|
to,
|
|
20
22
|
from
|
|
21
23
|
);
|
|
24
|
+
__publicField(this, "taskName");
|
|
22
25
|
this.name = "RouteTaskCancelledError";
|
|
23
26
|
this.taskName = taskName;
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
export class RouteTaskExecutionError extends RouteError {
|
|
27
|
-
taskName;
|
|
28
|
-
originalError;
|
|
29
30
|
constructor(taskName, to, from = null, originalError) {
|
|
30
31
|
const error = originalError instanceof Error ? originalError : new Error(String(originalError));
|
|
31
|
-
const message =
|
|
32
|
+
const message = 'Route task "'.concat(taskName, '" failed').concat(error.message ? ": ".concat(error.message) : "");
|
|
32
33
|
super(message, "ROUTE_TASK_EXECUTION_ERROR", to, from);
|
|
34
|
+
__publicField(this, "taskName");
|
|
35
|
+
__publicField(this, "originalError");
|
|
33
36
|
this.name = "RouteTaskExecutionError";
|
|
34
37
|
this.taskName = taskName;
|
|
35
38
|
this.originalError = error;
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
export class RouteNavigationAbortedError extends RouteError {
|
|
39
|
-
taskName;
|
|
40
42
|
constructor(taskName, to, from = null) {
|
|
41
43
|
super(
|
|
42
|
-
|
|
44
|
+
'Navigation was aborted by task "'.concat(taskName, '"'),
|
|
43
45
|
"ROUTE_NAVIGATION_ABORTED",
|
|
44
46
|
to,
|
|
45
47
|
from
|
|
46
48
|
);
|
|
49
|
+
__publicField(this, "taskName");
|
|
47
50
|
this.name = "RouteNavigationAbortedError";
|
|
48
51
|
this.taskName = taskName;
|
|
49
52
|
}
|
|
@@ -51,7 +54,7 @@ export class RouteNavigationAbortedError extends RouteError {
|
|
|
51
54
|
export class RouteSelfRedirectionError extends RouteError {
|
|
52
55
|
constructor(fullPath, to, from = null) {
|
|
53
56
|
super(
|
|
54
|
-
|
|
57
|
+
'Detected a self-redirection to "'.concat(fullPath, '". Aborting navigation.'),
|
|
55
58
|
"ROUTE_SELF_REDIRECTION",
|
|
56
59
|
to,
|
|
57
60
|
from
|
package/dist/increment-id.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
export class IncrementId {
|
|
2
|
-
|
|
5
|
+
constructor() {
|
|
6
|
+
__publicField(this, "value", 0);
|
|
7
|
+
}
|
|
3
8
|
equal(id) {
|
|
4
9
|
return this.value === id;
|
|
5
10
|
}
|
package/dist/location.mjs
CHANGED
|
@@ -4,7 +4,7 @@ export function normalizeURL(url, base) {
|
|
|
4
4
|
return url;
|
|
5
5
|
}
|
|
6
6
|
if (url.startsWith("//")) {
|
|
7
|
-
return new URL(
|
|
7
|
+
return new URL("http:".concat(url));
|
|
8
8
|
}
|
|
9
9
|
if (url.startsWith("/")) {
|
|
10
10
|
const newBase = new URL(".", base);
|
|
@@ -19,10 +19,11 @@ export function normalizeURL(url, base) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
export function parseLocation(toInput, baseURL) {
|
|
22
|
+
var _a, _b;
|
|
22
23
|
if (typeof toInput === "string") {
|
|
23
24
|
return normalizeURL(toInput, baseURL);
|
|
24
25
|
}
|
|
25
|
-
const url = normalizeURL(toInput.path
|
|
26
|
+
const url = normalizeURL((_b = (_a = toInput.path) != null ? _a : toInput.url) != null ? _b : "", baseURL);
|
|
26
27
|
const searchParams = url.searchParams;
|
|
27
28
|
const mergedQuery = {};
|
|
28
29
|
if (toInput.query) {
|
package/dist/location.test.mjs
CHANGED
|
@@ -4,7 +4,7 @@ expect.extend({
|
|
|
4
4
|
toEqURL: (received, expected) => {
|
|
5
5
|
if (!(received instanceof URL)) {
|
|
6
6
|
return {
|
|
7
|
-
message: () =>
|
|
7
|
+
message: () => "expected ".concat(received, " to be an instance of URL"),
|
|
8
8
|
pass: false
|
|
9
9
|
};
|
|
10
10
|
}
|
|
@@ -13,7 +13,7 @@ expect.extend({
|
|
|
13
13
|
received.hash = received.hash;
|
|
14
14
|
expected.hash = expected.hash;
|
|
15
15
|
return {
|
|
16
|
-
message: () =>
|
|
16
|
+
message: () => "expected ".concat(received.href, " to be ").concat(expected.href),
|
|
17
17
|
pass: received.href === expected.href
|
|
18
18
|
};
|
|
19
19
|
}
|
|
@@ -143,7 +143,7 @@ describe("parseLocation", () => {
|
|
|
143
143
|
symbol: Symbol(),
|
|
144
144
|
fn: async () => "",
|
|
145
145
|
obj: { a: 10 },
|
|
146
|
-
big:
|
|
146
|
+
big: /* @__PURE__ */ BigInt("12345678901234567891234567890123456789"),
|
|
147
147
|
a: Number.NaN,
|
|
148
148
|
b: "",
|
|
149
149
|
c: "0",
|
|
@@ -152,9 +152,9 @@ describe("parseLocation", () => {
|
|
|
152
152
|
}
|
|
153
153
|
},
|
|
154
154
|
base: "http://example.com",
|
|
155
|
-
expected:
|
|
155
|
+
expected: "http://example.com/products?symbol=Symbol()&fn=".concat(String(
|
|
156
156
|
async () => ""
|
|
157
|
-
)
|
|
157
|
+
), "&obj=").concat(String({}), "&big=12345678901234567891234567890123456789&b&c=0&d=0&e=1"),
|
|
158
158
|
description: "should ignore null, undefined, and NaN query parameters"
|
|
159
159
|
},
|
|
160
160
|
{
|
|
@@ -350,8 +350,8 @@ describe("normalizeURL more", () => {
|
|
|
350
350
|
"new/.././a/../../x/": "https://www.esmx.dev/a/b/x/"
|
|
351
351
|
}
|
|
352
352
|
})
|
|
353
|
-
)(
|
|
354
|
-
test.each(Object.entries(cases))(
|
|
353
|
+
)("base: $0", ([base, cases]) => {
|
|
354
|
+
test.each(Object.entries(cases))("input: $0", (input, expected) => {
|
|
355
355
|
const url = normalizeURL(input, new URL(base));
|
|
356
356
|
expect(url).toEqURL(expected);
|
|
357
357
|
const pathSuffix = "?a&b=1&c=2&a=&a=4&base=10#hash";
|
package/dist/matcher.mjs
CHANGED
|
@@ -40,5 +40,5 @@ function createRouteMatches(routes, base = "") {
|
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
export function joinPathname(pathname, base = "") {
|
|
43
|
-
return "/" +
|
|
43
|
+
return "/" + "".concat(base, "/").concat(pathname).split("/").filter(Boolean).join("/");
|
|
44
44
|
}
|
package/dist/matcher.test.mjs
CHANGED
|
@@ -95,7 +95,7 @@ describe("joinPathname", () => {
|
|
|
95
95
|
const longSegment = "very-long-segment-name-that-could-cause-issues";
|
|
96
96
|
const base = Array(10).fill(longSegment).join("/");
|
|
97
97
|
const path = Array(10).fill(longSegment).join("/");
|
|
98
|
-
const expected =
|
|
98
|
+
const expected = "/".concat(base, "/").concat(path);
|
|
99
99
|
return [{ path, base, expected }];
|
|
100
100
|
}
|
|
101
101
|
},
|
|
@@ -203,7 +203,7 @@ describe("joinPathname", () => {
|
|
|
203
203
|
description: "Handling of special symbols and punctuation",
|
|
204
204
|
cases: [
|
|
205
205
|
{ path: "path!@#$%^&\\*()", base: "base!@#$%^&\\*()", expected: "/base!@#$%^&\\*()/path!@#$%^&\\*()" },
|
|
206
|
-
{ path:
|
|
206
|
+
{ path: "path\\[]{};:\"'<>\\?", base: "base\\[]{};:\"'<>\\?", expected: "/base\\[]{};:\"'<>\\?/path\\[]{};:\"'<>\\?" },
|
|
207
207
|
{ path: "path\\backslash", base: "base\\backslash\\", expected: "/base\\backslash\\/path\\backslash" }
|
|
208
208
|
]
|
|
209
209
|
},
|
|
@@ -501,7 +501,7 @@ describe("createMatcher", () => {
|
|
|
501
501
|
});
|
|
502
502
|
test("Chinese path parameters", () => {
|
|
503
503
|
const matcher = createMatcher([
|
|
504
|
-
{ path:
|
|
504
|
+
{ path: "/".concat(encodeURIComponent("\u5206\u7C7B"), "/:name") }
|
|
505
505
|
]);
|
|
506
506
|
const result = matcher(new URL("/\u5206\u7C7B/\u6280\u672F", BASE_URL), BASE_URL);
|
|
507
507
|
assert.equal(result.matches.length, 1);
|
|
@@ -568,7 +568,7 @@ describe("createMatcher", () => {
|
|
|
568
568
|
});
|
|
569
569
|
test.todo("Route matching performance verification", () => {
|
|
570
570
|
const routes = Array.from({ length: 1e3 }, (_, i) => ({
|
|
571
|
-
path:
|
|
571
|
+
path: "/route".concat(i, "/:id")
|
|
572
572
|
}));
|
|
573
573
|
routes.push({ path: "/target/:id" });
|
|
574
574
|
const matcher = createMatcher(routes);
|
|
@@ -939,7 +939,7 @@ describe("createMatcher", () => {
|
|
|
939
939
|
const routes = [];
|
|
940
940
|
for (let i = 0; i < 500; i++) {
|
|
941
941
|
routes.push({
|
|
942
|
-
path:
|
|
942
|
+
path: "/category".concat(i, "/:id"),
|
|
943
943
|
children: [
|
|
944
944
|
{
|
|
945
945
|
path: "subcategory/:subId"
|
package/dist/micro-app.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
import { isBrowser, isPlainObject } from "./util.mjs";
|
|
2
5
|
export function resolveRootElement(rootConfig) {
|
|
3
6
|
let el = null;
|
|
@@ -8,7 +11,7 @@ export function resolveRootElement(rootConfig) {
|
|
|
8
11
|
try {
|
|
9
12
|
el = document.querySelector(rootConfig);
|
|
10
13
|
} catch (error) {
|
|
11
|
-
console.warn(
|
|
14
|
+
console.warn("Failed to resolve root element: ".concat(rootConfig));
|
|
12
15
|
}
|
|
13
16
|
}
|
|
14
17
|
if (el === null) {
|
|
@@ -17,9 +20,11 @@ export function resolveRootElement(rootConfig) {
|
|
|
17
20
|
return el;
|
|
18
21
|
}
|
|
19
22
|
export class MicroApp {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
constructor() {
|
|
24
|
+
__publicField(this, "app", null);
|
|
25
|
+
__publicField(this, "root", null);
|
|
26
|
+
__publicField(this, "_factory", null);
|
|
27
|
+
}
|
|
23
28
|
_update(router, force = false) {
|
|
24
29
|
const factory = this._getNextFactory(router);
|
|
25
30
|
if (!force && factory === this._factory) {
|
package/dist/navigation.mjs
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
import { PAGE_ID } from "./increment-id.mjs";
|
|
2
5
|
import { RouterMode } from "./types.mjs";
|
|
3
6
|
const PAGE_ID_KEY = "__pageId__";
|
|
4
7
|
export class Navigation {
|
|
5
|
-
options;
|
|
6
|
-
_history;
|
|
7
|
-
_unSubscribePopState;
|
|
8
|
-
_promiseResolve = null;
|
|
9
8
|
constructor(options, onUpdated) {
|
|
9
|
+
__publicField(this, "options");
|
|
10
|
+
__publicField(this, "_history");
|
|
11
|
+
__publicField(this, "_unSubscribePopState");
|
|
12
|
+
__publicField(this, "_promiseResolve", null);
|
|
10
13
|
const history2 = options.mode === RouterMode.history ? window.history : new MemoryHistory();
|
|
11
14
|
const onPopStateChange = (url, state) => {
|
|
12
15
|
const dispatchEvent = this._promiseResolve || onUpdated;
|
|
@@ -77,34 +80,35 @@ export class Navigation {
|
|
|
77
80
|
}
|
|
78
81
|
}
|
|
79
82
|
export class MemoryHistory {
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
constructor() {
|
|
84
|
+
__publicField(this, "_entries", []);
|
|
85
|
+
__publicField(this, "_index", -1);
|
|
86
|
+
__publicField(this, "_popStateCbs", /* @__PURE__ */ new Set());
|
|
87
|
+
__publicField(this, "scrollRestoration", "auto");
|
|
88
|
+
this.pushState(null, "", "/");
|
|
89
|
+
}
|
|
82
90
|
get _curEntry() {
|
|
83
91
|
const idx = this._index;
|
|
84
92
|
if (idx < 0 || idx >= this.length) return null;
|
|
85
93
|
return this._entries[idx];
|
|
86
94
|
}
|
|
87
|
-
_popStateCbs = /* @__PURE__ */ new Set();
|
|
88
|
-
scrollRestoration = "auto";
|
|
89
95
|
// Return null when no current entry to align with browser history.state behavior
|
|
90
96
|
// Browser history.state can be null when no state was provided
|
|
91
97
|
get state() {
|
|
92
|
-
var _a;
|
|
93
|
-
return ((_a = this._curEntry) == null ? void 0 : _a.state)
|
|
98
|
+
var _a, _b;
|
|
99
|
+
return (_b = (_a = this._curEntry) == null ? void 0 : _a.state) != null ? _b : null;
|
|
94
100
|
}
|
|
95
101
|
get url() {
|
|
96
|
-
var _a;
|
|
97
|
-
return ((_a = this._curEntry) == null ? void 0 : _a.url)
|
|
98
|
-
}
|
|
99
|
-
constructor() {
|
|
100
|
-
this.pushState(null, "", "/");
|
|
102
|
+
var _a, _b;
|
|
103
|
+
return (_b = (_a = this._curEntry) == null ? void 0 : _a.url) != null ? _b : "";
|
|
101
104
|
}
|
|
102
105
|
get length() {
|
|
103
106
|
return this._entries.length;
|
|
104
107
|
}
|
|
105
108
|
pushState(data, unused, url) {
|
|
109
|
+
var _a;
|
|
106
110
|
this._entries.splice(this._index + 1);
|
|
107
|
-
this._entries.push({ state: data, url: (url == null ? void 0 : url.toString())
|
|
111
|
+
this._entries.push({ state: data, url: (_a = url == null ? void 0 : url.toString()) != null ? _a : this.url });
|
|
108
112
|
this._index = this._entries.length - 1;
|
|
109
113
|
}
|
|
110
114
|
replaceState(data, unused, url) {
|
package/dist/options.mjs
CHANGED
|
@@ -13,7 +13,7 @@ function getBaseUrl(options) {
|
|
|
13
13
|
const host = req.headers["x-forwarded-host"] || req.headers.host || req.headers["x-real-ip"] || "localhost";
|
|
14
14
|
const port = req.headers["x-forwarded-port"];
|
|
15
15
|
const path = req.url || "";
|
|
16
|
-
sourceUrl =
|
|
16
|
+
sourceUrl = "".concat(protocol, "://").concat(host).concat(port ? ":".concat(port) : "").concat(path);
|
|
17
17
|
} else {
|
|
18
18
|
sourceUrl = "https://www.esmnext.com/";
|
|
19
19
|
}
|
|
@@ -22,7 +22,7 @@ function getBaseUrl(options) {
|
|
|
22
22
|
base = new URL(".", sourceUrl);
|
|
23
23
|
} catch (e) {
|
|
24
24
|
console.warn(
|
|
25
|
-
|
|
25
|
+
"Failed to parse base URL '".concat(sourceUrl, "', using default: https://www.esmnext.com/")
|
|
26
26
|
);
|
|
27
27
|
base = new URL("https://www.esmnext.com/");
|
|
28
28
|
}
|
|
@@ -30,8 +30,9 @@ function getBaseUrl(options) {
|
|
|
30
30
|
return base;
|
|
31
31
|
}
|
|
32
32
|
export function parsedOptions(options = {}) {
|
|
33
|
+
var _a, _b, _c, _d, _e, _f;
|
|
33
34
|
const base = getBaseUrl(options);
|
|
34
|
-
const routes = Array.from(options.routes
|
|
35
|
+
const routes = Array.from((_a = options.routes) != null ? _a : []);
|
|
35
36
|
return Object.freeze({
|
|
36
37
|
rootStyle: options.rootStyle || false,
|
|
37
38
|
root: options.root || "",
|
|
@@ -41,16 +42,16 @@ export function parsedOptions(options = {}) {
|
|
|
41
42
|
layer: options.layer || false,
|
|
42
43
|
zIndex: options.zIndex || 1e4,
|
|
43
44
|
base,
|
|
44
|
-
mode: isBrowser ? options.mode
|
|
45
|
+
mode: isBrowser ? (_b = options.mode) != null ? _b : RouterMode.history : RouterMode.memory,
|
|
45
46
|
routes,
|
|
46
47
|
apps: typeof options.apps === "function" ? options.apps : Object.assign({}, options.apps),
|
|
47
48
|
matcher: createMatcher(routes),
|
|
48
|
-
normalizeURL: options.normalizeURL
|
|
49
|
-
fallback: options.fallback
|
|
50
|
-
handleBackBoundary: options.handleBackBoundary
|
|
51
|
-
}
|
|
52
|
-
handleLayerClose: options.handleLayerClose
|
|
53
|
-
}
|
|
49
|
+
normalizeURL: (_c = options.normalizeURL) != null ? _c : (url) => url,
|
|
50
|
+
fallback: (_d = options.fallback) != null ? _d : fallback,
|
|
51
|
+
handleBackBoundary: (_e = options.handleBackBoundary) != null ? _e : () => {
|
|
52
|
+
},
|
|
53
|
+
handleLayerClose: (_f = options.handleLayerClose) != null ? _f : () => {
|
|
54
|
+
}
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
57
|
export function fallback(to, from, router) {
|
|
@@ -62,7 +63,7 @@ export function fallback(to, from, router) {
|
|
|
62
63
|
statusCode = to.statusCode;
|
|
63
64
|
} else if (to.statusCode) {
|
|
64
65
|
console.warn(
|
|
65
|
-
|
|
66
|
+
"Invalid redirect status code ".concat(to.statusCode, ", using default 302")
|
|
66
67
|
);
|
|
67
68
|
}
|
|
68
69
|
router.res.statusCode = statusCode;
|
|
@@ -80,7 +81,7 @@ export function fallback(to, from, router) {
|
|
|
80
81
|
newWindow.opener = null;
|
|
81
82
|
}
|
|
82
83
|
return newWindow;
|
|
83
|
-
} catch {
|
|
84
|
+
} catch (e) {
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
location.href = href;
|
package/dist/route-task.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
import {
|
|
2
5
|
RouteNavigationAbortedError,
|
|
3
6
|
RouteSelfRedirectionError,
|
|
@@ -7,7 +10,9 @@ import {
|
|
|
7
10
|
import { Route } from "./route.mjs";
|
|
8
11
|
import { isUrlEqual, isValidConfirmHookResult } from "./util.mjs";
|
|
9
12
|
export class RouteTaskController {
|
|
10
|
-
|
|
13
|
+
constructor() {
|
|
14
|
+
__publicField(this, "_aborted", false);
|
|
15
|
+
}
|
|
11
16
|
/**
|
|
12
17
|
* Aborts the current task.
|
|
13
18
|
*/
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
import { Route } from "./route.mjs";
|
|
2
5
|
import {
|
|
3
6
|
RouteTaskController,
|
|
@@ -31,9 +34,9 @@ export const ROUTE_TRANSITION_HOOKS = {
|
|
|
31
34
|
try {
|
|
32
35
|
const result = await asyncComponent();
|
|
33
36
|
matched.component = result;
|
|
34
|
-
} catch {
|
|
37
|
+
} catch (e) {
|
|
35
38
|
throw new Error(
|
|
36
|
-
|
|
39
|
+
"Async component '".concat(matched.compilePath, "' is not a valid component.")
|
|
37
40
|
);
|
|
38
41
|
}
|
|
39
42
|
}
|
|
@@ -237,16 +240,16 @@ const ROUTE_TRANSITION_PIPELINE = {
|
|
|
237
240
|
]
|
|
238
241
|
};
|
|
239
242
|
export class RouteTransition {
|
|
240
|
-
router;
|
|
241
|
-
route = null;
|
|
242
|
-
// Task controller for the current transition.
|
|
243
|
-
_controller = null;
|
|
244
|
-
// Guard arrays, responsible for storing navigation guards.
|
|
245
|
-
guards = {
|
|
246
|
-
beforeEach: [],
|
|
247
|
-
afterEach: []
|
|
248
|
-
};
|
|
249
243
|
constructor(router) {
|
|
244
|
+
__publicField(this, "router");
|
|
245
|
+
__publicField(this, "route", null);
|
|
246
|
+
// Task controller for the current transition.
|
|
247
|
+
__publicField(this, "_controller", null);
|
|
248
|
+
// Guard arrays, responsible for storing navigation guards.
|
|
249
|
+
__publicField(this, "guards", {
|
|
250
|
+
beforeEach: [],
|
|
251
|
+
afterEach: []
|
|
252
|
+
});
|
|
250
253
|
this.router = router;
|
|
251
254
|
}
|
|
252
255
|
beforeEach(guard) {
|
|
@@ -267,13 +270,14 @@ export class RouteTransition {
|
|
|
267
270
|
this._controller = null;
|
|
268
271
|
}
|
|
269
272
|
async to(toType, toInput) {
|
|
270
|
-
|
|
273
|
+
var _a, _b, _c;
|
|
274
|
+
const from = (_b = (_a = this.route) == null ? void 0 : _a.clone()) != null ? _b : null;
|
|
271
275
|
const to = await this._runTask(
|
|
272
276
|
new Route({
|
|
273
277
|
options: this.router.parsedOptions,
|
|
274
278
|
toType,
|
|
275
279
|
toInput,
|
|
276
|
-
from: (from == null ? void 0 : from.url)
|
|
280
|
+
from: (_c = from == null ? void 0 : from.url) != null ? _c : null
|
|
277
281
|
}),
|
|
278
282
|
from
|
|
279
283
|
);
|
|
@@ -62,7 +62,7 @@ describe("Route Transition Tests", () => {
|
|
|
62
62
|
test("should handle concurrent navigation attempts", async () => {
|
|
63
63
|
const promises = Array.from(
|
|
64
64
|
{ length: 5 },
|
|
65
|
-
(_, i) => router.push(
|
|
65
|
+
(_, i) => router.push("/user/".concat(i + 1)).catch((err) => err)
|
|
66
66
|
);
|
|
67
67
|
const results = await Promise.all(promises);
|
|
68
68
|
const successResults = results.filter((r) => !(r instanceof Error));
|
package/dist/route.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
import { parseLocation } from "./location.mjs";
|
|
2
5
|
import { parsedOptions } from "./options.mjs";
|
|
3
6
|
import {
|
|
@@ -39,35 +42,35 @@ export function applyRouteParams(match, toInput, base, to) {
|
|
|
39
42
|
Object.assign(match.params, toInput.params);
|
|
40
43
|
}
|
|
41
44
|
export class Route {
|
|
42
|
-
// Private fields for handle validation
|
|
43
|
-
_handled = false;
|
|
44
|
-
_handle = null;
|
|
45
|
-
_handleResult = null;
|
|
46
|
-
_options;
|
|
47
|
-
// Public properties
|
|
48
|
-
statusCode = null;
|
|
49
|
-
state;
|
|
50
|
-
keepScrollPosition;
|
|
51
|
-
/** Custom confirm handler that overrides default route-transition confirm logic */
|
|
52
|
-
confirm;
|
|
53
|
-
/** Layer configuration for layer routes */
|
|
54
|
-
layer;
|
|
55
|
-
// Read-only properties
|
|
56
|
-
type;
|
|
57
|
-
req;
|
|
58
|
-
res;
|
|
59
|
-
context;
|
|
60
|
-
url;
|
|
61
|
-
path;
|
|
62
|
-
fullPath;
|
|
63
|
-
hash;
|
|
64
|
-
params = {};
|
|
65
|
-
query = {};
|
|
66
|
-
queryArray = {};
|
|
67
|
-
meta;
|
|
68
|
-
matched;
|
|
69
|
-
config;
|
|
70
45
|
constructor(routeOptions = {}) {
|
|
46
|
+
// Private fields for handle validation
|
|
47
|
+
__publicField(this, "_handled", false);
|
|
48
|
+
__publicField(this, "_handle", null);
|
|
49
|
+
__publicField(this, "_handleResult", null);
|
|
50
|
+
__publicField(this, "_options");
|
|
51
|
+
// Public properties
|
|
52
|
+
__publicField(this, "statusCode", null);
|
|
53
|
+
__publicField(this, "state");
|
|
54
|
+
__publicField(this, "keepScrollPosition");
|
|
55
|
+
/** Custom confirm handler that overrides default route-transition confirm logic */
|
|
56
|
+
__publicField(this, "confirm");
|
|
57
|
+
/** Layer configuration for layer routes */
|
|
58
|
+
__publicField(this, "layer");
|
|
59
|
+
// Read-only properties
|
|
60
|
+
__publicField(this, "type");
|
|
61
|
+
__publicField(this, "req");
|
|
62
|
+
__publicField(this, "res");
|
|
63
|
+
__publicField(this, "context");
|
|
64
|
+
__publicField(this, "url");
|
|
65
|
+
__publicField(this, "path");
|
|
66
|
+
__publicField(this, "fullPath");
|
|
67
|
+
__publicField(this, "hash");
|
|
68
|
+
__publicField(this, "params", {});
|
|
69
|
+
__publicField(this, "query", {});
|
|
70
|
+
__publicField(this, "queryArray", {});
|
|
71
|
+
__publicField(this, "meta");
|
|
72
|
+
__publicField(this, "matched");
|
|
73
|
+
__publicField(this, "config");
|
|
71
74
|
var _a;
|
|
72
75
|
const {
|
|
73
76
|
toType = RouteType.push,
|
package/dist/route.test.mjs
CHANGED
|
@@ -892,9 +892,9 @@ describe("Route Class Complete Test Suite", () => {
|
|
|
892
892
|
const options = createOptions();
|
|
893
893
|
const queryParams = Array.from(
|
|
894
894
|
{ length: 100 },
|
|
895
|
-
(_, i) =>
|
|
895
|
+
(_, i) => "param".concat(i, "=value").concat(i)
|
|
896
896
|
).join("&");
|
|
897
|
-
const path =
|
|
897
|
+
const path = "/test?".concat(queryParams);
|
|
898
898
|
const route = new Route({
|
|
899
899
|
options,
|
|
900
900
|
toType: RouteType.push,
|
|
@@ -1081,7 +1081,7 @@ describe("Route Class Complete Test Suite", () => {
|
|
|
1081
1081
|
new Route({
|
|
1082
1082
|
options,
|
|
1083
1083
|
toType: RouteType.push,
|
|
1084
|
-
toInput:
|
|
1084
|
+
toInput: "/users/".concat(i)
|
|
1085
1085
|
});
|
|
1086
1086
|
}
|
|
1087
1087
|
const endTime = performance.now();
|
|
@@ -1097,7 +1097,7 @@ describe("Route Class Complete Test Suite", () => {
|
|
|
1097
1097
|
});
|
|
1098
1098
|
const startTime = performance.now();
|
|
1099
1099
|
for (let i = 0; i < 1e3; i++) {
|
|
1100
|
-
route.state[
|
|
1100
|
+
route.state["key".concat(i)] = "value".concat(i);
|
|
1101
1101
|
}
|
|
1102
1102
|
const endTime = performance.now();
|
|
1103
1103
|
const duration = endTime - startTime;
|
|
@@ -10,7 +10,7 @@ describe("Router.back Tests", () => {
|
|
|
10
10
|
mode: RouterMode.memory,
|
|
11
11
|
base: new URL("http://localhost:3000/"),
|
|
12
12
|
fallback: (to, from) => {
|
|
13
|
-
executionLog.push(
|
|
13
|
+
executionLog.push("location-handler-".concat(to.path));
|
|
14
14
|
},
|
|
15
15
|
routes: [
|
|
16
16
|
{
|
|
@@ -10,7 +10,7 @@ describe("Router.forward Tests", () => {
|
|
|
10
10
|
mode: RouterMode.memory,
|
|
11
11
|
base: new URL("http://localhost:3000/"),
|
|
12
12
|
fallback: (to, from) => {
|
|
13
|
-
executionLog.push(
|
|
13
|
+
executionLog.push("location-handler-".concat(to.path));
|
|
14
14
|
},
|
|
15
15
|
routes: [
|
|
16
16
|
{
|
|
@@ -246,7 +246,7 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
246
246
|
it("should correctly execute beforeEach guards", async () => {
|
|
247
247
|
const unregister = router.beforeEach(async (to, from) => {
|
|
248
248
|
guardExecutionLog.push(
|
|
249
|
-
|
|
249
|
+
"beforeEach-".concat(to.path, "-from-").concat((from == null ? void 0 : from.path) || "null")
|
|
250
250
|
);
|
|
251
251
|
});
|
|
252
252
|
await router.restartApp("/about");
|
|
@@ -256,7 +256,7 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
256
256
|
it("should correctly execute afterEach guards", async () => {
|
|
257
257
|
const unregister = router.afterEach((to, from) => {
|
|
258
258
|
guardExecutionLog.push(
|
|
259
|
-
|
|
259
|
+
"afterEach-".concat(to.path, "-from-").concat((from == null ? void 0 : from.path) || "null")
|
|
260
260
|
);
|
|
261
261
|
});
|
|
262
262
|
await router.restartApp("/about");
|
|
@@ -504,10 +504,10 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
504
504
|
});
|
|
505
505
|
it("should correctly execute complete route lifecycle", async () => {
|
|
506
506
|
const unregisterBefore = lifecycleRouter.beforeEach((to, from) => {
|
|
507
|
-
lifecycleLog.push(
|
|
507
|
+
lifecycleLog.push("global-beforeEach-".concat(to.path));
|
|
508
508
|
});
|
|
509
509
|
const unregisterAfter = lifecycleRouter.afterEach((to, from) => {
|
|
510
|
-
lifecycleLog.push(
|
|
510
|
+
lifecycleLog.push("global-afterEach-".concat(to.path));
|
|
511
511
|
});
|
|
512
512
|
await lifecycleRouter.restartApp("/lifecycle");
|
|
513
513
|
expect(lifecycleLog).toEqual([
|
|
@@ -588,7 +588,7 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
588
588
|
0
|
|
589
589
|
);
|
|
590
590
|
for (let i = 0; i < 50; i++) {
|
|
591
|
-
await router.restartApp(
|
|
591
|
+
await router.restartApp("/user/".concat(i));
|
|
592
592
|
}
|
|
593
593
|
const finalAppsCallCount = Object.values(mockApps).reduce(
|
|
594
594
|
(sum, app) => sum + app.mock.calls.length,
|
|
@@ -601,7 +601,7 @@ describe("Router.restartApp Focused Tests", () => {
|
|
|
601
601
|
const startTime = Date.now();
|
|
602
602
|
const promises = Array.from(
|
|
603
603
|
{ length: 10 },
|
|
604
|
-
(_, i) => router.restartApp(
|
|
604
|
+
(_, i) => router.restartApp("/user/".concat(i)).catch((err) => err)
|
|
605
605
|
);
|
|
606
606
|
const results = await Promise.all(promises);
|
|
607
607
|
const endTime = Date.now();
|
|
@@ -33,8 +33,8 @@ describe("Router Window Navigation Tests", () => {
|
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
35
|
function createWindowNavigationTests(methodName, expectedIsPush) {
|
|
36
|
-
describe(
|
|
37
|
-
it(
|
|
36
|
+
describe("\u{1FA9F} ".concat(methodName, " Core Functionality Tests"), () => {
|
|
37
|
+
it("should support using current route path", async () => {
|
|
38
38
|
await router.push("/about");
|
|
39
39
|
const result = await router[methodName]("/about");
|
|
40
40
|
expect(result.type).toBe(RouteType[methodName]);
|
|
@@ -42,7 +42,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
42
42
|
expect(result.isPush).toBe(expectedIsPush);
|
|
43
43
|
expect(result.handle).not.toBeNull();
|
|
44
44
|
});
|
|
45
|
-
it(
|
|
45
|
+
it("should support string path parameters", async () => {
|
|
46
46
|
const result = await router[methodName]("/user/123");
|
|
47
47
|
expect(result.type).toBe(RouteType[methodName]);
|
|
48
48
|
expect(result.path).toBe("/user/123");
|
|
@@ -50,7 +50,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
50
50
|
expect(result.isPush).toBe(expectedIsPush);
|
|
51
51
|
expect(result.handle).not.toBeNull();
|
|
52
52
|
});
|
|
53
|
-
it(
|
|
53
|
+
it("should support object parameters", async () => {
|
|
54
54
|
const result = await router[methodName]({
|
|
55
55
|
path: "/user/456",
|
|
56
56
|
query: { tab: "profile" },
|
|
@@ -64,7 +64,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
64
64
|
expect(result.isPush).toBe(expectedIsPush);
|
|
65
65
|
expect(result.handle).not.toBeNull();
|
|
66
66
|
});
|
|
67
|
-
it(
|
|
67
|
+
it("should correctly handle complete URLs", async () => {
|
|
68
68
|
const result = await router[methodName](
|
|
69
69
|
"https://example.com/user/789?sort=name#top"
|
|
70
70
|
);
|
|
@@ -76,13 +76,13 @@ describe("Router Window Navigation Tests", () => {
|
|
|
76
76
|
expect(result.handle).not.toBeNull();
|
|
77
77
|
});
|
|
78
78
|
});
|
|
79
|
-
describe(
|
|
80
|
-
it(
|
|
79
|
+
describe("\u{1F3AF} ".concat(methodName, " Specific Behavior Tests"), () => {
|
|
80
|
+
it("should set correct isPush flag", async () => {
|
|
81
81
|
const result = await router[methodName]("/about");
|
|
82
82
|
expect(result.isPush).toBe(expectedIsPush);
|
|
83
83
|
expect(result.type).toBe(RouteType[methodName]);
|
|
84
84
|
});
|
|
85
|
-
it(
|
|
85
|
+
it("should call location handler", async () => {
|
|
86
86
|
let locationCalled = false;
|
|
87
87
|
let receivedRoute = null;
|
|
88
88
|
const windowRouter = new Router({
|
|
@@ -101,7 +101,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
101
101
|
expect(result.handleResult).toEqual({ windowNavigation: true });
|
|
102
102
|
windowRouter.destroy();
|
|
103
103
|
});
|
|
104
|
-
it(
|
|
104
|
+
it("should not update current route state", async () => {
|
|
105
105
|
await router.push("/about");
|
|
106
106
|
const beforeRoute = router.route;
|
|
107
107
|
await router[methodName]("/user/123");
|
|
@@ -109,14 +109,14 @@ describe("Router Window Navigation Tests", () => {
|
|
|
109
109
|
expect(afterRoute.path).toBe(beforeRoute.path);
|
|
110
110
|
expect(afterRoute.url.href).toBe(beforeRoute.url.href);
|
|
111
111
|
});
|
|
112
|
-
it(
|
|
112
|
+
it("should not trigger MicroApp update", async () => {
|
|
113
113
|
const updateSpy = vi.spyOn(router.microApp, "_update");
|
|
114
114
|
await router[methodName]("/user/123");
|
|
115
115
|
expect(updateSpy).not.toHaveBeenCalled();
|
|
116
116
|
});
|
|
117
117
|
});
|
|
118
|
-
describe(
|
|
119
|
-
it(
|
|
118
|
+
describe("\u{1F6E1}\uFE0F ".concat(methodName, " Route Guards Tests"), () => {
|
|
119
|
+
it("should execute beforeEach guards", async () => {
|
|
120
120
|
let guardCalled = false;
|
|
121
121
|
const unregister = router.beforeEach(async (to, from) => {
|
|
122
122
|
guardCalled = true;
|
|
@@ -126,7 +126,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
126
126
|
expect(guardCalled).toBe(true);
|
|
127
127
|
unregister();
|
|
128
128
|
});
|
|
129
|
-
it(
|
|
129
|
+
it("should abort navigation when guard returns false", async () => {
|
|
130
130
|
const unregister = router.beforeEach((to, from) => {
|
|
131
131
|
return false;
|
|
132
132
|
});
|
|
@@ -135,7 +135,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
135
135
|
);
|
|
136
136
|
unregister();
|
|
137
137
|
});
|
|
138
|
-
it(
|
|
138
|
+
it("should support guard redirects", async () => {
|
|
139
139
|
const unregister = router.beforeEach(async (to) => {
|
|
140
140
|
if (to.path === "/about") {
|
|
141
141
|
return "/user/redirect";
|
|
@@ -146,7 +146,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
146
146
|
expect(result.params.id).toBe("redirect");
|
|
147
147
|
unregister();
|
|
148
148
|
});
|
|
149
|
-
it(
|
|
149
|
+
it("should execute afterEach guards", async () => {
|
|
150
150
|
let guardCalled = false;
|
|
151
151
|
const unregister = router.afterEach((to, from) => {
|
|
152
152
|
guardCalled = true;
|
|
@@ -157,19 +157,19 @@ describe("Router Window Navigation Tests", () => {
|
|
|
157
157
|
unregister();
|
|
158
158
|
});
|
|
159
159
|
});
|
|
160
|
-
describe(
|
|
161
|
-
it(
|
|
160
|
+
describe("\u{1F3AD} ".concat(methodName, " Edge Cases Tests"), () => {
|
|
161
|
+
it("should handle non-existent routes", async () => {
|
|
162
162
|
const result = await router[methodName]("/nonexistent");
|
|
163
163
|
expect(result.handle).not.toBeNull();
|
|
164
164
|
expect(result.matched.length).toBe(0);
|
|
165
165
|
expect(result.isPush).toBe(expectedIsPush);
|
|
166
166
|
});
|
|
167
|
-
it(
|
|
167
|
+
it("should handle empty string path", async () => {
|
|
168
168
|
const result = await router[methodName]("");
|
|
169
169
|
expect(result.handle).not.toBeNull();
|
|
170
170
|
expect(result.isPush).toBe(expectedIsPush);
|
|
171
171
|
});
|
|
172
|
-
it(
|
|
172
|
+
it("should handle special characters", async () => {
|
|
173
173
|
const result = await router[methodName](
|
|
174
174
|
"/user/\u6D4B\u8BD5\u7528\u6237?name=\u5F20\u4E09&age=25#\u4E2A\u4EBA\u4FE1\u606F"
|
|
175
175
|
);
|
|
@@ -180,8 +180,8 @@ describe("Router Window Navigation Tests", () => {
|
|
|
180
180
|
);
|
|
181
181
|
});
|
|
182
182
|
});
|
|
183
|
-
describe(
|
|
184
|
-
it(
|
|
183
|
+
describe("\u26A1 ".concat(methodName, " Task Cancellation and Concurrency Control"), () => {
|
|
184
|
+
it("should support concurrent calls", async () => {
|
|
185
185
|
const promises = [
|
|
186
186
|
router[methodName]("/user/1").catch((err) => err),
|
|
187
187
|
router[methodName]("/user/2").catch((err) => err),
|
|
@@ -198,10 +198,10 @@ describe("Router Window Navigation Tests", () => {
|
|
|
198
198
|
expect(result.isPush).toBe(expectedIsPush);
|
|
199
199
|
});
|
|
200
200
|
});
|
|
201
|
-
it(
|
|
201
|
+
it("should correctly handle rapid consecutive calls", async () => {
|
|
202
202
|
const results = [];
|
|
203
203
|
for (let i = 0; i < 5; i++) {
|
|
204
|
-
results.push(await router[methodName](
|
|
204
|
+
results.push(await router[methodName]("/user/".concat(i)));
|
|
205
205
|
}
|
|
206
206
|
results.forEach((result, index) => {
|
|
207
207
|
expect(result.handle).not.toBeNull();
|
|
@@ -210,15 +210,15 @@ describe("Router Window Navigation Tests", () => {
|
|
|
210
210
|
});
|
|
211
211
|
});
|
|
212
212
|
});
|
|
213
|
-
describe(
|
|
214
|
-
it(
|
|
213
|
+
describe("\u274C ".concat(methodName, " Error Handling"), () => {
|
|
214
|
+
it("should handle exceptions in guards", async () => {
|
|
215
215
|
const unregister = router.beforeEach(async () => {
|
|
216
216
|
throw new Error("Guard error");
|
|
217
217
|
});
|
|
218
218
|
await expect(router[methodName]("/about")).rejects.toThrow();
|
|
219
219
|
unregister();
|
|
220
220
|
});
|
|
221
|
-
it(
|
|
221
|
+
it("should handle location handler exceptions", async () => {
|
|
222
222
|
const windowRouter = new Router({
|
|
223
223
|
routes: [{ path: "/", app: "home" }],
|
|
224
224
|
apps: mockApps,
|
|
@@ -233,8 +233,8 @@ describe("Router Window Navigation Tests", () => {
|
|
|
233
233
|
windowRouter.destroy();
|
|
234
234
|
});
|
|
235
235
|
});
|
|
236
|
-
describe(
|
|
237
|
-
it(
|
|
236
|
+
describe("\u{1F9E9} ".concat(methodName, " Async Component Handling"), () => {
|
|
237
|
+
it("should correctly handle async components", async () => {
|
|
238
238
|
const asyncRouter = new Router({
|
|
239
239
|
routes: [
|
|
240
240
|
{
|
|
@@ -261,7 +261,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
261
261
|
expect(result.handleResult).toEqual({ windowNavigation: true });
|
|
262
262
|
asyncRouter.destroy();
|
|
263
263
|
});
|
|
264
|
-
it(
|
|
264
|
+
it("should handle async component loading failures", async () => {
|
|
265
265
|
const asyncRouter = new Router({
|
|
266
266
|
routes: [
|
|
267
267
|
{
|
|
@@ -285,8 +285,8 @@ describe("Router Window Navigation Tests", () => {
|
|
|
285
285
|
asyncRouter.destroy();
|
|
286
286
|
});
|
|
287
287
|
});
|
|
288
|
-
describe(
|
|
289
|
-
it(
|
|
288
|
+
describe("\u{1F527} ".concat(methodName, " Differences from Other Methods"), () => {
|
|
289
|
+
it("should behave differently from push/replace methods", async () => {
|
|
290
290
|
await router.push("/about");
|
|
291
291
|
const pushResult = await router.push("/user/123");
|
|
292
292
|
const windowResult = await router[methodName]("/user/456");
|
|
@@ -296,7 +296,7 @@ describe("Router Window Navigation Tests", () => {
|
|
|
296
296
|
expect(pushResult.type).toBe(RouteType.push);
|
|
297
297
|
expect(windowResult.type).toBe(RouteType[methodName]);
|
|
298
298
|
});
|
|
299
|
-
it(
|
|
299
|
+
it("should maintain consistency with resolve method in URL parsing", async () => {
|
|
300
300
|
const resolvedRoute = router.resolve("/user/789");
|
|
301
301
|
const windowRoute = await router[methodName]("/user/789");
|
|
302
302
|
expect(windowRoute.url.href).toBe(resolvedRoute.url.href);
|
package/dist/router.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1
4
|
import { LAYER_ID } from "./increment-id.mjs";
|
|
2
5
|
import { MicroApp } from "./micro-app.mjs";
|
|
3
6
|
import { Navigation } from "./navigation.mjs";
|
|
@@ -8,13 +11,27 @@ import { createLinkResolver } from "./router-link.mjs";
|
|
|
8
11
|
import { RouteType, RouterMode } from "./types.mjs";
|
|
9
12
|
import { isNotNullish, isPlainObject, isRouteMatched } from "./util.mjs";
|
|
10
13
|
export class Router {
|
|
11
|
-
options
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
constructor(options) {
|
|
15
|
+
__publicField(this, "options");
|
|
16
|
+
__publicField(this, "parsedOptions");
|
|
17
|
+
__publicField(this, "isLayer");
|
|
18
|
+
__publicField(this, "navigation");
|
|
19
|
+
__publicField(this, "microApp", new MicroApp());
|
|
20
|
+
// Route transition manager
|
|
21
|
+
__publicField(this, "transition", new RouteTransition(this));
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.parsedOptions = parsedOptions(options);
|
|
24
|
+
this.isLayer = this.parsedOptions.layer;
|
|
25
|
+
this.navigation = new Navigation(
|
|
26
|
+
this.parsedOptions,
|
|
27
|
+
(url, state) => {
|
|
28
|
+
this.transition.to(RouteType.unknown, {
|
|
29
|
+
url,
|
|
30
|
+
state
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
18
35
|
get route() {
|
|
19
36
|
const route = this.transition.route;
|
|
20
37
|
if (route === null) {
|
|
@@ -28,24 +45,12 @@ export class Router {
|
|
|
28
45
|
return this.parsedOptions.root;
|
|
29
46
|
}
|
|
30
47
|
get req() {
|
|
31
|
-
|
|
48
|
+
var _a;
|
|
49
|
+
return (_a = this.parsedOptions.req) != null ? _a : null;
|
|
32
50
|
}
|
|
33
51
|
get res() {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
constructor(options) {
|
|
37
|
-
this.options = options;
|
|
38
|
-
this.parsedOptions = parsedOptions(options);
|
|
39
|
-
this.isLayer = this.parsedOptions.layer;
|
|
40
|
-
this.navigation = new Navigation(
|
|
41
|
-
this.parsedOptions,
|
|
42
|
-
(url, state) => {
|
|
43
|
-
this.transition.to(RouteType.unknown, {
|
|
44
|
-
url,
|
|
45
|
-
state
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
);
|
|
52
|
+
var _a;
|
|
53
|
+
return (_a = this.parsedOptions.res) != null ? _a : null;
|
|
49
54
|
}
|
|
50
55
|
push(toInput) {
|
|
51
56
|
return this.transition.to(RouteType.push, toInput);
|
|
@@ -62,7 +67,7 @@ export class Router {
|
|
|
62
67
|
restartApp(toInput) {
|
|
63
68
|
return this.transition.to(
|
|
64
69
|
RouteType.restartApp,
|
|
65
|
-
toInput
|
|
70
|
+
toInput != null ? toInput : this.route.url.href
|
|
66
71
|
);
|
|
67
72
|
}
|
|
68
73
|
async back() {
|
|
@@ -132,12 +137,12 @@ export class Router {
|
|
|
132
137
|
* ```
|
|
133
138
|
*/
|
|
134
139
|
resolve(toInput, toType) {
|
|
135
|
-
var _a;
|
|
140
|
+
var _a, _b;
|
|
136
141
|
return new Route({
|
|
137
142
|
options: this.parsedOptions,
|
|
138
143
|
toType,
|
|
139
144
|
toInput,
|
|
140
|
-
from: ((_a = this.transition.route) == null ? void 0 : _a.url)
|
|
145
|
+
from: (_b = (_a = this.transition.route) == null ? void 0 : _a.url) != null ? _b : null
|
|
141
146
|
});
|
|
142
147
|
}
|
|
143
148
|
/**
|
|
@@ -194,8 +199,9 @@ export class Router {
|
|
|
194
199
|
return createLinkResolver(this, props);
|
|
195
200
|
}
|
|
196
201
|
async createLayer(toInput) {
|
|
202
|
+
var _a;
|
|
197
203
|
const layerOptions = (isPlainObject(toInput) ? toInput.layer : null) || {};
|
|
198
|
-
const zIndex = layerOptions.zIndex
|
|
204
|
+
const zIndex = (_a = layerOptions.zIndex) != null ? _a : this.parsedOptions.zIndex + LAYER_ID.next();
|
|
199
205
|
let promiseResolve;
|
|
200
206
|
const promise = new Promise((resolve) => {
|
|
201
207
|
promiseResolve = resolve;
|
|
@@ -245,7 +251,7 @@ export class Router {
|
|
|
245
251
|
router.afterEach((to, from) => {
|
|
246
252
|
if (layerOptions.shouldClose) {
|
|
247
253
|
const result = layerOptions.shouldClose(to, from, router);
|
|
248
|
-
if (result ===
|
|
254
|
+
if (result === true) {
|
|
249
255
|
router.destroy();
|
|
250
256
|
promiseResolve({
|
|
251
257
|
type: "push",
|
|
@@ -277,7 +283,7 @@ export class Router {
|
|
|
277
283
|
var _a, _b;
|
|
278
284
|
try {
|
|
279
285
|
const result = await ((_b = (_a = this.microApp.app) == null ? void 0 : _a.renderToString) == null ? void 0 : _b.call(_a));
|
|
280
|
-
return result
|
|
286
|
+
return result != null ? result : null;
|
|
281
287
|
} catch (e) {
|
|
282
288
|
if (throwError) throw e;
|
|
283
289
|
else console.error(e);
|
package/dist/util.test.mjs
CHANGED
|
@@ -23,8 +23,8 @@ describe("isNotNullish", () => {
|
|
|
23
23
|
expect(isNotNullish(new Number("a"))).toBe(false);
|
|
24
24
|
expect(isNotNullish(0)).toBe(true);
|
|
25
25
|
expect(isNotNullish(123)).toBe(true);
|
|
26
|
-
expect(isNotNullish(
|
|
27
|
-
expect(isNotNullish(
|
|
26
|
+
expect(isNotNullish(/* @__PURE__ */ BigInt("123"))).toBe(true);
|
|
27
|
+
expect(isNotNullish(/* @__PURE__ */ BigInt("0"))).toBe(true);
|
|
28
28
|
expect(isNotNullish(new Number("1"))).toBe(true);
|
|
29
29
|
expect(isNotNullish(Number.POSITIVE_INFINITY)).toBe(true);
|
|
30
30
|
expect(isNotNullish(Number.NEGATIVE_INFINITY)).toBe(true);
|
|
@@ -171,9 +171,9 @@ describe("isPlainObject", () => {
|
|
|
171
171
|
expect(isPlainObject(new Boolean(true))).toBe(false);
|
|
172
172
|
expect(isPlainObject(new Boolean(false))).toBe(false);
|
|
173
173
|
expect(isPlainObject(0)).toBe(false);
|
|
174
|
-
expect(isPlainObject(
|
|
174
|
+
expect(isPlainObject(/* @__PURE__ */ BigInt("0"))).toBe(false);
|
|
175
175
|
expect(isPlainObject(123)).toBe(false);
|
|
176
|
-
expect(isPlainObject(
|
|
176
|
+
expect(isPlainObject(/* @__PURE__ */ BigInt("123"))).toBe(false);
|
|
177
177
|
expect(isPlainObject(new Number("1"))).toBe(false);
|
|
178
178
|
expect(isPlainObject(+"a")).toBe(false);
|
|
179
179
|
expect(isPlainObject(Number.NaN)).toBe(false);
|
|
@@ -249,8 +249,8 @@ describe("isNonEmptyPlainObject", () => {
|
|
|
249
249
|
expect(isNonEmptyPlainObject("non-empty")).toBe(false);
|
|
250
250
|
expect(isNonEmptyPlainObject(0)).toBe(false);
|
|
251
251
|
expect(isNonEmptyPlainObject(123)).toBe(false);
|
|
252
|
-
expect(isNonEmptyPlainObject(
|
|
253
|
-
expect(isNonEmptyPlainObject(
|
|
252
|
+
expect(isNonEmptyPlainObject(/* @__PURE__ */ BigInt("0"))).toBe(false);
|
|
253
|
+
expect(isNonEmptyPlainObject(/* @__PURE__ */ BigInt("123"))).toBe(false);
|
|
254
254
|
expect(isNonEmptyPlainObject(true)).toBe(false);
|
|
255
255
|
expect(isNonEmptyPlainObject(false)).toBe(false);
|
|
256
256
|
expect(isNonEmptyPlainObject(Symbol("test"))).toBe(false);
|
|
@@ -381,12 +381,12 @@ describe("removeFromArray", () => {
|
|
|
381
381
|
expect(complexArr).toHaveLength(2);
|
|
382
382
|
});
|
|
383
383
|
test("should handle arrays with different primitive types", () => {
|
|
384
|
-
let mixedArr = [1, "1", true,
|
|
384
|
+
let mixedArr = [1, "1", true, /* @__PURE__ */ BigInt("1"), Symbol("test")];
|
|
385
385
|
removeFromArray(mixedArr, 1);
|
|
386
|
-
expect(mixedArr).toEqual(["1", true,
|
|
387
|
-
mixedArr = [1, "1", true,
|
|
386
|
+
expect(mixedArr).toEqual(["1", true, /* @__PURE__ */ BigInt("1"), expect.any(Symbol)]);
|
|
387
|
+
mixedArr = [1, "1", true, /* @__PURE__ */ BigInt("1"), Symbol("test")];
|
|
388
388
|
removeFromArray(mixedArr, "1");
|
|
389
|
-
expect(mixedArr).toEqual([1, true,
|
|
389
|
+
expect(mixedArr).toEqual([1, true, /* @__PURE__ */ BigInt("1"), expect.any(Symbol)]);
|
|
390
390
|
const mixedArray = [
|
|
391
391
|
"string",
|
|
392
392
|
42,
|
|
@@ -496,8 +496,8 @@ describe("isValidConfirmHookResult", () => {
|
|
|
496
496
|
expect(isValidConfirmHookResult(void 0)).toBe(false);
|
|
497
497
|
expect(isValidConfirmHookResult(123)).toBe(false);
|
|
498
498
|
expect(isValidConfirmHookResult(0)).toBe(false);
|
|
499
|
-
expect(isValidConfirmHookResult(
|
|
500
|
-
expect(isValidConfirmHookResult(
|
|
499
|
+
expect(isValidConfirmHookResult(/* @__PURE__ */ BigInt("123"))).toBe(false);
|
|
500
|
+
expect(isValidConfirmHookResult(/* @__PURE__ */ BigInt("0"))).toBe(false);
|
|
501
501
|
expect(isValidConfirmHookResult(new Number("1"))).toBe(false);
|
|
502
502
|
expect(isValidConfirmHookResult(+"a")).toBe(false);
|
|
503
503
|
expect(isValidConfirmHookResult(Number.NaN)).toBe(false);
|
|
@@ -798,11 +798,11 @@ describe("isUrlEqual", () => {
|
|
|
798
798
|
const params1 = new URLSearchParams();
|
|
799
799
|
const params2 = new URLSearchParams();
|
|
800
800
|
for (let i = 0; i < 100; i++) {
|
|
801
|
-
params1.append(
|
|
802
|
-
params2.append(
|
|
801
|
+
params1.append("param".concat(i), "value".concat(i));
|
|
802
|
+
params2.append("param".concat(99 - i), "value".concat(99 - i));
|
|
803
803
|
}
|
|
804
|
-
const url1 = new URL(
|
|
805
|
-
const url2 = new URL(
|
|
804
|
+
const url1 = new URL("https://example.com/path?".concat(params1));
|
|
805
|
+
const url2 = new URL("https://example.com/path?".concat(params2));
|
|
806
806
|
const start = performance.now();
|
|
807
807
|
const result = isUrlEqual(url1, url2);
|
|
808
808
|
const end = performance.now();
|
|
@@ -812,10 +812,10 @@ describe("isUrlEqual", () => {
|
|
|
812
812
|
test("should handle complex real-world scenarios", () => {
|
|
813
813
|
const baseUrl = "https://api.example.com/v1/users";
|
|
814
814
|
const url1 = new URL(
|
|
815
|
-
|
|
815
|
+
"".concat(baseUrl, "?page=1&limit=20&sort=name&filter=active&tag=user&tag=admin")
|
|
816
816
|
);
|
|
817
817
|
const url2 = new URL(
|
|
818
|
-
|
|
818
|
+
"".concat(baseUrl, "?limit=20&tag=user&page=1&tag=admin&filter=active&sort=name")
|
|
819
819
|
);
|
|
820
820
|
expect(isUrlEqual(url1, url2)).toBe(true);
|
|
821
821
|
const oauthUrl1 = new URL(
|
package/package.json
CHANGED
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@biomejs/biome": "1.9.4",
|
|
35
|
-
"@esmx/lint": "3.0.0-rc.
|
|
36
|
-
"@types/node": "
|
|
37
|
-
"@vitest/coverage-v8": "3.
|
|
35
|
+
"@esmx/lint": "3.0.0-rc.25",
|
|
36
|
+
"@types/node": "^24.0.10",
|
|
37
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
38
38
|
"happy-dom": "^18.0.1",
|
|
39
|
-
"stylelint": "16.
|
|
40
|
-
"typescript": "5.8.
|
|
39
|
+
"stylelint": "16.21.0",
|
|
40
|
+
"typescript": "5.8.3",
|
|
41
41
|
"unbuild": "3.5.0",
|
|
42
|
-
"vitest": "3.
|
|
42
|
+
"vitest": "3.2.4"
|
|
43
43
|
},
|
|
44
|
-
"version": "3.0.0-rc.
|
|
44
|
+
"version": "3.0.0-rc.25",
|
|
45
45
|
"type": "module",
|
|
46
46
|
"private": false,
|
|
47
47
|
"exports": {
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"template",
|
|
61
61
|
"public"
|
|
62
62
|
],
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "da6576d7505ad48cb78905b18e17940d43510250"
|
|
64
64
|
}
|
package/src/route-transition.ts
CHANGED
|
@@ -380,7 +380,7 @@ export class RouteTransition {
|
|
|
380
380
|
toType: RouteType,
|
|
381
381
|
toInput: RouteLocationInput
|
|
382
382
|
): Promise<Route> {
|
|
383
|
-
const from = this.route;
|
|
383
|
+
const from = this.route?.clone() ?? null;
|
|
384
384
|
const to = await this._runTask(
|
|
385
385
|
new Route({
|
|
386
386
|
options: this.router.parsedOptions,
|
package/src/router.ts
CHANGED
|
@@ -283,7 +283,7 @@ export class Router {
|
|
|
283
283
|
router.afterEach((to, from) => {
|
|
284
284
|
if (layerOptions.shouldClose) {
|
|
285
285
|
const result = layerOptions.shouldClose(to, from, router);
|
|
286
|
-
if (result ===
|
|
286
|
+
if (result === true) {
|
|
287
287
|
router.destroy();
|
|
288
288
|
promiseResolve({
|
|
289
289
|
type: 'push',
|