@route-forge/vue 1.1.0 → 1.2.0
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 +43 -25
- package/dist/index.cjs +46 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -111
- package/dist/index.d.ts +20 -111
- package/dist/index.js +41 -61
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @route-forge/vue
|
|
2
2
|
|
|
3
|
-
Route Forge 的 Vue 3 集成:插件 + composable(`useForge` / `useForgeApi` /
|
|
3
|
+
Route Forge 的 Vue 3 集成:插件 + composable(`useForge` / `useForgeApi` /
|
|
4
4
|
`useForgeRoute` / `useForgeByPrefix`)。
|
|
5
5
|
|
|
6
6
|
## 安装
|
|
@@ -17,27 +17,38 @@ import { createApp } from 'vue'
|
|
|
17
17
|
import { createRouteForgePlugin } from '@route-forge/vue'
|
|
18
18
|
import App from './App.vue'
|
|
19
19
|
|
|
20
|
-
const
|
|
21
|
-
app.use(createRouteForgePlugin({
|
|
20
|
+
const plugin = createRouteForgePlugin({
|
|
22
21
|
endpoint: '/_forge/routes',
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
onSummaryReady: () => {
|
|
23
|
+
// 推荐:在路由数据就绪后挂载应用
|
|
24
|
+
app.mount('#app')
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const app = createApp(App)
|
|
29
|
+
app.use(plugin)
|
|
30
|
+
// 如果不使用 onSummaryReady 回调,也可以直接挂载
|
|
31
|
+
// app.mount('#app')
|
|
25
32
|
```
|
|
26
33
|
|
|
27
34
|
## useForge — 核心 composable
|
|
28
35
|
|
|
29
|
-
`useForge()`
|
|
36
|
+
`useForge()` 返回一个 forge 实例。支持可选传入 `level` 绑定层级:
|
|
30
37
|
|
|
31
38
|
```ts
|
|
32
39
|
import { useForge } from '@route-forge/vue'
|
|
33
40
|
|
|
34
|
-
// 不绑定层级 —
|
|
41
|
+
// 不绑定层级 — 仅提供异步 API + 工具方法
|
|
35
42
|
const forge = useForge()
|
|
36
43
|
forge('admin', 'users.show', { user: 1 }) // = forge.api('admin', 'users.show', ...)
|
|
37
44
|
forge.api('admin', 'users.show', { user: 1 }) // 显式调用
|
|
45
|
+
forge.ready // Promise<void>
|
|
46
|
+
forge.onLevelLoaded('admin', () => { ... }) // 订阅 level 加载
|
|
38
47
|
|
|
39
|
-
// 绑定层级 —
|
|
48
|
+
// 绑定层级 — 自动触发 load,提供同步方法 + levelLoaded 状态
|
|
40
49
|
const forge = useForge('admin')
|
|
50
|
+
forge.level // → 'admin'
|
|
51
|
+
forge.levelLoaded // Ref<boolean>,加载完成后变为 true
|
|
41
52
|
forge('users.show', { user: 1 }) // 自动带 admin
|
|
42
53
|
forge.api('users.show', { user: 1 }) // 同上
|
|
43
54
|
forge.route('users.show', { user: 1 }) // 生成 URL,自动带 admin
|
|
@@ -45,19 +56,20 @@ forge.url('users.show', { user: 1 }) // route() 语义别名
|
|
|
45
56
|
|
|
46
57
|
// 绑定层级 + 前缀 — 路由名自动拼接
|
|
47
58
|
const forge = useForge('admin', 'users')
|
|
48
|
-
forge.level
|
|
49
|
-
forge.prefix
|
|
50
|
-
forge('show', { user: 1 })
|
|
51
|
-
forge.
|
|
52
|
-
forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)
|
|
59
|
+
forge.level // → 'admin'
|
|
60
|
+
forge.prefix // → 'users'
|
|
61
|
+
forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)
|
|
62
|
+
forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)
|
|
53
63
|
|
|
54
64
|
// 通用方法(无论是否绑定 level 均可用)
|
|
55
|
-
forge.load('admin')
|
|
56
|
-
forge.isLoaded('admin')
|
|
57
|
-
forge.invalidate('admin')
|
|
58
|
-
forge.interceptors.request.use(...) // 拦截器管理
|
|
65
|
+
forge.load('admin') // 加载层级
|
|
66
|
+
forge.isLoaded('admin') // 检查缓存
|
|
67
|
+
forge.invalidate('admin') // 失效缓存
|
|
59
68
|
```
|
|
60
69
|
|
|
70
|
+
> **注意**:`useForge()` 无 level 时 **不提供** `route`/`url`/`hasRoute`/`getRoutes` 同步方法,
|
|
71
|
+
> 因为 auto-discovery 可能未完成。请使用 `useForgeRoute` 或 `await forge.ready` 后再调用。
|
|
72
|
+
|
|
61
73
|
### 参数智能解析
|
|
62
74
|
|
|
63
75
|
`api()` 的参数支持智能消解:路径参数平铺传入,`query`/`body`/`headers` 为固定 key。当路径参数名与固定
|
|
@@ -80,7 +92,6 @@ forge.api('search.show', {
|
|
|
80
92
|
```ts
|
|
81
93
|
import {
|
|
82
94
|
useForgeApi,
|
|
83
|
-
useForgeLevel,
|
|
84
95
|
useForgeRoute,
|
|
85
96
|
useForgeByPrefix,
|
|
86
97
|
} from '@route-forge/vue'
|
|
@@ -89,10 +100,8 @@ import {
|
|
|
89
100
|
const { call, pending, error } = useForgeApi()
|
|
90
101
|
const { data } = await call('admin', 'users.show', { user: 1 })
|
|
91
102
|
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// useForgeRoute — 响应式 URL 生成(用于 <a href> 等)
|
|
103
|
+
// useForgeRoute — 响应式 URL 生成器,内部处理 level 加载状态
|
|
104
|
+
// level 未加载时返回 '',加载后自动更新
|
|
96
105
|
const url = useForgeRoute('public', 'login.show')
|
|
97
106
|
|
|
98
107
|
// useForgeByPrefix — 层级 + 名字前缀封装
|
|
@@ -104,15 +113,24 @@ await api('show', { user: 1 }) // = forge.api('admin', 'users.show', { user: 1
|
|
|
104
113
|
|
|
105
114
|
```vue
|
|
106
115
|
<template>
|
|
116
|
+
<!-- useForgeRoute 内部处理加载状态,可直接在模板中使用 -->
|
|
117
|
+
<a :href="url">登录</a>
|
|
118
|
+
|
|
119
|
+
<!-- 或通过 $forge 全局属性(需确保 level 已加载) -->
|
|
107
120
|
<a :href="$forge.route('public', 'login.show')">登录</a>
|
|
108
121
|
</template>
|
|
122
|
+
|
|
123
|
+
<script setup>
|
|
124
|
+
import { useForgeRoute } from '@route-forge/vue'
|
|
125
|
+
const url = useForgeRoute('public', 'login.show')
|
|
126
|
+
</script>
|
|
109
127
|
```
|
|
110
128
|
|
|
111
129
|
## 文档
|
|
112
130
|
|
|
113
|
-
- 仓库主页: https://github.com/
|
|
114
|
-
- 设计文档: https://github.com/
|
|
115
|
-
- 规范: https://github.com/
|
|
131
|
+
- 仓库主页: https://github.com/route-forge/route-forge
|
|
132
|
+
- 设计文档: https://github.com/route-forge/route-forge/blob/main/.docs/DESIGN.md
|
|
133
|
+
- 规范: https://github.com/route-forge/route-forge/blob/main/.docs/SPEC.md
|
|
116
134
|
|
|
117
135
|
## License
|
|
118
136
|
|
package/dist/index.cjs
CHANGED
|
@@ -2,31 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
var vue = require('vue');
|
|
4
4
|
var core = require('@route-forge/core');
|
|
5
|
-
|
|
6
|
-
// src/plugin.ts
|
|
7
|
-
async function resolveRouteName(forge, level, prefix, suffix, separator = ".") {
|
|
8
|
-
if (!suffix) return prefix;
|
|
9
|
-
const joined = `${prefix}${separator}${suffix}`;
|
|
10
|
-
if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
|
|
11
|
-
await forge.load(level);
|
|
12
|
-
if (forge.hasRoute(level, joined)) return joined;
|
|
13
|
-
if (forge.hasRoute(level, suffix)) return suffix;
|
|
14
|
-
throw new core.UnknownRouteError(joined, level);
|
|
15
|
-
}
|
|
16
|
-
function resolveRouteNameSync(forge, level, prefix, suffix, separator = ".") {
|
|
17
|
-
if (!suffix) return prefix;
|
|
18
|
-
const joined = `${prefix}${separator}${suffix}`;
|
|
19
|
-
if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
|
|
20
|
-
if (forge.hasRoute(level, joined)) return joined;
|
|
21
|
-
if (forge.hasRoute(level, suffix)) return suffix;
|
|
22
|
-
throw new core.UnknownRouteError(joined, level);
|
|
23
|
-
}
|
|
5
|
+
var internal = require('@route-forge/core/internal');
|
|
24
6
|
|
|
25
7
|
// src/plugin.ts
|
|
26
8
|
var FORGE_INJECTION_KEY = /* @__PURE__ */ Symbol("route-forge");
|
|
27
9
|
function createRouteForgePlugin(options) {
|
|
28
10
|
const forge = core.createRouteForge(options);
|
|
29
11
|
return {
|
|
12
|
+
ready: forge.ready,
|
|
30
13
|
install(app) {
|
|
31
14
|
app.provide(FORGE_INJECTION_KEY, forge);
|
|
32
15
|
app.config.globalProperties.$forge = {
|
|
@@ -43,53 +26,52 @@ function useForge(level, prefix) {
|
|
|
43
26
|
);
|
|
44
27
|
}
|
|
45
28
|
if (level !== void 0) {
|
|
46
|
-
const
|
|
47
|
-
|
|
29
|
+
const levelLoaded = vue.ref(forge.isLoaded(level));
|
|
30
|
+
forge.load(level).then(() => {
|
|
31
|
+
levelLoaded.value = true;
|
|
32
|
+
}).catch(() => {
|
|
33
|
+
});
|
|
34
|
+
const unsub = forge.onLevelLoaded(level, () => {
|
|
35
|
+
levelLoaded.value = true;
|
|
36
|
+
unsub();
|
|
37
|
+
});
|
|
38
|
+
const callable2 = prefix ? async (name, params) => forge.api(level, await core.resolveRouteName(forge, level, prefix, name), params) : (name, params) => forge.api(level, name, params);
|
|
39
|
+
internal.defineImmutableProps(callable2, {
|
|
48
40
|
level,
|
|
49
41
|
// 未传 prefix 时不定义该属性,与 React 包行为保持一致('prefix' in forge === false)
|
|
50
42
|
...prefix !== void 0 ? { prefix } : {},
|
|
51
|
-
api: prefix ? async (name, params) => forge.api(level, await resolveRouteName(forge, level, prefix, name), params) : (name, params) => forge.api(level, name, params),
|
|
52
|
-
route: prefix ? (name, params) => forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params) : (name, params) => forge.route(level, name, params),
|
|
53
|
-
url: prefix ? (name, params) => forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params) : (name, params) => forge.route(level, name, params),
|
|
43
|
+
api: prefix ? async (name, params) => forge.api(level, await core.resolveRouteName(forge, level, prefix, name), params) : (name, params) => forge.api(level, name, params),
|
|
44
|
+
route: prefix ? (name, params) => forge.route(level, core.resolveRouteNameSync(forge, level, prefix, name), params) : (name, params) => forge.route(level, name, params),
|
|
45
|
+
url: prefix ? (name, params) => forge.route(level, core.resolveRouteNameSync(forge, level, prefix, name), params) : (name, params) => forge.route(level, name, params),
|
|
54
46
|
load: forge.load.bind(forge),
|
|
55
47
|
invalidate: forge.invalidate.bind(forge),
|
|
56
48
|
isLoaded: forge.isLoaded.bind(forge),
|
|
57
49
|
hasRoute: forge.hasRoute.bind(forge),
|
|
58
50
|
isLoading: forge.isLoading.bind(forge),
|
|
59
51
|
onLoadingChange: forge.onLoadingChange.bind(forge),
|
|
60
|
-
getRoutes: forge.getRoutes.bind(forge)
|
|
61
|
-
|
|
52
|
+
getRoutes: forge.getRoutes.bind(forge)
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(callable2, "levelLoaded", {
|
|
55
|
+
value: levelLoaded,
|
|
56
|
+
writable: false,
|
|
57
|
+
enumerable: true,
|
|
58
|
+
configurable: false
|
|
62
59
|
});
|
|
63
60
|
return callable2;
|
|
64
61
|
}
|
|
65
62
|
const callable = (lvl, name, params) => forge.api(lvl, name, params);
|
|
66
|
-
defineImmutableProps(callable, {
|
|
63
|
+
internal.defineImmutableProps(callable, {
|
|
67
64
|
api: forge.api.bind(forge),
|
|
68
|
-
route: forge.route.bind(forge),
|
|
69
|
-
url: forge.url.bind(forge),
|
|
70
65
|
load: forge.load.bind(forge),
|
|
71
66
|
invalidate: forge.invalidate.bind(forge),
|
|
72
67
|
isLoaded: forge.isLoaded.bind(forge),
|
|
73
|
-
hasRoute: forge.hasRoute.bind(forge),
|
|
74
68
|
isLoading: forge.isLoading.bind(forge),
|
|
75
69
|
onLoadingChange: forge.onLoadingChange.bind(forge),
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
ready: forge.ready,
|
|
71
|
+
onLevelLoaded: forge.onLevelLoaded.bind(forge)
|
|
78
72
|
});
|
|
79
73
|
return callable;
|
|
80
74
|
}
|
|
81
|
-
function defineImmutableProps(target, props) {
|
|
82
|
-
for (const key of Object.keys(props)) {
|
|
83
|
-
const val = props[key];
|
|
84
|
-
Object.defineProperty(target, key, {
|
|
85
|
-
value: val !== null && typeof val === "object" ? Object.freeze(val) : val,
|
|
86
|
-
writable: false,
|
|
87
|
-
enumerable: false,
|
|
88
|
-
configurable: false
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
return target;
|
|
92
|
-
}
|
|
93
75
|
function useForgeApi(level, prefix) {
|
|
94
76
|
const forge = level !== void 0 ? useForge(level, prefix) : useForge();
|
|
95
77
|
const pending = vue.ref(false);
|
|
@@ -109,38 +91,36 @@ function useForgeApi(level, prefix) {
|
|
|
109
91
|
}
|
|
110
92
|
return { pending, error, call };
|
|
111
93
|
}
|
|
112
|
-
function useForgeLevel(level) {
|
|
113
|
-
const forge = useForge();
|
|
114
|
-
const loaded = vue.ref(false);
|
|
115
|
-
const error = vue.ref(null);
|
|
116
|
-
vue.onMounted(async () => {
|
|
117
|
-
try {
|
|
118
|
-
await forge.load(level);
|
|
119
|
-
loaded.value = true;
|
|
120
|
-
} catch (e) {
|
|
121
|
-
error.value = e;
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
return { loaded, error };
|
|
125
|
-
}
|
|
126
94
|
function useForgeRoute(level, name, params) {
|
|
127
|
-
const forge =
|
|
95
|
+
const forge = vue.inject(FORGE_INJECTION_KEY);
|
|
96
|
+
const levelLoaded = vue.ref(forge.isLoaded(typeof level === "function" ? level() : level));
|
|
97
|
+
const lvl = typeof level === "function" ? level() : level;
|
|
98
|
+
if (!levelLoaded.value) {
|
|
99
|
+
vue.onMounted(() => {
|
|
100
|
+
forge.load(lvl).then(() => {
|
|
101
|
+
levelLoaded.value = true;
|
|
102
|
+
}).catch(() => {
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
128
106
|
return vue.computed(() => {
|
|
129
|
-
|
|
107
|
+
if (!levelLoaded.value) return "";
|
|
108
|
+
const l = typeof level === "function" ? level() : level;
|
|
130
109
|
const n = typeof name === "function" ? name() : name;
|
|
131
110
|
const p = params ? params() : void 0;
|
|
132
|
-
return forge.route(
|
|
111
|
+
return forge.route(l, n, p);
|
|
133
112
|
});
|
|
134
113
|
}
|
|
135
|
-
|
|
136
|
-
// src/composables/useForgeByPrefix.ts
|
|
137
114
|
function useForgeByPrefix(level, prefix, separator = ".") {
|
|
138
|
-
const forge =
|
|
115
|
+
const forge = vue.inject(FORGE_INJECTION_KEY);
|
|
139
116
|
return {
|
|
140
|
-
api: (suffix, params) => resolveRouteName(forge, level, prefix, suffix, separator).then(
|
|
117
|
+
api: (suffix, params) => core.resolveRouteName(forge, level, prefix, suffix, separator).then(
|
|
141
118
|
(name) => forge.api(level, name, params)
|
|
142
119
|
),
|
|
143
|
-
route: (suffix, params) =>
|
|
120
|
+
route: (suffix, params) => {
|
|
121
|
+
if (!forge.isLoaded(level)) return "";
|
|
122
|
+
return forge.route(level, core.resolveRouteNameSync(forge, level, prefix, suffix, separator), params);
|
|
123
|
+
}
|
|
144
124
|
};
|
|
145
125
|
}
|
|
146
126
|
|
|
@@ -149,7 +129,6 @@ exports.createRouteForgePlugin = createRouteForgePlugin;
|
|
|
149
129
|
exports.useForge = useForge;
|
|
150
130
|
exports.useForgeApi = useForgeApi;
|
|
151
131
|
exports.useForgeByPrefix = useForgeByPrefix;
|
|
152
|
-
exports.useForgeLevel = useForgeLevel;
|
|
153
132
|
exports.useForgeRoute = useForgeRoute;
|
|
154
133
|
//# sourceMappingURL=index.cjs.map
|
|
155
134
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/resolveRouteName.ts","../src/plugin.ts","../src/composables/useForgeApi.ts","../src/composables/useForgeLevel.ts","../src/composables/useForgeRoute.ts","../src/composables/useForgeByPrefix.ts"],"names":["UnknownRouteError","createRouteForge","inject","callable","ref","onMounted","computed"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * 智能路由名前缀解析\n *\n * 当前缀与后缀拼接产生歧义时(后缀本身已以前缀开头),\n * 通过查询已加载路由表来判定正确名称:\n * - 优先尝试 prefix + sep + suffix(完整拼接)\n * - 若不存在则回退到 suffix(视为已含前缀)\n * - 均不存在则抛 UnknownRouteError\n *\n * @see .docs/SPEC.md §4.1.7\n */\n\nimport { UnknownRouteError } from '@route-forge/core';\n\n/**\n * 路由名解析所需的最小 forge 接口。\n * 仅依赖 load() 和 hasRoute(),不依赖拦截器等完整能力。\n * 兼容 RouteForge、BoundForgeTyped、ForgeInstanceTyped 等所有形态。\n */\ninterface RouteResolver {\n load(level: string | string[]): Promise<void>;\n\n hasRoute(level: string, name: string): boolean;\n}\n\n/**\n * 异步版本:先确保层级已加载,再做歧义消解。\n * 适用于 api() 调用路径。\n */\nexport async function resolveRouteName(\n forge: RouteResolver,\n level: string,\n prefix: string,\n suffix: string,\n separator = '.',\n): Promise<string> {\n // 后缀为空 → 直接返回前缀\n if (!suffix) return prefix;\n\n const joined = `${prefix}${separator}${suffix}`;\n\n // 后缀不以前缀开头 → 无歧义,直接拼接\n if (!suffix.startsWith(`${prefix}${separator}`)) return joined;\n\n // 歧义场景:先确保层级已加载\n await forge.load(level);\n\n // 优先尝试完整拼接\n if (forge.hasRoute(level, joined)) return joined;\n // 回退到后缀本身(视为已含前缀)\n if (forge.hasRoute(level, suffix)) return suffix;\n\n // 均不存在 → 报错\n throw new UnknownRouteError(joined, level);\n}\n\n/**\n * 同步版本:基于已加载缓存做歧义消解。\n * 适用于 route() / url() 调用路径(要求层级已加载)。\n */\nexport function resolveRouteNameSync(\n forge: RouteResolver,\n level: string,\n prefix: string,\n suffix: string,\n separator = '.',\n): string {\n if (!suffix) return prefix;\n\n const joined = `${prefix}${separator}${suffix}`;\n if (!suffix.startsWith(`${prefix}${separator}`)) return joined;\n\n // 歧义场景:基于已加载缓存判定\n if (forge.hasRoute(level, joined)) return joined;\n if (forge.hasRoute(level, suffix)) return suffix;\n\n throw new UnknownRouteError(joined, level);\n}\n","/**\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 } from 'vue';\nimport { inject, reactive, readonly } from 'vue';\nimport {\n type ApiCallParams,\n createRouteForge,\n type ForgeApiParams,\n type ForgeApiResponse,\n type ForgeRouteName,\n type InterceptorHandler,\n type LoadingChangeCallback,\n type RequestConfig,\n type ResponseData,\n type RouteForge,\n type RouteForgeOptions,\n type RouteMeta,\n} from '@route-forge/core';\nimport { resolveRouteName, resolveRouteNameSync } from './utils/resolveRouteName.js';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** 只读拦截器管理器:仅暴露查询方法,隐藏 use/eject/clear */\ninterface ReadOnlyInterceptorManager<TIn, TOut = TIn> {\n readonly size: number;\n\n forEach(fn: (handler: InterceptorHandler<TIn, TOut>) => void): void;\n}\n\n/**\n * 共享方法集(level 已绑定时的方法签名)\n * .api() / .route() / .url() — name 和 params 根据 ForgeRouteMap 自动推断\n * .load() / .invalidate() / .isLoaded() / .interceptors\n */\nexport interface BoundForgeMethods<L extends string = string> {\n interceptors: {\n request: ReadOnlyInterceptorManager<RequestConfig>;\n response: ReadOnlyInterceptorManager<ResponseData>;\n };\n\n api(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<ForgeApiResponse<L, ForgeRouteName<L>>>;\n\n route(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): string;\n\n url(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): string;\n\n load(level: string | string[]): Promise<void>;\n\n invalidate(level?: string | string[]): void;\n\n isLoaded(level?: string): boolean;\n\n hasRoute(level: string, name: string): boolean;\n\n /** 查询加载中标识状态 */\n isLoading(): boolean;\n\n /** 订阅加载状态变更,返回取消订阅函数 */\n onLoadingChange(cb: LoadingChangeCallback): () => void;\n\n /** 获取指定层级下全部路由元信息(深拷贝,修改不影响内部缓存) */\n getRoutes(level: string): Record<string, RouteMeta>;\n}\n\n/** 已绑定 level — 直接调用无需 level,api/route/url 的 name 自动限定到该层级 */\nexport interface BoundForgeTyped<L extends string> extends BoundForgeMethods<L> {\n (name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<ForgeApiResponse<L, ForgeRouteName<L>>>;\n /** 当前绑定的 level 值 */\n readonly level: L;\n /** 路由名前缀(仅在 useForge(level, prefix) 传入 prefix 时存在) */\n readonly prefix?: string;\n}\n\n/** 未绑定 level — 直接调用需要传 level */\nexport interface ForgeInstanceTyped extends Omit<BoundForgeMethods<string>, 'api' | 'route' | 'url' | 'hasRoute' | 'getRoutes'> {\n (level: string, name: string, params?: ApiCallParams): Promise<unknown>;\n api(level: string, name: string, params?: ApiCallParams): Promise<unknown>;\n route(level: string, name: string, params?: Record<string, unknown>): string;\n url(level: string, name: string, params?: Record<string, unknown>): string;\n\n hasRoute(level: string, name: string): boolean;\n\n /** 获取全部层级路由(深拷贝);传 level 时仅返回该层级 */\n getRoutes(): Record<string, Record<string, RouteMeta>>;\n getRoutes(level: string): Record<string, RouteMeta>;\n}\n\nexport function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]> {\n const forge = createRouteForge(options);\n\n return {\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 实例。\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('users.show', { user: 1 })\n * forge.api('users.show')\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge.level // → 'admin'\n * forge.prefix // → 'users'\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.api('index') // → forge.api('admin', 'users.index')\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): BoundForgeTyped<L>;\nexport function useForge<L extends string>(level: L): BoundForgeTyped<L>;\nexport function useForge(): ForgeInstanceTyped;\nexport function useForge(level?: string, prefix?: string): ForgeInstanceTyped | BoundForgeTyped<string> {\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 const callable = prefix\n ? async (name: string, params?: ApiCallParams) =>\n forge.api(level, await resolveRouteName(forge, level, prefix, name), params)\n : (name: string, params?: ApiCallParams) =>\n forge.api(level, name, params);\n defineImmutableProps(callable, {\n level,\n // 未传 prefix 时不定义该属性,与 React 包行为保持一致('prefix' in forge === false)\n ...(prefix !== undefined ? { prefix } : {}),\n api: prefix\n ? async (name: string, params?: ApiCallParams) =>\n forge.api(level, await resolveRouteName(forge, level, prefix, name), params)\n : (name: string, params?: ApiCallParams) => forge.api(level, name, params),\n route: prefix\n ? (name: string, params?: Record<string, unknown>) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params)\n : (name: string, params?: Record<string, unknown>) => forge.route(level, name, params),\n url: prefix\n ? (name: string, params?: Record<string, unknown>) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params)\n : (name: string, params?: Record<string, unknown>) => forge.route(level, name, params),\n load: forge.load.bind(forge),\n invalidate: forge.invalidate.bind(forge),\n isLoaded: forge.isLoaded.bind(forge),\n hasRoute: forge.hasRoute.bind(forge),\n isLoading: forge.isLoading.bind(forge),\n onLoadingChange: forge.onLoadingChange.bind(forge),\n getRoutes: forge.getRoutes.bind(forge),\n interceptors: forge.interceptors,\n });\n return callable as unknown as BoundForgeTyped<string>;\n }\n\n const callable = (lvl: string, name: string, params?: ApiCallParams) =>\n forge.api(lvl, name, params);\n defineImmutableProps(callable, {\n api: forge.api.bind(forge),\n route: forge.route.bind(forge),\n url: forge.url.bind(forge),\n load: forge.load.bind(forge),\n invalidate: forge.invalidate.bind(forge),\n isLoaded: forge.isLoaded.bind(forge),\n hasRoute: forge.hasRoute.bind(forge),\n isLoading: forge.isLoading.bind(forge),\n onLoadingChange: forge.onLoadingChange.bind(forge),\n getRoutes: forge.getRoutes.bind(forge),\n interceptors: forge.interceptors,\n });\n return callable as ForgeInstanceTyped;\n}\n\nexport { readonly, reactive };\n\n/**\n * 以不可变、不可枚举、不可重配置的方式将属性挂载到目标对象上。\n * 相比 Object.assign 更安全——外部无法通过遍历/删除/重写篡改这些方法。\n * 对象类型的值会浅冻结(Object.freeze),防止内部键被增删改。\n */\nfunction defineImmutableProps<T extends object>(target: T, props: Record<string, unknown>): T {\n for (const key of Object.keys(props)) {\n const val = props[key];\n Object.defineProperty(target, key, {\n value: val !== null && typeof val === 'object' ? Object.freeze(val) : val,\n writable: false,\n enumerable: false,\n configurable: false,\n });\n }\n return target;\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\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type {\n ApiCallParams,\n ForgeApiParams,\n ForgeApiResponse,\n ForgeRouteName,\n} from '@route-forge/core';\n\n/** call 函数签名 — 未绑定 level,需要显式传入 */\nexport interface UseForgeApiCall {\n (level: string, name: string, params?: ApiCallParams): Promise<{\n data: unknown;\n error: unknown;\n }>;\n}\n\n/** call 函数签名 — 已绑定 level,无需再传 */\nexport interface UseForgeApiBoundCall<L extends string> {\n (name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<{\n data: ForgeApiResponse<L, ForgeRouteName<L>>;\n error: unknown;\n }>;\n}\n\nexport interface UseForgeApiReturn {\n pending: ReturnType<typeof ref<boolean>>;\n error: ReturnType<typeof ref<unknown>>;\n call: UseForgeApiCall;\n}\n\nexport interface UseForgeApiBoundReturn<L extends string> {\n pending: ReturnType<typeof ref<boolean>>;\n error: ReturnType<typeof ref<unknown>>;\n call: UseForgeApiBoundCall<L>;\n}\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturn;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturn<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturn<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturn | UseForgeApiBoundReturn<string> {\n const forge = level !== undefined ? useForge(level, prefix as string) : useForge();\n const pending = ref(false);\n const error = ref<unknown>(null);\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n pending.value = true;\n error.value = null;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = await (forge as any).api(...args);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n pending.value = false;\n }\n }\n\n return { pending, error, call: call as any };\n}\n","/**\n * useForgeLevel:声明组件依赖某层级,挂载时自动 forge.load(level),销毁时不主动失效\n * @see .docs/SPEC.md §4.1.7\n */\n\nimport { onMounted, ref } from 'vue';\nimport { useForge } from '../plugin.js';\n\nexport interface UseForgeLevelReturn {\n loaded: ReturnType<typeof ref<boolean>>;\n error: ReturnType<typeof ref<unknown>>;\n}\n\nexport function useForgeLevel(level: string): UseForgeLevelReturn {\n const forge = useForge();\n const loaded = ref(false);\n const error = ref<unknown>(null);\n\n onMounted(async () => {\n try {\n await forge.load(level);\n loaded.value = true;\n } catch (e) {\n error.value = e;\n }\n });\n\n return { loaded, error };\n}\n","/**\n * useForgeRoute:仅生成 URL,不发请求(用于 <a href>、外部跳转等)\n * @see .docs/SPEC.md §4.1.7\n */\n\nimport { computed, type ComputedRef } from 'vue';\nimport { useForge } from '../plugin.js';\n\nexport function useForgeRoute(\n level: string | (() => string),\n name: string | (() => string),\n params?: () => Record<string, unknown>,\n): ComputedRef<string> {\n const forge = useForge();\n return computed(() => {\n const lvl = typeof level === 'function' ? level() : level;\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n return forge.route(lvl, n, p);\n });\n}\n","/**\n * useForgeByPrefix:带层级 + 名字前缀的封装,方便后续减少名称传入\n * @see .docs/SPEC.md §4.1.7\n *\n * 智能前缀解析:\n * - 传入后缀不以前缀开头 → 自动拼接 prefix.suffix\n * - 传入后缀已以前缀开头(歧义) → 优先尝试完整拼接,\n * 若不存在则视为已含前缀直接使用,均不存在则报错\n *\n * 示例(prefix = 'test'):\n * api('1') → test.1\n * api('test1.1') → test.test1.1\n * api('test.1') → 歧义:优先 test.test.1,回退 test.1\n */\n\nimport { useForge } from '../plugin.js';\nimport { resolveRouteName, resolveRouteNameSync } from '../utils/resolveRouteName.js';\nimport type { ApiCallParams } from '@route-forge/core';\n\nexport interface UseForgeByPrefixReturn {\n api: (suffix: string, params?: ApiCallParams) => Promise<unknown>;\n route: (suffix: string, params?: Record<string, unknown>) => string;\n}\n\nexport function useForgeByPrefix(level: string, prefix: string, separator = '.'): UseForgeByPrefixReturn {\n const forge = useForge();\n\n return {\n api: (suffix, params) =>\n resolveRouteName(forge, level, prefix, suffix, separator).then(\n (name) => forge.api(level, name, params),\n ),\n route: (suffix, params) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, suffix, separator), params),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/composables/useForgeApi.ts","../src/composables/useForgeRoute.ts","../src/composables/useForgeByPrefix.ts"],"names":["createRouteForge","inject","ref","callable","resolveRouteName","defineImmutableProps","resolveRouteNameSync","onMounted","computed"],"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 createRouteForge,\n type ForgeInstanceTyped,\n type RouteForge,\n type RouteForgeOptions,\n resolveRouteName,\n resolveRouteNameSync,\n} from '@route-forge/core';\nimport { defineImmutableProps } from '@route-forge/core/internal';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** 已绑定 level — 直接调用无需 level,api/route/url 的 name 自动限定到该层级 */\nexport type BoundForgeTyped<L extends string> = import('@route-forge/core').BoundForgeTyped<L, Ref<boolean>>;\n\n/** 未绑定 level — 直接调用需要传 level(不提供 route/url/hasRoute/getRoutes 等同步方法) */\nexport type { ForgeInstanceTyped } from '@route-forge/core';\n\nexport function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]> & {\n ready: Promise<void>\n} {\n const forge = createRouteForge(options);\n\n return {\n ready: forge.ready,\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 实例。\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('users.show', { user: 1 })\n * forge.api('users.show')\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge.level // → 'admin'\n * forge.prefix // → 'users'\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.api('index') // → forge.api('admin', 'users.index')\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): BoundForgeTyped<L>;\nexport function useForge<L extends string>(level: L): BoundForgeTyped<L>;\nexport function useForge(): ForgeInstanceTyped;\nexport function useForge(level?: string, prefix?: string): ForgeInstanceTyped | BoundForgeTyped<string> {\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 // 自动触发 level 加载 + 响应式 levelLoaded 状态\n const levelLoaded = ref(forge.isLoaded(level));\n forge.load(level).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */\n });\n // 订阅 level 加载完成事件(兜底:如果 load() 在 ref 赋值后才完成)\n const unsub = forge.onLevelLoaded(level, () => {\n levelLoaded.value = true;\n unsub();\n });\n\n const callable = prefix\n ? async (name: string, params?: ApiCallParams) =>\n forge.api(level, await resolveRouteName(forge, level, prefix, name), params)\n : (name: string, params?: ApiCallParams) =>\n forge.api(level, name, params);\n defineImmutableProps(callable, {\n level,\n // 未传 prefix 时不定义该属性,与 React 包行为保持一致('prefix' in forge === false)\n ...(prefix !== undefined ? { prefix } : {}),\n api: prefix\n ? async (name: string, params?: ApiCallParams) =>\n forge.api(level, await resolveRouteName(forge, level, prefix, name), params)\n : (name: string, params?: ApiCallParams) => forge.api(level, name, params),\n route: prefix\n ? (name: string, params?: Record<string, unknown>) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params)\n : (name: string, params?: Record<string, unknown>) => forge.route(level, name, params),\n url: prefix\n ? (name: string, params?: Record<string, unknown>) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params)\n : (name: string, params?: Record<string, unknown>) => forge.route(level, name, params),\n load: forge.load.bind(forge),\n invalidate: forge.invalidate.bind(forge),\n isLoaded: forge.isLoaded.bind(forge),\n hasRoute: forge.hasRoute.bind(forge),\n isLoading: forge.isLoading.bind(forge),\n onLoadingChange: forge.onLoadingChange.bind(forge),\n getRoutes: forge.getRoutes.bind(forge),\n });\n // levelLoaded 需要保持响应式,不能通过 defineImmutableProps(会 Object.freeze)\n Object.defineProperty(callable, 'levelLoaded', {\n value: levelLoaded,\n writable: false,\n enumerable: true,\n configurable: false,\n });\n return callable as unknown as BoundForgeTyped<string>;\n }\n\n const callable = (lvl: string, name: string, params?: ApiCallParams) =>\n forge.api(lvl, name, params);\n defineImmutableProps(callable, {\n api: forge.api.bind(forge),\n load: forge.load.bind(forge),\n invalidate: forge.invalidate.bind(forge),\n isLoaded: forge.isLoaded.bind(forge),\n isLoading: forge.isLoading.bind(forge),\n onLoadingChange: forge.onLoadingChange.bind(forge),\n ready: forge.ready,\n onLevelLoaded: forge.onLevelLoaded.bind(forge),\n });\n return callable as unknown as ForgeInstanceTyped;\n}\n\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\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type { Ref } from 'vue';\nimport type {\n UseForgeApiCall,\n UseForgeApiBoundCall,\n UseForgeApiReturn,\n UseForgeApiBoundReturn,\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 forge = level !== undefined ? useForge(level, prefix as string) : useForge();\n const pending = ref(false);\n const error = ref<unknown>(null);\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n pending.value = true;\n error.value = null;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = await (forge as any).api(...args);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n pending.value = false;\n }\n }\n\n return { pending, error, call: call as any };\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\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\nexport function useForgeRoute(\n level: string | (() => string),\n name: string | (() => string),\n params?: () => Record<string, unknown>,\n): ComputedRef<string> {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n\n // 响应式追踪 level 加载状态(computed 依赖此 ref 触发重新计算)\n const levelLoaded = ref(forge.isLoaded(typeof level === 'function' ? level() : level));\n\n const lvl = typeof level === 'function' ? level() : level;\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 const l = typeof level === 'function' ? level() : level;\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n return forge.route(l, n, p);\n });\n}\n","/**\n * useForgeByPrefix:带层级 + 名字前缀的封装,方便后续减少名称传入\n * @see .docs/SPEC.md §4.1.7\n *\n * 智能前缀解析:\n * - 传入后缀不以前缀开头 → 自动拼接 prefix.suffix\n * - 传入后缀已以前缀开头(歧义) → 优先尝试完整拼接,\n * 若不存在则视为已含前缀直接使用,均不存在则报错\n *\n * 示例(prefix = 'test'):\n * api('1') → test.1\n * api('test1.1') → test.test1.1\n * api('test.1') → 歧义:优先 test.test.1,回退 test.1\n */\n\nimport { inject } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport {\n resolveRouteName,\n resolveRouteNameSync,\n type ApiCallParams,\n type RouteForge,\n type UseForgeByPrefixReturn,\n} from '@route-forge/core';\n\nexport type { UseForgeByPrefixReturn };\n\nexport function useForgeByPrefix(level: string, prefix: string, separator = '.'): UseForgeByPrefixReturn {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n\n return {\n api: (suffix, params) =>\n resolveRouteName(forge, level, prefix, suffix, separator).then(\n (name) => forge.api(level, name, params),\n ),\n route: (suffix, params) => {\n // level 未加载时返回空字符串,避免 resolveRouteNameSync 内部 hasRoute() 抛错\n if (!forge.isLoaded(level)) return '';\n return forge.route(level, resolveRouteNameSync(forge, level, prefix, suffix, separator), params);\n },\n };\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,75 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* Vue 3 插件入口
|
|
6
|
-
* @see .docs/SPEC.md §4.1.7
|
|
7
|
-
*
|
|
8
|
-
* 提供:
|
|
9
|
-
* - 全局属性 $forge(route() 工具)
|
|
10
|
-
* - inject symbol 注入 RouteForge 实例供 composable 使用
|
|
11
|
-
* - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例
|
|
12
|
-
* • 不传 level:forge(level, name, params?) 直接调用
|
|
13
|
-
* • 传 level:forge(name, params?) 直接调用,自动绑定层级
|
|
14
|
-
* • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix
|
|
15
|
-
*
|
|
16
|
-
* 类型推断:
|
|
17
|
-
* 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,
|
|
18
|
-
* level / name / params 均自动推断,IDE 提供补全提示。
|
|
19
|
-
*/
|
|
1
|
+
import * as _route_forge_core from '@route-forge/core';
|
|
2
|
+
import { RouteForge, RouteForgeOptions, ForgeInstanceTyped, UseForgeApiBoundReturn, UseForgeApiReturn, UseForgeByPrefixReturn } from '@route-forge/core';
|
|
3
|
+
export { ForgeInstanceTyped, UseForgeApiBoundCall, UseForgeApiCall, UseForgeByPrefixReturn } from '@route-forge/core';
|
|
4
|
+
import { Ref, InjectionKey, Plugin, ComputedRef } from 'vue';
|
|
20
5
|
|
|
21
6
|
declare const FORGE_INJECTION_KEY: InjectionKey<RouteForge>;
|
|
22
7
|
interface RouteForgePluginOptions extends RouteForgeOptions {
|
|
23
8
|
}
|
|
24
|
-
/** 只读拦截器管理器:仅暴露查询方法,隐藏 use/eject/clear */
|
|
25
|
-
interface ReadOnlyInterceptorManager<TIn, TOut = TIn> {
|
|
26
|
-
readonly size: number;
|
|
27
|
-
forEach(fn: (handler: InterceptorHandler<TIn, TOut>) => void): void;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* 共享方法集(level 已绑定时的方法签名)
|
|
31
|
-
* .api() / .route() / .url() — name 和 params 根据 ForgeRouteMap 自动推断
|
|
32
|
-
* .load() / .invalidate() / .isLoaded() / .interceptors
|
|
33
|
-
*/
|
|
34
|
-
interface BoundForgeMethods<L extends string = string> {
|
|
35
|
-
interceptors: {
|
|
36
|
-
request: ReadOnlyInterceptorManager<RequestConfig>;
|
|
37
|
-
response: ReadOnlyInterceptorManager<ResponseData>;
|
|
38
|
-
};
|
|
39
|
-
api(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<ForgeApiResponse<L, ForgeRouteName<L>>>;
|
|
40
|
-
route(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): string;
|
|
41
|
-
url(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): string;
|
|
42
|
-
load(level: string | string[]): Promise<void>;
|
|
43
|
-
invalidate(level?: string | string[]): void;
|
|
44
|
-
isLoaded(level?: string): boolean;
|
|
45
|
-
hasRoute(level: string, name: string): boolean;
|
|
46
|
-
/** 查询加载中标识状态 */
|
|
47
|
-
isLoading(): boolean;
|
|
48
|
-
/** 订阅加载状态变更,返回取消订阅函数 */
|
|
49
|
-
onLoadingChange(cb: LoadingChangeCallback): () => void;
|
|
50
|
-
/** 获取指定层级下全部路由元信息(深拷贝,修改不影响内部缓存) */
|
|
51
|
-
getRoutes(level: string): Record<string, RouteMeta>;
|
|
52
|
-
}
|
|
53
9
|
/** 已绑定 level — 直接调用无需 level,api/route/url 的 name 自动限定到该层级 */
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
readonly prefix?: string;
|
|
60
|
-
}
|
|
61
|
-
/** 未绑定 level — 直接调用需要传 level */
|
|
62
|
-
interface ForgeInstanceTyped extends Omit<BoundForgeMethods<string>, 'api' | 'route' | 'url' | 'hasRoute' | 'getRoutes'> {
|
|
63
|
-
(level: string, name: string, params?: ApiCallParams): Promise<unknown>;
|
|
64
|
-
api(level: string, name: string, params?: ApiCallParams): Promise<unknown>;
|
|
65
|
-
route(level: string, name: string, params?: Record<string, unknown>): string;
|
|
66
|
-
url(level: string, name: string, params?: Record<string, unknown>): string;
|
|
67
|
-
hasRoute(level: string, name: string): boolean;
|
|
68
|
-
/** 获取全部层级路由(深拷贝);传 level 时仅返回该层级 */
|
|
69
|
-
getRoutes(): Record<string, Record<string, RouteMeta>>;
|
|
70
|
-
getRoutes(level: string): Record<string, RouteMeta>;
|
|
71
|
-
}
|
|
72
|
-
declare function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]>;
|
|
10
|
+
type BoundForgeTyped<L extends string> = _route_forge_core.BoundForgeTyped<L, Ref<boolean>>;
|
|
11
|
+
|
|
12
|
+
declare function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]> & {
|
|
13
|
+
ready: Promise<void>;
|
|
14
|
+
};
|
|
73
15
|
/**
|
|
74
16
|
* 获取 forge 实例。
|
|
75
17
|
*
|
|
@@ -113,51 +55,22 @@ declare function useForge(): ForgeInstanceTyped;
|
|
|
113
55
|
* level / name / params 均自动推断,IDE 提供补全提示。
|
|
114
56
|
*/
|
|
115
57
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
(level: string, name: string, params?: ApiCallParams): Promise<{
|
|
119
|
-
data: unknown;
|
|
120
|
-
error: unknown;
|
|
121
|
-
}>;
|
|
122
|
-
}
|
|
123
|
-
/** call 函数签名 — 已绑定 level,无需再传 */
|
|
124
|
-
interface UseForgeApiBoundCall<L extends string> {
|
|
125
|
-
(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<{
|
|
126
|
-
data: ForgeApiResponse<L, ForgeRouteName<L>>;
|
|
127
|
-
error: unknown;
|
|
128
|
-
}>;
|
|
129
|
-
}
|
|
130
|
-
interface UseForgeApiReturn {
|
|
131
|
-
pending: ReturnType<typeof ref<boolean>>;
|
|
132
|
-
error: ReturnType<typeof ref<unknown>>;
|
|
133
|
-
call: UseForgeApiCall;
|
|
134
|
-
}
|
|
135
|
-
interface UseForgeApiBoundReturn<L extends string> {
|
|
136
|
-
pending: ReturnType<typeof ref<boolean>>;
|
|
137
|
-
error: ReturnType<typeof ref<unknown>>;
|
|
138
|
-
call: UseForgeApiBoundCall<L>;
|
|
139
|
-
}
|
|
58
|
+
type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;
|
|
59
|
+
type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;
|
|
140
60
|
/** 不绑定层级 — call 需要传 level */
|
|
141
|
-
declare function useForgeApi():
|
|
61
|
+
declare function useForgeApi(): UseForgeApiReturnVue;
|
|
142
62
|
/** 绑定层级 — call 无需传 level */
|
|
143
|
-
declare function useForgeApi<L extends string>(level: L):
|
|
63
|
+
declare function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;
|
|
144
64
|
/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */
|
|
145
|
-
declare function useForgeApi<L extends string>(level: L, prefix: string):
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* useForgeLevel:声明组件依赖某层级,挂载时自动 forge.load(level),销毁时不主动失效
|
|
149
|
-
* @see .docs/SPEC.md §4.1.7
|
|
150
|
-
*/
|
|
151
|
-
|
|
152
|
-
interface UseForgeLevelReturn {
|
|
153
|
-
loaded: ReturnType<typeof ref<boolean>>;
|
|
154
|
-
error: ReturnType<typeof ref<unknown>>;
|
|
155
|
-
}
|
|
156
|
-
declare function useForgeLevel(level: string): UseForgeLevelReturn;
|
|
65
|
+
declare function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;
|
|
157
66
|
|
|
158
67
|
/**
|
|
159
|
-
* useForgeRoute
|
|
68
|
+
* useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态
|
|
160
69
|
* @see .docs/SPEC.md §4.1.7
|
|
70
|
+
*
|
|
71
|
+
* - level 未加载时返回空字符串 ''(不抛错,模板不崩)
|
|
72
|
+
* - level 加载完成后自动重新计算并返回正确 URL
|
|
73
|
+
* - 用户无需关心 levelLoaded 状态,直接用即可
|
|
161
74
|
*/
|
|
162
75
|
|
|
163
76
|
declare function useForgeRoute(level: string | (() => string), name: string | (() => string), params?: () => Record<string, unknown>): ComputedRef<string>;
|
|
@@ -177,10 +90,6 @@ declare function useForgeRoute(level: string | (() => string), name: string | ((
|
|
|
177
90
|
* api('test.1') → 歧义:优先 test.test.1,回退 test.1
|
|
178
91
|
*/
|
|
179
92
|
|
|
180
|
-
interface UseForgeByPrefixReturn {
|
|
181
|
-
api: (suffix: string, params?: ApiCallParams) => Promise<unknown>;
|
|
182
|
-
route: (suffix: string, params?: Record<string, unknown>) => string;
|
|
183
|
-
}
|
|
184
93
|
declare function useForgeByPrefix(level: string, prefix: string, separator?: string): UseForgeByPrefixReturn;
|
|
185
94
|
|
|
186
|
-
export { type
|
|
95
|
+
export { type BoundForgeTyped, FORGE_INJECTION_KEY, type RouteForgePluginOptions, type UseForgeApiBoundReturnVue, type UseForgeApiReturnVue, createRouteForgePlugin, useForge, useForgeApi, useForgeByPrefix, useForgeRoute };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,75 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* Vue 3 插件入口
|
|
6
|
-
* @see .docs/SPEC.md §4.1.7
|
|
7
|
-
*
|
|
8
|
-
* 提供:
|
|
9
|
-
* - 全局属性 $forge(route() 工具)
|
|
10
|
-
* - inject symbol 注入 RouteForge 实例供 composable 使用
|
|
11
|
-
* - useForge() / useForge(level) / useForge(level, prefix) 返回统一方法的 forge 实例
|
|
12
|
-
* • 不传 level:forge(level, name, params?) 直接调用
|
|
13
|
-
* • 传 level:forge(name, params?) 直接调用,自动绑定层级
|
|
14
|
-
* • 传 level + prefix:forge(suffix, params?) 自动拼接 prefix
|
|
15
|
-
*
|
|
16
|
-
* 类型推断:
|
|
17
|
-
* 当 ForgeRouteMap 通过 codegen 或 module augmentation 定义时,
|
|
18
|
-
* level / name / params 均自动推断,IDE 提供补全提示。
|
|
19
|
-
*/
|
|
1
|
+
import * as _route_forge_core from '@route-forge/core';
|
|
2
|
+
import { RouteForge, RouteForgeOptions, ForgeInstanceTyped, UseForgeApiBoundReturn, UseForgeApiReturn, UseForgeByPrefixReturn } from '@route-forge/core';
|
|
3
|
+
export { ForgeInstanceTyped, UseForgeApiBoundCall, UseForgeApiCall, UseForgeByPrefixReturn } from '@route-forge/core';
|
|
4
|
+
import { Ref, InjectionKey, Plugin, ComputedRef } from 'vue';
|
|
20
5
|
|
|
21
6
|
declare const FORGE_INJECTION_KEY: InjectionKey<RouteForge>;
|
|
22
7
|
interface RouteForgePluginOptions extends RouteForgeOptions {
|
|
23
8
|
}
|
|
24
|
-
/** 只读拦截器管理器:仅暴露查询方法,隐藏 use/eject/clear */
|
|
25
|
-
interface ReadOnlyInterceptorManager<TIn, TOut = TIn> {
|
|
26
|
-
readonly size: number;
|
|
27
|
-
forEach(fn: (handler: InterceptorHandler<TIn, TOut>) => void): void;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* 共享方法集(level 已绑定时的方法签名)
|
|
31
|
-
* .api() / .route() / .url() — name 和 params 根据 ForgeRouteMap 自动推断
|
|
32
|
-
* .load() / .invalidate() / .isLoaded() / .interceptors
|
|
33
|
-
*/
|
|
34
|
-
interface BoundForgeMethods<L extends string = string> {
|
|
35
|
-
interceptors: {
|
|
36
|
-
request: ReadOnlyInterceptorManager<RequestConfig>;
|
|
37
|
-
response: ReadOnlyInterceptorManager<ResponseData>;
|
|
38
|
-
};
|
|
39
|
-
api(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<ForgeApiResponse<L, ForgeRouteName<L>>>;
|
|
40
|
-
route(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): string;
|
|
41
|
-
url(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): string;
|
|
42
|
-
load(level: string | string[]): Promise<void>;
|
|
43
|
-
invalidate(level?: string | string[]): void;
|
|
44
|
-
isLoaded(level?: string): boolean;
|
|
45
|
-
hasRoute(level: string, name: string): boolean;
|
|
46
|
-
/** 查询加载中标识状态 */
|
|
47
|
-
isLoading(): boolean;
|
|
48
|
-
/** 订阅加载状态变更,返回取消订阅函数 */
|
|
49
|
-
onLoadingChange(cb: LoadingChangeCallback): () => void;
|
|
50
|
-
/** 获取指定层级下全部路由元信息(深拷贝,修改不影响内部缓存) */
|
|
51
|
-
getRoutes(level: string): Record<string, RouteMeta>;
|
|
52
|
-
}
|
|
53
9
|
/** 已绑定 level — 直接调用无需 level,api/route/url 的 name 自动限定到该层级 */
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
readonly prefix?: string;
|
|
60
|
-
}
|
|
61
|
-
/** 未绑定 level — 直接调用需要传 level */
|
|
62
|
-
interface ForgeInstanceTyped extends Omit<BoundForgeMethods<string>, 'api' | 'route' | 'url' | 'hasRoute' | 'getRoutes'> {
|
|
63
|
-
(level: string, name: string, params?: ApiCallParams): Promise<unknown>;
|
|
64
|
-
api(level: string, name: string, params?: ApiCallParams): Promise<unknown>;
|
|
65
|
-
route(level: string, name: string, params?: Record<string, unknown>): string;
|
|
66
|
-
url(level: string, name: string, params?: Record<string, unknown>): string;
|
|
67
|
-
hasRoute(level: string, name: string): boolean;
|
|
68
|
-
/** 获取全部层级路由(深拷贝);传 level 时仅返回该层级 */
|
|
69
|
-
getRoutes(): Record<string, Record<string, RouteMeta>>;
|
|
70
|
-
getRoutes(level: string): Record<string, RouteMeta>;
|
|
71
|
-
}
|
|
72
|
-
declare function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]>;
|
|
10
|
+
type BoundForgeTyped<L extends string> = _route_forge_core.BoundForgeTyped<L, Ref<boolean>>;
|
|
11
|
+
|
|
12
|
+
declare function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]> & {
|
|
13
|
+
ready: Promise<void>;
|
|
14
|
+
};
|
|
73
15
|
/**
|
|
74
16
|
* 获取 forge 实例。
|
|
75
17
|
*
|
|
@@ -113,51 +55,22 @@ declare function useForge(): ForgeInstanceTyped;
|
|
|
113
55
|
* level / name / params 均自动推断,IDE 提供补全提示。
|
|
114
56
|
*/
|
|
115
57
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
(level: string, name: string, params?: ApiCallParams): Promise<{
|
|
119
|
-
data: unknown;
|
|
120
|
-
error: unknown;
|
|
121
|
-
}>;
|
|
122
|
-
}
|
|
123
|
-
/** call 函数签名 — 已绑定 level,无需再传 */
|
|
124
|
-
interface UseForgeApiBoundCall<L extends string> {
|
|
125
|
-
(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<{
|
|
126
|
-
data: ForgeApiResponse<L, ForgeRouteName<L>>;
|
|
127
|
-
error: unknown;
|
|
128
|
-
}>;
|
|
129
|
-
}
|
|
130
|
-
interface UseForgeApiReturn {
|
|
131
|
-
pending: ReturnType<typeof ref<boolean>>;
|
|
132
|
-
error: ReturnType<typeof ref<unknown>>;
|
|
133
|
-
call: UseForgeApiCall;
|
|
134
|
-
}
|
|
135
|
-
interface UseForgeApiBoundReturn<L extends string> {
|
|
136
|
-
pending: ReturnType<typeof ref<boolean>>;
|
|
137
|
-
error: ReturnType<typeof ref<unknown>>;
|
|
138
|
-
call: UseForgeApiBoundCall<L>;
|
|
139
|
-
}
|
|
58
|
+
type UseForgeApiReturnVue = UseForgeApiReturn<Ref<boolean>, Ref<unknown>>;
|
|
59
|
+
type UseForgeApiBoundReturnVue<L extends string> = UseForgeApiBoundReturn<L, Ref<boolean>, Ref<unknown>>;
|
|
140
60
|
/** 不绑定层级 — call 需要传 level */
|
|
141
|
-
declare function useForgeApi():
|
|
61
|
+
declare function useForgeApi(): UseForgeApiReturnVue;
|
|
142
62
|
/** 绑定层级 — call 无需传 level */
|
|
143
|
-
declare function useForgeApi<L extends string>(level: L):
|
|
63
|
+
declare function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturnVue<L>;
|
|
144
64
|
/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */
|
|
145
|
-
declare function useForgeApi<L extends string>(level: L, prefix: string):
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* useForgeLevel:声明组件依赖某层级,挂载时自动 forge.load(level),销毁时不主动失效
|
|
149
|
-
* @see .docs/SPEC.md §4.1.7
|
|
150
|
-
*/
|
|
151
|
-
|
|
152
|
-
interface UseForgeLevelReturn {
|
|
153
|
-
loaded: ReturnType<typeof ref<boolean>>;
|
|
154
|
-
error: ReturnType<typeof ref<unknown>>;
|
|
155
|
-
}
|
|
156
|
-
declare function useForgeLevel(level: string): UseForgeLevelReturn;
|
|
65
|
+
declare function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturnVue<L>;
|
|
157
66
|
|
|
158
67
|
/**
|
|
159
|
-
* useForgeRoute
|
|
68
|
+
* useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态
|
|
160
69
|
* @see .docs/SPEC.md §4.1.7
|
|
70
|
+
*
|
|
71
|
+
* - level 未加载时返回空字符串 ''(不抛错,模板不崩)
|
|
72
|
+
* - level 加载完成后自动重新计算并返回正确 URL
|
|
73
|
+
* - 用户无需关心 levelLoaded 状态,直接用即可
|
|
161
74
|
*/
|
|
162
75
|
|
|
163
76
|
declare function useForgeRoute(level: string | (() => string), name: string | (() => string), params?: () => Record<string, unknown>): ComputedRef<string>;
|
|
@@ -177,10 +90,6 @@ declare function useForgeRoute(level: string | (() => string), name: string | ((
|
|
|
177
90
|
* api('test.1') → 歧义:优先 test.test.1,回退 test.1
|
|
178
91
|
*/
|
|
179
92
|
|
|
180
|
-
interface UseForgeByPrefixReturn {
|
|
181
|
-
api: (suffix: string, params?: ApiCallParams) => Promise<unknown>;
|
|
182
|
-
route: (suffix: string, params?: Record<string, unknown>) => string;
|
|
183
|
-
}
|
|
184
93
|
declare function useForgeByPrefix(level: string, prefix: string, separator?: string): UseForgeByPrefixReturn;
|
|
185
94
|
|
|
186
|
-
export { type
|
|
95
|
+
export { type BoundForgeTyped, FORGE_INJECTION_KEY, type RouteForgePluginOptions, type UseForgeApiBoundReturnVue, type UseForgeApiReturnVue, createRouteForgePlugin, useForge, useForgeApi, useForgeByPrefix, useForgeRoute };
|
package/dist/index.js
CHANGED
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
import { inject, ref, onMounted, computed } from 'vue';
|
|
2
|
-
import { createRouteForge,
|
|
3
|
-
|
|
4
|
-
// src/plugin.ts
|
|
5
|
-
async function resolveRouteName(forge, level, prefix, suffix, separator = ".") {
|
|
6
|
-
if (!suffix) return prefix;
|
|
7
|
-
const joined = `${prefix}${separator}${suffix}`;
|
|
8
|
-
if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
|
|
9
|
-
await forge.load(level);
|
|
10
|
-
if (forge.hasRoute(level, joined)) return joined;
|
|
11
|
-
if (forge.hasRoute(level, suffix)) return suffix;
|
|
12
|
-
throw new UnknownRouteError(joined, level);
|
|
13
|
-
}
|
|
14
|
-
function resolveRouteNameSync(forge, level, prefix, suffix, separator = ".") {
|
|
15
|
-
if (!suffix) return prefix;
|
|
16
|
-
const joined = `${prefix}${separator}${suffix}`;
|
|
17
|
-
if (!suffix.startsWith(`${prefix}${separator}`)) return joined;
|
|
18
|
-
if (forge.hasRoute(level, joined)) return joined;
|
|
19
|
-
if (forge.hasRoute(level, suffix)) return suffix;
|
|
20
|
-
throw new UnknownRouteError(joined, level);
|
|
21
|
-
}
|
|
2
|
+
import { createRouteForge, resolveRouteNameSync, resolveRouteName } from '@route-forge/core';
|
|
3
|
+
import { defineImmutableProps } from '@route-forge/core/internal';
|
|
22
4
|
|
|
23
5
|
// src/plugin.ts
|
|
24
6
|
var FORGE_INJECTION_KEY = /* @__PURE__ */ Symbol("route-forge");
|
|
25
7
|
function createRouteForgePlugin(options) {
|
|
26
8
|
const forge = createRouteForge(options);
|
|
27
9
|
return {
|
|
10
|
+
ready: forge.ready,
|
|
28
11
|
install(app) {
|
|
29
12
|
app.provide(FORGE_INJECTION_KEY, forge);
|
|
30
13
|
app.config.globalProperties.$forge = {
|
|
@@ -41,6 +24,15 @@ function useForge(level, prefix) {
|
|
|
41
24
|
);
|
|
42
25
|
}
|
|
43
26
|
if (level !== void 0) {
|
|
27
|
+
const levelLoaded = ref(forge.isLoaded(level));
|
|
28
|
+
forge.load(level).then(() => {
|
|
29
|
+
levelLoaded.value = true;
|
|
30
|
+
}).catch(() => {
|
|
31
|
+
});
|
|
32
|
+
const unsub = forge.onLevelLoaded(level, () => {
|
|
33
|
+
levelLoaded.value = true;
|
|
34
|
+
unsub();
|
|
35
|
+
});
|
|
44
36
|
const callable2 = prefix ? async (name, params) => forge.api(level, await resolveRouteName(forge, level, prefix, name), params) : (name, params) => forge.api(level, name, params);
|
|
45
37
|
defineImmutableProps(callable2, {
|
|
46
38
|
level,
|
|
@@ -55,39 +47,29 @@ function useForge(level, prefix) {
|
|
|
55
47
|
hasRoute: forge.hasRoute.bind(forge),
|
|
56
48
|
isLoading: forge.isLoading.bind(forge),
|
|
57
49
|
onLoadingChange: forge.onLoadingChange.bind(forge),
|
|
58
|
-
getRoutes: forge.getRoutes.bind(forge)
|
|
59
|
-
|
|
50
|
+
getRoutes: forge.getRoutes.bind(forge)
|
|
51
|
+
});
|
|
52
|
+
Object.defineProperty(callable2, "levelLoaded", {
|
|
53
|
+
value: levelLoaded,
|
|
54
|
+
writable: false,
|
|
55
|
+
enumerable: true,
|
|
56
|
+
configurable: false
|
|
60
57
|
});
|
|
61
58
|
return callable2;
|
|
62
59
|
}
|
|
63
60
|
const callable = (lvl, name, params) => forge.api(lvl, name, params);
|
|
64
61
|
defineImmutableProps(callable, {
|
|
65
62
|
api: forge.api.bind(forge),
|
|
66
|
-
route: forge.route.bind(forge),
|
|
67
|
-
url: forge.url.bind(forge),
|
|
68
63
|
load: forge.load.bind(forge),
|
|
69
64
|
invalidate: forge.invalidate.bind(forge),
|
|
70
65
|
isLoaded: forge.isLoaded.bind(forge),
|
|
71
|
-
hasRoute: forge.hasRoute.bind(forge),
|
|
72
66
|
isLoading: forge.isLoading.bind(forge),
|
|
73
67
|
onLoadingChange: forge.onLoadingChange.bind(forge),
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
ready: forge.ready,
|
|
69
|
+
onLevelLoaded: forge.onLevelLoaded.bind(forge)
|
|
76
70
|
});
|
|
77
71
|
return callable;
|
|
78
72
|
}
|
|
79
|
-
function defineImmutableProps(target, props) {
|
|
80
|
-
for (const key of Object.keys(props)) {
|
|
81
|
-
const val = props[key];
|
|
82
|
-
Object.defineProperty(target, key, {
|
|
83
|
-
value: val !== null && typeof val === "object" ? Object.freeze(val) : val,
|
|
84
|
-
writable: false,
|
|
85
|
-
enumerable: false,
|
|
86
|
-
configurable: false
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
return target;
|
|
90
|
-
}
|
|
91
73
|
function useForgeApi(level, prefix) {
|
|
92
74
|
const forge = level !== void 0 ? useForge(level, prefix) : useForge();
|
|
93
75
|
const pending = ref(false);
|
|
@@ -107,41 +89,39 @@ function useForgeApi(level, prefix) {
|
|
|
107
89
|
}
|
|
108
90
|
return { pending, error, call };
|
|
109
91
|
}
|
|
110
|
-
function useForgeLevel(level) {
|
|
111
|
-
const forge = useForge();
|
|
112
|
-
const loaded = ref(false);
|
|
113
|
-
const error = ref(null);
|
|
114
|
-
onMounted(async () => {
|
|
115
|
-
try {
|
|
116
|
-
await forge.load(level);
|
|
117
|
-
loaded.value = true;
|
|
118
|
-
} catch (e) {
|
|
119
|
-
error.value = e;
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
return { loaded, error };
|
|
123
|
-
}
|
|
124
92
|
function useForgeRoute(level, name, params) {
|
|
125
|
-
const forge =
|
|
93
|
+
const forge = inject(FORGE_INJECTION_KEY);
|
|
94
|
+
const levelLoaded = ref(forge.isLoaded(typeof level === "function" ? level() : level));
|
|
95
|
+
const lvl = typeof level === "function" ? level() : level;
|
|
96
|
+
if (!levelLoaded.value) {
|
|
97
|
+
onMounted(() => {
|
|
98
|
+
forge.load(lvl).then(() => {
|
|
99
|
+
levelLoaded.value = true;
|
|
100
|
+
}).catch(() => {
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
126
104
|
return computed(() => {
|
|
127
|
-
|
|
105
|
+
if (!levelLoaded.value) return "";
|
|
106
|
+
const l = typeof level === "function" ? level() : level;
|
|
128
107
|
const n = typeof name === "function" ? name() : name;
|
|
129
108
|
const p = params ? params() : void 0;
|
|
130
|
-
return forge.route(
|
|
109
|
+
return forge.route(l, n, p);
|
|
131
110
|
});
|
|
132
111
|
}
|
|
133
|
-
|
|
134
|
-
// src/composables/useForgeByPrefix.ts
|
|
135
112
|
function useForgeByPrefix(level, prefix, separator = ".") {
|
|
136
|
-
const forge =
|
|
113
|
+
const forge = inject(FORGE_INJECTION_KEY);
|
|
137
114
|
return {
|
|
138
115
|
api: (suffix, params) => resolveRouteName(forge, level, prefix, suffix, separator).then(
|
|
139
116
|
(name) => forge.api(level, name, params)
|
|
140
117
|
),
|
|
141
|
-
route: (suffix, params) =>
|
|
118
|
+
route: (suffix, params) => {
|
|
119
|
+
if (!forge.isLoaded(level)) return "";
|
|
120
|
+
return forge.route(level, resolveRouteNameSync(forge, level, prefix, suffix, separator), params);
|
|
121
|
+
}
|
|
142
122
|
};
|
|
143
123
|
}
|
|
144
124
|
|
|
145
|
-
export { FORGE_INJECTION_KEY, createRouteForgePlugin, useForge, useForgeApi, useForgeByPrefix,
|
|
125
|
+
export { FORGE_INJECTION_KEY, createRouteForgePlugin, useForge, useForgeApi, useForgeByPrefix, useForgeRoute };
|
|
146
126
|
//# sourceMappingURL=index.js.map
|
|
147
127
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/resolveRouteName.ts","../src/plugin.ts","../src/composables/useForgeApi.ts","../src/composables/useForgeLevel.ts","../src/composables/useForgeRoute.ts","../src/composables/useForgeByPrefix.ts"],"names":["callable","ref"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * 智能路由名前缀解析\n *\n * 当前缀与后缀拼接产生歧义时(后缀本身已以前缀开头),\n * 通过查询已加载路由表来判定正确名称:\n * - 优先尝试 prefix + sep + suffix(完整拼接)\n * - 若不存在则回退到 suffix(视为已含前缀)\n * - 均不存在则抛 UnknownRouteError\n *\n * @see .docs/SPEC.md §4.1.7\n */\n\nimport { UnknownRouteError } from '@route-forge/core';\n\n/**\n * 路由名解析所需的最小 forge 接口。\n * 仅依赖 load() 和 hasRoute(),不依赖拦截器等完整能力。\n * 兼容 RouteForge、BoundForgeTyped、ForgeInstanceTyped 等所有形态。\n */\ninterface RouteResolver {\n load(level: string | string[]): Promise<void>;\n\n hasRoute(level: string, name: string): boolean;\n}\n\n/**\n * 异步版本:先确保层级已加载,再做歧义消解。\n * 适用于 api() 调用路径。\n */\nexport async function resolveRouteName(\n forge: RouteResolver,\n level: string,\n prefix: string,\n suffix: string,\n separator = '.',\n): Promise<string> {\n // 后缀为空 → 直接返回前缀\n if (!suffix) return prefix;\n\n const joined = `${prefix}${separator}${suffix}`;\n\n // 后缀不以前缀开头 → 无歧义,直接拼接\n if (!suffix.startsWith(`${prefix}${separator}`)) return joined;\n\n // 歧义场景:先确保层级已加载\n await forge.load(level);\n\n // 优先尝试完整拼接\n if (forge.hasRoute(level, joined)) return joined;\n // 回退到后缀本身(视为已含前缀)\n if (forge.hasRoute(level, suffix)) return suffix;\n\n // 均不存在 → 报错\n throw new UnknownRouteError(joined, level);\n}\n\n/**\n * 同步版本:基于已加载缓存做歧义消解。\n * 适用于 route() / url() 调用路径(要求层级已加载)。\n */\nexport function resolveRouteNameSync(\n forge: RouteResolver,\n level: string,\n prefix: string,\n suffix: string,\n separator = '.',\n): string {\n if (!suffix) return prefix;\n\n const joined = `${prefix}${separator}${suffix}`;\n if (!suffix.startsWith(`${prefix}${separator}`)) return joined;\n\n // 歧义场景:基于已加载缓存判定\n if (forge.hasRoute(level, joined)) return joined;\n if (forge.hasRoute(level, suffix)) return suffix;\n\n throw new UnknownRouteError(joined, level);\n}\n","/**\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 } from 'vue';\nimport { inject, reactive, readonly } from 'vue';\nimport {\n type ApiCallParams,\n createRouteForge,\n type ForgeApiParams,\n type ForgeApiResponse,\n type ForgeRouteName,\n type InterceptorHandler,\n type LoadingChangeCallback,\n type RequestConfig,\n type ResponseData,\n type RouteForge,\n type RouteForgeOptions,\n type RouteMeta,\n} from '@route-forge/core';\nimport { resolveRouteName, resolveRouteNameSync } from './utils/resolveRouteName.js';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** 只读拦截器管理器:仅暴露查询方法,隐藏 use/eject/clear */\ninterface ReadOnlyInterceptorManager<TIn, TOut = TIn> {\n readonly size: number;\n\n forEach(fn: (handler: InterceptorHandler<TIn, TOut>) => void): void;\n}\n\n/**\n * 共享方法集(level 已绑定时的方法签名)\n * .api() / .route() / .url() — name 和 params 根据 ForgeRouteMap 自动推断\n * .load() / .invalidate() / .isLoaded() / .interceptors\n */\nexport interface BoundForgeMethods<L extends string = string> {\n interceptors: {\n request: ReadOnlyInterceptorManager<RequestConfig>;\n response: ReadOnlyInterceptorManager<ResponseData>;\n };\n\n api(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<ForgeApiResponse<L, ForgeRouteName<L>>>;\n\n route(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): string;\n\n url(name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): string;\n\n load(level: string | string[]): Promise<void>;\n\n invalidate(level?: string | string[]): void;\n\n isLoaded(level?: string): boolean;\n\n hasRoute(level: string, name: string): boolean;\n\n /** 查询加载中标识状态 */\n isLoading(): boolean;\n\n /** 订阅加载状态变更,返回取消订阅函数 */\n onLoadingChange(cb: LoadingChangeCallback): () => void;\n\n /** 获取指定层级下全部路由元信息(深拷贝,修改不影响内部缓存) */\n getRoutes(level: string): Record<string, RouteMeta>;\n}\n\n/** 已绑定 level — 直接调用无需 level,api/route/url 的 name 自动限定到该层级 */\nexport interface BoundForgeTyped<L extends string> extends BoundForgeMethods<L> {\n (name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<ForgeApiResponse<L, ForgeRouteName<L>>>;\n /** 当前绑定的 level 值 */\n readonly level: L;\n /** 路由名前缀(仅在 useForge(level, prefix) 传入 prefix 时存在) */\n readonly prefix?: string;\n}\n\n/** 未绑定 level — 直接调用需要传 level */\nexport interface ForgeInstanceTyped extends Omit<BoundForgeMethods<string>, 'api' | 'route' | 'url' | 'hasRoute' | 'getRoutes'> {\n (level: string, name: string, params?: ApiCallParams): Promise<unknown>;\n api(level: string, name: string, params?: ApiCallParams): Promise<unknown>;\n route(level: string, name: string, params?: Record<string, unknown>): string;\n url(level: string, name: string, params?: Record<string, unknown>): string;\n\n hasRoute(level: string, name: string): boolean;\n\n /** 获取全部层级路由(深拷贝);传 level 时仅返回该层级 */\n getRoutes(): Record<string, Record<string, RouteMeta>>;\n getRoutes(level: string): Record<string, RouteMeta>;\n}\n\nexport function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]> {\n const forge = createRouteForge(options);\n\n return {\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 实例。\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('users.show', { user: 1 })\n * forge.api('users.show')\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge.level // → 'admin'\n * forge.prefix // → 'users'\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.api('index') // → forge.api('admin', 'users.index')\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): BoundForgeTyped<L>;\nexport function useForge<L extends string>(level: L): BoundForgeTyped<L>;\nexport function useForge(): ForgeInstanceTyped;\nexport function useForge(level?: string, prefix?: string): ForgeInstanceTyped | BoundForgeTyped<string> {\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 const callable = prefix\n ? async (name: string, params?: ApiCallParams) =>\n forge.api(level, await resolveRouteName(forge, level, prefix, name), params)\n : (name: string, params?: ApiCallParams) =>\n forge.api(level, name, params);\n defineImmutableProps(callable, {\n level,\n // 未传 prefix 时不定义该属性,与 React 包行为保持一致('prefix' in forge === false)\n ...(prefix !== undefined ? { prefix } : {}),\n api: prefix\n ? async (name: string, params?: ApiCallParams) =>\n forge.api(level, await resolveRouteName(forge, level, prefix, name), params)\n : (name: string, params?: ApiCallParams) => forge.api(level, name, params),\n route: prefix\n ? (name: string, params?: Record<string, unknown>) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params)\n : (name: string, params?: Record<string, unknown>) => forge.route(level, name, params),\n url: prefix\n ? (name: string, params?: Record<string, unknown>) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params)\n : (name: string, params?: Record<string, unknown>) => forge.route(level, name, params),\n load: forge.load.bind(forge),\n invalidate: forge.invalidate.bind(forge),\n isLoaded: forge.isLoaded.bind(forge),\n hasRoute: forge.hasRoute.bind(forge),\n isLoading: forge.isLoading.bind(forge),\n onLoadingChange: forge.onLoadingChange.bind(forge),\n getRoutes: forge.getRoutes.bind(forge),\n interceptors: forge.interceptors,\n });\n return callable as unknown as BoundForgeTyped<string>;\n }\n\n const callable = (lvl: string, name: string, params?: ApiCallParams) =>\n forge.api(lvl, name, params);\n defineImmutableProps(callable, {\n api: forge.api.bind(forge),\n route: forge.route.bind(forge),\n url: forge.url.bind(forge),\n load: forge.load.bind(forge),\n invalidate: forge.invalidate.bind(forge),\n isLoaded: forge.isLoaded.bind(forge),\n hasRoute: forge.hasRoute.bind(forge),\n isLoading: forge.isLoading.bind(forge),\n onLoadingChange: forge.onLoadingChange.bind(forge),\n getRoutes: forge.getRoutes.bind(forge),\n interceptors: forge.interceptors,\n });\n return callable as ForgeInstanceTyped;\n}\n\nexport { readonly, reactive };\n\n/**\n * 以不可变、不可枚举、不可重配置的方式将属性挂载到目标对象上。\n * 相比 Object.assign 更安全——外部无法通过遍历/删除/重写篡改这些方法。\n * 对象类型的值会浅冻结(Object.freeze),防止内部键被增删改。\n */\nfunction defineImmutableProps<T extends object>(target: T, props: Record<string, unknown>): T {\n for (const key of Object.keys(props)) {\n const val = props[key];\n Object.defineProperty(target, key, {\n value: val !== null && typeof val === 'object' ? Object.freeze(val) : val,\n writable: false,\n enumerable: false,\n configurable: false,\n });\n }\n return target;\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\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type {\n ApiCallParams,\n ForgeApiParams,\n ForgeApiResponse,\n ForgeRouteName,\n} from '@route-forge/core';\n\n/** call 函数签名 — 未绑定 level,需要显式传入 */\nexport interface UseForgeApiCall {\n (level: string, name: string, params?: ApiCallParams): Promise<{\n data: unknown;\n error: unknown;\n }>;\n}\n\n/** call 函数签名 — 已绑定 level,无需再传 */\nexport interface UseForgeApiBoundCall<L extends string> {\n (name: ForgeRouteName<L>, params?: ForgeApiParams<L, ForgeRouteName<L>>): Promise<{\n data: ForgeApiResponse<L, ForgeRouteName<L>>;\n error: unknown;\n }>;\n}\n\nexport interface UseForgeApiReturn {\n pending: ReturnType<typeof ref<boolean>>;\n error: ReturnType<typeof ref<unknown>>;\n call: UseForgeApiCall;\n}\n\nexport interface UseForgeApiBoundReturn<L extends string> {\n pending: ReturnType<typeof ref<boolean>>;\n error: ReturnType<typeof ref<unknown>>;\n call: UseForgeApiBoundCall<L>;\n}\n\n/** 不绑定层级 — call 需要传 level */\nexport function useForgeApi(): UseForgeApiReturn;\n/** 绑定层级 — call 无需传 level */\nexport function useForgeApi<L extends string>(level: L): UseForgeApiBoundReturn<L>;\n/** 绑定层级 + 前缀 — call 无需传 level,路由名自动拼接 prefix */\nexport function useForgeApi<L extends string>(level: L, prefix: string): UseForgeApiBoundReturn<L>;\nexport function useForgeApi(level?: string, prefix?: string): UseForgeApiReturn | UseForgeApiBoundReturn<string> {\n const forge = level !== undefined ? useForge(level, prefix as string) : useForge();\n const pending = ref(false);\n const error = ref<unknown>(null);\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n pending.value = true;\n error.value = null;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = await (forge as any).api(...args);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n pending.value = false;\n }\n }\n\n return { pending, error, call: call as any };\n}\n","/**\n * useForgeLevel:声明组件依赖某层级,挂载时自动 forge.load(level),销毁时不主动失效\n * @see .docs/SPEC.md §4.1.7\n */\n\nimport { onMounted, ref } from 'vue';\nimport { useForge } from '../plugin.js';\n\nexport interface UseForgeLevelReturn {\n loaded: ReturnType<typeof ref<boolean>>;\n error: ReturnType<typeof ref<unknown>>;\n}\n\nexport function useForgeLevel(level: string): UseForgeLevelReturn {\n const forge = useForge();\n const loaded = ref(false);\n const error = ref<unknown>(null);\n\n onMounted(async () => {\n try {\n await forge.load(level);\n loaded.value = true;\n } catch (e) {\n error.value = e;\n }\n });\n\n return { loaded, error };\n}\n","/**\n * useForgeRoute:仅生成 URL,不发请求(用于 <a href>、外部跳转等)\n * @see .docs/SPEC.md §4.1.7\n */\n\nimport { computed, type ComputedRef } from 'vue';\nimport { useForge } from '../plugin.js';\n\nexport function useForgeRoute(\n level: string | (() => string),\n name: string | (() => string),\n params?: () => Record<string, unknown>,\n): ComputedRef<string> {\n const forge = useForge();\n return computed(() => {\n const lvl = typeof level === 'function' ? level() : level;\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n return forge.route(lvl, n, p);\n });\n}\n","/**\n * useForgeByPrefix:带层级 + 名字前缀的封装,方便后续减少名称传入\n * @see .docs/SPEC.md §4.1.7\n *\n * 智能前缀解析:\n * - 传入后缀不以前缀开头 → 自动拼接 prefix.suffix\n * - 传入后缀已以前缀开头(歧义) → 优先尝试完整拼接,\n * 若不存在则视为已含前缀直接使用,均不存在则报错\n *\n * 示例(prefix = 'test'):\n * api('1') → test.1\n * api('test1.1') → test.test1.1\n * api('test.1') → 歧义:优先 test.test.1,回退 test.1\n */\n\nimport { useForge } from '../plugin.js';\nimport { resolveRouteName, resolveRouteNameSync } from '../utils/resolveRouteName.js';\nimport type { ApiCallParams } from '@route-forge/core';\n\nexport interface UseForgeByPrefixReturn {\n api: (suffix: string, params?: ApiCallParams) => Promise<unknown>;\n route: (suffix: string, params?: Record<string, unknown>) => string;\n}\n\nexport function useForgeByPrefix(level: string, prefix: string, separator = '.'): UseForgeByPrefixReturn {\n const forge = useForge();\n\n return {\n api: (suffix, params) =>\n resolveRouteName(forge, level, prefix, suffix, separator).then(\n (name) => forge.api(level, name, params),\n ),\n route: (suffix, params) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, suffix, separator), params),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/composables/useForgeApi.ts","../src/composables/useForgeRoute.ts","../src/composables/useForgeByPrefix.ts"],"names":["callable","ref","inject","resolveRouteName","resolveRouteNameSync"],"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 createRouteForge,\n type ForgeInstanceTyped,\n type RouteForge,\n type RouteForgeOptions,\n resolveRouteName,\n resolveRouteNameSync,\n} from '@route-forge/core';\nimport { defineImmutableProps } from '@route-forge/core/internal';\n\nexport const FORGE_INJECTION_KEY: InjectionKey<RouteForge> = Symbol('route-forge');\n\nexport interface RouteForgePluginOptions extends RouteForgeOptions {}\n\n/** 已绑定 level — 直接调用无需 level,api/route/url 的 name 自动限定到该层级 */\nexport type BoundForgeTyped<L extends string> = import('@route-forge/core').BoundForgeTyped<L, Ref<boolean>>;\n\n/** 未绑定 level — 直接调用需要传 level(不提供 route/url/hasRoute/getRoutes 等同步方法) */\nexport type { ForgeInstanceTyped } from '@route-forge/core';\n\nexport function createRouteForgePlugin(options: RouteForgePluginOptions): Plugin<[]> & {\n ready: Promise<void>\n} {\n const forge = createRouteForge(options);\n\n return {\n ready: forge.ready,\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 实例。\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('users.show', { user: 1 })\n * forge.api('users.show')\n *\n * @example\n * // 绑定层级 + 前缀 — 路由名自动拼接\n * const forge = useForge('admin', 'users')\n * forge.level // → 'admin'\n * forge.prefix // → 'users'\n * forge('show', { user: 1 }) // → forge.api('admin', 'users.show', ...)\n * forge.api('index') // → forge.api('admin', 'users.index')\n * forge.route('show', { user: 1 }) // → forge.route('admin', 'users.show', ...)\n */\nexport function useForge<L extends string>(level: L, prefix: string): BoundForgeTyped<L>;\nexport function useForge<L extends string>(level: L): BoundForgeTyped<L>;\nexport function useForge(): ForgeInstanceTyped;\nexport function useForge(level?: string, prefix?: string): ForgeInstanceTyped | BoundForgeTyped<string> {\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 // 自动触发 level 加载 + 响应式 levelLoaded 状态\n const levelLoaded = ref(forge.isLoaded(level));\n forge.load(level).then(() => {\n levelLoaded.value = true;\n }).catch(() => { /* 加载失败时 levelLoaded 保持 false */\n });\n // 订阅 level 加载完成事件(兜底:如果 load() 在 ref 赋值后才完成)\n const unsub = forge.onLevelLoaded(level, () => {\n levelLoaded.value = true;\n unsub();\n });\n\n const callable = prefix\n ? async (name: string, params?: ApiCallParams) =>\n forge.api(level, await resolveRouteName(forge, level, prefix, name), params)\n : (name: string, params?: ApiCallParams) =>\n forge.api(level, name, params);\n defineImmutableProps(callable, {\n level,\n // 未传 prefix 时不定义该属性,与 React 包行为保持一致('prefix' in forge === false)\n ...(prefix !== undefined ? { prefix } : {}),\n api: prefix\n ? async (name: string, params?: ApiCallParams) =>\n forge.api(level, await resolveRouteName(forge, level, prefix, name), params)\n : (name: string, params?: ApiCallParams) => forge.api(level, name, params),\n route: prefix\n ? (name: string, params?: Record<string, unknown>) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params)\n : (name: string, params?: Record<string, unknown>) => forge.route(level, name, params),\n url: prefix\n ? (name: string, params?: Record<string, unknown>) =>\n forge.route(level, resolveRouteNameSync(forge, level, prefix, name), params)\n : (name: string, params?: Record<string, unknown>) => forge.route(level, name, params),\n load: forge.load.bind(forge),\n invalidate: forge.invalidate.bind(forge),\n isLoaded: forge.isLoaded.bind(forge),\n hasRoute: forge.hasRoute.bind(forge),\n isLoading: forge.isLoading.bind(forge),\n onLoadingChange: forge.onLoadingChange.bind(forge),\n getRoutes: forge.getRoutes.bind(forge),\n });\n // levelLoaded 需要保持响应式,不能通过 defineImmutableProps(会 Object.freeze)\n Object.defineProperty(callable, 'levelLoaded', {\n value: levelLoaded,\n writable: false,\n enumerable: true,\n configurable: false,\n });\n return callable as unknown as BoundForgeTyped<string>;\n }\n\n const callable = (lvl: string, name: string, params?: ApiCallParams) =>\n forge.api(lvl, name, params);\n defineImmutableProps(callable, {\n api: forge.api.bind(forge),\n load: forge.load.bind(forge),\n invalidate: forge.invalidate.bind(forge),\n isLoaded: forge.isLoaded.bind(forge),\n isLoading: forge.isLoading.bind(forge),\n onLoadingChange: forge.onLoadingChange.bind(forge),\n ready: forge.ready,\n onLevelLoaded: forge.onLevelLoaded.bind(forge),\n });\n return callable as unknown as ForgeInstanceTyped;\n}\n\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\nimport { ref } from 'vue';\nimport { useForge } from '../plugin.js';\nimport type { Ref } from 'vue';\nimport type {\n UseForgeApiCall,\n UseForgeApiBoundCall,\n UseForgeApiReturn,\n UseForgeApiBoundReturn,\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 forge = level !== undefined ? useForge(level, prefix as string) : useForge();\n const pending = ref(false);\n const error = ref<unknown>(null);\n\n async function call(...args: unknown[]): Promise<{ data: unknown; error: unknown }> {\n pending.value = true;\n error.value = null;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = await (forge as any).api(...args);\n return { data, error: null };\n } catch (e) {\n error.value = e;\n return { data: undefined, error: e };\n } finally {\n pending.value = false;\n }\n }\n\n return { pending, error, call: call as any };\n}\n","/**\n * useForgeRoute:响应式 URL 生成器,内部处理 level 加载状态\n * @see .docs/SPEC.md §4.1.7\n *\n * - level 未加载时返回空字符串 ''(不抛错,模板不崩)\n * - level 加载完成后自动重新计算并返回正确 URL\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\nexport function useForgeRoute(\n level: string | (() => string),\n name: string | (() => string),\n params?: () => Record<string, unknown>,\n): ComputedRef<string> {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n\n // 响应式追踪 level 加载状态(computed 依赖此 ref 触发重新计算)\n const levelLoaded = ref(forge.isLoaded(typeof level === 'function' ? level() : level));\n\n const lvl = typeof level === 'function' ? level() : level;\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 const l = typeof level === 'function' ? level() : level;\n const n = typeof name === 'function' ? name() : name;\n const p = params ? params() : undefined;\n return forge.route(l, n, p);\n });\n}\n","/**\n * useForgeByPrefix:带层级 + 名字前缀的封装,方便后续减少名称传入\n * @see .docs/SPEC.md §4.1.7\n *\n * 智能前缀解析:\n * - 传入后缀不以前缀开头 → 自动拼接 prefix.suffix\n * - 传入后缀已以前缀开头(歧义) → 优先尝试完整拼接,\n * 若不存在则视为已含前缀直接使用,均不存在则报错\n *\n * 示例(prefix = 'test'):\n * api('1') → test.1\n * api('test1.1') → test.test1.1\n * api('test.1') → 歧义:优先 test.test.1,回退 test.1\n */\n\nimport { inject } from 'vue';\nimport { FORGE_INJECTION_KEY } from '../plugin.js';\nimport {\n resolveRouteName,\n resolveRouteNameSync,\n type ApiCallParams,\n type RouteForge,\n type UseForgeByPrefixReturn,\n} from '@route-forge/core';\n\nexport type { UseForgeByPrefixReturn };\n\nexport function useForgeByPrefix(level: string, prefix: string, separator = '.'): UseForgeByPrefixReturn {\n const forge = inject(FORGE_INJECTION_KEY) as RouteForge;\n\n return {\n api: (suffix, params) =>\n resolveRouteName(forge, level, prefix, suffix, separator).then(\n (name) => forge.api(level, name, params),\n ),\n route: (suffix, params) => {\n // level 未加载时返回空字符串,避免 resolveRouteNameSync 内部 hasRoute() 抛错\n if (!forge.isLoaded(level)) return '';\n return forge.route(level, resolveRouteNameSync(forge, level, prefix, suffix, separator), params);\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@route-forge/vue",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Route Forge 的 Vue 3 集成:插件 + composable(useForge/useForgeApi/useForgeLevel/useForgeRoute/useForgeByPrefix)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "阿杰很厉害 <506907958@qq.com>",
|
|
7
|
-
"homepage": "https://github.com/
|
|
7
|
+
"homepage": "https://github.com/route-forge/route-forge",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/
|
|
10
|
+
"url": "git+https://github.com/route-forge/route-forge.git",
|
|
11
11
|
"directory": "packages/vue"
|
|
12
12
|
},
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/
|
|
14
|
+
"url": "https://github.com/route-forge/route-forge/issues"
|
|
15
15
|
},
|
|
16
16
|
"type": "module",
|
|
17
17
|
"sideEffects": false,
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"vue": "^3.4.0"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@route-forge/core": "1.
|
|
43
|
+
"@route-forge/core": "1.2.0"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|