uni-router-enhance 1.0.5 → 1.0.6

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.d.mts CHANGED
@@ -2943,6 +2943,11 @@ interface RouteInfo<TName extends string> {
2943
2943
  handlerResult?: unknown;
2944
2944
  }
2945
2945
 
2946
+ type RouteNameStrategy = 'default' | 'package_page' | ((routePath: string) => string);
2947
+
2948
+ interface CreateRouterOptions {
2949
+ namingStrategy?: RouteNameStrategy;
2950
+ }
2946
2951
  type RouteHandler = (payload?: unknown) => unknown | Promise<unknown>;
2947
2952
  interface RouteLocationNormalized<TName extends string> {
2948
2953
  name: TName;
@@ -2965,13 +2970,19 @@ interface Router<TName extends string> {
2965
2970
  useRouter(): RouterHookResult<TName>;
2966
2971
  useRoute(): RouteInfo<TName>;
2967
2972
  }
2968
- declare function createRouter<const TRoutes extends Record<string, RouteMeta>>(routes: PagesConfig): Router<Extract<keyof TRoutes, string>>;
2969
- declare function createRouter<TName extends string>(routes?: PagesConfig): Router<TName>;
2973
+ declare function createRouter<const TRoutes extends Record<string, RouteMeta>>(routes: PagesConfig, options?: CreateRouterOptions): Router<Extract<keyof TRoutes, string>>;
2974
+ declare function createRouter<TName extends string>(routes?: PagesConfig, options?: CreateRouterOptions): Router<TName>;
2970
2975
 
2971
- declare function routeTypesPlugin(dts: string): {
2976
+ interface RouteTypesPluginOptions {
2977
+ dts: string;
2978
+ typeName?: string;
2979
+ generator?: (routeNames: string[], typeName: string) => string;
2980
+ namingStrategy?: RouteNameStrategy;
2981
+ }
2982
+ declare function routeTypesPlugin(options: string | RouteTypesPluginOptions): {
2972
2983
  name: string;
2973
2984
  buildStart(): void;
2974
2985
  handleHotUpdate(ctx: any): void;
2975
2986
  };
2976
2987
 
2977
- export { createRouter, routeTypesPlugin };
2988
+ export { type CreateRouterOptions, type RouteNameStrategy, type RouteTypesPluginOptions, createRouter, routeTypesPlugin };
package/dist/index.d.ts CHANGED
@@ -2943,6 +2943,11 @@ interface RouteInfo<TName extends string> {
2943
2943
  handlerResult?: unknown;
2944
2944
  }
2945
2945
 
2946
+ type RouteNameStrategy = 'default' | 'package_page' | ((routePath: string) => string);
2947
+
2948
+ interface CreateRouterOptions {
2949
+ namingStrategy?: RouteNameStrategy;
2950
+ }
2946
2951
  type RouteHandler = (payload?: unknown) => unknown | Promise<unknown>;
2947
2952
  interface RouteLocationNormalized<TName extends string> {
2948
2953
  name: TName;
@@ -2965,13 +2970,19 @@ interface Router<TName extends string> {
2965
2970
  useRouter(): RouterHookResult<TName>;
2966
2971
  useRoute(): RouteInfo<TName>;
2967
2972
  }
2968
- declare function createRouter<const TRoutes extends Record<string, RouteMeta>>(routes: PagesConfig): Router<Extract<keyof TRoutes, string>>;
2969
- declare function createRouter<TName extends string>(routes?: PagesConfig): Router<TName>;
2973
+ declare function createRouter<const TRoutes extends Record<string, RouteMeta>>(routes: PagesConfig, options?: CreateRouterOptions): Router<Extract<keyof TRoutes, string>>;
2974
+ declare function createRouter<TName extends string>(routes?: PagesConfig, options?: CreateRouterOptions): Router<TName>;
2970
2975
 
2971
- declare function routeTypesPlugin(dts: string): {
2976
+ interface RouteTypesPluginOptions {
2977
+ dts: string;
2978
+ typeName?: string;
2979
+ generator?: (routeNames: string[], typeName: string) => string;
2980
+ namingStrategy?: RouteNameStrategy;
2981
+ }
2982
+ declare function routeTypesPlugin(options: string | RouteTypesPluginOptions): {
2972
2983
  name: string;
2973
2984
  buildStart(): void;
2974
2985
  handleHotUpdate(ctx: any): void;
2975
2986
  };
2976
2987
 
2977
- export { createRouter, routeTypesPlugin };
2988
+ export { type CreateRouterOptions, type RouteNameStrategy, type RouteTypesPluginOptions, createRouter, routeTypesPlugin };
package/dist/index.js CHANGED
@@ -48,6 +48,20 @@ function extractSecondPathSegment(url) {
48
48
  const segments = url.split("/").slice(1, -1);
49
49
  return segments.length === 1 ? segments[0] : segments.join("_");
50
50
  }
51
+ var resolveRouteName = (routePath, strategy = "default") => {
52
+ if (typeof strategy === "function") {
53
+ return strategy(routePath);
54
+ }
55
+ const normalized = routePath.replace(/^\/+/, "").replace(/\.vue$/i, "");
56
+ if (strategy === "package_page") {
57
+ const segments = normalized.split("/").filter(Boolean);
58
+ if (segments[segments.length - 1] === "index") {
59
+ segments.pop();
60
+ }
61
+ return segments.length > 0 ? segments.join("_") : void 0;
62
+ }
63
+ return extractSecondPathSegment(routePath);
64
+ };
51
65
  var isEnumValue = (enumObject, value) => Object.values(enumObject).includes(value);
52
66
  var ensureLeadingSlash = (url) => url.startsWith("/") ? url : `/${url}`;
53
67
  var buildUrlWithQuery = (url, query) => {
@@ -68,7 +82,7 @@ var resolveCloseType = (close) => {
68
82
  if (typeof close === "string" && close in CloseTypes) return CloseTypes[close];
69
83
  return "default" /* default */;
70
84
  };
71
- function parseRoutesFromPagesJson(routes) {
85
+ function parseRoutesFromPagesJson(routes, namingStrategy = "default") {
72
86
  const routeMeta = /* @__PURE__ */ new Map();
73
87
  const tabBarPaths = /* @__PURE__ */ new Set();
74
88
  if (routes.tabBar?.list) {
@@ -78,7 +92,7 @@ function parseRoutesFromPagesJson(routes) {
78
92
  }
79
93
  if (routes.pages) {
80
94
  routes.pages.forEach((page) => {
81
- const name = extractSecondPathSegment(page.path);
95
+ const name = resolveRouteName(page.path, namingStrategy);
82
96
  if (name) {
83
97
  routeMeta.set(name, {
84
98
  ...page,
@@ -95,7 +109,7 @@ function parseRoutesFromPagesJson(routes) {
95
109
  const root = subpackage.root;
96
110
  subpackage.pages.forEach((page) => {
97
111
  const fullPath = `${root}/${page.path}`;
98
- const name = extractSecondPathSegment(fullPath);
112
+ const name = resolveRouteName(fullPath, namingStrategy);
99
113
  ;
100
114
  if (name) {
101
115
  routeMeta.set(name, {
@@ -144,7 +158,7 @@ function createRouterHook(router) {
144
158
  if (!currentPage?.route) {
145
159
  return "";
146
160
  }
147
- return extractSecondPathSegment(currentPage.route) || "";
161
+ return router.resolveNameByUrl(currentPage.route) || "";
148
162
  };
149
163
  const basicPush = async (input) => {
150
164
  const routeData = typeof input === "string" ? { path: input } : input;
@@ -330,7 +344,7 @@ function createRouteHook(router) {
330
344
  console.warn("\u65E0\u6CD5\u83B7\u53D6\u5F53\u524D\u9875\u9762\u7684\u8DEF\u7531\u4FE1\u606F");
331
345
  return;
332
346
  }
333
- const routeName = extractSecondPathSegment(currentPage.route);
347
+ const routeName = router.resolveNameByUrl(currentPage.route) || extractSecondPathSegment(currentPage.route);
334
348
  const meta = router.getRouteMeta(routeName);
335
349
  const cache = router.getPageCache(routeName);
336
350
  const runtimeQuery = resolvePageOptions(currentPage);
@@ -348,14 +362,15 @@ function createRouteHook(router) {
348
362
  }
349
363
 
350
364
  // src/create.ts
351
- function createRouter(routes) {
365
+ function createRouter(routes, options) {
352
366
  const handlers = /* @__PURE__ */ new Map();
353
367
  const beforeInterceptors = [];
354
368
  const afterInterceptors = [];
355
369
  const routeMeta = /* @__PURE__ */ new Map();
356
370
  const pageCache = /* @__PURE__ */ new Map();
371
+ const namingStrategy = options?.namingStrategy || "default";
357
372
  if (routes) {
358
- parseRoutesFromPagesJson(routes).forEach((meta, name) => {
373
+ parseRoutesFromPagesJson(routes, namingStrategy).forEach((meta, name) => {
359
374
  routeMeta.set(name, meta);
360
375
  });
361
376
  }
@@ -422,7 +437,14 @@ function createRouter(routes) {
422
437
  // 页面缓存管理方法
423
438
  setPageCache: (name, data) => pageCache.set(name, data),
424
439
  getPageCache: (name) => pageCache.get(name),
425
- deletePageCache: (name) => pageCache.delete(name)
440
+ deletePageCache: (name) => pageCache.delete(name),
441
+ resolveNameByUrl: (routePath) => {
442
+ const normalized = routePath.replace(/^\/+/, "");
443
+ for (const [name, meta] of routeMeta.entries()) {
444
+ if (meta.url === normalized) return name;
445
+ }
446
+ return void 0;
447
+ }
426
448
  };
427
449
  const useRouterFactory = () => createRouterHook(routerImpl);
428
450
  const useRouteFactory = () => createRouteHook(routerImpl);
@@ -447,11 +469,11 @@ function createRouter(routes) {
447
469
  // src/plugin.ts
448
470
  var import_fs = __toESM(require("fs"));
449
471
  var import_path = __toESM(require("path"));
450
- function extractRouteNamesFromPages(pagesJson) {
472
+ function extractRouteNamesFromPages(pagesJson, namingStrategy) {
451
473
  const routes = /* @__PURE__ */ new Set();
452
474
  if (pagesJson.pages) {
453
475
  pagesJson.pages.forEach((page) => {
454
- const name = extractSecondPathSegment(page.path);
476
+ const name = resolveRouteName(page.path, namingStrategy);
455
477
  if (name) {
456
478
  routes.add(name);
457
479
  }
@@ -461,7 +483,7 @@ function extractRouteNamesFromPages(pagesJson) {
461
483
  pagesJson.subPackages.forEach((subpackage) => {
462
484
  const root = subpackage.root;
463
485
  subpackage.pages.forEach((page) => {
464
- const name = extractSecondPathSegment(`${root}/${page.path}`);
486
+ const name = resolveRouteName(`${root}/${page.path}`, namingStrategy);
465
487
  if (name) {
466
488
  routes.add(name);
467
489
  }
@@ -470,19 +492,20 @@ function extractRouteNamesFromPages(pagesJson) {
470
492
  }
471
493
  return routes;
472
494
  }
473
- function generateTypeDefinition(routeNames) {
495
+ function generateTypeDefinition(routeNames, typeName = "ENHANCE_ROUTE_PATH") {
474
496
  const sortedRoutes = [...routeNames].sort((a, b) => a.localeCompare(b));
475
- return `export type ENHANCE_ROUTE_PATH =
497
+ return `export type ${typeName} =
476
498
  ${sortedRoutes.map((name) => ` | '${name}'`).join("\n")}`;
477
499
  }
478
500
  function readPagesJson(pagesJsonPath) {
479
501
  const content = import_fs.default.readFileSync(pagesJsonPath, "utf8");
480
502
  return JSON.parse(content);
481
503
  }
482
- function generateRouteTypeFile(dts, pagesJsonPath) {
504
+ function generateRouteTypeFile(dts, pagesJsonPath, options) {
483
505
  const pagesJson = readPagesJson(pagesJsonPath);
484
- const routeNames = extractRouteNamesFromPages(pagesJson);
485
- const typeDefinition = generateTypeDefinition(Array.from(routeNames));
506
+ const routeNames = extractRouteNamesFromPages(pagesJson, options?.namingStrategy || "default");
507
+ const typeName = options?.typeName || "ENHANCE_ROUTE_PATH";
508
+ const typeDefinition = options?.generator ? options.generator(Array.from(routeNames), typeName) : generateTypeDefinition(Array.from(routeNames), typeName);
486
509
  import_fs.default.writeFileSync(dts, typeDefinition, "utf8");
487
510
  }
488
511
  var getValidatedPaths = () => {
@@ -492,8 +515,9 @@ var getValidatedPaths = () => {
492
515
  }
493
516
  return import_path.default.resolve(inputDir, "pages.json");
494
517
  };
495
- function routeTypesPlugin(dts) {
518
+ function routeTypesPlugin(options) {
496
519
  let isFirstBuild = true;
520
+ const config = typeof options === "string" ? { dts: options } : options;
497
521
  return {
498
522
  name: "route-types-generator",
499
523
  /**
@@ -503,7 +527,11 @@ function routeTypesPlugin(dts) {
503
527
  if (isFirstBuild) {
504
528
  try {
505
529
  const pagesJsonPath = getValidatedPaths();
506
- generateRouteTypeFile(dts, pagesJsonPath);
530
+ generateRouteTypeFile(config.dts, pagesJsonPath, {
531
+ typeName: config.typeName,
532
+ generator: config.generator,
533
+ namingStrategy: config.namingStrategy
534
+ });
507
535
  isFirstBuild = false;
508
536
  } catch (error) {
509
537
  const message = error instanceof Error ? error.message : String(error);
@@ -518,7 +546,11 @@ function routeTypesPlugin(dts) {
518
546
  if (ctx.file.endsWith("pages.json")) {
519
547
  try {
520
548
  const pagesJsonPath = getValidatedPaths();
521
- generateRouteTypeFile(dts, pagesJsonPath);
549
+ generateRouteTypeFile(config.dts, pagesJsonPath, {
550
+ typeName: config.typeName,
551
+ generator: config.generator,
552
+ namingStrategy: config.namingStrategy
553
+ });
522
554
  console.log("\u{1F504} \u68C0\u6D4B\u5230 pages.json \u53D8\u5316\uFF0C\u5DF2\u81EA\u52A8\u66F4\u65B0\u8DEF\u7531\u7C7B\u578B");
523
555
  } catch (error) {
524
556
  const message = error instanceof Error ? error.message : String(error);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/type.ts","../src/utils.ts","../src/useRouter.ts","../src/useRoute.ts","../src/create.ts","../src/plugin.ts"],"sourcesContent":["import { createRouter } from './create';\r\nimport {routeTypesPlugin} from './plugin'\r\n\r\nexport {\r\n\tcreateRouter,\r\n\trouteTypesPlugin\r\n}","import type { PageMetaDatum } from './pages';\r\n\r\nexport enum CloseTypes {\r\n default = 'default',\r\n current = 'current',\r\n all = 'all',\r\n}\r\n\r\nexport interface RouteMeta extends PageMetaDatum {\r\n /** 页面对应的真实路径,例如:pages/home/index */\r\n url: string\r\n /** 是否为 tabBar 页面 */\r\n isTabBar?: boolean\r\n /**\r\n * 页面唯一key\r\n */\r\n name: string\r\n}\r\n\r\nexport interface RouterParams<TPath extends string> {\r\n /** 路由名称(来自 createRouter 注册的类型) */\r\n path?: TPath\r\n /** 需要传递给目标页面的查询参数 */\r\n query?: Record<string, any>\r\n /** 页面关闭策略 */\r\n close?: CloseTypes | keyof typeof CloseTypes\r\n /** 成功回调,可以接收 handler 的返回值 */\r\n success?: (result?: unknown) => void\r\n /** 失败回调 */\r\n fail?: (error?: any) => void\r\n}\r\n\r\n/** 类型安全的路由推送函数类型 */\r\nexport type TypeSafePush<TPath extends string> = (\r\n data: TPath | RouterParams<TPath>,\r\n callbacks?: {\r\n success?: (result?: unknown) => void\r\n fail?: (error?: any) => void\r\n }\r\n) => Promise<void>\r\n\r\n/**\r\n * 页面关闭策略输入类型\r\n */\r\nexport type CloseInput = CloseTypes | keyof typeof CloseTypes | undefined;\r\n\r\n\r\n","import { PagesConfig } from \"./pages\";\r\nimport { CloseInput, CloseTypes, RouteMeta } from \"./type\";\r\n\r\n/**\r\n * 提取URL路径的第二段或者将多段路径用下划线连接\r\n * @param url 需要处理的URL\r\n * @returns 处理后的字符串\r\n */\r\nexport function extractSecondPathSegment(url: string): string {\r\n\tconst segments = url.split(\"/\").slice(1, -1);\r\n\treturn segments.length === 1 ? segments[0] : segments.join(\"_\");\r\n}\r\n\r\nconst isEnumValue = <T extends Record<string, string>>(enumObject: T, value: unknown): value is T[keyof T] =>\r\n\tObject.values(enumObject).includes(value as T[keyof T]);\r\n\r\nexport const ensureLeadingSlash = (url: string): string => (url.startsWith(\"/\") ? url : `/${url}`);\r\n\r\nexport const buildUrlWithQuery = (url: string, query: Record<string, any>): string => {\r\n\tconst normalized = ensureLeadingSlash(url);\r\n\tconst queryEntries = Object.entries(query ?? {}).filter(([, value]) => value !== undefined);\r\n\tif (queryEntries.length === 0) {\r\n\t\treturn normalized;\r\n\t}\r\n\r\n\tconst queryString = queryEntries\r\n\t\t.map(([key, value]) => {\r\n\t\t\tconst serialized = typeof value === \"object\" && value !== null ? JSON.stringify(value) : String(value);\r\n\t\t\treturn `${encodeURIComponent(key)}=${encodeURIComponent(serialized)}`;\r\n\t\t})\r\n\t\t.join(\"&\");\r\n\r\n\treturn `${normalized}?${queryString}`;\r\n};\r\nexport const resolveCloseType = (close: CloseInput): CloseTypes => {\r\n\tif (!close) return CloseTypes.default;\r\n\tif (isEnumValue(CloseTypes, close)) return close;\r\n\tif (typeof close === \"string\" && close in CloseTypes) return CloseTypes[close as keyof typeof CloseTypes];\r\n\treturn CloseTypes.default;\r\n};\r\n\r\n/**\r\n * 从 pages.json 解析路由信息\r\n * @param routes - pages.json 配置对象\r\n * @returns 路由元信息映射\r\n */\r\nexport function parseRoutesFromPagesJson<TName extends string>(routes: PagesConfig) {\r\n\tconst routeMeta = new Map<TName, RouteMeta>();\r\n\t// 获取 TabBar 页面路径集合\r\n\tconst tabBarPaths = new Set<string>();\r\n\tif (routes.tabBar?.list) {\r\n\t\troutes.tabBar.list.forEach(item => {\r\n\t\t\ttabBarPaths.add(item.pagePath);\r\n\t\t});\r\n\t}\r\n\r\n\t// 处理主包页面\r\n\tif (routes.pages) {\r\n\t\troutes.pages.forEach(page => {\r\n\t\t\tconst name = extractSecondPathSegment(page.path) as TName;\r\n\t\t\tif (name) {\r\n\t\t\t\trouteMeta.set(name, {\r\n\t\t\t\t\t...page,\r\n\t\t\t\t\tname,\r\n\t\t\t\t\tisTabBar: tabBarPaths.has(page.path) || page.type === \"tabBar\",\r\n\t\t\t\t\turl: page.path,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\tif (routes.subPackages) {\r\n\t\t// 处理分包页面\r\n\t\tconst subpackages = routes.subPackages;\r\n\t\tsubpackages.forEach(subpackage => {\r\n\t\t\tconst root = subpackage.root;\r\n\t\t\tsubpackage.pages.forEach(page => {\r\n\t\t\t\tconst fullPath = `${root}/${page.path}`;\r\n\t\t\t\tconst name = extractSecondPathSegment(fullPath) as TName;;\r\n\t\t\t\tif (name) {\r\n\t\t\t\t\trouteMeta.set(name, {\r\n\t\t\t\t\t\t...page,\r\n\t\t\t\t\t\tname,\r\n\t\t\t\t\t\tisTabBar: tabBarPaths.has(fullPath) || page.type === \"tabBar\",\r\n\t\t\t\t\t\turl: fullPath,\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\treturn routeMeta;\r\n}\r\n","import type { RouterCore } from './create';\r\nimport type { RouteLocationNormalized, RouteLocationRaw } from './create';\r\nimport { CloseTypes, RouterParams, TypeSafePush } from './type';\r\nimport { ensureLeadingSlash, buildUrlWithQuery, resolveCloseType, extractSecondPathSegment } from './utils';\r\n\r\n\r\nconst performNavigation = async (url: string, close: CloseTypes): Promise<void> => {\r\n\tconst navigationMethods: Record<CloseTypes, (options: UniApp.NavigateToOptions) => Promise<void>> = {\r\n\t\t[CloseTypes.default]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.navigateTo({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t\t[CloseTypes.current]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.redirectTo({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t\t[CloseTypes.all]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.reLaunch({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t};\r\n\r\n\tawait navigationMethods[close]({ url });\r\n};\r\n\r\nexport type RouterHookResult<TPath extends string> = {\r\n\t/** 类型安全的路由跳转方法 */\r\n\tpush: TypeSafePush<TPath>;\r\n};\r\n\r\n/**\r\n * 创建与指定 Router 实例绑定的路由钩子,避免在调用端重复传参。\r\n */\r\nexport function createRouterHook<TName extends string>(router: RouterCore<TName>): RouterHookResult<TName> {\r\n\t/**\r\n\t * 获取当前路由名称\r\n\t */\r\n\tconst getCurrentRouteName = (): TName | '' => {\r\n\t\tconst currentPage = getCurrentPages().at(-1);\r\n\t\tif (!currentPage?.route) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn (extractSecondPathSegment(currentPage.route) as TName) || '';\r\n\t};\r\n\r\n\t/**\r\n\t * 统一的路由跳转实现:先触发 createRouter 注册的拦截器与处理器,再执行实际跳转。\r\n\t */\r\n\tconst basicPush = async (input: TName | RouterParams<TName>): Promise<void> => {\r\n\t\tconst routeData = typeof input === 'string' ? { path: input } : input;\r\n\t\tconst path = routeData.path;\r\n\t\tif (!path) {\r\n\t\t\tconst error = new Error('路由名称不能为空');\r\n\t\t\trouteData.fail?.(error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst meta = router.getRouteMeta(path);\r\n\t\tif (!meta) {\r\n\t\t\tconst error = new Error(`找不到匹配的路由配置: ${String(path)}`);\r\n\t\t\trouteData.fail?.(error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst query = routeData.query ?? {};\r\n\t\tconst closeType = resolveCloseType(routeData.close);\r\n\r\n\t\tconst routePayload = { query, closeType, meta };\r\n\r\n\t\t// 获取来源路由信息\r\n\t\tconst fromName = getCurrentRouteName();\r\n\t\tconst fromMeta = fromName ? router.getRouteMeta(fromName) : undefined;\r\n\r\n\t\t// 创建标准化的路由位置对象\r\n\t\tconst to: RouteLocationNormalized<TName> = {\r\n\t\t\tname: path,\r\n\t\t\tmeta,\r\n\t\t\tquery,\r\n\t\t\tpath: meta.url,\r\n\t\t};\r\n\r\n\t\tconst from: RouteLocationNormalized<TName> = {\r\n\t\t\tname: fromName || ('' as TName),\r\n\t\t\tmeta: fromMeta,\r\n\t\t\tquery: {},\r\n\t\t\tpath: fromMeta?.url || '',\r\n\t\t};\r\n\r\n\t\tlet navigationResult: unknown;\r\n\t\tlet redirectTo: RouteLocationRaw<TName> | undefined;\r\n\r\n\t\ttry {\r\n\t\t\t// 执行 beforeEach 导航守卫\r\n\t\t\tconst beforeResult = await router.runBeforeInterceptors(to, from);\r\n\r\n\t\t\tif (!beforeResult.shouldContinue) {\r\n\t\t\t\t// 导航被取消\r\n\t\t\t\tif (beforeResult.redirectTo) {\r\n\t\t\t\t\t// 重定向到其他路由\r\n\t\t\t\t\tredirectTo = beforeResult.redirectTo;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 完全取消导航\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} catch (error) {\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 如果有重定向,递归调用 push\r\n\t\tif (redirectTo) {\r\n\t\t\tif (typeof redirectTo === 'string') {\r\n\t\t\t\t// 简单的路由名称重定向\r\n\t\t\t\treturn basicPush(\r\n\t\t\t\t\ttypeof routeData === 'object'\r\n\t\t\t\t\t\t? { ...routeData, path: redirectTo }\r\n\t\t\t\t\t\t: redirectTo\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\t// 路由对象重定向\r\n\t\t\t\treturn basicPush({\r\n\t\t\t\t\t...routeData,\r\n\t\t\t\t\tpath: redirectTo.path,\r\n\t\t\t\t\tquery: redirectTo.query || routeData.query,\r\n\t\t\t\t\t// TODO: 处理 replace 选项\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// 执行 handler\r\n\t\ttry {\r\n\t\t\tconst handler = router.getHandler(path);\r\n\t\t\tnavigationResult = handler ? await handler(routePayload) : undefined;\r\n\t\t\tawait router.runAfterInterceptors(to, from);\r\n\t\t} catch (error) {\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (navigationResult === false) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 将 query 和 handler 返回值一起缓存,供目标页面使用\r\n\t\trouter.setPageCache(path, {\r\n\t\t\tquery,\r\n\t\t\thandlerResult: navigationResult,\r\n\t\t});\r\n\r\n\t\ttry {\r\n\t\t\tif (meta.isTabBar) {\r\n\t\t\t\tif (Object.keys(query).length > 0) {\r\n\t\t\t\t\tconsole.warn('跳转 tabBar 页面时会忽略 query 参数');\r\n\t\t\t\t}\r\n\t\t\t\tawait new Promise<void>((resolve, reject) => {\r\n\t\t\t\t\tuni.switchTab({\r\n\t\t\t\t\t\turl: ensureLeadingSlash(meta.url),\r\n\t\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tawait performNavigation(buildUrlWithQuery(meta.url, query), closeType);\r\n\t\t\t}\r\n\r\n\t\t\t// 成功回调,传递 handler 的返回值(仅用于通知跳转成功)\r\n\t\t\trouteData.success?.(navigationResult);\r\n\t\t} catch (error) {\r\n\t\t\trouter.deletePageCache(path);\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t}\r\n\t};\r\n\r\n\t/**\r\n\t * 导出给外部使用的 push,支持额外回调合并。\r\n\t */\r\n\tconst push: TypeSafePush<TName> = async (data, callbacks) => {\r\n\t\tif (data == null) {\r\n\t\t\tconst error = new Error('路由参数不能为空');\r\n\t\t\tcallbacks?.fail?.(error);\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\tconst routeData = typeof data === 'string' ? { path: data } : data;\r\n\t\tconst finalRouteData: RouterParams<TName> = {\r\n\t\t\t...routeData,\r\n\t\t\tsuccess: callbacks?.success ?? routeData.success,\r\n\t\t\tfail: callbacks?.fail ?? routeData.fail,\r\n\t\t};\r\n\r\n\t\tawait basicPush(finalRouteData);\r\n\t};\r\n\r\n\treturn {\r\n\t\tpush\r\n\t}\r\n}","import { onMounted, reactive } from 'vue';\r\nimport type { UnwrapRef } from 'vue';\r\nimport type { RouterCore } from './create';\r\nimport type { RouteMeta } from './type';\r\nimport { extractSecondPathSegment } from './utils';\r\n\r\n/**\r\n * 扩展 uni-app 页面实例类型,包含 options 属性\r\n */\r\ninterface UniPageInstance extends Page.PageInstance<AnyObject, Record<string, any>> {\r\n\t/** 页面路由路径 */\r\n\troute?: string;\r\n\t/** 页面 URL 查询参数 */\r\n\toptions?: Record<string, string>;\r\n}\r\n\r\ntype RuntimePageInstance = UniPageInstance & {\r\n\t$page?: {\r\n\t\toptions?: Record<string, string>;\r\n\t\tfullPath?: string;\r\n\t};\r\n};\r\n\r\nconst decodeQuery = (query: Record<string, any>): Record<string, any> => {\r\n\tconst decoded: Record<string, any> = {};\r\n\tfor (const key in query) {\r\n\t\tconst value = query[key];\r\n\t\tif (typeof value === 'string') {\r\n\t\t\ttry {\r\n\t\t\t\tdecoded[key] = decodeURIComponent(value);\r\n\t\t\t} catch {\r\n\t\t\t\tdecoded[key] = value;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tdecoded[key] = value;\r\n\t\t}\r\n\t}\r\n\treturn decoded;\r\n};\r\n\r\nconst parseQueryString = (queryString?: string): Record<string, string> => {\r\n\tif (!queryString) return {};\r\n\treturn queryString.split(\"&\").reduce<Record<string, string>>((acc, segment) => {\r\n\t\tif (!segment) return acc;\r\n\t\tconst [rawKey, rawValue = \"\"] = segment.split(\"=\");\r\n\t\tconst key = decodeURIComponent(rawKey);\r\n\t\tconst value = decodeURIComponent(rawValue);\r\n\t\tacc[key] = value;\r\n\t\treturn acc;\r\n\t}, {});\r\n};\r\n\r\nconst resolvePageOptions = (page?: UniPageInstance): Record<string, any> => {\r\n\tif (!page) return {};\r\n\tconst runtimePage = page as RuntimePageInstance;\r\n\tconst sources: Record<string, any>[] = [];\r\n\r\n\tif (page.options && Object.keys(page.options).length > 0) {\r\n\t\tsources.push(decodeQuery(page.options));\r\n\t}\r\n\r\n\tif (runtimePage.$page?.options && Object.keys(runtimePage.$page.options).length > 0) {\r\n\t\tsources.push(decodeQuery(runtimePage.$page.options));\r\n\t}\r\n\r\n\tif (runtimePage.$page?.fullPath) {\r\n\t\tconst queryIndex = runtimePage.$page.fullPath.indexOf(\"?\");\r\n\t\tif (queryIndex !== -1) {\r\n\t\t\tsources.push(parseQueryString(runtimePage.$page.fullPath.slice(queryIndex + 1)));\r\n\t\t}\r\n\t}\r\n\r\n\tif (sources.length === 0) {\r\n\t\treturn {};\r\n\t}\r\n\r\n\treturn Object.assign({}, ...sources);\r\n};\r\n\r\n/**\r\n * useRoute 返回的路由信息\r\n */\r\nexport interface RouteInfo<TName extends string> {\r\n\t/** 路由名称 */\r\n\tname: TName;\r\n\t/** 路由元信息 */\r\n\tmeta?: RouteMeta;\r\n\t/** 合并后的查询参数(包含 URL 参数和缓存参数) */\r\n\tquery: Record<string, any>;\r\n\t/** Handler 返回值 */\r\n\thandlerResult?: unknown;\r\n}\r\n\r\n/**\r\n * 创建路由钩子,获取当前页面的路由信息\r\n * @param router - Router 核心实例\r\n * @returns 当前页面的路由信息\r\n */\r\nexport function createRouteHook<TName extends string>(router: RouterCore<TName>): RouteInfo<TName> {\r\n\t// 初始化响应式状态,在组件挂载后填充运行时数据\r\n\tconst state = reactive<RouteInfo<TName>>({\r\n\t\tname: '' as TName,\r\n\t\tmeta: undefined,\r\n\t\tquery: {},\r\n\t\thandlerResult: undefined,\r\n\t});\r\n\r\n\tonMounted(() => {\r\n\t\t// 获取当前页面实例\r\n\t\tconst pages = getCurrentPages();\r\n\t\tconst currentPage = pages[pages.length - 1] as UniPageInstance | undefined;\r\n\r\n\t\t// 如果没有当前页面,保留默认空状态并打印警告\r\n\t\tif (!currentPage?.route) {\r\n\t\t\t// 运行时未能获取到 page 实例\r\n\t\t\t// 不抛错,只是保留空状态以避免阻断调用方\r\n\t\t\t// 日志便于调试\r\n\t\t\t// eslint-disable-next-line no-console\r\n\t\t\tconsole.warn('无法获取当前页面的路由信息');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 从路由路径提取路由名称\r\n\t\tconst routeName = extractSecondPathSegment(currentPage.route) as TName;\r\n\r\n\t\t// 获取路由元信息\r\n\t\tconst meta = router.getRouteMeta(routeName);\r\n\r\n\t\t// 获取页面缓存数据(包含 query 和 handlerResult)\r\n\t\tconst cache = router.getPageCache(routeName as TName);\r\n\r\n\t\tconst runtimeQuery = resolvePageOptions(currentPage);\r\n\r\n\t\t// 合并查询参数: URL 中的参数为基础,缓存的 query(如果存在)覆盖它以保留原始类型\r\n\t\tconst mergedQuery: Record<string, any> = {\r\n\t\t\t...runtimeQuery,\r\n\t\t\t...(cache?.query ? decodeQuery(cache.query) : {}),\r\n\t\t};\r\n\t\tstate.name = routeName as unknown as UnwrapRef<TName>;\r\n\t\tstate.meta = meta;\r\n\t\tstate.query = mergedQuery;\r\n\t\tstate.handlerResult = cache?.handlerResult;\r\n\t\tstate.handlerResult = cache?.handlerResult;\r\n\t});\r\n\r\n\t// 类型声明需要一个普通的 `RouteInfo<TName>`,将响应式对象断言为该类型以兼容 d.ts 输出。\r\n\treturn state as unknown as RouteInfo<TName>;\r\n}","import { createRouterHook, RouterHookResult } from './useRouter';\r\nimport { createRouteHook, RouteInfo } from './useRoute';\r\nimport type { RouteMeta } from './type';\r\nimport { PagesConfig } from './pages';\r\nimport { parseRoutesFromPagesJson } from './utils';\r\n\r\n// 导出类型供外部使用\r\nexport type { RouteInfo, RouterHookResult, RouteMeta };\r\nexport { CloseTypes, RouterParams } from './type';\r\n\r\ntype RouteHandler = (payload?: unknown) => unknown | Promise<unknown>;\r\n\r\n/**\r\n * 标准化的路由位置\r\n */\r\nexport interface RouteLocationNormalized<TName extends string> {\r\n /** 路由名称 */\r\n name: TName;\r\n /** 路由元信息 */\r\n meta?: RouteMeta;\r\n /** 查询参数 */\r\n query: Record<string, any>;\r\n /** 完整路径 */\r\n path: string;\r\n}\r\n\r\n/**\r\n * 路由地址(用于重定向)\r\n */\r\nexport type RouteLocationRaw<TName extends string> =\r\n | TName\r\n | {\r\n path: TName;\r\n query?: Record<string, any>;\r\n replace?: boolean;\r\n };\r\n\r\n/**\r\n * 路由守卫函数类型\r\n * @param to 即将要进入的目标路由\r\n * @param from 当前导航正要离开的路由\r\n * @returns \r\n * - false: 取消当前导航\r\n * - RouteLocationRaw: 重定向到不同的地址\r\n * - undefined/true/void: 继续导航\r\n */\r\nexport type NavigationGuard<TName extends string> = (\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n) => void | boolean | RouteLocationRaw<TName> | Promise<void | boolean | RouteLocationRaw<TName>>;\r\n\r\n\r\n\r\n/**\r\n * Router 核心能力:注册处理函数与拦截器,并存储元信息。\r\n */\r\nexport interface RouterCore<TName extends string> {\r\n /**\r\n * 注册一个路由处理函数。返回一个取消订阅(卸载)函数,用于移除该处理函数。\r\n */\r\n register(name: TName, handler: RouteHandler): () => void;\r\n /**\r\n * 通过名称移除已注册的处理函数。若存在则返回 true。\r\n */\r\n unregister(name: TName): boolean;\r\n /**\r\n * 检查是否已为给定名称注册处理函数。\r\n */\r\n has(name: TName): boolean;\r\n /**\r\n * 获取指定路由名称对应的处理函数。\r\n */\r\n getHandler(name: TName): RouteHandler | undefined;\r\n /**\r\n * 添加一个 beforeEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n beforeEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 添加一个 afterEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n afterEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 记录路由元信息,返回一个用于撤销注册的函数。\r\n */\r\n defineRoute(name: TName, meta: RouteMeta): () => void;\r\n /**\r\n * 获取对应路由的元信息。\r\n */\r\n getRouteMeta(name: TName): RouteMeta | undefined;\r\n /**\r\n * 获取所有路由的元信息快照。\r\n */\r\n listRouteMeta(): ReadonlyMap<TName, RouteMeta>;\r\n /**\r\n * 手动执行 beforeEach 导航守卫链。\r\n * @returns 返回导航控制结果\r\n */\r\n runBeforeInterceptors(\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<{ shouldContinue: boolean; redirectTo?: RouteLocationRaw<TName> }>;\r\n /**\r\n * 手动执行 afterEach 导航守卫链。\r\n */\r\n runAfterInterceptors(to: RouteLocationNormalized<TName>, from: RouteLocationNormalized<TName>): Promise<void>;\r\n /**\r\n * 设置页面缓存数据(query 和 handler 返回值)\r\n */\r\n setPageCache(url: TName, data: { query: Record<string, any>; handlerResult?: unknown }): void;\r\n /**\r\n * 获取页面缓存数据\r\n */\r\n getPageCache(url: TName): { query: Record<string, any>; handlerResult?: unknown } | undefined;\r\n /**\r\n * 删除页面缓存数据\r\n */\r\n deletePageCache(url: TName): void;\r\n}\r\n\r\n/**\r\n * Router 对外暴露的完整接口,只包含公开的方法。\r\n */\r\nexport interface Router<TName extends string> {\r\n /**\r\n * 注册一个路由处理函数。返回一个取消订阅(卸载)函数,用于移除该处理函数。\r\n */\r\n register(name: TName, handler: RouteHandler): () => void;\r\n /**\r\n * 通过名称移除已注册的处理函数。若存在则返回 true。\r\n */\r\n unregister(name: TName): boolean;\r\n /**\r\n * 检查是否已为给定名称注册处理函数。\r\n */\r\n has(name: TName): boolean;\r\n /**\r\n * 添加一个 beforeEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n beforeEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 添加一个 afterEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n afterEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 生成绑定当前 Router 实例的 useRouter 钩子。\r\n */\r\n useRouter(): RouterHookResult<TName>;\r\n /**\r\n * 生成绑定当前 Router 实例的 useRoute 钩子,获取当前页面的路由信息。\r\n */\r\n useRoute(): RouteInfo<TName>;\r\n}\r\n\r\n/**\r\n * 创建一个路由实例,泛型 TName 表示允许的路由名称(通常为字符串字面量联合类型)。\r\n */\r\nexport function createRouter<const TRoutes extends Record<string, RouteMeta>>(routes: PagesConfig): Router<Extract<keyof TRoutes, string>>;\r\nexport function createRouter<TName extends string>(routes?: PagesConfig): Router<TName>;\r\nexport function createRouter<TName extends string>(routes?: PagesConfig): Router<TName> {\r\n // 存储路由处理函数的映射表\r\n const handlers = new Map<TName, RouteHandler>();\r\n // beforeEach 导航守卫数组\r\n const beforeInterceptors: NavigationGuard<TName>[] = [];\r\n // afterEach 导航守卫数组\r\n const afterInterceptors: NavigationGuard<TName>[] = [];\r\n // 路由元信息映射表\r\n const routeMeta = new Map<TName, RouteMeta>();\r\n // 页面缓存: 存储 query 和 handler 返回值\r\n const pageCache = new Map<TName, { query: Record<string, any>; handlerResult?: unknown }>();\r\n\r\n // 如果提供了 pages.json 配置,解析并注册所有路由\r\n if (routes) {\r\n parseRoutesFromPagesJson(routes).forEach((meta, name) => {\r\n routeMeta.set(name as TName, meta);\r\n });\r\n }\r\n\r\n /**\r\n * 添加守卫到指定的守卫数组\r\n * @param bucket 守卫数组\r\n * @param guard 要添加的守卫函数\r\n * @returns 返回一个卸载函数,调用后可移除该守卫\r\n */\r\n const addInterceptor = (bucket: NavigationGuard<TName>[], guard: NavigationGuard<TName>) => {\r\n bucket.push(guard);\r\n return () => {\r\n const index = bucket.indexOf(guard);\r\n if (index >= 0) bucket.splice(index, 1);\r\n };\r\n };\r\n /**\r\n * 执行导航守卫链\r\n * 按注册顺序依次执行守卫,任何守卫返回 false 或重定向地址都会中断后续守卫的执行\r\n * @param bucket 守卫数组\r\n * @param to 目标路由位置\r\n * @param from 来源路由位置\r\n * @returns 返回导航控制结果\r\n * - shouldContinue: true 表示继续导航, false 表示取消导航\r\n * - redirectTo: 如果存在,表示重定向到该地址\r\n */\r\n const runInterceptors = async (\r\n bucket: NavigationGuard<TName>[],\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<{ shouldContinue: boolean; redirectTo?: RouteLocationRaw<TName> }> => {\r\n for (const guard of bucket) {\r\n // 在循环中 await,以支持异步守卫的顺序执行\r\n // eslint-disable-next-line no-await-in-loop\r\n const result = await guard(to, from);\r\n\r\n // 处理守卫返回值\r\n if (result === false) {\r\n // 返回 false 取消导航\r\n return { shouldContinue: false };\r\n }\r\n\r\n if (result && typeof result === 'object' && 'path' in result) {\r\n // 返回路由对象重定向 { path: 'home', query: {...}, replace: true }\r\n return { shouldContinue: false, redirectTo: result };\r\n }\r\n\r\n if (typeof result === 'string') {\r\n // 返回路由名称字符串重定向\r\n return { shouldContinue: false, redirectTo: result as TName };\r\n }\r\n\r\n // result 为 undefined 或 true,继续执行下一个守卫\r\n }\r\n\r\n // 所有守卫都通过,允许导航继续\r\n return { shouldContinue: true };\r\n };\r\n\r\n /**\r\n * 执行 after 守卫链(不支持导航控制,仅用于通知)\r\n * after 守卫在导航完成后执行,无法阻止或重定向导航\r\n * @param bucket 守卫数组\r\n * @param to 目标路由位置\r\n * @param from 来源路由位置\r\n */\r\n const runAfterInterceptors = async (\r\n bucket: NavigationGuard<TName>[],\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<void> => {\r\n for (const guard of bucket) {\r\n // 按顺序执行所有 after 守卫\r\n // eslint-disable-next-line no-await-in-loop\r\n await guard(to, from);\r\n }\r\n };\r\n\r\n\r\n\r\n // Router 核心实现对象,包含所有内部方法\r\n const routerImpl: RouterCore<TName> = {\r\n // 注册路由处理函数\r\n register: (name, handler) => {\r\n handlers.set(name, handler);\r\n // 返回卸载函数\r\n return () => {\r\n handlers.delete(name);\r\n };\r\n },\r\n // 移除路由处理函数\r\n unregister: (name) => handlers.delete(name),\r\n // 检查是否已注册处理函数\r\n has: (name) => handlers.has(name),\r\n // 获取路由处理函数\r\n getHandler: (name) => handlers.get(name),\r\n // 添加 beforeEach 守卫\r\n beforeEach: (interceptor) => addInterceptor(beforeInterceptors, interceptor),\r\n // 添加 afterEach 守卫\r\n afterEach: (interceptor) => addInterceptor(afterInterceptors, interceptor),\r\n // 定义路由元信息\r\n defineRoute: (name, meta) => {\r\n routeMeta.set(name, meta);\r\n // 返回撤销函数\r\n return () => {\r\n routeMeta.delete(name);\r\n };\r\n },\r\n // 获取路由元信息\r\n getRouteMeta: (name) => routeMeta.get(name),\r\n // 获取所有路由元信息的只读快照\r\n listRouteMeta: () => new Map(routeMeta),\r\n // 执行 beforeEach 守卫链\r\n runBeforeInterceptors: (to, from) => runInterceptors(beforeInterceptors, to, from),\r\n // 执行 afterEach 守卫链\r\n runAfterInterceptors: (to, from) => runAfterInterceptors(afterInterceptors, to, from),\r\n // 页面缓存管理方法\r\n setPageCache: (name, data) => pageCache.set(name, data),\r\n getPageCache: (name) => pageCache.get(name),\r\n deletePageCache: (name) => pageCache.delete(name),\r\n };\r\n\r\n // 创建 useRouter 工厂函数,闭包持有完整的 routerImpl\r\n const useRouterFactory = () => createRouterHook(routerImpl);\r\n // 创建 useRoute 工厂函数,闭包持有完整的 routerImpl\r\n const useRouteFactory = () => createRouteHook(routerImpl);\r\n\r\n // 只返回公开的方法,隐藏内部实现细节\r\n return {\r\n afterEach: routerImpl.afterEach, // 注册 afterEach 守卫\r\n beforeEach: routerImpl.beforeEach, // 注册 beforeEach 守卫\r\n register: routerImpl.register, // 注册路由处理函数\r\n unregister: routerImpl.unregister, // 移除路由处理函数\r\n has: routerImpl.has, // 检查处理函数是否存在\r\n useRouter: useRouterFactory, // 创建 useRouter 钩子\r\n useRoute: useRouteFactory // 创建 useRoute 钩子\r\n } as Router<TName>;\r\n}\r\n","import { PagesConfig } from \"./pages\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { extractSecondPathSegment } from \"./utils\";\r\n\r\n\r\n\r\n/**\r\n * 从 pages.json 中提取所有路由名称\r\n * @param pagesJson pages.json 配置对象\r\n * @returns 路由名称的 Set 集合\r\n */\r\nfunction extractRouteNamesFromPages(pagesJson: PagesConfig): Set<string> {\r\n\tconst routes = new Set<string>();\r\n\r\n\t// 处理主包页面\r\n\tif (pagesJson.pages) {\r\n\t\tpagesJson.pages.forEach(page => {\r\n\t\t\tconst name = extractSecondPathSegment(page.path);\r\n\t\t\tif (name) {\r\n\t\t\t\troutes.add(name);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t// 处理分包页面\r\n\tif (pagesJson.subPackages) {\r\n\t\tpagesJson.subPackages.forEach(subpackage => {\r\n\t\t\tconst root = subpackage.root;\r\n\t\t\tsubpackage.pages.forEach(page => {\r\n\t\t\t\tconst name = extractSecondPathSegment(`${root}/${page.path}`);\r\n\t\t\t\tif (name) {\r\n\t\t\t\t\troutes.add(name);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\treturn routes;\r\n}\r\n\r\n/**\r\n * 生成路由类型定义字符串\r\n * @param routeNames 路由名称数组\r\n * @returns TypeScript 类型定义字符串\r\n */\r\nfunction generateTypeDefinition(routeNames: string[]): string {\r\n\tconst sortedRoutes = [...routeNames].sort((a, b) => a.localeCompare(b));\r\n\treturn `export type ENHANCE_ROUTE_PATH =\\n${sortedRoutes.map(name => ` | '${name}'`).join('\\n')}`;\r\n}\r\n\r\n/**\r\n * 读取并解析 pages.json 文件\r\n * @param pagesJsonPath pages.json 文件路径\r\n * @returns 解析后的配置对象\r\n */\r\nfunction readPagesJson(pagesJsonPath: string): PagesConfig {\r\n\tconst content = fs.readFileSync(pagesJsonPath, 'utf8');\r\n\treturn JSON.parse(content);\r\n}\r\n\r\n/**\r\n * 生成路由类型文件\r\n * @param dts 类型文件输出路径\r\n * @param pagesJsonPath pages.json 文件路径\r\n */\r\nfunction generateRouteTypeFile(dts: string, pagesJsonPath: string): void {\r\n\tconst pagesJson = readPagesJson(pagesJsonPath);\r\n\tconst routeNames = extractRouteNamesFromPages(pagesJson);\r\n\tconst typeDefinition = generateTypeDefinition(Array.from(routeNames));\r\n\tfs.writeFileSync(dts, typeDefinition, 'utf8');\r\n}\r\n\r\n// 环境配置验证\r\nconst getValidatedPaths = () => {\r\n\tconst inputDir = process.env.UNI_INPUT_DIR || `${process.env.INIT_CWD}/src`;\r\n\tif (!inputDir || inputDir.trim() === '') {\r\n\t\tthrow new Error('Missing required environment variables: UNI_INPUT_DIR or INIT_CWD');\r\n\t}\r\n\treturn path.resolve(inputDir, 'pages.json')\r\n};\r\n\r\n/**\r\n * Vite 插件: 自动生成路由类型定义\r\n * @param dts 类型文件输出路径\r\n * @returns Vite 插件对象\r\n */\r\nexport function routeTypesPlugin(dts: string) {\r\n\tlet isFirstBuild = true;\r\n\r\n\treturn {\r\n\t\tname: 'route-types-generator',\r\n\t\t/**\r\n\t\t * 构建开始时生成路由类型\r\n\t\t */\r\n\t\tbuildStart() {\r\n\t\t\t// 只在首次构建时生成类型,避免重复生成\r\n\t\t\tif (isFirstBuild) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst pagesJsonPath = getValidatedPaths();\r\n\t\t\t\t\tgenerateRouteTypeFile(dts, pagesJsonPath);\r\n\t\t\t\t\tisFirstBuild = false;\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\r\n\t\t\t\t\tconsole.warn('路由类型生成失败:', message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\t/**\r\n\t\t * 热更新时监听 pages.json 变化\r\n\t\t */\r\n\t\thandleHotUpdate(ctx: any) {\r\n\t\t\t// 监听 pages.json 变化,自动重新生成类型\r\n\t\t\tif (ctx.file.endsWith('pages.json')) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst pagesJsonPath = getValidatedPaths();\r\n\r\n\r\n\t\t\t\t\tgenerateRouteTypeFile(dts, pagesJsonPath);\r\n\t\t\t\t\tconsole.log('🔄 检测到 pages.json 变化,已自动更新路由类型');\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\r\n\t\t\t\t\tconsole.warn('热更新时生成路由类型失败:', message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t};\r\n}\r\n\r\n"],"mappings":"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","names":["CloseTypes","path","fs","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/type.ts","../src/utils.ts","../src/useRouter.ts","../src/useRoute.ts","../src/create.ts","../src/plugin.ts"],"sourcesContent":["import { createRouter, type CreateRouterOptions } from './create';\r\nimport { routeTypesPlugin, type RouteTypesPluginOptions, type RouteNameStrategy } from './plugin'\r\n\r\nexport {\r\n\tcreateRouter,\r\n\trouteTypesPlugin,\r\n\ttype CreateRouterOptions,\r\n\ttype RouteTypesPluginOptions,\r\n\ttype RouteNameStrategy,\r\n}","import type { PageMetaDatum } from './pages';\r\n\r\nexport enum CloseTypes {\r\n default = 'default',\r\n current = 'current',\r\n all = 'all',\r\n}\r\n\r\nexport interface RouteMeta extends PageMetaDatum {\r\n /** 页面对应的真实路径,例如:pages/home/index */\r\n url: string\r\n /** 是否为 tabBar 页面 */\r\n isTabBar?: boolean\r\n /**\r\n * 页面唯一key\r\n */\r\n name: string\r\n}\r\n\r\nexport interface RouterParams<TPath extends string> {\r\n /** 路由名称(来自 createRouter 注册的类型) */\r\n path?: TPath\r\n /** 需要传递给目标页面的查询参数 */\r\n query?: Record<string, any>\r\n /** 页面关闭策略 */\r\n close?: CloseTypes | keyof typeof CloseTypes\r\n /** 成功回调,可以接收 handler 的返回值 */\r\n success?: (result?: unknown) => void\r\n /** 失败回调 */\r\n fail?: (error?: any) => void\r\n}\r\n\r\n/** 类型安全的路由推送函数类型 */\r\nexport type TypeSafePush<TPath extends string> = (\r\n data: TPath | RouterParams<TPath>,\r\n callbacks?: {\r\n success?: (result?: unknown) => void\r\n fail?: (error?: any) => void\r\n }\r\n) => Promise<void>\r\n\r\n/**\r\n * 页面关闭策略输入类型\r\n */\r\nexport type CloseInput = CloseTypes | keyof typeof CloseTypes | undefined;\r\n\r\n\r\n","import { PagesConfig } from \"./pages\";\r\nimport { CloseInput, CloseTypes, RouteMeta } from \"./type\";\r\n\r\n/**\r\n * 提取URL路径的第二段或者将多段路径用下划线连接\r\n * @param url 需要处理的URL\r\n * @returns 处理后的字符串\r\n */\r\nexport type RouteNameStrategy = 'default' | 'package_page' | ((routePath: string) => string);\r\n\r\nexport function extractSecondPathSegment(url: string): string {\r\n\tconst segments = url.split(\"/\").slice(1, -1);\r\n\treturn segments.length === 1 ? segments[0] : segments.join(\"_\");\r\n}\r\n\r\nexport const resolveRouteName = (routePath: string, strategy: RouteNameStrategy = 'default'): string | undefined => {\r\n\tif (typeof strategy === 'function') {\r\n\t\treturn strategy(routePath);\r\n\t}\r\n\r\n\tconst normalized = routePath.replace(/^\\/+/, '').replace(/\\.vue$/i, '');\r\n\tif (strategy === 'package_page') {\r\n\t\tconst segments = normalized.split('/').filter(Boolean);\r\n\t\tif (segments[segments.length - 1] === 'index') {\r\n\t\t\tsegments.pop();\r\n\t\t}\r\n\t\treturn segments.length > 0 ? segments.join('_') : undefined;\r\n\t}\r\n\r\n\treturn extractSecondPathSegment(routePath);\r\n};\r\n\r\nconst isEnumValue = <T extends Record<string, string>>(enumObject: T, value: unknown): value is T[keyof T] =>\r\n\tObject.values(enumObject).includes(value as T[keyof T]);\r\n\r\nexport const ensureLeadingSlash = (url: string): string => (url.startsWith(\"/\") ? url : `/${url}`);\r\n\r\nexport const buildUrlWithQuery = (url: string, query: Record<string, any>): string => {\r\n\tconst normalized = ensureLeadingSlash(url);\r\n\tconst queryEntries = Object.entries(query ?? {}).filter(([, value]) => value !== undefined);\r\n\tif (queryEntries.length === 0) {\r\n\t\treturn normalized;\r\n\t}\r\n\r\n\tconst queryString = queryEntries\r\n\t\t.map(([key, value]) => {\r\n\t\t\tconst serialized = typeof value === \"object\" && value !== null ? JSON.stringify(value) : String(value);\r\n\t\t\treturn `${encodeURIComponent(key)}=${encodeURIComponent(serialized)}`;\r\n\t\t})\r\n\t\t.join(\"&\");\r\n\r\n\treturn `${normalized}?${queryString}`;\r\n};\r\nexport const resolveCloseType = (close: CloseInput): CloseTypes => {\r\n\tif (!close) return CloseTypes.default;\r\n\tif (isEnumValue(CloseTypes, close)) return close;\r\n\tif (typeof close === \"string\" && close in CloseTypes) return CloseTypes[close as keyof typeof CloseTypes];\r\n\treturn CloseTypes.default;\r\n};\r\n\r\n/**\r\n * 从 pages.json 解析路由信息\r\n * @param routes - pages.json 配置对象\r\n * @returns 路由元信息映射\r\n */\r\nexport function parseRoutesFromPagesJson<TName extends string>(routes: PagesConfig, namingStrategy: RouteNameStrategy = 'default') {\r\n\tconst routeMeta = new Map<TName, RouteMeta>();\r\n\t// 获取 TabBar 页面路径集合\r\n\tconst tabBarPaths = new Set<string>();\r\n\tif (routes.tabBar?.list) {\r\n\t\troutes.tabBar.list.forEach(item => {\r\n\t\t\ttabBarPaths.add(item.pagePath);\r\n\t\t});\r\n\t}\r\n\r\n\t// 处理主包页面\r\n\tif (routes.pages) {\r\n\t\troutes.pages.forEach(page => {\r\n\t\t\tconst name = resolveRouteName(page.path, namingStrategy) as TName;\r\n\t\t\tif (name) {\r\n\t\t\t\trouteMeta.set(name, {\r\n\t\t\t\t\t...page,\r\n\t\t\t\t\tname,\r\n\t\t\t\t\tisTabBar: tabBarPaths.has(page.path) || page.type === \"tabBar\",\r\n\t\t\t\t\turl: page.path,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\tif (routes.subPackages) {\r\n\t\t// 处理分包页面\r\n\t\tconst subpackages = routes.subPackages;\r\n\t\tsubpackages.forEach(subpackage => {\r\n\t\t\tconst root = subpackage.root;\r\n\t\t\tsubpackage.pages.forEach(page => {\r\n\t\t\t\tconst fullPath = `${root}/${page.path}`;\r\n\t\t\t\tconst name = resolveRouteName(fullPath, namingStrategy) as TName;;\r\n\t\t\t\tif (name) {\r\n\t\t\t\t\trouteMeta.set(name, {\r\n\t\t\t\t\t\t...page,\r\n\t\t\t\t\t\tname,\r\n\t\t\t\t\t\tisTabBar: tabBarPaths.has(fullPath) || page.type === \"tabBar\",\r\n\t\t\t\t\t\turl: fullPath,\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\treturn routeMeta;\r\n}\r\n","import type { RouterCore } from './create';\r\nimport type { RouteLocationNormalized, RouteLocationRaw } from './create';\r\nimport { CloseTypes, RouterParams, TypeSafePush } from './type';\r\nimport { ensureLeadingSlash, buildUrlWithQuery, resolveCloseType } from './utils';\r\n\r\n\r\nconst performNavigation = async (url: string, close: CloseTypes): Promise<void> => {\r\n\tconst navigationMethods: Record<CloseTypes, (options: UniApp.NavigateToOptions) => Promise<void>> = {\r\n\t\t[CloseTypes.default]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.navigateTo({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t\t[CloseTypes.current]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.redirectTo({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t\t[CloseTypes.all]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.reLaunch({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t};\r\n\r\n\tawait navigationMethods[close]({ url });\r\n};\r\n\r\nexport type RouterHookResult<TPath extends string> = {\r\n\t/** 类型安全的路由跳转方法 */\r\n\tpush: TypeSafePush<TPath>;\r\n};\r\n\r\n/**\r\n * 创建与指定 Router 实例绑定的路由钩子,避免在调用端重复传参。\r\n */\r\nexport function createRouterHook<TName extends string>(router: RouterCore<TName>): RouterHookResult<TName> {\r\n\t/**\r\n\t * 获取当前路由名称\r\n\t */\r\n\tconst getCurrentRouteName = (): TName | '' => {\r\n\t\tconst currentPage = getCurrentPages().at(-1);\r\n\t\tif (!currentPage?.route) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn router.resolveNameByUrl(currentPage.route) || '';\r\n\t};\r\n\r\n\t/**\r\n\t * 统一的路由跳转实现:先触发 createRouter 注册的拦截器与处理器,再执行实际跳转。\r\n\t */\r\n\tconst basicPush = async (input: TName | RouterParams<TName>): Promise<void> => {\r\n\t\tconst routeData = typeof input === 'string' ? { path: input } : input;\r\n\t\tconst path = routeData.path;\r\n\t\tif (!path) {\r\n\t\t\tconst error = new Error('路由名称不能为空');\r\n\t\t\trouteData.fail?.(error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst meta = router.getRouteMeta(path);\r\n\t\tif (!meta) {\r\n\t\t\tconst error = new Error(`找不到匹配的路由配置: ${String(path)}`);\r\n\t\t\trouteData.fail?.(error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst query = routeData.query ?? {};\r\n\t\tconst closeType = resolveCloseType(routeData.close);\r\n\r\n\t\tconst routePayload = { query, closeType, meta };\r\n\r\n\t\t// 获取来源路由信息\r\n\t\tconst fromName = getCurrentRouteName();\r\n\t\tconst fromMeta = fromName ? router.getRouteMeta(fromName) : undefined;\r\n\r\n\t\t// 创建标准化的路由位置对象\r\n\t\tconst to: RouteLocationNormalized<TName> = {\r\n\t\t\tname: path,\r\n\t\t\tmeta,\r\n\t\t\tquery,\r\n\t\t\tpath: meta.url,\r\n\t\t};\r\n\r\n\t\tconst from: RouteLocationNormalized<TName> = {\r\n\t\t\tname: fromName || ('' as TName),\r\n\t\t\tmeta: fromMeta,\r\n\t\t\tquery: {},\r\n\t\t\tpath: fromMeta?.url || '',\r\n\t\t};\r\n\r\n\t\tlet navigationResult: unknown;\r\n\t\tlet redirectTo: RouteLocationRaw<TName> | undefined;\r\n\r\n\t\ttry {\r\n\t\t\t// 执行 beforeEach 导航守卫\r\n\t\t\tconst beforeResult = await router.runBeforeInterceptors(to, from);\r\n\r\n\t\t\tif (!beforeResult.shouldContinue) {\r\n\t\t\t\t// 导航被取消\r\n\t\t\t\tif (beforeResult.redirectTo) {\r\n\t\t\t\t\t// 重定向到其他路由\r\n\t\t\t\t\tredirectTo = beforeResult.redirectTo;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 完全取消导航\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} catch (error) {\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 如果有重定向,递归调用 push\r\n\t\tif (redirectTo) {\r\n\t\t\tif (typeof redirectTo === 'string') {\r\n\t\t\t\t// 简单的路由名称重定向\r\n\t\t\t\treturn basicPush(\r\n\t\t\t\t\ttypeof routeData === 'object'\r\n\t\t\t\t\t\t? { ...routeData, path: redirectTo }\r\n\t\t\t\t\t\t: redirectTo\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\t// 路由对象重定向\r\n\t\t\t\treturn basicPush({\r\n\t\t\t\t\t...routeData,\r\n\t\t\t\t\tpath: redirectTo.path,\r\n\t\t\t\t\tquery: redirectTo.query || routeData.query,\r\n\t\t\t\t\t// TODO: 处理 replace 选项\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// 执行 handler\r\n\t\ttry {\r\n\t\t\tconst handler = router.getHandler(path);\r\n\t\t\tnavigationResult = handler ? await handler(routePayload) : undefined;\r\n\t\t\tawait router.runAfterInterceptors(to, from);\r\n\t\t} catch (error) {\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (navigationResult === false) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 将 query 和 handler 返回值一起缓存,供目标页面使用\r\n\t\trouter.setPageCache(path, {\r\n\t\t\tquery,\r\n\t\t\thandlerResult: navigationResult,\r\n\t\t});\r\n\r\n\t\ttry {\r\n\t\t\tif (meta.isTabBar) {\r\n\t\t\t\tif (Object.keys(query).length > 0) {\r\n\t\t\t\t\tconsole.warn('跳转 tabBar 页面时会忽略 query 参数');\r\n\t\t\t\t}\r\n\t\t\t\tawait new Promise<void>((resolve, reject) => {\r\n\t\t\t\t\tuni.switchTab({\r\n\t\t\t\t\t\turl: ensureLeadingSlash(meta.url),\r\n\t\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tawait performNavigation(buildUrlWithQuery(meta.url, query), closeType);\r\n\t\t\t}\r\n\r\n\t\t\t// 成功回调,传递 handler 的返回值(仅用于通知跳转成功)\r\n\t\t\trouteData.success?.(navigationResult);\r\n\t\t} catch (error) {\r\n\t\t\trouter.deletePageCache(path);\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t}\r\n\t};\r\n\r\n\t/**\r\n\t * 导出给外部使用的 push,支持额外回调合并。\r\n\t */\r\n\tconst push: TypeSafePush<TName> = async (data, callbacks) => {\r\n\t\tif (data == null) {\r\n\t\t\tconst error = new Error('路由参数不能为空');\r\n\t\t\tcallbacks?.fail?.(error);\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\tconst routeData = typeof data === 'string' ? { path: data } : data;\r\n\t\tconst finalRouteData: RouterParams<TName> = {\r\n\t\t\t...routeData,\r\n\t\t\tsuccess: callbacks?.success ?? routeData.success,\r\n\t\t\tfail: callbacks?.fail ?? routeData.fail,\r\n\t\t};\r\n\r\n\t\tawait basicPush(finalRouteData);\r\n\t};\r\n\r\n\treturn {\r\n\t\tpush\r\n\t}\r\n}","import { onMounted, reactive } from 'vue';\r\nimport type { UnwrapRef } from 'vue';\r\nimport type { RouterCore } from './create';\r\nimport type { RouteMeta } from './type';\r\nimport { extractSecondPathSegment } from './utils';\r\n\r\n/**\r\n * 扩展 uni-app 页面实例类型,包含 options 属性\r\n */\r\ninterface UniPageInstance extends Page.PageInstance<AnyObject, Record<string, any>> {\r\n\t/** 页面路由路径 */\r\n\troute?: string;\r\n\t/** 页面 URL 查询参数 */\r\n\toptions?: Record<string, string>;\r\n}\r\n\r\ntype RuntimePageInstance = UniPageInstance & {\r\n\t$page?: {\r\n\t\toptions?: Record<string, string>;\r\n\t\tfullPath?: string;\r\n\t};\r\n};\r\n\r\nconst decodeQuery = (query: Record<string, any>): Record<string, any> => {\r\n\tconst decoded: Record<string, any> = {};\r\n\tfor (const key in query) {\r\n\t\tconst value = query[key];\r\n\t\tif (typeof value === 'string') {\r\n\t\t\ttry {\r\n\t\t\t\tdecoded[key] = decodeURIComponent(value);\r\n\t\t\t} catch {\r\n\t\t\t\tdecoded[key] = value;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tdecoded[key] = value;\r\n\t\t}\r\n\t}\r\n\treturn decoded;\r\n};\r\n\r\nconst parseQueryString = (queryString?: string): Record<string, string> => {\r\n\tif (!queryString) return {};\r\n\treturn queryString.split(\"&\").reduce<Record<string, string>>((acc, segment) => {\r\n\t\tif (!segment) return acc;\r\n\t\tconst [rawKey, rawValue = \"\"] = segment.split(\"=\");\r\n\t\tconst key = decodeURIComponent(rawKey);\r\n\t\tconst value = decodeURIComponent(rawValue);\r\n\t\tacc[key] = value;\r\n\t\treturn acc;\r\n\t}, {});\r\n};\r\n\r\nconst resolvePageOptions = (page?: UniPageInstance): Record<string, any> => {\r\n\tif (!page) return {};\r\n\tconst runtimePage = page as RuntimePageInstance;\r\n\tconst sources: Record<string, any>[] = [];\r\n\r\n\tif (page.options && Object.keys(page.options).length > 0) {\r\n\t\tsources.push(decodeQuery(page.options));\r\n\t}\r\n\r\n\tif (runtimePage.$page?.options && Object.keys(runtimePage.$page.options).length > 0) {\r\n\t\tsources.push(decodeQuery(runtimePage.$page.options));\r\n\t}\r\n\r\n\tif (runtimePage.$page?.fullPath) {\r\n\t\tconst queryIndex = runtimePage.$page.fullPath.indexOf(\"?\");\r\n\t\tif (queryIndex !== -1) {\r\n\t\t\tsources.push(parseQueryString(runtimePage.$page.fullPath.slice(queryIndex + 1)));\r\n\t\t}\r\n\t}\r\n\r\n\tif (sources.length === 0) {\r\n\t\treturn {};\r\n\t}\r\n\r\n\treturn Object.assign({}, ...sources);\r\n};\r\n\r\n/**\r\n * useRoute 返回的路由信息\r\n */\r\nexport interface RouteInfo<TName extends string> {\r\n\t/** 路由名称 */\r\n\tname: TName;\r\n\t/** 路由元信息 */\r\n\tmeta?: RouteMeta;\r\n\t/** 合并后的查询参数(包含 URL 参数和缓存参数) */\r\n\tquery: Record<string, any>;\r\n\t/** Handler 返回值 */\r\n\thandlerResult?: unknown;\r\n}\r\n\r\n/**\r\n * 创建路由钩子,获取当前页面的路由信息\r\n * @param router - Router 核心实例\r\n * @returns 当前页面的路由信息\r\n */\r\nexport function createRouteHook<TName extends string>(router: RouterCore<TName>): RouteInfo<TName> {\r\n\t// 初始化响应式状态,在组件挂载后填充运行时数据\r\n\tconst state = reactive<RouteInfo<TName>>({\r\n\t\tname: '' as TName,\r\n\t\tmeta: undefined,\r\n\t\tquery: {},\r\n\t\thandlerResult: undefined,\r\n\t});\r\n\r\n\tonMounted(() => {\r\n\t\t// 获取当前页面实例\r\n\t\tconst pages = getCurrentPages();\r\n\t\tconst currentPage = pages[pages.length - 1] as UniPageInstance | undefined;\r\n\r\n\t\t// 如果没有当前页面,保留默认空状态并打印警告\r\n\t\tif (!currentPage?.route) {\r\n\t\t\t// 运行时未能获取到 page 实例\r\n\t\t\t// 不抛错,只是保留空状态以避免阻断调用方\r\n\t\t\t// 日志便于调试\r\n\t\t\t// eslint-disable-next-line no-console\r\n\t\t\tconsole.warn('无法获取当前页面的路由信息');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 从路由路径提取路由名称\r\n\t\tconst routeName = (router.resolveNameByUrl(currentPage.route) || extractSecondPathSegment(currentPage.route)) as TName;\r\n\r\n\t\t// 获取路由元信息\r\n\t\tconst meta = router.getRouteMeta(routeName);\r\n\r\n\t\t// 获取页面缓存数据(包含 query 和 handlerResult)\r\n\t\tconst cache = router.getPageCache(routeName as TName);\r\n\r\n\t\tconst runtimeQuery = resolvePageOptions(currentPage);\r\n\r\n\t\t// 合并查询参数: URL 中的参数为基础,缓存的 query(如果存在)覆盖它以保留原始类型\r\n\t\tconst mergedQuery: Record<string, any> = {\r\n\t\t\t...runtimeQuery,\r\n\t\t\t...(cache?.query ? decodeQuery(cache.query) : {}),\r\n\t\t};\r\n\t\tstate.name = routeName as unknown as UnwrapRef<TName>;\r\n\t\tstate.meta = meta;\r\n\t\tstate.query = mergedQuery;\r\n\t\tstate.handlerResult = cache?.handlerResult;\r\n\t\tstate.handlerResult = cache?.handlerResult;\r\n\t});\r\n\r\n\t// 类型声明需要一个普通的 `RouteInfo<TName>`,将响应式对象断言为该类型以兼容 d.ts 输出。\r\n\treturn state as unknown as RouteInfo<TName>;\r\n}","import { createRouterHook, RouterHookResult } from './useRouter';\r\nimport { createRouteHook, RouteInfo } from './useRoute';\r\nimport type { RouteMeta } from './type';\r\nimport { PagesConfig } from './pages';\r\nimport { parseRoutesFromPagesJson, RouteNameStrategy } from './utils';\r\n\r\n// 导出类型供外部使用\r\nexport type { RouteInfo, RouterHookResult, RouteMeta };\r\nexport { CloseTypes, RouterParams } from './type';\r\n\r\n\r\nexport interface CreateRouterOptions {\r\n namingStrategy?: RouteNameStrategy;\r\n}\r\n\r\ntype RouteHandler = (payload?: unknown) => unknown | Promise<unknown>;\r\n\r\n/**\r\n * 标准化的路由位置\r\n */\r\nexport interface RouteLocationNormalized<TName extends string> {\r\n /** 路由名称 */\r\n name: TName;\r\n /** 路由元信息 */\r\n meta?: RouteMeta;\r\n /** 查询参数 */\r\n query: Record<string, any>;\r\n /** 完整路径 */\r\n path: string;\r\n}\r\n\r\n/**\r\n * 路由地址(用于重定向)\r\n */\r\nexport type RouteLocationRaw<TName extends string> =\r\n | TName\r\n | {\r\n path: TName;\r\n query?: Record<string, any>;\r\n replace?: boolean;\r\n };\r\n\r\n/**\r\n * 路由守卫函数类型\r\n * @param to 即将要进入的目标路由\r\n * @param from 当前导航正要离开的路由\r\n * @returns \r\n * - false: 取消当前导航\r\n * - RouteLocationRaw: 重定向到不同的地址\r\n * - undefined/true/void: 继续导航\r\n */\r\nexport type NavigationGuard<TName extends string> = (\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n) => void | boolean | RouteLocationRaw<TName> | Promise<void | boolean | RouteLocationRaw<TName>>;\r\n\r\n\r\n\r\n/**\r\n * Router 核心能力:注册处理函数与拦截器,并存储元信息。\r\n */\r\nexport interface RouterCore<TName extends string> {\r\n /**\r\n * 注册一个路由处理函数。返回一个取消订阅(卸载)函数,用于移除该处理函数。\r\n */\r\n register(name: TName, handler: RouteHandler): () => void;\r\n /**\r\n * 通过名称移除已注册的处理函数。若存在则返回 true。\r\n */\r\n unregister(name: TName): boolean;\r\n /**\r\n * 检查是否已为给定名称注册处理函数。\r\n */\r\n has(name: TName): boolean;\r\n /**\r\n * 获取指定路由名称对应的处理函数。\r\n */\r\n getHandler(name: TName): RouteHandler | undefined;\r\n /**\r\n * 添加一个 beforeEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n beforeEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 添加一个 afterEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n afterEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 记录路由元信息,返回一个用于撤销注册的函数。\r\n */\r\n defineRoute(name: TName, meta: RouteMeta): () => void;\r\n /**\r\n * 获取对应路由的元信息。\r\n */\r\n getRouteMeta(name: TName): RouteMeta | undefined;\r\n /**\r\n * 获取所有路由的元信息快照。\r\n */\r\n listRouteMeta(): ReadonlyMap<TName, RouteMeta>;\r\n /**\r\n * 手动执行 beforeEach 导航守卫链。\r\n * @returns 返回导航控制结果\r\n */\r\n runBeforeInterceptors(\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<{ shouldContinue: boolean; redirectTo?: RouteLocationRaw<TName> }>;\r\n /**\r\n * 手动执行 afterEach 导航守卫链。\r\n */\r\n runAfterInterceptors(to: RouteLocationNormalized<TName>, from: RouteLocationNormalized<TName>): Promise<void>;\r\n /**\r\n * 设置页面缓存数据(query 和 handler 返回值)\r\n */\r\n setPageCache(url: TName, data: { query: Record<string, any>; handlerResult?: unknown }): void;\r\n /**\r\n * 获取页面缓存数据\r\n */\r\n getPageCache(url: TName): { query: Record<string, any>; handlerResult?: unknown } | undefined;\r\n /**\r\n * 删除页面缓存数据\r\n */\r\n deletePageCache(url: TName): void;\r\n /**\r\n * 根据 pages.json 原始 url 解析出路由名称\r\n */\r\n resolveNameByUrl(routePath: string): TName | undefined;\r\n}\r\n\r\n/**\r\n * Router 对外暴露的完整接口,只包含公开的方法。\r\n */\r\nexport interface Router<TName extends string> {\r\n /**\r\n * 注册一个路由处理函数。返回一个取消订阅(卸载)函数,用于移除该处理函数。\r\n */\r\n register(name: TName, handler: RouteHandler): () => void;\r\n /**\r\n * 通过名称移除已注册的处理函数。若存在则返回 true。\r\n */\r\n unregister(name: TName): boolean;\r\n /**\r\n * 检查是否已为给定名称注册处理函数。\r\n */\r\n has(name: TName): boolean;\r\n /**\r\n * 添加一个 beforeEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n beforeEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 添加一个 afterEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n afterEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 生成绑定当前 Router 实例的 useRouter 钩子。\r\n */\r\n useRouter(): RouterHookResult<TName>;\r\n /**\r\n * 生成绑定当前 Router 实例的 useRoute 钩子,获取当前页面的路由信息。\r\n */\r\n useRoute(): RouteInfo<TName>;\r\n}\r\n\r\n/**\r\n * 创建一个路由实例,泛型 TName 表示允许的路由名称(通常为字符串字面量联合类型)。\r\n */\r\nexport function createRouter<const TRoutes extends Record<string, RouteMeta>>(routes: PagesConfig, options?: CreateRouterOptions): Router<Extract<keyof TRoutes, string>>;\r\nexport function createRouter<TName extends string>(routes?: PagesConfig, options?: CreateRouterOptions): Router<TName>;\r\nexport function createRouter<TName extends string>(routes?: PagesConfig, options?: CreateRouterOptions): Router<TName> {\r\n // 存储路由处理函数的映射表\r\n const handlers = new Map<TName, RouteHandler>();\r\n // beforeEach 导航守卫数组\r\n const beforeInterceptors: NavigationGuard<TName>[] = [];\r\n // afterEach 导航守卫数组\r\n const afterInterceptors: NavigationGuard<TName>[] = [];\r\n // 路由元信息映射表\r\n const routeMeta = new Map<TName, RouteMeta>();\r\n // 页面缓存: 存储 query 和 handler 返回值\r\n const pageCache = new Map<TName, { query: Record<string, any>; handlerResult?: unknown }>();\r\n\r\n // 如果提供了 pages.json 配置,解析并注册所有路由\r\n const namingStrategy = options?.namingStrategy || 'default';\r\n\r\n if (routes) {\r\n parseRoutesFromPagesJson(routes, namingStrategy).forEach((meta, name) => {\r\n routeMeta.set(name as TName, meta);\r\n });\r\n }\r\n\r\n /**\r\n * 添加守卫到指定的守卫数组\r\n * @param bucket 守卫数组\r\n * @param guard 要添加的守卫函数\r\n * @returns 返回一个卸载函数,调用后可移除该守卫\r\n */\r\n const addInterceptor = (bucket: NavigationGuard<TName>[], guard: NavigationGuard<TName>) => {\r\n bucket.push(guard);\r\n return () => {\r\n const index = bucket.indexOf(guard);\r\n if (index >= 0) bucket.splice(index, 1);\r\n };\r\n };\r\n /**\r\n * 执行导航守卫链\r\n * 按注册顺序依次执行守卫,任何守卫返回 false 或重定向地址都会中断后续守卫的执行\r\n * @param bucket 守卫数组\r\n * @param to 目标路由位置\r\n * @param from 来源路由位置\r\n * @returns 返回导航控制结果\r\n * - shouldContinue: true 表示继续导航, false 表示取消导航\r\n * - redirectTo: 如果存在,表示重定向到该地址\r\n */\r\n const runInterceptors = async (\r\n bucket: NavigationGuard<TName>[],\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<{ shouldContinue: boolean; redirectTo?: RouteLocationRaw<TName> }> => {\r\n for (const guard of bucket) {\r\n // 在循环中 await,以支持异步守卫的顺序执行\r\n // eslint-disable-next-line no-await-in-loop\r\n const result = await guard(to, from);\r\n\r\n // 处理守卫返回值\r\n if (result === false) {\r\n // 返回 false 取消导航\r\n return { shouldContinue: false };\r\n }\r\n\r\n if (result && typeof result === 'object' && 'path' in result) {\r\n // 返回路由对象重定向 { path: 'home', query: {...}, replace: true }\r\n return { shouldContinue: false, redirectTo: result };\r\n }\r\n\r\n if (typeof result === 'string') {\r\n // 返回路由名称字符串重定向\r\n return { shouldContinue: false, redirectTo: result as TName };\r\n }\r\n\r\n // result 为 undefined 或 true,继续执行下一个守卫\r\n }\r\n\r\n // 所有守卫都通过,允许导航继续\r\n return { shouldContinue: true };\r\n };\r\n\r\n /**\r\n * 执行 after 守卫链(不支持导航控制,仅用于通知)\r\n * after 守卫在导航完成后执行,无法阻止或重定向导航\r\n * @param bucket 守卫数组\r\n * @param to 目标路由位置\r\n * @param from 来源路由位置\r\n */\r\n const runAfterInterceptors = async (\r\n bucket: NavigationGuard<TName>[],\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<void> => {\r\n for (const guard of bucket) {\r\n // 按顺序执行所有 after 守卫\r\n // eslint-disable-next-line no-await-in-loop\r\n await guard(to, from);\r\n }\r\n };\r\n\r\n\r\n\r\n // Router 核心实现对象,包含所有内部方法\r\n const routerImpl: RouterCore<TName> = {\r\n // 注册路由处理函数\r\n register: (name, handler) => {\r\n handlers.set(name, handler);\r\n // 返回卸载函数\r\n return () => {\r\n handlers.delete(name);\r\n };\r\n },\r\n // 移除路由处理函数\r\n unregister: (name) => handlers.delete(name),\r\n // 检查是否已注册处理函数\r\n has: (name) => handlers.has(name),\r\n // 获取路由处理函数\r\n getHandler: (name) => handlers.get(name),\r\n // 添加 beforeEach 守卫\r\n beforeEach: (interceptor) => addInterceptor(beforeInterceptors, interceptor),\r\n // 添加 afterEach 守卫\r\n afterEach: (interceptor) => addInterceptor(afterInterceptors, interceptor),\r\n // 定义路由元信息\r\n defineRoute: (name, meta) => {\r\n routeMeta.set(name, meta);\r\n // 返回撤销函数\r\n return () => {\r\n routeMeta.delete(name);\r\n };\r\n },\r\n // 获取路由元信息\r\n getRouteMeta: (name) => routeMeta.get(name),\r\n // 获取所有路由元信息的只读快照\r\n listRouteMeta: () => new Map(routeMeta),\r\n // 执行 beforeEach 守卫链\r\n runBeforeInterceptors: (to, from) => runInterceptors(beforeInterceptors, to, from),\r\n // 执行 afterEach 守卫链\r\n runAfterInterceptors: (to, from) => runAfterInterceptors(afterInterceptors, to, from),\r\n // 页面缓存管理方法\r\n setPageCache: (name, data) => pageCache.set(name, data),\r\n getPageCache: (name) => pageCache.get(name),\r\n deletePageCache: (name) => pageCache.delete(name),\r\n resolveNameByUrl: (routePath: string) => {\r\n const normalized = routePath.replace(/^\\/+/, '');\r\n for (const [name, meta] of routeMeta.entries()) {\r\n if (meta.url === normalized) return name;\r\n }\r\n return undefined;\r\n },\r\n };\r\n\r\n // 创建 useRouter 工厂函数,闭包持有完整的 routerImpl\r\n const useRouterFactory = () => createRouterHook(routerImpl);\r\n // 创建 useRoute 工厂函数,闭包持有完整的 routerImpl\r\n const useRouteFactory = () => createRouteHook(routerImpl);\r\n\r\n // 只返回公开的方法,隐藏内部实现细节\r\n return {\r\n afterEach: routerImpl.afterEach, // 注册 afterEach 守卫\r\n beforeEach: routerImpl.beforeEach, // 注册 beforeEach 守卫\r\n register: routerImpl.register, // 注册路由处理函数\r\n unregister: routerImpl.unregister, // 移除路由处理函数\r\n has: routerImpl.has, // 检查处理函数是否存在\r\n useRouter: useRouterFactory, // 创建 useRouter 钩子\r\n useRoute: useRouteFactory // 创建 useRoute 钩子\r\n } as Router<TName>;\r\n}\r\n","import { PagesConfig } from \"./pages\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { resolveRouteName, RouteNameStrategy } from \"./utils\";\r\nexport type { RouteNameStrategy } from \"./utils\";\r\n\r\n/**\r\n * 插件配置选项\r\n */\r\nexport interface RouteTypesPluginOptions {\r\n\t/** 类型文件输出路径 */\r\n\tdts: string;\r\n\t/** 自定义类型名称,默认为 'ENHANCE_ROUTE_PATH' */\r\n\ttypeName?: string;\r\n\t/** 自定义类型生成规则 */\r\n\tgenerator?: (routeNames: string[], typeName: string) => string;\r\n\t/** 路由名称生成策略,默认 'default' */\r\n\tnamingStrategy?: RouteNameStrategy;\r\n}\r\n\r\n\r\n/**\r\n * 从 pages.json 中提取所有路由名称\r\n * @param pagesJson pages.json 配置对象\r\n * @returns 路由名称的 Set 集合\r\n */\r\nfunction extractRouteNamesFromPages(pagesJson: PagesConfig, namingStrategy: RouteNameStrategy): Set<string> {\r\n\tconst routes = new Set<string>();\r\n\r\n\t// 处理主包页面\r\n\tif (pagesJson.pages) {\r\n\t\tpagesJson.pages.forEach(page => {\r\n\t\t\tconst name = resolveRouteName(page.path, namingStrategy);\r\n\t\t\tif (name) {\r\n\t\t\t\troutes.add(name);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t// 处理分包页面\r\n\tif (pagesJson.subPackages) {\r\n\t\tpagesJson.subPackages.forEach(subpackage => {\r\n\t\t\tconst root = subpackage.root;\r\n\t\t\tsubpackage.pages.forEach(page => {\r\n\t\t\t\tconst name = resolveRouteName(`${root}/${page.path}`, namingStrategy);\r\n\t\t\t\tif (name) {\r\n\t\t\t\t\troutes.add(name);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\treturn routes;\r\n}\r\n\r\n/**\r\n * 生成路由类型定义字符串\r\n * @param routeNames 路由名称数组\r\n * @param typeName 类型名称\r\n * @returns TypeScript 类型定义字符串\r\n */\r\nfunction generateTypeDefinition(routeNames: string[], typeName: string = 'ENHANCE_ROUTE_PATH'): string {\r\n\tconst sortedRoutes = [...routeNames].sort((a, b) => a.localeCompare(b));\r\n\treturn `export type ${typeName} =\\n${sortedRoutes.map(name => ` | '${name}'`).join('\\n')}`;\r\n}\r\n\r\n/**\r\n * 读取并解析 pages.json 文件\r\n * @param pagesJsonPath pages.json 文件路径\r\n * @returns 解析后的配置对象\r\n */\r\nfunction readPagesJson(pagesJsonPath: string): PagesConfig {\r\n\tconst content = fs.readFileSync(pagesJsonPath, 'utf8');\r\n\treturn JSON.parse(content);\r\n}\r\n\r\n/**\r\n * 生成路由类型文件\r\n * @param dts 类型文件输出路径\r\n * @param pagesJsonPath pages.json 文件路径\r\n * @param options 可选配置\r\n */\r\nfunction generateRouteTypeFile(\r\n\tdts: string,\r\n\tpagesJsonPath: string,\r\n\toptions?: { typeName?: string; generator?: (routeNames: string[], typeName: string) => string; namingStrategy?: RouteNameStrategy }\r\n): void {\r\n\tconst pagesJson = readPagesJson(pagesJsonPath);\r\n\tconst routeNames = extractRouteNamesFromPages(pagesJson, options?.namingStrategy || 'default');\r\n\tconst typeName = options?.typeName || 'ENHANCE_ROUTE_PATH';\r\n\tconst typeDefinition = options?.generator\r\n\t\t? options.generator(Array.from(routeNames), typeName)\r\n\t\t: generateTypeDefinition(Array.from(routeNames), typeName);\r\n\tfs.writeFileSync(dts, typeDefinition, 'utf8');\r\n}\r\n\r\n// 环境配置验证\r\nconst getValidatedPaths = () => {\r\n\tconst inputDir = process.env.UNI_INPUT_DIR || `${process.env.INIT_CWD}/src`;\r\n\tif (!inputDir || inputDir.trim() === '') {\r\n\t\tthrow new Error('Missing required environment variables: UNI_INPUT_DIR or INIT_CWD');\r\n\t}\r\n\treturn path.resolve(inputDir, 'pages.json')\r\n};\r\n\r\n/**\r\n * Vite 插件: 自动生成路由类型定义\r\n * @param options 插件配置选项,可以是字符串(类型文件输出路径)或配置对象\r\n * @returns Vite 插件对象\r\n */\r\nexport function routeTypesPlugin(options: string | RouteTypesPluginOptions) {\r\n\tlet isFirstBuild = true;\r\n\tconst config: RouteTypesPluginOptions = typeof options === 'string'\r\n\t\t? { dts: options }\r\n\t\t: options;\r\n\r\n\treturn {\r\n\t\tname: 'route-types-generator',\r\n\t\t/**\r\n\t\t * 构建开始时生成路由类型\r\n\t\t */\r\n\t\tbuildStart() {\r\n\t\t\t// 只在首次构建时生成类型,避免重复生成\r\n\t\t\tif (isFirstBuild) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst pagesJsonPath = getValidatedPaths();\r\n\t\t\t\t\tgenerateRouteTypeFile(config.dts, pagesJsonPath, {\r\n\t\t\t\t\t\ttypeName: config.typeName,\r\n\t\t\t\t\t\tgenerator: config.generator,\r\n\t\t\t\t\t\tnamingStrategy: config.namingStrategy,\r\n\t\t\t\t\t});\r\n\t\t\t\t\tisFirstBuild = false;\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\r\n\t\t\t\t\tconsole.warn('路由类型生成失败:', message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\t/**\r\n\t\t * 热更新时监听 pages.json 变化\r\n\t\t */\r\n\t\thandleHotUpdate(ctx: any) {\r\n\t\t\t// 监听 pages.json 变化,自动重新生成类型\r\n\t\t\tif (ctx.file.endsWith('pages.json')) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst pagesJsonPath = getValidatedPaths();\r\n\t\t\t\t\tgenerateRouteTypeFile(config.dts, pagesJsonPath, {\r\n\t\t\t\t\t\ttypeName: config.typeName,\r\n\t\t\t\t\t\tgenerator: config.generator,\r\n\t\t\t\t\t\tnamingStrategy: config.namingStrategy,\r\n\t\t\t\t\t});\r\n\t\t\t\t\tconsole.log('🔄 检测到 pages.json 变化,已自动更新路由类型');\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\r\n\t\t\t\t\tconsole.warn('热更新时生成路由类型失败:', message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t};\r\n}\r\n\r\n"],"mappings":"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","names":["CloseTypes","path","fs","path"]}
package/dist/index.mjs CHANGED
@@ -11,6 +11,20 @@ function extractSecondPathSegment(url) {
11
11
  const segments = url.split("/").slice(1, -1);
12
12
  return segments.length === 1 ? segments[0] : segments.join("_");
13
13
  }
14
+ var resolveRouteName = (routePath, strategy = "default") => {
15
+ if (typeof strategy === "function") {
16
+ return strategy(routePath);
17
+ }
18
+ const normalized = routePath.replace(/^\/+/, "").replace(/\.vue$/i, "");
19
+ if (strategy === "package_page") {
20
+ const segments = normalized.split("/").filter(Boolean);
21
+ if (segments[segments.length - 1] === "index") {
22
+ segments.pop();
23
+ }
24
+ return segments.length > 0 ? segments.join("_") : void 0;
25
+ }
26
+ return extractSecondPathSegment(routePath);
27
+ };
14
28
  var isEnumValue = (enumObject, value) => Object.values(enumObject).includes(value);
15
29
  var ensureLeadingSlash = (url) => url.startsWith("/") ? url : `/${url}`;
16
30
  var buildUrlWithQuery = (url, query) => {
@@ -31,7 +45,7 @@ var resolveCloseType = (close) => {
31
45
  if (typeof close === "string" && close in CloseTypes) return CloseTypes[close];
32
46
  return "default" /* default */;
33
47
  };
34
- function parseRoutesFromPagesJson(routes) {
48
+ function parseRoutesFromPagesJson(routes, namingStrategy = "default") {
35
49
  const routeMeta = /* @__PURE__ */ new Map();
36
50
  const tabBarPaths = /* @__PURE__ */ new Set();
37
51
  if (routes.tabBar?.list) {
@@ -41,7 +55,7 @@ function parseRoutesFromPagesJson(routes) {
41
55
  }
42
56
  if (routes.pages) {
43
57
  routes.pages.forEach((page) => {
44
- const name = extractSecondPathSegment(page.path);
58
+ const name = resolveRouteName(page.path, namingStrategy);
45
59
  if (name) {
46
60
  routeMeta.set(name, {
47
61
  ...page,
@@ -58,7 +72,7 @@ function parseRoutesFromPagesJson(routes) {
58
72
  const root = subpackage.root;
59
73
  subpackage.pages.forEach((page) => {
60
74
  const fullPath = `${root}/${page.path}`;
61
- const name = extractSecondPathSegment(fullPath);
75
+ const name = resolveRouteName(fullPath, namingStrategy);
62
76
  ;
63
77
  if (name) {
64
78
  routeMeta.set(name, {
@@ -107,7 +121,7 @@ function createRouterHook(router) {
107
121
  if (!currentPage?.route) {
108
122
  return "";
109
123
  }
110
- return extractSecondPathSegment(currentPage.route) || "";
124
+ return router.resolveNameByUrl(currentPage.route) || "";
111
125
  };
112
126
  const basicPush = async (input) => {
113
127
  const routeData = typeof input === "string" ? { path: input } : input;
@@ -293,7 +307,7 @@ function createRouteHook(router) {
293
307
  console.warn("\u65E0\u6CD5\u83B7\u53D6\u5F53\u524D\u9875\u9762\u7684\u8DEF\u7531\u4FE1\u606F");
294
308
  return;
295
309
  }
296
- const routeName = extractSecondPathSegment(currentPage.route);
310
+ const routeName = router.resolveNameByUrl(currentPage.route) || extractSecondPathSegment(currentPage.route);
297
311
  const meta = router.getRouteMeta(routeName);
298
312
  const cache = router.getPageCache(routeName);
299
313
  const runtimeQuery = resolvePageOptions(currentPage);
@@ -311,14 +325,15 @@ function createRouteHook(router) {
311
325
  }
312
326
 
313
327
  // src/create.ts
314
- function createRouter(routes) {
328
+ function createRouter(routes, options) {
315
329
  const handlers = /* @__PURE__ */ new Map();
316
330
  const beforeInterceptors = [];
317
331
  const afterInterceptors = [];
318
332
  const routeMeta = /* @__PURE__ */ new Map();
319
333
  const pageCache = /* @__PURE__ */ new Map();
334
+ const namingStrategy = options?.namingStrategy || "default";
320
335
  if (routes) {
321
- parseRoutesFromPagesJson(routes).forEach((meta, name) => {
336
+ parseRoutesFromPagesJson(routes, namingStrategy).forEach((meta, name) => {
322
337
  routeMeta.set(name, meta);
323
338
  });
324
339
  }
@@ -385,7 +400,14 @@ function createRouter(routes) {
385
400
  // 页面缓存管理方法
386
401
  setPageCache: (name, data) => pageCache.set(name, data),
387
402
  getPageCache: (name) => pageCache.get(name),
388
- deletePageCache: (name) => pageCache.delete(name)
403
+ deletePageCache: (name) => pageCache.delete(name),
404
+ resolveNameByUrl: (routePath) => {
405
+ const normalized = routePath.replace(/^\/+/, "");
406
+ for (const [name, meta] of routeMeta.entries()) {
407
+ if (meta.url === normalized) return name;
408
+ }
409
+ return void 0;
410
+ }
389
411
  };
390
412
  const useRouterFactory = () => createRouterHook(routerImpl);
391
413
  const useRouteFactory = () => createRouteHook(routerImpl);
@@ -410,11 +432,11 @@ function createRouter(routes) {
410
432
  // src/plugin.ts
411
433
  import fs from "fs";
412
434
  import path from "path";
413
- function extractRouteNamesFromPages(pagesJson) {
435
+ function extractRouteNamesFromPages(pagesJson, namingStrategy) {
414
436
  const routes = /* @__PURE__ */ new Set();
415
437
  if (pagesJson.pages) {
416
438
  pagesJson.pages.forEach((page) => {
417
- const name = extractSecondPathSegment(page.path);
439
+ const name = resolveRouteName(page.path, namingStrategy);
418
440
  if (name) {
419
441
  routes.add(name);
420
442
  }
@@ -424,7 +446,7 @@ function extractRouteNamesFromPages(pagesJson) {
424
446
  pagesJson.subPackages.forEach((subpackage) => {
425
447
  const root = subpackage.root;
426
448
  subpackage.pages.forEach((page) => {
427
- const name = extractSecondPathSegment(`${root}/${page.path}`);
449
+ const name = resolveRouteName(`${root}/${page.path}`, namingStrategy);
428
450
  if (name) {
429
451
  routes.add(name);
430
452
  }
@@ -433,19 +455,20 @@ function extractRouteNamesFromPages(pagesJson) {
433
455
  }
434
456
  return routes;
435
457
  }
436
- function generateTypeDefinition(routeNames) {
458
+ function generateTypeDefinition(routeNames, typeName = "ENHANCE_ROUTE_PATH") {
437
459
  const sortedRoutes = [...routeNames].sort((a, b) => a.localeCompare(b));
438
- return `export type ENHANCE_ROUTE_PATH =
460
+ return `export type ${typeName} =
439
461
  ${sortedRoutes.map((name) => ` | '${name}'`).join("\n")}`;
440
462
  }
441
463
  function readPagesJson(pagesJsonPath) {
442
464
  const content = fs.readFileSync(pagesJsonPath, "utf8");
443
465
  return JSON.parse(content);
444
466
  }
445
- function generateRouteTypeFile(dts, pagesJsonPath) {
467
+ function generateRouteTypeFile(dts, pagesJsonPath, options) {
446
468
  const pagesJson = readPagesJson(pagesJsonPath);
447
- const routeNames = extractRouteNamesFromPages(pagesJson);
448
- const typeDefinition = generateTypeDefinition(Array.from(routeNames));
469
+ const routeNames = extractRouteNamesFromPages(pagesJson, options?.namingStrategy || "default");
470
+ const typeName = options?.typeName || "ENHANCE_ROUTE_PATH";
471
+ const typeDefinition = options?.generator ? options.generator(Array.from(routeNames), typeName) : generateTypeDefinition(Array.from(routeNames), typeName);
449
472
  fs.writeFileSync(dts, typeDefinition, "utf8");
450
473
  }
451
474
  var getValidatedPaths = () => {
@@ -455,8 +478,9 @@ var getValidatedPaths = () => {
455
478
  }
456
479
  return path.resolve(inputDir, "pages.json");
457
480
  };
458
- function routeTypesPlugin(dts) {
481
+ function routeTypesPlugin(options) {
459
482
  let isFirstBuild = true;
483
+ const config = typeof options === "string" ? { dts: options } : options;
460
484
  return {
461
485
  name: "route-types-generator",
462
486
  /**
@@ -466,7 +490,11 @@ function routeTypesPlugin(dts) {
466
490
  if (isFirstBuild) {
467
491
  try {
468
492
  const pagesJsonPath = getValidatedPaths();
469
- generateRouteTypeFile(dts, pagesJsonPath);
493
+ generateRouteTypeFile(config.dts, pagesJsonPath, {
494
+ typeName: config.typeName,
495
+ generator: config.generator,
496
+ namingStrategy: config.namingStrategy
497
+ });
470
498
  isFirstBuild = false;
471
499
  } catch (error) {
472
500
  const message = error instanceof Error ? error.message : String(error);
@@ -481,7 +509,11 @@ function routeTypesPlugin(dts) {
481
509
  if (ctx.file.endsWith("pages.json")) {
482
510
  try {
483
511
  const pagesJsonPath = getValidatedPaths();
484
- generateRouteTypeFile(dts, pagesJsonPath);
512
+ generateRouteTypeFile(config.dts, pagesJsonPath, {
513
+ typeName: config.typeName,
514
+ generator: config.generator,
515
+ namingStrategy: config.namingStrategy
516
+ });
485
517
  console.log("\u{1F504} \u68C0\u6D4B\u5230 pages.json \u53D8\u5316\uFF0C\u5DF2\u81EA\u52A8\u66F4\u65B0\u8DEF\u7531\u7C7B\u578B");
486
518
  } catch (error) {
487
519
  const message = error instanceof Error ? error.message : String(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/type.ts","../src/utils.ts","../src/useRouter.ts","../src/useRoute.ts","../src/create.ts","../src/plugin.ts"],"sourcesContent":["import type { PageMetaDatum } from './pages';\r\n\r\nexport enum CloseTypes {\r\n default = 'default',\r\n current = 'current',\r\n all = 'all',\r\n}\r\n\r\nexport interface RouteMeta extends PageMetaDatum {\r\n /** 页面对应的真实路径,例如:pages/home/index */\r\n url: string\r\n /** 是否为 tabBar 页面 */\r\n isTabBar?: boolean\r\n /**\r\n * 页面唯一key\r\n */\r\n name: string\r\n}\r\n\r\nexport interface RouterParams<TPath extends string> {\r\n /** 路由名称(来自 createRouter 注册的类型) */\r\n path?: TPath\r\n /** 需要传递给目标页面的查询参数 */\r\n query?: Record<string, any>\r\n /** 页面关闭策略 */\r\n close?: CloseTypes | keyof typeof CloseTypes\r\n /** 成功回调,可以接收 handler 的返回值 */\r\n success?: (result?: unknown) => void\r\n /** 失败回调 */\r\n fail?: (error?: any) => void\r\n}\r\n\r\n/** 类型安全的路由推送函数类型 */\r\nexport type TypeSafePush<TPath extends string> = (\r\n data: TPath | RouterParams<TPath>,\r\n callbacks?: {\r\n success?: (result?: unknown) => void\r\n fail?: (error?: any) => void\r\n }\r\n) => Promise<void>\r\n\r\n/**\r\n * 页面关闭策略输入类型\r\n */\r\nexport type CloseInput = CloseTypes | keyof typeof CloseTypes | undefined;\r\n\r\n\r\n","import { PagesConfig } from \"./pages\";\r\nimport { CloseInput, CloseTypes, RouteMeta } from \"./type\";\r\n\r\n/**\r\n * 提取URL路径的第二段或者将多段路径用下划线连接\r\n * @param url 需要处理的URL\r\n * @returns 处理后的字符串\r\n */\r\nexport function extractSecondPathSegment(url: string): string {\r\n\tconst segments = url.split(\"/\").slice(1, -1);\r\n\treturn segments.length === 1 ? segments[0] : segments.join(\"_\");\r\n}\r\n\r\nconst isEnumValue = <T extends Record<string, string>>(enumObject: T, value: unknown): value is T[keyof T] =>\r\n\tObject.values(enumObject).includes(value as T[keyof T]);\r\n\r\nexport const ensureLeadingSlash = (url: string): string => (url.startsWith(\"/\") ? url : `/${url}`);\r\n\r\nexport const buildUrlWithQuery = (url: string, query: Record<string, any>): string => {\r\n\tconst normalized = ensureLeadingSlash(url);\r\n\tconst queryEntries = Object.entries(query ?? {}).filter(([, value]) => value !== undefined);\r\n\tif (queryEntries.length === 0) {\r\n\t\treturn normalized;\r\n\t}\r\n\r\n\tconst queryString = queryEntries\r\n\t\t.map(([key, value]) => {\r\n\t\t\tconst serialized = typeof value === \"object\" && value !== null ? JSON.stringify(value) : String(value);\r\n\t\t\treturn `${encodeURIComponent(key)}=${encodeURIComponent(serialized)}`;\r\n\t\t})\r\n\t\t.join(\"&\");\r\n\r\n\treturn `${normalized}?${queryString}`;\r\n};\r\nexport const resolveCloseType = (close: CloseInput): CloseTypes => {\r\n\tif (!close) return CloseTypes.default;\r\n\tif (isEnumValue(CloseTypes, close)) return close;\r\n\tif (typeof close === \"string\" && close in CloseTypes) return CloseTypes[close as keyof typeof CloseTypes];\r\n\treturn CloseTypes.default;\r\n};\r\n\r\n/**\r\n * 从 pages.json 解析路由信息\r\n * @param routes - pages.json 配置对象\r\n * @returns 路由元信息映射\r\n */\r\nexport function parseRoutesFromPagesJson<TName extends string>(routes: PagesConfig) {\r\n\tconst routeMeta = new Map<TName, RouteMeta>();\r\n\t// 获取 TabBar 页面路径集合\r\n\tconst tabBarPaths = new Set<string>();\r\n\tif (routes.tabBar?.list) {\r\n\t\troutes.tabBar.list.forEach(item => {\r\n\t\t\ttabBarPaths.add(item.pagePath);\r\n\t\t});\r\n\t}\r\n\r\n\t// 处理主包页面\r\n\tif (routes.pages) {\r\n\t\troutes.pages.forEach(page => {\r\n\t\t\tconst name = extractSecondPathSegment(page.path) as TName;\r\n\t\t\tif (name) {\r\n\t\t\t\trouteMeta.set(name, {\r\n\t\t\t\t\t...page,\r\n\t\t\t\t\tname,\r\n\t\t\t\t\tisTabBar: tabBarPaths.has(page.path) || page.type === \"tabBar\",\r\n\t\t\t\t\turl: page.path,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\tif (routes.subPackages) {\r\n\t\t// 处理分包页面\r\n\t\tconst subpackages = routes.subPackages;\r\n\t\tsubpackages.forEach(subpackage => {\r\n\t\t\tconst root = subpackage.root;\r\n\t\t\tsubpackage.pages.forEach(page => {\r\n\t\t\t\tconst fullPath = `${root}/${page.path}`;\r\n\t\t\t\tconst name = extractSecondPathSegment(fullPath) as TName;;\r\n\t\t\t\tif (name) {\r\n\t\t\t\t\trouteMeta.set(name, {\r\n\t\t\t\t\t\t...page,\r\n\t\t\t\t\t\tname,\r\n\t\t\t\t\t\tisTabBar: tabBarPaths.has(fullPath) || page.type === \"tabBar\",\r\n\t\t\t\t\t\turl: fullPath,\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\treturn routeMeta;\r\n}\r\n","import type { RouterCore } from './create';\r\nimport type { RouteLocationNormalized, RouteLocationRaw } from './create';\r\nimport { CloseTypes, RouterParams, TypeSafePush } from './type';\r\nimport { ensureLeadingSlash, buildUrlWithQuery, resolveCloseType, extractSecondPathSegment } from './utils';\r\n\r\n\r\nconst performNavigation = async (url: string, close: CloseTypes): Promise<void> => {\r\n\tconst navigationMethods: Record<CloseTypes, (options: UniApp.NavigateToOptions) => Promise<void>> = {\r\n\t\t[CloseTypes.default]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.navigateTo({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t\t[CloseTypes.current]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.redirectTo({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t\t[CloseTypes.all]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.reLaunch({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t};\r\n\r\n\tawait navigationMethods[close]({ url });\r\n};\r\n\r\nexport type RouterHookResult<TPath extends string> = {\r\n\t/** 类型安全的路由跳转方法 */\r\n\tpush: TypeSafePush<TPath>;\r\n};\r\n\r\n/**\r\n * 创建与指定 Router 实例绑定的路由钩子,避免在调用端重复传参。\r\n */\r\nexport function createRouterHook<TName extends string>(router: RouterCore<TName>): RouterHookResult<TName> {\r\n\t/**\r\n\t * 获取当前路由名称\r\n\t */\r\n\tconst getCurrentRouteName = (): TName | '' => {\r\n\t\tconst currentPage = getCurrentPages().at(-1);\r\n\t\tif (!currentPage?.route) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn (extractSecondPathSegment(currentPage.route) as TName) || '';\r\n\t};\r\n\r\n\t/**\r\n\t * 统一的路由跳转实现:先触发 createRouter 注册的拦截器与处理器,再执行实际跳转。\r\n\t */\r\n\tconst basicPush = async (input: TName | RouterParams<TName>): Promise<void> => {\r\n\t\tconst routeData = typeof input === 'string' ? { path: input } : input;\r\n\t\tconst path = routeData.path;\r\n\t\tif (!path) {\r\n\t\t\tconst error = new Error('路由名称不能为空');\r\n\t\t\trouteData.fail?.(error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst meta = router.getRouteMeta(path);\r\n\t\tif (!meta) {\r\n\t\t\tconst error = new Error(`找不到匹配的路由配置: ${String(path)}`);\r\n\t\t\trouteData.fail?.(error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst query = routeData.query ?? {};\r\n\t\tconst closeType = resolveCloseType(routeData.close);\r\n\r\n\t\tconst routePayload = { query, closeType, meta };\r\n\r\n\t\t// 获取来源路由信息\r\n\t\tconst fromName = getCurrentRouteName();\r\n\t\tconst fromMeta = fromName ? router.getRouteMeta(fromName) : undefined;\r\n\r\n\t\t// 创建标准化的路由位置对象\r\n\t\tconst to: RouteLocationNormalized<TName> = {\r\n\t\t\tname: path,\r\n\t\t\tmeta,\r\n\t\t\tquery,\r\n\t\t\tpath: meta.url,\r\n\t\t};\r\n\r\n\t\tconst from: RouteLocationNormalized<TName> = {\r\n\t\t\tname: fromName || ('' as TName),\r\n\t\t\tmeta: fromMeta,\r\n\t\t\tquery: {},\r\n\t\t\tpath: fromMeta?.url || '',\r\n\t\t};\r\n\r\n\t\tlet navigationResult: unknown;\r\n\t\tlet redirectTo: RouteLocationRaw<TName> | undefined;\r\n\r\n\t\ttry {\r\n\t\t\t// 执行 beforeEach 导航守卫\r\n\t\t\tconst beforeResult = await router.runBeforeInterceptors(to, from);\r\n\r\n\t\t\tif (!beforeResult.shouldContinue) {\r\n\t\t\t\t// 导航被取消\r\n\t\t\t\tif (beforeResult.redirectTo) {\r\n\t\t\t\t\t// 重定向到其他路由\r\n\t\t\t\t\tredirectTo = beforeResult.redirectTo;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 完全取消导航\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} catch (error) {\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 如果有重定向,递归调用 push\r\n\t\tif (redirectTo) {\r\n\t\t\tif (typeof redirectTo === 'string') {\r\n\t\t\t\t// 简单的路由名称重定向\r\n\t\t\t\treturn basicPush(\r\n\t\t\t\t\ttypeof routeData === 'object'\r\n\t\t\t\t\t\t? { ...routeData, path: redirectTo }\r\n\t\t\t\t\t\t: redirectTo\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\t// 路由对象重定向\r\n\t\t\t\treturn basicPush({\r\n\t\t\t\t\t...routeData,\r\n\t\t\t\t\tpath: redirectTo.path,\r\n\t\t\t\t\tquery: redirectTo.query || routeData.query,\r\n\t\t\t\t\t// TODO: 处理 replace 选项\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// 执行 handler\r\n\t\ttry {\r\n\t\t\tconst handler = router.getHandler(path);\r\n\t\t\tnavigationResult = handler ? await handler(routePayload) : undefined;\r\n\t\t\tawait router.runAfterInterceptors(to, from);\r\n\t\t} catch (error) {\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (navigationResult === false) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 将 query 和 handler 返回值一起缓存,供目标页面使用\r\n\t\trouter.setPageCache(path, {\r\n\t\t\tquery,\r\n\t\t\thandlerResult: navigationResult,\r\n\t\t});\r\n\r\n\t\ttry {\r\n\t\t\tif (meta.isTabBar) {\r\n\t\t\t\tif (Object.keys(query).length > 0) {\r\n\t\t\t\t\tconsole.warn('跳转 tabBar 页面时会忽略 query 参数');\r\n\t\t\t\t}\r\n\t\t\t\tawait new Promise<void>((resolve, reject) => {\r\n\t\t\t\t\tuni.switchTab({\r\n\t\t\t\t\t\turl: ensureLeadingSlash(meta.url),\r\n\t\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tawait performNavigation(buildUrlWithQuery(meta.url, query), closeType);\r\n\t\t\t}\r\n\r\n\t\t\t// 成功回调,传递 handler 的返回值(仅用于通知跳转成功)\r\n\t\t\trouteData.success?.(navigationResult);\r\n\t\t} catch (error) {\r\n\t\t\trouter.deletePageCache(path);\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t}\r\n\t};\r\n\r\n\t/**\r\n\t * 导出给外部使用的 push,支持额外回调合并。\r\n\t */\r\n\tconst push: TypeSafePush<TName> = async (data, callbacks) => {\r\n\t\tif (data == null) {\r\n\t\t\tconst error = new Error('路由参数不能为空');\r\n\t\t\tcallbacks?.fail?.(error);\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\tconst routeData = typeof data === 'string' ? { path: data } : data;\r\n\t\tconst finalRouteData: RouterParams<TName> = {\r\n\t\t\t...routeData,\r\n\t\t\tsuccess: callbacks?.success ?? routeData.success,\r\n\t\t\tfail: callbacks?.fail ?? routeData.fail,\r\n\t\t};\r\n\r\n\t\tawait basicPush(finalRouteData);\r\n\t};\r\n\r\n\treturn {\r\n\t\tpush\r\n\t}\r\n}","import { onMounted, reactive } from 'vue';\r\nimport type { UnwrapRef } from 'vue';\r\nimport type { RouterCore } from './create';\r\nimport type { RouteMeta } from './type';\r\nimport { extractSecondPathSegment } from './utils';\r\n\r\n/**\r\n * 扩展 uni-app 页面实例类型,包含 options 属性\r\n */\r\ninterface UniPageInstance extends Page.PageInstance<AnyObject, Record<string, any>> {\r\n\t/** 页面路由路径 */\r\n\troute?: string;\r\n\t/** 页面 URL 查询参数 */\r\n\toptions?: Record<string, string>;\r\n}\r\n\r\ntype RuntimePageInstance = UniPageInstance & {\r\n\t$page?: {\r\n\t\toptions?: Record<string, string>;\r\n\t\tfullPath?: string;\r\n\t};\r\n};\r\n\r\nconst decodeQuery = (query: Record<string, any>): Record<string, any> => {\r\n\tconst decoded: Record<string, any> = {};\r\n\tfor (const key in query) {\r\n\t\tconst value = query[key];\r\n\t\tif (typeof value === 'string') {\r\n\t\t\ttry {\r\n\t\t\t\tdecoded[key] = decodeURIComponent(value);\r\n\t\t\t} catch {\r\n\t\t\t\tdecoded[key] = value;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tdecoded[key] = value;\r\n\t\t}\r\n\t}\r\n\treturn decoded;\r\n};\r\n\r\nconst parseQueryString = (queryString?: string): Record<string, string> => {\r\n\tif (!queryString) return {};\r\n\treturn queryString.split(\"&\").reduce<Record<string, string>>((acc, segment) => {\r\n\t\tif (!segment) return acc;\r\n\t\tconst [rawKey, rawValue = \"\"] = segment.split(\"=\");\r\n\t\tconst key = decodeURIComponent(rawKey);\r\n\t\tconst value = decodeURIComponent(rawValue);\r\n\t\tacc[key] = value;\r\n\t\treturn acc;\r\n\t}, {});\r\n};\r\n\r\nconst resolvePageOptions = (page?: UniPageInstance): Record<string, any> => {\r\n\tif (!page) return {};\r\n\tconst runtimePage = page as RuntimePageInstance;\r\n\tconst sources: Record<string, any>[] = [];\r\n\r\n\tif (page.options && Object.keys(page.options).length > 0) {\r\n\t\tsources.push(decodeQuery(page.options));\r\n\t}\r\n\r\n\tif (runtimePage.$page?.options && Object.keys(runtimePage.$page.options).length > 0) {\r\n\t\tsources.push(decodeQuery(runtimePage.$page.options));\r\n\t}\r\n\r\n\tif (runtimePage.$page?.fullPath) {\r\n\t\tconst queryIndex = runtimePage.$page.fullPath.indexOf(\"?\");\r\n\t\tif (queryIndex !== -1) {\r\n\t\t\tsources.push(parseQueryString(runtimePage.$page.fullPath.slice(queryIndex + 1)));\r\n\t\t}\r\n\t}\r\n\r\n\tif (sources.length === 0) {\r\n\t\treturn {};\r\n\t}\r\n\r\n\treturn Object.assign({}, ...sources);\r\n};\r\n\r\n/**\r\n * useRoute 返回的路由信息\r\n */\r\nexport interface RouteInfo<TName extends string> {\r\n\t/** 路由名称 */\r\n\tname: TName;\r\n\t/** 路由元信息 */\r\n\tmeta?: RouteMeta;\r\n\t/** 合并后的查询参数(包含 URL 参数和缓存参数) */\r\n\tquery: Record<string, any>;\r\n\t/** Handler 返回值 */\r\n\thandlerResult?: unknown;\r\n}\r\n\r\n/**\r\n * 创建路由钩子,获取当前页面的路由信息\r\n * @param router - Router 核心实例\r\n * @returns 当前页面的路由信息\r\n */\r\nexport function createRouteHook<TName extends string>(router: RouterCore<TName>): RouteInfo<TName> {\r\n\t// 初始化响应式状态,在组件挂载后填充运行时数据\r\n\tconst state = reactive<RouteInfo<TName>>({\r\n\t\tname: '' as TName,\r\n\t\tmeta: undefined,\r\n\t\tquery: {},\r\n\t\thandlerResult: undefined,\r\n\t});\r\n\r\n\tonMounted(() => {\r\n\t\t// 获取当前页面实例\r\n\t\tconst pages = getCurrentPages();\r\n\t\tconst currentPage = pages[pages.length - 1] as UniPageInstance | undefined;\r\n\r\n\t\t// 如果没有当前页面,保留默认空状态并打印警告\r\n\t\tif (!currentPage?.route) {\r\n\t\t\t// 运行时未能获取到 page 实例\r\n\t\t\t// 不抛错,只是保留空状态以避免阻断调用方\r\n\t\t\t// 日志便于调试\r\n\t\t\t// eslint-disable-next-line no-console\r\n\t\t\tconsole.warn('无法获取当前页面的路由信息');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 从路由路径提取路由名称\r\n\t\tconst routeName = extractSecondPathSegment(currentPage.route) as TName;\r\n\r\n\t\t// 获取路由元信息\r\n\t\tconst meta = router.getRouteMeta(routeName);\r\n\r\n\t\t// 获取页面缓存数据(包含 query 和 handlerResult)\r\n\t\tconst cache = router.getPageCache(routeName as TName);\r\n\r\n\t\tconst runtimeQuery = resolvePageOptions(currentPage);\r\n\r\n\t\t// 合并查询参数: URL 中的参数为基础,缓存的 query(如果存在)覆盖它以保留原始类型\r\n\t\tconst mergedQuery: Record<string, any> = {\r\n\t\t\t...runtimeQuery,\r\n\t\t\t...(cache?.query ? decodeQuery(cache.query) : {}),\r\n\t\t};\r\n\t\tstate.name = routeName as unknown as UnwrapRef<TName>;\r\n\t\tstate.meta = meta;\r\n\t\tstate.query = mergedQuery;\r\n\t\tstate.handlerResult = cache?.handlerResult;\r\n\t\tstate.handlerResult = cache?.handlerResult;\r\n\t});\r\n\r\n\t// 类型声明需要一个普通的 `RouteInfo<TName>`,将响应式对象断言为该类型以兼容 d.ts 输出。\r\n\treturn state as unknown as RouteInfo<TName>;\r\n}","import { createRouterHook, RouterHookResult } from './useRouter';\r\nimport { createRouteHook, RouteInfo } from './useRoute';\r\nimport type { RouteMeta } from './type';\r\nimport { PagesConfig } from './pages';\r\nimport { parseRoutesFromPagesJson } from './utils';\r\n\r\n// 导出类型供外部使用\r\nexport type { RouteInfo, RouterHookResult, RouteMeta };\r\nexport { CloseTypes, RouterParams } from './type';\r\n\r\ntype RouteHandler = (payload?: unknown) => unknown | Promise<unknown>;\r\n\r\n/**\r\n * 标准化的路由位置\r\n */\r\nexport interface RouteLocationNormalized<TName extends string> {\r\n /** 路由名称 */\r\n name: TName;\r\n /** 路由元信息 */\r\n meta?: RouteMeta;\r\n /** 查询参数 */\r\n query: Record<string, any>;\r\n /** 完整路径 */\r\n path: string;\r\n}\r\n\r\n/**\r\n * 路由地址(用于重定向)\r\n */\r\nexport type RouteLocationRaw<TName extends string> =\r\n | TName\r\n | {\r\n path: TName;\r\n query?: Record<string, any>;\r\n replace?: boolean;\r\n };\r\n\r\n/**\r\n * 路由守卫函数类型\r\n * @param to 即将要进入的目标路由\r\n * @param from 当前导航正要离开的路由\r\n * @returns \r\n * - false: 取消当前导航\r\n * - RouteLocationRaw: 重定向到不同的地址\r\n * - undefined/true/void: 继续导航\r\n */\r\nexport type NavigationGuard<TName extends string> = (\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n) => void | boolean | RouteLocationRaw<TName> | Promise<void | boolean | RouteLocationRaw<TName>>;\r\n\r\n\r\n\r\n/**\r\n * Router 核心能力:注册处理函数与拦截器,并存储元信息。\r\n */\r\nexport interface RouterCore<TName extends string> {\r\n /**\r\n * 注册一个路由处理函数。返回一个取消订阅(卸载)函数,用于移除该处理函数。\r\n */\r\n register(name: TName, handler: RouteHandler): () => void;\r\n /**\r\n * 通过名称移除已注册的处理函数。若存在则返回 true。\r\n */\r\n unregister(name: TName): boolean;\r\n /**\r\n * 检查是否已为给定名称注册处理函数。\r\n */\r\n has(name: TName): boolean;\r\n /**\r\n * 获取指定路由名称对应的处理函数。\r\n */\r\n getHandler(name: TName): RouteHandler | undefined;\r\n /**\r\n * 添加一个 beforeEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n beforeEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 添加一个 afterEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n afterEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 记录路由元信息,返回一个用于撤销注册的函数。\r\n */\r\n defineRoute(name: TName, meta: RouteMeta): () => void;\r\n /**\r\n * 获取对应路由的元信息。\r\n */\r\n getRouteMeta(name: TName): RouteMeta | undefined;\r\n /**\r\n * 获取所有路由的元信息快照。\r\n */\r\n listRouteMeta(): ReadonlyMap<TName, RouteMeta>;\r\n /**\r\n * 手动执行 beforeEach 导航守卫链。\r\n * @returns 返回导航控制结果\r\n */\r\n runBeforeInterceptors(\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<{ shouldContinue: boolean; redirectTo?: RouteLocationRaw<TName> }>;\r\n /**\r\n * 手动执行 afterEach 导航守卫链。\r\n */\r\n runAfterInterceptors(to: RouteLocationNormalized<TName>, from: RouteLocationNormalized<TName>): Promise<void>;\r\n /**\r\n * 设置页面缓存数据(query 和 handler 返回值)\r\n */\r\n setPageCache(url: TName, data: { query: Record<string, any>; handlerResult?: unknown }): void;\r\n /**\r\n * 获取页面缓存数据\r\n */\r\n getPageCache(url: TName): { query: Record<string, any>; handlerResult?: unknown } | undefined;\r\n /**\r\n * 删除页面缓存数据\r\n */\r\n deletePageCache(url: TName): void;\r\n}\r\n\r\n/**\r\n * Router 对外暴露的完整接口,只包含公开的方法。\r\n */\r\nexport interface Router<TName extends string> {\r\n /**\r\n * 注册一个路由处理函数。返回一个取消订阅(卸载)函数,用于移除该处理函数。\r\n */\r\n register(name: TName, handler: RouteHandler): () => void;\r\n /**\r\n * 通过名称移除已注册的处理函数。若存在则返回 true。\r\n */\r\n unregister(name: TName): boolean;\r\n /**\r\n * 检查是否已为给定名称注册处理函数。\r\n */\r\n has(name: TName): boolean;\r\n /**\r\n * 添加一个 beforeEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n beforeEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 添加一个 afterEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n afterEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 生成绑定当前 Router 实例的 useRouter 钩子。\r\n */\r\n useRouter(): RouterHookResult<TName>;\r\n /**\r\n * 生成绑定当前 Router 实例的 useRoute 钩子,获取当前页面的路由信息。\r\n */\r\n useRoute(): RouteInfo<TName>;\r\n}\r\n\r\n/**\r\n * 创建一个路由实例,泛型 TName 表示允许的路由名称(通常为字符串字面量联合类型)。\r\n */\r\nexport function createRouter<const TRoutes extends Record<string, RouteMeta>>(routes: PagesConfig): Router<Extract<keyof TRoutes, string>>;\r\nexport function createRouter<TName extends string>(routes?: PagesConfig): Router<TName>;\r\nexport function createRouter<TName extends string>(routes?: PagesConfig): Router<TName> {\r\n // 存储路由处理函数的映射表\r\n const handlers = new Map<TName, RouteHandler>();\r\n // beforeEach 导航守卫数组\r\n const beforeInterceptors: NavigationGuard<TName>[] = [];\r\n // afterEach 导航守卫数组\r\n const afterInterceptors: NavigationGuard<TName>[] = [];\r\n // 路由元信息映射表\r\n const routeMeta = new Map<TName, RouteMeta>();\r\n // 页面缓存: 存储 query 和 handler 返回值\r\n const pageCache = new Map<TName, { query: Record<string, any>; handlerResult?: unknown }>();\r\n\r\n // 如果提供了 pages.json 配置,解析并注册所有路由\r\n if (routes) {\r\n parseRoutesFromPagesJson(routes).forEach((meta, name) => {\r\n routeMeta.set(name as TName, meta);\r\n });\r\n }\r\n\r\n /**\r\n * 添加守卫到指定的守卫数组\r\n * @param bucket 守卫数组\r\n * @param guard 要添加的守卫函数\r\n * @returns 返回一个卸载函数,调用后可移除该守卫\r\n */\r\n const addInterceptor = (bucket: NavigationGuard<TName>[], guard: NavigationGuard<TName>) => {\r\n bucket.push(guard);\r\n return () => {\r\n const index = bucket.indexOf(guard);\r\n if (index >= 0) bucket.splice(index, 1);\r\n };\r\n };\r\n /**\r\n * 执行导航守卫链\r\n * 按注册顺序依次执行守卫,任何守卫返回 false 或重定向地址都会中断后续守卫的执行\r\n * @param bucket 守卫数组\r\n * @param to 目标路由位置\r\n * @param from 来源路由位置\r\n * @returns 返回导航控制结果\r\n * - shouldContinue: true 表示继续导航, false 表示取消导航\r\n * - redirectTo: 如果存在,表示重定向到该地址\r\n */\r\n const runInterceptors = async (\r\n bucket: NavigationGuard<TName>[],\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<{ shouldContinue: boolean; redirectTo?: RouteLocationRaw<TName> }> => {\r\n for (const guard of bucket) {\r\n // 在循环中 await,以支持异步守卫的顺序执行\r\n // eslint-disable-next-line no-await-in-loop\r\n const result = await guard(to, from);\r\n\r\n // 处理守卫返回值\r\n if (result === false) {\r\n // 返回 false 取消导航\r\n return { shouldContinue: false };\r\n }\r\n\r\n if (result && typeof result === 'object' && 'path' in result) {\r\n // 返回路由对象重定向 { path: 'home', query: {...}, replace: true }\r\n return { shouldContinue: false, redirectTo: result };\r\n }\r\n\r\n if (typeof result === 'string') {\r\n // 返回路由名称字符串重定向\r\n return { shouldContinue: false, redirectTo: result as TName };\r\n }\r\n\r\n // result 为 undefined 或 true,继续执行下一个守卫\r\n }\r\n\r\n // 所有守卫都通过,允许导航继续\r\n return { shouldContinue: true };\r\n };\r\n\r\n /**\r\n * 执行 after 守卫链(不支持导航控制,仅用于通知)\r\n * after 守卫在导航完成后执行,无法阻止或重定向导航\r\n * @param bucket 守卫数组\r\n * @param to 目标路由位置\r\n * @param from 来源路由位置\r\n */\r\n const runAfterInterceptors = async (\r\n bucket: NavigationGuard<TName>[],\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<void> => {\r\n for (const guard of bucket) {\r\n // 按顺序执行所有 after 守卫\r\n // eslint-disable-next-line no-await-in-loop\r\n await guard(to, from);\r\n }\r\n };\r\n\r\n\r\n\r\n // Router 核心实现对象,包含所有内部方法\r\n const routerImpl: RouterCore<TName> = {\r\n // 注册路由处理函数\r\n register: (name, handler) => {\r\n handlers.set(name, handler);\r\n // 返回卸载函数\r\n return () => {\r\n handlers.delete(name);\r\n };\r\n },\r\n // 移除路由处理函数\r\n unregister: (name) => handlers.delete(name),\r\n // 检查是否已注册处理函数\r\n has: (name) => handlers.has(name),\r\n // 获取路由处理函数\r\n getHandler: (name) => handlers.get(name),\r\n // 添加 beforeEach 守卫\r\n beforeEach: (interceptor) => addInterceptor(beforeInterceptors, interceptor),\r\n // 添加 afterEach 守卫\r\n afterEach: (interceptor) => addInterceptor(afterInterceptors, interceptor),\r\n // 定义路由元信息\r\n defineRoute: (name, meta) => {\r\n routeMeta.set(name, meta);\r\n // 返回撤销函数\r\n return () => {\r\n routeMeta.delete(name);\r\n };\r\n },\r\n // 获取路由元信息\r\n getRouteMeta: (name) => routeMeta.get(name),\r\n // 获取所有路由元信息的只读快照\r\n listRouteMeta: () => new Map(routeMeta),\r\n // 执行 beforeEach 守卫链\r\n runBeforeInterceptors: (to, from) => runInterceptors(beforeInterceptors, to, from),\r\n // 执行 afterEach 守卫链\r\n runAfterInterceptors: (to, from) => runAfterInterceptors(afterInterceptors, to, from),\r\n // 页面缓存管理方法\r\n setPageCache: (name, data) => pageCache.set(name, data),\r\n getPageCache: (name) => pageCache.get(name),\r\n deletePageCache: (name) => pageCache.delete(name),\r\n };\r\n\r\n // 创建 useRouter 工厂函数,闭包持有完整的 routerImpl\r\n const useRouterFactory = () => createRouterHook(routerImpl);\r\n // 创建 useRoute 工厂函数,闭包持有完整的 routerImpl\r\n const useRouteFactory = () => createRouteHook(routerImpl);\r\n\r\n // 只返回公开的方法,隐藏内部实现细节\r\n return {\r\n afterEach: routerImpl.afterEach, // 注册 afterEach 守卫\r\n beforeEach: routerImpl.beforeEach, // 注册 beforeEach 守卫\r\n register: routerImpl.register, // 注册路由处理函数\r\n unregister: routerImpl.unregister, // 移除路由处理函数\r\n has: routerImpl.has, // 检查处理函数是否存在\r\n useRouter: useRouterFactory, // 创建 useRouter 钩子\r\n useRoute: useRouteFactory // 创建 useRoute 钩子\r\n } as Router<TName>;\r\n}\r\n","import { PagesConfig } from \"./pages\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { extractSecondPathSegment } from \"./utils\";\r\n\r\n\r\n\r\n/**\r\n * 从 pages.json 中提取所有路由名称\r\n * @param pagesJson pages.json 配置对象\r\n * @returns 路由名称的 Set 集合\r\n */\r\nfunction extractRouteNamesFromPages(pagesJson: PagesConfig): Set<string> {\r\n\tconst routes = new Set<string>();\r\n\r\n\t// 处理主包页面\r\n\tif (pagesJson.pages) {\r\n\t\tpagesJson.pages.forEach(page => {\r\n\t\t\tconst name = extractSecondPathSegment(page.path);\r\n\t\t\tif (name) {\r\n\t\t\t\troutes.add(name);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t// 处理分包页面\r\n\tif (pagesJson.subPackages) {\r\n\t\tpagesJson.subPackages.forEach(subpackage => {\r\n\t\t\tconst root = subpackage.root;\r\n\t\t\tsubpackage.pages.forEach(page => {\r\n\t\t\t\tconst name = extractSecondPathSegment(`${root}/${page.path}`);\r\n\t\t\t\tif (name) {\r\n\t\t\t\t\troutes.add(name);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\treturn routes;\r\n}\r\n\r\n/**\r\n * 生成路由类型定义字符串\r\n * @param routeNames 路由名称数组\r\n * @returns TypeScript 类型定义字符串\r\n */\r\nfunction generateTypeDefinition(routeNames: string[]): string {\r\n\tconst sortedRoutes = [...routeNames].sort((a, b) => a.localeCompare(b));\r\n\treturn `export type ENHANCE_ROUTE_PATH =\\n${sortedRoutes.map(name => ` | '${name}'`).join('\\n')}`;\r\n}\r\n\r\n/**\r\n * 读取并解析 pages.json 文件\r\n * @param pagesJsonPath pages.json 文件路径\r\n * @returns 解析后的配置对象\r\n */\r\nfunction readPagesJson(pagesJsonPath: string): PagesConfig {\r\n\tconst content = fs.readFileSync(pagesJsonPath, 'utf8');\r\n\treturn JSON.parse(content);\r\n}\r\n\r\n/**\r\n * 生成路由类型文件\r\n * @param dts 类型文件输出路径\r\n * @param pagesJsonPath pages.json 文件路径\r\n */\r\nfunction generateRouteTypeFile(dts: string, pagesJsonPath: string): void {\r\n\tconst pagesJson = readPagesJson(pagesJsonPath);\r\n\tconst routeNames = extractRouteNamesFromPages(pagesJson);\r\n\tconst typeDefinition = generateTypeDefinition(Array.from(routeNames));\r\n\tfs.writeFileSync(dts, typeDefinition, 'utf8');\r\n}\r\n\r\n// 环境配置验证\r\nconst getValidatedPaths = () => {\r\n\tconst inputDir = process.env.UNI_INPUT_DIR || `${process.env.INIT_CWD}/src`;\r\n\tif (!inputDir || inputDir.trim() === '') {\r\n\t\tthrow new Error('Missing required environment variables: UNI_INPUT_DIR or INIT_CWD');\r\n\t}\r\n\treturn path.resolve(inputDir, 'pages.json')\r\n};\r\n\r\n/**\r\n * Vite 插件: 自动生成路由类型定义\r\n * @param dts 类型文件输出路径\r\n * @returns Vite 插件对象\r\n */\r\nexport function routeTypesPlugin(dts: string) {\r\n\tlet isFirstBuild = true;\r\n\r\n\treturn {\r\n\t\tname: 'route-types-generator',\r\n\t\t/**\r\n\t\t * 构建开始时生成路由类型\r\n\t\t */\r\n\t\tbuildStart() {\r\n\t\t\t// 只在首次构建时生成类型,避免重复生成\r\n\t\t\tif (isFirstBuild) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst pagesJsonPath = getValidatedPaths();\r\n\t\t\t\t\tgenerateRouteTypeFile(dts, pagesJsonPath);\r\n\t\t\t\t\tisFirstBuild = false;\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\r\n\t\t\t\t\tconsole.warn('路由类型生成失败:', message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\t/**\r\n\t\t * 热更新时监听 pages.json 变化\r\n\t\t */\r\n\t\thandleHotUpdate(ctx: any) {\r\n\t\t\t// 监听 pages.json 变化,自动重新生成类型\r\n\t\t\tif (ctx.file.endsWith('pages.json')) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst pagesJsonPath = getValidatedPaths();\r\n\r\n\r\n\t\t\t\t\tgenerateRouteTypeFile(dts, pagesJsonPath);\r\n\t\t\t\t\tconsole.log('🔄 检测到 pages.json 变化,已自动更新路由类型');\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\r\n\t\t\t\t\tconsole.warn('热更新时生成路由类型失败:', message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t};\r\n}\r\n\r\n"],"mappings":"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","names":["CloseTypes","path"]}
1
+ {"version":3,"sources":["../src/type.ts","../src/utils.ts","../src/useRouter.ts","../src/useRoute.ts","../src/create.ts","../src/plugin.ts"],"sourcesContent":["import type { PageMetaDatum } from './pages';\r\n\r\nexport enum CloseTypes {\r\n default = 'default',\r\n current = 'current',\r\n all = 'all',\r\n}\r\n\r\nexport interface RouteMeta extends PageMetaDatum {\r\n /** 页面对应的真实路径,例如:pages/home/index */\r\n url: string\r\n /** 是否为 tabBar 页面 */\r\n isTabBar?: boolean\r\n /**\r\n * 页面唯一key\r\n */\r\n name: string\r\n}\r\n\r\nexport interface RouterParams<TPath extends string> {\r\n /** 路由名称(来自 createRouter 注册的类型) */\r\n path?: TPath\r\n /** 需要传递给目标页面的查询参数 */\r\n query?: Record<string, any>\r\n /** 页面关闭策略 */\r\n close?: CloseTypes | keyof typeof CloseTypes\r\n /** 成功回调,可以接收 handler 的返回值 */\r\n success?: (result?: unknown) => void\r\n /** 失败回调 */\r\n fail?: (error?: any) => void\r\n}\r\n\r\n/** 类型安全的路由推送函数类型 */\r\nexport type TypeSafePush<TPath extends string> = (\r\n data: TPath | RouterParams<TPath>,\r\n callbacks?: {\r\n success?: (result?: unknown) => void\r\n fail?: (error?: any) => void\r\n }\r\n) => Promise<void>\r\n\r\n/**\r\n * 页面关闭策略输入类型\r\n */\r\nexport type CloseInput = CloseTypes | keyof typeof CloseTypes | undefined;\r\n\r\n\r\n","import { PagesConfig } from \"./pages\";\r\nimport { CloseInput, CloseTypes, RouteMeta } from \"./type\";\r\n\r\n/**\r\n * 提取URL路径的第二段或者将多段路径用下划线连接\r\n * @param url 需要处理的URL\r\n * @returns 处理后的字符串\r\n */\r\nexport type RouteNameStrategy = 'default' | 'package_page' | ((routePath: string) => string);\r\n\r\nexport function extractSecondPathSegment(url: string): string {\r\n\tconst segments = url.split(\"/\").slice(1, -1);\r\n\treturn segments.length === 1 ? segments[0] : segments.join(\"_\");\r\n}\r\n\r\nexport const resolveRouteName = (routePath: string, strategy: RouteNameStrategy = 'default'): string | undefined => {\r\n\tif (typeof strategy === 'function') {\r\n\t\treturn strategy(routePath);\r\n\t}\r\n\r\n\tconst normalized = routePath.replace(/^\\/+/, '').replace(/\\.vue$/i, '');\r\n\tif (strategy === 'package_page') {\r\n\t\tconst segments = normalized.split('/').filter(Boolean);\r\n\t\tif (segments[segments.length - 1] === 'index') {\r\n\t\t\tsegments.pop();\r\n\t\t}\r\n\t\treturn segments.length > 0 ? segments.join('_') : undefined;\r\n\t}\r\n\r\n\treturn extractSecondPathSegment(routePath);\r\n};\r\n\r\nconst isEnumValue = <T extends Record<string, string>>(enumObject: T, value: unknown): value is T[keyof T] =>\r\n\tObject.values(enumObject).includes(value as T[keyof T]);\r\n\r\nexport const ensureLeadingSlash = (url: string): string => (url.startsWith(\"/\") ? url : `/${url}`);\r\n\r\nexport const buildUrlWithQuery = (url: string, query: Record<string, any>): string => {\r\n\tconst normalized = ensureLeadingSlash(url);\r\n\tconst queryEntries = Object.entries(query ?? {}).filter(([, value]) => value !== undefined);\r\n\tif (queryEntries.length === 0) {\r\n\t\treturn normalized;\r\n\t}\r\n\r\n\tconst queryString = queryEntries\r\n\t\t.map(([key, value]) => {\r\n\t\t\tconst serialized = typeof value === \"object\" && value !== null ? JSON.stringify(value) : String(value);\r\n\t\t\treturn `${encodeURIComponent(key)}=${encodeURIComponent(serialized)}`;\r\n\t\t})\r\n\t\t.join(\"&\");\r\n\r\n\treturn `${normalized}?${queryString}`;\r\n};\r\nexport const resolveCloseType = (close: CloseInput): CloseTypes => {\r\n\tif (!close) return CloseTypes.default;\r\n\tif (isEnumValue(CloseTypes, close)) return close;\r\n\tif (typeof close === \"string\" && close in CloseTypes) return CloseTypes[close as keyof typeof CloseTypes];\r\n\treturn CloseTypes.default;\r\n};\r\n\r\n/**\r\n * 从 pages.json 解析路由信息\r\n * @param routes - pages.json 配置对象\r\n * @returns 路由元信息映射\r\n */\r\nexport function parseRoutesFromPagesJson<TName extends string>(routes: PagesConfig, namingStrategy: RouteNameStrategy = 'default') {\r\n\tconst routeMeta = new Map<TName, RouteMeta>();\r\n\t// 获取 TabBar 页面路径集合\r\n\tconst tabBarPaths = new Set<string>();\r\n\tif (routes.tabBar?.list) {\r\n\t\troutes.tabBar.list.forEach(item => {\r\n\t\t\ttabBarPaths.add(item.pagePath);\r\n\t\t});\r\n\t}\r\n\r\n\t// 处理主包页面\r\n\tif (routes.pages) {\r\n\t\troutes.pages.forEach(page => {\r\n\t\t\tconst name = resolveRouteName(page.path, namingStrategy) as TName;\r\n\t\t\tif (name) {\r\n\t\t\t\trouteMeta.set(name, {\r\n\t\t\t\t\t...page,\r\n\t\t\t\t\tname,\r\n\t\t\t\t\tisTabBar: tabBarPaths.has(page.path) || page.type === \"tabBar\",\r\n\t\t\t\t\turl: page.path,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\tif (routes.subPackages) {\r\n\t\t// 处理分包页面\r\n\t\tconst subpackages = routes.subPackages;\r\n\t\tsubpackages.forEach(subpackage => {\r\n\t\t\tconst root = subpackage.root;\r\n\t\t\tsubpackage.pages.forEach(page => {\r\n\t\t\t\tconst fullPath = `${root}/${page.path}`;\r\n\t\t\t\tconst name = resolveRouteName(fullPath, namingStrategy) as TName;;\r\n\t\t\t\tif (name) {\r\n\t\t\t\t\trouteMeta.set(name, {\r\n\t\t\t\t\t\t...page,\r\n\t\t\t\t\t\tname,\r\n\t\t\t\t\t\tisTabBar: tabBarPaths.has(fullPath) || page.type === \"tabBar\",\r\n\t\t\t\t\t\turl: fullPath,\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\treturn routeMeta;\r\n}\r\n","import type { RouterCore } from './create';\r\nimport type { RouteLocationNormalized, RouteLocationRaw } from './create';\r\nimport { CloseTypes, RouterParams, TypeSafePush } from './type';\r\nimport { ensureLeadingSlash, buildUrlWithQuery, resolveCloseType } from './utils';\r\n\r\n\r\nconst performNavigation = async (url: string, close: CloseTypes): Promise<void> => {\r\n\tconst navigationMethods: Record<CloseTypes, (options: UniApp.NavigateToOptions) => Promise<void>> = {\r\n\t\t[CloseTypes.default]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.navigateTo({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t\t[CloseTypes.current]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.redirectTo({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t\t[CloseTypes.all]: (options) =>\r\n\t\t\tnew Promise<void>((resolve, reject) => {\r\n\t\t\t\tuni.reLaunch({\r\n\t\t\t\t\t...options,\r\n\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t});\r\n\t\t\t}),\r\n\t};\r\n\r\n\tawait navigationMethods[close]({ url });\r\n};\r\n\r\nexport type RouterHookResult<TPath extends string> = {\r\n\t/** 类型安全的路由跳转方法 */\r\n\tpush: TypeSafePush<TPath>;\r\n};\r\n\r\n/**\r\n * 创建与指定 Router 实例绑定的路由钩子,避免在调用端重复传参。\r\n */\r\nexport function createRouterHook<TName extends string>(router: RouterCore<TName>): RouterHookResult<TName> {\r\n\t/**\r\n\t * 获取当前路由名称\r\n\t */\r\n\tconst getCurrentRouteName = (): TName | '' => {\r\n\t\tconst currentPage = getCurrentPages().at(-1);\r\n\t\tif (!currentPage?.route) {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t\treturn router.resolveNameByUrl(currentPage.route) || '';\r\n\t};\r\n\r\n\t/**\r\n\t * 统一的路由跳转实现:先触发 createRouter 注册的拦截器与处理器,再执行实际跳转。\r\n\t */\r\n\tconst basicPush = async (input: TName | RouterParams<TName>): Promise<void> => {\r\n\t\tconst routeData = typeof input === 'string' ? { path: input } : input;\r\n\t\tconst path = routeData.path;\r\n\t\tif (!path) {\r\n\t\t\tconst error = new Error('路由名称不能为空');\r\n\t\t\trouteData.fail?.(error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst meta = router.getRouteMeta(path);\r\n\t\tif (!meta) {\r\n\t\t\tconst error = new Error(`找不到匹配的路由配置: ${String(path)}`);\r\n\t\t\trouteData.fail?.(error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst query = routeData.query ?? {};\r\n\t\tconst closeType = resolveCloseType(routeData.close);\r\n\r\n\t\tconst routePayload = { query, closeType, meta };\r\n\r\n\t\t// 获取来源路由信息\r\n\t\tconst fromName = getCurrentRouteName();\r\n\t\tconst fromMeta = fromName ? router.getRouteMeta(fromName) : undefined;\r\n\r\n\t\t// 创建标准化的路由位置对象\r\n\t\tconst to: RouteLocationNormalized<TName> = {\r\n\t\t\tname: path,\r\n\t\t\tmeta,\r\n\t\t\tquery,\r\n\t\t\tpath: meta.url,\r\n\t\t};\r\n\r\n\t\tconst from: RouteLocationNormalized<TName> = {\r\n\t\t\tname: fromName || ('' as TName),\r\n\t\t\tmeta: fromMeta,\r\n\t\t\tquery: {},\r\n\t\t\tpath: fromMeta?.url || '',\r\n\t\t};\r\n\r\n\t\tlet navigationResult: unknown;\r\n\t\tlet redirectTo: RouteLocationRaw<TName> | undefined;\r\n\r\n\t\ttry {\r\n\t\t\t// 执行 beforeEach 导航守卫\r\n\t\t\tconst beforeResult = await router.runBeforeInterceptors(to, from);\r\n\r\n\t\t\tif (!beforeResult.shouldContinue) {\r\n\t\t\t\t// 导航被取消\r\n\t\t\t\tif (beforeResult.redirectTo) {\r\n\t\t\t\t\t// 重定向到其他路由\r\n\t\t\t\t\tredirectTo = beforeResult.redirectTo;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 完全取消导航\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} catch (error) {\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 如果有重定向,递归调用 push\r\n\t\tif (redirectTo) {\r\n\t\t\tif (typeof redirectTo === 'string') {\r\n\t\t\t\t// 简单的路由名称重定向\r\n\t\t\t\treturn basicPush(\r\n\t\t\t\t\ttypeof routeData === 'object'\r\n\t\t\t\t\t\t? { ...routeData, path: redirectTo }\r\n\t\t\t\t\t\t: redirectTo\r\n\t\t\t\t);\r\n\t\t\t} else {\r\n\t\t\t\t// 路由对象重定向\r\n\t\t\t\treturn basicPush({\r\n\t\t\t\t\t...routeData,\r\n\t\t\t\t\tpath: redirectTo.path,\r\n\t\t\t\t\tquery: redirectTo.query || routeData.query,\r\n\t\t\t\t\t// TODO: 处理 replace 选项\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// 执行 handler\r\n\t\ttry {\r\n\t\t\tconst handler = router.getHandler(path);\r\n\t\t\tnavigationResult = handler ? await handler(routePayload) : undefined;\r\n\t\t\tawait router.runAfterInterceptors(to, from);\r\n\t\t} catch (error) {\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (navigationResult === false) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 将 query 和 handler 返回值一起缓存,供目标页面使用\r\n\t\trouter.setPageCache(path, {\r\n\t\t\tquery,\r\n\t\t\thandlerResult: navigationResult,\r\n\t\t});\r\n\r\n\t\ttry {\r\n\t\t\tif (meta.isTabBar) {\r\n\t\t\t\tif (Object.keys(query).length > 0) {\r\n\t\t\t\t\tconsole.warn('跳转 tabBar 页面时会忽略 query 参数');\r\n\t\t\t\t}\r\n\t\t\t\tawait new Promise<void>((resolve, reject) => {\r\n\t\t\t\t\tuni.switchTab({\r\n\t\t\t\t\t\turl: ensureLeadingSlash(meta.url),\r\n\t\t\t\t\t\tsuccess: () => resolve(),\r\n\t\t\t\t\t\tfail: (err) => reject(err),\r\n\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tawait performNavigation(buildUrlWithQuery(meta.url, query), closeType);\r\n\t\t\t}\r\n\r\n\t\t\t// 成功回调,传递 handler 的返回值(仅用于通知跳转成功)\r\n\t\t\trouteData.success?.(navigationResult);\r\n\t\t} catch (error) {\r\n\t\t\trouter.deletePageCache(path);\r\n\t\t\trouteData.fail?.(error as Error);\r\n\t\t\tif (!routeData.fail) throw error;\r\n\t\t}\r\n\t};\r\n\r\n\t/**\r\n\t * 导出给外部使用的 push,支持额外回调合并。\r\n\t */\r\n\tconst push: TypeSafePush<TName> = async (data, callbacks) => {\r\n\t\tif (data == null) {\r\n\t\t\tconst error = new Error('路由参数不能为空');\r\n\t\t\tcallbacks?.fail?.(error);\r\n\t\t\tthrow error;\r\n\t\t}\r\n\r\n\t\tconst routeData = typeof data === 'string' ? { path: data } : data;\r\n\t\tconst finalRouteData: RouterParams<TName> = {\r\n\t\t\t...routeData,\r\n\t\t\tsuccess: callbacks?.success ?? routeData.success,\r\n\t\t\tfail: callbacks?.fail ?? routeData.fail,\r\n\t\t};\r\n\r\n\t\tawait basicPush(finalRouteData);\r\n\t};\r\n\r\n\treturn {\r\n\t\tpush\r\n\t}\r\n}","import { onMounted, reactive } from 'vue';\r\nimport type { UnwrapRef } from 'vue';\r\nimport type { RouterCore } from './create';\r\nimport type { RouteMeta } from './type';\r\nimport { extractSecondPathSegment } from './utils';\r\n\r\n/**\r\n * 扩展 uni-app 页面实例类型,包含 options 属性\r\n */\r\ninterface UniPageInstance extends Page.PageInstance<AnyObject, Record<string, any>> {\r\n\t/** 页面路由路径 */\r\n\troute?: string;\r\n\t/** 页面 URL 查询参数 */\r\n\toptions?: Record<string, string>;\r\n}\r\n\r\ntype RuntimePageInstance = UniPageInstance & {\r\n\t$page?: {\r\n\t\toptions?: Record<string, string>;\r\n\t\tfullPath?: string;\r\n\t};\r\n};\r\n\r\nconst decodeQuery = (query: Record<string, any>): Record<string, any> => {\r\n\tconst decoded: Record<string, any> = {};\r\n\tfor (const key in query) {\r\n\t\tconst value = query[key];\r\n\t\tif (typeof value === 'string') {\r\n\t\t\ttry {\r\n\t\t\t\tdecoded[key] = decodeURIComponent(value);\r\n\t\t\t} catch {\r\n\t\t\t\tdecoded[key] = value;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tdecoded[key] = value;\r\n\t\t}\r\n\t}\r\n\treturn decoded;\r\n};\r\n\r\nconst parseQueryString = (queryString?: string): Record<string, string> => {\r\n\tif (!queryString) return {};\r\n\treturn queryString.split(\"&\").reduce<Record<string, string>>((acc, segment) => {\r\n\t\tif (!segment) return acc;\r\n\t\tconst [rawKey, rawValue = \"\"] = segment.split(\"=\");\r\n\t\tconst key = decodeURIComponent(rawKey);\r\n\t\tconst value = decodeURIComponent(rawValue);\r\n\t\tacc[key] = value;\r\n\t\treturn acc;\r\n\t}, {});\r\n};\r\n\r\nconst resolvePageOptions = (page?: UniPageInstance): Record<string, any> => {\r\n\tif (!page) return {};\r\n\tconst runtimePage = page as RuntimePageInstance;\r\n\tconst sources: Record<string, any>[] = [];\r\n\r\n\tif (page.options && Object.keys(page.options).length > 0) {\r\n\t\tsources.push(decodeQuery(page.options));\r\n\t}\r\n\r\n\tif (runtimePage.$page?.options && Object.keys(runtimePage.$page.options).length > 0) {\r\n\t\tsources.push(decodeQuery(runtimePage.$page.options));\r\n\t}\r\n\r\n\tif (runtimePage.$page?.fullPath) {\r\n\t\tconst queryIndex = runtimePage.$page.fullPath.indexOf(\"?\");\r\n\t\tif (queryIndex !== -1) {\r\n\t\t\tsources.push(parseQueryString(runtimePage.$page.fullPath.slice(queryIndex + 1)));\r\n\t\t}\r\n\t}\r\n\r\n\tif (sources.length === 0) {\r\n\t\treturn {};\r\n\t}\r\n\r\n\treturn Object.assign({}, ...sources);\r\n};\r\n\r\n/**\r\n * useRoute 返回的路由信息\r\n */\r\nexport interface RouteInfo<TName extends string> {\r\n\t/** 路由名称 */\r\n\tname: TName;\r\n\t/** 路由元信息 */\r\n\tmeta?: RouteMeta;\r\n\t/** 合并后的查询参数(包含 URL 参数和缓存参数) */\r\n\tquery: Record<string, any>;\r\n\t/** Handler 返回值 */\r\n\thandlerResult?: unknown;\r\n}\r\n\r\n/**\r\n * 创建路由钩子,获取当前页面的路由信息\r\n * @param router - Router 核心实例\r\n * @returns 当前页面的路由信息\r\n */\r\nexport function createRouteHook<TName extends string>(router: RouterCore<TName>): RouteInfo<TName> {\r\n\t// 初始化响应式状态,在组件挂载后填充运行时数据\r\n\tconst state = reactive<RouteInfo<TName>>({\r\n\t\tname: '' as TName,\r\n\t\tmeta: undefined,\r\n\t\tquery: {},\r\n\t\thandlerResult: undefined,\r\n\t});\r\n\r\n\tonMounted(() => {\r\n\t\t// 获取当前页面实例\r\n\t\tconst pages = getCurrentPages();\r\n\t\tconst currentPage = pages[pages.length - 1] as UniPageInstance | undefined;\r\n\r\n\t\t// 如果没有当前页面,保留默认空状态并打印警告\r\n\t\tif (!currentPage?.route) {\r\n\t\t\t// 运行时未能获取到 page 实例\r\n\t\t\t// 不抛错,只是保留空状态以避免阻断调用方\r\n\t\t\t// 日志便于调试\r\n\t\t\t// eslint-disable-next-line no-console\r\n\t\t\tconsole.warn('无法获取当前页面的路由信息');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// 从路由路径提取路由名称\r\n\t\tconst routeName = (router.resolveNameByUrl(currentPage.route) || extractSecondPathSegment(currentPage.route)) as TName;\r\n\r\n\t\t// 获取路由元信息\r\n\t\tconst meta = router.getRouteMeta(routeName);\r\n\r\n\t\t// 获取页面缓存数据(包含 query 和 handlerResult)\r\n\t\tconst cache = router.getPageCache(routeName as TName);\r\n\r\n\t\tconst runtimeQuery = resolvePageOptions(currentPage);\r\n\r\n\t\t// 合并查询参数: URL 中的参数为基础,缓存的 query(如果存在)覆盖它以保留原始类型\r\n\t\tconst mergedQuery: Record<string, any> = {\r\n\t\t\t...runtimeQuery,\r\n\t\t\t...(cache?.query ? decodeQuery(cache.query) : {}),\r\n\t\t};\r\n\t\tstate.name = routeName as unknown as UnwrapRef<TName>;\r\n\t\tstate.meta = meta;\r\n\t\tstate.query = mergedQuery;\r\n\t\tstate.handlerResult = cache?.handlerResult;\r\n\t\tstate.handlerResult = cache?.handlerResult;\r\n\t});\r\n\r\n\t// 类型声明需要一个普通的 `RouteInfo<TName>`,将响应式对象断言为该类型以兼容 d.ts 输出。\r\n\treturn state as unknown as RouteInfo<TName>;\r\n}","import { createRouterHook, RouterHookResult } from './useRouter';\r\nimport { createRouteHook, RouteInfo } from './useRoute';\r\nimport type { RouteMeta } from './type';\r\nimport { PagesConfig } from './pages';\r\nimport { parseRoutesFromPagesJson, RouteNameStrategy } from './utils';\r\n\r\n// 导出类型供外部使用\r\nexport type { RouteInfo, RouterHookResult, RouteMeta };\r\nexport { CloseTypes, RouterParams } from './type';\r\n\r\n\r\nexport interface CreateRouterOptions {\r\n namingStrategy?: RouteNameStrategy;\r\n}\r\n\r\ntype RouteHandler = (payload?: unknown) => unknown | Promise<unknown>;\r\n\r\n/**\r\n * 标准化的路由位置\r\n */\r\nexport interface RouteLocationNormalized<TName extends string> {\r\n /** 路由名称 */\r\n name: TName;\r\n /** 路由元信息 */\r\n meta?: RouteMeta;\r\n /** 查询参数 */\r\n query: Record<string, any>;\r\n /** 完整路径 */\r\n path: string;\r\n}\r\n\r\n/**\r\n * 路由地址(用于重定向)\r\n */\r\nexport type RouteLocationRaw<TName extends string> =\r\n | TName\r\n | {\r\n path: TName;\r\n query?: Record<string, any>;\r\n replace?: boolean;\r\n };\r\n\r\n/**\r\n * 路由守卫函数类型\r\n * @param to 即将要进入的目标路由\r\n * @param from 当前导航正要离开的路由\r\n * @returns \r\n * - false: 取消当前导航\r\n * - RouteLocationRaw: 重定向到不同的地址\r\n * - undefined/true/void: 继续导航\r\n */\r\nexport type NavigationGuard<TName extends string> = (\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n) => void | boolean | RouteLocationRaw<TName> | Promise<void | boolean | RouteLocationRaw<TName>>;\r\n\r\n\r\n\r\n/**\r\n * Router 核心能力:注册处理函数与拦截器,并存储元信息。\r\n */\r\nexport interface RouterCore<TName extends string> {\r\n /**\r\n * 注册一个路由处理函数。返回一个取消订阅(卸载)函数,用于移除该处理函数。\r\n */\r\n register(name: TName, handler: RouteHandler): () => void;\r\n /**\r\n * 通过名称移除已注册的处理函数。若存在则返回 true。\r\n */\r\n unregister(name: TName): boolean;\r\n /**\r\n * 检查是否已为给定名称注册处理函数。\r\n */\r\n has(name: TName): boolean;\r\n /**\r\n * 获取指定路由名称对应的处理函数。\r\n */\r\n getHandler(name: TName): RouteHandler | undefined;\r\n /**\r\n * 添加一个 beforeEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n beforeEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 添加一个 afterEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n afterEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 记录路由元信息,返回一个用于撤销注册的函数。\r\n */\r\n defineRoute(name: TName, meta: RouteMeta): () => void;\r\n /**\r\n * 获取对应路由的元信息。\r\n */\r\n getRouteMeta(name: TName): RouteMeta | undefined;\r\n /**\r\n * 获取所有路由的元信息快照。\r\n */\r\n listRouteMeta(): ReadonlyMap<TName, RouteMeta>;\r\n /**\r\n * 手动执行 beforeEach 导航守卫链。\r\n * @returns 返回导航控制结果\r\n */\r\n runBeforeInterceptors(\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<{ shouldContinue: boolean; redirectTo?: RouteLocationRaw<TName> }>;\r\n /**\r\n * 手动执行 afterEach 导航守卫链。\r\n */\r\n runAfterInterceptors(to: RouteLocationNormalized<TName>, from: RouteLocationNormalized<TName>): Promise<void>;\r\n /**\r\n * 设置页面缓存数据(query 和 handler 返回值)\r\n */\r\n setPageCache(url: TName, data: { query: Record<string, any>; handlerResult?: unknown }): void;\r\n /**\r\n * 获取页面缓存数据\r\n */\r\n getPageCache(url: TName): { query: Record<string, any>; handlerResult?: unknown } | undefined;\r\n /**\r\n * 删除页面缓存数据\r\n */\r\n deletePageCache(url: TName): void;\r\n /**\r\n * 根据 pages.json 原始 url 解析出路由名称\r\n */\r\n resolveNameByUrl(routePath: string): TName | undefined;\r\n}\r\n\r\n/**\r\n * Router 对外暴露的完整接口,只包含公开的方法。\r\n */\r\nexport interface Router<TName extends string> {\r\n /**\r\n * 注册一个路由处理函数。返回一个取消订阅(卸载)函数,用于移除该处理函数。\r\n */\r\n register(name: TName, handler: RouteHandler): () => void;\r\n /**\r\n * 通过名称移除已注册的处理函数。若存在则返回 true。\r\n */\r\n unregister(name: TName): boolean;\r\n /**\r\n * 检查是否已为给定名称注册处理函数。\r\n */\r\n has(name: TName): boolean;\r\n /**\r\n * 添加一个 beforeEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n beforeEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 添加一个 afterEach 导航守卫。返回一个卸载该守卫的函数。\r\n */\r\n afterEach(guard: NavigationGuard<TName>): () => void;\r\n /**\r\n * 生成绑定当前 Router 实例的 useRouter 钩子。\r\n */\r\n useRouter(): RouterHookResult<TName>;\r\n /**\r\n * 生成绑定当前 Router 实例的 useRoute 钩子,获取当前页面的路由信息。\r\n */\r\n useRoute(): RouteInfo<TName>;\r\n}\r\n\r\n/**\r\n * 创建一个路由实例,泛型 TName 表示允许的路由名称(通常为字符串字面量联合类型)。\r\n */\r\nexport function createRouter<const TRoutes extends Record<string, RouteMeta>>(routes: PagesConfig, options?: CreateRouterOptions): Router<Extract<keyof TRoutes, string>>;\r\nexport function createRouter<TName extends string>(routes?: PagesConfig, options?: CreateRouterOptions): Router<TName>;\r\nexport function createRouter<TName extends string>(routes?: PagesConfig, options?: CreateRouterOptions): Router<TName> {\r\n // 存储路由处理函数的映射表\r\n const handlers = new Map<TName, RouteHandler>();\r\n // beforeEach 导航守卫数组\r\n const beforeInterceptors: NavigationGuard<TName>[] = [];\r\n // afterEach 导航守卫数组\r\n const afterInterceptors: NavigationGuard<TName>[] = [];\r\n // 路由元信息映射表\r\n const routeMeta = new Map<TName, RouteMeta>();\r\n // 页面缓存: 存储 query 和 handler 返回值\r\n const pageCache = new Map<TName, { query: Record<string, any>; handlerResult?: unknown }>();\r\n\r\n // 如果提供了 pages.json 配置,解析并注册所有路由\r\n const namingStrategy = options?.namingStrategy || 'default';\r\n\r\n if (routes) {\r\n parseRoutesFromPagesJson(routes, namingStrategy).forEach((meta, name) => {\r\n routeMeta.set(name as TName, meta);\r\n });\r\n }\r\n\r\n /**\r\n * 添加守卫到指定的守卫数组\r\n * @param bucket 守卫数组\r\n * @param guard 要添加的守卫函数\r\n * @returns 返回一个卸载函数,调用后可移除该守卫\r\n */\r\n const addInterceptor = (bucket: NavigationGuard<TName>[], guard: NavigationGuard<TName>) => {\r\n bucket.push(guard);\r\n return () => {\r\n const index = bucket.indexOf(guard);\r\n if (index >= 0) bucket.splice(index, 1);\r\n };\r\n };\r\n /**\r\n * 执行导航守卫链\r\n * 按注册顺序依次执行守卫,任何守卫返回 false 或重定向地址都会中断后续守卫的执行\r\n * @param bucket 守卫数组\r\n * @param to 目标路由位置\r\n * @param from 来源路由位置\r\n * @returns 返回导航控制结果\r\n * - shouldContinue: true 表示继续导航, false 表示取消导航\r\n * - redirectTo: 如果存在,表示重定向到该地址\r\n */\r\n const runInterceptors = async (\r\n bucket: NavigationGuard<TName>[],\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<{ shouldContinue: boolean; redirectTo?: RouteLocationRaw<TName> }> => {\r\n for (const guard of bucket) {\r\n // 在循环中 await,以支持异步守卫的顺序执行\r\n // eslint-disable-next-line no-await-in-loop\r\n const result = await guard(to, from);\r\n\r\n // 处理守卫返回值\r\n if (result === false) {\r\n // 返回 false 取消导航\r\n return { shouldContinue: false };\r\n }\r\n\r\n if (result && typeof result === 'object' && 'path' in result) {\r\n // 返回路由对象重定向 { path: 'home', query: {...}, replace: true }\r\n return { shouldContinue: false, redirectTo: result };\r\n }\r\n\r\n if (typeof result === 'string') {\r\n // 返回路由名称字符串重定向\r\n return { shouldContinue: false, redirectTo: result as TName };\r\n }\r\n\r\n // result 为 undefined 或 true,继续执行下一个守卫\r\n }\r\n\r\n // 所有守卫都通过,允许导航继续\r\n return { shouldContinue: true };\r\n };\r\n\r\n /**\r\n * 执行 after 守卫链(不支持导航控制,仅用于通知)\r\n * after 守卫在导航完成后执行,无法阻止或重定向导航\r\n * @param bucket 守卫数组\r\n * @param to 目标路由位置\r\n * @param from 来源路由位置\r\n */\r\n const runAfterInterceptors = async (\r\n bucket: NavigationGuard<TName>[],\r\n to: RouteLocationNormalized<TName>,\r\n from: RouteLocationNormalized<TName>\r\n ): Promise<void> => {\r\n for (const guard of bucket) {\r\n // 按顺序执行所有 after 守卫\r\n // eslint-disable-next-line no-await-in-loop\r\n await guard(to, from);\r\n }\r\n };\r\n\r\n\r\n\r\n // Router 核心实现对象,包含所有内部方法\r\n const routerImpl: RouterCore<TName> = {\r\n // 注册路由处理函数\r\n register: (name, handler) => {\r\n handlers.set(name, handler);\r\n // 返回卸载函数\r\n return () => {\r\n handlers.delete(name);\r\n };\r\n },\r\n // 移除路由处理函数\r\n unregister: (name) => handlers.delete(name),\r\n // 检查是否已注册处理函数\r\n has: (name) => handlers.has(name),\r\n // 获取路由处理函数\r\n getHandler: (name) => handlers.get(name),\r\n // 添加 beforeEach 守卫\r\n beforeEach: (interceptor) => addInterceptor(beforeInterceptors, interceptor),\r\n // 添加 afterEach 守卫\r\n afterEach: (interceptor) => addInterceptor(afterInterceptors, interceptor),\r\n // 定义路由元信息\r\n defineRoute: (name, meta) => {\r\n routeMeta.set(name, meta);\r\n // 返回撤销函数\r\n return () => {\r\n routeMeta.delete(name);\r\n };\r\n },\r\n // 获取路由元信息\r\n getRouteMeta: (name) => routeMeta.get(name),\r\n // 获取所有路由元信息的只读快照\r\n listRouteMeta: () => new Map(routeMeta),\r\n // 执行 beforeEach 守卫链\r\n runBeforeInterceptors: (to, from) => runInterceptors(beforeInterceptors, to, from),\r\n // 执行 afterEach 守卫链\r\n runAfterInterceptors: (to, from) => runAfterInterceptors(afterInterceptors, to, from),\r\n // 页面缓存管理方法\r\n setPageCache: (name, data) => pageCache.set(name, data),\r\n getPageCache: (name) => pageCache.get(name),\r\n deletePageCache: (name) => pageCache.delete(name),\r\n resolveNameByUrl: (routePath: string) => {\r\n const normalized = routePath.replace(/^\\/+/, '');\r\n for (const [name, meta] of routeMeta.entries()) {\r\n if (meta.url === normalized) return name;\r\n }\r\n return undefined;\r\n },\r\n };\r\n\r\n // 创建 useRouter 工厂函数,闭包持有完整的 routerImpl\r\n const useRouterFactory = () => createRouterHook(routerImpl);\r\n // 创建 useRoute 工厂函数,闭包持有完整的 routerImpl\r\n const useRouteFactory = () => createRouteHook(routerImpl);\r\n\r\n // 只返回公开的方法,隐藏内部实现细节\r\n return {\r\n afterEach: routerImpl.afterEach, // 注册 afterEach 守卫\r\n beforeEach: routerImpl.beforeEach, // 注册 beforeEach 守卫\r\n register: routerImpl.register, // 注册路由处理函数\r\n unregister: routerImpl.unregister, // 移除路由处理函数\r\n has: routerImpl.has, // 检查处理函数是否存在\r\n useRouter: useRouterFactory, // 创建 useRouter 钩子\r\n useRoute: useRouteFactory // 创建 useRoute 钩子\r\n } as Router<TName>;\r\n}\r\n","import { PagesConfig } from \"./pages\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { resolveRouteName, RouteNameStrategy } from \"./utils\";\r\nexport type { RouteNameStrategy } from \"./utils\";\r\n\r\n/**\r\n * 插件配置选项\r\n */\r\nexport interface RouteTypesPluginOptions {\r\n\t/** 类型文件输出路径 */\r\n\tdts: string;\r\n\t/** 自定义类型名称,默认为 'ENHANCE_ROUTE_PATH' */\r\n\ttypeName?: string;\r\n\t/** 自定义类型生成规则 */\r\n\tgenerator?: (routeNames: string[], typeName: string) => string;\r\n\t/** 路由名称生成策略,默认 'default' */\r\n\tnamingStrategy?: RouteNameStrategy;\r\n}\r\n\r\n\r\n/**\r\n * 从 pages.json 中提取所有路由名称\r\n * @param pagesJson pages.json 配置对象\r\n * @returns 路由名称的 Set 集合\r\n */\r\nfunction extractRouteNamesFromPages(pagesJson: PagesConfig, namingStrategy: RouteNameStrategy): Set<string> {\r\n\tconst routes = new Set<string>();\r\n\r\n\t// 处理主包页面\r\n\tif (pagesJson.pages) {\r\n\t\tpagesJson.pages.forEach(page => {\r\n\t\t\tconst name = resolveRouteName(page.path, namingStrategy);\r\n\t\t\tif (name) {\r\n\t\t\t\troutes.add(name);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t// 处理分包页面\r\n\tif (pagesJson.subPackages) {\r\n\t\tpagesJson.subPackages.forEach(subpackage => {\r\n\t\t\tconst root = subpackage.root;\r\n\t\t\tsubpackage.pages.forEach(page => {\r\n\t\t\t\tconst name = resolveRouteName(`${root}/${page.path}`, namingStrategy);\r\n\t\t\t\tif (name) {\r\n\t\t\t\t\troutes.add(name);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\treturn routes;\r\n}\r\n\r\n/**\r\n * 生成路由类型定义字符串\r\n * @param routeNames 路由名称数组\r\n * @param typeName 类型名称\r\n * @returns TypeScript 类型定义字符串\r\n */\r\nfunction generateTypeDefinition(routeNames: string[], typeName: string = 'ENHANCE_ROUTE_PATH'): string {\r\n\tconst sortedRoutes = [...routeNames].sort((a, b) => a.localeCompare(b));\r\n\treturn `export type ${typeName} =\\n${sortedRoutes.map(name => ` | '${name}'`).join('\\n')}`;\r\n}\r\n\r\n/**\r\n * 读取并解析 pages.json 文件\r\n * @param pagesJsonPath pages.json 文件路径\r\n * @returns 解析后的配置对象\r\n */\r\nfunction readPagesJson(pagesJsonPath: string): PagesConfig {\r\n\tconst content = fs.readFileSync(pagesJsonPath, 'utf8');\r\n\treturn JSON.parse(content);\r\n}\r\n\r\n/**\r\n * 生成路由类型文件\r\n * @param dts 类型文件输出路径\r\n * @param pagesJsonPath pages.json 文件路径\r\n * @param options 可选配置\r\n */\r\nfunction generateRouteTypeFile(\r\n\tdts: string,\r\n\tpagesJsonPath: string,\r\n\toptions?: { typeName?: string; generator?: (routeNames: string[], typeName: string) => string; namingStrategy?: RouteNameStrategy }\r\n): void {\r\n\tconst pagesJson = readPagesJson(pagesJsonPath);\r\n\tconst routeNames = extractRouteNamesFromPages(pagesJson, options?.namingStrategy || 'default');\r\n\tconst typeName = options?.typeName || 'ENHANCE_ROUTE_PATH';\r\n\tconst typeDefinition = options?.generator\r\n\t\t? options.generator(Array.from(routeNames), typeName)\r\n\t\t: generateTypeDefinition(Array.from(routeNames), typeName);\r\n\tfs.writeFileSync(dts, typeDefinition, 'utf8');\r\n}\r\n\r\n// 环境配置验证\r\nconst getValidatedPaths = () => {\r\n\tconst inputDir = process.env.UNI_INPUT_DIR || `${process.env.INIT_CWD}/src`;\r\n\tif (!inputDir || inputDir.trim() === '') {\r\n\t\tthrow new Error('Missing required environment variables: UNI_INPUT_DIR or INIT_CWD');\r\n\t}\r\n\treturn path.resolve(inputDir, 'pages.json')\r\n};\r\n\r\n/**\r\n * Vite 插件: 自动生成路由类型定义\r\n * @param options 插件配置选项,可以是字符串(类型文件输出路径)或配置对象\r\n * @returns Vite 插件对象\r\n */\r\nexport function routeTypesPlugin(options: string | RouteTypesPluginOptions) {\r\n\tlet isFirstBuild = true;\r\n\tconst config: RouteTypesPluginOptions = typeof options === 'string'\r\n\t\t? { dts: options }\r\n\t\t: options;\r\n\r\n\treturn {\r\n\t\tname: 'route-types-generator',\r\n\t\t/**\r\n\t\t * 构建开始时生成路由类型\r\n\t\t */\r\n\t\tbuildStart() {\r\n\t\t\t// 只在首次构建时生成类型,避免重复生成\r\n\t\t\tif (isFirstBuild) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst pagesJsonPath = getValidatedPaths();\r\n\t\t\t\t\tgenerateRouteTypeFile(config.dts, pagesJsonPath, {\r\n\t\t\t\t\t\ttypeName: config.typeName,\r\n\t\t\t\t\t\tgenerator: config.generator,\r\n\t\t\t\t\t\tnamingStrategy: config.namingStrategy,\r\n\t\t\t\t\t});\r\n\t\t\t\t\tisFirstBuild = false;\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\r\n\t\t\t\t\tconsole.warn('路由类型生成失败:', message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\t/**\r\n\t\t * 热更新时监听 pages.json 变化\r\n\t\t */\r\n\t\thandleHotUpdate(ctx: any) {\r\n\t\t\t// 监听 pages.json 变化,自动重新生成类型\r\n\t\t\tif (ctx.file.endsWith('pages.json')) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst pagesJsonPath = getValidatedPaths();\r\n\t\t\t\t\tgenerateRouteTypeFile(config.dts, pagesJsonPath, {\r\n\t\t\t\t\t\ttypeName: config.typeName,\r\n\t\t\t\t\t\tgenerator: config.generator,\r\n\t\t\t\t\t\tnamingStrategy: config.namingStrategy,\r\n\t\t\t\t\t});\r\n\t\t\t\t\tconsole.log('🔄 检测到 pages.json 变化,已自动更新路由类型');\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\r\n\t\t\t\t\tconsole.warn('热更新时生成路由类型失败:', message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t};\r\n}\r\n\r\n"],"mappings":"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","names":["CloseTypes","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uni-router-enhance",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "一个为 uni-app 设计的类型安全路由增强库,提供完整的 TypeScript 支持、路由守卫、动态处理函数等高级特性",
5
5
  "files": [
6
6
  "dist"