Build deeply nested, self-documenting CLI applications dynamically and declaratively.
Install
Usage
Simple example
import { buildCli, describe, withFlags } from '@saeon/cli-tools' /** * Specify a function that takes a single object * as a parameter. You can assume the keys of * this object parameter if you use the 'withFlags' * function (see below) * * Functions can be async */ const fn = async args => { await new Promise(res => setTimeout(res, 1000)) console.log(args) } /** * Specify what flags that function should be passed * * keys with values that are other keys are treated as * aliases (aliases can ONLY be single letters) */ const fnWithFlags = withFlags(fn, { 'arg-a': String, 'arg-b': Number, a: 'arg-a', b: 'arg-b', }) /** * Describe the function * * This is used to output helpful * CLI documentation */ describe(fnWithFlags, { title: 'Some title', description: 'Some description', }) // Build a simple CLI const cli = args => buildCli( { fn1: () => console.log('fn1 called'), fn2: async () => { await new Promise(res => setTimeout(res, 1000)) console.log('fn2 called') }, 'fn-with-flags': fnWithFlags, }, args ) cli(process.argv.slice(2))
Complete (nested) example
import { buildCli, describe, withFlags } from '@saeon/cli-tools' const cli = args => buildCli( describe( { 'simple-function': () => console.log('Run a simple function with no args'), 'simple-described-function': describe( () => console.log('This function has a helpful description in the help output'), { title: 'A described function', description: 'You can add descriptions to cmds and/or functions using describe()', } ), 'simple-function-with-args': withFlags( ({ name }) => { if (!name) { console.log('Specify the name flag! (--name or -n)') return } console.log('Function calld with name', name) }, { name: String, n: 'name', } ), 'simple-described-function-with-args': describe( withFlags( async ({ name }) => { if (!name) { console.log('Specify the name flag! (--name or -n)') return } console.log('Function calld with name', name) }, { name: String, n: 'name', } ), { title: 'Described, async function with args', description: 'A described, async function that accepts args. Defined declaratively!', } ), 'sub-cmd': describe( { 'simple-function': async () => { await new Promise(res => setTimeout(res, 1000)) console.log('Simple async function of sub-cmd with no args') }, 'sub-sub-cmd': describe( { 'async-fn-with-flags': describe( withFlags( async ({ duration }) => { if (!duration) { console.log('Specify the duration flag (--duration or -d)') return } await new Promise(res => setTimeout(res, duration * 1000)) console.log(`Well done for waiting ${duration} seconds`) }, { duration: Number, d: 'duration' } ), { title: 'Another function', description: 'This one is quite deeply nested', } ), }, { title: 'Sub-sub command', description: 'Build deeply nested CLIs like this', } ), }, { title: 'Sub command', description: 'Example of nested sub-command. Sub cmds and fns are hidden from top level output', } ), }, { title: 'CLI Example', description: 'The CLI, cmds, and functions are all described the same way', } ), args ) cli(process.argv.slice(2))
Output example
Running the nested example above, this is the output
$ sdp
CLI (@saeon/cli-tools v0.2.0): CLI Example
Unknown command ""
Commands
simple-function [Fn []] No description
simple-described-function [Fn []] You can add descriptions to cmds and/or functions using describe()
simple-function-with-args [Fn [name]] No description
simple-described-function-with-args [Fn [name]] A described, async function that accepts args. Defined declaratively!
sub-cmd [Cmd] Example of nested sub-command. Sub cmds and fns are hidden from top level output$ sdp sub-cmd
CLI (@saeon/cli-tools v0.2.0): Sub command
Unknown command ""
Commands
simple-function [Fn []] No description
sub-sub-cmd [Cmd] Build deeply nested CLIs like this$ sdp sub-cmd sub-sub-cmd
CLI (@saeon/cli-tools v0.2.0): Sub-sub command
Unknown command ""
Commands
async-fn-with-flags [Fn [duration]] This one is quite deeply nestedLocal development
From the repository root
# Install dependencies npm install # This registers the 'cli' command on your $PATH source env.sh # Run the CLI sdp
Publishing to NPM
Run chomp publish:<semver> (refer to chompfile.toml for the command names for path, minor, and major version pushes)