├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .github
└── workflows
│ ├── ci.yaml
│ └── release-please.yaml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── index.js
├── package-lock.json
├── package.json
└── test
└── index.spec.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 4
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [{*.md,*.snap}]
12 | trim_trailing_whitespace = false
13 |
14 | [package.json]
15 | indent_size = 2
16 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage/
2 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": [
4 | "eslint-config-moxy/es6",
5 | "eslint-config-moxy/addons/node",
6 | "eslint-config-moxy/addons/jest"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - master
5 | pull_request:
6 | types: [ assigned, opened, synchronize, reopened, labeled ]
7 | name: ci
8 | jobs:
9 | test:
10 | runs-on: ubuntu-latest
11 | strategy:
12 | matrix:
13 | node: [10, 12, 14]
14 | steps:
15 | - uses: actions/checkout@v1
16 | - uses: actions/setup-node@v1
17 | with:
18 | node-version: ${{ matrix.node }}
19 | - run: node --version
20 | - run: npm install --engines-strict
21 | - run: npm test
22 | windows:
23 | runs-on: windows-latest
24 | steps:
25 | - uses: actions/checkout@v2
26 | - uses: actions/setup-node@v1
27 | with:
28 | node-version: 14
29 | - run: npm install
30 | - run: npm test
31 |
--------------------------------------------------------------------------------
/.github/workflows/release-please.yaml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - master
5 | name: release-please
6 | jobs:
7 | release-please:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: GoogleCloudPlatform/release-please-action@v2.4.2
11 | id: release
12 | with:
13 | token: ${{ secrets.GITHUB_TOKEN }}
14 | release-type: node
15 | package-name: yargs-unparser
16 | # The logic below handles the npm publication:
17 | - uses: actions/checkout@v2
18 | # these if statements ensure that a publication only occurs when
19 | # a new release is created:
20 | if: ${{ steps.release.outputs.release_created }}
21 | - uses: actions/setup-node@v1
22 | with:
23 | node-version: 12
24 | registry-url: 'https://external-dot-oss-automation.appspot.com'
25 | if: ${{ steps.release.outputs.release_created }}
26 | - run: npm ci
27 | if: ${{ steps.release.outputs.release_created }}
28 | - run: npm publish
29 | env:
30 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
31 | if: ${{ steps.release.outputs.release_created }}
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | npm-debug.*
3 | coverage/
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 | ## [2.0.0](https://www.github.com/yargs/yargs-unparser/compare/v1.6.4...v2.0.0) (2020-10-02)
6 |
7 |
8 | ### ⚠ BREAKING CHANGES
9 |
10 | * upgrade deps drop Node 6/8 (#71)
11 |
12 | ### Code Refactoring
13 |
14 | * upgrade deps drop Node 6/8 ([#71](https://www.github.com/yargs/yargs-unparser/issues/71)) ([c686882](https://www.github.com/yargs/yargs-unparser/commit/c686882f5ad554be44169e3745e741cb4ec898d0))
15 |
16 | ### [1.6.4](https://www.github.com/yargs/yargs-unparser/compare/v1.6.3...v1.6.4) (2020-10-01)
17 |
18 |
19 | ### Bug Fixes
20 |
21 | * **security:** upgraded flat to version ^5.0.2 ([9bd7c67](https://www.github.com/yargs/yargs-unparser/commit/9bd7c672e12417319c5d4de79070d9c7cd5107f2))
22 |
23 | ### [1.6.3](https://www.github.com/yargs/yargs-unparser/compare/v1.6.2...v1.6.3) (2020-06-17)
24 |
25 |
26 | ### Bug Fixes
27 |
28 | * test automatic publish ([209a487](https://www.github.com/yargs/yargs-unparser/commit/209a4870af799f4b200c2a89d7b7e50c9fd5fd1f))
29 |
30 | ### [1.6.2](https://www.github.com/yargs/yargs-unparser/compare/v1.6.1...v1.6.2) (2020-06-17)
31 |
32 |
33 | ### Bug Fixes
34 |
35 | * **readme:** marketing was injected dubiously into README ([#60](https://www.github.com/yargs/yargs-unparser/issues/60)) ([1167667](https://www.github.com/yargs/yargs-unparser/commit/1167667886fcb103c747e3c9855f353ee0e41c03))
36 |
37 | ### [1.6.1](https://www.github.com/yargs/yargs-unparser/compare/v1.6.0...v1.6.1) (2020-06-17)
38 |
39 |
40 | ### Bug Fixes
41 |
42 | * **deps:** downgrade yargs, such that we continue supporting Node 6 ([#57](https://www.github.com/yargs/yargs-unparser/issues/57)) ([f69406c](https://www.github.com/yargs/yargs-unparser/commit/f69406c34bead63011590f7b51a24a6f311c1a48))
43 |
44 | ## 1.6.0 (2019-07-30)
45 |
46 |
47 | ### Bug Fixes
48 |
49 | * **security:** update deps addressing recent audit vulnerabilities ([#40](https://github.com/yargs/yargs-unparser/issues/40)) ([2e74f1b](https://github.com/yargs/yargs-unparser/commit/2e74f1b))
50 | * address bug with camelCased flattened keys ([#32](https://github.com/yargs/yargs-unparser/issues/32)) ([981533a](https://github.com/yargs/yargs-unparser/commit/981533a))
51 | * **deps:** updated the lodash version to fix vulnerability ([#39](https://github.com/yargs/yargs-unparser/issues/39)) ([7375966](https://github.com/yargs/yargs-unparser/commit/7375966))
52 | * **package:** update yargs to version 10.0.3 ([f1eb4cb](https://github.com/yargs/yargs-unparser/commit/f1eb4cb))
53 | * **package:** update yargs to version 11.0.0 ([6aa7c91](https://github.com/yargs/yargs-unparser/commit/6aa7c91))
54 |
55 |
56 | ### Features
57 |
58 | * add interoperation with minimist ([ba477f5](https://github.com/yargs/yargs-unparser/commit/ba477f5))
59 |
60 |
61 | # 1.5.0 (2018-11-30)
62 |
63 |
64 | ### Bug Fixes
65 |
66 | * **package:** update yargs to version 10.0.3 ([f1eb4cb](https://github.com/yargs/yargs-unparser/commit/f1eb4cb))
67 | * **package:** update yargs to version 11.0.0 ([6aa7c91](https://github.com/yargs/yargs-unparser/commit/6aa7c91))
68 |
69 |
70 | ### Features
71 |
72 | * add interoperation with minimist ([ba477f5](https://github.com/yargs/yargs-unparser/commit/ba477f5))
73 |
74 |
75 |
76 |
77 | # [1.4.0](https://github.com/moxystudio/yargs-unparser/compare/v1.3.0...v1.4.0) (2017-12-30)
78 |
79 |
80 | ### Features
81 |
82 | * add interoperation with minimist ([ba477f5](https://github.com/moxystudio/yargs-unparser/commit/ba477f5))
83 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Made With MOXY Lda
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # yargs-unparser
2 |
3 | [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url]
4 |
5 | [npm-url]:https://npmjs.org/package/yargs-unparser
6 | [npm-image]:http://img.shields.io/npm/v/yargs-unparser.svg
7 | [downloads-image]:http://img.shields.io/npm/dm/yargs-unparser.svg
8 |
9 | Converts back a `yargs` argv object to its original array form.
10 |
11 | Probably the unparser word doesn't even exist, but it sounds nice and goes well with [yargs-parser](https://github.com/yargs/yargs-parser).
12 |
13 | The code originally lived in [MOXY](https://github.com/moxystudio)'s GitHub but was later moved here for discoverability.
14 |
15 |
16 | ## Installation
17 |
18 | `$ npm install yargs-unparser`
19 |
20 |
21 | ## Usage
22 |
23 | ```js
24 | const parse = require('yargs-parser');
25 | const unparse = require('yargs-unparser');
26 |
27 | const argv = parse(['--no-boolean', '--number', '4', '--string', 'foo'], {
28 | boolean: ['boolean'],
29 | number: ['number'],
30 | string: ['string'],
31 | });
32 | // { boolean: false, number: 4, string: 'foo', _: [] }
33 |
34 | const unparsedArgv = unparse(argv);
35 | // ['--no-boolean', '--number', '4', '--string', 'foo'];
36 | ```
37 |
38 | The second argument of `unparse` accepts an options object:
39 |
40 | - `alias`: The [aliases](https://github.com/yargs/yargs-parser#requireyargs-parserargs-opts) so that duplicate options aren't generated
41 | - `default`: The [default](https://github.com/yargs/yargs-parser#requireyargs-parserargs-opts) values so that the options with default values are omitted
42 | - `command`: The [command](https://github.com/yargs/yargs/blob/master/docs/advanced.md#commands) first argument so that command names and positional arguments are handled correctly
43 |
44 | ### Example with `command` options
45 |
46 | ```js
47 | const yargs = require('yargs');
48 | const unparse = require('yargs-unparser');
49 |
50 | const argv = yargs
51 | .command('my-command ', 'My awesome command', (yargs) =>
52 | yargs
53 | .option('boolean', { type: 'boolean' })
54 | .option('number', { type: 'number' })
55 | .option('string', { type: 'string' })
56 | )
57 | .parse(['my-command', 'hello', '--no-boolean', '--number', '4', '--string', 'foo']);
58 | // { positional: 'hello', boolean: false, number: 4, string: 'foo', _: ['my-command'] }
59 |
60 | const unparsedArgv = unparse(argv, {
61 | command: 'my-command ',
62 | });
63 | // ['my-command', 'hello', '--no-boolean', '--number', '4', '--string', 'foo'];
64 | ```
65 |
66 | ### Caveats
67 |
68 | The returned array can be parsed again by `yargs-parser` using the default configuration. If you used custom configuration that you want `yargs-unparser` to be aware, please fill an [issue](https://github.com/yargs/yargs-unparser/issues).
69 |
70 | If you `coerce` in weird ways, things might not work correctly.
71 |
72 |
73 | ## Tests
74 |
75 | `$ npm test`
76 | `$ npm test -- --watch` during development
77 |
78 | ## Supported Node.js Versions
79 |
80 | Libraries in this ecosystem make a best effort to track
81 | [Node.js' release schedule](https://nodejs.org/en/about/releases/). Here's [a
82 | post on why we think this is important](https://medium.com/the-node-js-collection/maintainers-should-consider-following-node-js-release-schedule-ab08ed4de71a).
83 |
84 | ## License
85 |
86 | [MIT License](http://opensource.org/licenses/MIT)
87 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const flatten = require('flat');
4 | const camelcase = require('camelcase');
5 | const decamelize = require('decamelize');
6 | const isPlainObj = require('is-plain-obj');
7 |
8 | function isAlias(key, alias) {
9 | // TODO Switch to Object.values one Node.js 6 is dropped
10 | return Object.keys(alias).some((id) => [].concat(alias[id]).indexOf(key) !== -1);
11 | }
12 |
13 | function hasDefaultValue(key, value, defaults) {
14 | return value === defaults[key];
15 | }
16 |
17 | function isCamelCased(key, argv) {
18 | return /[A-Z]/.test(key) && camelcase(key) === key && // Is it camel case?
19 | argv[decamelize(key, '-')] != null; // Is the standard version defined?
20 | }
21 |
22 | function keyToFlag(key) {
23 | return key.length === 1 ? `-${key}` : `--${key}`;
24 | }
25 |
26 | function parseCommand(cmd) {
27 | const extraSpacesStrippedCommand = cmd.replace(/\s{2,}/g, ' ');
28 | const splitCommand = extraSpacesStrippedCommand.split(/\s+(?![^[]*]|[^<]*>)/);
29 | const bregex = /\.*[\][<>]/g;
30 | const firstCommand = splitCommand.shift();
31 |
32 | if (!firstCommand) { throw new Error(`No command found in: ${cmd}`); }
33 | const parsedCommand = {
34 | cmd: firstCommand.replace(bregex, ''),
35 | demanded: [],
36 | optional: [],
37 | };
38 |
39 | splitCommand.forEach((cmd, i) => {
40 | let variadic = false;
41 |
42 | cmd = cmd.replace(/\s/g, '');
43 | if (/\.+[\]>]/.test(cmd) && i === splitCommand.length - 1) { variadic = true; }
44 | if (/^\[/.test(cmd)) {
45 | parsedCommand.optional.push({
46 | cmd: cmd.replace(bregex, '').split('|'),
47 | variadic,
48 | });
49 | } else {
50 | parsedCommand.demanded.push({
51 | cmd: cmd.replace(bregex, '').split('|'),
52 | variadic,
53 | });
54 | }
55 | });
56 |
57 | return parsedCommand;
58 | }
59 |
60 | function unparseOption(key, value, unparsed) {
61 | if (typeof value === 'string') {
62 | unparsed.push(keyToFlag(key), value);
63 | } else if (value === true) {
64 | unparsed.push(keyToFlag(key));
65 | } else if (value === false) {
66 | unparsed.push(`--no-${key}`);
67 | } else if (Array.isArray(value)) {
68 | value.forEach((item) => unparseOption(key, item, unparsed));
69 | } else if (isPlainObj(value)) {
70 | const flattened = flatten(value, { safe: true });
71 |
72 | for (const flattenedKey in flattened) {
73 | if (!isCamelCased(flattenedKey, flattened)) {
74 | unparseOption(`${key}.${flattenedKey}`, flattened[flattenedKey], unparsed);
75 | }
76 | }
77 | // Fallback case (numbers and other types)
78 | } else if (value != null) {
79 | unparsed.push(keyToFlag(key), `${value}`);
80 | }
81 | }
82 |
83 | function unparsePositional(argv, options, unparsed) {
84 | const knownPositional = [];
85 |
86 | // Unparse command if set, collecting all known positional arguments
87 | // e.g.: build
88 | if (options.command) {
89 | const { 0: cmd, index } = options.command.match(/[^<[]*/);
90 | const { demanded, optional } = parseCommand(`foo ${options.command.substr(index + cmd.length)}`);
91 |
92 | // Push command (can be a deep command)
93 | unparsed.push(...cmd.trim().split(/\s+/));
94 |
95 | // Push positional arguments
96 | [...demanded, ...optional].forEach(({ cmd: cmds, variadic }) => {
97 | knownPositional.push(...cmds);
98 |
99 | const cmd = cmds[0];
100 | const args = (variadic ? argv[cmd] || [] : [argv[cmd]])
101 | .filter((arg) => arg != null)
102 | .map((arg) => `${arg}`);
103 |
104 | unparsed.push(...args);
105 | });
106 | }
107 |
108 | // Unparse unkown positional arguments
109 | argv._ && unparsed.push(...argv._.slice(knownPositional.length));
110 |
111 | return knownPositional;
112 | }
113 |
114 | function unparseOptions(argv, options, knownPositional, unparsed) {
115 | for (const key of Object.keys(argv)) {
116 | const value = argv[key];
117 |
118 | if (
119 | // Remove positional arguments
120 | knownPositional.includes(key) ||
121 | // Remove special _, -- and $0
122 | ['_', '--', '$0'].includes(key) ||
123 | // Remove aliases
124 | isAlias(key, options.alias) ||
125 | // Remove default values
126 | hasDefaultValue(key, value, options.default) ||
127 | // Remove camel-cased
128 | isCamelCased(key, argv)
129 | ) {
130 | continue;
131 | }
132 |
133 | unparseOption(key, argv[key], unparsed);
134 | }
135 | }
136 |
137 | function unparseEndOfOptions(argv, options, unparsed) {
138 | // Unparse ending (--) arguments if set
139 | argv['--'] && unparsed.push('--', ...argv['--']);
140 | }
141 |
142 | // ------------------------------------------------------------
143 |
144 | function unparser(argv, options) {
145 | options = Object.assign({
146 | alias: {},
147 | default: {},
148 | command: null,
149 | }, options);
150 |
151 | const unparsed = [];
152 |
153 | // Unparse known & unknown positional arguments (foo [rest...])
154 | // All known positional will be returned so that they are not added as flags
155 | const knownPositional = unparsePositional(argv, options, unparsed);
156 |
157 | // Unparse option arguments (--foo hello --bar hi)
158 | unparseOptions(argv, options, knownPositional, unparsed);
159 |
160 | // Unparse "end-of-options" arguments (stuff after " -- ")
161 | unparseEndOfOptions(argv, options, unparsed);
162 |
163 | return unparsed;
164 | }
165 |
166 | module.exports = unparser;
167 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yargs-unparser",
3 | "description": "Converts back a yargs argv object to its original array form",
4 | "version": "2.0.0",
5 | "keywords": [
6 | "yargs",
7 | "unparse",
8 | "expand",
9 | "inverse",
10 | "argv"
11 | ],
12 | "author": "André Cruz ",
13 | "engines": {
14 | "node": ">=10"
15 | },
16 | "homepage": "https://github.com/yargs/yargs-unparser",
17 | "repository": "yargs/yargs-unparser",
18 | "license": "MIT",
19 | "main": "index.js",
20 | "files": [],
21 | "scripts": {
22 | "lint": "eslint .",
23 | "fix": "eslint . --fix",
24 | "test": "jest --env node --coverage",
25 | "prerelease": "npm t && npm run lint",
26 | "precommit": "lint-staged"
27 | },
28 | "lint-staged": {
29 | "*.js": [
30 | "eslint --fix",
31 | "git add"
32 | ]
33 | },
34 | "devDependencies": {
35 | "eslint": "^6.1.0",
36 | "eslint-config-moxy": "^7.1.0",
37 | "husky": "^3.0.1",
38 | "jest": "^24.9.0",
39 | "lint-staged": "^9.5.0",
40 | "minimist": "^1.2.5",
41 | "yargs-parser": "^18.1.3"
42 | },
43 | "dependencies": {
44 | "camelcase": "^6.0.0",
45 | "decamelize": "^4.0.0",
46 | "flat": "^5.0.2",
47 | "is-plain-obj": "^2.1.0"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/test/index.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const yargs = require('yargs/yargs');
4 | const parse = require('yargs-parser');
5 | const minimist = require('minimist');
6 | const unparse = require('../');
7 |
8 | it('should unparse options whose values are primitives', () => {
9 | const argv = parse(['--no-boolean1', '--boolean2', '--number', '4', '--string', 'foo'], {
10 | number: 'number',
11 | string: 'string',
12 | boolean: ['boolean1', 'boolean2'],
13 | });
14 |
15 | expect(unparse(argv)).toEqual(['--no-boolean1', '--boolean2', '--number', '4', '--string', 'foo']);
16 | });
17 |
18 | it('should unparse options whose values are arrays', () => {
19 | const argv = parse(['--array1', '1', '2', '--array2', '3', '--array2', '4'], {
20 | array: ['array1', 'array2'],
21 | });
22 |
23 | expect(unparse(argv)).toEqual(['--array1', '1', '--array1', '2', '--array2', '3', '--array2', '4']);
24 | });
25 |
26 | it('should unparse options whose values are objects', () => {
27 | const argv = parse(['--foo.x', 'x', '--foo.y', 'y', '--foo.w', '1', '2', '--foo.z', '3', '--foo.z', '4'], {
28 | array: ['foo.w', 'foo.z'],
29 | });
30 |
31 | expect(unparse(argv)).toEqual(['--foo.x', 'x', '--foo.y', 'y', '--foo.w', '1', '--foo.w', '2', '--foo.z', '3', '--foo.z', '4']);
32 | });
33 |
34 | it('should unparse options whose values are not primitives, arrays or objects', () => {
35 | class Baz {
36 | toString() {
37 | return 'baz';
38 | }
39 | }
40 |
41 | const date = new Date(1502708276274);
42 |
43 | expect(unparse({
44 | foo: date,
45 | bar: /bar/,
46 | baz: new Baz(),
47 | })).toEqual(['--foo', date.toString(), '--bar', '/bar/', '--baz', 'baz']);
48 | });
49 |
50 | it('should unparse options whose values are empty strings correctly', () => {
51 | let argv = parse(['--string', ''], {
52 | string: 'string',
53 | });
54 |
55 | expect(unparse(argv)).toEqual(['--string', '']);
56 |
57 | argv = parse(['--string', '']);
58 |
59 | expect(unparse(argv)).toEqual(['--string', '']);
60 | });
61 |
62 | it('should only add a dash for short option names', () => {
63 | const argv = parse(['--n', '4', '--s', 'foo'], {
64 | number: 'n',
65 | string: 's',
66 | });
67 |
68 | expect(unparse(argv)).toEqual(['-n', '4', '-s', 'foo']);
69 | });
70 |
71 | it('should not duplicate keys that are camel-cased', () => {
72 | const argv = parse(['--some-string', 'foo']);
73 |
74 | expect(unparse(argv)).toEqual(['--some-string', 'foo']);
75 | });
76 |
77 | it('should keep camel-cased keys if standard ones were not found on argv', () => {
78 | const argv = parse(['--someNumber', '1']);
79 |
80 | expect(unparse(argv)).toEqual(['--someNumber', '1']);
81 | });
82 |
83 | it('should not duplicate nested keys that are camel-cased', () => {
84 | const argv = parse(['--paths.some-string', 'foo']);
85 |
86 | expect(unparse(argv)).toEqual(['--paths.some-string', 'foo']);
87 | });
88 |
89 | it('should keep nested camel-cased keys if standard ones were not found on argv', () => {
90 | const argv = parse(['--paths.someNumber', '1']);
91 |
92 | expect(unparse(argv)).toEqual(['--paths.someNumber', '1']);
93 | });
94 |
95 | it('should ignore nullish option values', () => {
96 | const argv = parse(['node', 'cli.js'], {
97 | number: 'n',
98 | string: 's',
99 | });
100 |
101 | expect(unparse(argv)).toEqual(['node', 'cli.js']);
102 | });
103 |
104 | it('should add unknown positional arguments at the start', () => {
105 | const argv = parse(['foo', '--string', 'bar']);
106 |
107 | expect(unparse(argv)).toEqual(['foo', '--string', 'bar']);
108 | });
109 |
110 | it('should add arguments after -- at the end', () => {
111 | const argv = parse(['--string', 'foo', '--', '--number', '1'], {
112 | configuration: {
113 | 'populate--': true,
114 | },
115 | });
116 |
117 | expect(unparse(argv)).toEqual(['--string', 'foo', '--', '--number', '1']);
118 | });
119 |
120 | it('should ignore $0', () => {
121 | const argv = parse(['foo', '--string', 'bar']);
122 |
123 | argv.$0 = 'foo.js';
124 |
125 | expect(unparse(argv)).toEqual(['foo', '--string', 'bar']);
126 | });
127 |
128 | describe('options', () => {
129 | it('should ignore aliases specified via `options.aliases`', () => {
130 | const alias = {
131 | string: 's', // Single alias
132 | number: ['n', 'no'], // Multiple aliases
133 | substr: 'substring',
134 | };
135 | const argv = parse(['--string', 'foo', '--number', '1', '--substr', 'a'], { alias });
136 |
137 | expect(unparse(argv, { alias })).toEqual([
138 | '--string', 'foo',
139 | '--number', '1',
140 | '--substr', 'a',
141 | ]);
142 | });
143 |
144 | it('should filter flags with default values via `options.defaults`', () => {
145 | const defaults = { foo: false };
146 | const argv = parse([], { default: defaults });
147 |
148 | expect(unparse(argv, { default: defaults })).toEqual([]);
149 | });
150 |
151 | it('should handle known positional arguments specified via `options.command`', () => {
152 | const command = 'build [second] [rest..]';
153 | const argv = yargs()
154 | .help(false)
155 | .version(false)
156 | .command(command, '', (yargs) => yargs, () => {})
157 | .parse(['build', 'foo', 'foz', 'bar', 'baz', '--string', 'hello']);
158 |
159 | expect(unparse(argv, {
160 | command,
161 | })).toEqual(['build', 'foo', 'foz', 'bar', 'baz', '--string', 'hello']);
162 | });
163 |
164 | it('should handle optional known positional arguments specified via `options.command`', () => {
165 | const command = 'build [first] [rest..]';
166 | const argv = yargs()
167 | .help(false)
168 | .version(false)
169 | .command(command, '', (yargs) => yargs, () => {})
170 | .parse(['build', '--string', 'hello']);
171 |
172 | expect(unparse(argv, {
173 | command,
174 | })).toEqual(['build', '--string', 'hello']);
175 | });
176 |
177 | it('should handle unknown positional arguments when `options.command` is set', () => {
178 | const command = 'build ';
179 | const argv = yargs()
180 | .help(false)
181 | .version(false)
182 | .command(command, '', (yargs) => yargs, () => {})
183 | .parse(['build', 'foo', 'foz', '--string', 'hello']);
184 |
185 | expect(unparse(argv, {
186 | command,
187 | })).toEqual(['build', 'foo', 'foz', '--string', 'hello']);
188 | });
189 |
190 | it('should handle positional arguments with alias specified in `options.command`', () => {
191 | const command = 'build ';
192 | const argv = yargs()
193 | .help(false)
194 | .version(false)
195 | .command(command, '', (yargs) => yargs, () => {})
196 | .parse(['build', 'foo', '--string', 'hello']);
197 |
198 | expect(unparse(argv, {
199 | command,
200 | })).toEqual(['build', 'foo', '--string', 'hello']);
201 | });
202 | });
203 |
204 | describe('interoperation with other libraries', () => {
205 | it('should have basic integration with minimist', () => {
206 | const argv = parse(['--no-cache', '--optimize', '--host', '0.0.0.0', '--collect', 'x', 'y'], {
207 | boolean: ['cache', 'optimize'],
208 | string: 'host',
209 | array: 'collect',
210 | });
211 |
212 | const argvArray = unparse(argv);
213 |
214 | expect(minimist(argvArray)).toMatchObject({
215 | cache: false,
216 | optimize: true,
217 | host: '0.0.0.0',
218 | collect: ['x', 'y'],
219 | });
220 | });
221 | });
222 |
--------------------------------------------------------------------------------