pax_global_header 0000666 0000000 0000000 00000000064 14144615712 0014517 g ustar 00root root 0000000 0000000 52 comment=217aa62906d0bbd40e06d675b8a23df8d49a5ad4
yargs-parser-yargs-parser-v21.0.0/ 0000775 0000000 0000000 00000000000 14144615712 0017021 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/.eslintrc 0000664 0000000 0000000 00000000710 14144615712 0020643 0 ustar 00root root 0000000 0000000 {
"overrides": [
{
"files": "*.ts",
"parser": "@typescript-eslint/parser",
"rules": {
"no-unused-vars": "off",
"no-useless-constructor": "off",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-useless-constructor": "error"
}
}
],
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint/eslint-plugin"
]
}
yargs-parser-yargs-parser-v21.0.0/.github/ 0000775 0000000 0000000 00000000000 14144615712 0020361 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/.github/workflows/ 0000775 0000000 0000000 00000000000 14144615712 0022416 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/.github/workflows/ci.yaml 0000664 0000000 0000000 00000004312 14144615712 0023675 0 ustar 00root root 0000000 0000000 on:
push:
branches:
- main
pull_request:
types: [ assigned, opened, synchronize, reopened, labeled ]
name: ci
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [12, 14, 16]
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
- run: node --version
- run: npm install
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- run: npm test
- run: npm run check
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- run: npm install
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- run: npm test
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 14
- run: npm install
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- run: npm test
- run: npm run coverage
deno:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 14
- run: npm install
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- run: npm run compile
- uses: denolib/setup-deno@v2
with:
deno-version: v1.x
- run: |
deno --version
deno test --allow-read test/deno/yargs-test.ts
browser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 14
- run: npm install
- run: npm run test:browser
typescript:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 14
- run: npm install
- run: npm run test:typescript
optimize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 16
- run: cd test/tscc && npm install && npx @tscc/tscc
- run: cd test/tscc && node out.js
yargs-parser-yargs-parser-v21.0.0/.github/workflows/release-please.yml 0000664 0000000 0000000 00000003255 14144615712 0026035 0 ustar 00root root 0000000 0000000 on:
push:
branches:
- main
name: release-please
jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/release-please-action@v2
id: release
with:
token: ${{ secrets.GITHUB_TOKEN }}
command: manifest
default-branch: main
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 14
- run: npm install
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
- run: npm run compile
- name: push Deno release
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git remote add gh-token "https://${{ secrets.GITHUB_TOKEN}}@github.com/yargs/yargs-parser.git"
git checkout -b deno
git add -f build
git commit -a -m 'chore: ${{ steps.release.outputs.tag_name }} release'
git push origin +deno
git tag -a ${{ steps.release.outputs.tag_name }}-deno -m 'chore: ${{ steps.release.outputs.tag_name }} release'
git push origin ${{ steps.release.outputs.tag_name }}-deno
if: ${{ steps.release.outputs.releases_created }}
- uses: actions/setup-node@v1
with:
node-version: 14
registry-url: 'https://external-dot-oss-automation.appspot.com/'
if: ${{ steps.release.outputs.releases_created }}
- run: npm install
if: ${{ steps.release.outputs.releases_created }}
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_MONOREPO_TOKEN}}
if: ${{ steps.release.outputs.releases_created }}
yargs-parser-yargs-parser-v21.0.0/.gitignore 0000664 0000000 0000000 00000000161 14144615712 0021007 0 ustar 00root root 0000000 0000000 .idea
.nyc_output
node_modules
.DS_Store
package-lock.json
./test/fixtures/package.json
coverage
build
example.*
yargs-parser-yargs-parser-v21.0.0/.nycrc 0000664 0000000 0000000 00000000243 14144615712 0020137 0 ustar 00root root 0000000 0000000 {
"exclude": [
"build/test/**",
"test/**"
],
"reporter": [
"html",
"text"
],
"lines": 99.5,
"branches": "98",
"statements": "99.5"
}
yargs-parser-yargs-parser-v21.0.0/.release-please-manifest.json 0000664 0000000 0000000 00000000016 14144615712 0024462 0 ustar 00root root 0000000 0000000 {".":"21.0.0"} yargs-parser-yargs-parser-v21.0.0/CHANGELOG.md 0000664 0000000 0000000 00000034575 14144615712 0020650 0 ustar 00root root 0000000 0000000 # Changelog
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.
## [21.0.0](https://www.github.com/yargs/yargs-parser/compare/yargs-parser-v20.2.9...yargs-parser-v21.0.0) (2021-11-15)
### ⚠ BREAKING CHANGES
* drops support for 10 (#421)
### Bug Fixes
* esm json import ([#416](https://www.github.com/yargs/yargs-parser/issues/416)) ([90f970a](https://www.github.com/yargs/yargs-parser/commit/90f970a6482dd4f5b5eb18d38596dd6f02d73edf))
* parser should preserve inner quotes ([#407](https://www.github.com/yargs/yargs-parser/issues/407)) ([ae11f49](https://www.github.com/yargs/yargs-parser/commit/ae11f496a8318ea8885aa25015d429b33713c314))
### Code Refactoring
* drops support for 10 ([#421](https://www.github.com/yargs/yargs-parser/issues/421)) ([3aaf878](https://www.github.com/yargs/yargs-parser/commit/3aaf8784f5c7f2aec6108c1c6a55537fa7e3b5c1))
### [20.2.9](https://www.github.com/yargs/yargs-parser/compare/yargs-parser-v20.2.8...yargs-parser-v20.2.9) (2021-06-20)
### Bug Fixes
* **build:** fixed automated release pipeline ([1fe9135](https://www.github.com/yargs/yargs-parser/commit/1fe9135884790a083615419b2861683e2597dac3))
### [20.2.8](https://www.github.com/yargs/yargs-parser/compare/yargs-parser-v20.2.7...yargs-parser-v20.2.8) (2021-06-20)
### Bug Fixes
* **locale:** Turkish camelize and decamelize issues with toLocaleLowerCase/toLocaleUpperCase ([2617303](https://www.github.com/yargs/yargs-parser/commit/261730383e02448562f737b94bbd1f164aed5143))
* **perf:** address slow parse when using unknown-options-as-args ([#394](https://www.github.com/yargs/yargs-parser/issues/394)) ([441f059](https://www.github.com/yargs/yargs-parser/commit/441f059d585d446551068ad213db79ac91daf83a))
* **string-utils:** detect [0,1] ranged values as numbers ([#388](https://www.github.com/yargs/yargs-parser/issues/388)) ([efcc32c](https://www.github.com/yargs/yargs-parser/commit/efcc32c2d6b09aba31abfa2db9bd947befe5586b))
### [20.2.7](https://www.github.com/yargs/yargs-parser/compare/v20.2.6...v20.2.7) (2021-03-10)
### Bug Fixes
* **deno:** force release for Deno ([6687c97](https://www.github.com/yargs/yargs-parser/commit/6687c972d0f3ca7865a97908dde3080b05f8b026))
### [20.2.6](https://www.github.com/yargs/yargs-parser/compare/v20.2.5...v20.2.6) (2021-02-22)
### Bug Fixes
* **populate--:** -- should always be array ([#354](https://www.github.com/yargs/yargs-parser/issues/354)) ([585ae8f](https://www.github.com/yargs/yargs-parser/commit/585ae8ffad74cc02974f92d788e750137fd65146))
### [20.2.5](https://www.github.com/yargs/yargs-parser/compare/v20.2.4...v20.2.5) (2021-02-13)
### Bug Fixes
* do not lowercase camel cased string ([#348](https://www.github.com/yargs/yargs-parser/issues/348)) ([5f4da1f](https://www.github.com/yargs/yargs-parser/commit/5f4da1f17d9d50542d2aaa206c9806ce3e320335))
### [20.2.4](https://www.github.com/yargs/yargs-parser/compare/v20.2.3...v20.2.4) (2020-11-09)
### Bug Fixes
* **deno:** address import issues in Deno ([#339](https://www.github.com/yargs/yargs-parser/issues/339)) ([3b54e5e](https://www.github.com/yargs/yargs-parser/commit/3b54e5eef6e9a7b7c6eec7c12bab3ba3b8ba8306))
### [20.2.3](https://www.github.com/yargs/yargs-parser/compare/v20.2.2...v20.2.3) (2020-10-16)
### Bug Fixes
* **exports:** node 13.0 and 13.1 require the dotted object form _with_ a string fallback ([#336](https://www.github.com/yargs/yargs-parser/issues/336)) ([3ae7242](https://www.github.com/yargs/yargs-parser/commit/3ae7242040ff876d28dabded60ac226e00150c88))
### [20.2.2](https://www.github.com/yargs/yargs-parser/compare/v20.2.1...v20.2.2) (2020-10-14)
### Bug Fixes
* **exports:** node 13.0-13.6 require a string fallback ([#333](https://www.github.com/yargs/yargs-parser/issues/333)) ([291aeda](https://www.github.com/yargs/yargs-parser/commit/291aeda06b685b7a015d83bdf2558e180b37388d))
### [20.2.1](https://www.github.com/yargs/yargs-parser/compare/v20.2.0...v20.2.1) (2020-10-01)
### Bug Fixes
* **deno:** update types for deno ^1.4.0 ([#330](https://www.github.com/yargs/yargs-parser/issues/330)) ([0ab92e5](https://www.github.com/yargs/yargs-parser/commit/0ab92e50b090f11196334c048c9c92cecaddaf56))
## [20.2.0](https://www.github.com/yargs/yargs-parser/compare/v20.1.0...v20.2.0) (2020-09-21)
### Features
* **string-utils:** export looksLikeNumber helper ([#324](https://www.github.com/yargs/yargs-parser/issues/324)) ([c8580a2](https://www.github.com/yargs/yargs-parser/commit/c8580a2327b55f6342acecb6e72b62963d506750))
### Bug Fixes
* **unknown-options-as-args:** convert positionals that look like numbers ([#326](https://www.github.com/yargs/yargs-parser/issues/326)) ([f85ebb4](https://www.github.com/yargs/yargs-parser/commit/f85ebb4face9d4b0f56147659404cbe0002f3dad))
## [20.1.0](https://www.github.com/yargs/yargs-parser/compare/v20.0.0...v20.1.0) (2020-09-20)
### Features
* adds parse-positional-numbers configuration ([#321](https://www.github.com/yargs/yargs-parser/issues/321)) ([9cec00a](https://www.github.com/yargs/yargs-parser/commit/9cec00a622251292ffb7dce6f78f5353afaa0d4c))
### Bug Fixes
* **build:** update release-please; make labels kick off builds ([#323](https://www.github.com/yargs/yargs-parser/issues/323)) ([09f448b](https://www.github.com/yargs/yargs-parser/commit/09f448b4cd66e25d2872544718df46dab8af062a))
## [20.0.0](https://www.github.com/yargs/yargs-parser/compare/v19.0.4...v20.0.0) (2020-09-09)
### ⚠ BREAKING CHANGES
* do not ship type definitions (#318)
### Bug Fixes
* only strip camel case if hyphenated ([#316](https://www.github.com/yargs/yargs-parser/issues/316)) ([95a9e78](https://www.github.com/yargs/yargs-parser/commit/95a9e785127b9bbf2d1db1f1f808ca1fb100e82a)), closes [#315](https://www.github.com/yargs/yargs-parser/issues/315)
### Code Refactoring
* do not ship type definitions ([#318](https://www.github.com/yargs/yargs-parser/issues/318)) ([8fbd56f](https://www.github.com/yargs/yargs-parser/commit/8fbd56f1d0b6c44c30fca62708812151ca0ce330))
### [19.0.4](https://www.github.com/yargs/yargs-parser/compare/v19.0.3...v19.0.4) (2020-08-27)
### Bug Fixes
* **build:** fixing publication ([#310](https://www.github.com/yargs/yargs-parser/issues/310)) ([5d3c6c2](https://www.github.com/yargs/yargs-parser/commit/5d3c6c29a9126248ba601920d9cf87c78e161ff5))
### [19.0.3](https://www.github.com/yargs/yargs-parser/compare/v19.0.2...v19.0.3) (2020-08-27)
### Bug Fixes
* **build:** switch to action for publish ([#308](https://www.github.com/yargs/yargs-parser/issues/308)) ([5c2f305](https://www.github.com/yargs/yargs-parser/commit/5c2f30585342bcd8aaf926407c863099d256d174))
### [19.0.2](https://www.github.com/yargs/yargs-parser/compare/v19.0.1...v19.0.2) (2020-08-27)
### Bug Fixes
* **types:** envPrefix should be optional ([#305](https://www.github.com/yargs/yargs-parser/issues/305)) ([ae3f180](https://www.github.com/yargs/yargs-parser/commit/ae3f180e14df2de2fd962145f4518f9aa0e76523))
### [19.0.1](https://www.github.com/yargs/yargs-parser/compare/v19.0.0...v19.0.1) (2020-08-09)
### Bug Fixes
* **build:** push tag created for deno ([2186a14](https://www.github.com/yargs/yargs-parser/commit/2186a14989749887d56189867602e39e6679f8b0))
## [19.0.0](https://www.github.com/yargs/yargs-parser/compare/v18.1.3...v19.0.0) (2020-08-09)
### ⚠ BREAKING CHANGES
* adds support for ESM and Deno (#295)
* **ts:** projects using `@types/yargs-parser` may see variations in type definitions.
* drops Node 6. begin following Node.js LTS schedule (#278)
### Features
* adds support for ESM and Deno ([#295](https://www.github.com/yargs/yargs-parser/issues/295)) ([195bc4a](https://www.github.com/yargs/yargs-parser/commit/195bc4a7f20c2a8f8e33fbb6ba96ef6e9a0120a1))
* expose camelCase and decamelize helpers ([#296](https://www.github.com/yargs/yargs-parser/issues/296)) ([39154ce](https://www.github.com/yargs/yargs-parser/commit/39154ceb5bdcf76b5f59a9219b34cedb79b67f26))
* **deps:** update to latest camelcase/decamelize ([#281](https://www.github.com/yargs/yargs-parser/issues/281)) ([8931ab0](https://www.github.com/yargs/yargs-parser/commit/8931ab08f686cc55286f33a95a83537da2be5516))
### Bug Fixes
* boolean numeric short option ([#294](https://www.github.com/yargs/yargs-parser/issues/294)) ([f600082](https://www.github.com/yargs/yargs-parser/commit/f600082c959e092076caf420bbbc9d7a231e2418))
* raise permission error for Deno if config load fails ([#298](https://www.github.com/yargs/yargs-parser/issues/298)) ([1174e2b](https://www.github.com/yargs/yargs-parser/commit/1174e2b3f0c845a1cd64e14ffc3703e730567a84))
* **deps:** update dependency decamelize to v3 ([#274](https://www.github.com/yargs/yargs-parser/issues/274)) ([4d98698](https://www.github.com/yargs/yargs-parser/commit/4d98698bc6767e84ec54a0842908191739be73b7))
* **types:** switch back to using Partial types ([#293](https://www.github.com/yargs/yargs-parser/issues/293)) ([bdc80ba](https://www.github.com/yargs/yargs-parser/commit/bdc80ba59fa13bc3025ce0a85e8bad9f9da24ea7))
### Build System
* drops Node 6. begin following Node.js LTS schedule ([#278](https://www.github.com/yargs/yargs-parser/issues/278)) ([9014ed7](https://www.github.com/yargs/yargs-parser/commit/9014ed722a32768b96b829e65a31705db5c1458a))
### Code Refactoring
* **ts:** move index.js to TypeScript ([#292](https://www.github.com/yargs/yargs-parser/issues/292)) ([f78d2b9](https://www.github.com/yargs/yargs-parser/commit/f78d2b97567ac4828624406e420b4047c710b789))
### [18.1.3](https://www.github.com/yargs/yargs-parser/compare/v18.1.2...v18.1.3) (2020-04-16)
### Bug Fixes
* **setArg:** options using camel-case and dot-notation populated twice ([#268](https://www.github.com/yargs/yargs-parser/issues/268)) ([f7e15b9](https://www.github.com/yargs/yargs-parser/commit/f7e15b9800900b9856acac1a830a5f35847be73e))
### [18.1.2](https://www.github.com/yargs/yargs-parser/compare/v18.1.1...v18.1.2) (2020-03-26)
### Bug Fixes
* **array, nargs:** support -o=--value and --option=--value format ([#262](https://www.github.com/yargs/yargs-parser/issues/262)) ([41d3f81](https://www.github.com/yargs/yargs-parser/commit/41d3f8139e116706b28de9b0de3433feb08d2f13))
### [18.1.1](https://www.github.com/yargs/yargs-parser/compare/v18.1.0...v18.1.1) (2020-03-16)
### Bug Fixes
* \_\_proto\_\_ will now be replaced with \_\_\_proto\_\_\_ in parse ([#258](https://www.github.com/yargs/yargs-parser/issues/258)), patching a potential
prototype pollution vulnerability. This was reported by the Snyk Security Research Team.([63810ca](https://www.github.com/yargs/yargs-parser/commit/63810ca1ae1a24b08293a4d971e70e058c7a41e2))
## [18.1.0](https://www.github.com/yargs/yargs-parser/compare/v18.0.0...v18.1.0) (2020-03-07)
### Features
* introduce single-digit boolean aliases ([#255](https://www.github.com/yargs/yargs-parser/issues/255)) ([9c60265](https://www.github.com/yargs/yargs-parser/commit/9c60265fd7a03cb98e6df3e32c8c5e7508d9f56f))
## [18.0.0](https://www.github.com/yargs/yargs-parser/compare/v17.1.0...v18.0.0) (2020-03-02)
### ⚠ BREAKING CHANGES
* the narg count is now enforced when parsing arrays.
### Features
* NaN can now be provided as a value for nargs, indicating "at least" one value is expected for array ([#251](https://www.github.com/yargs/yargs-parser/issues/251)) ([9db4be8](https://www.github.com/yargs/yargs-parser/commit/9db4be81417a2c7097128db34d86fe70ef4af70c))
## [17.1.0](https://www.github.com/yargs/yargs-parser/compare/v17.0.1...v17.1.0) (2020-03-01)
### Features
* introduce greedy-arrays config, for specifying whether arrays consume multiple positionals ([#249](https://www.github.com/yargs/yargs-parser/issues/249)) ([60e880a](https://www.github.com/yargs/yargs-parser/commit/60e880a837046314d89fa4725f923837fd33a9eb))
### [17.0.1](https://www.github.com/yargs/yargs-parser/compare/v17.0.0...v17.0.1) (2020-02-29)
### Bug Fixes
* normalized keys were not enumerable ([#247](https://www.github.com/yargs/yargs-parser/issues/247)) ([57119f9](https://www.github.com/yargs/yargs-parser/commit/57119f9f17cf27499bd95e61c2f72d18314f11ba))
## [17.0.0](https://www.github.com/yargs/yargs-parser/compare/v16.1.0...v17.0.0) (2020-02-10)
### ⚠ BREAKING CHANGES
* this reverts parsing behavior of booleans to that of yargs@14
* objects used during parsing are now created with a null
prototype. There may be some scenarios where this change in behavior
leaks externally.
### Features
* boolean arguments will not be collected into an implicit array ([#236](https://www.github.com/yargs/yargs-parser/issues/236)) ([34c4e19](https://www.github.com/yargs/yargs-parser/commit/34c4e19bae4e7af63e3cb6fa654a97ed476e5eb5))
* introduce nargs-eats-options config option ([#246](https://www.github.com/yargs/yargs-parser/issues/246)) ([d50822a](https://www.github.com/yargs/yargs-parser/commit/d50822ac10e1b05f2e9643671ca131ac251b6732))
### Bug Fixes
* address bugs with "uknown-options-as-args" ([bc023e3](https://www.github.com/yargs/yargs-parser/commit/bc023e3b13e20a118353f9507d1c999bf388a346))
* array should take precedence over nargs, but enforce nargs ([#243](https://www.github.com/yargs/yargs-parser/issues/243)) ([4cbc188](https://www.github.com/yargs/yargs-parser/commit/4cbc188b7abb2249529a19c090338debdad2fe6c))
* support keys that collide with object prototypes ([#234](https://www.github.com/yargs/yargs-parser/issues/234)) ([1587b6d](https://www.github.com/yargs/yargs-parser/commit/1587b6d91db853a9109f1be6b209077993fee4de))
* unknown options terminated with digits now handled by unknown-options-as-args ([#238](https://www.github.com/yargs/yargs-parser/issues/238)) ([d36cdfa](https://www.github.com/yargs/yargs-parser/commit/d36cdfa854254d7c7e0fe1d583818332ac46c2a5))
## [16.1.0](https://www.github.com/yargs/yargs-parser/compare/v16.0.0...v16.1.0) (2019-11-01)
### ⚠ BREAKING CHANGES
* populate error if incompatible narg/count or array/count options are used (#191)
### Features
* options that have had their default value used are now tracked ([#211](https://www.github.com/yargs/yargs-parser/issues/211)) ([a525234](https://www.github.com/yargs/yargs-parser/commit/a525234558c847deedd73f8792e0a3b77b26e2c0))
* populate error if incompatible narg/count or array/count options are used ([#191](https://www.github.com/yargs/yargs-parser/issues/191)) ([84a401f](https://www.github.com/yargs/yargs-parser/commit/84a401f0fa3095e0a19661670d1570d0c3b9d3c9))
### Reverts
* revert 16.0.0 CHANGELOG entry ([920320a](https://www.github.com/yargs/yargs-parser/commit/920320ad9861bbfd58eda39221ae211540fc1daf))
yargs-parser-yargs-parser-v21.0.0/LICENSE.txt 0000664 0000000 0000000 00000001333 14144615712 0020644 0 ustar 00root root 0000000 0000000 Copyright (c) 2016, Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
yargs-parser-yargs-parser-v21.0.0/README.md 0000664 0000000 0000000 00000027214 14144615712 0020306 0 ustar 00root root 0000000 0000000 # yargs-parser

[](https://www.npmjs.com/package/yargs-parser)
[](https://conventionalcommits.org)

The mighty option parser used by [yargs](https://github.com/yargs/yargs).
visit the [yargs website](http://yargs.js.org/) for more examples, and thorough usage instructions.
## Example
```sh
npm i yargs-parser --save
```
```js
const argv = require('yargs-parser')(process.argv.slice(2))
console.log(argv)
```
```console
$ node example.js --foo=33 --bar hello
{ _: [], foo: 33, bar: 'hello' }
```
_or parse a string!_
```js
const argv = require('yargs-parser')('--foo=99 --bar=33')
console.log(argv)
```
```console
{ _: [], foo: 99, bar: 33 }
```
Convert an array of mixed types before passing to `yargs-parser`:
```js
const parse = require('yargs-parser')
parse(['-f', 11, '--zoom', 55].join(' ')) // <-- array to string
parse(['-f', 11, '--zoom', 55].map(String)) // <-- array of strings
```
## Deno Example
As of `v19` `yargs-parser` supports [Deno](https://github.com/denoland/deno):
```typescript
import parser from "https://deno.land/x/yargs_parser/deno.ts";
const argv = parser('--foo=99 --bar=9987930', {
string: ['bar']
})
console.log(argv)
```
## ESM Example
As of `v19` `yargs-parser` supports ESM (_both in Node.js and in the browser_):
**Node.js:**
```js
import parser from 'yargs-parser'
const argv = parser('--foo=99 --bar=9987930', {
string: ['bar']
})
console.log(argv)
```
**Browsers:**
```html
```
## API
### parser(args, opts={})
Parses command line arguments returning a simple mapping of keys and values.
**expects:**
* `args`: a string or array of strings representing the options to parse.
* `opts`: provide a set of hints indicating how `args` should be parsed:
* `opts.alias`: an object representing the set of aliases for a key: `{alias: {foo: ['f']}}`.
* `opts.array`: indicate that keys should be parsed as an array: `{array: ['foo', 'bar']}`.
Indicate that keys should be parsed as an array and coerced to booleans / numbers:
`{array: [{ key: 'foo', boolean: true }, {key: 'bar', number: true}]}`.
* `opts.boolean`: arguments should be parsed as booleans: `{boolean: ['x', 'y']}`.
* `opts.coerce`: provide a custom synchronous function that returns a coerced value from the argument provided
(or throws an error). For arrays the function is called only once for the entire array:
`{coerce: {foo: function (arg) {return modifiedArg}}}`.
* `opts.config`: indicate a key that represents a path to a configuration file (this file will be loaded and parsed).
* `opts.configObjects`: configuration objects to parse, their properties will be set as arguments:
`{configObjects: [{'x': 5, 'y': 33}, {'z': 44}]}`.
* `opts.configuration`: provide configuration options to the yargs-parser (see: [configuration](#configuration)).
* `opts.count`: indicate a key that should be used as a counter, e.g., `-vvv` = `{v: 3}`.
* `opts.default`: provide default values for keys: `{default: {x: 33, y: 'hello world!'}}`.
* `opts.envPrefix`: environment variables (`process.env`) with the prefix provided should be parsed.
* `opts.narg`: specify that a key requires `n` arguments: `{narg: {x: 2}}`.
* `opts.normalize`: `path.normalize()` will be applied to values set to this key.
* `opts.number`: keys should be treated as numbers.
* `opts.string`: keys should be treated as strings (even if they resemble a number `-x 33`).
**returns:**
* `obj`: an object representing the parsed value of `args`
* `key/value`: key value pairs for each argument and their aliases.
* `_`: an array representing the positional arguments.
* [optional] `--`: an array with arguments after the end-of-options flag `--`.
### require('yargs-parser').detailed(args, opts={})
Parses a command line string, returning detailed information required by the
yargs engine.
**expects:**
* `args`: a string or array of strings representing options to parse.
* `opts`: provide a set of hints indicating how `args`, inputs are identical to `require('yargs-parser')(args, opts={})`.
**returns:**
* `argv`: an object representing the parsed value of `args`
* `key/value`: key value pairs for each argument and their aliases.
* `_`: an array representing the positional arguments.
* [optional] `--`: an array with arguments after the end-of-options flag `--`.
* `error`: populated with an error object if an exception occurred during parsing.
* `aliases`: the inferred list of aliases built by combining lists in `opts.alias`.
* `newAliases`: any new aliases added via camel-case expansion:
* `boolean`: `{ fooBar: true }`
* `defaulted`: any new argument created by `opts.default`, no aliases included.
* `boolean`: `{ foo: true }`
* `configuration`: given by default settings and `opts.configuration`.
### Configuration
The yargs-parser applies several automated transformations on the keys provided
in `args`. These features can be turned on and off using the `configuration` field
of `opts`.
```js
var parsed = parser(['--no-dice'], {
configuration: {
'boolean-negation': false
}
})
```
### short option groups
* default: `true`.
* key: `short-option-groups`.
Should a group of short-options be treated as boolean flags?
```console
$ node example.js -abc
{ _: [], a: true, b: true, c: true }
```
_if disabled:_
```console
$ node example.js -abc
{ _: [], abc: true }
```
### camel-case expansion
* default: `true`.
* key: `camel-case-expansion`.
Should hyphenated arguments be expanded into camel-case aliases?
```console
$ node example.js --foo-bar
{ _: [], 'foo-bar': true, fooBar: true }
```
_if disabled:_
```console
$ node example.js --foo-bar
{ _: [], 'foo-bar': true }
```
### dot-notation
* default: `true`
* key: `dot-notation`
Should keys that contain `.` be treated as objects?
```console
$ node example.js --foo.bar
{ _: [], foo: { bar: true } }
```
_if disabled:_
```console
$ node example.js --foo.bar
{ _: [], "foo.bar": true }
```
### parse numbers
* default: `true`
* key: `parse-numbers`
Should keys that look like numbers be treated as such?
```console
$ node example.js --foo=99.3
{ _: [], foo: 99.3 }
```
_if disabled:_
```console
$ node example.js --foo=99.3
{ _: [], foo: "99.3" }
```
### parse positional numbers
* default: `true`
* key: `parse-positional-numbers`
Should positional keys that look like numbers be treated as such.
```console
$ node example.js 99.3
{ _: [99.3] }
```
_if disabled:_
```console
$ node example.js 99.3
{ _: ['99.3'] }
```
### boolean negation
* default: `true`
* key: `boolean-negation`
Should variables prefixed with `--no` be treated as negations?
```console
$ node example.js --no-foo
{ _: [], foo: false }
```
_if disabled:_
```console
$ node example.js --no-foo
{ _: [], "no-foo": true }
```
### combine arrays
* default: `false`
* key: `combine-arrays`
Should arrays be combined when provided by both command line arguments and
a configuration file.
### duplicate arguments array
* default: `true`
* key: `duplicate-arguments-array`
Should arguments be coerced into an array when duplicated:
```console
$ node example.js -x 1 -x 2
{ _: [], x: [1, 2] }
```
_if disabled:_
```console
$ node example.js -x 1 -x 2
{ _: [], x: 2 }
```
### flatten duplicate arrays
* default: `true`
* key: `flatten-duplicate-arrays`
Should array arguments be coerced into a single array when duplicated:
```console
$ node example.js -x 1 2 -x 3 4
{ _: [], x: [1, 2, 3, 4] }
```
_if disabled:_
```console
$ node example.js -x 1 2 -x 3 4
{ _: [], x: [[1, 2], [3, 4]] }
```
### greedy arrays
* default: `true`
* key: `greedy-arrays`
Should arrays consume more than one positional argument following their flag.
```console
$ node example --arr 1 2
{ _: [], arr: [1, 2] }
```
_if disabled:_
```console
$ node example --arr 1 2
{ _: [2], arr: [1] }
```
**Note: in `v18.0.0` we are considering defaulting greedy arrays to `false`.**
### nargs eats options
* default: `false`
* key: `nargs-eats-options`
Should nargs consume dash options as well as positional arguments.
### negation prefix
* default: `no-`
* key: `negation-prefix`
The prefix to use for negated boolean variables.
```console
$ node example.js --no-foo
{ _: [], foo: false }
```
_if set to `quux`:_
```console
$ node example.js --quuxfoo
{ _: [], foo: false }
```
### populate --
* default: `false`.
* key: `populate--`
Should unparsed flags be stored in `--` or `_`.
_If disabled:_
```console
$ node example.js a -b -- x y
{ _: [ 'a', 'x', 'y' ], b: true }
```
_If enabled:_
```console
$ node example.js a -b -- x y
{ _: [ 'a' ], '--': [ 'x', 'y' ], b: true }
```
### set placeholder key
* default: `false`.
* key: `set-placeholder-key`.
Should a placeholder be added for keys not set via the corresponding CLI argument?
_If disabled:_
```console
$ node example.js -a 1 -c 2
{ _: [], a: 1, c: 2 }
```
_If enabled:_
```console
$ node example.js -a 1 -c 2
{ _: [], a: 1, b: undefined, c: 2 }
```
### halt at non-option
* default: `false`.
* key: `halt-at-non-option`.
Should parsing stop at the first positional argument? This is similar to how e.g. `ssh` parses its command line.
_If disabled:_
```console
$ node example.js -a run b -x y
{ _: [ 'b' ], a: 'run', x: 'y' }
```
_If enabled:_
```console
$ node example.js -a run b -x y
{ _: [ 'b', '-x', 'y' ], a: 'run' }
```
### strip aliased
* default: `false`
* key: `strip-aliased`
Should aliases be removed before returning results?
_If disabled:_
```console
$ node example.js --test-field 1
{ _: [], 'test-field': 1, testField: 1, 'test-alias': 1, testAlias: 1 }
```
_If enabled:_
```console
$ node example.js --test-field 1
{ _: [], 'test-field': 1, testField: 1 }
```
### strip dashed
* default: `false`
* key: `strip-dashed`
Should dashed keys be removed before returning results? This option has no effect if
`camel-case-expansion` is disabled.
_If disabled:_
```console
$ node example.js --test-field 1
{ _: [], 'test-field': 1, testField: 1 }
```
_If enabled:_
```console
$ node example.js --test-field 1
{ _: [], testField: 1 }
```
### unknown options as args
* default: `false`
* key: `unknown-options-as-args`
Should unknown options be treated like regular arguments? An unknown option is one that is not
configured in `opts`.
_If disabled_
```console
$ node example.js --unknown-option --known-option 2 --string-option --unknown-option2
{ _: [], unknownOption: true, knownOption: 2, stringOption: '', unknownOption2: true }
```
_If enabled_
```console
$ node example.js --unknown-option --known-option 2 --string-option --unknown-option2
{ _: ['--unknown-option'], knownOption: 2, stringOption: '--unknown-option2' }
```
## Supported Node.js Versions
Libraries in this ecosystem make a best effort to track
[Node.js' release schedule](https://nodejs.org/en/about/releases/). Here's [a
post on why we think this is important](https://medium.com/the-node-js-collection/maintainers-should-consider-following-node-js-release-schedule-ab08ed4de71a).
## Special Thanks
The yargs project evolves from optimist and minimist. It owes its
existence to a lot of James Halliday's hard work. Thanks [substack](https://github.com/substack) **beep** **boop** \o/
## License
ISC
yargs-parser-yargs-parser-v21.0.0/browser.js 0000664 0000000 0000000 00000001770 14144615712 0021047 0 ustar 00root root 0000000 0000000 // Main entrypoint for ESM web browser environments. Avoids using Node.js
// specific libraries, such as "path".
//
// TODO: figure out reasonable web equivalents for "resolve", "normalize", etc.
import { camelCase, decamelize, looksLikeNumber } from './build/lib/string-utils.js'
import { YargsParser } from './build/lib/yargs-parser.js'
const parser = new YargsParser({
cwd: () => { return '' },
format: (str, arg) => { return str.replace('%s', arg) },
normalize: (str) => { return str },
resolve: (str) => { return str },
require: () => {
throw Error('loading config from files not currently supported in browser')
},
env: () => {}
})
const yargsParser = function Parser (args, opts) {
const result = parser.parse(args.slice(), opts)
return result.argv
}
yargsParser.detailed = function (args, opts) {
return parser.parse(args.slice(), opts)
}
yargsParser.camelCase = camelCase
yargsParser.decamelize = decamelize
yargsParser.looksLikeNumber = looksLikeNumber
export default yargsParser
yargs-parser-yargs-parser-v21.0.0/deno.ts 0000664 0000000 0000000 00000002460 14144615712 0020320 0 ustar 00root root 0000000 0000000 /* global Deno */
// Main entrypoint for Deno.
//
// TODO: find reasonable replacement for require logic.
import * as path from 'https://deno.land/std/path/mod.ts'
import { camelCase, decamelize, looksLikeNumber } from './build/lib/string-utils.js'
import { YargsParser } from './build/lib/yargs-parser.js'
import type { Arguments, ArgsInput, Parser, Options, DetailedArguments } from './build/lib/yargs-parser-types.d.ts'
const parser = new YargsParser({
cwd: Deno.cwd,
env: () => {
Deno.env.toObject()
},
format: (str: string, arg: string) => { return str.replace('%s', arg) },
normalize: path.posix.normalize,
resolve: path.posix.resolve,
require: (path: string) => {
if (!path.match(/\.json$/)) {
throw Error('only .json config files are supported in Deno')
} else {
return JSON.parse(Deno.readTextFileSync(path))
}
}
})
const yargsParser: Parser = function Parser (args: ArgsInput, opts?: Partial): Arguments {
const result = parser.parse(args.slice(), opts)
return result.argv
}
yargsParser.detailed = function (args: ArgsInput, opts?: Partial): DetailedArguments {
return parser.parse(args.slice(), opts)
}
yargsParser.camelCase = camelCase
yargsParser.decamelize = decamelize
yargsParser.looksLikeNumber = looksLikeNumber
export default yargsParser
yargs-parser-yargs-parser-v21.0.0/docs/ 0000775 0000000 0000000 00000000000 14144615712 0017751 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/docs/CHANGELOG-full.md 0000664 0000000 0000000 00000046157 14144615712 0022537 0 ustar 00root root 0000000 0000000 ## [15.0.0](https://github.com/yargs/yargs-parser/compare/v14.0.0...v15.0.0) (2019-10-07)
### Features
* rework `collect-unknown-options` into `unknown-options-as-args`, providing more comprehensive functionality ([ef771ca](https://github.com/yargs/yargs-parser/commit/ef771ca))
### BREAKING CHANGES
* rework `collect-unknown-options` into `unknown-options-as-args`, providing more comprehensive functionality
## [14.0.0](https://github.com/yargs/yargs-parser/compare/v13.1.1...v14.0.0) (2019-09-06)
### Bug Fixes
* boolean arrays with default values ([#185](https://github.com/yargs/yargs-parser/issues/185)) ([7d42572](https://github.com/yargs/yargs-parser/commit/7d42572))
* boolean now behaves the same as other array types ([#184](https://github.com/yargs/yargs-parser/issues/184)) ([17ca3bd](https://github.com/yargs/yargs-parser/commit/17ca3bd))
* eatNargs() for 'opt.narg === 0' and boolean typed options ([#188](https://github.com/yargs/yargs-parser/issues/188)) ([c5a1db0](https://github.com/yargs/yargs-parser/commit/c5a1db0))
* maybeCoerceNumber now takes precedence over coerce return value ([#182](https://github.com/yargs/yargs-parser/issues/182)) ([2f26436](https://github.com/yargs/yargs-parser/commit/2f26436))
* take into account aliases when appending arrays from config object ([#199](https://github.com/yargs/yargs-parser/issues/199)) ([f8a2d3f](https://github.com/yargs/yargs-parser/commit/f8a2d3f))
### Features
* add configuration option to "collect-unknown-options" ([#181](https://github.com/yargs/yargs-parser/issues/181)) ([7909cc4](https://github.com/yargs/yargs-parser/commit/7909cc4))
* maybeCoerceNumber() now takes into account arrays ([#187](https://github.com/yargs/yargs-parser/issues/187)) ([31c204b](https://github.com/yargs/yargs-parser/commit/31c204b))
### BREAKING CHANGES
* unless "parse-numbers" is set to "false", arrays of numeric strings are now parsed as numbers, rather than strings.
* we have dropped the broken "defaulted" functionality; we would like to revisit adding this in the future.
* maybeCoerceNumber now takes precedence over coerce return value (#182)
### [13.1.1](https://www.github.com/yargs/yargs-parser/compare/v13.1.0...v13.1.1) (2019-06-10)
### Bug Fixes
* convert values to strings when tokenizing ([#167](https://www.github.com/yargs/yargs-parser/issues/167)) ([57b7883](https://www.github.com/yargs/yargs-parser/commit/57b7883))
* nargs should allow duplicates when duplicate-arguments-array=false ([#164](https://www.github.com/yargs/yargs-parser/issues/164)) ([47ccb0b](https://www.github.com/yargs/yargs-parser/commit/47ccb0b))
* should populate "_" when given config with "short-option-groups" false ([#179](https://www.github.com/yargs/yargs-parser/issues/179)) ([6055974](https://www.github.com/yargs/yargs-parser/commit/6055974))
## [13.1.0](https://github.com/yargs/yargs-parser/compare/v13.0.0...v13.1.0) (2019-05-05)
### Features
* add `strip-aliased` and `strip-dashed` configuration options. ([#172](https://github.com/yargs/yargs-parser/issues/172)) ([a3936aa](https://github.com/yargs/yargs-parser/commit/a3936aa))
* support boolean which do not consume next argument. ([#171](https://github.com/yargs/yargs-parser/issues/171)) ([0ae7fcb](https://github.com/yargs/yargs-parser/commit/0ae7fcb))
# [13.0.0](https://github.com/yargs/yargs-parser/compare/v12.0.0...v13.0.0) (2019-02-02)
### Features
* don't coerce number from string with leading '0' or '+' ([#158](https://github.com/yargs/yargs-parser/issues/158)) ([18d0fd5](https://github.com/yargs/yargs-parser/commit/18d0fd5))
### BREAKING CHANGES
* options with leading '+' or '0' now parse as strings
# [12.0.0](https://github.com/yargs/yargs-parser/compare/v11.1.1...v12.0.0) (2019-01-29)
### Bug Fixes
* better handling of quoted strings ([#153](https://github.com/yargs/yargs-parser/issues/153)) ([2fb71b2](https://github.com/yargs/yargs-parser/commit/2fb71b2))
### Features
* default value is now used if no right-hand value provided for numbers/strings ([#156](https://github.com/yargs/yargs-parser/issues/156)) ([5a7c46a](https://github.com/yargs/yargs-parser/commit/5a7c46a))
### BREAKING CHANGES
* a flag with no right-hand value no longer populates defaulted options with `undefined`.
* quotes at beginning and endings of strings are not removed during parsing.
## [11.1.1](https://github.com/yargs/yargs-parser/compare/v11.1.0...v11.1.1) (2018-11-19)
### Bug Fixes
* ensure empty string is added into argv._ ([#140](https://github.com/yargs/yargs-parser/issues/140)) ([79cda98](https://github.com/yargs/yargs-parser/commit/79cda98))
### Reverts
* make requiresArg work in conjunction with arrays ([#136](https://github.com/yargs/yargs-parser/issues/136)) ([f4a3063](https://github.com/yargs/yargs-parser/commit/f4a3063))
# [11.1.0](https://github.com/yargs/yargs-parser/compare/v11.0.0...v11.1.0) (2018-11-10)
### Bug Fixes
* handling of one char alias ([#139](https://github.com/yargs/yargs-parser/issues/139)) ([ee56e31](https://github.com/yargs/yargs-parser/commit/ee56e31))
### Features
* add halt-at-non-option configuration option ([#130](https://github.com/yargs/yargs-parser/issues/130)) ([a849fce](https://github.com/yargs/yargs-parser/commit/a849fce))
# [11.0.0](https://github.com/yargs/yargs-parser/compare/v10.1.0...v11.0.0) (2018-10-06)
### Bug Fixes
* flatten-duplicate-arrays:false for more than 2 arrays ([#128](https://github.com/yargs/yargs-parser/issues/128)) ([2bc395f](https://github.com/yargs/yargs-parser/commit/2bc395f))
* hyphenated flags combined with dot notation broke parsing ([#131](https://github.com/yargs/yargs-parser/issues/131)) ([dc788da](https://github.com/yargs/yargs-parser/commit/dc788da))
* make requiresArg work in conjunction with arrays ([#136](https://github.com/yargs/yargs-parser/issues/136)) ([77ae1d4](https://github.com/yargs/yargs-parser/commit/77ae1d4))
### Chores
* update dependencies ([6dc42a1](https://github.com/yargs/yargs-parser/commit/6dc42a1))
### Features
* also add camelCase array options ([#125](https://github.com/yargs/yargs-parser/issues/125)) ([08c0117](https://github.com/yargs/yargs-parser/commit/08c0117))
* array.type can now be provided, supporting coercion ([#132](https://github.com/yargs/yargs-parser/issues/132)) ([4b8cfce](https://github.com/yargs/yargs-parser/commit/4b8cfce))
### BREAKING CHANGES
* drops Node 4 support
* the argv object is now populated differently (correctly) when hyphens and dot notation are used in conjunction.
# [10.1.0](https://github.com/yargs/yargs-parser/compare/v10.0.0...v10.1.0) (2018-06-29)
### Features
* add `set-placeholder-key` configuration ([#123](https://github.com/yargs/yargs-parser/issues/123)) ([19386ee](https://github.com/yargs/yargs-parser/commit/19386ee))
# [10.0.0](https://github.com/yargs/yargs-parser/compare/v9.0.2...v10.0.0) (2018-04-04)
### Bug Fixes
* do not set boolean flags if not defined in `argv` ([#119](https://github.com/yargs/yargs-parser/issues/119)) ([f6e6599](https://github.com/yargs/yargs-parser/commit/f6e6599))
### BREAKING CHANGES
* `boolean` flags defined without a `default` value will now behave like other option type and won't be set in the parsed results when the user doesn't set the corresponding CLI arg.
Previous behavior:
```js
var parse = require('yargs-parser');
parse('--flag', {boolean: ['flag']});
// => { _: [], flag: true }
parse('--no-flag', {boolean: ['flag']});
// => { _: [], flag: false }
parse('', {boolean: ['flag']});
// => { _: [], flag: false }
```
New behavior:
```js
var parse = require('yargs-parser');
parse('--flag', {boolean: ['flag']});
// => { _: [], flag: true }
parse('--no-flag', {boolean: ['flag']});
// => { _: [], flag: false }
parse('', {boolean: ['flag']});
// => { _: [] } => flag not set similarly to other option type
```
## [9.0.2](https://github.com/yargs/yargs-parser/compare/v9.0.1...v9.0.2) (2018-01-20)
### Bug Fixes
* nargs was still aggressively consuming too many arguments ([9b28aad](https://github.com/yargs/yargs-parser/commit/9b28aad))
## [9.0.1](https://github.com/yargs/yargs-parser/compare/v9.0.0...v9.0.1) (2018-01-20)
### Bug Fixes
* nargs was consuming too many arguments ([4fef206](https://github.com/yargs/yargs-parser/commit/4fef206))
# [9.0.0](https://github.com/yargs/yargs-parser/compare/v8.1.0...v9.0.0) (2018-01-20)
### Features
* narg arguments no longer consume flag arguments ([#114](https://github.com/yargs/yargs-parser/issues/114)) ([60bb9b3](https://github.com/yargs/yargs-parser/commit/60bb9b3))
### BREAKING CHANGES
* arguments of form --foo, -abc, will no longer be consumed by nargs
# [8.1.0](https://github.com/yargs/yargs-parser/compare/v8.0.0...v8.1.0) (2017-12-20)
### Bug Fixes
* allow null config values ([#108](https://github.com/yargs/yargs-parser/issues/108)) ([d8b14f9](https://github.com/yargs/yargs-parser/commit/d8b14f9))
* ensure consistent parsing of dot-notation arguments ([#102](https://github.com/yargs/yargs-parser/issues/102)) ([c9bd79c](https://github.com/yargs/yargs-parser/commit/c9bd79c))
* implement [@antoniom](https://github.com/antoniom)'s fix for camel-case expansion ([3087e1d](https://github.com/yargs/yargs-parser/commit/3087e1d))
* only run coercion functions once, despite aliases. ([#76](https://github.com/yargs/yargs-parser/issues/76)) ([#103](https://github.com/yargs/yargs-parser/issues/103)) ([507aaef](https://github.com/yargs/yargs-parser/commit/507aaef))
* scientific notation circumvented bounds check ([#110](https://github.com/yargs/yargs-parser/issues/110)) ([3571f57](https://github.com/yargs/yargs-parser/commit/3571f57))
* tokenizer should ignore spaces at the beginning of the argString ([#106](https://github.com/yargs/yargs-parser/issues/106)) ([f34ead9](https://github.com/yargs/yargs-parser/commit/f34ead9))
### Features
* make combining arrays a configurable option ([#111](https://github.com/yargs/yargs-parser/issues/111)) ([c8bf536](https://github.com/yargs/yargs-parser/commit/c8bf536))
* merge array from arguments with array from config ([#83](https://github.com/yargs/yargs-parser/issues/83)) ([806ddd6](https://github.com/yargs/yargs-parser/commit/806ddd6))
# [8.0.0](https://github.com/yargs/yargs-parser/compare/v7.0.0...v8.0.0) (2017-10-05)
### Bug Fixes
* Ignore multiple spaces between arguments. ([#100](https://github.com/yargs/yargs-parser/issues/100)) ([d137227](https://github.com/yargs/yargs-parser/commit/d137227))
### Features
* allow configuration of prefix for boolean negation ([#94](https://github.com/yargs/yargs-parser/issues/94)) ([00bde7d](https://github.com/yargs/yargs-parser/commit/00bde7d))
* reworking how numbers are parsed ([#104](https://github.com/yargs/yargs-parser/issues/104)) ([fba00eb](https://github.com/yargs/yargs-parser/commit/fba00eb))
### BREAKING CHANGES
* strings that fail `Number.isSafeInteger()` are no longer coerced into numbers.
# [7.0.0](https://github.com/yargs/yargs-parser/compare/v6.0.1...v7.0.0) (2017-05-02)
### Chores
* revert populate-- logic ([#91](https://github.com/yargs/yargs-parser/issues/91)) ([6003e6d](https://github.com/yargs/yargs-parser/commit/6003e6d))
### BREAKING CHANGES
* populate-- now defaults to false.
## [6.0.1](https://github.com/yargs/yargs-parser/compare/v6.0.0...v6.0.1) (2017-05-01)
### Bug Fixes
* default '--' to undefined when not provided; this is closer to the array API ([#90](https://github.com/yargs/yargs-parser/issues/90)) ([4e739cc](https://github.com/yargs/yargs-parser/commit/4e739cc))
# [6.0.0](https://github.com/yargs/yargs-parser/compare/v4.2.1...v6.0.0) (2017-05-01)
### Bug Fixes
* environment variables should take precedence over config file ([#81](https://github.com/yargs/yargs-parser/issues/81)) ([76cee1f](https://github.com/yargs/yargs-parser/commit/76cee1f))
* parsing hints should apply for dot notation keys ([#86](https://github.com/yargs/yargs-parser/issues/86)) ([3e47d62](https://github.com/yargs/yargs-parser/commit/3e47d62))
### Chores
* upgrade to newest version of camelcase ([#87](https://github.com/yargs/yargs-parser/issues/87)) ([f1903aa](https://github.com/yargs/yargs-parser/commit/f1903aa))
### Features
* add -- option which allows arguments after the -- flag to be returned separated from positional arguments ([#84](https://github.com/yargs/yargs-parser/issues/84)) ([2572ca8](https://github.com/yargs/yargs-parser/commit/2572ca8))
* when parsing stops, we now populate "--" by default ([#88](https://github.com/yargs/yargs-parser/issues/88)) ([cd666db](https://github.com/yargs/yargs-parser/commit/cd666db))
### BREAKING CHANGES
* rather than placing arguments in "_", when parsing is stopped via "--"; we now populate an array called "--" by default.
* camelcase now requires Node 4+.
* environment variables will now override config files (args, env, config-file, config-object)
# [5.0.0](https://github.com/yargs/yargs-parser/compare/v4.2.1...v5.0.0) (2017-02-18)
### Bug Fixes
* environment variables should take precedence over config file ([#81](https://github.com/yargs/yargs-parser/issues/81)) ([76cee1f](https://github.com/yargs/yargs-parser/commit/76cee1f))
### BREAKING CHANGES
* environment variables will now override config files (args, env, config-file, config-object)
## [4.2.1](https://github.com/yargs/yargs-parser/compare/v4.2.0...v4.2.1) (2017-01-02)
### Bug Fixes
* flatten/duplicate regression ([#75](https://github.com/yargs/yargs-parser/issues/75)) ([68d68a0](https://github.com/yargs/yargs-parser/commit/68d68a0))
# [4.2.0](https://github.com/yargs/yargs-parser/compare/v4.1.0...v4.2.0) (2016-12-01)
### Bug Fixes
* inner objects in configs had their keys appended to top-level key when dot-notation was disabled ([#72](https://github.com/yargs/yargs-parser/issues/72)) ([0b1b5f9](https://github.com/yargs/yargs-parser/commit/0b1b5f9))
### Features
* allow multiple arrays to be provided, rather than always combining ([#71](https://github.com/yargs/yargs-parser/issues/71)) ([0f0fb2d](https://github.com/yargs/yargs-parser/commit/0f0fb2d))
# [4.1.0](https://github.com/yargs/yargs-parser/compare/v4.0.2...v4.1.0) (2016-11-07)
### Features
* apply coercions to default options ([#65](https://github.com/yargs/yargs-parser/issues/65)) ([c79052b](https://github.com/yargs/yargs-parser/commit/c79052b))
* handle dot notation boolean options ([#63](https://github.com/yargs/yargs-parser/issues/63)) ([02c3545](https://github.com/yargs/yargs-parser/commit/02c3545))
## [4.0.2](https://github.com/yargs/yargs-parser/compare/v4.0.1...v4.0.2) (2016-09-30)
### Bug Fixes
* whoops, let's make the assign not change the Object key order ([29d069a](https://github.com/yargs/yargs-parser/commit/29d069a))
## [4.0.1](https://github.com/yargs/yargs-parser/compare/v4.0.0...v4.0.1) (2016-09-30)
### Bug Fixes
* lodash.assign was deprecated ([#59](https://github.com/yargs/yargs-parser/issues/59)) ([5e7eb11](https://github.com/yargs/yargs-parser/commit/5e7eb11))
# [4.0.0](https://github.com/yargs/yargs-parser/compare/v3.2.0...v4.0.0) (2016-09-26)
### Bug Fixes
* coerce should be applied to the final objects and arrays created ([#57](https://github.com/yargs/yargs-parser/issues/57)) ([4ca69da](https://github.com/yargs/yargs-parser/commit/4ca69da))
### BREAKING CHANGES
* coerce is no longer applied to individual arguments in an implicit array.
# [3.2.0](https://github.com/yargs/yargs-parser/compare/v3.1.0...v3.2.0) (2016-08-13)
### Features
* coerce full array instead of each element ([#51](https://github.com/yargs/yargs-parser/issues/51)) ([cc4dc56](https://github.com/yargs/yargs-parser/commit/cc4dc56))
# [3.1.0](https://github.com/yargs/yargs-parser/compare/v3.0.0...v3.1.0) (2016-08-09)
### Bug Fixes
* address pkgConf parsing bug outlined in [#37](https://github.com/yargs/yargs-parser/issues/37) ([#45](https://github.com/yargs/yargs-parser/issues/45)) ([be76ee6](https://github.com/yargs/yargs-parser/commit/be76ee6))
* better parsing of negative values ([#44](https://github.com/yargs/yargs-parser/issues/44)) ([2e43692](https://github.com/yargs/yargs-parser/commit/2e43692))
* check aliases when guessing defaults for arguments fixes [#41](https://github.com/yargs/yargs-parser/issues/41) ([#43](https://github.com/yargs/yargs-parser/issues/43)) ([f3e4616](https://github.com/yargs/yargs-parser/commit/f3e4616))
### Features
* added coerce option, for providing specialized argument parsing ([#42](https://github.com/yargs/yargs-parser/issues/42)) ([7b49cd2](https://github.com/yargs/yargs-parser/commit/7b49cd2))
# [3.0.0](https://github.com/yargs/yargs-parser/compare/v2.4.1...v3.0.0) (2016-08-07)
### Bug Fixes
* parsing issue with numeric character in group of options ([#19](https://github.com/yargs/yargs-parser/issues/19)) ([f743236](https://github.com/yargs/yargs-parser/commit/f743236))
* upgraded lodash.assign ([5d7fdf4](https://github.com/yargs/yargs-parser/commit/5d7fdf4))
### BREAKING CHANGES
* subtle change to how values are parsed in a group of single-character arguments.
* _first released in 3.1.0, better handling of negative values should be considered a breaking change._
## [2.4.1](https://github.com/yargs/yargs-parser/compare/v2.4.0...v2.4.1) (2016-07-16)
### Bug Fixes
* **count:** do not increment a default value ([#39](https://github.com/yargs/yargs-parser/issues/39)) ([b04a189](https://github.com/yargs/yargs-parser/commit/b04a189))
# [2.4.0](https://github.com/yargs/yargs-parser/compare/v2.3.0...v2.4.0) (2016-04-11)
### Features
* **environment:** Support nested options in environment variables ([#26](https://github.com/yargs/yargs-parser/issues/26)) thanks [@elas7](https://github.com/elas7) \o/ ([020778b](https://github.com/yargs/yargs-parser/commit/020778b))
# [2.3.0](https://github.com/yargs/yargs-parser/compare/v2.2.0...v2.3.0) (2016-04-09)
### Bug Fixes
* **boolean:** fix for boolean options with non boolean defaults (#20) ([2dbe86b](https://github.com/yargs/yargs-parser/commit/2dbe86b)), closes [(#20](https://github.com/(/issues/20)
* **package:** remove tests from tarball ([0353c0d](https://github.com/yargs/yargs-parser/commit/0353c0d))
* **parsing:** handle calling short option with an empty string as the next value. ([a867165](https://github.com/yargs/yargs-parser/commit/a867165))
* boolean flag when next value contains the strings 'true' or 'false'. ([69941a6](https://github.com/yargs/yargs-parser/commit/69941a6))
* update dependencies; add standard-version bin for next release (#24) ([822d9d5](https://github.com/yargs/yargs-parser/commit/822d9d5))
### Features
* **configuration:** Allow to pass configuration objects to yargs-parser ([0780900](https://github.com/yargs/yargs-parser/commit/0780900))
* **normalize:** allow normalize to work with arrays ([e0eaa1a](https://github.com/yargs/yargs-parser/commit/e0eaa1a))
yargs-parser-yargs-parser-v21.0.0/lib/ 0000775 0000000 0000000 00000000000 14144615712 0017567 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/lib/index.ts 0000664 0000000 0000000 00000004425 14144615712 0021253 0 ustar 00root root 0000000 0000000 /**
* @fileoverview Main entrypoint for libraries using yargs-parser in Node.js
* CJS and ESM environments.
*
* @license
* Copyright (c) 2016, Contributors
* SPDX-License-Identifier: ISC
*/
import { format } from 'util'
import { normalize, resolve } from 'path'
import { ArgsInput, Arguments, Parser, Options, DetailedArguments } from './yargs-parser-types.js'
import { camelCase, decamelize, looksLikeNumber } from './string-utils.js'
import { YargsParser } from './yargs-parser.js'
import { readFileSync } from 'fs'
// See https://github.com/yargs/yargs-parser#supported-nodejs-versions for our
// version support policy. The YARGS_MIN_NODE_VERSION is used for testing only.
const minNodeVersion = (process && process.env && process.env.YARGS_MIN_NODE_VERSION)
? Number(process.env.YARGS_MIN_NODE_VERSION)
: 12
if (process && process.version) {
const major = Number(process.version.match(/v([^.]+)/)![1])
if (major < minNodeVersion) {
throw Error(`yargs parser supports a minimum Node.js version of ${minNodeVersion}. Read our version support policy: https://github.com/yargs/yargs-parser#supported-nodejs-versions`)
}
}
// Creates a yargs-parser instance using Node.js standard libraries:
const env = process ? process.env as { [key: string]: string } : {}
const parser = new YargsParser({
cwd: process.cwd,
env: () => {
return env
},
format,
normalize,
resolve,
// TODO: figure out a way to combine ESM and CJS coverage, such that
// we can exercise all the lines below:
require: (path: string) => {
if (typeof require !== 'undefined') {
return require(path)
} else if (path.match(/\.json$/)) {
// Addresses: https://github.com/yargs/yargs/issues/2040
return JSON.parse(readFileSync(path, 'utf8'))
} else {
throw Error('only .json config files are supported in ESM')
}
}
})
const yargsParser: Parser = function Parser (args: ArgsInput, opts?: Partial): Arguments {
const result = parser.parse(args.slice(), opts)
return result.argv
}
yargsParser.detailed = function (args: ArgsInput, opts?: Partial): DetailedArguments {
return parser.parse(args.slice(), opts)
}
yargsParser.camelCase = camelCase
yargsParser.decamelize = decamelize
yargsParser.looksLikeNumber = looksLikeNumber
export default yargsParser
yargs-parser-yargs-parser-v21.0.0/lib/string-utils.ts 0000664 0000000 0000000 00000003601 14144615712 0022603 0 ustar 00root root 0000000 0000000 /**
* @license
* Copyright (c) 2016, Contributors
* SPDX-License-Identifier: ISC
*/
export function camelCase (str: string): string {
// Handle the case where an argument is provided as camel case, e.g., fooBar.
// by ensuring that the string isn't already mixed case:
const isCamelCase = str !== str.toLowerCase() && str !== str.toUpperCase()
if (!isCamelCase) {
str = str.toLowerCase()
}
if (str.indexOf('-') === -1 && str.indexOf('_') === -1) {
return str
} else {
let camelcase = ''
let nextChrUpper = false
const leadingHyphens = str.match(/^-+/)
for (let i = leadingHyphens ? leadingHyphens[0].length : 0; i < str.length; i++) {
let chr = str.charAt(i)
if (nextChrUpper) {
nextChrUpper = false
chr = chr.toUpperCase()
}
if (i !== 0 && (chr === '-' || chr === '_')) {
nextChrUpper = true
} else if (chr !== '-' && chr !== '_') {
camelcase += chr
}
}
return camelcase
}
}
export function decamelize (str: string, joinString?: string): string {
const lowercase = str.toLowerCase()
joinString = joinString || '-'
let notCamelcase = ''
for (let i = 0; i < str.length; i++) {
const chrLower = lowercase.charAt(i)
const chrString = str.charAt(i)
if (chrLower !== chrString && i > 0) {
notCamelcase += `${joinString}${lowercase.charAt(i)}`
} else {
notCamelcase += chrString
}
}
return notCamelcase
}
export function looksLikeNumber (x: null | undefined | number | string): boolean {
if (x === null || x === undefined) return false
// if loaded from config, may already be a number.
if (typeof x === 'number') return true
// hexadecimal.
if (/^0x[0-9a-f]+$/i.test(x)) return true
// don't treat 0123 as a number; as it drops the leading '0'.
if (/^0[^.]/.test(x)) return false
return /^[-]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x)
}
yargs-parser-yargs-parser-v21.0.0/lib/tokenize-arg-string.ts 0000664 0000000 0000000 00000002012 14144615712 0024035 0 ustar 00root root 0000000 0000000 /**
* @license
* Copyright (c) 2016, Contributors
* SPDX-License-Identifier: ISC
*/
// take an un-split argv string and tokenize it.
export function tokenizeArgString (argString: string | any[]): string[] {
if (Array.isArray(argString)) {
return argString.map(e => typeof e !== 'string' ? e + '' : e)
}
argString = argString.trim()
let i = 0
let prevC: string | null = null
let c: string | null = null
let opening: string | null = null
const args: string[] = []
for (let ii = 0; ii < argString.length; ii++) {
prevC = c
c = argString.charAt(ii)
// split on spaces unless we're in quotes.
if (c === ' ' && !opening) {
if (!(prevC === ' ')) {
i++
}
continue
}
// don't split the string if we're in matching
// opening or closing single and double quotes.
if (c === opening) {
opening = null
} else if ((c === "'" || c === '"') && !opening) {
opening = c
}
if (!args[i]) args[i] = ''
args[i] += c
}
return args
}
yargs-parser-yargs-parser-v21.0.0/lib/yargs-parser-types.ts 0000664 0000000 0000000 00000017422 14144615712 0023726 0 ustar 00root root 0000000 0000000 /**
* @license
* Copyright (c) 2016, Contributors
* SPDX-License-Identifier: ISC
*/
/**
* An object whose all properties have the same type, where each key is a string.
*/
export interface Dictionary {
[key: string]: T;
}
/**
* Returns the keys of T.
*/
export type KeyOf = {
[K in keyof T]: string extends K ? never : number extends K ? never : K
} extends { [_ in keyof T]: infer U } ? U : never;
/**
* Returns the type of a Dictionary or array values.
*/
export type ValueOf = T extends (infer U)[] ? U : T[keyof T];
export type ArgsInput = string | any[];
export type ArgsOutput = (string | number)[];
export interface Arguments {
/** Non-option arguments */
_: ArgsOutput;
/** Arguments after the end-of-options flag `--` */
'--'?: ArgsOutput;
/** All remaining options */
[argName: string]: any;
}
export interface DetailedArguments {
/** An object representing the parsed value of `args` */
argv: Arguments;
/** Populated with an error object if an exception occurred during parsing. */
error: Error | null;
/** The inferred list of aliases built by combining lists in opts.alias. */
aliases: Dictionary;
/** Any new aliases added via camel-case expansion. */
newAliases: Dictionary;
/** Any new argument created by opts.default, no aliases included. */
defaulted: Dictionary;
/** The configuration loaded from the yargs stanza in package.json. */
configuration: Configuration;
}
export interface Configuration {
/** Should variables prefixed with --no be treated as negations? Default is `true` */
'boolean-negation': boolean;
/** Should hyphenated arguments be expanded into camel-case aliases? Default is `true` */
'camel-case-expansion': boolean;
/** Should arrays be combined when provided by both command line arguments and a configuration file? Default is `false` */
'combine-arrays': boolean;
/** Should keys that contain `.` be treated as objects? Default is `true` */
'dot-notation': boolean;
/** Should arguments be coerced into an array when duplicated? Default is `true` */
'duplicate-arguments-array': boolean;
/** Should array arguments be coerced into a single array when duplicated? Default is `true` */
'flatten-duplicate-arrays': boolean;
/** Should arrays consume more than one positional argument following their flag? Default is `true` */
'greedy-arrays': boolean;
/** Should parsing stop at the first text argument? This is similar to how e.g. ssh parses its command line. Default is `false` */
'halt-at-non-option': boolean;
/** Should nargs consume dash options as well as positional arguments? Default is `false` */
'nargs-eats-options': boolean;
/** The prefix to use for negated boolean variables. Default is `'no-'` */
'negation-prefix': string;
/** Should positional values that look like numbers be parsed? Default is `true` */
'parse-positional-numbers': boolean;
/** Should keys that look like numbers be treated as such? Default is `true` */
'parse-numbers': boolean;
/** Should unparsed flags be stored in -- or _? Default is `false` */
'populate--': boolean;
/** Should a placeholder be added for keys not set via the corresponding CLI argument? Default is `false` */
'set-placeholder-key': boolean;
/** Should a group of short-options be treated as boolean flags? Default is `true` */
'short-option-groups': boolean;
/** Should aliases be removed before returning results? Default is `false` */
'strip-aliased': boolean;
/** Should dashed keys be removed before returning results? This option has no effect if camel-case-expansion is disabled. Default is `false` */
'strip-dashed': boolean;
/** Should unknown options be treated like regular arguments? An unknown option is one that is not configured in opts. Default is `false` */
'unknown-options-as-args': boolean;
}
export type ArrayOption = string | { key: string; boolean?: boolean, string?: boolean, number?: boolean, integer?: boolean };
export type CoerceCallback = (arg: any) => any;
export type ConfigCallback = (configPath: string) => { [key: string]: any } | Error;
export interface Options {
/** An object representing the set of aliases for a key: `{ alias: { foo: ['f']} }`. */
alias: Dictionary;
/**
* Indicate that keys should be parsed as an array: `{ array: ['foo', 'bar'] }`.
* Indicate that keys should be parsed as an array and coerced to booleans / numbers:
* { array: [ { key: 'foo', boolean: true }, {key: 'bar', number: true} ] }`.
*/
array: ArrayOption | ArrayOption[];
/** Arguments should be parsed as booleans: `{ boolean: ['x', 'y'] }`. */
boolean: string | string[];
/** Indicate a key that represents a path to a configuration file (this file will be loaded and parsed). */
config: string | string[] | Dictionary;
/** configuration objects to parse, their properties will be set as arguments */
configObjects: Dictionary[];
/** Provide configuration options to the yargs-parser. */
configuration: Partial;
/**
* Provide a custom synchronous function that returns a coerced value from the argument provided (or throws an error), e.g.
* `{ coerce: { foo: function (arg) { return modifiedArg } } }`.
*/
coerce: Dictionary;
/** Indicate a key that should be used as a counter, e.g., `-vvv = {v: 3}`. */
count: string | string[];
/** Provide default values for keys: `{ default: { x: 33, y: 'hello world!' } }`. */
default: Dictionary;
/** Environment variables (`process.env`) with the prefix provided should be parsed. */
envPrefix?: string;
/** Specify that a key requires n arguments: `{ narg: {x: 2} }`. */
narg: Dictionary;
/** `path.normalize()` will be applied to values set to this key. */
normalize: string | string[];
/** Keys should be treated as strings (even if they resemble a number `-x 33`). */
string: string | string[];
/** Keys should be treated as numbers. */
number: string | string[];
/** i18n handler, defaults to util.format */
__: (format: any, ...param: any[]) => string;
/** alias lookup table defaults */
key: Dictionary;
}
export interface YargsParserMixin {
cwd: Function;
format: Function;
normalize: Function;
require: Function;
resolve: Function;
env: Function;
}
export type OptionsDefault = ValueOf, 'default'>>;
export interface Parser {
(args: ArgsInput, opts?: Partial): Arguments;
detailed(args: ArgsInput, opts?: Partial): DetailedArguments;
camelCase(str: string): string;
decamelize(str: string, joinString?: string): string;
looksLikeNumber(x: null | undefined | number | string): boolean;
}
export type StringFlag = Dictionary;
export type BooleanFlag = Dictionary;
export type NumberFlag = Dictionary;
export type ConfigsFlag = Dictionary;
export type CoercionsFlag = Dictionary;
export type KeysFlag = string[];
export interface Flags {
aliases: StringFlag;
arrays: BooleanFlag;
bools: BooleanFlag;
strings: BooleanFlag;
numbers: BooleanFlag;
counts: BooleanFlag;
normalize: BooleanFlag;
configs: ConfigsFlag;
nargs: NumberFlag;
coercions: CoercionsFlag;
keys: KeysFlag;
}
export type Flag = ValueOf>;
export type FlagValue = ValueOf;
export type FlagsKey = KeyOf>;
export type ArrayFlagsKey = Extract;
export enum DefaultValuesForTypeKey {
BOOLEAN = 'boolean',
STRING = 'string',
NUMBER = 'number',
ARRAY = 'array',
}
export interface DefaultValuesForType {
[DefaultValuesForTypeKey.BOOLEAN]: boolean;
[DefaultValuesForTypeKey.STRING]: string;
[DefaultValuesForTypeKey.NUMBER]: undefined;
[DefaultValuesForTypeKey.ARRAY]: any[];
}
yargs-parser-yargs-parser-v21.0.0/lib/yargs-parser.ts 0000664 0000000 0000000 00000117663 14144615712 0022574 0 ustar 00root root 0000000 0000000 /**
* @license
* Copyright (c) 2016, Contributors
* SPDX-License-Identifier: ISC
*/
import { tokenizeArgString } from './tokenize-arg-string.js'
import type {
ArgsInput,
Arguments,
ArrayFlagsKey,
ArrayOption,
CoerceCallback,
Configuration,
DefaultValuesForType,
DetailedArguments,
Dictionary,
Flag,
Flags,
FlagsKey,
StringFlag,
BooleanFlag,
NumberFlag,
ConfigsFlag,
CoercionsFlag,
Options,
OptionsDefault,
ValueOf,
YargsParserMixin
} from './yargs-parser-types.js'
import { DefaultValuesForTypeKey } from './yargs-parser-types.js'
import { camelCase, decamelize, looksLikeNumber } from './string-utils.js'
let mixin: YargsParserMixin
export class YargsParser {
constructor (_mixin: YargsParserMixin) {
mixin = _mixin
}
parse (argsInput: ArgsInput, options?: Partial): DetailedArguments {
const opts: Partial = Object.assign({
alias: undefined,
array: undefined,
boolean: undefined,
config: undefined,
configObjects: undefined,
configuration: undefined,
coerce: undefined,
count: undefined,
default: undefined,
envPrefix: undefined,
narg: undefined,
normalize: undefined,
string: undefined,
number: undefined,
__: undefined,
key: undefined
}, options)
// allow a string argument to be passed in rather
// than an argv array.
const args = tokenizeArgString(argsInput)
// tokenizeArgString adds extra quotes to args if argsInput is a string
// only strip those extra quotes in processValue if argsInput is a string
const inputIsString = typeof argsInput === 'string'
// aliases might have transitive relationships, normalize this.
const aliases = combineAliases(Object.assign(Object.create(null), opts.alias))
const configuration: Configuration = Object.assign({
'boolean-negation': true,
'camel-case-expansion': true,
'combine-arrays': false,
'dot-notation': true,
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': true,
'greedy-arrays': true,
'halt-at-non-option': false,
'nargs-eats-options': false,
'negation-prefix': 'no-',
'parse-numbers': true,
'parse-positional-numbers': true,
'populate--': false,
'set-placeholder-key': false,
'short-option-groups': true,
'strip-aliased': false,
'strip-dashed': false,
'unknown-options-as-args': false
}, opts.configuration)
const defaults: OptionsDefault = Object.assign(Object.create(null), opts.default)
const configObjects = opts.configObjects || []
const envPrefix = opts.envPrefix
const notFlagsOption = configuration['populate--']
const notFlagsArgv: string = notFlagsOption ? '--' : '_'
const newAliases: Dictionary = Object.create(null)
const defaulted: Dictionary = Object.create(null)
// allow a i18n handler to be passed in, default to a fake one (util.format).
const __ = opts.__ || mixin.format
const flags: Flags = {
aliases: Object.create(null),
arrays: Object.create(null),
bools: Object.create(null),
strings: Object.create(null),
numbers: Object.create(null),
counts: Object.create(null),
normalize: Object.create(null),
configs: Object.create(null),
nargs: Object.create(null),
coercions: Object.create(null),
keys: []
}
const negative = /^-([0-9]+(\.[0-9]+)?|\.[0-9]+)$/
const negatedBoolean = new RegExp('^--' + configuration['negation-prefix'] + '(.+)')
;([] as ArrayOption[]).concat(opts.array || []).filter(Boolean).forEach(function (opt) {
const key = typeof opt === 'object' ? opt.key : opt
// assign to flags[bools|strings|numbers]
const assignment: ArrayFlagsKey | undefined = Object.keys(opt).map(function (key) {
const arrayFlagKeys: Record = {
boolean: 'bools',
string: 'strings',
number: 'numbers'
}
return arrayFlagKeys[key]
}).filter(Boolean).pop()
// assign key to be coerced
if (assignment) {
flags[assignment][key] = true
}
flags.arrays[key] = true
flags.keys.push(key)
})
;([] as string[]).concat(opts.boolean || []).filter(Boolean).forEach(function (key) {
flags.bools[key] = true
flags.keys.push(key)
})
;([] as string[]).concat(opts.string || []).filter(Boolean).forEach(function (key) {
flags.strings[key] = true
flags.keys.push(key)
})
;([] as string[]).concat(opts.number || []).filter(Boolean).forEach(function (key) {
flags.numbers[key] = true
flags.keys.push(key)
})
;([] as string[]).concat(opts.count || []).filter(Boolean).forEach(function (key) {
flags.counts[key] = true
flags.keys.push(key)
})
;([] as string[]).concat(opts.normalize || []).filter(Boolean).forEach(function (key) {
flags.normalize[key] = true
flags.keys.push(key)
})
if (typeof opts.narg === 'object') {
Object.entries(opts.narg).forEach(([key, value]) => {
if (typeof value === 'number') {
flags.nargs[key] = value
flags.keys.push(key)
}
})
}
if (typeof opts.coerce === 'object') {
Object.entries(opts.coerce).forEach(([key, value]) => {
if (typeof value === 'function') {
flags.coercions[key] = value
flags.keys.push(key)
}
})
}
if (typeof opts.config !== 'undefined') {
if (Array.isArray(opts.config) || typeof opts.config === 'string') {
;([] as string[]).concat(opts.config).filter(Boolean).forEach(function (key) {
flags.configs[key] = true
})
} else if (typeof opts.config === 'object') {
Object.entries(opts.config).forEach(([key, value]) => {
if (typeof value === 'boolean' || typeof value === 'function') {
flags.configs[key] = value
}
})
}
}
// create a lookup table that takes into account all
// combinations of aliases: {f: ['foo'], foo: ['f']}
extendAliases(opts.key, aliases, opts.default, flags.arrays)
// apply default values to all aliases.
Object.keys(defaults).forEach(function (key) {
(flags.aliases[key] || []).forEach(function (alias) {
defaults[alias] = defaults[key]
})
})
let error: Error | null = null
checkConfiguration()
let notFlags: string[] = []
const argv: Arguments = Object.assign(Object.create(null), { _: [] })
// TODO(bcoe): for the first pass at removing object prototype we didn't
// remove all prototypes from objects returned by this API, we might want
// to gradually move towards doing so.
const argvReturn: { [argName: string]: any } = {}
for (let i = 0; i < args.length; i++) {
const arg = args[i]
const truncatedArg = arg.replace(/^-{3,}/, '---')
let broken: boolean
let key: string | undefined
let letters: string[]
let m: RegExpMatchArray | null
let next: string
let value: string
// any unknown option (except for end-of-options, "--")
if (arg !== '--' && isUnknownOptionAsArg(arg)) {
pushPositional(arg)
// ---, ---=, ----, etc,
} else if (truncatedArg.match(/---+(=|$)/)) {
// options without key name are invalid.
pushPositional(arg)
continue
// -- separated by =
} else if (arg.match(/^--.+=/) || (
!configuration['short-option-groups'] && arg.match(/^-.+=/)
)) {
// Using [\s\S] instead of . because js doesn't support the
// 'dotall' regex modifier. See:
// http://stackoverflow.com/a/1068308/13216
m = arg.match(/^--?([^=]+)=([\s\S]*)$/)
// arrays format = '--f=a b c'
if (m !== null && Array.isArray(m) && m.length >= 3) {
if (checkAllAliases(m[1], flags.arrays)) {
i = eatArray(i, m[1], args, m[2])
} else if (checkAllAliases(m[1], flags.nargs) !== false) {
// nargs format = '--f=monkey washing cat'
i = eatNargs(i, m[1], args, m[2])
} else {
setArg(m[1], m[2], true)
}
}
} else if (arg.match(negatedBoolean) && configuration['boolean-negation']) {
m = arg.match(negatedBoolean)
if (m !== null && Array.isArray(m) && m.length >= 2) {
key = m[1]
setArg(key, checkAllAliases(key, flags.arrays) ? [false] : false)
}
// -- separated by space.
} else if (arg.match(/^--.+/) || (
!configuration['short-option-groups'] && arg.match(/^-[^-]+/)
)) {
m = arg.match(/^--?(.+)/)
if (m !== null && Array.isArray(m) && m.length >= 2) {
key = m[1]
if (checkAllAliases(key, flags.arrays)) {
// array format = '--foo a b c'
i = eatArray(i, key, args)
} else if (checkAllAliases(key, flags.nargs) !== false) {
// nargs format = '--foo a b c'
// should be truthy even if: flags.nargs[key] === 0
i = eatNargs(i, key, args)
} else {
next = args[i + 1]
if (next !== undefined && (!next.match(/^-/) ||
next.match(negative)) &&
!checkAllAliases(key, flags.bools) &&
!checkAllAliases(key, flags.counts)) {
setArg(key, next)
i++
} else if (/^(true|false)$/.test(next)) {
setArg(key, next)
i++
} else {
setArg(key, defaultValue(key))
}
}
}
// dot-notation flag separated by '='.
} else if (arg.match(/^-.\..+=/)) {
m = arg.match(/^-([^=]+)=([\s\S]*)$/)
if (m !== null && Array.isArray(m) && m.length >= 3) {
setArg(m[1], m[2])
}
// dot-notation flag separated by space.
} else if (arg.match(/^-.\..+/) && !arg.match(negative)) {
next = args[i + 1]
m = arg.match(/^-(.\..+)/)
if (m !== null && Array.isArray(m) && m.length >= 2) {
key = m[1]
if (next !== undefined && !next.match(/^-/) &&
!checkAllAliases(key, flags.bools) &&
!checkAllAliases(key, flags.counts)) {
setArg(key, next)
i++
} else {
setArg(key, defaultValue(key))
}
}
} else if (arg.match(/^-[^-]+/) && !arg.match(negative)) {
letters = arg.slice(1, -1).split('')
broken = false
for (let j = 0; j < letters.length; j++) {
next = arg.slice(j + 2)
if (letters[j + 1] && letters[j + 1] === '=') {
value = arg.slice(j + 3)
key = letters[j]
if (checkAllAliases(key, flags.arrays)) {
// array format = '-f=a b c'
i = eatArray(i, key, args, value)
} else if (checkAllAliases(key, flags.nargs) !== false) {
// nargs format = '-f=monkey washing cat'
i = eatNargs(i, key, args, value)
} else {
setArg(key, value)
}
broken = true
break
}
if (next === '-') {
setArg(letters[j], next)
continue
}
// current letter is an alphabetic character and next value is a number
if (/[A-Za-z]/.test(letters[j]) &&
/^-?\d+(\.\d*)?(e-?\d+)?$/.test(next) &&
checkAllAliases(next, flags.bools) === false) {
setArg(letters[j], next)
broken = true
break
}
if (letters[j + 1] && letters[j + 1].match(/\W/)) {
setArg(letters[j], next)
broken = true
break
} else {
setArg(letters[j], defaultValue(letters[j]))
}
}
key = arg.slice(-1)[0]
if (!broken && key !== '-') {
if (checkAllAliases(key, flags.arrays)) {
// array format = '-f a b c'
i = eatArray(i, key, args)
} else if (checkAllAliases(key, flags.nargs) !== false) {
// nargs format = '-f a b c'
// should be truthy even if: flags.nargs[key] === 0
i = eatNargs(i, key, args)
} else {
next = args[i + 1]
if (next !== undefined && (!/^(-|--)[^-]/.test(next) ||
next.match(negative)) &&
!checkAllAliases(key, flags.bools) &&
!checkAllAliases(key, flags.counts)) {
setArg(key, next)
i++
} else if (/^(true|false)$/.test(next)) {
setArg(key, next)
i++
} else {
setArg(key, defaultValue(key))
}
}
}
} else if (arg.match(/^-[0-9]$/) &&
arg.match(negative) &&
checkAllAliases(arg.slice(1), flags.bools)) {
// single-digit boolean alias, e.g: xargs -0
key = arg.slice(1)
setArg(key, defaultValue(key))
} else if (arg === '--') {
notFlags = args.slice(i + 1)
break
} else if (configuration['halt-at-non-option']) {
notFlags = args.slice(i)
break
} else {
pushPositional(arg)
}
}
// order of precedence:
// 1. command line arg
// 2. value from env var
// 3. value from config file
// 4. value from config objects
// 5. configured default value
applyEnvVars(argv, true) // special case: check env vars that point to config file
applyEnvVars(argv, false)
setConfig(argv)
setConfigObjects()
applyDefaultsAndAliases(argv, flags.aliases, defaults, true)
applyCoercions(argv)
if (configuration['set-placeholder-key']) setPlaceholderKeys(argv)
// for any counts either not in args or without an explicit default, set to 0
Object.keys(flags.counts).forEach(function (key) {
if (!hasKey(argv, key.split('.'))) setArg(key, 0)
})
// '--' defaults to undefined.
if (notFlagsOption && notFlags.length) argv[notFlagsArgv] = []
notFlags.forEach(function (key) {
argv[notFlagsArgv].push(key)
})
if (configuration['camel-case-expansion'] && configuration['strip-dashed']) {
Object.keys(argv).filter(key => key !== '--' && key.includes('-')).forEach(key => {
delete argv[key]
})
}
if (configuration['strip-aliased']) {
;([] as string[]).concat(...Object.keys(aliases).map(k => aliases[k])).forEach(alias => {
if (configuration['camel-case-expansion'] && alias.includes('-')) {
delete argv[alias.split('.').map(prop => camelCase(prop)).join('.')]
}
delete argv[alias]
})
}
// Push argument into positional array, applying numeric coercion:
function pushPositional (arg: string) {
const maybeCoercedNumber = maybeCoerceNumber('_', arg)
if (typeof maybeCoercedNumber === 'string' || typeof maybeCoercedNumber === 'number') {
argv._.push(maybeCoercedNumber)
}
}
// how many arguments should we consume, based
// on the nargs option?
function eatNargs (i: number, key: string, args: string[], argAfterEqualSign?: string): number {
let ii
let toEat = checkAllAliases(key, flags.nargs)
// NaN has a special meaning for the array type, indicating that one or
// more values are expected.
toEat = typeof toEat !== 'number' || isNaN(toEat) ? 1 : toEat
if (toEat === 0) {
if (!isUndefined(argAfterEqualSign)) {
error = Error(__('Argument unexpected for: %s', key))
}
setArg(key, defaultValue(key))
return i
}
let available = isUndefined(argAfterEqualSign) ? 0 : 1
if (configuration['nargs-eats-options']) {
// classic behavior, yargs eats positional and dash arguments.
if (args.length - (i + 1) + available < toEat) {
error = Error(__('Not enough arguments following: %s', key))
}
available = toEat
} else {
// nargs will not consume flag arguments, e.g., -abc, --foo,
// and terminates when one is observed.
for (ii = i + 1; ii < args.length; ii++) {
if (!args[ii].match(/^-[^0-9]/) || args[ii].match(negative) || isUnknownOptionAsArg(args[ii])) available++
else break
}
if (available < toEat) error = Error(__('Not enough arguments following: %s', key))
}
let consumed = Math.min(available, toEat)
if (!isUndefined(argAfterEqualSign) && consumed > 0) {
setArg(key, argAfterEqualSign)
consumed--
}
for (ii = i + 1; ii < (consumed + i + 1); ii++) {
setArg(key, args[ii])
}
return (i + consumed)
}
// if an option is an array, eat all non-hyphenated arguments
// following it... YUM!
// e.g., --foo apple banana cat becomes ["apple", "banana", "cat"]
function eatArray (i: number, key: string, args: string[], argAfterEqualSign?: string): number {
let argsToSet = []
let next = argAfterEqualSign || args[i + 1]
// If both array and nargs are configured, enforce the nargs count:
const nargsCount = checkAllAliases(key, flags.nargs)
if (checkAllAliases(key, flags.bools) && !(/^(true|false)$/.test(next))) {
argsToSet.push(true)
} else if (isUndefined(next) ||
(isUndefined(argAfterEqualSign) && /^-/.test(next) && !negative.test(next) && !isUnknownOptionAsArg(next))) {
// for keys without value ==> argsToSet remains an empty []
// set user default value, if available
if (defaults[key] !== undefined) {
const defVal = defaults[key]
argsToSet = Array.isArray(defVal) ? defVal : [defVal]
}
} else {
// value in --option=value is eaten as is
if (!isUndefined(argAfterEqualSign)) {
argsToSet.push(processValue(key, argAfterEqualSign, true))
}
for (let ii = i + 1; ii < args.length; ii++) {
if ((!configuration['greedy-arrays'] && argsToSet.length > 0) ||
(nargsCount && typeof nargsCount === 'number' && argsToSet.length >= nargsCount)) break
next = args[ii]
if (/^-/.test(next) && !negative.test(next) && !isUnknownOptionAsArg(next)) break
i = ii
argsToSet.push(processValue(key, next, inputIsString))
}
}
// If both array and nargs are configured, create an error if less than
// nargs positionals were found. NaN has special meaning, indicating
// that at least one value is required (more are okay).
if (typeof nargsCount === 'number' && ((nargsCount && argsToSet.length < nargsCount) ||
(isNaN(nargsCount) && argsToSet.length === 0))) {
error = Error(__('Not enough arguments following: %s', key))
}
setArg(key, argsToSet)
return i
}
function setArg (key: string, val: any, shouldStripQuotes: boolean = inputIsString): void {
if (/-/.test(key) && configuration['camel-case-expansion']) {
const alias = key.split('.').map(function (prop) {
return camelCase(prop)
}).join('.')
addNewAlias(key, alias)
}
const value = processValue(key, val, shouldStripQuotes)
const splitKey = key.split('.')
setKey(argv, splitKey, value)
// handle populating aliases of the full key
if (flags.aliases[key]) {
flags.aliases[key].forEach(function (x) {
const keyProperties = x.split('.')
setKey(argv, keyProperties, value)
})
}
// handle populating aliases of the first element of the dot-notation key
if (splitKey.length > 1 && configuration['dot-notation']) {
;(flags.aliases[splitKey[0]] || []).forEach(function (x) {
let keyProperties = x.split('.')
// expand alias with nested objects in key
const a = ([] as string[]).concat(splitKey)
a.shift() // nuke the old key.
keyProperties = keyProperties.concat(a)
// populate alias only if is not already an alias of the full key
// (already populated above)
if (!(flags.aliases[key] || []).includes(keyProperties.join('.'))) {
setKey(argv, keyProperties, value)
}
})
}
// Set normalize getter and setter when key is in 'normalize' but isn't an array
if (checkAllAliases(key, flags.normalize) && !checkAllAliases(key, flags.arrays)) {
const keys = [key].concat(flags.aliases[key] || [])
keys.forEach(function (key) {
Object.defineProperty(argvReturn, key, {
enumerable: true,
get () {
return val
},
set (value) {
val = typeof value === 'string' ? mixin.normalize(value) : value
}
})
})
}
}
function addNewAlias (key: string, alias: string): void {
if (!(flags.aliases[key] && flags.aliases[key].length)) {
flags.aliases[key] = [alias]
newAliases[alias] = true
}
if (!(flags.aliases[alias] && flags.aliases[alias].length)) {
addNewAlias(alias, key)
}
}
function processValue (key: string, val: any, shouldStripQuotes: boolean) {
// strings may be quoted, clean this up as we assign values.
if (shouldStripQuotes) {
val = stripQuotes(val)
}
// handle parsing boolean arguments --foo=true --bar false.
if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) {
if (typeof val === 'string') val = val === 'true'
}
let value = Array.isArray(val)
? val.map(function (v) { return maybeCoerceNumber(key, v) })
: maybeCoerceNumber(key, val)
// increment a count given as arg (either no value or value parsed as boolean)
if (checkAllAliases(key, flags.counts) && (isUndefined(value) || typeof value === 'boolean')) {
value = increment()
}
// Set normalized value when key is in 'normalize' and in 'arrays'
if (checkAllAliases(key, flags.normalize) && checkAllAliases(key, flags.arrays)) {
if (Array.isArray(val)) value = val.map((val) => { return mixin.normalize(val) })
else value = mixin.normalize(val)
}
return value
}
function maybeCoerceNumber (key: string, value: string | number | null | undefined) {
if (!configuration['parse-positional-numbers'] && key === '_') return value
if (!checkAllAliases(key, flags.strings) && !checkAllAliases(key, flags.bools) && !Array.isArray(value)) {
const shouldCoerceNumber = looksLikeNumber(value) && configuration['parse-numbers'] && (
Number.isSafeInteger(Math.floor(parseFloat(`${value}`)))
)
if (shouldCoerceNumber || (!isUndefined(value) && checkAllAliases(key, flags.numbers))) {
value = Number(value)
}
}
return value
}
// set args from config.json file, this should be
// applied last so that defaults can be applied.
function setConfig (argv: Arguments): void {
const configLookup = Object.create(null)
// expand defaults/aliases, in-case any happen to reference
// the config.json file.
applyDefaultsAndAliases(configLookup, flags.aliases, defaults)
Object.keys(flags.configs).forEach(function (configKey) {
const configPath = argv[configKey] || configLookup[configKey]
if (configPath) {
try {
let config = null
const resolvedConfigPath = mixin.resolve(mixin.cwd(), configPath)
const resolveConfig = flags.configs[configKey]
if (typeof resolveConfig === 'function') {
try {
config = resolveConfig(resolvedConfigPath)
} catch (e) {
config = e
}
if (config instanceof Error) {
error = config
return
}
} else {
config = mixin.require(resolvedConfigPath)
}
setConfigObject(config)
} catch (ex: any) {
// Deno will receive a PermissionDenied error if an attempt is
// made to load config without the --allow-read flag:
if (ex.name === 'PermissionDenied') error = ex
else if (argv[configKey]) error = Error(__('Invalid JSON config file: %s', configPath))
}
}
})
}
// set args from config object.
// it recursively checks nested objects.
function setConfigObject (config: { [key: string]: any }, prev?: string): void {
Object.keys(config).forEach(function (key) {
const value = config[key]
const fullKey = prev ? prev + '.' + key : key
// if the value is an inner object and we have dot-notation
// enabled, treat inner objects in config the same as
// heavily nested dot notations (foo.bar.apple).
if (typeof value === 'object' && value !== null && !Array.isArray(value) && configuration['dot-notation']) {
// if the value is an object but not an array, check nested object
setConfigObject(value, fullKey)
} else {
// setting arguments via CLI takes precedence over
// values within the config file.
if (!hasKey(argv, fullKey.split('.')) || (checkAllAliases(fullKey, flags.arrays) && configuration['combine-arrays'])) {
setArg(fullKey, value)
}
}
})
}
// set all config objects passed in opts
function setConfigObjects (): void {
if (typeof configObjects !== 'undefined') {
configObjects.forEach(function (configObject) {
setConfigObject(configObject)
})
}
}
function applyEnvVars (argv: Arguments, configOnly: boolean): void {
if (typeof envPrefix === 'undefined') return
const prefix = typeof envPrefix === 'string' ? envPrefix : ''
const env = mixin.env()
Object.keys(env).forEach(function (envVar) {
if (prefix === '' || envVar.lastIndexOf(prefix, 0) === 0) {
// get array of nested keys and convert them to camel case
const keys = envVar.split('__').map(function (key, i) {
if (i === 0) {
key = key.substring(prefix.length)
}
return camelCase(key)
})
if (((configOnly && flags.configs[keys.join('.')]) || !configOnly) && !hasKey(argv, keys)) {
setArg(keys.join('.'), env[envVar])
}
}
})
}
function applyCoercions (argv: Arguments): void {
let coerce: false | CoerceCallback
const applied: Set = new Set()
Object.keys(argv).forEach(function (key) {
if (!applied.has(key)) { // If we haven't already coerced this option via one of its aliases
coerce = checkAllAliases(key, flags.coercions)
if (typeof coerce === 'function') {
try {
const value = maybeCoerceNumber(key, coerce(argv[key]))
;(([] as string[]).concat(flags.aliases[key] || [], key)).forEach(ali => {
applied.add(ali)
argv[ali] = value
})
} catch (err) {
error = err as Error
}
}
}
})
}
function setPlaceholderKeys (argv: Arguments): Arguments {
flags.keys.forEach((key) => {
// don't set placeholder keys for dot notation options 'foo.bar'.
if (~key.indexOf('.')) return
if (typeof argv[key] === 'undefined') argv[key] = undefined
})
return argv
}
function applyDefaultsAndAliases (obj: { [key: string]: any }, aliases: { [key: string]: string[] }, defaults: { [key: string]: any }, canLog: boolean = false): void {
Object.keys(defaults).forEach(function (key) {
if (!hasKey(obj, key.split('.'))) {
setKey(obj, key.split('.'), defaults[key])
if (canLog) defaulted[key] = true
;(aliases[key] || []).forEach(function (x) {
if (hasKey(obj, x.split('.'))) return
setKey(obj, x.split('.'), defaults[key])
})
}
})
}
function hasKey (obj: { [key: string]: any }, keys: string[]): boolean {
let o = obj
if (!configuration['dot-notation']) keys = [keys.join('.')]
keys.slice(0, -1).forEach(function (key) {
o = (o[key] || {})
})
const key = keys[keys.length - 1]
if (typeof o !== 'object') return false
else return key in o
}
function setKey (obj: { [key: string]: any }, keys: string[], value: any): void {
let o = obj
if (!configuration['dot-notation']) keys = [keys.join('.')]
keys.slice(0, -1).forEach(function (key) {
// TODO(bcoe): in the next major version of yargs, switch to
// Object.create(null) for dot notation:
key = sanitizeKey(key)
if (typeof o === 'object' && o[key] === undefined) {
o[key] = {}
}
if (typeof o[key] !== 'object' || Array.isArray(o[key])) {
// ensure that o[key] is an array, and that the last item is an empty object.
if (Array.isArray(o[key])) {
o[key].push({})
} else {
o[key] = [o[key], {}]
}
// we want to update the empty object at the end of the o[key] array, so set o to that object
o = o[key][o[key].length - 1]
} else {
o = o[key]
}
})
// TODO(bcoe): in the next major version of yargs, switch to
// Object.create(null) for dot notation:
const key = sanitizeKey(keys[keys.length - 1])
const isTypeArray = checkAllAliases(keys.join('.'), flags.arrays)
const isValueArray = Array.isArray(value)
let duplicate = configuration['duplicate-arguments-array']
// nargs has higher priority than duplicate
if (!duplicate && checkAllAliases(key, flags.nargs)) {
duplicate = true
if ((!isUndefined(o[key]) && flags.nargs[key] === 1) || (Array.isArray(o[key]) && o[key].length === flags.nargs[key])) {
o[key] = undefined
}
}
if (value === increment()) {
o[key] = increment(o[key])
} else if (Array.isArray(o[key])) {
if (duplicate && isTypeArray && isValueArray) {
o[key] = configuration['flatten-duplicate-arrays'] ? o[key].concat(value) : (Array.isArray(o[key][0]) ? o[key] : [o[key]]).concat([value])
} else if (!duplicate && Boolean(isTypeArray) === Boolean(isValueArray)) {
o[key] = value
} else {
o[key] = o[key].concat([value])
}
} else if (o[key] === undefined && isTypeArray) {
o[key] = isValueArray ? value : [value]
} else if (duplicate && !(
o[key] === undefined ||
checkAllAliases(key, flags.counts) ||
checkAllAliases(key, flags.bools)
)) {
o[key] = [o[key], value]
} else {
o[key] = value
}
}
// extend the aliases list with inferred aliases.
function extendAliases (...args: Array<{ [key: string]: any } | undefined>) {
args.forEach(function (obj) {
Object.keys(obj || {}).forEach(function (key) {
// short-circuit if we've already added a key
// to the aliases array, for example it might
// exist in both 'opts.default' and 'opts.key'.
if (flags.aliases[key]) return
flags.aliases[key] = ([] as string[]).concat(aliases[key] || [])
// For "--option-name", also set argv.optionName
flags.aliases[key].concat(key).forEach(function (x) {
if (/-/.test(x) && configuration['camel-case-expansion']) {
const c = camelCase(x)
if (c !== key && flags.aliases[key].indexOf(c) === -1) {
flags.aliases[key].push(c)
newAliases[c] = true
}
}
})
// For "--optionName", also set argv['option-name']
flags.aliases[key].concat(key).forEach(function (x) {
if (x.length > 1 && /[A-Z]/.test(x) && configuration['camel-case-expansion']) {
const c = decamelize(x, '-')
if (c !== key && flags.aliases[key].indexOf(c) === -1) {
flags.aliases[key].push(c)
newAliases[c] = true
}
}
})
flags.aliases[key].forEach(function (x) {
flags.aliases[x] = [key].concat(flags.aliases[key].filter(function (y) {
return x !== y
}))
})
})
})
}
// return the 1st set flag for any of a key's aliases (or false if no flag set)
function checkAllAliases (key: string, flag: StringFlag): ValueOf | false
function checkAllAliases (key: string, flag: BooleanFlag): ValueOf | false
function checkAllAliases (key: string, flag: NumberFlag): ValueOf | false
function checkAllAliases (key: string, flag: ConfigsFlag): ValueOf | false
function checkAllAliases (key: string, flag: CoercionsFlag): ValueOf | false
function checkAllAliases (key: string, flag: Flag): ValueOf | false {
const toCheck = ([] as string[]).concat(flags.aliases[key] || [], key)
const keys = Object.keys(flag)
const setAlias = toCheck.find(key => keys.includes(key))
return setAlias ? flag[setAlias] : false
}
function hasAnyFlag (key: string): boolean {
const flagsKeys = Object.keys(flags) as FlagsKey[]
const toCheck = ([] as Array<{ [key: string]: any } | string[]>).concat(flagsKeys.map(k => flags[k]))
return toCheck.some(function (flag) {
return Array.isArray(flag) ? flag.includes(key) : flag[key]
})
}
function hasFlagsMatching (arg: string, ...patterns: RegExp[]): boolean {
const toCheck = ([] as RegExp[]).concat(...patterns)
return toCheck.some(function (pattern) {
const match = arg.match(pattern)
return match && hasAnyFlag(match[1])
})
}
// based on a simplified version of the short flag group parsing logic
function hasAllShortFlags (arg: string): boolean {
// if this is a negative number, or doesn't start with a single hyphen, it's not a short flag group
if (arg.match(negative) || !arg.match(/^-[^-]+/)) { return false }
let hasAllFlags = true
let next: string
const letters = arg.slice(1).split('')
for (let j = 0; j < letters.length; j++) {
next = arg.slice(j + 2)
if (!hasAnyFlag(letters[j])) {
hasAllFlags = false
break
}
if ((letters[j + 1] && letters[j + 1] === '=') ||
next === '-' ||
(/[A-Za-z]/.test(letters[j]) && /^-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) ||
(letters[j + 1] && letters[j + 1].match(/\W/))) {
break
}
}
return hasAllFlags
}
function isUnknownOptionAsArg (arg: string): boolean {
return configuration['unknown-options-as-args'] && isUnknownOption(arg)
}
function isUnknownOption (arg: string): boolean {
arg = arg.replace(/^-{3,}/, '--')
// ignore negative numbers
if (arg.match(negative)) { return false }
// if this is a short option group and all of them are configured, it isn't unknown
if (hasAllShortFlags(arg)) { return false }
// e.g. '--count=2'
const flagWithEquals = /^-+([^=]+?)=[\s\S]*$/
// e.g. '-a' or '--arg'
const normalFlag = /^-+([^=]+?)$/
// e.g. '-a-'
const flagEndingInHyphen = /^-+([^=]+?)-$/
// e.g. '-abc123'
const flagEndingInDigits = /^-+([^=]+?\d+)$/
// e.g. '-a/usr/local'
const flagEndingInNonWordCharacters = /^-+([^=]+?)\W+.*$/
// check the different types of flag styles, including negatedBoolean, a pattern defined near the start of the parse method
return !hasFlagsMatching(arg, flagWithEquals, negatedBoolean, normalFlag, flagEndingInHyphen, flagEndingInDigits, flagEndingInNonWordCharacters)
}
// make a best effort to pick a default value
// for an option based on name and type.
function defaultValue (key: string) {
if (!checkAllAliases(key, flags.bools) &&
!checkAllAliases(key, flags.counts) &&
`${key}` in defaults) {
return defaults[key]
} else {
return defaultForType(guessType(key))
}
}
// return a default value, given the type of a flag.,
function defaultForType (type: K): DefaultValuesForType[K] {
const def: DefaultValuesForType = {
[DefaultValuesForTypeKey.BOOLEAN]: true,
[DefaultValuesForTypeKey.STRING]: '',
[DefaultValuesForTypeKey.NUMBER]: undefined,
[DefaultValuesForTypeKey.ARRAY]: []
}
return def[type]
}
// given a flag, enforce a default type.
function guessType (key: string): DefaultValuesForTypeKey {
let type: DefaultValuesForTypeKey = DefaultValuesForTypeKey.BOOLEAN
if (checkAllAliases(key, flags.strings)) type = DefaultValuesForTypeKey.STRING
else if (checkAllAliases(key, flags.numbers)) type = DefaultValuesForTypeKey.NUMBER
else if (checkAllAliases(key, flags.bools)) type = DefaultValuesForTypeKey.BOOLEAN
else if (checkAllAliases(key, flags.arrays)) type = DefaultValuesForTypeKey.ARRAY
return type
}
function isUndefined (num: any): num is undefined {
return num === undefined
}
// check user configuration settings for inconsistencies
function checkConfiguration (): void {
// count keys should not be set as array/narg
Object.keys(flags.counts).find(key => {
if (checkAllAliases(key, flags.arrays)) {
error = Error(__('Invalid configuration: %s, opts.count excludes opts.array.', key))
return true
} else if (checkAllAliases(key, flags.nargs)) {
error = Error(__('Invalid configuration: %s, opts.count excludes opts.narg.', key))
return true
}
return false
})
}
return {
aliases: Object.assign({}, flags.aliases),
argv: Object.assign(argvReturn, argv),
configuration: configuration,
defaulted: Object.assign({}, defaulted),
error: error,
newAliases: Object.assign({}, newAliases)
}
}
}
// if any aliases reference each other, we should
// merge them together.
function combineAliases (aliases: Dictionary): Dictionary {
const aliasArrays: Array = []
const combined: Dictionary = Object.create(null)
let change = true
// turn alias lookup hash {key: ['alias1', 'alias2']} into
// a simple array ['key', 'alias1', 'alias2']
Object.keys(aliases).forEach(function (key) {
aliasArrays.push(
([] as string[]).concat(aliases[key], key)
)
})
// combine arrays until zero changes are
// made in an iteration.
while (change) {
change = false
for (let i = 0; i < aliasArrays.length; i++) {
for (let ii = i + 1; ii < aliasArrays.length; ii++) {
const intersect = aliasArrays[i].filter(function (v) {
return aliasArrays[ii].indexOf(v) !== -1
})
if (intersect.length) {
aliasArrays[i] = aliasArrays[i].concat(aliasArrays[ii])
aliasArrays.splice(ii, 1)
change = true
break
}
}
}
}
// map arrays back to the hash-lookup (de-dupe while
// we're at it).
aliasArrays.forEach(function (aliasArray) {
aliasArray = aliasArray.filter(function (v, i, self) {
return self.indexOf(v) === i
})
const lastAlias = aliasArray.pop()
if (lastAlias !== undefined && typeof lastAlias === 'string') {
combined[lastAlias] = aliasArray
}
})
return combined
}
// this function should only be called when a count is given as an arg
// it is NOT called to set a default value
// thus we can start the count at 1 instead of 0
function increment (orig?: number | undefined): number {
return orig !== undefined ? orig + 1 : 1
}
// TODO(bcoe): in the next major version of yargs, switch to
// Object.create(null) for dot notation:
function sanitizeKey (key: string): string {
if (key === '__proto__') return '___proto___'
return key
}
function stripQuotes (val: string): string {
return (
typeof val === 'string' &&
(val[0] === "'" || val[0] === '"') &&
val[val.length - 1] === val[0]
)
? val.substring(1, val.length - 1)
: val
}
yargs-parser-yargs-parser-v21.0.0/package.json 0000664 0000000 0000000 00000004641 14144615712 0021314 0 ustar 00root root 0000000 0000000 {
"name": "yargs-parser",
"version": "21.0.0",
"description": "the mighty option parser used by yargs",
"main": "build/index.cjs",
"exports": {
".": [
{
"import": "./build/lib/index.js",
"require": "./build/index.cjs"
},
"./build/index.cjs"
]
},
"type": "module",
"module": "./build/lib/index.js",
"scripts": {
"check": "standardx '**/*.ts' && standardx '**/*.js' && standardx '**/*.cjs'",
"fix": "standardx --fix '**/*.ts' && standardx --fix '**/*.js' && standardx --fix '**/*.cjs'",
"pretest": "rimraf build && tsc -p tsconfig.test.json && cross-env NODE_ENV=test npm run build:cjs",
"test": "c8 --reporter=text --reporter=html mocha test/*.cjs",
"test:esm": "c8 --reporter=text --reporter=html mocha test/*.mjs",
"test:browser": "start-server-and-test 'serve ./ -p 8080' http://127.0.0.1:8080/package.json 'node ./test/browser/yargs-test.cjs'",
"pretest:typescript": "npm run pretest",
"test:typescript": "c8 mocha ./build/test/typescript/*.js",
"coverage": "c8 report --check-coverage",
"precompile": "rimraf build",
"compile": "tsc",
"postcompile": "npm run build:cjs",
"build:cjs": "rollup -c",
"prepare": "npm run compile"
},
"repository": {
"type": "git",
"url": "https://github.com/yargs/yargs-parser.git"
},
"keywords": [
"argument",
"parser",
"yargs",
"command",
"cli",
"parsing",
"option",
"args",
"argument"
],
"author": "Ben Coe ",
"license": "ISC",
"devDependencies": {
"@types/chai": "^4.2.11",
"@types/mocha": "^9.0.0",
"@types/node": "^16.11.4",
"@typescript-eslint/eslint-plugin": "^3.10.1",
"@typescript-eslint/parser": "^3.10.1",
"@wessberg/rollup-plugin-ts": "^1.2.28",
"c8": "^7.3.0",
"chai": "^4.2.0",
"cross-env": "^7.0.2",
"eslint": "^7.0.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-node": "^11.0.0",
"gts": "^3.0.0",
"mocha": "^9.0.0",
"puppeteer": "^11.0.0",
"rimraf": "^3.0.2",
"rollup": "^2.22.1",
"rollup-plugin-cleanup": "^3.1.1",
"serve": "^13.0.0",
"standardx": "^7.0.0",
"start-server-and-test": "^1.11.2",
"ts-transform-default-export": "^1.0.2",
"typescript": "^4.0.0"
},
"files": [
"browser.js",
"build",
"!*.d.ts"
],
"engines": {
"node": ">=12"
},
"standardx": {
"ignore": [
"build"
]
}
}
yargs-parser-yargs-parser-v21.0.0/release-please-config.json 0000664 0000000 0000000 00000000143 14144615712 0024044 0 ustar 00root root 0000000 0000000 {
"bootstrap-sha": "686ec15fb7e4a996763c60cf6661b2698f28dac4",
"packages": {
".": {}
}
}
yargs-parser-yargs-parser-v21.0.0/renovate.json 0000664 0000000 0000000 00000000160 14144615712 0021534 0 ustar 00root root 0000000 0000000 {
"extends": [
"config:base"
],
"pinVersions": false,
"rebaseStalePrs": true,
"gitAuthor": null
}
yargs-parser-yargs-parser-v21.0.0/rollup.config.js 0000664 0000000 0000000 00000001072 14144615712 0022140 0 ustar 00root root 0000000 0000000 import cleanup from 'rollup-plugin-cleanup'
import ts from '@wessberg/rollup-plugin-ts'
import transformDefaultExport from 'ts-transform-default-export'
const output = {
format: 'cjs',
file: './build/index.cjs',
exports: 'default'
}
if (process.env.NODE_ENV === 'test') output.sourcemap = true
export default {
input: './lib/index.ts',
output,
plugins: [
ts({
transformers: ({ program }) => ({
afterDeclarations: transformDefaultExport(program)
})
}),
cleanup({
comments: 'none',
extensions: ['*']
})
]
}
yargs-parser-yargs-parser-v21.0.0/test/ 0000775 0000000 0000000 00000000000 14144615712 0020000 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/test/browser/ 0000775 0000000 0000000 00000000000 14144615712 0021463 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/test/browser/yargs-test.cjs 0000664 0000000 0000000 00000002521 14144615712 0024266 0 ustar 00root root 0000000 0000000 const { deepStrictEqual } = require('assert')
const puppeteer = require('puppeteer')
// Runs a browser window with a given argv string and options:
let browser
async function parse (argv, opts) {
if (!browser) {
browser = await puppeteer.launch()
}
const page = await browser.newPage()
opts = encodeURIComponent(JSON.stringify(opts))
await page.goto(`http://127.0.0.1:8080/test/browser/yargs-test?argv=${encodeURIComponent(argv)}&opts=${opts}`)
const element = await page.$('#output')
return JSON.parse(await page.evaluate(element => element.textContent, element))
}
// The actual tests:
async function tests () {
{
const output = await parse('--hello world --x 102')
deepStrictEqual(output, {
_: [],
hello: 'world',
x: 102
})
console.info('✅ parse simple string')
}
{
const output = await parse('--hello world --x 102', {
alias: {
hello: ['goodbye'],
x: ['example']
}
})
deepStrictEqual(output, {
_: [],
hello: 'world',
x: 102,
example: 102,
goodbye: 'world'
})
console.info('✅ parse with aliases')
}
}
tests().then(() => {
console.info('👌all tests finished')
browser.close()
}).catch((err) => {
console.error(err.stack)
console.error('❌some tests failed')
process.exitCode = 1
browser.close()
})
yargs-parser-yargs-parser-v21.0.0/test/browser/yargs-test.html 0000664 0000000 0000000 00000001274 14144615712 0024457 0 ustar 00root root 0000000 0000000
yargs-parser-yargs-parser-v21.0.0/test/deno/ 0000775 0000000 0000000 00000000000 14144615712 0020725 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/test/deno/yargs-test.ts 0000664 0000000 0000000 00000003200 14144615712 0023372 0 ustar 00root root 0000000 0000000 /* global Deno */
import {
assertEquals
} from 'https://deno.land/std/testing/asserts.ts'
import parser from '../../deno.ts'
// Parser:
Deno.test('parse string', () => {
const parsed = parser('--foo --bar 99')
assertEquals(parsed.foo, true)
assertEquals(parsed.bar, 99)
})
Deno.test('parse array', () => {
const parsed = parser(['--foo', '--bar', '99'])
assertEquals(parsed.foo, true)
assertEquals(parsed.bar, 99)
})
Deno.test('aliases', () => {
const parsed = parser(['--bar', '99'], {
alias: {
bar: ['foo'],
foo: ['f']
}
})
assertEquals(parsed.bar, 99)
assertEquals(parsed.foo, 99)
assertEquals(parsed.f, 99)
})
const jsonPath = './test/fixtures/config.json'
Deno.test('should load options and values from default config if specified', () => {
const argv = parser(['--foo', 'bar'], {
alias: {
z: 'zoom'
},
default: {
settings: jsonPath
},
config: 'settings'
})
assertEquals(argv.herp, 'derp')
assertEquals(argv.zoom, 55)
assertEquals(argv.zoom, 55)
})
// String utilities:
Deno.test('convert hyphenated string to camelcase', () => {
assertEquals(parser.camelCase('hello-world'), 'helloWorld')
})
Deno.test('convert camelcase string to hyphenated', () => {
assertEquals(parser.decamelize('helloWorld'), 'hello-world')
})
Deno.test('it detects strings that could be parsed as numbers', () => {
assertEquals(parser.looksLikeNumber('3293'), true)
assertEquals(parser.looksLikeNumber('0x10'), true)
assertEquals(parser.looksLikeNumber('0x10'), true)
assertEquals(parser.looksLikeNumber('0100'), false)
assertEquals(parser.looksLikeNumber('apple'), false)
})
yargs-parser-yargs-parser-v21.0.0/test/fixtures/ 0000775 0000000 0000000 00000000000 14144615712 0021651 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/test/fixtures/config.json 0000664 0000000 0000000 00000000357 14144615712 0024016 0 ustar 00root root 0000000 0000000 {
"herp": "derp",
"z": 55,
"foo": "baz",
"version": "1.0.2",
"truthy": true,
"toString": "method name",
"__proto__": {
"aaa": 99
},
"bar": {
"__proto__": {
"bbb": 100
}
}
}
yargs-parser-yargs-parser-v21.0.0/test/fixtures/config.txt 0000664 0000000 0000000 00000000035 14144615712 0023655 0 ustar 00root root 0000000 0000000 AWESOME=banana
BATMAN=grumpy
yargs-parser-yargs-parser-v21.0.0/test/fixtures/nested_config.json 0000664 0000000 0000000 00000000120 14144615712 0025344 0 ustar 00root root 0000000 0000000 {
"a": "a",
"nested": {
"foo": "baz",
"bar": "bar"
},
"b": "b"
} yargs-parser-yargs-parser-v21.0.0/test/fixtures/settings.cjs 0000664 0000000 0000000 00000000127 14144615712 0024212 0 ustar 00root root 0000000 0000000 module.exports = {
calculate: function (a) {
return a + 55
},
herp: 'derp'
}
yargs-parser-yargs-parser-v21.0.0/test/string-utils.cjs 0000664 0000000 0000000 00000002566 14144615712 0023156 0 ustar 00root root 0000000 0000000 /* global describe, it */
const { strictEqual } = require('assert')
const { camelCase, decamelize, looksLikeNumber } = require('../build/index.cjs')
describe('string-utils', function () {
describe('camelCase', () => {
it('converts string with hypen in middle to camel case', () => {
strictEqual(camelCase('hello-world'), 'helloWorld')
})
it('removes leading hyphens', () => {
strictEqual(camelCase('-goodnight-moon'), 'goodnightMoon')
})
it('camelCase string stays as is', () => {
strictEqual(camelCase('iAmCamelCase'), 'iAmCamelCase')
})
it('uppercase string with underscore to camel case', () => {
strictEqual(camelCase('NODE_VERSION'), 'nodeVersion')
})
})
describe('decamelize', () => {
it('adds hyphens back to camelcase string', () => {
strictEqual(decamelize('helloWorld'), 'hello-world')
})
})
describe('looksLikeNumber', () => {
it('it detects strings that could be parsed as numbers', () => {
strictEqual(looksLikeNumber('3293'), true)
strictEqual(looksLikeNumber('0x10'), true)
strictEqual(looksLikeNumber('.1'), true)
strictEqual(looksLikeNumber('0.1'), true)
strictEqual(looksLikeNumber('0.10'), true)
strictEqual(looksLikeNumber('00.1'), false)
strictEqual(looksLikeNumber('0100'), false)
strictEqual(looksLikeNumber('apple'), false)
})
})
})
yargs-parser-yargs-parser-v21.0.0/test/tscc/ 0000775 0000000 0000000 00000000000 14144615712 0020734 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/test/tscc/.gitignore 0000664 0000000 0000000 00000000005 14144615712 0022717 0 ustar 00root root 0000000 0000000 *.js
yargs-parser-yargs-parser-v21.0.0/test/tscc/lib 0000777 0000000 0000000 00000000000 14144615712 0022537 2../../lib ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/test/tscc/optimized.ts 0000664 0000000 0000000 00000002512 14144615712 0023310 0 ustar 00root root 0000000 0000000 import { YargsParser } from './lib/yargs-parser'
const parser = new YargsParser({
cwd: () => { return '' },
format: (str, arg) => { return str.replace('%s', arg) },
normalize: (str) => { return str },
resolve: (str) => { return str },
require: () => {
throw Error('loading config from files not currently supported in browser')
},
env: () => {}
})
// Workaround the need for proper nodejs typings and externs
// eslint-disable-next-line no-eval
const anyDeepEqual = eval('require("assert").strict.deepEqual') as any
function deepEqual (actual: T, expected: T, message?: string): void {
anyDeepEqual(actual, expected, message)
}
// Quoted properties aren't allowed in these lint settings.
const FLAG_X = 'x'
function runTests () {
deepEqual(parser.parse([]).argv, { _: [] }, 'empty argv')
deepEqual(
parser.parse([`--${FLAG_X}=42`]).argv,
{ _: [], [FLAG_X]: 42 },
'guessed numeric value')
deepEqual(
parser.parse([`--${FLAG_X}=str`]).argv,
{ _: [], [FLAG_X]: 'str' },
'guessed string value')
deepEqual(
parser.parse([`--no-${FLAG_X}`]).argv,
{ _: [], [FLAG_X]: false },
'guessed boolean negation')
// Default values for types:
deepEqual(
parser.parse([`--${FLAG_X}`]).argv,
{ _: [], [FLAG_X]: true },
'guessed boolean default true')
console.log('ok')
}
runTests()
yargs-parser-yargs-parser-v21.0.0/test/tscc/package.json 0000664 0000000 0000000 00000000210 14144615712 0023213 0 ustar 00root root 0000000 0000000 {
"name": "optimized-test",
"version": "0.0.0",
"dependencies": {
"@tscc/tscc": "^0.7.4",
"@types/node": "^16.11.4"
}
}
yargs-parser-yargs-parser-v21.0.0/test/tscc/tscc.spec.json 0000664 0000000 0000000 00000000061 14144615712 0023511 0 ustar 00root root 0000000 0000000 {
"modules": {
"out": "optimized.ts"
}
}
yargs-parser-yargs-parser-v21.0.0/test/tscc/tsconfig.json 0000664 0000000 0000000 00000000246 14144615712 0023445 0 ustar 00root root 0000000 0000000 {
"compilerOptions": {
"module": "es2020",
"target": "es2017",
"moduleResolution": "node"
},
"include": [
"./*.ts",
"./lib/**/*.ts"
]
}
yargs-parser-yargs-parser-v21.0.0/test/typescript/ 0000775 0000000 0000000 00000000000 14144615712 0022206 5 ustar 00root root 0000000 0000000 yargs-parser-yargs-parser-v21.0.0/test/typescript/tokenize-arg-string.ts 0000664 0000000 0000000 00000010566 14144615712 0026471 0 ustar 00root root 0000000 0000000 /* global describe, it */
import { strictEqual } from 'assert'
import { tokenizeArgString } from '../../lib/tokenize-arg-string.js'
describe('TokenizeArgString', function () {
it('handles unquoted string', function () {
const args = tokenizeArgString('--foo 99')
strictEqual(args[0], '--foo')
strictEqual(args[1], '99')
})
it('handles unquoted numbers', function () {
const args = tokenizeArgString(['--foo', 9])
strictEqual(args[0], '--foo')
strictEqual(args[1], '9')
})
it('handles quoted string with no spaces', function () {
const args = tokenizeArgString("--foo 'hello'")
strictEqual(args[0], '--foo')
strictEqual(args[1], "'hello'")
})
it('handles single quoted string with spaces', function () {
const args = tokenizeArgString("--foo 'hello world' --bar='foo bar'")
strictEqual(args[0], '--foo')
strictEqual(args[1], "'hello world'")
strictEqual(args[2], "--bar='foo bar'")
})
it('handles double quoted string with spaces', function () {
const args = tokenizeArgString('--foo "hello world" --bar="foo bar"')
strictEqual(args[0], '--foo')
strictEqual(args[1], '"hello world"')
strictEqual(args[2], '--bar="foo bar"')
})
it('handles single quoted empty string', function () {
const args = tokenizeArgString('--foo \'\' --bar=\'\'')
strictEqual(args[0], '--foo')
strictEqual(args[1], "''")
strictEqual(args[2], "--bar=''")
})
it('handles double quoted empty string', function () {
const args = tokenizeArgString('--foo "" --bar=""')
strictEqual(args[0], '--foo')
strictEqual(args[1], '""')
strictEqual(args[2], '--bar=""')
})
it('handles quoted string with embedded quotes', function () {
const args = tokenizeArgString('--foo "hello \'world\'" --bar=\'foo "bar"\'')
strictEqual(args[0], '--foo')
strictEqual(args[1], '"hello \'world\'"')
strictEqual(args[2], '--bar=\'foo "bar"\'')
})
// https://github.com/yargs/yargs-parser/pull/100
// https://github.com/yargs/yargs-parser/pull/106
it('ignores unneeded spaces', function () {
const args = tokenizeArgString(' foo bar "foo bar" ')
strictEqual(args[0], 'foo')
strictEqual(args[1], 'bar')
strictEqual(args[2], '"foo bar"')
})
it('handles boolean options', function () {
const args = tokenizeArgString('--foo -bar')
strictEqual(args[0], '--foo')
strictEqual(args[1], '-bar')
})
it('handles empty string', function () {
const args = tokenizeArgString('')
strictEqual(args.length, 0)
})
it('handles array with unquoted string', function () {
const args = tokenizeArgString(['--foo', '99'])
strictEqual(args[0], '--foo')
strictEqual(args[1], '99')
})
it('handles array with quoted string with no spaces', function () {
const args = tokenizeArgString(['--foo', "'hello'"])
strictEqual(args[0], '--foo')
strictEqual(args[1], "'hello'")
})
it('handles array with single quoted string with spaces', function () {
const args = tokenizeArgString(['--foo', "'hello world'", "--bar='foo bar'"])
strictEqual(args[0], '--foo')
strictEqual(args[1], "'hello world'")
strictEqual(args[2], "--bar='foo bar'")
})
it('handles array with double quoted string with spaces', function () {
const args = tokenizeArgString(['--foo', '"hello world"', '--bar="foo bar"'])
strictEqual(args[0], '--foo')
strictEqual(args[1], '"hello world"')
strictEqual(args[2], '--bar="foo bar"')
})
it('handles array with single quoted empty string', function () {
const args = tokenizeArgString(['--foo', "''", "--bar=''"])
strictEqual(args[0], '--foo')
strictEqual(args[1], "''")
strictEqual(args[2], "--bar=''")
})
it('handles array with double quoted empty string', function () {
const args = tokenizeArgString(['--foo', '""', '--bar=""'])
strictEqual(args[0], '--foo')
strictEqual(args[1], '""')
strictEqual(args[2], '--bar=""')
})
it('handles array with quoted string with embedded quotes', function () {
const args = tokenizeArgString(['--foo', '"hello \'world\'"', '--bar=\'foo "bar"\''])
strictEqual(args[0], '--foo')
strictEqual(args[1], '"hello \'world\'"')
strictEqual(args[2], '--bar=\'foo "bar"\'')
})
it('handles array with boolean options', function () {
const args = tokenizeArgString(['--foo', '-bar'])
strictEqual(args[0], '--foo')
strictEqual(args[1], '-bar')
})
})
yargs-parser-yargs-parser-v21.0.0/test/typescript/types.ts 0000664 0000000 0000000 00000000476 14144615712 0023731 0 ustar 00root root 0000000 0000000 /* global describe, it */
import yargsParser from '../../lib/index.js'
import * as assert from 'assert'
describe('types', function () {
it('allows a partial options object to be provided', () => {
const argv = yargsParser('--foo 99', {
string: 'foo'
})
assert.strictEqual(argv.foo, '99')
})
})
yargs-parser-yargs-parser-v21.0.0/test/yargs-parser.cjs 0000664 0000000 0000000 00000364205 14144615712 0023132 0 ustar 00root root 0000000 0000000 /* global beforeEach, describe, it */
require('chai').should()
const { expect } = require('chai')
const fs = require('fs')
const parser = require('../build/index.cjs')
const path = require('path')
describe('yargs-parser', function () {
it('should parse a "short boolean"', function () {
const parse = parser(['-b'])
parse.should.not.have.property('--')
parse.should.have.property('b').to.be.ok.and.be.a('boolean')
parse.should.have.property('_').with.length(0)
})
it('should parse a "long boolean"', function () {
const parse = parser('--bool')
parse.should.not.have.property('--')
parse.should.have.property('bool', true)
parse.should.have.property('_').with.length(0)
})
it('should place bare options in the _ array', function () {
const parse = parser('foo bar baz')
parse.should.have.property('_').and.deep.equal(['foo', 'bar', 'baz'])
})
it('should set the value of the final option in a group to the next supplied value', function () {
const parse = parser(['-cats', 'meow'])
parse.should.have.property('c', true)
parse.should.have.property('a', true)
parse.should.have.property('t', true)
parse.should.have.property('s', 'meow')
parse.should.have.property('_').with.length(0)
})
it('should set the value of a single long option to the next supplied value', function () {
const parse = parser(['--pow', 'xixxle'])
parse.should.have.property('pow', 'xixxle')
parse.should.have.property('_').with.length(0)
})
it('should set the value of a single long option to the next supplied value, even if the value is empty', function () {
const parse = parser(['--pow', ''])
parse.should.have.property('pow', '')
parse.should.have.property('_').with.length(0)
})
it('should set the value of a single long option if an = was used', function () {
const parse = parser(['--pow=xixxle'])
parse.should.have.property('pow', 'xixxle')
parse.should.have.property('_').with.length(0)
})
it('should set the value of multiple long options to the next supplied values relative to each', function () {
const parse = parser(['--host', 'localhost', '--port', '555'])
parse.should.have.property('host', 'localhost')
parse.should.have.property('port', 555)
parse.should.have.property('_').with.length(0)
})
it('should set the value of multiple long options if = signs were used', function () {
const parse = parser(['--host=localhost', '--port=555'])
parse.should.have.property('host', 'localhost')
parse.should.have.property('port', 555)
parse.should.have.property('_').with.length(0)
})
it('should still set values appropriately if a mix of short, long, and grouped short options are specified', function () {
const parse = parser(['-h', 'localhost', '-fp', '555', 'script.js'])
parse.should.have.property('f', true)
parse.should.have.property('p', 555)
parse.should.have.property('h', 'localhost')
parse.should.have.property('_').and.deep.equal(['script.js'])
})
it('should still set values appropriately if a mix of short and long options are specified', function () {
const parse = parser(['-h', 'localhost', '--port', '555'])
parse.should.have.property('h', 'localhost')
parse.should.have.property('port', 555)
parse.should.have.property('_').with.length(0)
})
it('should explicitly set a boolean option to false if preceded by "--no-"', function () {
const parse = parser(['--no-moo'])
parse.should.have.property('moo', false)
parse.should.have.property('_').with.length(0)
})
it('should still set values appropriately if we supply a comprehensive list of various types of options', function () {
const parse = parser([
'--name=meowmers', 'bare', '-cats', 'woo',
'-h', 'awesome', '--multi=quux',
'--key', 'value',
'-b', '--bool', '--no-meep', '--multi=baz',
'--', '--not-a-flag', '-', '-h', '-multi', '--', 'eek'
], {
configuration: {
'populate--': false
}
})
parse.should.have.property('c', true)
parse.should.have.property('a', true)
parse.should.have.property('t', true)
parse.should.have.property('s', 'woo')
parse.should.have.property('h', 'awesome')
parse.should.have.property('b', true)
parse.should.have.property('bool', true)
parse.should.have.property('key', 'value')
parse.should.have.property('multi').and.deep.equal(['quux', 'baz'])
parse.should.have.property('meep', false)
parse.should.have.property('name', 'meowmers')
parse.should.have.property('_').and.deep.equal(['bare', '--not-a-flag', '-', '-h', '-multi', '--', 'eek'])
})
it('should parse numbers appropriately', function () {
const argv = parser([
'-x', '1234',
'-y', '5.67',
'-z', '1e7',
'-w', '10f',
'--hex', '0xdeadbeef',
'789'
])
argv.should.have.property('x', 1234).and.be.a('number')
argv.should.have.property('y', 5.67).and.be.a('number')
argv.should.have.property('z', 1e7).and.be.a('number')
argv.should.have.property('w', '10f').and.be.a('string')
argv.should.have.property('hex', 0xdeadbeef).and.be.a('number')
argv.should.have.property('_').and.deep.equal([789])
argv._[0].should.be.a('number')
})
// addresses: https://github.com/yargs/yargs-parser/issues/33
it('should handle parsing negative #s', function () {
const argv = parser([
'-33', '-177', '33',
'--n1', '-33',
'-n', '-44',
'--n2=-55',
'--foo.bar', '-33',
'-o=-55',
'--bounds', '-180', '99', '-180', '90',
'--other', '-99', '-220'
], {
array: 'bounds',
narg: { other: 2 }
})
argv._.should.deep.equal([-33, -177, 33])
argv.n1.should.equal(-33)
argv.n.should.equal(-44)
argv.n2.should.equal(-55)
argv.foo.bar.should.equal(-33)
argv.o.should.equal(-55)
argv.bounds.should.deep.equal([-180, 99, -180, 90])
argv.other.should.deep.equal([-99, -220])
})
it('should handle negative (and positive) numbers with decimal places, with or without a leading 0', function () {
const argv = parser([
'-0.1', '-1.1', '-.5', '-.1', '.1', '.5',
'--bounds', '-5.1', '-.1', '.1',
'--other', '.9', '-.5'
], {
array: 'bounds',
narg: { other: 2 }
})
argv._.should.deep.equal([-0.1, -1.1, -0.5, -0.1, 0.1, 0.5])
argv.bounds.should.deep.equal([-5.1, -0.1, 0.1])
argv.other.should.deep.equal([0.9, -0.5])
})
it('should set the value of a single short option to the next supplied value, even if the value is empty', function () {
const parse = parser(['-p', ''])
parse.should.have.property('p', '')
parse.should.have.property('_').with.length(0)
})
it('should not set the next value as the value of a short option if that option is explicitly defined as a boolean', function () {
const parse = parser(['-t', 'moo'], {
boolean: 't'
})
parse.should.have.property('t', true).and.be.a('boolean')
parse.should.have.property('_').and.deep.equal(['moo'])
})
it('should set boolean options values if the next value is "true" or "false"', function () {
const parse = parser(['--verbose', 'false', 'moo', '-t', 'true'], {
boolean: ['t', 'verbose'],
default: {
verbose: true
}
})
parse.should.have.property('verbose', false).and.be.a('boolean')
parse.should.have.property('t', true).and.be.a('boolean')
parse.should.have.property('_').and.deep.equal(['moo'])
})
it('should not set boolean options values if the next value only contains the words "true" or "false"', function () {
const parse = parser(['--verbose', 'aaatrueaaa', 'moo', '-t', 'aaafalseaaa'], {
boolean: ['t', 'verbose']
})
parse.should.have.property('verbose', true).and.be.a('boolean')
parse.should.have.property('t', true).and.be.a('boolean')
parse.should.have.property('_').and.deep.equal(['aaatrueaaa', 'moo', 'aaafalseaaa'])
})
it('should not use next value for boolean/number/string configured with zero narg', function () {
const parse = parser(['--bool', 'false', '--nr', '7', '--str', 'foo'], {
boolean: ['bool'],
number: ['nr'],
string: ['str'],
narg: { bool: 0, nr: 0, str: 0 }
})
parse.should.have.property('bool', true).and.be.a('boolean')
parse.should.have.property('nr', undefined).and.be.a('undefined')
parse.should.have.property('str', '').and.be.a('string')
parse.should.have.property('_').and.deep.equal(['false', 7, 'foo'])
})
it('should allow defining options as boolean in groups', function () {
const parse = parser(['-x', '-z', 'one', 'two', 'three'], {
boolean: ['x', 'y', 'z']
})
parse.should.have.property('x', true).and.be.a('boolean')
parse.should.not.have.property('y')
parse.should.have.property('z', true).and.be.a('boolean')
parse.should.have.property('_').and.deep.equal(['one', 'two', 'three'])
})
it('should correctly parse dot-notation boolean flags', function () {
const parse = parser(['--nested', '--n.v', '--n.y', 'foo'], {
boolean: ['nested', 'n.v']
})
parse.should.have.property('nested', true).and.be.a('boolean')
parse.should.have.property('n').and.deep.equal({
v: true,
y: 'foo'
})
})
it('should preserve newlines in option values', function () {
let args = parser(['-s', 'X\nX'])
args.should.have.property('_').with.length(0)
args.should.have.property('s', 'X\nX')
// reproduce in bash:
// VALUE="new
// line"
// node program.js --s="$VALUE"
args = parser(['--s=X\nX'])
args.should.have.property('_').with.length(0)
args.should.have.property('s', 'X\nX')
})
it('should not convert numbers to type number if explicitly defined as strings', function () {
const s = parser(['-s', '0001234'], {
string: 's'
}).s
s.should.be.a('string').and.equal('0001234')
const x = parser(['-x', '56'], {
string: ['x']
}).x
x.should.be.a('string').and.equal('56')
})
it('should default numbers to undefined', function () {
const n = parser(['-n'], {
number: ['n']
}).n
expect(n).to.equal(undefined)
})
it('should default number to NaN if value is not a valid number', function () {
const n = parser(['-n', 'string'], {
number: ['n']
}).n
expect(n).to.deep.equal(NaN)
})
// Fixes: https://github.com/bcoe/yargs/issues/68
it('should parse flag arguments with no right-hand value as strings, if defined as strings', function () {
let s = parser(['-s'], {
string: ['s']
}).s
s.should.be.a('string').and.equal('')
s = parser(['-sf'], {
string: ['s']
}).s
s.should.be.a('string').and.equal('')
s = parser(['--string'], {
string: ['string']
}).string
s.should.be.a('string').and.equal('')
})
it('should leave all non-hyphenated values as strings if _ is defined as a string', function () {
const s = parser([' ', ' '], {
string: ['_']
})._
s.should.have.length(2)
s[0].should.be.a('string').and.equal(' ')
s[1].should.be.a('string').and.equal(' ')
})
describe('normalize', function () {
it('should normalize redundant paths', function () {
const a = parser(['-s', ['', 'tmp', '..', ''].join(path.sep)], {
alias: {
s: ['save']
},
normalize: 's'
})
a.should.have.property('s', path.sep)
a.should.have.property('save', path.sep)
})
it('should normalize redundant paths when a value is later assigned', function () {
const a = parser(['-s'], {
normalize: ['s']
})
a.should.have.property('s', true)
a.s = ['', 'path', 'to', 'new', 'dir', '..', '..', ''].join(path.sep)
a.s.should.equal(['', 'path', 'to', ''].join(path.sep))
})
it('should normalize when key is also an array', function () {
const a = parser(['-s', ['', 'tmp', '..', ''].join(path.sep), ['', 'path', 'to', 'new', 'dir', '..', '..', ''].join(path.sep)], {
alias: {
s: ['save']
},
normalize: 's',
array: 's'
})
const expected = [path.sep, ['', 'path', 'to', ''].join(path.sep)]
a.should.have.property('s').and.deep.equal(expected)
a.should.have.property('save').and.deep.equal(expected)
})
it('should allow normalized keys to be enumerated', () => {
const a = parser(['-s', ['', 'tmp', '..', ''].join(path.sep)], {
alias: {
s: ['save']
},
normalize: 's'
})
Object.keys(a).should.include('s')
})
})
describe('alias', function () {
it('should set alias value to the same value as the full option', function () {
const argv = parser(['-f', '11', '--zoom', '55'], {
alias: {
z: ['zoom']
}
})
argv.should.have.property('zoom', 55)
argv.should.have.property('z', 55)
argv.should.have.property('f', 11)
})
it('should allow multiple aliases to be specified', function () {
const argv = parser(['-f', '11', '--zoom', '55'], {
alias: {
z: ['zm', 'zoom']
}
})
argv.should.have.property('zoom', 55)
argv.should.have.property('z', 55)
argv.should.have.property('zm', 55)
argv.should.have.property('f', 11)
})
// regression, see https://github.com/chevex/yargs/issues/63
it('should not add the same key to argv multiple times, when creating camel-case aliases', function () {
const argv = parser(['--health-check=banana', '--second-key', 'apple', '-t=blarg'], {
alias: {
h: ['health-check'],
'second-key': ['s'],
'third-key': ['t']
},
default: {
h: 'apple',
'second-key': 'banana',
'third-key': 'third'
}
})
// before this fix, yargs failed parsing
// one but not all forms of an arg.
argv.secondKey.should.eql('apple')
argv.s.should.eql('apple')
argv['second-key'].should.eql('apple')
argv.healthCheck.should.eql('banana')
argv.h.should.eql('banana')
argv['health-check'].should.eql('banana')
argv.thirdKey.should.eql('blarg')
argv.t.should.eql('blarg')
argv['third-key'].should.eql('blarg')
})
it('should allow transitive aliases to be specified', function () {
const argv = parser(['-f', '11', '--zoom', '55'], {
alias: {
z: 'zm',
zm: 'zoom'
}
})
argv.should.have.property('zoom', 55)
argv.should.have.property('z', 55)
argv.should.have.property('zm', 55)
argv.should.have.property('f', 11)
})
it('should merge two lists of aliases if they collide', function () {
const argv = parser(['-f', '11', '--zoom', '55'], {
alias: {
z: 'zm',
zoom: 'zoop',
zm: 'zoom'
}
})
argv.should.have.property('zoom', 55)
argv.should.have.property('zoop', 55)
argv.should.have.property('z', 55)
argv.should.have.property('zm', 55)
argv.should.have.property('f', 11)
})
it('should set single-digit boolean alias', function () {
const argv = parser(['-f', '11', '-0'], {
alias: {
0: 'print0'
},
boolean: [
'print0'
]
})
argv.should.have.property('print0', true)
argv.should.have.property('f', 11)
})
it('should not set single-digit alias if no alias defined', function () {
const argv = parser(['-f', '11', '-0', '-1'])
argv.should.have.property('f', 11)
argv._.should.deep.equal([-0, -1])
})
it('should not set single-digit boolean alias if no boolean defined', function () {
const argv = parser(['-f', '11', '-9'], {
alias: {
0: 'print0'
}
})
argv.should.have.property('f', 11)
argv._.should.deep.equal([-9])
})
it('should be able to negate set single-digit boolean alias', function () {
const argv = parser(['--no-9'], {
alias: {
9: 'max'
},
boolean: [
'max'
]
})
argv.should.have.property('max', false)
})
})
it('should assign data after forward slash to the option before the slash', function () {
let parse = parser(['-I/foo/bar/baz'])
parse.should.have.property('_').with.length(0)
parse.should.have.property('I', '/foo/bar/baz')
parse = parser(['-xyz/foo/bar/baz'])
parse.should.have.property('x', true)
parse.should.have.property('y', true)
parse.should.have.property('z', '/foo/bar/baz')
parse.should.have.property('_').with.length(0)
})
const jsonPath = path.resolve(__dirname, './fixtures/config.json')
describe('config', function () {
// See: https://github.com/chevex/yargs/issues/12
it('should load options and values from default config if specified', function () {
const argv = parser(['--foo', 'bar'], {
alias: {
z: 'zoom'
},
default: {
settings: jsonPath
},
config: 'settings'
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('bar')
})
it('should use value from config file, if argv value is using default value', function () {
const argv = parser([], {
alias: {
z: 'zoom'
},
config: ['settings'],
default: {
settings: jsonPath,
foo: 'banana'
}
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('baz')
})
it('should combine values from config file and argv, if argv value is an array', function () {
const argv = parser(['--foo', 'bar'], {
config: ['settings'],
array: ['foo'],
default: {
settings: jsonPath
},
configuration: {
'combine-arrays': true
}
})
argv.should.have.property('foo').and.deep.equal(['bar', 'baz'])
})
it('should use value from config file, if argv key is a boolean', function () {
const argv = parser([], {
config: ['settings'],
default: {
settings: jsonPath
},
boolean: ['truthy']
})
argv.should.have.property('truthy', true)
})
it('should use value from cli, if cli overrides boolean argv key', function () {
const argv = parser(['--no-truthy'], {
config: ['settings'],
default: {
settings: jsonPath
},
boolean: ['truthy']
})
argv.should.have.property('truthy', false)
})
it('should use cli value, if cli value is set and both cli and default value match', function () {
const argv = parser(['--foo', 'banana'], {
alias: {
z: 'zoom'
},
config: ['settings'],
default: {
settings: jsonPath,
foo: 'banana'
}
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('banana')
})
it("should allow config to be set as flag in 'option'", function () {
const argv = parser(['--settings', jsonPath, '--foo', 'bar'], {
alias: {
z: 'zoom'
},
config: ['settings']
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('bar')
})
it('should load options and values from a JS file when config has .js extention', function () {
const jsPath = path.resolve(__dirname, './fixtures/settings.cjs')
const argv = parser(['--settings', jsPath, '--foo', 'bar'], {
config: ['settings']
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('foo', 'bar')
argv.should.have.property('calculate').and.be.a('function')
})
it('should raise an appropriate error if JSON file is not found', function () {
const argv = parser.detailed(['--settings', 'fake.json', '--foo', 'bar'], {
alias: {
z: 'zoom'
},
config: ['settings']
})
argv.error.message.should.equal('Invalid JSON config file: fake.json')
})
// see: https://github.com/bcoe/yargs/issues/172
it('should not raise an exception if config file is set as default argument value', function () {
const argv = parser.detailed([], {
default: {
config: 'foo.json'
},
config: ['config']
})
expect(argv.error).to.equal(null)
})
it('should load nested options from config file', function () {
const jsonPath = path.resolve(__dirname, './fixtures/nested_config.json')
const argv = parser(['--settings', jsonPath, '--nested.foo', 'bar'], {
config: ['settings']
})
argv.should.have.property('a', 'a')
argv.should.have.property('b', 'b')
argv.should.have.property('nested').and.deep.equal({
foo: 'bar',
bar: 'bar'
})
})
it('should use nested value from config file, if argv value is using default value', function () {
const jsonPath = path.resolve(__dirname, './fixtures/nested_config.json')
const argv = parser(['--settings', jsonPath], {
config: ['settings'],
default: {
'nested.foo': 'banana'
}
})
argv.should.have.property('a', 'a')
argv.should.have.property('b', 'b')
argv.should.have.property('nested').and.deep.equal({
foo: 'baz',
bar: 'bar'
})
})
it('allows a custom parsing function to be provided', function () {
const jsPath = path.resolve(__dirname, './fixtures/config.txt')
const argv = parser(['--settings', jsPath, '--foo', 'bar'], {
config: {
settings: function (configPath) {
// as an example, parse an environment
// variable style config:
// FOO=99
// BATMAN=grumpy
const config = {}
const txt = fs.readFileSync(configPath, 'utf-8')
txt.split(/\r?\n/).forEach(function (l) {
const kv = l.split('=')
config[kv[0].toLowerCase()] = kv[1]
})
return config
}
}
})
argv.batman.should.equal('grumpy')
argv.awesome.should.equal('banana')
argv.foo.should.equal('bar')
})
it('allows a custom parsing function to be provided as an alias', function () {
const jsPath = path.resolve(__dirname, './fixtures/config.json')
const argv = parser(['--settings', jsPath, '--foo', 'bar'], {
config: {
s: function (configPath) {
return JSON.parse(fs.readFileSync(configPath, 'utf-8'))
}
},
alias: {
s: ['settings']
}
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('foo', 'bar')
})
it('outputs an error returned by the parsing function', function () {
const argv = parser.detailed(['--settings=./package.json'], {
config: {
settings: function (configPath) {
return Error('someone set us up the bomb')
}
}
})
argv.error.message.should.equal('someone set us up the bomb')
})
it('outputs an error if thrown by the parsing function', function () {
const argv = parser.detailed(['--settings=./package.json'], {
config: {
settings: function (configPath) {
throw Error('someone set us up the bomb')
}
}
})
argv.error.message.should.equal('someone set us up the bomb')
})
it('should not pollute the prototype', function () {
const argv = parser(['--foo', 'bar'], {
alias: {
z: 'zoom'
},
default: {
settings: jsonPath
},
config: 'settings'
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('bar')
expect({}.bbb).to.equal(undefined)
expect({}.aaa).to.equal(undefined)
})
})
describe('config objects', function () {
it('should load options from config object', function () {
const argv = parser(['--foo', 'bar'], {
configObjects: [{
apple: 'apple',
banana: 42,
foo: 'baz',
gotcha: null
}]
})
argv.should.have.property('apple', 'apple')
argv.should.have.property('banana', 42)
argv.should.have.property('foo', 'bar')
argv.should.have.property('gotcha', null)
})
it('should use value from config object, if argv value is using default value', function () {
const argv = parser([], {
configObjects: [{
apple: 'apple',
banana: 42,
foo: 'baz'
}],
default: {
foo: 'banana'
}
})
argv.should.have.property('apple', 'apple')
argv.should.have.property('banana', 42)
argv.should.have.property('foo', 'baz')
})
it('should use value from config object to all aliases', function () {
const argv = parser([], {
configObjects: [{
apple: 'apple',
banana: 42,
foo: 'baz'
}],
alias: {
a: ['apple'],
banana: ['b']
}
})
argv.should.have.property('apple', 'apple')
argv.should.have.property('a', 'apple')
argv.should.have.property('banana', 42)
argv.should.have.property('b', 42)
argv.should.have.property('foo', 'baz')
})
it('should load nested options from config object', function () {
const argv = parser(['--nested.foo', 'bar'], {
configObjects: [{
a: 'a',
nested: {
foo: 'baz',
bar: 'bar'
},
b: 'b'
}]
})
argv.should.have.property('a', 'a')
argv.should.have.property('b', 'b')
argv.should.have.property('nested').and.deep.equal({
foo: 'bar',
bar: 'bar'
})
})
it('should use nested value from config object, if argv value is using default value', function () {
const argv = parser([], {
configObjects: [{
a: 'a',
nested: {
foo: 'baz',
bar: 'bar'
},
b: 'b'
}],
default: {
'nested.foo': 'banana'
}
})
argv.should.have.property('a', 'a')
argv.should.have.property('b', 'b')
argv.should.have.property('nested').and.deep.equal({
foo: 'baz',
bar: 'bar'
})
})
it('should load objects with first object having greatest priority', function () {
const argv = parser(['--foo', 'bar'], {
configObjects: [{
bar: 'baz'
}, {
bar: 'quux',
foo: 'spam'
}]
})
argv.should.have.property('foo', 'bar')
argv.should.have.property('bar', 'baz')
})
it('should combine array typed options with alias and camel-case', function () {
const argv = parser(['--camEl', 'foo', '--camEl', 'bar', '-a', 'red'], {
array: ['cam-el', 'apple'],
alias: { apple: 'a' },
configObjects: [{ camEl: 'baz' }, { a: 'sweet' }],
configuration: {
'combine-arrays': true,
'camel-case-expansion': true
}
})
argv['cam-el'].should.deep.equal(['foo', 'bar', 'baz'])
argv.apple.should.deep.equal(['red', 'sweet'])
})
})
describe('dot notation', function () {
it('should allow object graph traversal via dot notation', function () {
const argv = parser([
'--foo.bar', '3', '--foo.baz', '4',
'--foo.quux.quibble', '5', '--foo.quux.o_O',
'--beep.boop'
])
argv.should.have.property('foo').and.deep.equal({
bar: 3,
baz: 4,
quux: {
quibble: 5,
o_O: true
}
})
argv.should.have.property('beep').and.deep.equal({ boop: true })
})
it('should apply defaults to dot notation arguments', function () {
const argv = parser([], {
default: {
'foo.bar': 99
}
})
argv.foo.bar.should.eql(99)
})
// see #279
it('should allow default to be overridden when an alias is provided', function () {
const argv = parser(['--foo.bar', '200'], {
default: {
'foo.bar': 99
}
})
argv.foo.bar.should.eql(200)
})
// see #279
it('should also override alias', function () {
const argv = parser(['--foo.bar', '200'], {
alias: {
'foo.bar': ['f']
},
default: {
'foo.bar': 99
}
})
argv.f.should.eql(200)
})
// see #279
it('should not set an undefined dot notation key', function () {
const argv = parser(['--foo.bar', '200'], {
default: {
'foo.bar': 99
},
alias: {
'foo.bar': ['f']
}
})
; ('foo.bar' in argv).should.equal(false)
})
it('should respect .string() for dot notation arguments', function () {
const argv = parser(['--foo.bar', '99', '--bar.foo=99'], {
string: ['foo.bar']
})
argv.foo.bar.should.eql('99')
argv.bar.foo.should.eql(99)
})
it('should populate aliases when dot notation is used', function () {
const argv = parser(['--foo.bar', '99'], {
alias: {
foo: ['f']
}
})
argv.f.bar.should.eql(99)
argv.foo.bar.should.eql(99)
})
// see #267
it('should populate aliases when dot notation is used on camel-cased option', function () {
const argv = parser(['--foo-baz.bar', '99'], {
alias: {
'foo-baz': ['f']
}
})
argv.f.bar.should.eql(99)
argv['foo-baz'].bar.should.eql(99)
argv.fooBaz.bar.should.eql(99)
})
it('should populate aliases when nested dot notation is used', function () {
const argv = parser(['--foo.bar.snuh', '99', '--foo.apple', '33', '--foo.bar.cool', '11'], {
alias: {
foo: ['f']
}
})
argv.f.bar.snuh.should.eql(99)
argv.foo.bar.snuh.should.eql(99)
argv.f.apple.should.eql(33)
argv.foo.apple.should.eql(33)
argv.f.bar.cool.should.eql(11)
argv.foo.bar.cool.should.eql(11)
})
it("should allow flags to use dot notation, when separated by '='", function () {
const argv = parser(['-f.foo=99'])
argv.f.foo.should.eql(99)
})
it("should allow flags to use dot notation, when separated by ' '", function () {
const argv = parser(['-f.foo', '99'])
argv.f.foo.should.eql(99)
})
it('should allow flags to use dot notation when no right-hand-side is given', function () {
const argv = parser(['-f.foo', '99', '-f.bar'])
argv.f.foo.should.eql(99)
argv.f.bar.should.eql(true)
})
it('should not pollute the prototype', function () {
parser(['-f.__proto__.foo', '99', '-x.y.__proto__.bar', '100', '--__proto__', '200'])
Object.keys({}.__proto__).length.should.equal(0) // eslint-disable-line
expect({}.foo).to.equal(undefined)
expect({}.bar).to.equal(undefined)
})
})
it('should set boolean and alias using explicit true', function () {
const aliased = ['-h', 'true']
const aliasedArgv = parser(aliased, {
boolean: ['h'],
alias: {
h: ['herp']
}
})
aliasedArgv.should.have.property('herp', true)
aliasedArgv.should.have.property('h', true)
aliasedArgv.should.have.property('_').with.length(0)
})
// regression, see https://github.com/substack/node-optimist/issues/71
it('should set boolean and --x=true', function () {
let parsed = parser(['--boool', '--other=true'], {
boolean: ['boool']
})
parsed.should.have.property('boool', true)
parsed.should.have.property('other', 'true')
parsed = parser(['--boool', '--other=false'], {
boolean: ['boool']
})
parsed.should.have.property('boool', true)
parsed.should.have.property('other', 'false')
})
// regression, see https://github.com/chevex/yargs/issues/66
it('should set boolean options values if next value is "true" or "false" with = as separator', function () {
const argv = parser(['--bool=false'], {
boolean: ['b'],
alias: {
b: ['bool']
},
default: {
b: true
}
})
argv.bool.should.eql(false)
})
describe('short options', function () {
it('should set the value of multiple single short options to the next supplied values relative to each', function () {
const parse = parser(['-h', 'localhost', '-p', '555'])
parse.should.have.property('h', 'localhost')
parse.should.have.property('p', 555)
parse.should.have.property('_').with.length(0)
})
it('should set the value of a single short option to the next supplied value', function () {
const parse = parser(['-h', 'localhost'])
parse.should.have.property('h', 'localhost')
parse.should.have.property('_').with.length(0)
})
it('should expand grouped short options to a hash with a key for each', function () {
const parse = parser(['-cats'])
parse.should.have.property('c', true)
parse.should.have.property('a', true)
parse.should.have.property('t', true)
parse.should.have.property('s', true)
parse.should.have.property('_').with.length(0)
})
it('should set n to the numeric value 123', function () {
const argv = parser(['-n123'])
argv.should.have.property('n', 123)
})
it('should set n to the numeric value 123, with n at the end of a group', function () {
const argv = parser(['-ab5n123'])
argv.should.have.property('a', true)
argv.should.have.property('b', true)
argv.should.have.property('5', true)
argv.should.have.property('n', 123)
argv.should.have.property('_').with.length(0)
})
it('should set n to the numeric value 123, with = as separator', function () {
const argv = parser(['-n=123'])
argv.should.have.property('n', 123)
})
it('should set n to the numeric value 123, with n at the end of a group and = as separator', function () {
const argv = parser(['-ab5n=123'])
argv.should.have.property('a', true)
argv.should.have.property('b', true)
argv.should.have.property('5', true)
argv.should.have.property('n', 123)
argv.should.have.property('_').with.length(0)
})
})
describe('whitespace', function () {
it('should be whitespace', function () {
const argv = parser(['-x', '\t'])
argv.should.have.property('x', '\t')
})
})
describe('boolean modifier function', function () {
it('should prevent yargs from sucking in the next option as the value of the first option', function () {
// Arrange & Act
const result = parser(['-b', '123'], {
boolean: ['b']
})
// Assert
result.should.have.property('b').that.is.a('boolean').and.is.true // eslint-disable-line
result.should.have.property('_').and.deep.equal([123])
})
// Fixes: https://github.com/yargs/yargs-parser/issues/283
it('should set boolean numeric option, with numeric option at the end of a group', function () {
const result = parser(['-x1'], { boolean: ['x', '1'] })
expect(result).to.have.property('x', true)
expect(result).to.have.property('1', true)
})
it('should set boolean numeric option, with numeric option at the start of a group', function () {
const result = parser(['-1x'], { boolean: ['x', '1'] })
expect(result).to.have.property('x', true)
expect(result).to.have.property('1', true)
})
it('should set boolean numeric option, with numeric option as part of a group', function () {
const result = parser(['-x1b'], { boolean: ['x', '1', 'b'] })
expect(result).to.have.property('x', true)
expect(result).to.have.property('1', true)
expect(result).to.have.property('b', true)
})
})
describe('defaults', function () {
function checkNoArgs (opts, hasAlias) {
it('should set defaults if no args', function () {
const result = parser([], opts)
result.should.have.property('flag', true)
if (hasAlias) {
result.should.have.property('f', true)
}
})
}
function checkExtraArg (opts, hasAlias) {
it('should set defaults if one extra arg', function () {
const result = parser(['extra'], opts)
result.should.have.property('flag', true)
result.should.have.property('_').and.deep.equal(['extra'])
if (hasAlias) {
result.should.have.property('f', true)
}
})
}
function checkStringArg (opts, hasAlias) {
it('should set defaults even if arg looks like a string', function () {
const result = parser(['--flag', 'extra'], opts)
result.should.have.property('flag', true)
result.should.have.property('_').and.deep.equal(['extra'])
if (hasAlias) {
result.should.have.property('f', true)
}
})
}
describe('for options with aliases', function () {
const opts = {
alias: {
flag: ['f']
},
default: {
flag: true
}
}
checkNoArgs(opts, true)
checkExtraArg(opts, true)
})
describe('for typed options without aliases', function () {
const opts = {
boolean: ['flag'],
default: {
flag: true
}
}
checkNoArgs(opts)
checkExtraArg(opts)
checkStringArg(opts)
})
describe('for typed options with aliases', function () {
const opts = {
alias: {
flag: ['f']
},
boolean: ['flag'],
default: {
flag: true
}
}
checkNoArgs(opts, true)
checkExtraArg(opts, true)
checkStringArg(opts, true)
})
describe('for boolean options', function () {
[true, false, undefined, null].forEach(function (def) {
describe('with explicit ' + def + ' default', function () {
const opts = {
default: {
flag: def
},
boolean: ['flag']
}
it('should set true if --flag in arg', function () {
parser(['--flag'], opts).flag.should.be.true // eslint-disable-line
})
it('should set false if --no-flag in arg', function () {
parser(['--no-flag'], opts).flag.should.be.false // eslint-disable-line
})
it('should set ' + def + ' if no flag in arg', function () {
expect(parser([], opts).flag).to.equal(def)
})
})
})
describe('without any default value', function () {
let opts = null
beforeEach(function () {
opts = {
boolean: ['flag']
}
})
it('should set true if --flag in arg', function () {
parser(['--flag'], opts).flag.should.be.true // eslint-disable-line
})
it('should set false if --no-flag in arg', function () {
parser(['--no-flag'], opts).flag.should.be.false // eslint-disable-line
})
it('should not add property if no flag in arg', function () {
parser([''], opts).should.not.have.property('flag')
})
})
// Fixes: https://github.com/bcoe/yargs/issues/341
it('should apply defaults to camel-case form of argument', function () {
const argv = parser([], {
default: {
'foo-bar': 99
}
})
argv.fooBar.should.equal(99)
})
// Fixes: https://github.com/yargs/yargs-parser/issues/77
it('should combine dot-notation and camel-case expansion', function () {
const argv = parser(['--dot-notation.foo.bar'])
argv.should.satisfy(function (args) {
return args.dotNotation.foo.bar
})
})
})
it('should define option as boolean and set default to true', function () {
const argv = parser([], {
boolean: ['sometrue'],
default: {
sometrue: true
}
})
argv.should.have.property('sometrue', true)
})
it('should define option as boolean and set default to false', function () {
const argv = parser([], {
default: {
somefalse: false
},
boolean: ['somefalse']
})
argv.should.have.property('somefalse', false)
})
it('should set boolean options to false by default', function () {
const parse = parser(['moo'], {
boolean: ['t', 'verbose'],
default: {
verbose: false,
t: false
}
})
parse.should.have.property('verbose', false).and.be.a('boolean')
parse.should.have.property('t', false).and.be.a('boolean')
parse.should.have.property('_').and.deep.equal(['moo'])
})
describe('track defaulted', function () {
it('should log defaulted options - not specified by user', function () {
const parsed = parser.detailed('', {
default: { foo: 'abc', 'bar.prop': 33, baz: 'x' },
configObjects: [{ baz: 'xyz' }]
})
expect(parsed.argv).to.eql({ _: [], baz: 'xyz', foo: 'abc', bar: { prop: 33 } })
parsed.defaulted.should.deep.equal({ foo: true, 'bar.prop': true })
})
it('should not log defaulted options - specified without value', function () {
const parsed = parser.detailed('--foo --bar.prop', {
default: { foo: 'abc', 'bar.prop': 33 }
})
parsed.argv.should.deep.equal({ _: [], foo: 'abc', bar: { prop: 33 } })
parsed.defaulted.should.deep.equal({})
})
it('should log defaulted options - no aliases included', function () {
const parsed = parser.detailed('', {
default: { kaa: 'abc' },
alias: { foo: 'kaa' }
})
parsed.argv.should.deep.equal({ _: [], kaa: 'abc', foo: 'abc' })
parsed.defaulted.should.deep.equal({ kaa: true })
})
it('setting an alias excludes associated key from defaulted', function () {
const parsed = parser.detailed('--foo abc', {
default: { kaa: 'abc' },
alias: { foo: 'kaa' }
})
parsed.argv.should.deep.equal({ _: [], kaa: 'abc', foo: 'abc' })
parsed.defaulted.should.deep.equal({})
})
})
})
describe('camelCase', function () {
function runTests (strict) {
if (!strict) {
// Skip this test in strict mode because this option is not specified
it('should provide options with dashes as camelCase properties', function () {
const result = parser(['--some-option'])
result.should.have.property('some-option').that.is.a('boolean').and.is.true // eslint-disable-line
result.should.have.property('someOption').that.is.a('boolean').and.is.true // eslint-disable-line
})
}
it('should provide count options with dashes as camelCase properties', function () {
const result = parser(['--some-option', '--some-option', '--some-option'], {
count: ['some-option']
})
result.should.have.property('some-option', 3)
result.should.have.property('someOption', 3)
})
it('should provide options with dashes and aliases as camelCase properties', function () {
const result = parser(['--some-option'], {
alias: {
'some-horse': 'o'
}
})
result.should.have.property('some-option').that.is.a('boolean').and.is.true // eslint-disable-line
result.should.have.property('someOption').that.is.a('boolean').and.is.true // eslint-disable-line
})
it('should provide defaults of options with dashes as camelCase properties', function () {
const result = parser([], {
default: {
'some-option': 'asdf'
}
})
result.should.have.property('some-option', 'asdf')
result.should.have.property('someOption', 'asdf')
})
it('should provide aliases of options with dashes as camelCase properties', function () {
const result = parser([], {
default: {
'some-option': 'asdf'
},
alias: {
'some-option': ['o']
}
})
result.should.have.property('o', 'asdf')
result.should.have.property('some-option', 'asdf')
result.should.have.property('someOption', 'asdf')
})
it('should not apply camel-case logic to 1-character options', function () {
const result = parser(['-p', 'hello'], {
alias: {
p: 'parallel',
P: 'parallel-series'
}
})
result.should.not.have.property('P', 'hello')
result.should.not.have.property('parallel-series', 'hello')
result.should.not.have.property('parallelSeries', 'hello')
result.should.have.property('parallel', 'hello')
result.should.have.property('p', 'hello')
})
it('should provide aliases of options with dashes as camelCase properties', function () {
const result = parser([], {
alias: {
o: ['some-option']
},
default: {
o: 'asdf'
}
})
result.should.have.property('o', 'asdf')
result.should.have.property('some-option', 'asdf')
result.should.have.property('someOption', 'asdf')
})
it('should provide aliases with dashes as camelCase properties', function () {
const result = parser(['--some-option', 'val'], {
alias: {
o: 'some-option'
}
})
result.should.have.property('o').that.is.a('string').and.equals('val')
result.should.have.property('some-option').that.is.a('string').and.equals('val')
result.should.have.property('someOption').that.is.a('string').and.equals('val')
})
// https://github.com/yargs/yargs-parser/issues/95
it('should not duplicate option values when equivalent dashed aliases are provided', function () {
const result = parser(['--someOption', 'val'], {
alias: {
someOption: 'some-option'
}
})
result.should.have.property('some-option').that.is.a('string').and.equals('val')
result.should.have.property('someOption').that.is.a('string').and.equals('val')
})
}
describe('dashes and camelCase', function () {
runTests()
})
describe('dashes and camelCase (strict)', function () {
runTests(true)
})
})
describe('-', function () {
it('should set - as value of n', function () {
const argv = parser(['-n', '-'])
argv.should.have.property('n', '-')
argv.should.have.property('_').with.length(0)
})
it('should set - as a non-hyphenated value', function () {
const argv = parser(['-'])
argv.should.have.property('_').and.deep.equal(['-'])
})
it('should set - as a value of f', function () {
const argv = parser(['-f-'])
argv.should.have.property('f', '-')
argv.should.have.property('_').with.length(0)
})
it('should set b to true and set - as a non-hyphenated value when b is set as a boolean', function () {
const argv = parser(['-b', '-'], {
boolean: ['b']
})
argv.should.have.property('b', true)
argv.should.have.property('_').and.deep.equal(['-'])
})
it('should set - as the value of s when s is set as a string', function () {
const argv = parser(['-s', '-'], {
string: ['s']
})
argv.should.have.property('s', '-')
argv.should.have.property('_').with.length(0)
})
})
describe('count', function () {
it('should count the number of times a boolean is present', function () {
let parsed
parsed = parser(['-x'], {
count: ['verbose']
})
parsed.verbose.should.equal(0)
parsed = parser(['--verbose'], {
count: ['verbose']
})
parsed.verbose.should.equal(1)
parsed = parser(['--verbose', '--verbose'], {
count: ['verbose']
})
parsed.verbose.should.equal(2)
parsed = parser(['-vvv'], {
alias: {
v: ['verbose']
},
count: ['verbose']
})
parsed.verbose.should.equal(3)
parsed = parser(['--verbose', '--verbose', '-v', '--verbose'], {
count: ['verbose'],
alias: {
v: ['verbose']
}
})
parsed.verbose.should.equal(4)
parsed = parser(['--verbose', '--verbose', '-v', '-vv'], {
count: ['verbose'],
alias: {
v: ['verbose']
}
})
parsed.verbose.should.equal(5)
})
it('should not consume the next argument', function () {
let parsed = parser(['-v', 'moo'], {
count: 'v'
})
parsed.v.should.equal(1)
parsed.should.have.property('_').and.deep.equal(['moo'])
parsed = parser(['--verbose', 'moomoo', '--verbose'], {
count: 'verbose'
})
parsed.verbose.should.equal(2)
parsed.should.have.property('_').and.deep.equal(['moomoo'])
})
it('should use a default value as is when no arg given', function () {
let parsed = parser([], {
count: 'v',
default: { v: 3 }
})
parsed.v.should.equal(3)
parsed = parser([], {
count: 'v',
default: { v: undefined }
})
expect(parsed.v).to.be.undefined // eslint-disable-line
parsed = parser([], {
count: 'v',
default: { v: null }
})
expect(parsed.v).to.be.null // eslint-disable-line
parsed = parser([], {
count: 'v',
default: { v: false }
})
parsed.v.should.equal(false)
parsed = parser([], {
count: 'v',
default: { v: 'hello' }
})
parsed.v.should.equal('hello')
})
it('should ignore a default value when arg given', function () {
const parsed = parser(['-vv', '-v', '-v'], {
count: 'v',
default: { v: 1 }
})
parsed.v.should.equal(4)
})
it('should increment regardless of arg value', function () {
const parsed = parser([
'-v',
'-v=true',
'-v', 'true',
'-v=false',
'-v', 'false',
'--no-v',
'-v=999',
'-v=foobar'
], { count: 'v' })
parsed.v.should.equal(8)
})
it('should add an error if counter is also set as array', function () {
const argv = parser.detailed(['--counter', '--counter', '--counter'], {
count: ['counter'],
array: ['counter']
})
argv.error.message.should.equal('Invalid configuration: counter, opts.count excludes opts.array.')
})
it('should add an error if counter is also set as narg', function () {
const argv = parser.detailed(['--counter', 'foo', 'bar'], {
count: ['counter'],
narg: { counter: 2 }
})
argv.error.message.should.equal('Invalid configuration: counter, opts.count excludes opts.narg.')
})
})
describe('array', function () {
it('should group values into an array if the same option is specified multiple times (duplicate-arguments-array=true)', function () {
const parse = parser(['-v', 'a', '-v', 'b', '-v', 'c'], { configuration: { 'duplicate-arguments-array': true } })
parse.should.have.property('v').and.deep.equal(['a', 'b', 'c'])
parse.should.have.property('_').with.length(0)
})
it('should keep only the last value if the same option is specified multiple times (duplicate-arguments-false)', function () {
const parse = parser(['-v', 'a', '-v', 'b', '-v', 'c'], { configuration: { 'duplicate-arguments-array': false } })
parse.should.have.property('v').and.equal('c')
parse.should.have.property('_').with.length(0)
})
it('should default an array to an empty array if passed as first option followed by another', function () {
const result = parser(['-a', '-b'], {
array: 'a'
})
result.should.have.property('a').and.deep.equal([])
})
it('should not attempt to default array if an element has already been populated', function () {
const result = parser(['-a', 'foo', 'bar', '-b'], {
array: 'a'
})
result.should.have.property('a').and.deep.equal(['foo', 'bar'])
})
it('should default argument to empty array if no value given', function () {
const result = parser(['-b', '--tag'], {
array: ['b', 'tag'],
default: { tag: [] }
})
result.b.should.deep.equal([])
result.tag.should.deep.equal([])
})
it('should place default of argument in array, when default provided', function () {
const result = parser(['-b', '--tag'], {
array: ['b', 'tag'],
default: { b: 33, tag: ['foo'] }
})
result.b.should.deep.equal([33])
result.tag.should.deep.equal(['foo'])
})
it('should place value of argument in array, when one argument provided', function () {
const result = parser(['-b', '33'], {
array: ['b']
})
Array.isArray(result.b).should.equal(true)
result.b[0].should.equal(33)
})
it('should add multiple argument values to the array', function () {
const result = parser(['-b', '33', '-b', 'hello'], {
array: 'b'
})
Array.isArray(result.b).should.equal(true)
result.b.should.include(33)
result.b.should.include('hello')
})
it('should allow array: true, to be set inside an option block', function () {
const result = parser(['-b', '33'], {
array: 'b'
})
Array.isArray(result.b).should.equal(true)
result.b.should.include(33)
})
// issue #103
it('should default camel-case alias to array type', function () {
const result = parser(['--ca-path', 'http://www.example.com'], {
array: ['ca-path']
})
Array.isArray(result['ca-path']).should.equal(true)
Array.isArray(result.caPath).should.equal(true)
})
it('should default alias to array type', function () {
const result = parser(['--ca-path', 'http://www.example.com'], {
array: 'ca-path',
alias: {
'ca-path': 'c'
}
})
Array.isArray(result['ca-path']).should.equal(true)
Array.isArray(result.caPath).should.equal(true)
Array.isArray(result.c).should.equal(true)
})
// see: https://github.com/bcoe/yargs/issues/162
it('should eat non-hyphenated arguments until hyphenated option is hit', function () {
const result = parser(['-a=hello', 'world', '-b',
'33', '22', '--foo', 'red', 'green',
'--bar=cat', 'dog'], {
array: ['a', 'b', 'foo', 'bar']
})
Array.isArray(result.a).should.equal(true)
result.a.should.include('hello')
result.a.should.include('world')
Array.isArray(result.b).should.equal(true)
result.b.should.include(33)
result.b.should.include(22)
Array.isArray(result.foo).should.equal(true)
result.foo.should.include('red')
result.foo.should.include('green')
Array.isArray(result.bar).should.equal(true)
result.bar.should.include('cat')
result.bar.should.include('dog')
})
// see: https://github.com/yargs/yargs-parser/pull/13
it('should support array for --foo= format when the key is a number', function () {
const result = parser(['--1=a', 'b'], {
array: ['1']
})
Array.isArray(result['1']).should.equal(true)
result['1'][0].should.equal('a')
result['1'][1].should.equal('b')
})
it('should support array for -f= and --bar= format when the value is dashed', function () {
const result = parser(['-f=--dog', 'cat', '--bar=--red', 'green'], {
array: ['f', 'bar']
})
Array.isArray(result.f).should.equal(true)
result.f[0].should.equal('--dog')
result.f[1].should.equal('cat')
Array.isArray(result.bar).should.equal(true)
result.bar[0].should.equal('--red')
result.bar[1].should.equal('green')
})
it('should create an array when passing an argument twice with same value', function () {
const result = parser(['-x', 'val1', '-x', 'val1'])
result.should.have.property('x').that.is.an('array').and.to.deep.equal(['val1', 'val1'])
})
it('should eat camelCase switch with camelCase array option', function () {
const result = parser(['--someOption', '1', '2'], {
array: ['someOption']
})
Array.isArray(result.someOption).should.equal(true)
result.someOption.should.deep.equal([1, 2])
})
it('should eat hyphenated switch with hyphenated array option', function () {
const result = parser(['--some-option', '1', '2'], {
array: ['some-option']
})
Array.isArray(result['some-option']).should.equal(true)
result['some-option'].should.deep.equal([1, 2])
})
it('should eat camelCase switch with hyphenated array option', function () {
const result = parser(['--someOption', '1', '2'], {
array: ['some-option']
})
Array.isArray(result['some-option']).should.equal(true)
result['some-option'].should.deep.equal([1, 2])
})
it('should eat hyphenated switch with camelCase array option', function () {
const result = parser(['--some-option', '1', '2'], {
array: ['someOption']
})
Array.isArray(result.someOption).should.equal(true)
result.someOption.should.deep.equal([1, 2])
})
// see https://github.com/yargs/yargs-parser/issues/6
it('should respect the type `boolean` option for arrays', function () {
const result = parser(['-x=true', 'false'], {
array: [{ key: 'x', boolean: true }]
})
result.should.have.property('x').that.is.an('array').and.to.deep.equal([true, false])
})
it('should respect type `boolean` without value for arrays', function () {
const result = parser(['-x', '-x'], {
array: [{ key: 'x', boolean: true }],
configuration: { 'flatten-duplicate-arrays': false }
})
result.x.should.deep.equal([[true], [true]])
})
it('should respect `boolean negation` for arrays', function () {
const result = parser(['--no-bool', '--no-bool'], {
array: [{ key: 'bool', boolean: true }],
configuration: { 'flatten-duplicate-arrays': false }
})
result.bool.should.deep.equal([[false], [false]])
})
it('should respect the type `number` option for arrays', function () {
const result = parser(['-x=5', '2'], {
array: [{ key: 'x', number: true }]
})
result.should.have.property('x').that.is.an('array').and.to.deep.equal([5, 2])
})
it('should respect the type `string` option for arrays', function () {
const result = parser(['-x=5', '2'], {
configuration: {
'parse-numbers': true
},
array: [{ key: 'x', string: true }]
})
result.should.have.property('x').that.is.an('array').and.to.deep.equal(['5', '2'])
})
it('should eat non-hyphenated arguments until hyphenated option is hit - combined with coercion', function () {
const result = parser([
'-a=hello', 'world',
'-b', '33', '22',
'--foo', 'true', 'false',
'--bar=cat', 'dog'
], {
array: [
'a',
{ key: 'b', integer: true },
{ key: 'foo', boolean: true },
'bar'
]
})
Array.isArray(result.a).should.equal(true)
result.a.should.include('hello')
result.a.should.include('world')
Array.isArray(result.b).should.equal(true)
result.b.should.include(33)
result.b.should.include(22)
Array.isArray(result.foo).should.equal(true)
result.foo.should.include(true)
result.foo.should.include(false)
Array.isArray(result.bar).should.equal(true)
result.bar.should.include('cat')
result.bar.should.include('dog')
})
})
describe('nargs', function () {
it('should allow the number of arguments following a key to be specified', function () {
const result = parser(['--foo', 'apple', 'bar'], {
narg: {
foo: 2
}
})
Array.isArray(result.foo).should.equal(true)
result.foo[0].should.equal('apple')
result.foo[1].should.equal('bar')
})
it('should raise an exception if -f== format is used for a key with no expected argument', function () {
const argv = parser.detailed('-f=apple', {
narg: {
f: 0
}
})
argv.error.message.should.equal('Argument unexpected for: f')
})
it('should raise an exception if --bar== format is used for a key with no expected argument', function () {
const argv = parser.detailed('--bar=apple', {
narg: {
bar: 0
}
})
argv.error.message.should.equal('Argument unexpected for: bar')
})
it('should raise an exception if there are not enough arguments following key', function () {
const argv = parser.detailed('--foo apple', {
narg: {
foo: 2
}
})
argv.error.message.should.equal('Not enough arguments following: foo')
})
it('nargs is applied to aliases', function () {
const result = parser(['--bar', 'apple', 'bar'], {
narg: {
foo: 2
},
alias: {
foo: 'bar'
}
})
Array.isArray(result.foo).should.equal(true)
result.foo[0].should.equal('apple')
result.foo[1].should.equal('bar')
})
it('should apply nargs to flag arguments', function () {
const result = parser(['-f', 'apple', 'bar', 'blerg'], {
narg: {
f: 2
}
})
result.f[0].should.equal('apple')
result.f[1].should.equal('bar')
result._[0].should.equal('blerg')
})
it('should support nargs for -f= and --bar= format arguments', function () {
const result = parser(['-f=apple', 'bar', 'blerg', '--bar=monkey', 'washing', 'cat'], {
narg: {
f: 2,
bar: 2
}
})
result.f[0].should.equal('apple')
result.f[1].should.equal('bar')
result._[0].should.equal('blerg')
result.bar[0].should.equal('monkey')
result.bar[1].should.equal('washing')
result._[1].should.equal('cat')
})
it('should support nargs for -f= and --bar= format arguments with dashed values', function () {
const result = parser(['-f=--apple', 'bar', 'blerg', '--bar=-monkey', 'washing', 'cat'], {
narg: {
f: 2,
bar: 2
}
})
result.f[0].should.equal('--apple')
result.f[1].should.equal('bar')
result._[0].should.equal('blerg')
result.bar[0].should.equal('-monkey')
result.bar[1].should.equal('washing')
result._[1].should.equal('cat')
})
it('should not modify the input args if an = was used', function () {
const expected = ['-f=apple', 'bar', 'blerg', '--bar=monkey', 'washing', 'cat']
const args = expected.slice()
parser(args, {
narg: {
f: 2,
bar: 2
}
})
args.should.deep.equal(expected)
parser.detailed(args, {
narg: {
f: 2,
bar: 2
}
})
args.should.deep.equal(expected)
})
it('allows multiple nargs to be set at the same time', function () {
const result = parser(['--foo', 'apple', 'bar', '--bar', 'banana', '-f'], {
narg: {
foo: 2,
bar: 1
}
})
Array.isArray(result.foo).should.equal(true)
result.foo[0].should.equal('apple')
result.foo[1].should.equal('bar')
result.bar.should.equal('banana')
result.f.should.equal(true)
})
// see: https://github.com/yargs/yargs-parser/pull/13
it('should support nargs for --foo= format when the key is a number', function () {
const result = parser(['--1=a', 'b'], {
narg: {
1: 2
}
})
Array.isArray(result['1']).should.equal(true)
result['1'][0].should.equal('a')
result['1'][1].should.equal('b')
})
it('should not treat flag arguments as satisfying narg requirements', function () {
const result = parser.detailed(['--foo', '--bar', '99'], {
narg: {
foo: 1
}
})
result.argv.bar.should.equal(99)
result.error.message.should.equal('Not enough arguments following: foo')
})
// See: https://github.com/yargs/yargs-parser/issues/232
it('should treat flag arguments as satisfying narg requirements, if nargs-eats-options=true', function () {
const result = parser.detailed(['--foo', '--bar', '99', '--batman', 'robin'], {
narg: {
foo: 2
},
configuration: {
'nargs-eats-options': true
}
})
result.argv.foo.should.eql(['--bar', 99])
result.argv.batman.should.eql('robin')
})
it('should not consume more than configured nargs', function () {
const result = parser(['--foo', 'a', 'b'], {
narg: {
foo: 1
}
})
result.foo.should.eql('a')
})
it('should ignore undefined configured nargs', function () {
const result = parser(['--foo', 'a', 'b'], {
narg: {
foo: undefined
}
})
result.foo.should.eql('a')
})
it('should default to 1 if configured narg is NaN', function () {
const result = parser(['--foo', 'a', 'b'], {
narg: {
foo: NaN
}
})
result.foo.should.eql('a')
})
})
describe('env vars', function () {
it('should apply all env vars if prefix is empty', function () {
process.env.ONE_FISH = 'twofish'
process.env.RED_FISH = 'bluefish'
const result = parser([], {
envPrefix: ''
})
result.oneFish.should.equal('twofish')
result.redFish.should.equal('bluefish')
})
// envPrefix falls back to empty string if not a string
it('should apply all env vars if prefix is not a string', function () {
process.env.ONE_FISH = 'twofish'
process.env.RED_FISH = 'bluefish'
const result = parser([], {
envPrefix: null
})
result.oneFish.should.equal('twofish')
result.redFish.should.equal('bluefish')
})
it('should not apply all env vars if prefix is undefined', function () {
process.env.ONE_FISH = 'twofish'
process.env.RED_FISH = 'bluefish'
const result = parser([], {
envPrefix: undefined
})
expect(result).to.not.have.property('oneFish')
expect(result).to.not.have.property('redFish')
})
it('should apply only env vars matching prefix if prefix is valid string', function () {
process.env.ONE_FISH = 'twofish'
process.env.RED_FISH = 'bluefish'
process.env.GREEN_EGGS = 'sam'
process.env.GREEN_HAM = 'iam'
const result = parser([], {
envPrefix: 'GREEN'
})
result.eggs.should.equal('sam')
result.ham.should.equal('iam')
expect(result.oneFish).to.be.undefined // eslint-disable-line
expect(result.redFish).to.be.undefined // eslint-disable-line
})
it('should set aliases for options defined by env var', function () {
process.env.AIRFORCE_ONE = 'two'
const result = parser([], {
envPrefix: 'AIRFORCE',
alias: {
1: ['one', 'uno']
}
})
result['1'].should.equal('two')
result.one.should.equal('two')
result.uno.should.equal('two')
})
it('should prefer command line value over env var', function () {
process.env.FOO_BAR = 'ignore'
const result = parser(['--foo-bar', 'baz'], {
envPrefix: ''
})
result.fooBar.should.equal('baz')
})
it('should respect type for args defined by env var', function () {
process.env.MY_TEST_STRING = '1'
process.env.MY_TEST_NUMBER = '2'
const result = parser([], {
string: 'string',
envPrefix: 'MY_TEST_'
})
result.string.should.equal('1')
result.number.should.equal(2)
})
it('should set option from aliased env var', function () {
process.env.SPACE_X = 'awesome'
const result = parser([], {
alias: {
xactly: 'x'
},
envPrefix: 'SPACE'
})
result.xactly.should.equal('awesome')
})
it('should prefer env var value over configured default', function () {
process.env.FOO_BALL = 'wut'
process.env.FOO_BOOL = 'true'
const result = parser([], {
envPrefix: 'FOO',
default: {
ball: 'baz',
bool: false
},
boolean: 'bool',
string: 'ball'
})
result.ball.should.equal('wut')
result.bool.should.equal(true)
})
const jsonPath = path.resolve(__dirname, './fixtures/config.json')
it('should prefer environment variables over config file', function () {
process.env.CFG_HERP = 'zerp'
const result = parser(['--cfg', jsonPath], {
envPrefix: 'CFG',
config: 'cfg',
string: 'herp',
default: {
herp: 'nerp'
}
})
result.herp.should.equal('zerp')
})
it('should support an env var value as config file option', function () {
process.env.TUX_CFG = jsonPath
const result = parser([], {
envPrefix: 'TUX',
config: ['cfg'],
default: {
z: 44
}
})
result.should.have.property('herp')
result.should.have.property('foo')
result.should.have.property('version')
result.should.have.property('truthy')
result.z.should.equal(55)
})
it('should prefer cli config file option over env var config file option', function () {
process.env.MUX_CFG = path.resolve(__dirname, '../package.json')
const result = parser(['--cfg', jsonPath], {
envPrefix: 'MUX',
config: 'cfg'
})
result.should.have.property('herp')
result.should.have.property('foo')
result.should.have.property('version')
result.should.have.property('truthy')
result.z.should.equal(55)
})
it('should apply all nested env vars', function () {
process.env.TEST_A = 'a'
process.env.TEST_NESTED_OPTION__FOO = 'baz'
process.env.TEST_NESTED_OPTION__BAR = 'bar'
const result = parser(['--nestedOption.foo', 'bar'], {
envPrefix: 'TEST'
})
result.should.have.property('a', 'a')
result.should.have.property('nestedOption').and.deep.equal({
foo: 'bar',
bar: 'bar'
})
})
it('should apply nested env var if argv value is using default value', function () {
process.env.TEST_A = 'a'
process.env.TEST_NESTED_OPTION__FOO = 'baz'
process.env.TEST_NESTED_OPTION__BAR = 'bar'
const result = parser([], {
envPrefix: 'TEST',
default: {
'nestedOption.foo': 'banana'
}
})
result.should.have.property('a', 'a')
result.should.have.property('nestedOption').and.deep.equal({
foo: 'baz',
bar: 'bar'
})
})
})
describe('configuration', function () {
describe('short option groups', function () {
it('allows short-option-groups to be disabled', function () {
let parse = parser(['-cats=meow'], {
configuration: {
'short-option-groups': false
}
})
parse.cats.should.equal('meow')
parse = parser(['-cats', 'meow'], {
configuration: {
'short-option-groups': false
}
})
parse.cats.should.equal('meow')
})
})
describe('camel-case expansion', function () {
it('does not expand camel-case aliases', function () {
const parsed = parser.detailed([], {
alias: {
'foo-bar': ['x']
},
configuration: {
'camel-case-expansion': false
}
})
expect(parsed.newAliases.fooBar).to.equal(undefined)
expect(parsed.aliases.fooBar).to.equal(undefined)
})
it('does not expand camel-case keys', function () {
const parsed = parser.detailed(['--foo-bar=apple'], {
configuration: {
'camel-case-expansion': false
}
})
expect(parsed.argv.fooBar).to.equal(undefined)
expect(parsed.argv['foo-bar']).to.equal('apple')
})
})
describe('dot notation', function () {
it('does not expand dot notation defaults', function () {
const parsed = parser([], {
default: {
'foo.bar': 'x'
},
configuration: {
'dot-notation': false
}
})
expect(parsed['foo.bar']).to.equal('x')
})
it('does not expand dot notation arguments', function () {
let parsed = parser(['--foo.bar', 'banana'], {
configuration: {
'dot-notation': false
}
})
expect(parsed['foo.bar']).to.equal('banana')
parsed = parser(['--foo.bar=banana'], {
configuration: {
'dot-notation': false
}
})
expect(parsed['foo.bar']).to.equal('banana')
})
it('should use value from cli, if cli overrides dot notation default', function () {
const parsed = parser(['--foo.bar', 'abc'], {
default: {
'foo.bar': 'default'
},
configuration: {
'dot-notation': false
}
})
expect(parsed['foo.bar']).to.equal('abc')
})
it('should also override dot notation alias', function () {
const parsed = parser(['--foo.bar', 'abc'], {
alias: {
'foo.bar': ['alias.bar']
},
default: {
'foo.bar': 'default'
},
configuration: {
'dot-notation': false
}
})
expect(parsed['alias.bar']).to.equal('abc')
})
it('does not expand alias of first element of dot notation arguments', function () {
const parsed = parser(['--foo.bar', 'banana'], {
alias: {
foo: ['f']
},
configuration: {
'dot-notation': false
}
})
expect(parsed['foo.bar']).to.equal('banana')
expect(parsed).not.to.include.keys('f.bar')
})
// addresses https://github.com/yargs/yargs/issues/716
it('does not append nested-object keys from config to top-level key', function () {
const parsed = parser([], {
alias: {
foo: ['f']
},
configuration: {
'dot-notation': false
},
configObjects: [
{
'website.com': {
a: 'b',
b: 'c'
}
}
]
})
parsed['website.com'].should.deep.equal({
a: 'b',
b: 'c'
})
})
})
describe('parse-positional-numbers', () => {
it('does not parse positionals into numbers when false', function () {
const parsed = parser(['5.0', '3'], {
configuration: {
'parse-positional-numbers': false
}
})
expect(parsed._[0]).to.equal('5.0')
expect(parsed._[1]).to.equal('3')
})
it('parses positionals into numbers by default', function () {
const parsed = parser(['5.0', '3'])
expect(parsed._[0]).to.equal(5)
expect(parsed._[1]).to.equal(3)
})
})
describe('parse numbers', function () {
it('does not coerce defaults into numbers', function () {
const parsed = parser([], {
default: {
foo: '5'
},
configuration: {
'parse-numbers': false
}
})
expect(parsed.foo).to.equal('5')
})
it('does not coerce arguments into numbers', function () {
const parsed = parser(['--foo', '5'], {
configuration: {
'parse-numbers': false
}
})
expect(parsed.foo).to.equal('5')
})
it('does not coerce positional arguments into numbers', function () {
const parsed = parser(['5'], {
configuration: {
'parse-numbers': false
}
})
expect(parsed._[0]).to.equal('5')
})
it('parses number if option explicitly set to number type', function () {
const parsed = parser(['--foo', '5', '--bar', '6', '--baz', '7'], {
number: ['bar', 'baz'],
coerce: {
baz: val => val
},
configuration: {
'parse-numbers': false
}
})
expect(parsed.foo).to.equal('5')
expect(parsed.bar).to.equal(6)
expect(parsed.baz).to.equal(7)
})
it('should coerce elements of number typed arrays to numbers', function () {
const parsed = parser(['--foo', '4', '--foo', '5', '2'], {
array: ['foo'],
configObjects: [{ foo: ['1', '2', '3'] }],
configuration: {
'combine-arrays': true,
'flatten-duplicate-arrays': false
}
})
expect(parsed.foo).to.deep.equal([[4], [5, 2], [1, 2, 3]])
})
})
describe('boolean negation', function () {
it('does not negate arguments prefixed with --no-', function () {
const parsed = parser(['--no-dice'], {
configuration: {
'boolean-negation': false
}
})
parsed['no-dice'].should.equal(true)
expect(parsed.dice).to.equal(undefined)
})
it('negates boolean arguments with correct prefix', function () {
const parsed = parser(['--foodice'], {
configuration: {
'negation-prefix': 'foo'
}
})
expect(parsed.dice).to.equal(false)
})
})
describe('duplicate arguments array', function () {
it('adds duplicate argument to array', function () {
const parsed = parser('-x a -x b', {
configuration: {
'duplicate-arguments-array': true
}
})
parsed.x.should.deep.equal(['a', 'b'])
})
it('keeps only last argument', function () {
const parsed = parser('-x a -x b', {
configuration: {
'duplicate-arguments-array': false
}
})
parsed.x.should.equal('b')
})
it('does not interfere with nargs', function () {
const parsed = parser('-x a b c -x o p q', {
narg: { x: 3 },
configuration: {
'duplicate-arguments-array': false
}
})
parsed.x.should.deep.equal(['o', 'p', 'q'])
})
})
describe('flatten duplicate arrays', function () {
it('flattens duplicate array type', function () {
const parsed = parser('-x a b -x c d', {
array: ['x'],
configuration: {
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal(['a', 'b', 'c', 'd'])
})
it('nests duplicate array types', function () {
const parsed = parser('-x a b -x c d', {
array: ['x'],
configuration: {
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal([['a', 'b'], ['c', 'd']])
})
it('nests duplicate array types of more than 2', function () {
const parsed = parser('-x a b -x c d -x e f -x g h', {
array: ['x'],
configuration: {
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal([['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']])
})
it('doesn\'t nests single arrays', function () {
const parsed = parser('-x a b', {
array: ['x'],
configuration: {
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal(['a', 'b'])
})
it('flattens duplicate array type, when argument uses dot notation', function () {
const parsed = parser('-x.foo a -x.foo b', {
array: ['x.foo'],
configuration: {
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal({ foo: ['a', 'b'] })
})
})
describe('duplicate-arguments-array VS flatten-duplicate-arrays', function () {
/*
duplicate=false, flatten=false
type=array
[-x 1 2 3] => [1, 2, 3]
[-x 1 2 3 -x 2 3 4] => [2, 3, 4]
type=string/number/etc
[-x 1 -x 2 -x 3] => 3
duplicate=false, flatten=true
type=array
[-x 1 2 3] => [1, 2, 3]
[-x 1 2 3 -x 2 3 4] => [2, 3, 4]
type=string/number/etc
[-x 1 -x 2 -x 3] => 3
duplicate=true, flatten=true
type=array
[-x 1 2 3] => [1, 2, 3]
[-x 1 2 3 -x 2 3 4] => [1, 2, 3, 2, 3, 4]
type=string/number/etc
[-x 1 -x 2 -x 3] => [1, 2, 3]
duplicate=true, flatten=false
type=array
[-x 1 2 3] => [1, 2, 3]
[-x 1 2 3 -x 2 3 4] => [[1, 2, 3], [2, 3, 4]]
type=string/number/etc
[-x 1 -x 2 -x 3] => [1, 2, 3]
*/
describe('duplicate=false, flatten=false,', function () {
describe('type=array', function () {
it('[-x 1 2 3] => [1, 2, 3]', function () {
const parsed = parser('-x 1 2 3', {
array: ['x'],
configuration: {
'duplicate-arguments-array': false,
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal([1, 2, 3])
})
it('[-x 1 2 3 -x 2 3 4] => [2, 3, 4]', function () {
const parsed = parser('-x 1 2 3 -x 2 3 4', {
array: ['x'],
configuration: {
'duplicate-arguments-array': false,
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal([2, 3, 4])
})
})
describe('type=number', function () {
it('[-x 1 -x 2 -x 3] => 3', function () {
const parsed = parser('-x 1 -x 2 -x 3', {
number: 'x',
configuration: {
'duplicate-arguments-array': false,
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal(3)
})
})
describe('type=boolean', function () {
it('[-x true -x true -x false] => false', function () {
const parsed = parser('-x true -x true -x false', {
boolean: ['x'],
configuration: {
'duplicate-arguments-array': false,
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal(false)
})
})
})
describe('duplicate=false, flatten=true,', function () {
describe('type=array', function () {
it('[-x 1 2 3] => [1, 2, 3]', function () {
const parsed = parser('-x 1 2 3', {
array: ['x'],
configuration: {
'duplicate-arguments-array': false,
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal([1, 2, 3])
})
it('[-x 1 2 3 -x 2 3 4] => [2, 3, 4]', function () {
const parsed = parser('-x 1 2 3 -x 2 3 4', {
array: ['x'],
configuration: {
'duplicate-arguments-array': false,
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal([2, 3, 4])
})
})
describe('type=number', function () {
it('[-x 1 -x 2 -x 3] => 3', function () {
const parsed = parser('-x 1 -x 2 -x 3', {
number: 'x',
configuration: {
'duplicate-arguments-array': false,
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal(3)
})
})
describe('type=boolean', function () {
it('[-x true -x true -x false] => false', function () {
const parsed = parser('-x true -x true -x false', {
boolean: ['x'],
configuration: {
'duplicate-arguments-array': false,
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal(false)
})
})
})
describe('duplicate=true, flatten=true,', function () {
describe('type=array', function () {
it('[-x 1 2 3] => [1, 2, 3]', function () {
const parsed = parser('-x 1 2 3', {
array: ['x'],
configuration: {
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal([1, 2, 3])
})
it('[-x 1 2 3 -x 2 3 4] => [1, 2, 3, 2, 3, 4]', function () {
const parsed = parser('-x 1 2 3 -x 2 3 4', {
array: ['x'],
configuration: {
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal([1, 2, 3, 2, 3, 4])
})
})
describe('type=number', function () {
it('[-x 1 -x 2 -x 3] => [1, 2, 3]', function () {
const parsed = parser('-x 1 -x 2 -x 3', {
number: 'x',
configuration: {
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal([1, 2, 3])
})
})
describe('type=boolean', function () {
// in the casse of boolean arguments, only the last argument is used:
it('[-x true -x true -x false] => false', function () {
const parsed = parser('-x true -x true -x false', {
boolean: ['x'],
configuration: {
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': true
}
})
parsed.x.should.deep.equal(false)
})
})
})
describe('duplicate=true, flatten=false,', function () {
describe('type=array', function () {
it('[-x 1 -x 2 -x 3] => [[1], [2], [3]]', function () {
const parsed = parser('-x 1 -x 2 -x 3', {
array: ['x'],
configuration: {
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal([[1], [2], [3]])
})
it('[-x 1 2 3 -x 2 3 4] => [[1, 2, 3], [ 2, 3, 4]]', function () {
const parsed = parser('-x 1 2 3 -x 2 3 4', {
array: ['x'],
configuration: {
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal([[1, 2, 3], [2, 3, 4]])
})
})
describe('type=number', function () {
it('[-x 1 -x 2 -x 3] => [1, 2, 3]', function () {
const parsed = parser('-x 1 -x 2 -x 3', {
number: 'x',
configuration: {
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal([1, 2, 3])
})
})
describe('type=boolean', function () {
it('[-x true -x true -x false] => false', function () {
const parsed = parser('-x true -x true -x false', {
boolean: ['x'],
configuration: {
'duplicate-arguments-array': true,
'flatten-duplicate-arrays': false
}
})
parsed.x.should.deep.equal(false)
})
})
})
})
describe('populate--', function () {
it('should populate "_" by default', function () {
const result = parser([
'bare',
'--', '-h', 'eek', '--'
])
result.should.have.property('_').and.deep.equal(['bare', '-h', 'eek', '--'])
result.should.not.have.property('--')
})
it('should populate "_" when given config with "short-option-groups" false', function () {
const result = parser.detailed([
'--', 'foo'
], {
configuration: {
'short-option-groups': false
}
})
result.argv.should.deep.equal({ _: ['foo'] })
result.argv.should.not.have.property('--')
result.newAliases.should.deep.equal({})
})
it('should populate the "--" if populate-- is "true"', function () {
const result = parser([
'--name=meowmers', 'bare', '-cats', 'woo', 'moxy',
'-h', 'awesome', '--multi=quux',
'--key', 'value',
'-b', '--bool', '--no-meep', '--multi=baz',
'--', '--not-a-flag', '-', '-h', '-multi', '--', 'eek'
], {
configuration: {
'populate--': true
}
})
result.should.have.property('c', true)
result.should.have.property('a', true)
result.should.have.property('t', true)
result.should.have.property('s', 'woo')
result.should.have.property('h', 'awesome')
result.should.have.property('b', true)
result.should.have.property('bool', true)
result.should.have.property('key', 'value')
result.should.have.property('multi').and.deep.equal(['quux', 'baz'])
result.should.have.property('meep', false)
result.should.have.property('name', 'meowmers')
result.should.have.property('_').and.deep.equal(['bare', 'moxy'])
result.should.have.property('--').and.deep.equal(['--not-a-flag', '-', '-h', '-multi', '--', 'eek'])
})
})
describe('set-placeholder-key', function () {
it('should not set placeholder key by default', function () {
const parsed = parser([], {
string: ['a']
})
parsed.should.not.have.property('a')
})
it('should set placeholder key to "undefined"', function () {
const parsed = parser([], {
array: ['a'],
boolean: ['b'],
string: ['c'],
number: ['d'],
count: ['e'],
normalize: ['f'],
narg: { g: 2 },
coerce: {
h: function (arg) {
return arg
}
},
configuration: { 'set-placeholder-key': true }
})
parsed.should.have.property('a')
expect(parsed.a).to.be.equal(undefined)
parsed.should.have.property('b')
expect(parsed.b).to.be.equal(undefined)
parsed.should.have.property('c')
expect(parsed.c).to.be.equal(undefined)
parsed.should.have.property('d')
expect(parsed.d).to.be.equal(undefined)
parsed.should.have.property('e')
expect(parsed.f).to.be.equal(undefined)
parsed.should.have.property('g')
expect(parsed.g).to.be.equal(undefined)
parsed.should.have.property('h')
expect(parsed.h).to.be.equal(undefined)
})
it('should not set placeholder for key with a default value', function () {
const parsed = parser([], {
string: ['a'],
default: { a: 'hello' },
configuration: { 'set-placeholder-key': true }
})
parsed.a.should.equal('hello')
})
it('should not set placeholder key with dot notation', function () {
const parsed = parser([], {
string: ['a.b']
})
parsed.should.not.have.property('a')
parsed.should.not.have.property('b')
parsed.should.not.have.property('a.b')
})
it('should not set placeholder key with dot notation when `set-placeholder-key` is `true`', function () {
const parsed = parser([], {
string: ['a.b'],
configuration: {
'set-placeholder-key': true
}
})
parsed.should.not.have.property('a')
parsed.should.not.have.property('b')
parsed.should.not.have.property('a.b')
})
})
describe('halt-at-non-option', function () {
it('gets the entire rest of line', function () {
const parse = parser(['--foo', './file.js', '--foo', '--bar'], {
configuration: { 'halt-at-non-option': true },
boolean: ['foo', 'bar']
})
parse.should.deep.equal({ foo: true, _: ['./file.js', '--foo', '--bar'] })
})
it('is not influenced by --', function () {
const parse = parser(
['--foo', './file.js', '--foo', '--', 'barbar', '--bar'],
{ configuration: { 'halt-at-non-option': true }, boolean: ['foo', 'bar'] }
)
parse.should.deep.equal({
foo: true,
_: ['./file.js', '--foo', '--', 'barbar', '--bar']
})
})
it('is not influenced by unknown options', function () {
const parse = parser(
['-v', '--long', 'arg', './file.js', '--foo', '--', 'barbar'],
{ configuration: { 'halt-at-non-option': true }, boolean: ['foo'] }
)
parse.should.deep.equal({
v: true,
long: 'arg',
_: ['./file.js', '--foo', '--', 'barbar']
})
})
})
describe('unknown-options-as-args = true', function () {
it('should ignore unknown options in long format separated by =', function () {
const argv = parser('--known-arg=1 --unknown-arg=2', {
number: ['known-arg'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['--unknown-arg=2'],
'known-arg': 1,
knownArg: 1
})
})
it('should ignore unknown options in boolean negations', function () {
const argv = parser('--no-known-arg --no-unknown-arg', {
boolean: ['known-arg'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['--no-unknown-arg'],
'known-arg': false,
knownArg: false
})
})
it('should ignore unknown options in long format separated by space', function () {
const argv = parser('--known-arg a --unknown-arg b', {
string: ['known-arg'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['--unknown-arg', 'b'],
'known-arg': 'a',
knownArg: 'a'
})
})
it('should ignore unknown options in short dot format separated by equals', function () {
const argv = parser('-k.arg=a -u.arg=b', {
string: ['k.arg'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['-u.arg=b'],
k: {
arg: 'a'
}
})
})
it('should ignore unknown options in short dot format separated by space', function () {
const argv = parser('-k.arg 1 -u.arg 2', {
number: ['k.arg'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['-u.arg', 2],
k: {
arg: 1
}
})
})
it('should ignore unknown options in short format separated by equals', function () {
const argv = parser('-k=a -u=b', {
string: ['k'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['-u=b'],
k: 'a'
})
})
it('should ignore unknown options in short format followed by hyphen', function () {
const argv = parser('-k- -u-', {
string: ['k'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['-u-'],
k: '-'
})
})
it('should ignore unknown options in short format separated by space', function () {
const argv = parser('-k 1 -u 2', {
number: ['k'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['-u', 2],
k: 1
})
})
it('should allow an unknown arg to be used as the value of another flag in short form', function () {
const argv = parser('-k -u', {
string: ['k'],
narg: { k: 1 },
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: [],
k: '-u'
})
})
it('should allow an unknown arg to be used as the value of another flag in long form', function () {
const argv = parser('--known-arg --unknown-arg', {
string: ['known-arg'],
narg: { 'known-arg': 1 },
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: [],
knownArg: '--unknown-arg',
'known-arg': '--unknown-arg'
})
})
it('should allow an unknown arg to be used as the value of another flag in array form', function () {
const argv = parser('--known-arg --unknown-arg1 --unknown-arg2', {
array: ['known-arg'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: [],
knownArg: ['--unknown-arg1', '--unknown-arg2'],
'known-arg': ['--unknown-arg1', '--unknown-arg2']
})
})
it('should ignore unknown options in short format followed by a number', function () {
const argv = parser('-k1 -u2', {
number: ['k'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['-u2'],
k: 1
})
})
it('should ignore unknown options in short format followed by a non-word character', function () {
const argv = parser('-k/1/ -u/2/', {
string: ['k'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['-u/2/'],
k: '/1/'
})
})
it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is before the end', function () {
const argv = parser('-kuv', {
boolean: ['k', 'v'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['-kuv']
})
})
it('should parse known options in short format with multiple flags in one argument where no unknown flag is in the argument', function () {
const argv = parser('-kv', {
boolean: ['k', 'v'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: [],
k: true,
v: true
})
})
it('should parse negative numbers', function () {
const argv = parser('-k -33', {
boolean: ['k'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: [-33],
k: true
})
})
it('should not identify "--" as an unknown option', function () {
const argv = parser('-a -k one -1 -- -b -k two -2', {
boolean: ['k'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['-a', 'one', -1, '-b', '-k', 'two', '-2'],
k: true
})
})
it('should not identify "--" as an unknown option when "populate--" is true', function () {
const argv = parser('-a -k one -1 -- -b -k two -2', {
boolean: ['k'],
configuration: {
'populate--': true,
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
// populate argv._ with everything before the --
_: ['-a', 'one', -1],
// and argv['--'] with everything after the --
'--': ['-b', '-k', 'two', '-2'],
k: true
})
})
// See: https://github.com/yargs/yargs/issues/1869
// ----=hello ---=hello ---- hello.
it('should not populate "--" for key values other than "--"', () => {
const argv = parser('----=test', {
configuration: {
'populate--': true
}
})
argv._.should.eql(['----=test'])
expect(argv['--']).to.equal(undefined)
})
// see: https://github.com/yargs/yargs/issues/1489
it('should identify "hasOwnProperty" as unknown option', () => {
const argv = parser('--known-arg=1 --hasOwnProperty=33', {
number: ['known-arg'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['--hasOwnProperty=33'],
'known-arg': 1,
knownArg: 1
})
})
it('should coerce unknown options that look numeric into numbers', () => {
const argv = parser('--known-arg 33', {
boolean: ['known-arg']
})
argv.should.deep.equal({
_: [33],
'known-arg': true,
knownArg: true
})
})
})
// See: https://github.com/yargs/yargs-parser/issues/231
it('should collect unknown options terminated with digit', function () {
const argv = parser('--known-arg=1 --num2', {
alias: { num: ['n'] },
number: ['known-arg'],
configuration: {
'unknown-options-as-args': true
}
})
argv.should.deep.equal({
_: ['--num2'],
'known-arg': 1,
knownArg: 1
})
})
})
// addresses: https://github.com/yargs/yargs-parser/issues/41
it('defaults to empty array if array option is provided no values', function () {
let parsed = parser(['-f'], {
alias: {
f: 'files'
},
array: ['files']
})
parsed.f.should.deep.equal([])
parsed.files.should.deep.equal([])
parsed = parser(['--files'], {
alias: {
f: 'files'
},
array: ['files']
})
parsed.f.should.deep.equal([])
parsed.files.should.deep.equal([])
parsed = parser(['-f', '-y'], {
alias: {
f: 'files'
},
array: ['files']
})
parsed.f.should.deep.equal([])
parsed.files.should.deep.equal([])
})
describe('coerce', function () {
it('applies coercion function to simple arguments', function () {
const parsed = parser(['--foo', '99'], {
coerce: {
foo: function (arg) {
return arg * -1
}
}
})
parsed.foo.should.equal(-99)
})
it('applies coercion function to aliases', function () {
const parsed = parser(['--foo', '99'], {
coerce: {
f: function (arg) {
return arg * -1
}
},
alias: {
f: ['foo']
}
})
parsed.foo.should.equal(-99)
parsed.f.should.equal(-99)
})
it('applies coercion function to all dot options', function () {
const parsed = parser(['--foo.bar', 'nananana'], {
coerce: {
foo: function (val) {
val.bar += ', batman!'
return val
}
}
})
parsed.foo.bar.should.equal('nananana, batman!')
})
it('applies coercion to defaults', function () {
const parsed = parser([], {
default: { foo: 'bar' },
coerce: {
foo: function (val) {
return val.toUpperCase()
}
}
})
parsed.foo.should.equal('BAR')
})
it('applies coercion function to an implicit array', function () {
const parsed = parser(['--foo', '99', '-f', '33'], {
coerce: {
f: function (arg) {
return arg.map(function (a) {
return a * -1
})
}
},
alias: {
f: ['foo']
}
})
parsed.f.should.deep.equal([-99, -33])
parsed.foo.should.deep.equal([-99, -33])
})
it('applies coercion function to an explicit array', function () {
const parsed = parser(['--foo', '99', '-f', '33'], {
coerce: {
f: function (arg) {
return arg.map(function (a) {
return a * -1
})
}
},
array: ['foo'],
alias: {
f: ['foo']
}
})
parsed.f.should.deep.equal([-99, -33])
parsed.foo.should.deep.equal([-99, -33])
})
it('applies coercion function to _', function () {
const parsed = parser(['99', '33'], {
coerce: {
_: function (arg) {
return arg.map(function (a) {
return a * -1
})
}
}
})
parsed._.should.deep.equal([-99, -33])
})
// see: https://github.com/yargs/yargs/issues/550
it('coercion function can be used to parse large #s', function () {
const fancyNumberParser = function (arg) {
if (arg.length > 10) return arg
else return parseInt(arg)
}
const parsed = parser(['--foo', '88888889999990000998989898989898', '--bar', '998'], {
coerce: {
foo: fancyNumberParser,
bar: fancyNumberParser
}
})
; (typeof parsed.foo).should.equal('string')
parsed.foo.should.equal('88888889999990000998989898989898')
; (typeof parsed.bar).should.equal('number')
parsed.bar.should.equal(998)
})
it('populates argv.error, if an error is thrown', function () {
const parsed = parser.detailed(['--foo', '99'], {
coerce: {
foo: function (arg) {
throw Error('banana')
}
}
})
parsed.error.message.should.equal('banana')
})
it('populates argv.error, if an error is thrown for an explicit array', function () {
const parsed = parser.detailed(['--foo', '99'], {
array: ['foo'],
coerce: {
foo: function (arg) {
throw Error('foo is array: ' + Array.isArray(arg))
}
}
})
parsed.error.message.should.equal('foo is array: true')
})
// see: https://github.com/yargs/yargs-parser/issues/76
it('only runs coercion functions once, even with aliases', function () {
let runcount = 0
const func = (arg) => {
runcount++
return undefined
}
parser(['--foo', 'bar'], {
alias: {
foo: ['f', 'foo-bar', 'bar'],
b: ['bar']
},
coerce: {
bar: func
}
})
runcount.should.equal(1)
})
})
// see: https://github.com/yargs/yargs-parser/issues/37
it('normalizes all paths in array when provided via config object', function () {
const argv = parser(['--foo', 'bar'], {
array: ['a'],
normalize: ['a'],
configObjects: [{ a: ['bin/../a.txt', 'bin/../b.txt'] }]
})
argv.a.should.deep.equal(['a.txt', 'b.txt'])
})
// see: https://github.com/yargs/yargs/issues/963
it('does not magically convert numeric strings larger than Number.MAX_SAFE_INTEGER', () => {
const argv = parser(['--foo', '93940495950949399948393'])
argv.foo.should.equal('93940495950949399948393')
})
it('does not magically convert scientific notation larger than Number.MAX_SAFE_INTEGER', () => {
const argv = parser(['--foo', '33e99999'])
argv.foo.should.equal('33e99999')
})
it('converts numeric options larger than Number.MAX_SAFE_INTEGER to number', () => {
const argv = parser(['--foo', '93940495950949399948393'], {
number: ['foo']
})
argv.foo.should.equal(9.39404959509494e+22)
})
// see: https://github.com/yargs/yargs/issues/1099
it('does not magically convert options with leading + to number', () => {
const argv = parser(['--foo', '+5550100', '--bar', '+5550100'], {
number: 'bar'
})
argv.foo.should.equal('+5550100')
argv.bar.should.equal(5550100)
})
// see: https://github.com/yargs/yargs/issues/1099
it('does not magically convert options with leading 0 to number', () => {
const argv = parser(['--foo', '000000', '--bar', '000000'], {
number: 'bar'
})
argv.foo.should.equal('000000')
argv.bar.should.equal(0)
})
// see: https://github.com/yargs/yargs-parser/issues/101
describe('dot-notation array arguments combined with string arguments', function () {
it('parses correctly when dot-notation argument is first', function () {
const argv = parser(['--foo.bar', 'baz', '--foo', 'bux'])
Array.isArray(argv.foo).should.equal(true)
argv.foo[0].bar.should.equal('baz')
argv.foo[1].should.equal('bux')
})
it('parses correctly when dot-notation argument is last', function () {
const argv = parser(['--foo', 'bux', '--foo.bar', 'baz'])
Array.isArray(argv.foo).should.equal(true)
argv.foo[0].should.equal('bux')
argv.foo[1].bar.should.equal('baz')
})
it('parses correctly when there are multiple dot-notation arguments', function () {
const argv = parser(['--foo.first', 'firstvalue', '--foo', 'bux', '--foo.bar', 'baz', '--foo.bla', 'banana'])
Array.isArray(argv.foo).should.equal(true)
argv.foo.length.should.equal(4)
argv.foo[0].first.should.equal('firstvalue')
argv.foo[1].should.equal('bux')
argv.foo[2].bar.should.equal('baz')
argv.foo[3].bla.should.equal('banana')
})
})
// see: https://github.com/yargs/yargs-parser/issues/145
describe('strings with quotes and dashes', () => {
it('handles double quoted strings', function () {
const args = parser('--foo "hello world" --bar="goodnight\'moon"')
args.foo.should.equal('hello world')
args.bar.should.equal('goodnight\'moon')
const args2 = parser(['--foo', '"hello world"', '--bar="goodnight\'moon"'])
args2.foo.should.equal('"hello world"')
args2.bar.should.equal('goodnight\'moon')
})
it('handles single quoted strings', function () {
const args = parser("--foo 'hello world' --bar='goodnight\"moon'")
args.foo.should.equal('hello world')
args.bar.should.equal('goodnight"moon')
const args2 = parser(['--foo', "'hello world'", "--bar='goodnight\"moon'"])
args2.foo.should.equal("'hello world'")
args2.bar.should.equal('goodnight"moon')
})
it('handles strings with dashes', function () {
const args = parser('--foo "-hello world" --bar="--goodnight moon"')
args.foo.should.equal('-hello world')
args.bar.should.equal('--goodnight moon')
})
it('respects inner quotes (string)', function () {
const args = parser('cmd --foo ""Hello"" --bar ""World"" --baz="":)""')
args.foo.should.equal('"Hello"')
args.bar.should.equal('"World"')
args.baz.should.equal('":)"')
})
it('respects inner quotes (array)', function () {
const args = parser(['cmd', '--foo', '"Hello"', '--bar', '"World"', '--baz="":)""'])
args.foo.should.equal('"Hello"')
args.bar.should.equal('"World"')
args.baz.should.equal('":)"')
})
})
// see: https://github.com/yargs/yargs-parser/issues/144
it('number/string types should use default when no right-hand value', () => {
let argv = parser(['--foo'], {
number: ['foo'],
default: {
foo: 99
}
})
argv.foo.should.equal(99)
argv = parser(['-b'], {
alias: {
bar: 'b'
},
string: ['bar'],
default: {
bar: 'hello'
}
})
argv.bar.should.equal('hello')
})
describe('stripping', function () {
it('strip-dashed removes expected fields from argv', function () {
const argv = parser(['--test-value', '1'], {
number: ['test-value'],
alias: {
'test-value': ['alt-test']
},
configuration: {
'strip-dashed': true
}
})
argv.should.deep.equal({
_: [],
testValue: 1,
altTest: 1
})
})
it('strip-aliased removes expected fields from argv', function () {
const argv = parser(['--test-value', '1'], {
number: ['test-value'],
alias: {
'test-value': ['alt-test']
},
configuration: {
'strip-aliased': true
}
})
argv.should.deep.equal({
_: [],
'test-value': 1,
testValue: 1
})
})
it('strip-aliased and strip-dashed combined removes expected fields from argv', function () {
const argv = parser(['--test-value', '1'], {
number: ['test-value'],
alias: {
'test-value': ['alt-test']
},
configuration: {
'strip-aliased': true,
'strip-dashed': true
}
})
argv.should.deep.equal({
_: [],
testValue: 1
})
})
it('ignores strip-dashed if camel-case-expansion is disabled', function () {
const argv = parser(['--test-value', '1'], {
number: ['test-value'],
configuration: {
'camel-case-expansion': false,
'strip-dashed': true
}
})
argv.should.deep.equal({
_: [],
'test-value': 1
})
})
it('only removes camel case expansion if keys have hyphen', function () {
const argv = parser(['--foo', '1', '-a', '2'], {
configuration: {
'strip-aliased': true
},
alias: {
aliased1: ['Foo'],
aliased2: ['A']
}
})
argv.should.deep.equal({
_: [],
foo: 1,
a: 2
})
})
})
describe('prototype collisions', () => {
it('parses unknown argument colliding with prototype', () => {
const parse = parser(['--toString'])
parse.toString.should.equal(true)
})
it('parses unknown argument colliding with prototype, when unknown options as args', () => {
const parse = parser(['--toString'], {
configuration: {
'unknown-options-as-args': true
}
})
parse._.should.include('--toString')
})
it('handles "alias" colliding with prototype', () => {
const parse = parser(['-t', '99'], {
alias: {
toString: ['t']
}
})
parse.toString.should.equal(99)
parse.t.should.equal(99)
parse['to-string'].should.equal(99)
})
it('handles multiple args colliding with alias', () => {
const parse = parser(['--toString', '88', '--toString', '99'])
parse.toString.should.eql([88, 99])
})
it('handle dot notation colliding with alias', () => {
const parse = parser(['--toString.cool', 'apple'])
parse.toString.cool.should.equal('apple')
})
it('handles "arrays" colliding with prototype', () => {
const parse = parser(['--toString', '99', '100'], {
array: ['toString']
})
parse.toString.should.eql([99, 100])
})
it('handles "arrays" colliding with prototype', () => {
const parse = parser(['--toString', '99', '100'], {
array: ['toString']
})
parse.toString.should.eql([99, 100])
})
it('handles "strings" colliding with prototype', () => {
const parse = parser(['--toString', '99'], {
string: ['toString']
})
parse.toString.should.eql('99')
})
it('handles "numbers" colliding with prototype', () => {
const parse = parser(['--toString', '99'], {
number: ['toString'],
configuration: {
'parse-numbers': false
}
})
parse.toString.should.eql(99)
})
it('handles "counts" colliding with prototype', () => {
const parse = parser(['--toString', '--toString', '--toString'], {
count: ['toString']
})
parse.toString.should.eql(3)
})
it('handles "normalize" colliding with prototype', () => {
const parse = parser(['--toString', './node_modules/chai'], {
normalize: ['toString']
})
parse.toString.should.include('node_modules')
})
it('handles "normalize" colliding with prototype', () => {
const parse = parser(['--toString', './node_modules/chai'], {
normalize: ['toString']
})
parse.toString.should.include('node_modules')
})
it('handles key in configuration file that collides with prototype', function () {
const argv = parser(['--foo', 'bar'], {
alias: {
z: 'zoom'
},
default: {
settings: jsonPath
},
config: 'settings'
})
argv.toString.should.equal('method name')
})
it('handles "nargs" colliding with prototype', () => {
const parse = parser(['--toString', 'apple', 'banana', 'batman', 'robin'], {
narg: {
toString: 3
}
})
parse.toString.should.eql(['apple', 'banana', 'batman'])
parse._.should.eql(['robin'])
})
it('handles "coercions" colliding with prototype', () => {
const parse = parser(['--toString', '33'], {
coerce: {
toString: (val) => {
return val * 2
}
}
})
parse.toString.should.equal(66)
})
})
// See: https://github.com/facebook/jest/issues/9517
it('does not collect arguments configured as booleans into implicit array', () => {
const parse = parser(['--infinite', 'true', '--infinite', 'true', '--no-infinite'], {
boolean: 'infinite'
})
parse.infinite.should.equal(false)
})
// See: https://github.com/yargs/yargs/issues/1098,
// https://github.com/yargs/yargs/issues/1570
describe('array with nargs', () => {
it('allows array and nargs to be configured in conjunction, enforcing the nargs value', () => {
const parse = parser.detailed(['-a', 'apple', 'banana'], {
array: 'a',
narg: {
a: 1
}
})
expect(parse.error).to.be.null // eslint-disable-line
parse.argv.a.should.eql(['apple'])
parse.argv._.should.eql(['banana'])
})
// see; https://github.com/yargs/yargs/issues/1098
it('allows special NaN count to be provided to narg, to indicate one or more array values', () => {
const parse = parser.detailed(['-a', 'apple', 'banana'], {
array: 'a',
narg: {
a: NaN
}
})
expect(parse.error).to.be.null // eslint-disable-line
parse.argv.a.should.eql(['apple', 'banana'])
})
it('throws error if at least one value not provided for NaN', () => {
const parse = parser.detailed(['-a'], {
array: 'a',
narg: {
a: NaN
}
})
parse.error.message.should.match(/Not enough arguments/)
})
it('returns an error if not enough positionals were provided for nargs', () => {
const parse = parser.detailed(['-a', '33'], {
array: 'a',
narg: {
a: 2
}
})
parse.argv.a.should.eql([33])
parse.error.message.should.equal('Not enough arguments following: a')
})
it('returns an error if not enough positionals were provided for nargs even with nargs-eats-options', () => {
const parse = parser.detailed(['-a', '33', '--cat'], {
narg: {
a: 3
},
configuration: {
'nargs-eats-options': true
}
})
parse.error.message.should.equal('Not enough arguments following: a')
})
it('does not raise error if no arguments are provided for boolean option', () => {
const parse = parser.detailed(['-a'], {
array: 'a',
boolean: 'a',
narg: {
a: NaN
}
})
expect(parse.error).to.be.null // eslint-disable-line
parse.argv.a.should.eql([true])
})
})
describe('greedy-arrays=false', () => {
it('does not consume more than one argument after array option', () => {
const argv = parser(['--arr', 'foo', 'bar'], {
array: 'arr',
configuration: {
'greedy-arrays': false
}
})
argv.arr.should.eql(['foo'])
argv._.should.eql(['bar'])
})
it('places argument into array when specified multiple times', () => {
const argv = parser(['--arr', 99, 'foo', '--arr', 'hello', 'bar'], {
array: 'arr',
configuration: {
'greedy-arrays': false
}
})
argv.arr.should.eql([99, 'hello'])
argv._.should.eql(['foo', 'bar'])
})
it('places boolean arguments into array when specified multiple times', () => {
const argv = parser(['--arr', 101, '--arr', 102, '--arr', 'false'], {
array: 'arr',
boolean: 'arr',
configuration: {
'greedy-arrays': false
}
})
argv.arr.should.eql([true, true, false])
argv._.should.eql([101, 102])
})
})
it('should replace the key __proto__ with the key ___proto___', function () {
const argv = parser(['-f.__proto__.foo', '99', '-x.y.__proto__.bar', '100', '--__proto__', '200'])
argv.should.eql({
_: [],
___proto___: 200,
f: {
___proto___: {
foo: 99
}
},
x: {
y: {
___proto___: {
bar: 100
}
}
}
})
})
it('throws error for unsupported Node.js versions', () => {
process.env.YARGS_MIN_NODE_VERSION = '55'
delete require.cache[require.resolve('../')]
expect(() => {
require('../')
}).to.throw(/yargs parser supports a minimum Node.js version of 55/)
delete process.env.YARGS_MIN_NODE_VERSION
})
// Refs: https://github.com/yargs/yargs-parser/issues/386
describe('perf', () => {
const i = 100000
describe('unknown-options-as-args', () => {
it('parses long chain of "-" with reasonable performance', function () {
this.timeout(500)
const s = (new Array(i).fill('-').join('')) + 'a'
const parsed = parser([s], { configuration: { 'unknown-options-as-args': true } })
parsed._[0].should.equal(s)
})
it('parses long chain of "-a-a" with reasonable performance', function () {
this.timeout(500)
const s = '-' + (new Array(i).fill('-a').join('')) + '=35'
const parsed = parser([s], { configuration: { 'unknown-options-as-args': true } })
parsed._[0].should.equal(s)
})
})
it('parses long chain of "-" with reasonable performance', function () {
this.timeout(500)
const s = (new Array(i).fill('-').join('')) + 'a'
const arg = (new Array(i - 2).fill('-').join('')) + 'a'
const parsed = parser([s])
parsed[arg].should.equal(true)
})
it('parses long chain of "-a-a" with reasonable performance', function () {
this.timeout(500)
const s = '-' + (new Array(i).fill('-a').join('')) + '=35'
const arg = 'a' + (new Array(i - 1).fill('A').join(''))
const parsed = parser([s])
parsed[arg].should.equal(35)
})
})
})
yargs-parser-yargs-parser-v21.0.0/test/yargs-parser.mjs 0000664 0000000 0000000 00000017345 14144615712 0023144 0 ustar 00root root 0000000 0000000 import { should, expect } from 'chai'
import parser from '../build/lib/index.js'
import path from 'path'
import { fileURLToPath } from 'url'
import { readFileSync } from 'fs'
should()
describe('yargs-parser (esm)', function () {
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const jsonPath = path.resolve(__dirname, './fixtures/config.json')
describe('config', function () {
it('should load options and values from default config if specified', function () {
const argv = parser(['--foo', 'bar'], {
alias: {
z: 'zoom'
},
default: {
settings: jsonPath
},
config: 'settings'
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('bar')
})
it('should use value from config file, if argv value is using default value', function () {
const argv = parser([], {
alias: {
z: 'zoom'
},
config: ['settings'],
default: {
settings: jsonPath,
foo: 'banana'
}
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('baz')
})
it('should combine values from config file and argv, if argv value is an array', function () {
const argv = parser(['--foo', 'bar'], {
config: ['settings'],
array: ['foo'],
default: {
settings: jsonPath
},
configuration: {
'combine-arrays': true
}
})
argv.should.have.property('foo').and.deep.equal(['bar', 'baz'])
})
it('should use value from config file, if argv key is a boolean', function () {
const argv = parser([], {
config: ['settings'],
default: {
settings: jsonPath
},
boolean: ['truthy']
})
argv.should.have.property('truthy', true)
})
it('should use value from cli, if cli overrides boolean argv key', function () {
const argv = parser(['--no-truthy'], {
config: ['settings'],
default: {
settings: jsonPath
},
boolean: ['truthy']
})
argv.should.have.property('truthy', false)
})
it('should use cli value, if cli value is set and both cli and default value match', function () {
const argv = parser(['--foo', 'banana'], {
alias: {
z: 'zoom'
},
config: ['settings'],
default: {
settings: jsonPath,
foo: 'banana'
}
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('banana')
})
it("should allow config to be set as flag in 'option'", function () {
const argv = parser(['--settings', jsonPath, '--foo', 'bar'], {
alias: {
z: 'zoom'
},
config: ['settings']
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('bar')
})
// for esm, only support importing json files
it('should fail to load options and values from a JS file when config has .js extention', function () {
const jsPath = path.resolve(__dirname, './fixtures/settings.cjs')
const argv = parser.detailed(['--settings', jsPath, '--foo', 'bar'], {
config: ['settings']
})
argv.error.message.should.include('Invalid JSON config file')
})
it('should raise an appropriate error if JSON file is not found', function () {
const argv = parser.detailed(['--settings', 'fake.json', '--foo', 'bar'], {
alias: {
z: 'zoom'
},
config: ['settings']
})
argv.error.message.should.equal('Invalid JSON config file: fake.json')
})
// see: https://github.com/bcoe/yargs/issues/172
it('should not raise an exception if config file is set as default argument value', function () {
const argv = parser.detailed([], {
default: {
config: 'foo.json'
},
config: ['config']
})
expect(argv.error).to.equal(null)
})
it('should load nested options from config file', function () {
const jsonPath = path.resolve(__dirname, './fixtures/nested_config.json')
const argv = parser(['--settings', jsonPath, '--nested.foo', 'bar'], {
config: ['settings']
})
argv.should.have.property('a', 'a')
argv.should.have.property('b', 'b')
argv.should.have.property('nested').and.deep.equal({
foo: 'bar',
bar: 'bar'
})
})
it('should use nested value from config file, if argv value is using default value', function () {
const jsonPath = path.resolve(__dirname, './fixtures/nested_config.json')
const argv = parser(['--settings', jsonPath], {
config: ['settings'],
default: {
'nested.foo': 'banana'
}
})
argv.should.have.property('a', 'a')
argv.should.have.property('b', 'b')
argv.should.have.property('nested').and.deep.equal({
foo: 'baz',
bar: 'bar'
})
})
it('allows a custom parsing function to be provided', function () {
const jsPath = path.resolve(__dirname, './fixtures/config.txt')
const argv = parser(['--settings', jsPath, '--foo', 'bar'], {
config: {
settings: function (configPath) {
// as an example, parse an environment
// variable style config:
// FOO=99
// BATMAN=grumpy
const config = {}
const txt = readFileSync(configPath, 'utf-8')
txt.split(/\r?\n/).forEach(function (l) {
const kv = l.split('=')
config[kv[0].toLowerCase()] = kv[1]
})
return config
}
}
})
argv.batman.should.equal('grumpy')
argv.awesome.should.equal('banana')
argv.foo.should.equal('bar')
})
it('allows a custom parsing function to be provided as an alias', function () {
const jsPath = path.resolve(__dirname, './fixtures/config.json')
const argv = parser(['--settings', jsPath, '--foo', 'bar'], {
config: {
s: function (configPath) {
return JSON.parse(readFileSync(configPath, 'utf-8'))
}
},
alias: {
s: ['settings']
}
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('foo', 'bar')
})
it('outputs an error returned by the parsing function', function () {
const argv = parser.detailed(['--settings=./package.json'], {
config: {
settings: function (configPath) {
return Error('someone set us up the bomb')
}
}
})
argv.error.message.should.equal('someone set us up the bomb')
})
it('outputs an error if thrown by the parsing function', function () {
const argv = parser.detailed(['--settings=./package.json'], {
config: {
settings: function (configPath) {
throw Error('someone set us up the bomb')
}
}
})
argv.error.message.should.equal('someone set us up the bomb')
})
it('should not pollute the prototype', function () {
const argv = parser(['--foo', 'bar'], {
alias: {
z: 'zoom'
},
default: {
settings: jsonPath
},
config: 'settings'
})
argv.should.have.property('herp', 'derp')
argv.should.have.property('zoom', 55)
argv.should.have.property('foo').and.deep.equal('bar')
expect({}.bbb).to.equal(undefined)
expect({}.aaa).to.equal(undefined)
})
})
}) yargs-parser-yargs-parser-v21.0.0/tsconfig.json 0000664 0000000 0000000 00000000420 14144615712 0021524 0 ustar 00root root 0000000 0000000 {
"extends": "./node_modules/gts/tsconfig-google.json",
"compilerOptions": {
"outDir": "build",
"rootDir": ".",
"sourceMap": false,
"target": "es2017",
"moduleResolution": "node",
"module": "es2020"
},
"include": [
"lib/**/*.ts"
]
} yargs-parser-yargs-parser-v21.0.0/tsconfig.test.json 0000664 0000000 0000000 00000000203 14144615712 0022501 0 ustar 00root root 0000000 0000000 {
"extends": "./tsconfig.json",
"compilerOptions": {
"sourceMap": true
},
"include": [
"test/typescript/*.ts"
]
} yargs-parser-yargs-parser-v21.0.0/yargs-logo.png 0000664 0000000 0000000 00000041431 14144615712 0021615 0 ustar 00root root 0000000 0000000 PNG
IHDR X bKGD pHYs gR tIME9_ iTXtComment Created with GIMPd.e IDATxwXoT]cM$^5$^@(U{K$ؖ;
b⦆b5Q).efy>ffϜo! :A&