uni-router-enhance 1.0.4 → 1.0.5

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.js CHANGED
@@ -336,7 +336,7 @@ function createRouteHook(router) {
336
336
  const runtimeQuery = resolvePageOptions(currentPage);
337
337
  const mergedQuery = {
338
338
  ...runtimeQuery,
339
- ...cache?.query
339
+ ...cache?.query ? decodeQuery(cache.query) : {}
340
340
  };
341
341
  state.name = routeName;
342
342
  state.meta = meta;
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,\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 } 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"]}
package/dist/index.mjs CHANGED
@@ -299,7 +299,7 @@ function createRouteHook(router) {
299
299
  const runtimeQuery = resolvePageOptions(currentPage);
300
300
  const mergedQuery = {
301
301
  ...runtimeQuery,
302
- ...cache?.query
302
+ ...cache?.query ? decodeQuery(cache.query) : {}
303
303
  };
304
304
  state.name = routeName;
305
305
  state.meta = meta;
@@ -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,\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 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uni-router-enhance",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "一个为 uni-app 设计的类型安全路由增强库,提供完整的 TypeScript 支持、路由守卫、动态处理函数等高级特性",
5
5
  "files": [
6
6
  "dist"