Middleware

This is a simple example that demonstrates how to register middleware that run before the command handler. Middleware can do a lot of things. Almost everything that middleware can do could be done at the beginning of the handler function, but middleware keeps the handler clean and focused on the command's behavior as well as being much more composable.

Some things middleware can do:

  • Modify the arguments object
  • Perform validation that takes multiple arguments into account
  • Perform side effects

All Example Files

FILE EXPLORER
middleware.ts
1import cliForge from 'cli-forge';
2
3const cli = cliForge('basic-cli')
4  // Requires a command to be provided
5  .demandCommand()
6
7  // Middleware registered on parent commands will be invoked before the child command's middleware
8  .middleware(() => {
9    console.log('ABOUT TO RUN A COMMAND');
10  })
11
12  // Registers "hello" command
13  .command('hello', {
14    // Builder is used to define the command's options
15    builder: (args) =>
16      args
17        .option('name', {
18          type: 'string',
19          description: 'The name to say hello to',
20          default: 'World',
21        })
22        // Middleware can mutate the args object
23        .middleware((args) => {
24          args.name = args.name.toUpperCase();
25        })
26        // Middleware can add new properties to the args object
27        .middleware((args) => {
28          return {
29            ...args,
30            env: process.env.NODE_ENV || 'development',
31          };
32        })
33        // Multiple middleware can be registered
34        .middleware(() => {
35          console.log('HELLO MIDDLEWARE');
36        }),
37    // Handler is used to define the command's behavior
38    handler: (args) => {
39      console.log(`Hello, ${args.name}! [${args.env.toUpperCase()}]`);
40    },
41  });
42
43// We export the CLI for a few reasons:
44// - Testing
45// - Composition (a CLI can be a subcommand of another CLI)
46// - Docs generation
47export default cli;
48
49// Calling `.forge()` executes the CLI. It's single parameter is the CLI args
50// and they default to `process.argv.slice(2)`.
51if (require.main === module) {
52  (async () => {
53    await cli.forge();
54  })();
55}
56