@magic/cli

@magic/cli

declarative cli sanitization and execution for @magic

sanitizes cli flags from aliases to default names rewrites process.argv accordingly provides autogenerated --help output (that can be customized) also handles commands and environment for you

exports a commonjs file that allows to launch mjs files as clis

install

be in a nodejs project

npm i --save-dev @magic/cli

caveats

there are some quirks that need some careful consideration when designing a cli api.

depending on your requirements, these caveats may or may not apply.

  • last argument

    if your last argument does not have a corresponding flag, it will still be assigned to the last flag prior to it.

    workaround

    do not design a cli with a trailing command.

  • option argument and command name clash

    if one of your options gets an argument that is equal to a command, this command will be executed.

    workaround

    do not name your commands like the possible arguments.

  • flag arguments can not start with a dash

    cli arguments that start with a - will always be treated as flags, not values.

    workaround

    do not design a cli that accepts arguments that start with a -

those issues might get addressed in the future.

Usage

full api example

#!/usr/bin/env nodeimport cli from '@magic/cli/src/index.mjs''const { argv, env, commands } = cli({  commands: [    ['cmd1', 'cmd1alias'],    'cmd2',  ],  options: [    ['--flag1', '-f1'],    ['--flag2', '-f2'],  ],  default: {    '--default-key': 'default-value',  },  single: [    '--default-key',  ],  required: [    '--default-key',  ],  pure: true, // do neither change process.argv nor process.env  pureArgv: true, // do not change process.argv  pureEnv: true, // do not change process.env})

options / argv

argv mappings will handle options and option aliases

using the cli file above

then, in your terminal / bash

bin.mjs -f1 arg1 arg2 -f2

resulting process.argv

process.argv = [  '/path/to/bin/node',  '/path/to/bin.mjs',  '--flag1'  'arg1',  'arg2',  '--flag2',]

returned javascript object

argv === { '--flag1': ['arg1', arg2], '--flag2': []}

commands

cli commands can be handled too.

import cli from '@magic/cli/src/index.mjs'const args = {  commands: [    ['dev', 'development', 'start'],    'serve',  ],}const argv = cli(args)// call./bin.mjs dev serve// results:{  cmds: ['dev', 'serve'],  commands: ['dev', 'serve'],}

help output

@magic/cli will derive a help text from your configuration.

help itself can be configured to provide better error messages.

simple help message

import cli from '@magic/cli/src/index.mjs'const args = {  commands: [['magic', 'm']],  options: [['--spell', '-s']],  prepend: 'prepend',  append: 'append',  help: 'custom help text',}const argv = cli(args)// running./bin.mjs// without arguments// help output@magic/cli wrapped cli.custom help textcli commandsmagic - aliases: ["m"]possible command line flags:--spell - aliases: ["-s"]environment switches:dev: set NODE_ENV to development - aliases ["development"]

detailed help message

the help property will accept an object which maps to the args object.

import cli from '@magic/cli/src/index.mjs'const args = {  commands: [['magic', 'm']],  options: [['--spell', '-s']],  prepend: 'prepend',  append: 'append',  help: {    name: 'cli name',    text: 'custom help text',    commands: {      magic: 'magic info help text',    },    options: {      '--spell': 'cast a simple spell',    },    env: ['dev', 'set environment to development'],  },}const argv = cli(args)// running./bin.mjs// without arguments// help outputcli namecustom help textcommands:magic - aliases: ["m"]flags:--spell - aliases: ["-s"]environment switches:dev: set process.NODE_ENV to development - aliases ["development"]

clean

some cli arguments will be expected to return a string instead of a list of arguments.

this can be achieved using the single array

const args = {  options: [['--single', '-s']],  single: ['--single'],}const res = cli(args)console.log(res)

required

some cli arguments will be required.

this can be achieved using the required array.

if a required field is missing, a error message and the help will be shown.

const args = {  options: [['--required', '-r']],  required: ['--required'],}const res = cli(args)console.log(res)

config

there are some configuration parameters that can be passed to the cli function

pure

const args = {  pure: false,    // set to true to prevent changes to process.argv and process.env  pureEnv: false, // set to true to prevent changes to process.env  pureArgv: false, // set to true to prevent changes to process.argv}cli(args)

prepend/append

process.argv values can be prepended and appended

import cli from '@magic/cli/src/index.mjs'const args = {  prepend: ['prepended']  append: ['appended']}cli(args)

default

use this to set default process.argv key: value pairs that should be set if they are not

import cli from '@magic/cli/src/index.mjs'const args = {  options: [    ['--default-key'],  ],  default: {    '--default-key': 'default-value',  },}const argv = cli(args)// returns{  argv: {    '--default-key': 'default-value',  },}

helpers

@magic/cli exports multiple promisified child_process commands.

exec
import cli from '@magic/cli'const execOptions = {  // any child_process.exec options}const {  err,  stderr,  stdout} = await cli.exec('cmd --flag Flag', execOptions)
execFile
const execFileOptions = {  // any child_process.execFile options}const {  err,  stderr,  stdout,} = await cli.execFile('/path/to/file.x', ['--flag', 'Flag'], execFileOptions)
spawn
const spawnOptions = {  // any child_process.spawn options}const spawnedProcess = cli.spawn('program', ['--flag', 'Flag'], spawnOptions)

source

the source for this page is in the docsrc directory and gets built and published to github using @magic/core