@wot-ui/router 0.0.4 → 0.0.9

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/index.cjs CHANGED
@@ -68,21 +68,16 @@ function createRouter(options) {
68
68
  if (typeof to === "string") return resolvePath(to);
69
69
  if (to.name) {
70
70
  const route = routes.find((r) => r.name === to.name);
71
- if (!route) {
72
- console.warn(`[router] Route with name '${to.name}' not found`);
73
- return {
74
- ...START_LOCATION_NORMALIZED,
75
- path: "/"
76
- };
77
- }
71
+ if (!route) throw new Error(`您正在尝试访问的路由 '${to.name}' 未在路由表中定义。请检查您的路由配置。`);
78
72
  const path = fillParams(route.path, to.params);
73
+ const finalQuery = to.params || {};
79
74
  return {
80
75
  path,
81
76
  name: to.name,
82
77
  params: to.params || {},
83
- query: to.query || {},
78
+ query: finalQuery,
84
79
  hash: to.hash || "",
85
- fullPath: stringifyQuery(path, to.query || {}),
80
+ fullPath: stringifyQuery(path, finalQuery),
86
81
  meta: route.meta || {}
87
82
  };
88
83
  }
@@ -92,6 +87,7 @@ function createRouter(options) {
92
87
  function resolvePath(path, query) {
93
88
  const normalizedPath = normalizeUrl(path.split("?")[0]);
94
89
  const route = routes.find((r) => r.path === normalizedPath || r.aliasPath === normalizedPath);
90
+ if (!route) throw new Error(`您正在尝试访问的路由 '${normalizedPath}' 未在路由表中定义。请检查您的路由配置。`);
95
91
  const finalQuery = {
96
92
  ...getUrlParams(path),
97
93
  ...query || {}
@@ -128,57 +124,82 @@ function createRouter(options) {
128
124
  if (back$1 === void 0 || typeof back$1 === "number") uni.navigateBack({ delta: back$1 ?? 1 });
129
125
  else uni.navigateBack(back$1);
130
126
  }
131
- async function navigate(to, type) {
127
+ async function navigate(to, type, skipGuards = false) {
132
128
  const targetLocation = resolve(to);
133
129
  const fromLocation = (0, vue.unref)(currentRoute);
134
- try {
130
+ if (!skipGuards) try {
135
131
  await runGuardQueue(beforeGuards, targetLocation, fromLocation);
136
132
  } catch (error) {
137
133
  if (error && (error.message === "NavigationCancelled" || error.message === "NavigationRedirect")) {
138
- if (error.message === "NavigationRedirect" && error.to) return navigate(error.to, type);
134
+ if (error.message === "NavigationRedirect" && error.to) return navigate(error.to, type, true);
139
135
  return Promise.reject(error);
140
136
  }
141
137
  return Promise.reject(error);
142
138
  }
143
139
  const url = targetLocation.fullPath;
144
- performUniNavigate(typeof to === "object" && to.navType || type || "push", url);
145
- currentRoute.value = targetLocation;
146
- afterGuards.forEach((guard) => guard(targetLocation, fromLocation));
147
- return Promise.resolve();
140
+ const finalType = typeof to === "object" && to.navType || type || "push";
141
+ try {
142
+ await performUniNavigate(finalType, url);
143
+ currentRoute.value = targetLocation;
144
+ afterGuards.forEach((guard) => guard(targetLocation, fromLocation));
145
+ return Promise.resolve();
146
+ } catch (error) {
147
+ return Promise.reject(error);
148
+ }
148
149
  }
149
150
  function performUniNavigate(type, url) {
150
- switch (type) {
151
- case "push":
152
- uni.navigateTo({ url });
153
- break;
154
- case "replace":
155
- uni.redirectTo({ url });
156
- break;
157
- case "pushTab":
158
- uni.switchTab({ url });
159
- break;
160
- case "replaceAll":
161
- uni.reLaunch({ url });
162
- break;
163
- case "back":
164
- uni.navigateBack({});
165
- break;
166
- default: uni.navigateTo({ url });
167
- }
151
+ return new Promise((resolve$1, reject) => {
152
+ const success = () => resolve$1();
153
+ const fail = (error) => {
154
+ reject(/* @__PURE__ */ new Error(`Navigation failed: ${error.message || error.errMsg || "Unknown error"}`));
155
+ };
156
+ switch (type) {
157
+ case "push":
158
+ uni.navigateTo({
159
+ url,
160
+ success,
161
+ fail
162
+ });
163
+ break;
164
+ case "replace":
165
+ uni.redirectTo({
166
+ url,
167
+ success,
168
+ fail
169
+ });
170
+ break;
171
+ case "pushTab":
172
+ uni.switchTab({
173
+ url,
174
+ success,
175
+ fail
176
+ });
177
+ break;
178
+ case "replaceAll":
179
+ uni.reLaunch({
180
+ url,
181
+ success,
182
+ fail
183
+ });
184
+ break;
185
+ case "back":
186
+ uni.navigateBack({
187
+ success,
188
+ fail
189
+ });
190
+ break;
191
+ default: uni.navigateTo({
192
+ url,
193
+ success,
194
+ fail
195
+ });
196
+ }
197
+ });
168
198
  }
169
199
  async function runGuardQueue(guards, to, from) {
170
200
  for (const guard of guards) await new Promise((resolve$1, reject) => {
171
201
  const next = (val) => {
172
- if (val === false) reject(/* @__PURE__ */ new Error("NavigationCancelled"));
173
- else if (val === void 0) resolve$1();
174
- else {
175
- const error = /* @__PURE__ */ new Error("NavigationRedirect");
176
- error.to = val;
177
- reject(error);
178
- }
179
- };
180
- const res = guard(to, from, next);
181
- if (res instanceof Promise) res.then((val) => {
202
+ next._called = true;
182
203
  if (val === false) reject(/* @__PURE__ */ new Error("NavigationCancelled"));
183
204
  else if (val === void 0 || val === true) resolve$1();
184
205
  else {
@@ -186,14 +207,26 @@ function createRouter(options) {
186
207
  error.to = val;
187
208
  reject(error);
188
209
  }
189
- }).catch(reject);
190
- else if (res !== void 0 && typeof res !== "function") if (res === false) reject(/* @__PURE__ */ new Error("NavigationCancelled"));
191
- else if (res === true) resolve$1();
210
+ };
211
+ const guardReturn = guard(to, from, next);
212
+ let guardCall = Promise.resolve(guardReturn);
213
+ if (guard.length < 3) guardCall = guardCall.then(next);
192
214
  else {
193
- const error = /* @__PURE__ */ new Error("NavigationRedirect");
194
- error.to = res;
195
- reject(error);
215
+ const message = `The "next" callback was never called inside of ${guard.name ? `"${guard.name}"` : ""}:\n${guard.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`;
216
+ if (guardReturn !== null && typeof guardReturn === "object" && "then" in guardReturn) guardCall = guardCall.then((resolvedValue) => {
217
+ if (!next._called) {
218
+ console.warn(message);
219
+ return Promise.reject(/* @__PURE__ */ new Error("Invalid navigation guard"));
220
+ }
221
+ return resolvedValue;
222
+ });
223
+ else if (!next._called) {
224
+ console.warn(message);
225
+ reject(/* @__PURE__ */ new Error("Invalid navigation guard"));
226
+ return;
227
+ }
196
228
  }
229
+ guardCall.catch((err) => reject(err));
197
230
  });
198
231
  }
199
232
  function beforeEach(guard) {
@@ -237,6 +270,7 @@ function createRouter(options) {
237
270
  if (router$1.currentRoute.value.path === newPath) return;
238
271
  const from = (0, vue.unref)(router$1.currentRoute);
239
272
  const matched = router$1.routes.find((r) => r.path === newPath || r.aliasPath === newPath);
273
+ if (!matched) console.warn(`[router] 路由 '${newPath}' 未在路由表中定义,但页面已加载。请检查您的路由配置。`);
240
274
  const to = {
241
275
  path: newPath,
242
276
  name: matched?.name,
package/dist/index.d.cts CHANGED
@@ -43,7 +43,7 @@ type RouteLocationRaw = string | {
43
43
  interface RouterOptions {
44
44
  routes: RouteRecordRaw[];
45
45
  }
46
- type NavigationGuardNext = (to?: RouteLocationRaw | false | void) => void;
46
+ type NavigationGuardNext = (to?: RouteLocationRaw | false | true | void) => void;
47
47
  type NavigationGuard = (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => Promise<void | RouteLocationRaw | false | boolean> | void | RouteLocationRaw | false | boolean;
48
48
  type NavigationHookAfter = (to: RouteLocationNormalized, from: RouteLocationNormalized) => void;
49
49
  type NavType = 'push' | 'replace' | 'replaceAll' | 'pushTab' | 'back';
package/dist/index.d.mts CHANGED
@@ -43,7 +43,7 @@ type RouteLocationRaw = string | {
43
43
  interface RouterOptions {
44
44
  routes: RouteRecordRaw[];
45
45
  }
46
- type NavigationGuardNext = (to?: RouteLocationRaw | false | void) => void;
46
+ type NavigationGuardNext = (to?: RouteLocationRaw | false | true | void) => void;
47
47
  type NavigationGuard = (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => Promise<void | RouteLocationRaw | false | boolean> | void | RouteLocationRaw | false | boolean;
48
48
  type NavigationHookAfter = (to: RouteLocationNormalized, from: RouteLocationNormalized) => void;
49
49
  type NavType = 'push' | 'replace' | 'replaceAll' | 'pushTab' | 'back';
package/dist/index.mjs CHANGED
@@ -68,21 +68,16 @@ function createRouter(options) {
68
68
  if (typeof to === "string") return resolvePath(to);
69
69
  if (to.name) {
70
70
  const route = routes.find((r) => r.name === to.name);
71
- if (!route) {
72
- console.warn(`[router] Route with name '${to.name}' not found`);
73
- return {
74
- ...START_LOCATION_NORMALIZED,
75
- path: "/"
76
- };
77
- }
71
+ if (!route) throw new Error(`您正在尝试访问的路由 '${to.name}' 未在路由表中定义。请检查您的路由配置。`);
78
72
  const path = fillParams(route.path, to.params);
73
+ const finalQuery = to.params || {};
79
74
  return {
80
75
  path,
81
76
  name: to.name,
82
77
  params: to.params || {},
83
- query: to.query || {},
78
+ query: finalQuery,
84
79
  hash: to.hash || "",
85
- fullPath: stringifyQuery(path, to.query || {}),
80
+ fullPath: stringifyQuery(path, finalQuery),
86
81
  meta: route.meta || {}
87
82
  };
88
83
  }
@@ -92,6 +87,7 @@ function createRouter(options) {
92
87
  function resolvePath(path, query) {
93
88
  const normalizedPath = normalizeUrl(path.split("?")[0]);
94
89
  const route = routes.find((r) => r.path === normalizedPath || r.aliasPath === normalizedPath);
90
+ if (!route) throw new Error(`您正在尝试访问的路由 '${normalizedPath}' 未在路由表中定义。请检查您的路由配置。`);
95
91
  const finalQuery = {
96
92
  ...getUrlParams(path),
97
93
  ...query || {}
@@ -128,57 +124,82 @@ function createRouter(options) {
128
124
  if (back$1 === void 0 || typeof back$1 === "number") uni.navigateBack({ delta: back$1 ?? 1 });
129
125
  else uni.navigateBack(back$1);
130
126
  }
131
- async function navigate(to, type) {
127
+ async function navigate(to, type, skipGuards = false) {
132
128
  const targetLocation = resolve(to);
133
129
  const fromLocation = unref(currentRoute);
134
- try {
130
+ if (!skipGuards) try {
135
131
  await runGuardQueue(beforeGuards, targetLocation, fromLocation);
136
132
  } catch (error) {
137
133
  if (error && (error.message === "NavigationCancelled" || error.message === "NavigationRedirect")) {
138
- if (error.message === "NavigationRedirect" && error.to) return navigate(error.to, type);
134
+ if (error.message === "NavigationRedirect" && error.to) return navigate(error.to, type, true);
139
135
  return Promise.reject(error);
140
136
  }
141
137
  return Promise.reject(error);
142
138
  }
143
139
  const url = targetLocation.fullPath;
144
- performUniNavigate(typeof to === "object" && to.navType || type || "push", url);
145
- currentRoute.value = targetLocation;
146
- afterGuards.forEach((guard) => guard(targetLocation, fromLocation));
147
- return Promise.resolve();
140
+ const finalType = typeof to === "object" && to.navType || type || "push";
141
+ try {
142
+ await performUniNavigate(finalType, url);
143
+ currentRoute.value = targetLocation;
144
+ afterGuards.forEach((guard) => guard(targetLocation, fromLocation));
145
+ return Promise.resolve();
146
+ } catch (error) {
147
+ return Promise.reject(error);
148
+ }
148
149
  }
149
150
  function performUniNavigate(type, url) {
150
- switch (type) {
151
- case "push":
152
- uni.navigateTo({ url });
153
- break;
154
- case "replace":
155
- uni.redirectTo({ url });
156
- break;
157
- case "pushTab":
158
- uni.switchTab({ url });
159
- break;
160
- case "replaceAll":
161
- uni.reLaunch({ url });
162
- break;
163
- case "back":
164
- uni.navigateBack({});
165
- break;
166
- default: uni.navigateTo({ url });
167
- }
151
+ return new Promise((resolve$1, reject) => {
152
+ const success = () => resolve$1();
153
+ const fail = (error) => {
154
+ reject(/* @__PURE__ */ new Error(`Navigation failed: ${error.message || error.errMsg || "Unknown error"}`));
155
+ };
156
+ switch (type) {
157
+ case "push":
158
+ uni.navigateTo({
159
+ url,
160
+ success,
161
+ fail
162
+ });
163
+ break;
164
+ case "replace":
165
+ uni.redirectTo({
166
+ url,
167
+ success,
168
+ fail
169
+ });
170
+ break;
171
+ case "pushTab":
172
+ uni.switchTab({
173
+ url,
174
+ success,
175
+ fail
176
+ });
177
+ break;
178
+ case "replaceAll":
179
+ uni.reLaunch({
180
+ url,
181
+ success,
182
+ fail
183
+ });
184
+ break;
185
+ case "back":
186
+ uni.navigateBack({
187
+ success,
188
+ fail
189
+ });
190
+ break;
191
+ default: uni.navigateTo({
192
+ url,
193
+ success,
194
+ fail
195
+ });
196
+ }
197
+ });
168
198
  }
169
199
  async function runGuardQueue(guards, to, from) {
170
200
  for (const guard of guards) await new Promise((resolve$1, reject) => {
171
201
  const next = (val) => {
172
- if (val === false) reject(/* @__PURE__ */ new Error("NavigationCancelled"));
173
- else if (val === void 0) resolve$1();
174
- else {
175
- const error = /* @__PURE__ */ new Error("NavigationRedirect");
176
- error.to = val;
177
- reject(error);
178
- }
179
- };
180
- const res = guard(to, from, next);
181
- if (res instanceof Promise) res.then((val) => {
202
+ next._called = true;
182
203
  if (val === false) reject(/* @__PURE__ */ new Error("NavigationCancelled"));
183
204
  else if (val === void 0 || val === true) resolve$1();
184
205
  else {
@@ -186,14 +207,26 @@ function createRouter(options) {
186
207
  error.to = val;
187
208
  reject(error);
188
209
  }
189
- }).catch(reject);
190
- else if (res !== void 0 && typeof res !== "function") if (res === false) reject(/* @__PURE__ */ new Error("NavigationCancelled"));
191
- else if (res === true) resolve$1();
210
+ };
211
+ const guardReturn = guard(to, from, next);
212
+ let guardCall = Promise.resolve(guardReturn);
213
+ if (guard.length < 3) guardCall = guardCall.then(next);
192
214
  else {
193
- const error = /* @__PURE__ */ new Error("NavigationRedirect");
194
- error.to = res;
195
- reject(error);
215
+ const message = `The "next" callback was never called inside of ${guard.name ? `"${guard.name}"` : ""}:\n${guard.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`;
216
+ if (guardReturn !== null && typeof guardReturn === "object" && "then" in guardReturn) guardCall = guardCall.then((resolvedValue) => {
217
+ if (!next._called) {
218
+ console.warn(message);
219
+ return Promise.reject(/* @__PURE__ */ new Error("Invalid navigation guard"));
220
+ }
221
+ return resolvedValue;
222
+ });
223
+ else if (!next._called) {
224
+ console.warn(message);
225
+ reject(/* @__PURE__ */ new Error("Invalid navigation guard"));
226
+ return;
227
+ }
196
228
  }
229
+ guardCall.catch((err) => reject(err));
197
230
  });
198
231
  }
199
232
  function beforeEach(guard) {
@@ -237,6 +270,7 @@ function createRouter(options) {
237
270
  if (router$1.currentRoute.value.path === newPath) return;
238
271
  const from = unref(router$1.currentRoute);
239
272
  const matched = router$1.routes.find((r) => r.path === newPath || r.aliasPath === newPath);
273
+ if (!matched) console.warn(`[router] 路由 '${newPath}' 未在路由表中定义,但页面已加载。请检查您的路由配置。`);
240
274
  const to = {
241
275
  path: newPath,
242
276
  name: matched?.name,
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@wot-ui/router",
3
- "version": "0.0.4",
3
+ "version": "0.0.9",
4
4
  "description": "轻量级 uni-app vue3 路由库",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/wot-ui/my-uni.git",
8
+ "directory": "packages/router"
9
+ },
5
10
  "type": "module",
6
11
  "main": "dist/index.js",
7
12
  "module": "dist/index.mjs",
@@ -23,7 +28,10 @@
23
28
  "clean": "rimraf dist",
24
29
  "build": "tsdown",
25
30
  "dev": "tsdown --watch",
26
- "lint": "eslint --fix --ext .json,.js,.ts src"
31
+ "lint": "eslint --fix --ext .json,.js,.ts src",
32
+ "test": "vitest",
33
+ "test:ui": "vitest --ui",
34
+ "test:coverage": "vitest --coverage"
27
35
  },
28
36
  "license": "MIT",
29
37
  "keywords": [
@@ -42,19 +50,25 @@
42
50
  "@types/node": "^20.16.2",
43
51
  "@typescript-eslint/eslint-plugin": "^5.54.1",
44
52
  "@typescript-eslint/parser": "^5.54.1",
53
+ "@vitejs/plugin-vue": "^6.0.3",
54
+ "@vitest/ui": "^4.0.16",
55
+ "@vue/test-utils": "^2.4.6",
45
56
  "eslint": "^8.57.0",
46
57
  "eslint-config-prettier": "^8.7.0",
47
58
  "eslint-plugin-import": "^2.25.2",
48
59
  "eslint-plugin-n": "^15.0.0",
49
60
  "eslint-plugin-prettier": "^4.2.1",
50
61
  "git-cz": "^4.9.0",
62
+ "happy-dom": "^20.0.11",
51
63
  "husky": "^8.0.3",
64
+ "jsdom": "^27.3.0",
52
65
  "lint-staged": "^13.1.2",
53
66
  "prettier": "^2.8.4",
54
67
  "rimraf": "^4.4.0",
55
68
  "standard-version": "^9.5.0",
56
69
  "ts-jest": "^29.0.5",
57
70
  "tsdown": "^0.18.2",
58
- "typescript": "~5.5.4"
71
+ "typescript": "~5.5.4",
72
+ "vitest": "^4.0.16"
59
73
  }
60
74
  }