feat: CLI 错误类层次
This commit is contained in:
26
src/cli/errors.ts
Normal file
26
src/cli/errors.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
export class CliError extends Error {
|
||||
readonly hint?: string;
|
||||
readonly usage?: string;
|
||||
|
||||
constructor(
|
||||
message: string,
|
||||
opts?: { hint?: string; usage?: string },
|
||||
) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
this.hint = opts?.hint;
|
||||
this.usage = opts?.usage;
|
||||
}
|
||||
}
|
||||
|
||||
export class UsageError extends CliError {}
|
||||
|
||||
export class ConfigError extends CliError {}
|
||||
|
||||
export class CommandError extends CliError {}
|
||||
|
||||
export class InternalError extends CliError {
|
||||
constructor() {
|
||||
super("发生了未预期的错误");
|
||||
}
|
||||
}
|
||||
55
tests/cli/errors.test.ts
Normal file
55
tests/cli/errors.test.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { describe, it, expect } from "bun:test";
|
||||
import {
|
||||
CliError,
|
||||
UsageError,
|
||||
ConfigError,
|
||||
CommandError,
|
||||
InternalError,
|
||||
} from "../../src/cli/errors.ts";
|
||||
|
||||
describe("CliError 类层次", () => {
|
||||
it("UsageError 携带 message 和可选 hint", () => {
|
||||
const err = new UsageError("缺少参数", { hint: "请提供参数" });
|
||||
expect(err).toBeInstanceOf(CliError);
|
||||
expect(err).toBeInstanceOf(UsageError);
|
||||
expect(err.message).toBe("缺少参数");
|
||||
expect(err.hint).toBe("请提供参数");
|
||||
expect(err.usage).toBeUndefined();
|
||||
});
|
||||
|
||||
it("UsageError 携带 message、hint、usage", () => {
|
||||
const err = new UsageError("缺少参数", {
|
||||
hint: "请提供参数",
|
||||
usage: "rune plan <change-name>",
|
||||
});
|
||||
expect(err.usage).toBe("rune plan <change-name>");
|
||||
});
|
||||
|
||||
it("ConfigError 只带 message", () => {
|
||||
const err = new ConfigError("未初始化");
|
||||
expect(err).toBeInstanceOf(CliError);
|
||||
expect(err).toBeInstanceOf(ConfigError);
|
||||
expect(err.message).toBe("未初始化");
|
||||
expect(err.hint).toBeUndefined();
|
||||
});
|
||||
|
||||
it("CommandError 带 message 和 hint", () => {
|
||||
const err = new CommandError("变更不存在", { hint: "请先运行 rune plan" });
|
||||
expect(err).toBeInstanceOf(CliError);
|
||||
expect(err.message).toBe("变更不存在");
|
||||
expect(err.hint).toBe("请先运行 rune plan");
|
||||
});
|
||||
|
||||
it("InternalError 用默认 message", () => {
|
||||
const err = new InternalError();
|
||||
expect(err).toBeInstanceOf(CliError);
|
||||
expect(err.message).toBe("发生了未预期的错误");
|
||||
});
|
||||
|
||||
it("可以用 name 区分错误类型", () => {
|
||||
expect(new UsageError("a").name).toBe("UsageError");
|
||||
expect(new ConfigError("b").name).toBe("ConfigError");
|
||||
expect(new CommandError("c").name).toBe("CommandError");
|
||||
expect(new InternalError().name).toBe("InternalError");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user