UNPKG

minargs

Version:
392 lines (302 loc) 10.1 kB
# minargs `minargs` is an argument parser with _minimal_ configuration & assumptions. Argument parsing can take many shapes but the explicit goals of this library are as follows: ### Goals - **no** usage - **no** validation - **no** types or type cohersion - **no** regular expressions - **no** strictness - **no** dependencies - **no** information loss - **minimal** assumptions - **minimal** configuration - **consistant** results/format - **100%** test coverage ### Mantras - Bring Your Own Usage™️ - Bring Your Own Validation™️ ### Installation ```bash npm install minargs ``` ### `minargs([argv][, options])` - `argv` (`Array`) - Default: `process.argv` - The argument strings to parse #### Options - `alias` (`Object`) - Default: none - Define shorts & aliases to map to a canonical argument - Note: only single character aliases can be parsed as "shorts" (read more in the **F.A.Q.** below) - `positionalValues` (`Boolean`) - Default: `false` - Define whether or not to use positionals that follow bare flag definitions as values - `recursive` (`Boolean`) - Default: `false` - Define whether or not to end parsing when a bare `--` marker is found ### Returned Values ```js { args: {}, positionals: [], remainder: [], argv: [] } ``` #### `args` - An `Object` of canonical argument keys with corresponding `Array` of parsed `String` values - **Examples:** - `--foo` will return `[""]` (note the empty string by default) - `--foo=bar` will return `["bar"]` - `--foo bar` will return `["bar"]` when `positionalValues` is `true` - Notably, `bar` is treated as a positional & returned in `positionals` if `positionalValues` is `false` #### `positionals` - An `Array` of parsed positional `String` values #### `remainder` - An `Array` of `String` values the follow the first bare `--` when `recursive` is `false` - Notably, this is useful for recursively parsing arguments or passing along args to other processes (read more in the **F.A.Q.** below) #### `argv` - An `Array` of `Object`s with corresponding `index`s mapping back to the original `process.argv` or provided `Array` - `Object`s also contain the `value` parsed & `type` (ie. `"argument"`, `"short"`, `"positional"` or `"value"`) - The `type` `"value"` will only ever be defined -- in place of `"positional"` -- when `positionalValues=true` - Notably, this is useful for recreating the original `String` values or extending the capabilities of this information (ref. https://github.com/pkgjs/parseargs/issues/84) ### Example Usage #### Basic ```bash $ basic.js - --foo=bar -- --baz ``` ```js #!/usr/bin/env node // basic.js const { minargs } = require('minargs') const { args, positionals, remainder, argv } = minargs() args // { "foo": ["bar"] } positionals // ["-"] remainder // ["--baz"] argv // [ { index: 0, type: 'argument', value: { name: "foo", value: "bar" } } ... ] ``` #### Handling existence <details> <summary>Toggle Example</summary> ```bash $ exists.js --foo ``` ```js #!/usr/bin/env node // exists.js const { minargs } = require('minargs') const { args } = minargs() if (args.foo) { // ... } ``` </details> #### Handling last value define <details> <summary>Toggle Example</summary> ```bash $ last-definition-.js --foo ``` ```js #!/usr/bin/env node // exists.js const { minargs } = require('minargs') const { args } = minargs() if (args.foo) { // ... } ``` </details> #### Handling unknown args <details> <summary>Toggle Example</summary> ```bash $ unknown.js --baz ``` #### Handling extension ```js #!/usr/bin/env node // unknown.js const { minargs } = require('minargs') const { args } = minargs() const known = ['foo', 'bar'] const unknown = Object.keys(args).filter(arg => !known.includes(arg)) if (unknown.length > 0) { console.error('unknown flags passed:', unknown) // stop the process & set an `exitCode` appropriately process.exit(1) } // ... ``` </details> #### Handling validation <details> <summary>Toggle Example</summary> ```bash $ validate.js --num=1337 ``` ```js #!/usr/bin/env node // validate.js const { minargs } = require('minargs') const { args } = minargs() const usage = { num: { validate: (value) => { if (!isNaN(value)) { return Number(value) } throw Error('Validation error!') } }, force: { validate: (value) => { if (~['true','false'].indexOf(value.toLowerCase())) { return Boolean(value) } throw Error('Validation error!') } } } Object.keys(args).filter(name => args[name]).map(name => { usage[name].validate(args[name].pop()) }) // ... ``` </details> #### Handling recursive parsing <details> <summary>Toggle Example</summary> ```bash $ recursive-parse.js ``` ```js #!/usr/bin/env node // recursive-parse.js const { minargs } = require('minargs') console.log(minargs({ recursive: true })) // ... ``` </details> #### Handling sub process <details> <summary>Toggle Example</summary> ```bash $ mkdir.js ./path/to/new/dir/ --force --verbose --parents ``` ```js #!/usr/bin/env node // mkdir.js const known = ['force'] const { args, positionals } = minargs() const cmd = (args.force) ? 'sudo mkdir' : 'mkdir' const _args = Object.keys(flags).filter(f => known[f]) process('child_process').spawnSync(cmd, [..._args, ...positionals]) ``` </details> #### Handling robust options & usage <details> <summary>Toggle Example</summary> ```bash $ usage.js -h ``` ```js #!/usr/bin/env node // usage.js const { minargs } = require('minargs') const usage = { help: { short: 'h', usage: 'cli --help', description: 'Print usage information' } force: { short: 'f', usage: 'cli --force', description: 'Run this cli tool with no restrictions' } } const opts = { alias: Object.keys(usage).filter(arg => usage[arg].short).reduce((o, k) => { o[usage[k].short] = k return o }, {}) } const { args } = minargs(opts) if (args.help) { Object.keys(usage).map(name => { let short = usage[name].short ? `-${usage[name].short}, ` : '' let row = [` ${short}--${name}`, usage[name].usage, usage[name].description] console.log.apply(this, fill(columns, row)) }) } /// ... ``` </details> ### F.A.Q. #### Why isn't strictness supported? * Strictness is a function of usage. By default, `minargs` does not assume anything about "known" or "unknown" arguments or their intended values (ex. defaults/types). Usage examples above show how you can quickly & easily utilize `minargs` as the backbone for an application which _does_ enforce strictness/validation & more. #### Are shorts supported? * Yes. * Individual (ex. `-a`) & combined (ex. `-aCdeFg`) shorts are supported * `-a=b` will capture & return `"b"` as a value * `-a b` will capture & return `"b"` as a value if `positionalValues` is `true` #### Are multiples supported? * Yes. * By default multiple definitions of the same argument will get consolidated into a single `arg` entry with a corresponding `Array` of `String` values * Getting the last defined value of an argument is as simple as running `.pop()` on the `Array` (ex. `args.foo.pop()`) #### What is an `alias`? * An alias can be any other string that maps to a *canonical* option; this includes single characters which will map shorts to a long-form (ex. `alias: { f: foo }` will parse `-f` as `{ args: { "foo": [""] } }`) #### Is `cmd --foo=bar baz` the same as `cmd baz --foo=bar`? * _Sort of_. * The returned `argv` `Array` will change to reflect the differing positions of the arguments & positionals **BUT** `args` & `positionals` will remain consistent #### Is value validation or type cohersion supported? * No. #### Are usage errors supported? * No. #### Does `--no-foo` coerce to `--foo=false`? * No. * `--no-foo` will parse to `{ args: { "no-foo": [""] } }` & `--foo-false` to `{ args: { "no-foo": ["false"] } }` respectively #### Is `--foo` the same as `--foo=true`? * No. * `--foo` will parse to `{ args: { "foo": [""] } }` & `--foo=true` to ` { args: { "foo": ["true"] } }` respectively #### Are environment variables supported? * No. #### Does `--` signal the end of flags/options? * Yes. * Any arguments following a bare `--` definition will be returned in `remainder`. #### Is a value stored to represent the existence of `--`? * No. * The only way to determine if `--` was present & there were arguments passed afterward is to check the value of `remainder` #### Is `-` a positional? * Yes. * A bare `-` is treated as & returned in `positionals` #### Is `-bar` the same as `--bar`? * No. * `-bar` will be parsed as short options, expanding to `-b`, `-a`, `-r` (ref. [Utility Syntax Guidelines in POSIX.1-2017](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html)) #### Is `---foo` the same as `--foo`? * No. * `---foo` returns `{ args: "-foo": [""] }` * `--foo` returns `{ args: { "foo": [""] }` #### Is `foo=bar` a positional? * Yes. #### Are negative numbers supported as positional values? * No. * `minargs` aligns with the [POSIX Argument Syntax](https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html) here (ie. "Arguments are options if they begin with a hyphen delimiter") * `--number -2` will be parsed as `{ args: { "number": [""], "2": [""] } }` * You will have to use explicit value setting to make this association (ex. `--number=-2`) & may further require validation/type coercion to determine if the value is a `Number` (as is shown in the usage examples above) ### CLI `minargs` has a companion CLI library: [`@minargs/cli`](https://www.npmjs.com/package/@minargs/cli) #### Installation ```bash # install package globally & call bin... npm install @minargs/cli -g && minargs # or, use `npx` to install & call bin... npx -- @minargs/cli "<args>" [<options>] ``` #### Usage ```bash minargs "<args>" [<options>] ``` #### Options & more.... To learn more, check out the `@minargs/cli` [GitHub repository](https://github.com/darcyclarke/minargs-cli) or [package page](https://www.npmjs.com/package/@minargs/cli)