fix(cli): show group help
This commit is contained in:
+90
-5
@@ -180,6 +180,18 @@ async function main() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isLocalHelpCommand(parsed.command)) {
|
||||||
|
const result = await dispatch(parsed, null);
|
||||||
|
emitSuccess({
|
||||||
|
summary: result.summary,
|
||||||
|
data: result.local,
|
||||||
|
ctx: null,
|
||||||
|
durationMs: 0,
|
||||||
|
nextCommands: result.nextCommands,
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const ctx = await buildContext(parsed.global);
|
const ctx = await buildContext(parsed.global);
|
||||||
const startedAt = Date.now();
|
const startedAt = Date.now();
|
||||||
const result = await dispatch(parsed, ctx);
|
const result = await dispatch(parsed, ctx);
|
||||||
@@ -194,14 +206,27 @@ async function main() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isLocalHelpCommand(command) {
|
||||||
|
if (command.length === 1 && GROUPS[command[0]]) return true;
|
||||||
|
return command.length > 1 && command.at(-1) === "help";
|
||||||
|
}
|
||||||
|
|
||||||
async function dispatch(parsed, ctx) {
|
async function dispatch(parsed, ctx) {
|
||||||
const [group, ...rest] = parsed.command;
|
const [group, ...rest] = parsed.command;
|
||||||
if (group === "network") {
|
if (group === "network") {
|
||||||
|
if (rest.length === 0 || rest[0] === "help") return helpResult(["network"], NETWORK_COMMANDS);
|
||||||
return commandFromMap(NETWORK_COMMANDS, rest, parsed, ctx);
|
return commandFromMap(NETWORK_COMMANDS, rest, parsed, ctx);
|
||||||
}
|
}
|
||||||
if (group === "component" && rest[0] === "option") {
|
if (group === "component" && rest[0] === "option") {
|
||||||
|
if (rest.length === 1 || rest[1] === "help") return helpResult(["component", "option"], {
|
||||||
|
schema: { summary: "读取选项 schema" },
|
||||||
|
get: { summary: "读取选项属性" },
|
||||||
|
});
|
||||||
return componentOption(rest.slice(1), parsed, ctx);
|
return componentOption(rest.slice(1), parsed, ctx);
|
||||||
}
|
}
|
||||||
|
if (group === "component" && (rest.length === 0 || rest[0] === "help")) {
|
||||||
|
return helpResult(["component"], { option: { summary: GROUPS.component } });
|
||||||
|
}
|
||||||
if (group === "simulation" && rest[0] === "run") {
|
if (group === "simulation" && rest[0] === "run") {
|
||||||
requireOptions(parsed.args, { "start-time": { required: true }, duration: { required: true } });
|
requireOptions(parsed.args, { "start-time": { required: true }, duration: { required: true } });
|
||||||
const start = parseTime(parsed.args["start-time"], "--start-time");
|
const start = parseTime(parsed.args["start-time"], "--start-time");
|
||||||
@@ -218,10 +243,24 @@ async function dispatch(parsed, ctx) {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (group === "simulation" && (rest.length === 0 || rest[0] === "help")) {
|
||||||
|
return helpResult(["simulation"], { run: { summary: "触发指定绝对时间的模拟运行" } });
|
||||||
|
}
|
||||||
if (group === "analysis") {
|
if (group === "analysis") {
|
||||||
|
if (rest.length === 0 || rest[0] === "help") return helpResult(["analysis"], {
|
||||||
|
age: { summary: "执行水龄分析" },
|
||||||
|
leakage: { summary: "漏损分析相关命令" },
|
||||||
|
"burst-detection": { summary: "爆管检测相关命令" },
|
||||||
|
"sensor-placement": { summary: "传感器选址相关命令" },
|
||||||
|
});
|
||||||
return analysis(rest, parsed, ctx);
|
return analysis(rest, parsed, ctx);
|
||||||
}
|
}
|
||||||
if (group === "data") {
|
if (group === "data") {
|
||||||
|
if (rest.length === 0 || rest[0] === "help") return helpResult(["data"], {
|
||||||
|
timeseries: { summary: "时序数据查询命令" },
|
||||||
|
scada: { summary: "SCADA 元数据查询命令" },
|
||||||
|
scheme: { summary: "方案数据查询命令" },
|
||||||
|
});
|
||||||
return dataCommand(rest, parsed, ctx);
|
return dataCommand(rest, parsed, ctx);
|
||||||
}
|
}
|
||||||
throw cliError("未找到命令", "COMMAND_NOT_FOUND", `unknown command: ${parsed.command.join(" ")}`, 2, {
|
throw cliError("未找到命令", "COMMAND_NOT_FOUND", `unknown command: ${parsed.command.join(" ")}`, 2, {
|
||||||
@@ -229,6 +268,19 @@ async function dispatch(parsed, ctx) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function helpResult(command, commands) {
|
||||||
|
return {
|
||||||
|
summary: `命令帮助:${command.join(" ")}`,
|
||||||
|
local: {
|
||||||
|
command: command.join(" "),
|
||||||
|
commands: Object.fromEntries(
|
||||||
|
Object.entries(commands).map(([name, spec]) => [name, spec.summary ?? ""]),
|
||||||
|
),
|
||||||
|
examples: examplesFor(command),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function commandFromMap(map, commandPath, parsed, ctx) {
|
function commandFromMap(map, commandPath, parsed, ctx) {
|
||||||
const name = commandPath[0];
|
const name = commandPath[0];
|
||||||
const spec = map[name];
|
const spec = map[name];
|
||||||
@@ -383,6 +435,9 @@ function dataCommand(rest, parsed, ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function requestJson(ctx, request) {
|
async function requestJson(ctx, request) {
|
||||||
|
if (request.local !== undefined) {
|
||||||
|
return request.local;
|
||||||
|
}
|
||||||
if (request.requireProject) {
|
if (request.requireProject) {
|
||||||
requireProject(ctx);
|
requireProject(ctx);
|
||||||
}
|
}
|
||||||
@@ -557,15 +612,45 @@ function emitSuccess({ summary, data, ctx, durationMs, nextCommands }) {
|
|||||||
schema_version: SCHEMA_VERSION,
|
schema_version: SCHEMA_VERSION,
|
||||||
summary,
|
summary,
|
||||||
data,
|
data,
|
||||||
metadata: {
|
metadata: ctx
|
||||||
server: ctx.server,
|
? {
|
||||||
request_id: ctx.requestId,
|
server: ctx.server,
|
||||||
duration_ms: durationMs,
|
request_id: ctx.requestId,
|
||||||
},
|
duration_ms: durationMs,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
next_commands: nextCommands,
|
next_commands: nextCommands,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function examplesFor(command) {
|
||||||
|
const key = command.join(" ");
|
||||||
|
const examples = {
|
||||||
|
network: [
|
||||||
|
"tjwater-cli network get-all-pipes-properties",
|
||||||
|
"tjwater-cli network get-pipe-properties --pipe P1",
|
||||||
|
],
|
||||||
|
component: ["tjwater-cli component option help"],
|
||||||
|
"component option": [
|
||||||
|
"tjwater-cli component option schema --kind time",
|
||||||
|
"tjwater-cli component option get --kind network",
|
||||||
|
],
|
||||||
|
simulation: [
|
||||||
|
"tjwater-cli simulation run --start-time 2025-01-01T00:00:00+08:00 --duration 30",
|
||||||
|
],
|
||||||
|
analysis: [
|
||||||
|
"tjwater-cli analysis age --start-time 2025-01-01T00:00:00+08:00 --duration 900",
|
||||||
|
"tjwater-cli analysis leakage schemes list",
|
||||||
|
],
|
||||||
|
data: [
|
||||||
|
"tjwater-cli data timeseries realtime links --start-time 2025-01-01T00:00:00+08:00 --end-time 2025-01-01T01:00:00+08:00",
|
||||||
|
"tjwater-cli data scada list",
|
||||||
|
"tjwater-cli data scheme list",
|
||||||
|
],
|
||||||
|
};
|
||||||
|
return examples[key] ?? ["tjwater-cli help"];
|
||||||
|
}
|
||||||
|
|
||||||
function emitFailure(error) {
|
function emitFailure(error) {
|
||||||
const payload = {
|
const payload = {
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user