feat: CLI 错误输出格式化

This commit is contained in:
2026-06-08 22:31:43 +08:00
parent dab63975f5
commit 50456188a0
2 changed files with 69 additions and 0 deletions

20
src/cli/output.ts Normal file
View File

@@ -0,0 +1,20 @@
import { CliError } from "./errors.ts";
export function formatError(error: CliError): string {
const parts: string[] = [`错误: ${error.message}`];
if (error.usage) {
parts.push(`用法: ${error.usage}`);
}
if (error.hint) {
parts.push(`提示: ${error.hint}`);
}
return parts.join("\n\n");
}
export function printError(error: CliError): never {
process.stderr.write(formatError(error) + "\n");
process.exit(1);
}

49
tests/cli/output.test.ts Normal file
View File

@@ -0,0 +1,49 @@
import { describe, it, expect } from "bun:test";
import { formatError } from "../../src/cli/output.ts";
import {
UsageError,
ConfigError,
CommandError,
InternalError,
} from "../../src/cli/errors.ts";
describe("formatError", () => {
it("只输出错误行(无 hint/usage", () => {
const err = new ConfigError("未初始化");
const output = formatError(err);
expect(output).toBe("错误: 未初始化");
});
it("输出错误行 + 提示行", () => {
const err = new ConfigError("未初始化", { hint: "请先运行 rune init" });
const output = formatError(err);
expect(output).toBe("错误: 未初始化\n\n提示: 请先运行 rune init");
});
it("输出错误行 + 用法行", () => {
const err = new UsageError("缺少参数", {
usage: "rune plan <change-name>",
});
const output = formatError(err);
expect(output).toBe(
"错误: 缺少参数\n\n用法: rune plan <change-name>",
);
});
it("输出完整格式(错误 + 用法 + 提示)", () => {
const err = new UsageError("缺少必填参数 <change-name>", {
usage: "rune plan <change-name>",
hint: "请指定变更名称,如 \"add-login\"",
});
const output = formatError(err);
expect(output).toBe(
'错误: 缺少必填参数 <change-name>\n\n用法: rune plan <change-name>\n\n提示: 请指定变更名称,如 "add-login"',
);
});
it("InternalError 输出固定消息", () => {
const err = new InternalError();
const output = formatError(err);
expect(output).toBe("错误: 发生了未预期的错误");
});
});