Repository navigation
How to create a CLI with subcommands? #558
Replies: 1 comment
|
A small dispatcher can use Node to select a known script, then invoke zx's CLI with the remaining arguments. Put this beside #!/usr/bin/env node
import { spawn } from 'node:child_process';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
const require = createRequire(import.meta.url);
const commands = new Map([
['foo', new URL('./foo.mjs', import.meta.url)],
['bar', new URL('./bar.mjs', import.meta.url)],
]);
const [command, ...args] = process.argv.slice(2);
if (!command || command === '--help') {
console.log('Usage: topic <foo|bar> [arguments...]');
} else if (!commands.has(command)) {
console.error(`Unknown command: ${command}`);
process.exitCode = 1;
} else {
const child = spawn(process.execPath, [
require.resolve('zx/cli'),
fileURLToPath(commands.get(command)),
...args,
], { stdio: 'inherit' });
child.on('error', error => {
console.error(error.message);
process.exitCode = 1;
});
child.on('exit', code => { process.exitCode = code ?? 1; });
}Then run I tested help, an unknown command, both subcommands, a forwarded argument containing spaces, and a child exit code with zx 8.8.4 / Node 24.19.0. For sharing, commit this directory plus |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hi,
I have developed a bunch of scripts that sits in local folders on my machine:
For now I always use them as
~/bin/generic.mjsor~/bin/topic/foo.mjs.I wanted to know what would be the recommended way to group everything related to a specific topic under a single CLI entrypoint, so that I could do something like:
Are there any examples of such patterns? Is it something that
zxwants to solve, or isn't it in its scope?Bonus: how could I then share these scripts with my coworkers? (i.e: have a shared Git repo we could pull and add to our path)
All reactions