UNPKG

pxi-args

Version:

A command-line arguments parser for pxi (pixie), the small, fast, and magical command-line data processor

249 lines (190 loc) 12.1 kB
![pxi teaser][teaser] `pxi-args` is a command-line arguments parser for [`pxi`][pxi] (pixie), the small, fast, and magical command-line data processor. [![node version][shield-node]][node] [![npm version][shield-npm]][npm-package] [![license][shield-license]][license] [![PRs Welcome][shield-prs]][contribute] [![linux unit tests status][shield-unit-tests-linux]][actions] [![macos unit tests status][shield-unit-tests-macos]][actions] [![windows unit tests status][shield-unit-tests-windows]][actions] ## Installation Installation is done using [`npm`][npm-install]. ```bash $ npm i --save pxi-args ``` ## Work in Progress This project is work in progress. Use it at your own risk! ## `pxi-args` `pxi-args` is the command-line argument parser used by [`pxi`][pxi]. ### Defining Command-Line Arguments The following definitions of `answerCmd` are identical: ```js const answerCmd = {key: 'answer', args: ['--answer', '-a'], types: ['number'], only: [42]} const answerCmd = number('answer', ['--answer', '-a'], {only: [42]}) const questionCmd = string('question', ['--question']) ``` You may either describe command-line arguments using a plain object or a type function like `number` or `string` from the functional DSL. The definition of `answerCmd` reads as follows: > `answerCmd` is a command-line argument that is read to the `answer` key > and is set using either `--answer` or `-a`. > It must be followed by exactly one number that can only be `42`. The object syntax takes `key`, `args`, and `types` as keys, while the type function syntax takes `key` and `args` as the first two arguments and sets `types` depending on the type function. Additional fields are passed as additional keys in the object syntax or in an object as the third parameter in the type function syntax. #### Fields The following command-line argument fields are available: | Field | Value | Default | Description | |---------|--------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------| | `key` | string | `null` | The command-line argument's value is assigned to a key of this name. | | `args` | array of strings | `[]` | A list of options that may be used to set the command-line option. | | `desc` | string | `''` | Description of the command-line argument for use in the usage text. | | `only` | array of values | `null` | The command-line argument's value can only be one of the values in this list. If `only` is `null`, the value may be set freely. | | `opts` | [command-line option](#defining-command-line-options) object | `null` | This field is only used if the command-line argument is a command (if `types` is `null`). | | `types` | `['number']` | | This command-line argument takes exactly one number. | | `types` | `['string']` | | This command-line argument takes exactly one string. | | `types` | `['bool']` | | This command-line argument takes exactly one boolean, `true` or `false`. | | `types` | `['number','string']` | | This command-line argument takes exactly two values, a number and a string. | | `types` | `[]` | | This command-line argument takes no value. It is a flag that is `true` if used and `false` if not used. | | `types` | `null` | | This command-line argument is a command. It may have its own list of arguments (see `opts`) and is terminated by either `--` or a line ending. | #### Functional DSL The following type functions are available to generate command-line arguments: | Function | Description | |-----------------------------------|------------------------------------------------------------| | `array(types)(key, args, fields)` | Assigns `types`, `key`, and `args` to `fields`. | | `bool(key, args, fields)` | Assigns `types: ['bool']`, `key` and `args` to `fields`. | | `command(key, args, fields)` | Assigns `types: null`, `key` and `args` to `fields`. | | `flag(key, args, fields)` | Assigns `types: []`, `key` and `args` to `fields`. | | `number(key, args, fields)` | Assigns `types: ['number']`, `key` and `args` to `fields`. | | `string(key, args, fields)` | Assigns `types: ['string']`, `key` and `args` to `fields`. | ### Defining Command-Line Options Command-line options are very similar to command-line arguments. In fact, most [command-line parsers](#defining-command-line-parsers) use the `option` function to generate them based on command-line arguments. The following definitions of `answerOpt` are identical: ```js const answerOpt = { errs: [], args: { '--answer': [{key: 'answer', types: ['number'], only: [42]}], '-a': [{key: 'answer', types: ['number'], only: [42]}] } } const answerOpt = option(answerCmd) ``` You may either describe command-line options using a plain object or the `option` function that takes a [command-line argument](#defining-command-line-arguments). The definition of `answerOpt` reads as follows: > `answerOpt` is a command-line option that has no errors and the following arguments: > `--answer` is an argument that is read to the `answer` key and > must be followed by exactly one number that can only be `42`. > `-a` is an argument that is read to the `answer` key and > must be followed by exactly one number that can only be `42`. The reason why options are defined redundant is because that makes it easier for parsers to look them up. Command-line arguments exist, because their syntax is easier to parse for usage generators. Several Command-line options may be combined: ```js const questionOpt = option(questionCmd) const combinedOpt = combine(questionOpt, answerOpt) const combinedOpt = { errs: [], args: { '--question': [{key: 'question', types: ['string']}], '--answer': [{key: 'answer', types: ['number'], only: [42]}], '-a': [{key: 'answer', types: ['number'], only: [42]}] } } ``` The `combinedOpt` includes `questionOpt` as well as `answerOpt`. If either one has errors, they are gathered in the `errs` array. Setting errors explicitly does not make much sense. However, `option` uses `errs` if e.g. a command-line argument does not set an `arg` or has an empty `args`. In some cases (most cases actually), an answer is not a number but a string. ```js const answerStrCmd = string('answerStr', ['-a']}) const answerStrOpt = option(answerStrCmd) const combinedOpt = combine(answerCmd, answerStrCmd) const combinedOpt = { errs: [], args: { '--answer': [ {key: 'answer', types: ['number'], only: [42]} ], '-a': [ {key: 'answer', types: ['number'], only: [42]} {key: 'answerStr', types: ['string']} ] } } ``` Here, a new command-line argument `answerStr` is defined that has the same argument `-a` as `answer`. If options of both command-line arguments are combined, the `-a` argument is interpreted twice: By `answer` as a number that can only be `42`, as well as by `answerStr` as a string without restrictions. An option can only be written two several keys, if the number of its arguments match. If `combine` tries to adds another interpretation to an argument that does not have the same number of keys, an error is recorded instead. ### Defining Command-Line Parsers Command-line parsers combine command-line options with parser plugins to process the command-line string given to a command-line program. The following parser uses `combinedOpts`: ```js const deepThought = opts => parser( splitShortOptions, parseArgs(opts), mergeArgs() )(opts) const parse = deepThought(combinedOpt) const result = parse(sliceArgv({argv: process.argv})) ``` The `deepThought` parser lets you parse command line input of the following kind: ```bash $ node index.js --question "What is the answer to everything?" -a 42 ``` Which would be equivalent to the following: ```js const result = { errs: [], argv: { "_": [], question: "What is the answer to everything?", answer: 42 } } ``` #### Parser Plugins The following parser plugins are available: | Plugin | Description | |-----------------------------------|-----------------------------------------------------------------------------------------------------------------| | `sliceArgv({errs, argv})` | Removes the first two elements from a process.argv array, as they are meta data. | | `splitShortOptions({errs, argv})` | Splits argument groups of shape `-vs` to `-v -s`. Only works if the arguments are preceded by a single dash. | | `parseArgs({args})({errs, argv})` | Groups arguments together with their values, types, and options if an argument is a command. | | `mergeArgs(parser)({errs, argv})` | Casts values to their types, validates values, and outputs the parsing result in a hierarchical JSON structure. | Note that not every combination of plugins produces a valid parser. ## Reporting Issues Please report issues [in the tracker][issues]! ## Contributing We are open to, and grateful for, any contributions made by the community. By contributing to pixie, you agree to abide by the [code of conduct][code]. Please read the [contributing guide][contribute]. ## License `pxi-args` is [MIT licensed][license]. [actions]: https://github.com/Yord/pxi-args/actions [code]: https://github.com/Yord/pxi-args/blob/master/CODE_OF_CONDUCT.md [contribute]: https://github.com/Yord/pxi-args/blob/master/CONTRIBUTING.md [issues]: https://github.com/Yord/pxi-args/issues [license]: https://github.com/Yord/pxi-args/blob/master/LICENSE [node]: https://nodejs.org/ [npm-install]: https://docs.npmjs.com/downloading-and-installing-packages-globally [npm-package]: https://www.npmjs.com/package/pxi-args [pxi]: https://github.com/Yord/pxi [shield-license]: https://img.shields.io/npm/l/pxi-args?color=yellow&labelColor=313A42 [shield-node]: https://img.shields.io/node/v/pxi-args?color=red&labelColor=313A42 [shield-npm]: https://img.shields.io/npm/v/pxi-args.svg?color=orange&labelColor=313A42 [shield-prs]: https://img.shields.io/badge/PRs-welcome-green.svg?labelColor=313A42 [shield-unit-tests-linux]: https://github.com/Yord/pxi-args/workflows/linux/badge.svg?branch=master [shield-unit-tests-macos]: https://github.com/Yord/pxi-args/workflows/macos/badge.svg?branch=master [shield-unit-tests-windows]: https://github.com/Yord/pxi-args/workflows/windows/badge.svg?branch=master [teaser]: https://github.com/Yord/pxi/blob/master/teaser.gif?raw=true