all repos — cmd @ be96aa58b12142f4d387b10159e24820a1cee100

Unnamed repository; edit this file 'description' to name the repository.

tests: add tests
vi did:web:vt3e.cat
Sun, 10 May 2026 02:10:19 +0100
commit

be96aa58b12142f4d387b10159e24820a1cee100

parent

941bdd14405d3d888743732037ec5d507a8f2731

2 files changed, 161 insertions(+), 3 deletions(-)

jump to
A tests/index.test.ts

@@ -0,0 +1,161 @@

+import { expect, test, describe } from "bun:test"; +import { Command } from "../src/index"; + +describe("command parser", () => { + test("sets name and description", () => { + const cmd = new Command("test") + .setName("test") + .setDescription("Test command"); + + expect(cmd.name).toBe("test"); + expect(cmd.description).toBe("Test command"); + }); + + test("parses boolean flags", async () => { + let context: any; + const cmd = new Command("test") + .addFlag("verbose", { short: "v", default: false }) + .addFlag("force", { short: "f", default: true }) + .setAction((ctx) => { + context = ctx; + }); + + await cmd.parse([]); + expect(context.verbose).toBe(false); + expect(context.force).toBe(true); + + await cmd.parse(["--verbose", "-f"]); + expect(context.verbose).toBe(true); + expect(context.force).toBe(true); + }); + + test("groups short flags", async () => { + let context: any; + const cmd = new Command("test") + .addFlag("verbose", { short: "v" }) + .addFlag("force", { short: "f" }) + .addStringArgument("config", { short: "c" }) + .setAction((ctx) => { + context = ctx; + }); + + await cmd.parse(["-vfc", "config.json"]); + expect(context.verbose).toBe(true); + expect(context.force).toBe(true); + expect(context.config).toBe("config.json"); + }); + + test("parses string arguments and defaults", async () => { + let context: any; + const cmd = new Command("test") + .addStringArgument("config", { short: "c", default: "default.json" }) + .setAction((ctx) => { + context = ctx; + }); + + await cmd.parse([]); + expect(context.config).toBe("default.json"); + + await cmd.parse(["--config", "config.json"]); + expect(context.config).toBe("config.json"); + + await cmd.parse(["-c", "other.json"]); + expect(context.config).toBe("other.json"); + + await cmd.parse(["--config=inline.json"]); + expect(context.config).toBe("inline.json"); + }); + + test("throws on missing required arguments", async () => { + const cmd = new Command("test").addStringArgument("env", { + required: true, + }); + + expect(cmd.parse([])).rejects.toThrow("Missing required argument: --env"); + }); + + test("parses number arguments and defaults", async () => { + let context: any; + const cmd = new Command("test") + .addNumberArgument("retries", { default: 5 }) + .setAction((ctx) => { + context = ctx; + }); + + await cmd.parse([]); + expect(context.retries).toBe(5); + + await cmd.parse(["--retries", "3"]); + expect(context.retries).toBe(3); + + expect(cmd.parse(["--retries", "abc"])).rejects.toThrow( + "Option --retries must be a valid number", + ); + }); + + test("parses choice arguments and defaults", async () => { + let context: any; + const cmd = new Command("test") + .addChoiceArgument("format", { choices: ["json", "xml"], default: "xml" }) + .setAction((ctx) => { + context = ctx; + }); + + await cmd.parse([]); + expect(context.format).toBe("xml"); + + await cmd.parse(["--format", "json"]); + expect(context.format).toBe("json"); + + expect(cmd.parse(["--format", "csv"])).rejects.toThrow( + "Option --format must be one of: json, xml", + ); + }); + + test("parses positionals", async () => { + let context: any; + const cmd = new Command("test") + .addPositional("source", { required: true }) + .addPositional("dest", { required: false }) + .setAction((ctx) => { + context = ctx; + }); + + await cmd.parse(["src-dir"]); + expect(context.source).toBe("src-dir"); + expect(context.dest).toBeUndefined(); + + await cmd.parse(["src-dir", "dest-dir"]); + expect(context.source).toBe("src-dir"); + expect(context.dest).toBe("dest-dir"); + + expect(cmd.parse([])).rejects.toThrow( + "Missing required positional argument: <source>", + ); + + expect(cmd.parse(["src-dir", "dest-dir", "extra-dir"])).rejects.toThrow( + "Unknown positional argument: extra-dir", + ); + }); + + test("handles subcommands", async () => { + let rootCalled = false; + let subCalled = false; + let subContext: any; + + const sub = new Command("push").addFlag("force").setAction((ctx) => { + subCalled = true; + subContext = ctx; + }); + + const root = new Command("git").addSubcommand(sub).setAction(() => { + rootCalled = true; + }); + + await root.parse(["push", "--force"]); + + expect(rootCalled).toBe(false); + expect(subCalled).toBe(true); + expect(subContext.force).toBe(true); + }); +});
M tsconfig.jsontsconfig.json

@@ -1,9 +1,6 @@

{ "include": ["src"], "compilerOptions": { - "paths": { - "@/*": ["./src/*"], - }, // Environment setup & latest features "lib": ["ESNext"], "target": "ESNext",