Skip to content

Advanced CLI-John Usage

Learn advanced command routing, event handling, and complex CLI application patterns.

Command Hierarchies

Build nested commands:

ts
import { CLI } from "@briklab/lib/cli-john";
import * as process from "node:process";

const cli = new CLI(process);

// Main command
cli.command("config").on("command", ({ commandArgs }) => {
  const subCommand = commandArgs[0];

  if (subCommand === "get") {
    console.log("Getting config...");
  } else if (subCommand === "set") {
    console.log(`Setting config to ${commandArgs[1]}`);
  } else if (subCommand === "list") {
    console.log("Listing configs");
  }
});

cli.run();

Multiple Command Handlers

Attach multiple command handlers to compose behavior:

ts
import { CLI } from "@briklab/lib/cli-john";
import * as process from "node:process";

const cli = new CLI(process);

cli.command("deploy")
  .on("command", ({ commandArgs }) => {
    console.log(`Deploying to ${commandArgs[0] || "production"}`);
  })
  .on("command", () => {
    console.log("Deployment command received");
  });

cli.run();

Live Demo - CLI Usage

Console
No logs yet.

Argument Parsing

Extract and validate arguments:

ts
import { CLI } from "@briklab/lib/cli-john";
import * as process from "node:process";

const cli = new CLI(process);

cli.command("user").on("command", ({ commandArgs }) => {
  const command = commandArgs[0];
  const name = commandArgs[1];
  const email = commandArgs[2];

  if (command === "create") {
    console.log(`Creating user: ${name} (${email})`);
  } else if (command === "update") {
    console.log(`Updating user: ${name}`);
  } else if (command === "delete") {
    console.log(`Deleting user: ${name}`);
  }
});

cli.run();

Command Registry

Organize commands in a registry:

ts
import { CLI } from "@briklab/lib/cli-john";
import * as process from "node:process";

class CommandRegistry {
  private cli: CLI;
  private commands: Map<string, () => void> = new Map();

  constructor(cli: CLI) {
    this.cli = cli;
  }

  register(name: string, handler: () => void): void {
    this.commands.set(name, handler);
    this.cli.command(name).on("command", handler);
  }

  listCommands(): void {
    console.log("Available commands:");
    this.commands.forEach((_, name) => {
      console.log(`  ${name}`);
    });
  }
}

const cli = new CLI(process);
const registry = new CommandRegistry(cli);

registry.register("start", () => console.log("Starting..."));
registry.register("stop", () => console.log("Stopping..."));
registry.register("status", () => console.log("Status OK"));

cli.run();

Fallback Handling

Handle unknown or missing subcommands inside a command handler:

ts
import { CLI } from "@briklab/lib/cli-john";
import * as process from "node:process";

const cli = new CLI(process);

cli.command("help").on("command", () => {
  console.log("Available commands:");
  console.log("  start   - Start the application");
  console.log("  stop    - Stop the application");
  console.log("  status  - Show status");
  console.log("  help    - Show this message");
});

cli.command("app").on("command", ({ commandArgs }) => {
  const subcommand = commandArgs[0];

  if (subcommand === "start") {
    console.log("Starting the application");
    return;
  }

  if (subcommand === "stop") {
    console.log("Stopping the application");
    return;
  }

  if (subcommand === "status") {
    console.log("Application status: running");
    return;
  }

  console.error(`Unknown subcommand: ${subcommand || "(none)"}`);
  console.error("Run `app help` for usage.");
});

cli.run();

Next Steps