@kevisual/router 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +1 -1
- package/dist/commander.js +13750 -142
- package/package.json +1 -1
- package/src/commander.ts +95 -19
package/package.json
CHANGED
package/src/commander.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, program } from 'commander';
|
|
2
|
-
import { App
|
|
2
|
+
import { App } from './app.ts';
|
|
3
3
|
import { RemoteApp } from '@kevisual/remote-app'
|
|
4
|
+
import z from 'zod';
|
|
4
5
|
export const groupByPath = (routes: App['routes']) => {
|
|
5
6
|
return routes.reduce((acc, route) => {
|
|
6
7
|
const path = route.path || 'default';
|
|
@@ -135,25 +136,8 @@ export const parse = async (opts: {
|
|
|
135
136
|
_program.version(version);
|
|
136
137
|
}
|
|
137
138
|
app.createRouteList();
|
|
138
|
-
app.route({
|
|
139
|
-
path: 'cli',
|
|
140
|
-
key: 'list'
|
|
141
|
-
}).define(async () => {
|
|
142
|
-
const routes = app.routes.map(route => {
|
|
143
|
-
return {
|
|
144
|
-
path: route.path,
|
|
145
|
-
key: route.key,
|
|
146
|
-
description: route?.metadata?.summary || route.description || '',
|
|
147
|
-
};
|
|
148
|
-
});
|
|
149
|
-
// 输出为表格格式
|
|
150
|
-
const table = routes.map(route => {
|
|
151
|
-
return `${route.path} ${route.key} - ${route.description}`;
|
|
152
|
-
}).join('\n');
|
|
153
|
-
|
|
154
|
-
console.log(table);
|
|
155
|
-
}).addTo(app, { overwrite: false })
|
|
156
139
|
|
|
140
|
+
createCliList(app);
|
|
157
141
|
createCommand({ app: app as App, program: _program });
|
|
158
142
|
|
|
159
143
|
if (opts.remote) {
|
|
@@ -176,4 +160,96 @@ export const parse = async (opts: {
|
|
|
176
160
|
process.exit(0);
|
|
177
161
|
}
|
|
178
162
|
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const createCliList = (app: App) => {
|
|
166
|
+
app.route({
|
|
167
|
+
path: 'cli',
|
|
168
|
+
key: 'list',
|
|
169
|
+
description: '列出所有可用的命令',
|
|
170
|
+
metadata: {
|
|
171
|
+
summary: '列出所有可用的命令',
|
|
172
|
+
args: {
|
|
173
|
+
q: z.string().optional().describe('查询关键词,支持模糊匹配命令'),
|
|
174
|
+
path: z.string().optional().describe('按路径前缀过滤,如 user、admin'),
|
|
175
|
+
tags: z.string().optional().describe('按标签过滤,多个标签用逗号分隔'),
|
|
176
|
+
sort: z.enum(['key', 'path', 'name']).optional().describe('排序方式'),
|
|
177
|
+
limit: z.number().optional().describe('限制返回数量'),
|
|
178
|
+
offset: z.number().optional().describe('偏移量,用于分页'),
|
|
179
|
+
format: z.enum(['table', 'simple', 'json']).optional().describe('输出格式'),
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}).define(async (ctx) => {
|
|
183
|
+
const { q, path: pathFilter, tags, sort, limit, offset, format } = ctx.query as any;
|
|
184
|
+
let routes = app.routes.map(route => {
|
|
185
|
+
return {
|
|
186
|
+
path: route.path,
|
|
187
|
+
key: route.key,
|
|
188
|
+
description: route?.metadata?.summary || route.description || '',
|
|
189
|
+
tags: route?.metadata?.tags || [],
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// 路径过滤
|
|
194
|
+
if (pathFilter) {
|
|
195
|
+
routes = routes.filter(route => route.path.startsWith(pathFilter));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 标签过滤
|
|
199
|
+
if (tags) {
|
|
200
|
+
const tagList = tags.split(',').map((t: string) => t.trim().toLowerCase()).filter(Boolean);
|
|
201
|
+
if (tagList.length > 0) {
|
|
202
|
+
routes = routes.filter(route => {
|
|
203
|
+
const routeTags = Array.isArray(route.tags) ? route.tags.map((t: unknown) => String(t).toLowerCase()) : [];
|
|
204
|
+
return tagList.some((tag: string) => routeTags.includes(tag));
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// 关键词过滤
|
|
210
|
+
if (q) {
|
|
211
|
+
const keyword = q.toLowerCase();
|
|
212
|
+
routes = routes.filter(route => {
|
|
213
|
+
return route.path.toLowerCase().includes(keyword) ||
|
|
214
|
+
route.key.toLowerCase().includes(keyword) ||
|
|
215
|
+
route.description.toLowerCase().includes(keyword);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 排序
|
|
220
|
+
if (sort) {
|
|
221
|
+
routes.sort((a, b) => {
|
|
222
|
+
if (sort === 'path') return a.path.localeCompare(b.path);
|
|
223
|
+
if (sort === 'key') return a.key.localeCompare(b.key);
|
|
224
|
+
return a.key.localeCompare(b.key); // name 默认为 key
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 分页
|
|
229
|
+
const total = routes.length;
|
|
230
|
+
const start = offset || 0;
|
|
231
|
+
const end = limit ? start + limit : undefined;
|
|
232
|
+
routes = routes.slice(start, end);
|
|
233
|
+
|
|
234
|
+
// 输出
|
|
235
|
+
const outputFormat = format || 'table';
|
|
236
|
+
if (outputFormat === 'json') {
|
|
237
|
+
console.log(JSON.stringify({ total, offset: start, limit, routes }, null, 2));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (outputFormat === 'simple') {
|
|
242
|
+
routes.forEach(route => {
|
|
243
|
+
console.log(`${route.path} ${route.key}`);
|
|
244
|
+
});
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// table 格式
|
|
249
|
+
const table = routes.map(route => {
|
|
250
|
+
return `${route.path} ${route.key} - ${route.description}`;
|
|
251
|
+
}).join('\n');
|
|
252
|
+
|
|
253
|
+
console.log(table);
|
|
254
|
+
}).addTo(app, { overwrite: false })
|
|
179
255
|
}
|