@route-forge/vue 2.2.0 → 2.2.1
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/README.md +1 -1
- package/README_zh.md +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ plugin.ready()
|
|
|
39
39
|
})
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
> Plugin options are exactly `createRouteForge(options)` (`levels` / `eager` / `adapter` / `cache` / `interceptors` / `timeout` / `baseURL`); full options table in the [core README](../core/README.md#options-createrouteforgeoptions).
|
|
42
|
+
> Plugin options are exactly `createRouteForge(options)` (`endpoint` / `summary` / `levels` / `eager` / `adapter` / `cache` / `interceptors` / `timeout` / `baseURL`); full options table in the [core README](../core/README.md#options-createrouteforgeoptions). `options` itself is optional — when the summary is embedded in the page via `@forgeSummary` (`window.__ROUTE_FORGE__`), install with a bare `createRouteForgePlugin()`.
|
|
43
43
|
|
|
44
44
|
## useForge — the core composable
|
|
45
45
|
|
package/README_zh.md
CHANGED
|
@@ -38,7 +38,7 @@ plugin.ready()
|
|
|
38
38
|
})
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
> 插件选项与 `createRouteForge(options)` 完全一致(`levels` / `eager` / `adapter` / `cache` / `interceptors` / `timeout` / `baseURL`),完整选项表见 [core README](../core/README_zh.md#配置选项createruteforgeoptions)
|
|
41
|
+
> 插件选项与 `createRouteForge(options)` 完全一致(`endpoint` / `summary` / `levels` / `eager` / `adapter` / `cache` / `interceptors` / `timeout` / `baseURL`),完整选项表见 [core README](../core/README_zh.md#配置选项createruteforgeoptions)。`options` 本身可选——摘要由页面内嵌 `@forgeSummary`(`window.__ROUTE_FORGE__`)提供时,可直接 `createRouteForgePlugin()` 无参安装。
|
|
42
42
|
|
|
43
43
|
## useForge — 核心 composable
|
|
44
44
|
|
package/dist/index.cjs
CHANGED
|
@@ -5,7 +5,7 @@ var core = require('@route-forge/core');
|
|
|
5
5
|
|
|
6
6
|
// src/plugin.ts
|
|
7
7
|
var FORGE_INJECTION_KEY = /* @__PURE__ */ Symbol("route-forge");
|
|
8
|
-
function createRouteForgePlugin(options) {
|
|
8
|
+
function createRouteForgePlugin(options = {}) {
|
|
9
9
|
const forge = core.createRouteForge(options);
|
|
10
10
|
return {
|
|
11
11
|
ready: forge.ready.bind(forge),
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts","../src/composables/useForgeApi.ts","../src/composables/useForgeRoute.ts","../src/components/shared.ts","../src/components/ForgeRoute.ts","../src/components/ForgeLink.ts"],"names":["createRouteForge","inject","ref","onMounted","computed","getCurrentInstance","defineComponent","h"],"mappings":";;;;;;AA2BO,IAAM,mBAAA,0BAAuD,aAAa;AAO1E,SAAS,uBAAuB,OAAA,EAErC;AACA,EAAA,MAAM,KAAA,GAAQA,sBAAiB,OAAO,CAAA;AAEtC,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA;AAAA,IAC7B,QAAQ,GAAA,EAAU;AAChB,MAAA,GAAA,CAAI,OAAA,CAAQ,qBAAqB,KAAK,CAAA;AACtC,MAAA,GAAA,CAAI,MAAA,CAAO,iBAAiB,MAAA,GAAS;AAAA,QACnC,KAAA,EAAO,CAAC,KAAA,EAAe,IAAA,EAAc,WACnC,KAAA,CAAM,KAAA,CAAM,KAAA,EAAO,IAAA,EAAM,MAAM;AAAA,OACnC;AAAA,IACF;AAAA,GACF;AACF;AA4BO,SAAS,QAAA,CAAS,OAAgB,MAAA,EAA6C;AACpF,EAAA,MAAM,KAAA,GAAQC,WAAO,mBAAmB,CAAA;AACxC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,OAAO,KAAA;AAAA,EACT;AAGA,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,GAAA,CAAI,KAAA,EAAO,MAAM,CAAA;AAGrC,EAAA,MAAM,cAAA,GAAiBC,QAAI,KAAK,CAAA;AAChC,EAAA,KAAA,CAAM,WAAA,CAAY,KAAK,MAAM;AAC3B,IAAA,cAAA,CAAe,KAAA,GAAQ,IAAA;AAAA,EACzB,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,EAAmC,CAAC,CAAA;AAEnD,EAAA,MAAA,CAAO,cAAA,CAAe,OAAO,aAAA,EAAe;AAAA,IAC1C,KAAA,EAAO,cAAA;AAAA,IACP,QAAA,EAAU,KAAA;AAAA,IACV,UAAA,EAAY,IAAA;AAAA,IACZ,YAAA,EAAc;AAAA,GACf,CAAA;AAED,EAAA,OAAO,KAAA;AACT;AClEO,SAAS,WAAA,CAAY,OAAgB,MAAA,EAA2E;AACrH,EAAA,MAAM,QAAQ,KAAA,KAAU,MAAA,GAAY,QAAA,CAAS,KAAA,EAAO,MAAgB,CAAA,GAAI,MAAA;AACxE,EAAA,MAAM,OAAA,GAAU,KAAA,KAAU,MAAA,GAAY,QAAA,EAAS,GAAI,MAAA;AACnD,EAAA,MAAM,OAAA,GAAUA,QAAI,KAAK,CAAA;AACzB,EAAA,MAAM,KAAA,GAAQA,QAAa,IAAI,CAAA;AAE/B,EAAA,IAAI,QAAA,GAAW,CAAA;AAEf,EAAA,eAAe,QAAQ,IAAA,EAA6D;AAClF,IAAA,QAAA,EAAA;AACA,IAAA,OAAA,CAAQ,KAAA,GAAQ,IAAA;AAChB,IAAA,KAAA,CAAM,KAAA,GAAQ,IAAA;AACd,IAAA,IAAI;AAGF,MAAA,MAAM,IAAA,GAAO,KAAA,KAAU,KAAA,CAAA,GACnB,MAAO,KAAA,CAAgC,IAAI,IAAA,CAAK,CAAC,CAAA,EAAa,IAAA,CAAK,CAAC,CAAU,IAC9E,MAAO,OAAA,CAAuB,GAAA,CAAI,IAAA,CAAK,CAAC,CAAA,EAAa,KAAK,CAAC,CAAA,EAAa,IAAA,CAAK,CAAC,CAAU,CAAA;AAC5F,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,IAAA,EAAK;AAAA,IAC7B,SAAS,CAAA,EAAG;AACV,MAAA,KAAA,CAAM,KAAA,GAAQ,CAAA;AACd,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAW,KAAA,EAAO,CAAA,EAAE;AAAA,IACrC,CAAA,SAAE;AACA,MAAA,QAAA,EAAA;AACA,MAAA,OAAA,CAAQ,QAAQ,QAAA,GAAW,CAAA;AAAA,IAC7B;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,IAAA,EAAyC;AACpE;AClDA,SAAS,gBAAgB,KAAA,EAAsB;AAC7C,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,gKAAA;AAAA,IACA,gCAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF;AACF;AAOO,SAAS,aAAA,CACd,KAAA,EACA,IAAA,EACA,MAAA,EACA,KAAA,EACqB;AAErB,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,MAAM,IAAI,SAAA;AAAA,MACR;AAAA,KAGF;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQD,WAAO,mBAAmB,CAAA;AAKxC,EAAA,MAAM,GAAA,GAAM,KAAA;AAGZ,EAAA,MAAM,WAAA,GAAcC,OAAAA,CAAI,KAAA,CAAM,QAAA,CAAS,GAAG,CAAC,CAAA;AAE3C,EAAA,IAAI,CAAC,YAAY,KAAA,EAAO;AACtB,IAAAC,aAAA,CAAU,MAAM;AACd,MAAA,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA,CAAE,IAAA,CAAK,MAAM;AACzB,QAAA,WAAA,CAAY,KAAA,GAAQ,IAAA;AAAA,MACtB,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,MACf,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAOC,aAAS,MAAM;AAEpB,IAAA,IAAI,CAAC,WAAA,CAAY,KAAA,EAAO,OAAO,EAAA;AAE/B,IAAA,MAAM,CAAA,GAAI,OAAO,IAAA,KAAS,UAAA,GAAa,MAAK,GAAI,IAAA;AAChD,IAAA,MAAM,CAAA,GAAI,MAAA,GAAS,MAAA,EAAO,GAAI,MAAA;AAC9B,IAAA,IAAI;AACF,MAAA,OAAO,KAAA,CAAM,KAAA,CAAM,GAAA,EAAK,CAAA,EAAG,CAAC,CAAA;AAAA,IAC9B,SAAS,CAAA,EAAG;AACV,MAAA,CAAC,KAAA,EAAO,SAAA,IAAa,eAAA,EAAiB,CAAC,CAAA;AACvC,MAAA,OAAO,EAAA;AAAA,IACT;AAAA,EACF,CAAC,CAAA;AACH;ACtEO,IAAM,cAAA,GAAiB;AAAA;AAAA,EAE5B,KAAA,EAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,UAAU,IAAA,EAAK;AAAA;AAAA,EAEtC,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,CAAC,MAAA,EAAQ,QAAQ,CAAA;AAAA,IACvB,QAAA,EAAU;AAAA,GACZ;AAAA;AAAA,EAEA,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,CAAC,MAAA,EAAQ,QAAQ,CAAA;AAAA,IACvB,QAAA,EAAU,KAAA;AAAA,IACV,OAAA,EAAS;AAAA;AAEb,CAAA;AAGO,SAAS,aAAA,CAAc,WAAmB,KAAA,EAAsB;AACrE,EAAA,OAAA,CAAQ,KAAA;AAAA,IACN,qBAAqB,SAAS,CAAA,qIAAA,CAAA;AAAA,IAC9B,gCAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF;AACF;AAGO,SAAS,gBAAA,CAAiB,SAAA,EAAmB,KAAA,EAAe,MAAA,EAAkC;AACnG,EAAA,IAAI,OAAO,KAAA,EAAO;AAClB,EAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AACf,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,CAAA,cAAA,EAAiB,SAAS,CAAA,SAAA,EAAY,KAAK,CAAA,sIAAA;AAAA,GAC7C;AACF;AAOO,SAAS,iBAAA,GAAmC;AACjD,EAAA,MAAM,OAAOC,sBAAA,EAAmB;AAChC,EAAA,MAAM,KAAA,GAAQ,MAAM,UAAA,CAAW,UAAA;AAC/B,EAAA,OAAO,KAAA,EAAO,UAAA,IAAc,KAAA,GAAQ,aAAa,CAAA,IAAK,IAAA;AACxD;;;ACrCO,IAAM,aAAaC,mBAAA,CAAgB;AAAA,EACxC,IAAA,EAAM,YAAA;AAAA;AAAA,EAEN,YAAA,EAAc,KAAA;AAAA,EACd,KAAA,EAAO,cAAA;AAAA,EACP,KAAA,EAAO,MAAA;AAAA,EAIP,KAAA,CAAM,KAAA,EAAO,EAAE,KAAA,EAAM,EAAG;AACtB,IAAA,MAAM,KAAA,GAAQL,WAAO,mBAAmB,CAAA;AAExC,IAAA,MAAM,UAAA,GAAa,MAAO,OAAO,KAAA,CAAM,SAAS,UAAA,GAAa,KAAA,CAAM,IAAA,EAAK,GAAI,KAAA,CAAM,IAAA;AAClF,IAAA,MAAM,YAAA,GAAe,MACnB,OAAO,KAAA,CAAM,WAAW,UAAA,GAAa,KAAA,CAAM,MAAA,EAAO,GAAI,KAAA,CAAM,MAAA;AAC9D,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,KAAA,CAAM,KAAA,EAAO,YAAY,YAAA,EAAc;AAAA,MAChE,SAAA,EAAW,CAAC,CAAA,KAAM,aAAA,CAAc,cAAc,CAAC;AAAA,KAChD,CAAA;AACD,IAAA,MAAM,YAAA,GAAe,EAAE,KAAA,EAAO,KAAA,EAAM;AAEpC,IAAA,OAAO,MAAM;AACX,MAAA,MAAM,MAAM,IAAA,CAAK,KAAA;AACjB,MAAA,MAAM,SAAS,GAAA,KAAQ,EAAA;AACvB,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAM,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA,EAAG;AAC3C,QAAA,gBAAA,CAAiB,YAAA,EAAc,KAAA,CAAM,KAAA,EAAO,YAAY,CAAA;AAAA,MAC1D;AAEA,MAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,MAAM,OAAA,GAAU,KAAA,CAAM,SAAQ,GAAI,IAAA;AACtD,MAAA,OAAO,KAAA,CAAM,UAAU,KAAA,CAAM,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,EAAK,MAAA,EAAQ,CAAA,GAAI,IAAA;AAAA,IAChE,CAAA;AAAA,EACF;AACF,CAAC;ACxBM,IAAM,YAAYK,mBAAAA,CAAgB;AAAA,EACvC,IAAA,EAAM,WAAA;AAAA;AAAA,EAEN,YAAA,EAAc,KAAA;AAAA,EACd,KAAA,EAAO,cAAA;AAAA,EACP,KAAA,EAAO,MAAA;AAAA,EAMP,KAAA,CAAM,KAAA,EAAO,EAAE,KAAA,EAAO,OAAM,EAAG;AAC7B,IAAA,MAAM,KAAA,GAAQL,WAAO,mBAAmB,CAAA;AAExC,IAAA,MAAM,UAAA,GAAa,MAAO,OAAO,KAAA,CAAM,SAAS,UAAA,GAAa,KAAA,CAAM,IAAA,EAAK,GAAI,KAAA,CAAM,IAAA;AAClF,IAAA,MAAM,YAAA,GAAe,MACnB,OAAO,KAAA,CAAM,WAAW,UAAA,GAAa,KAAA,CAAM,MAAA,EAAO,GAAI,KAAA,CAAM,MAAA;AAC9D,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,KAAA,CAAM,KAAA,EAAO,YAAY,YAAA,EAAc;AAAA,MAChE,SAAA,EAAW,CAAC,CAAA,KAAM,aAAA,CAAc,aAAa,CAAC;AAAA,KAC/C,CAAA;AACD,IAAA,MAAM,YAAA,GAAe,EAAE,KAAA,EAAO,KAAA,EAAM;AAEpC,IAAA,MAAM,aAAa,iBAAA,EAAkB;AAErC,IAAA,OAAO,MAAM;AACX,MAAA,MAAM,MAAM,IAAA,CAAK,KAAA;AACjB,MAAA,MAAM,SAAS,GAAA,KAAQ,EAAA;AACvB,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAM,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA,EAAG;AAC3C,QAAA,gBAAA,CAAiB,WAAA,EAAa,KAAA,CAAM,KAAA,EAAO,YAAY,CAAA;AAAA,MACzD;AACA,MAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,MAAM,OAAA,GAAU,KAAA,CAAM,SAAQ,GAAI,IAAA;AAEtD,MAAA,MAAM,QAAA,GAAW,KAAA,CAAM,OAAA,GAAU,KAAA,CAAM,SAAQ,GAAI,MAAA;AACnD,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,OAAOM,KAAA;AAAA,UACL,UAAA;AAAA,UACA,EAAE,GAAI,KAAA,EAAmC,EAAA,EAAI,GAAA,EAAI;AAAA,UACjD,EAAE,OAAA,EAAS,MAAM,QAAA;AAAS,SAC5B;AAAA,MACF;AACA,MAAA,OAAOA,KAAA,CAAE,KAAK,EAAE,GAAI,OAAmC,IAAA,EAAM,GAAA,IAAO,QAAQ,CAAA;AAAA,IAC9E,CAAA;AAAA,EACF;AACF,CAAC","file":"index.cjs","sourcesContent":["/**\n * Vue 3 插件入口\n * @see .docs/SPEC.md §4.1.7\n *\n * 提供:\n * - 全局属性 $forge(route() 工具)\n * - inject symbol 注入 RouteForge 实例供 composable 使用\n * - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例\n * • 不传 level:forge(level, name, params?) 直接调用\n * • 传 level:forge(name, params?) 直接调用,自动绑定层级\n * • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n */\n\nimport type { App, InjectionKey, Plugin, Ref } from 'vue';\nimport { inject, ref } from 'vue';\nimport {\n type ApiCallParams,\n type BoundForge,\n createRouteForge,\n type RouteForge,\n type RouteForgeOptions,\n} from '@route-forge/core';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** Vue 特化类型:levelLoaded 为 Ref<boolean> */\nexport type VueBoundForge = BoundForge<Ref<boolean>>;\n\nexport function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]> & {\n ready: RouteForge['ready']\n} {\n const forge = createRouteForge(options);\n\n return {\n ready: forge.ready.bind(forge),\n install(app: App) {\n app.provide(FORGE_INJECTION_KEY, forge);\n app.config.globalProperties.$forge = {\n route: (level: string, name: string, params?: Record<string, unknown>) =>\n forge.route(level, name, params),\n };\n },\n };\n}\n\n/**\n * 获取 forge 实例。内部委托 core 的 forge.use(),仅将 levelLoaded 替换为 Vue 响应式 Ref。\n *\n * @example\n * // 不绑定层级\n * const forge = useForge()\n * forge('admin', 'users.show', { user: 1 })\n * forge.api('admin', 'users.show')\n *\n * @example\n * // 绑定层级 — 直接调用和 api/route/url 均无需传 level\n * const forge = useForge('admin')\n * forge.level // → 'admin'\n * forge.levelLoaded // Ref<boolean>\n * forge('users.show', { user: 1 })\n * forge.route('users.show', { user: 1 })\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): VueBoundForge;\nexport function useForge<L extends string>(level: L): VueBoundForge;\nexport function useForge(): RouteForge;\nexport function useForge(level?: string, prefix?: string): RouteForge | VueBoundForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n '[route-forge/vue] useForge() must be used inside an app with createRouteForgePlugin() installed',\n );\n }\n\n if (level === undefined) {\n return forge;\n }\n\n // 委托 core 的 use(),获取 BoundForge(levelLoaded 为 Promise<void>)\n const bound = forge.use(level, prefix);\n\n // 将 levelLoaded 从 Promise<void> 替换为 Ref<boolean>\n const levelLoadedRef = ref(false);\n bound.levelLoaded.then(() => {\n levelLoadedRef.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */ });\n\n Object.defineProperty(bound, 'levelLoaded', {\n value: levelLoadedRef,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n\n return bound as unknown as VueBoundForge;\n}\n","/**\n * useForgeApi:包装 forge.api(),自动管理 loading/error 状态\n * @see .docs/SPEC.md §4.1.7\n *\n * 支持:\n * - useForgeApi() — call(level, name, params)\n * - useForgeApi(level) — call(name, params),自动绑定层级\n * - useForgeApi(level, prefix) — call(suffix, params),自动绑定层级 + 拼接前缀\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * pending 采用引用计数:并发多个 call 时,全部完成才置 false\n * (先完成的 call 不再把其他在途请求的 pending 提前清掉)。\n */\n\nimport type { Ref } from 'vue';\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type {\n BoundForge,\n RouteForge,\n UseForgeApiBoundCall,\n UseForgeApiBoundReturn,\n UseForgeApiCall,\n UseForgeApiReturn,\n} from '@route-forge/core';\n\n// Vue 特化类型:pending/error 为 Ref\nexport type { UseForgeApiCall, UseForgeApiBoundCall };\nexport type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;\nexport type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturnVue;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturnVue | UseForgeApiBoundReturnVue<string> {\n const bound = level !== undefined ? useForge(level, prefix as string) : undefined;\n const unbound = bound === undefined ? useForge() : undefined;\n const pending = ref(false);\n const error = ref<unknown>(null);\n // 并发计数:setup 闭包变量(组件实例生命周期存活)\n let inflight = 0;\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n inflight++;\n pending.value = true;\n error.value = null;\n try {\n // 按绑定形态分发:bound 走 BoundForge.api(name, params),unbound 走 RouteForge.api(level, name, params)\n // (窄断言替代 as any:重载签名已保证参数形状,此处仅消除联合类型/框架特化类型的分支歧义)\n const data = bound !== undefined\n ? await (bound as unknown as BoundForge).api(args[0] as string, args[1] as never)\n : await (unbound as RouteForge).api(args[0] as string, args[1] as string, args[2] as never);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n inflight--;\n pending.value = inflight > 0;\n }\n }\n\n return { pending, error, call: call as unknown as UseForgeApiCall };\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\n * - 路由名不存在或必填参数缺失等渲染期错误:降级为 '' 保证渲染不中断,\n * 同时以醒目的样式化 warn 输出完整错误(含堆栈)——开发期可见,生产无副作用\n * - level 为静态字符串(层级是确定性声明,不支持 `() => string` 函数形式):\n * 不支持中途动态切换 level\n * (需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)\n * - 用户无需关心 levelLoaded 状态,直接用即可\n */\n\nimport { computed, type ComputedRef, inject, onMounted, ref } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport type { RouteForge } from '@route-forge/core';\n\n/** 渲染期错误降级输出:橙色加粗标签 + 完整错误对象,控制台一眼可见 */\nfunction warnRenderError(error: unknown): void {\n console.warn(\n '%c[route-forge]%c useForgeRoute 渲染期错误(已降级为空字符串,渲染未中断)',\n 'color:#e67e22;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 降级报告钩子:组件层(ForgeRoute/ForgeLink)用它把默认 warn 升级为 error,避免双重打印 */\nexport interface ForgeRouteDegradeHooks {\n onDegrade?: (error: unknown) => void;\n}\n\nexport function useForgeRoute(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ComputedRef<string> {\n // 运行时守卫:level 必须是静态字符串(类型收窄后防 JS 用户误用静默降级为空链接)\n if (typeof level !== 'string') {\n throw new TypeError(\n '[route-forge/vue] useForgeRoute(): level must be a static string — ' +\n 'getter form is not supported (levels are deterministic declarations; ' +\n 'create another useForgeRoute call for another level)',\n );\n }\n\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n\n // level 为静态字符串(层级是确定性声明):绑定即固定,不支持中途动态切换\n //(需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)。\n // name / params 仍保持响应式。\n const lvl = level;\n\n // 响应式追踪该 level 的加载状态(computed 依赖此 ref 触发重算)\n const levelLoaded = ref(forge.isLoaded(lvl));\n\n if (!levelLoaded.value) {\n onMounted(() => {\n forge.load(lvl).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 computed 返回 '' */\n });\n });\n }\n\n return computed(() => {\n // level 未加载 → 返回空字符串,不抛错\n if (!levelLoaded.value) return '';\n // lvl 为 setup 快照(静态);name / params 每次重算读取,保持响应式\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n try {\n return forge.route(lvl, n, p);\n } catch (e) {\n (hooks?.onDegrade ?? warnRenderError)(e);\n return '';\n }\n });\n}\n","/**\n * ForgeRoute / ForgeLink 共享内部实现:props 定义、降级报告、RouterLink 探测\n * (非公共 API,不进包入口导出)\n */\n\nimport { getCurrentInstance, type PropType } from 'vue';\nimport type { RouteForge } from '@route-forge/core';\n\n/** ForgeRoute / ForgeLink 共享 props:level 静态快照,name / params 双形态响应式 */\n// as const:防止 required: true 被宽化为 boolean,导致 defineComponent 推断出 string | undefined\nexport const forgeLinkProps = {\n /** 层级名:静态快照,setup 求值一次后固定,不支持中途切换 */\n level: { type: String, required: true },\n /** 路由名:string 或 getter 函数,保持响应式 */\n name: {\n type: [String, Function] as PropType<string | (() => string)>,\n required: true,\n },\n /** 路由参数:对象或 getter 函数,保持响应式 */\n params: {\n type: [Object, Function] as PropType<Record<string, unknown> | (() => Record<string, unknown>)>,\n required: false,\n default: undefined,\n },\n} as const;\n\n/** 解析出错降级报告:红色加粗标签 + 完整错误对象,控制台一眼可见(error 级,每次出错都报) */\nexport function reportDegrade(component: string, error: unknown): void {\n console.error(\n `%c[route-forge]%c ${component} 路由解析失败(已降级为空字符串,渲染未中断)`,\n 'color:#c0392b;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** level 未加载提示:每实例仅一次(warned 为组件实例内的可变标记),避免正常加载瞬态刷屏 */\nexport function warnUnloadedOnce(component: string, level: string, warned: { value: boolean }): void {\n if (warned.value) return;\n warned.value = true;\n console.warn(\n `[route-forge] ${component}: level \"${level}\" 尚未加载,链接暂不渲染(加载完成后自动出现)`,\n );\n}\n\n/**\n * 从 app 全局组件中探测 vue-router 的 RouterLink(零依赖:不 import vue-router)。\n * vue-router 在 app.use(router) 时会把 RouterLink / router-link 注册到全局组件表;\n * 仅在父组件局部注册 RouterLink 的场景探测不到,此时降级渲染原生 <a>(README 有说明)。\n */\nexport function resolveRouterLink(): object | null {\n const inst = getCurrentInstance();\n const comps = inst?.appContext.components as Record<string, object> | undefined;\n return comps?.RouterLink ?? comps?.['router-link'] ?? null;\n}\n\nexport type { RouteForge };\n","/**\n * ForgeRoute:URL 生成组件(通用形态),封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - 通过作用域插槽暴露 { href, loaded },模板里自由决定渲染 <a>、RouterLink 或任意内容\n * - loaded = href !== ''(level 未加载与路由解析出错都降级为 '',正好复用该哨兵值)\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错(UnknownRouteError 等)以 console.error 报告,渲染不中断\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, inject, type SlotsType, type VNode } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport { useForgeRoute } from '../composables/useForgeRoute.js';\nimport { forgeLinkProps, reportDegrade, warnUnloadedOnce } from './shared.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport const ForgeRoute = defineComponent({\n name: 'ForgeRoute',\n // 根节点是用户插槽内容,框架透传 attrs 落到插槽上没有意义,显式关闭\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n default?: (props: { href: string; loaded: boolean }) => VNode[];\n loading?: () => VNode[];\n }>,\n setup(props, { slots }) {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const href = useForgeRoute(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeRoute', e),\n });\n const unloadWarned = { value: false };\n\n return () => {\n const url = href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeRoute', props.level, unloadWarned);\n }\n // 未加载/解析出错:loading 插槽优先(无则不渲染),与 ForgeLink 行为一致\n if (!loaded) return slots.loading ? slots.loading() : null;\n return slots.default ? slots.default({ href: url, loaded }) : null;\n };\n },\n});\n\nexport type ForgeRouteProps = InstanceType<typeof ForgeRoute>['$props'];\n","/**\n * ForgeLink:便捷链接组件,封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - loaded(href !== '')时直接渲染链接:检测到 vue-router 全局注册的 RouterLink\n * 则渲染 <RouterLink :to=\"href\">(SPA 内部跳转),否则渲染原生 <a :href=\"href\">\n * - 未加载(或路由解析出错)时渲染 loading 插槽,未传则默认不渲染;\n * 每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错以 console.error 报告,渲染不中断\n * - attrs 透传到根元素(class / target / rel 等),生成的 href / to 优先于同名 attr\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, h, inject, type SlotsType, type VNode } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport { useForgeRoute } from '../composables/useForgeRoute.js';\nimport {\n forgeLinkProps,\n reportDegrade,\n resolveRouterLink,\n warnUnloadedOnce,\n} from './shared.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport const ForgeLink = defineComponent({\n name: 'ForgeLink',\n // attrs 透传到 <a> / RouterLink,但 href / to 必须以组件生成的 URL 为准(显式合并)\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n /** 链接文本/内容 */\n default?: () => VNode[];\n /** 未加载占位 */\n loading?: () => VNode[];\n }>,\n setup(props, { slots, attrs }) {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const href = useForgeRoute(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeLink', e),\n });\n const unloadWarned = { value: false };\n // RouterLink 在 app.use(router) 时全局注册,app 生命周期内不变,setup 时探测一次即可\n const routerLink = resolveRouterLink();\n\n return () => {\n const url = href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeLink', props.level, unloadWarned);\n }\n if (!loaded) return slots.loading ? slots.loading() : null;\n\n const children = slots.default ? slots.default() : undefined;\n if (routerLink) {\n return h(\n routerLink,\n { ...(attrs as Record<string, unknown>), to: url },\n { default: () => children },\n );\n }\n return h('a', { ...(attrs as Record<string, unknown>), href: url }, children);\n };\n },\n});\n\nexport type ForgeLinkProps = InstanceType<typeof ForgeLink>['$props'];\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/composables/useForgeApi.ts","../src/composables/useForgeRoute.ts","../src/components/shared.ts","../src/components/ForgeRoute.ts","../src/components/ForgeLink.ts"],"names":["createRouteForge","inject","ref","onMounted","computed","getCurrentInstance","defineComponent","h"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Vue 3 插件入口\n * @see .docs/SPEC.md §4.1.7\n *\n * 提供:\n * - 全局属性 $forge(route() 工具)\n * - inject symbol 注入 RouteForge 实例供 composable 使用\n * - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例\n * • 不传 level:forge(level, name, params?) 直接调用\n * • 传 level:forge(name, params?) 直接调用,自动绑定层级\n * • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n */\n\nimport type { App, InjectionKey, Plugin, Ref } from 'vue';\nimport { inject, ref } from 'vue';\nimport {\n type ApiCallParams,\n type BoundForge,\n createRouteForge,\n type RouteForge,\n type RouteForgeOptions,\n} from '@route-forge/core';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** Vue 特化类型:levelLoaded 为 Ref<boolean> */\nexport type VueBoundForge = BoundForge<Ref<boolean>>;\n\nexport function createRouteForgePlugin(options: RouteForgePluginOptions = {}): Plugin<[]> & {\n ready: RouteForge['ready']\n} {\n const forge = createRouteForge(options);\n\n return {\n ready: forge.ready.bind(forge),\n install(app: App) {\n app.provide(FORGE_INJECTION_KEY, forge);\n app.config.globalProperties.$forge = {\n route: (level: string, name: string, params?: Record<string, unknown>) =>\n forge.route(level, name, params),\n };\n },\n };\n}\n\n/**\n * 获取 forge 实例。内部委托 core 的 forge.use(),仅将 levelLoaded 替换为 Vue 响应式 Ref。\n *\n * @example\n * // 不绑定层级\n * const forge = useForge()\n * forge('admin', 'users.show', { user: 1 })\n * forge.api('admin', 'users.show')\n *\n * @example\n * // 绑定层级 — 直接调用和 api/route/url 均无需传 level\n * const forge = useForge('admin')\n * forge.level // → 'admin'\n * forge.levelLoaded // Ref<boolean>\n * forge('users.show', { user: 1 })\n * forge.route('users.show', { user: 1 })\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): VueBoundForge;\nexport function useForge<L extends string>(level: L): VueBoundForge;\nexport function useForge(): RouteForge;\nexport function useForge(level?: string, prefix?: string): RouteForge | VueBoundForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n '[route-forge/vue] useForge() must be used inside an app with createRouteForgePlugin() installed',\n );\n }\n\n if (level === undefined) {\n return forge;\n }\n\n // 委托 core 的 use(),获取 BoundForge(levelLoaded 为 Promise<void>)\n const bound = forge.use(level, prefix);\n\n // 将 levelLoaded 从 Promise<void> 替换为 Ref<boolean>\n const levelLoadedRef = ref(false);\n bound.levelLoaded.then(() => {\n levelLoadedRef.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */ });\n\n Object.defineProperty(bound, 'levelLoaded', {\n value: levelLoadedRef,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n\n return bound as unknown as VueBoundForge;\n}\n","/**\n * useForgeApi:包装 forge.api(),自动管理 loading/error 状态\n * @see .docs/SPEC.md §4.1.7\n *\n * 支持:\n * - useForgeApi() — call(level, name, params)\n * - useForgeApi(level) — call(name, params),自动绑定层级\n * - useForgeApi(level, prefix) — call(suffix, params),自动绑定层级 + 拼接前缀\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * pending 采用引用计数:并发多个 call 时,全部完成才置 false\n * (先完成的 call 不再把其他在途请求的 pending 提前清掉)。\n */\n\nimport type { Ref } from 'vue';\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type {\n BoundForge,\n RouteForge,\n UseForgeApiBoundCall,\n UseForgeApiBoundReturn,\n UseForgeApiCall,\n UseForgeApiReturn,\n} from '@route-forge/core';\n\n// Vue 特化类型:pending/error 为 Ref\nexport type { UseForgeApiCall, UseForgeApiBoundCall };\nexport type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;\nexport type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturnVue;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturnVue | UseForgeApiBoundReturnVue<string> {\n const bound = level !== undefined ? useForge(level, prefix as string) : undefined;\n const unbound = bound === undefined ? useForge() : undefined;\n const pending = ref(false);\n const error = ref<unknown>(null);\n // 并发计数:setup 闭包变量(组件实例生命周期存活)\n let inflight = 0;\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n inflight++;\n pending.value = true;\n error.value = null;\n try {\n // 按绑定形态分发:bound 走 BoundForge.api(name, params),unbound 走 RouteForge.api(level, name, params)\n // (窄断言替代 as any:重载签名已保证参数形状,此处仅消除联合类型/框架特化类型的分支歧义)\n const data = bound !== undefined\n ? await (bound as unknown as BoundForge).api(args[0] as string, args[1] as never)\n : await (unbound as RouteForge).api(args[0] as string, args[1] as string, args[2] as never);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n inflight--;\n pending.value = inflight > 0;\n }\n }\n\n return { pending, error, call: call as unknown as UseForgeApiCall };\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\n * - 路由名不存在或必填参数缺失等渲染期错误:降级为 '' 保证渲染不中断,\n * 同时以醒目的样式化 warn 输出完整错误(含堆栈)——开发期可见,生产无副作用\n * - level 为静态字符串(层级是确定性声明,不支持 `() => string` 函数形式):\n * 不支持中途动态切换 level\n * (需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)\n * - 用户无需关心 levelLoaded 状态,直接用即可\n */\n\nimport { computed, type ComputedRef, inject, onMounted, ref } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport type { RouteForge } from '@route-forge/core';\n\n/** 渲染期错误降级输出:橙色加粗标签 + 完整错误对象,控制台一眼可见 */\nfunction warnRenderError(error: unknown): void {\n console.warn(\n '%c[route-forge]%c useForgeRoute 渲染期错误(已降级为空字符串,渲染未中断)',\n 'color:#e67e22;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 降级报告钩子:组件层(ForgeRoute/ForgeLink)用它把默认 warn 升级为 error,避免双重打印 */\nexport interface ForgeRouteDegradeHooks {\n onDegrade?: (error: unknown) => void;\n}\n\nexport function useForgeRoute(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ComputedRef<string> {\n // 运行时守卫:level 必须是静态字符串(类型收窄后防 JS 用户误用静默降级为空链接)\n if (typeof level !== 'string') {\n throw new TypeError(\n '[route-forge/vue] useForgeRoute(): level must be a static string — ' +\n 'getter form is not supported (levels are deterministic declarations; ' +\n 'create another useForgeRoute call for another level)',\n );\n }\n\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n\n // level 为静态字符串(层级是确定性声明):绑定即固定,不支持中途动态切换\n //(需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)。\n // name / params 仍保持响应式。\n const lvl = level;\n\n // 响应式追踪该 level 的加载状态(computed 依赖此 ref 触发重算)\n const levelLoaded = ref(forge.isLoaded(lvl));\n\n if (!levelLoaded.value) {\n onMounted(() => {\n forge.load(lvl).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 computed 返回 '' */\n });\n });\n }\n\n return computed(() => {\n // level 未加载 → 返回空字符串,不抛错\n if (!levelLoaded.value) return '';\n // lvl 为 setup 快照(静态);name / params 每次重算读取,保持响应式\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n try {\n return forge.route(lvl, n, p);\n } catch (e) {\n (hooks?.onDegrade ?? warnRenderError)(e);\n return '';\n }\n });\n}\n","/**\n * ForgeRoute / ForgeLink 共享内部实现:props 定义、降级报告、RouterLink 探测\n * (非公共 API,不进包入口导出)\n */\n\nimport { getCurrentInstance, type PropType } from 'vue';\nimport type { RouteForge } from '@route-forge/core';\n\n/** ForgeRoute / ForgeLink 共享 props:level 静态快照,name / params 双形态响应式 */\n// as const:防止 required: true 被宽化为 boolean,导致 defineComponent 推断出 string | undefined\nexport const forgeLinkProps = {\n /** 层级名:静态快照,setup 求值一次后固定,不支持中途切换 */\n level: { type: String, required: true },\n /** 路由名:string 或 getter 函数,保持响应式 */\n name: {\n type: [String, Function] as PropType<string | (() => string)>,\n required: true,\n },\n /** 路由参数:对象或 getter 函数,保持响应式 */\n params: {\n type: [Object, Function] as PropType<Record<string, unknown> | (() => Record<string, unknown>)>,\n required: false,\n default: undefined,\n },\n} as const;\n\n/** 解析出错降级报告:红色加粗标签 + 完整错误对象,控制台一眼可见(error 级,每次出错都报) */\nexport function reportDegrade(component: string, error: unknown): void {\n console.error(\n `%c[route-forge]%c ${component} 路由解析失败(已降级为空字符串,渲染未中断)`,\n 'color:#c0392b;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** level 未加载提示:每实例仅一次(warned 为组件实例内的可变标记),避免正常加载瞬态刷屏 */\nexport function warnUnloadedOnce(component: string, level: string, warned: { value: boolean }): void {\n if (warned.value) return;\n warned.value = true;\n console.warn(\n `[route-forge] ${component}: level \"${level}\" 尚未加载,链接暂不渲染(加载完成后自动出现)`,\n );\n}\n\n/**\n * 从 app 全局组件中探测 vue-router 的 RouterLink(零依赖:不 import vue-router)。\n * vue-router 在 app.use(router) 时会把 RouterLink / router-link 注册到全局组件表;\n * 仅在父组件局部注册 RouterLink 的场景探测不到,此时降级渲染原生 <a>(README 有说明)。\n */\nexport function resolveRouterLink(): object | null {\n const inst = getCurrentInstance();\n const comps = inst?.appContext.components as Record<string, object> | undefined;\n return comps?.RouterLink ?? comps?.['router-link'] ?? null;\n}\n\nexport type { RouteForge };\n","/**\n * ForgeRoute:URL 生成组件(通用形态),封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - 通过作用域插槽暴露 { href, loaded },模板里自由决定渲染 <a>、RouterLink 或任意内容\n * - loaded = href !== ''(level 未加载与路由解析出错都降级为 '',正好复用该哨兵值)\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错(UnknownRouteError 等)以 console.error 报告,渲染不中断\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, inject, type SlotsType, type VNode } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport { useForgeRoute } from '../composables/useForgeRoute.js';\nimport { forgeLinkProps, reportDegrade, warnUnloadedOnce } from './shared.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport const ForgeRoute = defineComponent({\n name: 'ForgeRoute',\n // 根节点是用户插槽内容,框架透传 attrs 落到插槽上没有意义,显式关闭\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n default?: (props: { href: string; loaded: boolean }) => VNode[];\n loading?: () => VNode[];\n }>,\n setup(props, { slots }) {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const href = useForgeRoute(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeRoute', e),\n });\n const unloadWarned = { value: false };\n\n return () => {\n const url = href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeRoute', props.level, unloadWarned);\n }\n // 未加载/解析出错:loading 插槽优先(无则不渲染),与 ForgeLink 行为一致\n if (!loaded) return slots.loading ? slots.loading() : null;\n return slots.default ? slots.default({ href: url, loaded }) : null;\n };\n },\n});\n\nexport type ForgeRouteProps = InstanceType<typeof ForgeRoute>['$props'];\n","/**\n * ForgeLink:便捷链接组件,封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - loaded(href !== '')时直接渲染链接:检测到 vue-router 全局注册的 RouterLink\n * 则渲染 <RouterLink :to=\"href\">(SPA 内部跳转),否则渲染原生 <a :href=\"href\">\n * - 未加载(或路由解析出错)时渲染 loading 插槽,未传则默认不渲染;\n * 每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错以 console.error 报告,渲染不中断\n * - attrs 透传到根元素(class / target / rel 等),生成的 href / to 优先于同名 attr\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, h, inject, type SlotsType, type VNode } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport { useForgeRoute } from '../composables/useForgeRoute.js';\nimport {\n forgeLinkProps,\n reportDegrade,\n resolveRouterLink,\n warnUnloadedOnce,\n} from './shared.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport const ForgeLink = defineComponent({\n name: 'ForgeLink',\n // attrs 透传到 <a> / RouterLink,但 href / to 必须以组件生成的 URL 为准(显式合并)\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n /** 链接文本/内容 */\n default?: () => VNode[];\n /** 未加载占位 */\n loading?: () => VNode[];\n }>,\n setup(props, { slots, attrs }) {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const href = useForgeRoute(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeLink', e),\n });\n const unloadWarned = { value: false };\n // RouterLink 在 app.use(router) 时全局注册,app 生命周期内不变,setup 时探测一次即可\n const routerLink = resolveRouterLink();\n\n return () => {\n const url = href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeLink', props.level, unloadWarned);\n }\n if (!loaded) return slots.loading ? slots.loading() : null;\n\n const children = slots.default ? slots.default() : undefined;\n if (routerLink) {\n return h(\n routerLink,\n { ...(attrs as Record<string, unknown>), to: url },\n { default: () => children },\n );\n }\n return h('a', { ...(attrs as Record<string, unknown>), href: url }, children);\n };\n },\n});\n\nexport type ForgeLinkProps = InstanceType<typeof ForgeLink>['$props'];\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -25,7 +25,7 @@ interface RouteForgePluginOptions extends RouteForgeOptions {
|
|
|
25
25
|
}
|
|
26
26
|
/** Vue 特化类型:levelLoaded 为 Ref<boolean> */
|
|
27
27
|
type VueBoundForge = BoundForge<Ref<boolean>>;
|
|
28
|
-
declare function createRouteForgePlugin(options
|
|
28
|
+
declare function createRouteForgePlugin(options?: RouteForgePluginOptions): Plugin<[]> & {
|
|
29
29
|
ready: RouteForge['ready'];
|
|
30
30
|
};
|
|
31
31
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ interface RouteForgePluginOptions extends RouteForgeOptions {
|
|
|
25
25
|
}
|
|
26
26
|
/** Vue 特化类型:levelLoaded 为 Ref<boolean> */
|
|
27
27
|
type VueBoundForge = BoundForge<Ref<boolean>>;
|
|
28
|
-
declare function createRouteForgePlugin(options
|
|
28
|
+
declare function createRouteForgePlugin(options?: RouteForgePluginOptions): Plugin<[]> & {
|
|
29
29
|
ready: RouteForge['ready'];
|
|
30
30
|
};
|
|
31
31
|
/**
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRouteForge } from '@route-forge/core';
|
|
|
3
3
|
|
|
4
4
|
// src/plugin.ts
|
|
5
5
|
var FORGE_INJECTION_KEY = /* @__PURE__ */ Symbol("route-forge");
|
|
6
|
-
function createRouteForgePlugin(options) {
|
|
6
|
+
function createRouteForgePlugin(options = {}) {
|
|
7
7
|
const forge = createRouteForge(options);
|
|
8
8
|
return {
|
|
9
9
|
ready: forge.ready.bind(forge),
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts","../src/composables/useForgeApi.ts","../src/composables/useForgeRoute.ts","../src/components/shared.ts","../src/components/ForgeRoute.ts","../src/components/ForgeLink.ts"],"names":["ref","inject","defineComponent"],"mappings":";;;;AA2BO,IAAM,mBAAA,0BAAuD,aAAa;AAO1E,SAAS,uBAAuB,OAAA,EAErC;AACA,EAAA,MAAM,KAAA,GAAQ,iBAAiB,OAAO,CAAA;AAEtC,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA;AAAA,IAC7B,QAAQ,GAAA,EAAU;AAChB,MAAA,GAAA,CAAI,OAAA,CAAQ,qBAAqB,KAAK,CAAA;AACtC,MAAA,GAAA,CAAI,MAAA,CAAO,iBAAiB,MAAA,GAAS;AAAA,QACnC,KAAA,EAAO,CAAC,KAAA,EAAe,IAAA,EAAc,WACnC,KAAA,CAAM,KAAA,CAAM,KAAA,EAAO,IAAA,EAAM,MAAM;AAAA,OACnC;AAAA,IACF;AAAA,GACF;AACF;AA4BO,SAAS,QAAA,CAAS,OAAgB,MAAA,EAA6C;AACpF,EAAA,MAAM,KAAA,GAAQ,OAAO,mBAAmB,CAAA;AACxC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,OAAO,KAAA;AAAA,EACT;AAGA,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,GAAA,CAAI,KAAA,EAAO,MAAM,CAAA;AAGrC,EAAA,MAAM,cAAA,GAAiB,IAAI,KAAK,CAAA;AAChC,EAAA,KAAA,CAAM,WAAA,CAAY,KAAK,MAAM;AAC3B,IAAA,cAAA,CAAe,KAAA,GAAQ,IAAA;AAAA,EACzB,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,EAAmC,CAAC,CAAA;AAEnD,EAAA,MAAA,CAAO,cAAA,CAAe,OAAO,aAAA,EAAe;AAAA,IAC1C,KAAA,EAAO,cAAA;AAAA,IACP,QAAA,EAAU,KAAA;AAAA,IACV,UAAA,EAAY,IAAA;AAAA,IACZ,YAAA,EAAc;AAAA,GACf,CAAA;AAED,EAAA,OAAO,KAAA;AACT;AClEO,SAAS,WAAA,CAAY,OAAgB,MAAA,EAA2E;AACrH,EAAA,MAAM,QAAQ,KAAA,KAAU,MAAA,GAAY,QAAA,CAAS,KAAA,EAAO,MAAgB,CAAA,GAAI,MAAA;AACxE,EAAA,MAAM,OAAA,GAAU,KAAA,KAAU,MAAA,GAAY,QAAA,EAAS,GAAI,MAAA;AACnD,EAAA,MAAM,OAAA,GAAUA,IAAI,KAAK,CAAA;AACzB,EAAA,MAAM,KAAA,GAAQA,IAAa,IAAI,CAAA;AAE/B,EAAA,IAAI,QAAA,GAAW,CAAA;AAEf,EAAA,eAAe,QAAQ,IAAA,EAA6D;AAClF,IAAA,QAAA,EAAA;AACA,IAAA,OAAA,CAAQ,KAAA,GAAQ,IAAA;AAChB,IAAA,KAAA,CAAM,KAAA,GAAQ,IAAA;AACd,IAAA,IAAI;AAGF,MAAA,MAAM,IAAA,GAAO,KAAA,KAAU,KAAA,CAAA,GACnB,MAAO,KAAA,CAAgC,IAAI,IAAA,CAAK,CAAC,CAAA,EAAa,IAAA,CAAK,CAAC,CAAU,IAC9E,MAAO,OAAA,CAAuB,GAAA,CAAI,IAAA,CAAK,CAAC,CAAA,EAAa,KAAK,CAAC,CAAA,EAAa,IAAA,CAAK,CAAC,CAAU,CAAA;AAC5F,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,IAAA,EAAK;AAAA,IAC7B,SAAS,CAAA,EAAG;AACV,MAAA,KAAA,CAAM,KAAA,GAAQ,CAAA;AACd,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAW,KAAA,EAAO,CAAA,EAAE;AAAA,IACrC,CAAA,SAAE;AACA,MAAA,QAAA,EAAA;AACA,MAAA,OAAA,CAAQ,QAAQ,QAAA,GAAW,CAAA;AAAA,IAC7B;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,IAAA,EAAyC;AACpE;AClDA,SAAS,gBAAgB,KAAA,EAAsB;AAC7C,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,gKAAA;AAAA,IACA,gCAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF;AACF;AAOO,SAAS,aAAA,CACd,KAAA,EACA,IAAA,EACA,MAAA,EACA,KAAA,EACqB;AAErB,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,MAAM,IAAI,SAAA;AAAA,MACR;AAAA,KAGF;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQC,OAAO,mBAAmB,CAAA;AAKxC,EAAA,MAAM,GAAA,GAAM,KAAA;AAGZ,EAAA,MAAM,WAAA,GAAcD,GAAAA,CAAI,KAAA,CAAM,QAAA,CAAS,GAAG,CAAC,CAAA;AAE3C,EAAA,IAAI,CAAC,YAAY,KAAA,EAAO;AACtB,IAAA,SAAA,CAAU,MAAM;AACd,MAAA,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA,CAAE,IAAA,CAAK,MAAM;AACzB,QAAA,WAAA,CAAY,KAAA,GAAQ,IAAA;AAAA,MACtB,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,MACf,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,SAAS,MAAM;AAEpB,IAAA,IAAI,CAAC,WAAA,CAAY,KAAA,EAAO,OAAO,EAAA;AAE/B,IAAA,MAAM,CAAA,GAAI,OAAO,IAAA,KAAS,UAAA,GAAa,MAAK,GAAI,IAAA;AAChD,IAAA,MAAM,CAAA,GAAI,MAAA,GAAS,MAAA,EAAO,GAAI,MAAA;AAC9B,IAAA,IAAI;AACF,MAAA,OAAO,KAAA,CAAM,KAAA,CAAM,GAAA,EAAK,CAAA,EAAG,CAAC,CAAA;AAAA,IAC9B,SAAS,CAAA,EAAG;AACV,MAAA,CAAC,KAAA,EAAO,SAAA,IAAa,eAAA,EAAiB,CAAC,CAAA;AACvC,MAAA,OAAO,EAAA;AAAA,IACT;AAAA,EACF,CAAC,CAAA;AACH;ACtEO,IAAM,cAAA,GAAiB;AAAA;AAAA,EAE5B,KAAA,EAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,UAAU,IAAA,EAAK;AAAA;AAAA,EAEtC,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,CAAC,MAAA,EAAQ,QAAQ,CAAA;AAAA,IACvB,QAAA,EAAU;AAAA,GACZ;AAAA;AAAA,EAEA,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,CAAC,MAAA,EAAQ,QAAQ,CAAA;AAAA,IACvB,QAAA,EAAU,KAAA;AAAA,IACV,OAAA,EAAS;AAAA;AAEb,CAAA;AAGO,SAAS,aAAA,CAAc,WAAmB,KAAA,EAAsB;AACrE,EAAA,OAAA,CAAQ,KAAA;AAAA,IACN,qBAAqB,SAAS,CAAA,qIAAA,CAAA;AAAA,IAC9B,gCAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF;AACF;AAGO,SAAS,gBAAA,CAAiB,SAAA,EAAmB,KAAA,EAAe,MAAA,EAAkC;AACnG,EAAA,IAAI,OAAO,KAAA,EAAO;AAClB,EAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AACf,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,CAAA,cAAA,EAAiB,SAAS,CAAA,SAAA,EAAY,KAAK,CAAA,sIAAA;AAAA,GAC7C;AACF;AAOO,SAAS,iBAAA,GAAmC;AACjD,EAAA,MAAM,OAAO,kBAAA,EAAmB;AAChC,EAAA,MAAM,KAAA,GAAQ,MAAM,UAAA,CAAW,UAAA;AAC/B,EAAA,OAAO,KAAA,EAAO,UAAA,IAAc,KAAA,GAAQ,aAAa,CAAA,IAAK,IAAA;AACxD;;;ACrCO,IAAM,aAAa,eAAA,CAAgB;AAAA,EACxC,IAAA,EAAM,YAAA;AAAA;AAAA,EAEN,YAAA,EAAc,KAAA;AAAA,EACd,KAAA,EAAO,cAAA;AAAA,EACP,KAAA,EAAO,MAAA;AAAA,EAIP,KAAA,CAAM,KAAA,EAAO,EAAE,KAAA,EAAM,EAAG;AACtB,IAAA,MAAM,KAAA,GAAQC,OAAO,mBAAmB,CAAA;AAExC,IAAA,MAAM,UAAA,GAAa,MAAO,OAAO,KAAA,CAAM,SAAS,UAAA,GAAa,KAAA,CAAM,IAAA,EAAK,GAAI,KAAA,CAAM,IAAA;AAClF,IAAA,MAAM,YAAA,GAAe,MACnB,OAAO,KAAA,CAAM,WAAW,UAAA,GAAa,KAAA,CAAM,MAAA,EAAO,GAAI,KAAA,CAAM,MAAA;AAC9D,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,KAAA,CAAM,KAAA,EAAO,YAAY,YAAA,EAAc;AAAA,MAChE,SAAA,EAAW,CAAC,CAAA,KAAM,aAAA,CAAc,cAAc,CAAC;AAAA,KAChD,CAAA;AACD,IAAA,MAAM,YAAA,GAAe,EAAE,KAAA,EAAO,KAAA,EAAM;AAEpC,IAAA,OAAO,MAAM;AACX,MAAA,MAAM,MAAM,IAAA,CAAK,KAAA;AACjB,MAAA,MAAM,SAAS,GAAA,KAAQ,EAAA;AACvB,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAM,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA,EAAG;AAC3C,QAAA,gBAAA,CAAiB,YAAA,EAAc,KAAA,CAAM,KAAA,EAAO,YAAY,CAAA;AAAA,MAC1D;AAEA,MAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,MAAM,OAAA,GAAU,KAAA,CAAM,SAAQ,GAAI,IAAA;AACtD,MAAA,OAAO,KAAA,CAAM,UAAU,KAAA,CAAM,OAAA,CAAQ,EAAE,IAAA,EAAM,GAAA,EAAK,MAAA,EAAQ,CAAA,GAAI,IAAA;AAAA,IAChE,CAAA;AAAA,EACF;AACF,CAAC;ACxBM,IAAM,YAAYC,eAAAA,CAAgB;AAAA,EACvC,IAAA,EAAM,WAAA;AAAA;AAAA,EAEN,YAAA,EAAc,KAAA;AAAA,EACd,KAAA,EAAO,cAAA;AAAA,EACP,KAAA,EAAO,MAAA;AAAA,EAMP,KAAA,CAAM,KAAA,EAAO,EAAE,KAAA,EAAO,OAAM,EAAG;AAC7B,IAAA,MAAM,KAAA,GAAQD,OAAO,mBAAmB,CAAA;AAExC,IAAA,MAAM,UAAA,GAAa,MAAO,OAAO,KAAA,CAAM,SAAS,UAAA,GAAa,KAAA,CAAM,IAAA,EAAK,GAAI,KAAA,CAAM,IAAA;AAClF,IAAA,MAAM,YAAA,GAAe,MACnB,OAAO,KAAA,CAAM,WAAW,UAAA,GAAa,KAAA,CAAM,MAAA,EAAO,GAAI,KAAA,CAAM,MAAA;AAC9D,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,KAAA,CAAM,KAAA,EAAO,YAAY,YAAA,EAAc;AAAA,MAChE,SAAA,EAAW,CAAC,CAAA,KAAM,aAAA,CAAc,aAAa,CAAC;AAAA,KAC/C,CAAA;AACD,IAAA,MAAM,YAAA,GAAe,EAAE,KAAA,EAAO,KAAA,EAAM;AAEpC,IAAA,MAAM,aAAa,iBAAA,EAAkB;AAErC,IAAA,OAAO,MAAM;AACX,MAAA,MAAM,MAAM,IAAA,CAAK,KAAA;AACjB,MAAA,MAAM,SAAS,GAAA,KAAQ,EAAA;AACvB,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAM,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA,EAAG;AAC3C,QAAA,gBAAA,CAAiB,WAAA,EAAa,KAAA,CAAM,KAAA,EAAO,YAAY,CAAA;AAAA,MACzD;AACA,MAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,MAAM,OAAA,GAAU,KAAA,CAAM,SAAQ,GAAI,IAAA;AAEtD,MAAA,MAAM,QAAA,GAAW,KAAA,CAAM,OAAA,GAAU,KAAA,CAAM,SAAQ,GAAI,MAAA;AACnD,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,OAAO,CAAA;AAAA,UACL,UAAA;AAAA,UACA,EAAE,GAAI,KAAA,EAAmC,EAAA,EAAI,GAAA,EAAI;AAAA,UACjD,EAAE,OAAA,EAAS,MAAM,QAAA;AAAS,SAC5B;AAAA,MACF;AACA,MAAA,OAAO,CAAA,CAAE,KAAK,EAAE,GAAI,OAAmC,IAAA,EAAM,GAAA,IAAO,QAAQ,CAAA;AAAA,IAC9E,CAAA;AAAA,EACF;AACF,CAAC","file":"index.js","sourcesContent":["/**\n * Vue 3 插件入口\n * @see .docs/SPEC.md §4.1.7\n *\n * 提供:\n * - 全局属性 $forge(route() 工具)\n * - inject symbol 注入 RouteForge 实例供 composable 使用\n * - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例\n * • 不传 level:forge(level, name, params?) 直接调用\n * • 传 level:forge(name, params?) 直接调用,自动绑定层级\n * • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n */\n\nimport type { App, InjectionKey, Plugin, Ref } from 'vue';\nimport { inject, ref } from 'vue';\nimport {\n type ApiCallParams,\n type BoundForge,\n createRouteForge,\n type RouteForge,\n type RouteForgeOptions,\n} from '@route-forge/core';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** Vue 特化类型:levelLoaded 为 Ref<boolean> */\nexport type VueBoundForge = BoundForge<Ref<boolean>>;\n\nexport function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]> & {\n ready: RouteForge['ready']\n} {\n const forge = createRouteForge(options);\n\n return {\n ready: forge.ready.bind(forge),\n install(app: App) {\n app.provide(FORGE_INJECTION_KEY, forge);\n app.config.globalProperties.$forge = {\n route: (level: string, name: string, params?: Record<string, unknown>) =>\n forge.route(level, name, params),\n };\n },\n };\n}\n\n/**\n * 获取 forge 实例。内部委托 core 的 forge.use(),仅将 levelLoaded 替换为 Vue 响应式 Ref。\n *\n * @example\n * // 不绑定层级\n * const forge = useForge()\n * forge('admin', 'users.show', { user: 1 })\n * forge.api('admin', 'users.show')\n *\n * @example\n * // 绑定层级 — 直接调用和 api/route/url 均无需传 level\n * const forge = useForge('admin')\n * forge.level // → 'admin'\n * forge.levelLoaded // Ref<boolean>\n * forge('users.show', { user: 1 })\n * forge.route('users.show', { user: 1 })\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): VueBoundForge;\nexport function useForge<L extends string>(level: L): VueBoundForge;\nexport function useForge(): RouteForge;\nexport function useForge(level?: string, prefix?: string): RouteForge | VueBoundForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n '[route-forge/vue] useForge() must be used inside an app with createRouteForgePlugin() installed',\n );\n }\n\n if (level === undefined) {\n return forge;\n }\n\n // 委托 core 的 use(),获取 BoundForge(levelLoaded 为 Promise<void>)\n const bound = forge.use(level, prefix);\n\n // 将 levelLoaded 从 Promise<void> 替换为 Ref<boolean>\n const levelLoadedRef = ref(false);\n bound.levelLoaded.then(() => {\n levelLoadedRef.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */ });\n\n Object.defineProperty(bound, 'levelLoaded', {\n value: levelLoadedRef,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n\n return bound as unknown as VueBoundForge;\n}\n","/**\n * useForgeApi:包装 forge.api(),自动管理 loading/error 状态\n * @see .docs/SPEC.md §4.1.7\n *\n * 支持:\n * - useForgeApi() — call(level, name, params)\n * - useForgeApi(level) — call(name, params),自动绑定层级\n * - useForgeApi(level, prefix) — call(suffix, params),自动绑定层级 + 拼接前缀\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * pending 采用引用计数:并发多个 call 时,全部完成才置 false\n * (先完成的 call 不再把其他在途请求的 pending 提前清掉)。\n */\n\nimport type { Ref } from 'vue';\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type {\n BoundForge,\n RouteForge,\n UseForgeApiBoundCall,\n UseForgeApiBoundReturn,\n UseForgeApiCall,\n UseForgeApiReturn,\n} from '@route-forge/core';\n\n// Vue 特化类型:pending/error 为 Ref\nexport type { UseForgeApiCall, UseForgeApiBoundCall };\nexport type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;\nexport type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturnVue;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturnVue | UseForgeApiBoundReturnVue<string> {\n const bound = level !== undefined ? useForge(level, prefix as string) : undefined;\n const unbound = bound === undefined ? useForge() : undefined;\n const pending = ref(false);\n const error = ref<unknown>(null);\n // 并发计数:setup 闭包变量(组件实例生命周期存活)\n let inflight = 0;\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n inflight++;\n pending.value = true;\n error.value = null;\n try {\n // 按绑定形态分发:bound 走 BoundForge.api(name, params),unbound 走 RouteForge.api(level, name, params)\n // (窄断言替代 as any:重载签名已保证参数形状,此处仅消除联合类型/框架特化类型的分支歧义)\n const data = bound !== undefined\n ? await (bound as unknown as BoundForge).api(args[0] as string, args[1] as never)\n : await (unbound as RouteForge).api(args[0] as string, args[1] as string, args[2] as never);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n inflight--;\n pending.value = inflight > 0;\n }\n }\n\n return { pending, error, call: call as unknown as UseForgeApiCall };\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\n * - 路由名不存在或必填参数缺失等渲染期错误:降级为 '' 保证渲染不中断,\n * 同时以醒目的样式化 warn 输出完整错误(含堆栈)——开发期可见,生产无副作用\n * - level 为静态字符串(层级是确定性声明,不支持 `() => string` 函数形式):\n * 不支持中途动态切换 level\n * (需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)\n * - 用户无需关心 levelLoaded 状态,直接用即可\n */\n\nimport { computed, type ComputedRef, inject, onMounted, ref } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport type { RouteForge } from '@route-forge/core';\n\n/** 渲染期错误降级输出:橙色加粗标签 + 完整错误对象,控制台一眼可见 */\nfunction warnRenderError(error: unknown): void {\n console.warn(\n '%c[route-forge]%c useForgeRoute 渲染期错误(已降级为空字符串,渲染未中断)',\n 'color:#e67e22;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 降级报告钩子:组件层(ForgeRoute/ForgeLink)用它把默认 warn 升级为 error,避免双重打印 */\nexport interface ForgeRouteDegradeHooks {\n onDegrade?: (error: unknown) => void;\n}\n\nexport function useForgeRoute(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ComputedRef<string> {\n // 运行时守卫:level 必须是静态字符串(类型收窄后防 JS 用户误用静默降级为空链接)\n if (typeof level !== 'string') {\n throw new TypeError(\n '[route-forge/vue] useForgeRoute(): level must be a static string — ' +\n 'getter form is not supported (levels are deterministic declarations; ' +\n 'create another useForgeRoute call for another level)',\n );\n }\n\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n\n // level 为静态字符串(层级是确定性声明):绑定即固定,不支持中途动态切换\n //(需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)。\n // name / params 仍保持响应式。\n const lvl = level;\n\n // 响应式追踪该 level 的加载状态(computed 依赖此 ref 触发重算)\n const levelLoaded = ref(forge.isLoaded(lvl));\n\n if (!levelLoaded.value) {\n onMounted(() => {\n forge.load(lvl).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 computed 返回 '' */\n });\n });\n }\n\n return computed(() => {\n // level 未加载 → 返回空字符串,不抛错\n if (!levelLoaded.value) return '';\n // lvl 为 setup 快照(静态);name / params 每次重算读取,保持响应式\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n try {\n return forge.route(lvl, n, p);\n } catch (e) {\n (hooks?.onDegrade ?? warnRenderError)(e);\n return '';\n }\n });\n}\n","/**\n * ForgeRoute / ForgeLink 共享内部实现:props 定义、降级报告、RouterLink 探测\n * (非公共 API,不进包入口导出)\n */\n\nimport { getCurrentInstance, type PropType } from 'vue';\nimport type { RouteForge } from '@route-forge/core';\n\n/** ForgeRoute / ForgeLink 共享 props:level 静态快照,name / params 双形态响应式 */\n// as const:防止 required: true 被宽化为 boolean,导致 defineComponent 推断出 string | undefined\nexport const forgeLinkProps = {\n /** 层级名:静态快照,setup 求值一次后固定,不支持中途切换 */\n level: { type: String, required: true },\n /** 路由名:string 或 getter 函数,保持响应式 */\n name: {\n type: [String, Function] as PropType<string | (() => string)>,\n required: true,\n },\n /** 路由参数:对象或 getter 函数,保持响应式 */\n params: {\n type: [Object, Function] as PropType<Record<string, unknown> | (() => Record<string, unknown>)>,\n required: false,\n default: undefined,\n },\n} as const;\n\n/** 解析出错降级报告:红色加粗标签 + 完整错误对象,控制台一眼可见(error 级,每次出错都报) */\nexport function reportDegrade(component: string, error: unknown): void {\n console.error(\n `%c[route-forge]%c ${component} 路由解析失败(已降级为空字符串,渲染未中断)`,\n 'color:#c0392b;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** level 未加载提示:每实例仅一次(warned 为组件实例内的可变标记),避免正常加载瞬态刷屏 */\nexport function warnUnloadedOnce(component: string, level: string, warned: { value: boolean }): void {\n if (warned.value) return;\n warned.value = true;\n console.warn(\n `[route-forge] ${component}: level \"${level}\" 尚未加载,链接暂不渲染(加载完成后自动出现)`,\n );\n}\n\n/**\n * 从 app 全局组件中探测 vue-router 的 RouterLink(零依赖:不 import vue-router)。\n * vue-router 在 app.use(router) 时会把 RouterLink / router-link 注册到全局组件表;\n * 仅在父组件局部注册 RouterLink 的场景探测不到,此时降级渲染原生 <a>(README 有说明)。\n */\nexport function resolveRouterLink(): object | null {\n const inst = getCurrentInstance();\n const comps = inst?.appContext.components as Record<string, object> | undefined;\n return comps?.RouterLink ?? comps?.['router-link'] ?? null;\n}\n\nexport type { RouteForge };\n","/**\n * ForgeRoute:URL 生成组件(通用形态),封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - 通过作用域插槽暴露 { href, loaded },模板里自由决定渲染 <a>、RouterLink 或任意内容\n * - loaded = href !== ''(level 未加载与路由解析出错都降级为 '',正好复用该哨兵值)\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错(UnknownRouteError 等)以 console.error 报告,渲染不中断\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, inject, type SlotsType, type VNode } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport { useForgeRoute } from '../composables/useForgeRoute.js';\nimport { forgeLinkProps, reportDegrade, warnUnloadedOnce } from './shared.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport const ForgeRoute = defineComponent({\n name: 'ForgeRoute',\n // 根节点是用户插槽内容,框架透传 attrs 落到插槽上没有意义,显式关闭\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n default?: (props: { href: string; loaded: boolean }) => VNode[];\n loading?: () => VNode[];\n }>,\n setup(props, { slots }) {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const href = useForgeRoute(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeRoute', e),\n });\n const unloadWarned = { value: false };\n\n return () => {\n const url = href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeRoute', props.level, unloadWarned);\n }\n // 未加载/解析出错:loading 插槽优先(无则不渲染),与 ForgeLink 行为一致\n if (!loaded) return slots.loading ? slots.loading() : null;\n return slots.default ? slots.default({ href: url, loaded }) : null;\n };\n },\n});\n\nexport type ForgeRouteProps = InstanceType<typeof ForgeRoute>['$props'];\n","/**\n * ForgeLink:便捷链接组件,封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - loaded(href !== '')时直接渲染链接:检测到 vue-router 全局注册的 RouterLink\n * 则渲染 <RouterLink :to=\"href\">(SPA 内部跳转),否则渲染原生 <a :href=\"href\">\n * - 未加载(或路由解析出错)时渲染 loading 插槽,未传则默认不渲染;\n * 每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错以 console.error 报告,渲染不中断\n * - attrs 透传到根元素(class / target / rel 等),生成的 href / to 优先于同名 attr\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, h, inject, type SlotsType, type VNode } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport { useForgeRoute } from '../composables/useForgeRoute.js';\nimport {\n forgeLinkProps,\n reportDegrade,\n resolveRouterLink,\n warnUnloadedOnce,\n} from './shared.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport const ForgeLink = defineComponent({\n name: 'ForgeLink',\n // attrs 透传到 <a> / RouterLink,但 href / to 必须以组件生成的 URL 为准(显式合并)\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n /** 链接文本/内容 */\n default?: () => VNode[];\n /** 未加载占位 */\n loading?: () => VNode[];\n }>,\n setup(props, { slots, attrs }) {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const href = useForgeRoute(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeLink', e),\n });\n const unloadWarned = { value: false };\n // RouterLink 在 app.use(router) 时全局注册,app 生命周期内不变,setup 时探测一次即可\n const routerLink = resolveRouterLink();\n\n return () => {\n const url = href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeLink', props.level, unloadWarned);\n }\n if (!loaded) return slots.loading ? slots.loading() : null;\n\n const children = slots.default ? slots.default() : undefined;\n if (routerLink) {\n return h(\n routerLink,\n { ...(attrs as Record<string, unknown>), to: url },\n { default: () => children },\n );\n }\n return h('a', { ...(attrs as Record<string, unknown>), href: url }, children);\n };\n },\n});\n\nexport type ForgeLinkProps = InstanceType<typeof ForgeLink>['$props'];\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/composables/useForgeApi.ts","../src/composables/useForgeRoute.ts","../src/components/shared.ts","../src/components/ForgeRoute.ts","../src/components/ForgeLink.ts"],"names":["ref","inject","defineComponent"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Vue 3 插件入口\n * @see .docs/SPEC.md §4.1.7\n *\n * 提供:\n * - 全局属性 $forge(route() 工具)\n * - inject symbol 注入 RouteForge 实例供 composable 使用\n * - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例\n * • 不传 level:forge(level, name, params?) 直接调用\n * • 传 level:forge(name, params?) 直接调用,自动绑定层级\n * • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n */\n\nimport type { App, InjectionKey, Plugin, Ref } from 'vue';\nimport { inject, ref } from 'vue';\nimport {\n type ApiCallParams,\n type BoundForge,\n createRouteForge,\n type RouteForge,\n type RouteForgeOptions,\n} from '@route-forge/core';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** Vue 特化类型:levelLoaded 为 Ref<boolean> */\nexport type VueBoundForge = BoundForge<Ref<boolean>>;\n\nexport function createRouteForgePlugin(options: RouteForgePluginOptions = {}): Plugin<[]> & {\n ready: RouteForge['ready']\n} {\n const forge = createRouteForge(options);\n\n return {\n ready: forge.ready.bind(forge),\n install(app: App) {\n app.provide(FORGE_INJECTION_KEY, forge);\n app.config.globalProperties.$forge = {\n route: (level: string, name: string, params?: Record<string, unknown>) =>\n forge.route(level, name, params),\n };\n },\n };\n}\n\n/**\n * 获取 forge 实例。内部委托 core 的 forge.use(),仅将 levelLoaded 替换为 Vue 响应式 Ref。\n *\n * @example\n * // 不绑定层级\n * const forge = useForge()\n * forge('admin', 'users.show', { user: 1 })\n * forge.api('admin', 'users.show')\n *\n * @example\n * // 绑定层级 — 直接调用和 api/route/url 均无需传 level\n * const forge = useForge('admin')\n * forge.level // → 'admin'\n * forge.levelLoaded // Ref<boolean>\n * forge('users.show', { user: 1 })\n * forge.route('users.show', { user: 1 })\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): VueBoundForge;\nexport function useForge<L extends string>(level: L): VueBoundForge;\nexport function useForge(): RouteForge;\nexport function useForge(level?: string, prefix?: string): RouteForge | VueBoundForge {\n const forge = inject(FORGE_INJECTION_KEY);\n if (!forge) {\n throw new Error(\n '[route-forge/vue] useForge() must be used inside an app with createRouteForgePlugin() installed',\n );\n }\n\n if (level === undefined) {\n return forge;\n }\n\n // 委托 core 的 use(),获取 BoundForge(levelLoaded 为 Promise<void>)\n const bound = forge.use(level, prefix);\n\n // 将 levelLoaded 从 Promise<void> 替换为 Ref<boolean>\n const levelLoadedRef = ref(false);\n bound.levelLoaded.then(() => {\n levelLoadedRef.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */ });\n\n Object.defineProperty(bound, 'levelLoaded', {\n value: levelLoadedRef,\n writable: false,\n enumerable: true,\n configurable: true,\n });\n\n return bound as unknown as VueBoundForge;\n}\n","/**\n * useForgeApi:包装 forge.api(),自动管理 loading/error 状态\n * @see .docs/SPEC.md §4.1.7\n *\n * 支持:\n * - useForgeApi() — call(level, name, params)\n * - useForgeApi(level) — call(name, params),自动绑定层级\n * - useForgeApi(level, prefix) — call(suffix, params),自动绑定层级 + 拼接前缀\n *\n * 类型推断:\n * 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,\n * level / name / params 均自动推断,IDE 提供补全提示。\n *\n * pending 采用引用计数:并发多个 call 时,全部完成才置 false\n * (先完成的 call 不再把其他在途请求的 pending 提前清掉)。\n */\n\nimport type { Ref } from 'vue';\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type {\n BoundForge,\n RouteForge,\n UseForgeApiBoundCall,\n UseForgeApiBoundReturn,\n UseForgeApiCall,\n UseForgeApiReturn,\n} from '@route-forge/core';\n\n// Vue 特化类型:pending/error 为 Ref\nexport type { UseForgeApiCall, UseForgeApiBoundCall };\nexport type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;\nexport type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturnVue;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturnVue | UseForgeApiBoundReturnVue<string> {\n const bound = level !== undefined ? useForge(level, prefix as string) : undefined;\n const unbound = bound === undefined ? useForge() : undefined;\n const pending = ref(false);\n const error = ref<unknown>(null);\n // 并发计数:setup 闭包变量(组件实例生命周期存活)\n let inflight = 0;\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n inflight++;\n pending.value = true;\n error.value = null;\n try {\n // 按绑定形态分发:bound 走 BoundForge.api(name, params),unbound 走 RouteForge.api(level, name, params)\n // (窄断言替代 as any:重载签名已保证参数形状,此处仅消除联合类型/框架特化类型的分支歧义)\n const data = bound !== undefined\n ? await (bound as unknown as BoundForge).api(args[0] as string, args[1] as never)\n : await (unbound as RouteForge).api(args[0] as string, args[1] as string, args[2] as never);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n inflight--;\n pending.value = inflight > 0;\n }\n }\n\n return { pending, error, call: call as unknown as UseForgeApiCall };\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\n * - 路由名不存在或必填参数缺失等渲染期错误:降级为 '' 保证渲染不中断,\n * 同时以醒目的样式化 warn 输出完整错误(含堆栈)——开发期可见,生产无副作用\n * - level 为静态字符串(层级是确定性声明,不支持 `() => string` 函数形式):\n * 不支持中途动态切换 level\n * (需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)\n * - 用户无需关心 levelLoaded 状态,直接用即可\n */\n\nimport { computed, type ComputedRef, inject, onMounted, ref } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport type { RouteForge } from '@route-forge/core';\n\n/** 渲染期错误降级输出:橙色加粗标签 + 完整错误对象,控制台一眼可见 */\nfunction warnRenderError(error: unknown): void {\n console.warn(\n '%c[route-forge]%c useForgeRoute 渲染期错误(已降级为空字符串,渲染未中断)',\n 'color:#e67e22;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** 降级报告钩子:组件层(ForgeRoute/ForgeLink)用它把默认 warn 升级为 error,避免双重打印 */\nexport interface ForgeRouteDegradeHooks {\n onDegrade?: (error: unknown) => void;\n}\n\nexport function useForgeRoute(\n level: string,\n name: string | (() => string),\n params?: () => Record<string, unknown> | undefined,\n hooks?: ForgeRouteDegradeHooks,\n): ComputedRef<string> {\n // 运行时守卫:level 必须是静态字符串(类型收窄后防 JS 用户误用静默降级为空链接)\n if (typeof level !== 'string') {\n throw new TypeError(\n '[route-forge/vue] useForgeRoute(): level must be a static string — ' +\n 'getter form is not supported (levels are deterministic declarations; ' +\n 'create another useForgeRoute call for another level)',\n );\n }\n\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n\n // level 为静态字符串(层级是确定性声明):绑定即固定,不支持中途动态切换\n //(需要另一个层级请在别的组件 / 别的 useForgeRoute 调用里分别使用,与 useForge 契约一致)。\n // name / params 仍保持响应式。\n const lvl = level;\n\n // 响应式追踪该 level 的加载状态(computed 依赖此 ref 触发重算)\n const levelLoaded = ref(forge.isLoaded(lvl));\n\n if (!levelLoaded.value) {\n onMounted(() => {\n forge.load(lvl).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 computed 返回 '' */\n });\n });\n }\n\n return computed(() => {\n // level 未加载 → 返回空字符串,不抛错\n if (!levelLoaded.value) return '';\n // lvl 为 setup 快照(静态);name / params 每次重算读取,保持响应式\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n try {\n return forge.route(lvl, n, p);\n } catch (e) {\n (hooks?.onDegrade ?? warnRenderError)(e);\n return '';\n }\n });\n}\n","/**\n * ForgeRoute / ForgeLink 共享内部实现:props 定义、降级报告、RouterLink 探测\n * (非公共 API,不进包入口导出)\n */\n\nimport { getCurrentInstance, type PropType } from 'vue';\nimport type { RouteForge } from '@route-forge/core';\n\n/** ForgeRoute / ForgeLink 共享 props:level 静态快照,name / params 双形态响应式 */\n// as const:防止 required: true 被宽化为 boolean,导致 defineComponent 推断出 string | undefined\nexport const forgeLinkProps = {\n /** 层级名:静态快照,setup 求值一次后固定,不支持中途切换 */\n level: { type: String, required: true },\n /** 路由名:string 或 getter 函数,保持响应式 */\n name: {\n type: [String, Function] as PropType<string | (() => string)>,\n required: true,\n },\n /** 路由参数:对象或 getter 函数,保持响应式 */\n params: {\n type: [Object, Function] as PropType<Record<string, unknown> | (() => Record<string, unknown>)>,\n required: false,\n default: undefined,\n },\n} as const;\n\n/** 解析出错降级报告:红色加粗标签 + 完整错误对象,控制台一眼可见(error 级,每次出错都报) */\nexport function reportDegrade(component: string, error: unknown): void {\n console.error(\n `%c[route-forge]%c ${component} 路由解析失败(已降级为空字符串,渲染未中断)`,\n 'color:#c0392b;font-weight:bold',\n 'color:inherit',\n error,\n );\n}\n\n/** level 未加载提示:每实例仅一次(warned 为组件实例内的可变标记),避免正常加载瞬态刷屏 */\nexport function warnUnloadedOnce(component: string, level: string, warned: { value: boolean }): void {\n if (warned.value) return;\n warned.value = true;\n console.warn(\n `[route-forge] ${component}: level \"${level}\" 尚未加载,链接暂不渲染(加载完成后自动出现)`,\n );\n}\n\n/**\n * 从 app 全局组件中探测 vue-router 的 RouterLink(零依赖:不 import vue-router)。\n * vue-router 在 app.use(router) 时会把 RouterLink / router-link 注册到全局组件表;\n * 仅在父组件局部注册 RouterLink 的场景探测不到,此时降级渲染原生 <a>(README 有说明)。\n */\nexport function resolveRouterLink(): object | null {\n const inst = getCurrentInstance();\n const comps = inst?.appContext.components as Record<string, object> | undefined;\n return comps?.RouterLink ?? comps?.['router-link'] ?? null;\n}\n\nexport type { RouteForge };\n","/**\n * ForgeRoute:URL 生成组件(通用形态),封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - 通过作用域插槽暴露 { href, loaded },模板里自由决定渲染 <a>、RouterLink 或任意内容\n * - loaded = href !== ''(level 未加载与路由解析出错都降级为 '',正好复用该哨兵值)\n * - 未加载且未传 loading 插槽时默认不渲染;每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错(UnknownRouteError 等)以 console.error 报告,渲染不中断\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, inject, type SlotsType, type VNode } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport { useForgeRoute } from '../composables/useForgeRoute.js';\nimport { forgeLinkProps, reportDegrade, warnUnloadedOnce } from './shared.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport const ForgeRoute = defineComponent({\n name: 'ForgeRoute',\n // 根节点是用户插槽内容,框架透传 attrs 落到插槽上没有意义,显式关闭\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n default?: (props: { href: string; loaded: boolean }) => VNode[];\n loading?: () => VNode[];\n }>,\n setup(props, { slots }) {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const href = useForgeRoute(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeRoute', e),\n });\n const unloadWarned = { value: false };\n\n return () => {\n const url = href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeRoute', props.level, unloadWarned);\n }\n // 未加载/解析出错:loading 插槽优先(无则不渲染),与 ForgeLink 行为一致\n if (!loaded) return slots.loading ? slots.loading() : null;\n return slots.default ? slots.default({ href: url, loaded }) : null;\n };\n },\n});\n\nexport type ForgeRouteProps = InstanceType<typeof ForgeRoute>['$props'];\n","/**\n * ForgeLink:便捷链接组件,封装 useForgeRoute 的\"先空串、后更新\"异步行为\n * @see .docs/SPEC.md §4.1.7\n *\n * - loaded(href !== '')时直接渲染链接:检测到 vue-router 全局注册的 RouterLink\n * 则渲染 <RouterLink :to=\"href\">(SPA 内部跳转),否则渲染原生 <a :href=\"href\">\n * - 未加载(或路由解析出错)时渲染 loading 插槽,未传则默认不渲染;\n * 每实例以 console.warn 提醒一次(防刷屏)\n * - 路由解析出错以 console.error 报告,渲染不中断\n * - attrs 透传到根元素(class / target / rel 等),生成的 href / to 优先于同名 attr\n * - level 为静态快照,name / params 保持响应式(值或 getter 函数双形态均可)\n */\n\nimport { defineComponent, h, inject, type SlotsType, type VNode } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport { useForgeRoute } from '../composables/useForgeRoute.js';\nimport {\n forgeLinkProps,\n reportDegrade,\n resolveRouterLink,\n warnUnloadedOnce,\n} from './shared.js';\nimport type { RouteForge } from '@route-forge/core';\n\nexport const ForgeLink = defineComponent({\n name: 'ForgeLink',\n // attrs 透传到 <a> / RouterLink,但 href / to 必须以组件生成的 URL 为准(显式合并)\n inheritAttrs: false,\n props: forgeLinkProps,\n slots: Object as SlotsType<{\n /** 链接文本/内容 */\n default?: () => VNode[];\n /** 未加载占位 */\n loading?: () => VNode[];\n }>,\n setup(props, { slots, attrs }) {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n // 统一收敛为 getter:name / params 双形态(值或函数)均保持响应式\n const nameGetter = () => (typeof props.name === 'function' ? props.name() : props.name);\n const paramsGetter = () =>\n typeof props.params === 'function' ? props.params() : props.params;\n const href = useForgeRoute(props.level, nameGetter, paramsGetter, {\n onDegrade: (e) => reportDegrade('ForgeLink', e),\n });\n const unloadWarned = { value: false };\n // RouterLink 在 app.use(router) 时全局注册,app 生命周期内不变,setup 时探测一次即可\n const routerLink = resolveRouterLink();\n\n return () => {\n const url = href.value;\n const loaded = url !== '';\n if (!loaded && !forge.isLoaded(props.level)) {\n warnUnloadedOnce('ForgeLink', props.level, unloadWarned);\n }\n if (!loaded) return slots.loading ? slots.loading() : null;\n\n const children = slots.default ? slots.default() : undefined;\n if (routerLink) {\n return h(\n routerLink,\n { ...(attrs as Record<string, unknown>), to: url },\n { default: () => children },\n );\n }\n return h('a', { ...(attrs as Record<string, unknown>), href: url }, children);\n };\n },\n});\n\nexport type ForgeLinkProps = InstanceType<typeof ForgeLink>['$props'];\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@route-forge/vue",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Route Forge 的 Vue 3 集成:插件 + composable(useForge/useForgeApi/useForgeRoute)+ 组件(ForgeRoute/ForgeLink)/ Vue 3 integration for Laravel named routes: plugin + composables (useForge / useForgeApi / useForgeRoute) + components (ForgeRoute / ForgeLink)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"laravel",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"vue": "^3.4.0"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@route-forge/core": "^2.1
|
|
56
|
+
"@route-forge/core": "^2.2.1"
|
|
57
57
|
},
|
|
58
58
|
"publishConfig": {
|
|
59
59
|
"access": "public"
|