feat: CLI 错误输出格式化
This commit is contained in:
20
src/cli/output.ts
Normal file
20
src/cli/output.ts
Normal 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
49
tests/cli/output.test.ts
Normal 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("错误: 发生了未预期的错误");
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user