Composable Options
Extract common options into reusable functions and compose them across
multiple commands. Shows two approaches: manual generics and the
makeComposableBuilder helper.
Also demonstrates accessing child commands programmatically via
getChildren() and invoking their handlers with full type inference.
1 FILESTry in Playground
All Example Files
FILE EXPLORER
composable-options.ts
1import { UnknownCLI, chain, cli, makeComposableBuilder } from 'cli-forge';
2
3// -- Reusable option definitions --
4
5// Manual generic approach (uses UnknownCLI as the constraint)
6function withName<T extends UnknownCLI>(argv: T) {
7 return argv.option('name', {
8 type: 'string',
9 description: 'Your name',
10 required: true,
11 });
12}
13
14const withGreeting = makeComposableBuilder((args) =>
15 args.option('greeting', {
16 type: 'string',
17 description: 'The greeting to use',
18 default: 'Hello',
19 })
20);
21
22const withFarewell = makeComposableBuilder((args) =>
23 args.option('farewell', {
24 type: 'string',
25 description: 'The farewell to use',
26 default: 'Goodbye',
27 })
28);
29
30// -- Commands with return values --
31
32const withGreetCommand = makeComposableBuilder((args) =>
33 args.command('greet', {
34 builder: (args) => chain(args, withName, withGreeting),
35 handler: (args): string => {
36 const message = `${args.greeting}, ${args.name}!`;
37 console.log(message);
38 return message;
39 },
40 })
41);
42
43const withFarewellCommand = makeComposableBuilder((args) =>
44 args.command('farewell', {
45 builder: (args) => chain(args, withName, withFarewell),
46 handler: (args): string => {
47 const message = `${args.farewell}, ${args.name}!`;
48 console.log(message);
49 return message;
50 },
51 })
52);
53
54const withConverseCommand = makeComposableBuilder((args) =>
55 args.command('converse', {
56 description: 'A quick chat',
57 builder: (args) => chain(args, withName),
58 handler: (args) => {
59 console.log(`[${args.name}]: hello!`);
60 },
61 })
62);
63
64// -- Parent command accessing children --
65
66cli('composable-options', {
67 builder: (args) =>
68 chain(args, withGreetCommand, withFarewellCommand, withConverseCommand),
69
70 handler: async (_args, ctx) => {
71 const children = ctx.command.getChildren();
72
73 // Handlers are typed - greetHandler returns string
74 const greetHandler = children.greet.getHandler();
75 if (greetHandler) {
76 const result = greetHandler({ name: 'Alice', greeting: 'Hi' });
77 console.log('Greeting ends with !:', result.endsWith('!'));
78 }
79
80 console.log('Available commands:', Object.keys(children).join(', '));
81 },
82}).forge();
83