From ac6d5d105a75711fe703f6a39dad5181b383d6c6 Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Sat, 22 Aug 2020 10:55:14 -0700 Subject: [PATCH] feat: adds support for ESM and Deno (#1708) BREAKING CHANGE: find-up replaced with escalade; export map added (limits importable files in Node >= 12); yarser-parser@19.x.x (new decamelize/camelcase implementation). --- .editorconfig | 14 - .github/workflows/ci.yaml | 30 +- .gitignore | 2 + .mocharc.json | 6 - .versionrc | 9 - CHANGELOG.md | 122 --- README.md | 55 +- browser.mjs | 7 + deno.ts | 16 + docs/CHANGELOG-historical.md | 120 +++ docs/browser.md | 32 + docs/webpack.md | 103 --- example/yargs.html | 50 ++ index.js => index.cjs | 7 +- index.mjs | 13 + lib/argsert.ts | 4 +- lib/cjs.ts | 38 + lib/command.ts | 42 +- lib/common-types.ts | 48 -- lib/completion.ts | 31 +- lib/middleware.ts | 6 +- lib/parse-command.ts | 2 +- lib/platform-shims/browser.mjs | 91 ++ lib/platform-shims/cjs.ts | 44 + lib/platform-shims/deno.ts | 116 +++ lib/platform-shims/esm.mjs | 80 ++ lib/typings/common-types.ts | 108 +++ lib/typings/require-directory.d.ts | 84 -- lib/typings/require-main-filename.d.ts | 21 - lib/typings/set-blocking.d.ts | 7 - lib/typings/which-module.d.ts | 14 - lib/typings/y18n.d.ts | 64 -- lib/typings/yargs-parser-types.ts | 165 ++++ lib/usage.ts | 34 +- lib/{ => utils}/apply-extends.ts | 68 +- lib/{ => utils}/is-promise.ts | 0 lib/{ => utils}/levenshtein.ts | 0 lib/{ => utils}/obj-filter.ts | 2 +- lib/{ => utils}/process-argv.ts | 0 lib/utils/set-blocking.ts | 17 + lib/utils/which-module.ts | 8 + lib/validation.ts | 34 +- lib/{yargs.ts => yargs-factory.ts} | 143 ++-- package.json | 58 +- rollup.config.cjs | 23 + test/{argsert.ts => argsert.cjs} | 34 +- test/{before.js => before.cjs} | 0 test/{command.js => command.cjs} | 4 +- test/{completion.js => completion.cjs} | 7 +- test/deno/platform-shim.test.ts | 22 + test/deno/yargs.test.ts | 26 + test/esm/platform-shim-test.mjs | 25 + test/esm/yargs-test.mjs | 31 + test/fixtures/bin.js | 2 +- test/fixtures/issue-497.js | 2 +- test/fixtures/no-extension | 2 +- test/fixtures/no-require-main.js | 2 +- test/fixtures/normal-bin.js | 2 +- ...t-assignment-and-positional-command-arg.js | 2 +- test/fixtures/symlink-bin.js | 2 +- test/helpers/{utils.ts => utils.cjs} | 35 +- test/{integration.js => integration.cjs} | 0 test/{is-promise.ts => is-promise.cjs} | 4 +- test/{middleware.js => middleware.cjs} | 11 +- test/{obj-filter.ts => obj-filter.cjs} | 9 +- test/{parse-command.ts => parse-command.cjs} | 4 +- test/{parser.js => parser.cjs} | 2 +- test/types/check-output-result.ts | 7 - test/types/hashish.d.ts | 5 - test/types/index.ts | 1 - test/{usage.js => usage.cjs} | 7 +- test/{validation.js => validation.cjs} | 12 +- test/{yargs.js => yargs.cjs} | 35 +- tsconfig.json | 12 +- tsconfig.test.json | 7 +- yargs-logo.png | Bin 20447 -> 0 bytes yargs.d.ts | 795 ------------------ yargs.js | 26 +- 78 files changed, 1434 insertions(+), 1639 deletions(-) delete mode 100644 .editorconfig delete mode 100644 .mocharc.json delete mode 100644 .versionrc create mode 100644 browser.mjs create mode 100644 deno.ts create mode 100644 docs/browser.md delete mode 100644 docs/webpack.md create mode 100644 example/yargs.html rename index.js => index.cjs (83%) create mode 100644 index.mjs create mode 100644 lib/cjs.ts delete mode 100644 lib/common-types.ts create mode 100644 lib/platform-shims/browser.mjs create mode 100644 lib/platform-shims/cjs.ts create mode 100644 lib/platform-shims/deno.ts create mode 100644 lib/platform-shims/esm.mjs create mode 100644 lib/typings/common-types.ts delete mode 100644 lib/typings/require-directory.d.ts delete mode 100644 lib/typings/require-main-filename.d.ts delete mode 100644 lib/typings/set-blocking.d.ts delete mode 100644 lib/typings/which-module.d.ts delete mode 100644 lib/typings/y18n.d.ts create mode 100644 lib/typings/yargs-parser-types.ts rename lib/{ => utils}/apply-extends.ts (80%) rename lib/{ => utils}/is-promise.ts (100%) rename lib/{ => utils}/levenshtein.ts (100%) rename lib/{ => utils}/obj-filter.ts (84%) rename lib/{ => utils}/process-argv.ts (100%) create mode 100644 lib/utils/set-blocking.ts create mode 100644 lib/utils/which-module.ts rename lib/{yargs.ts => yargs-factory.ts} (94%) create mode 100644 rollup.config.cjs rename test/{argsert.ts => argsert.cjs} (84%) rename test/{before.js => before.cjs} (100%) rename test/{command.js => command.cjs} (99%) rename test/{completion.js => completion.cjs} (99%) create mode 100644 test/deno/platform-shim.test.ts create mode 100644 test/deno/yargs.test.ts create mode 100644 test/esm/platform-shim-test.mjs create mode 100644 test/esm/yargs-test.mjs rename test/helpers/{utils.ts => utils.cjs} (56%) rename test/{integration.js => integration.cjs} (100%) rename test/{is-promise.ts => is-promise.cjs} (90%) rename test/{middleware.js => middleware.cjs} (97%) rename test/{obj-filter.ts => obj-filter.cjs} (59%) rename test/{parse-command.ts => parse-command.cjs} (68%) rename test/{parser.js => parser.cjs} (80%) delete mode 100644 test/types/check-output-result.ts delete mode 100644 test/types/hashish.d.ts delete mode 100644 test/types/index.ts rename test/{usage.js => usage.cjs} (99%) rename test/{validation.js => validation.cjs} (98%) rename test/{yargs.js => yargs.cjs} (99%) delete mode 100644 yargs-logo.png delete mode 100644 yargs.d.ts diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 3fd345c8a..000000000 --- a/.editorconfig +++ /dev/null @@ -1,14 +0,0 @@ -root = true - -[*] - -indent_style = space -indent_size = 2 - -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ab1bd7c89..d13e37711 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,7 +16,7 @@ jobs: with: node-version: ${{ matrix.node }} - run: node --version - - run: npm install + - run: npm install --engine-strict - run: npm test windows: runs-on: windows-latest @@ -27,6 +27,34 @@ jobs: node-version: 12 - run: npm install - run: npm test + esm: + runs-on: ubuntu-latest + strategy: + matrix: + node: [14] + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + - run: node --version + - run: npm install --engine-strict + - run: npm run test:esm + deno: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 14 + - run: npm install + - run: npm run compile + - uses: denolib/setup-deno@v2 + with: + deno-version: v1.x + - run: | + deno --version + deno test --allow-read test/deno/* coverage: runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 624a7ce7d..2cfab6bc8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ node_modules/ test.js coverage package-lock.json +example.* +.DS_Store .npmrc diff --git a/.mocharc.json b/.mocharc.json deleted file mode 100644 index ef1c3645a..000000000 --- a/.mocharc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "spec": [ - "build/test", - "test" - ] -} diff --git a/.versionrc b/.versionrc deleted file mode 100644 index 0b7f5a6c8..000000000 --- a/.versionrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "types": [ - {"type":"feat","section":"Features"}, - {"type":"fix","section":"Bug Fixes"}, - {"type":"test","section":"Tests", "hidden": true}, - {"type":"build","section":"Build System", "hidden": true}, - {"type":"ci","hidden":true} - ] -} diff --git a/CHANGELOG.md b/CHANGELOG.md index a010cf34f..33336f5b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -296,125 +296,3 @@ arguments when duplicates are provided * dropping Node 6 which hits end of life in April 2019 * see [yargs-parser@12.0.0 CHANGELOG](https://github.com/yargs/yargs-parser/blob/master/CHANGELOG.md#breaking-changes) * we now warn if the yargs stanza package.json is used. - - - - -## [12.0.5](https://github.com/yargs/yargs/compare/v12.0.4...v12.0.5) (2018-11-19) - - -### Bug Fixes - -* allows camel-case, variadic arguments, and strict mode to be combined ([#1247](https://github.com/yargs/yargs/issues/1247)) ([eacc035](https://github.com/yargs/yargs/commit/eacc035)) - - - - -## [12.0.4](https://github.com/yargs/yargs/compare/v12.0.3...v12.0.4) (2018-11-10) - - -### Bug Fixes - -* don't load config when processing positionals ([5d0dc92](https://github.com/yargs/yargs/commit/5d0dc92)) - - - - -## [12.0.3](https://github.com/yargs/yargs/compare/v12.0.2...v12.0.3) (2018-10-06) - - -### Bug Fixes - -* $0 contains first arg in bundled electron apps ([#1206](https://github.com/yargs/yargs/issues/1206)) ([567820b](https://github.com/yargs/yargs/commit/567820b)) -* accept single function for middleware ([66fd6f7](https://github.com/yargs/yargs/commit/66fd6f7)), closes [#1214](https://github.com/yargs/yargs/issues/1214) [#1214](https://github.com/yargs/yargs/issues/1214) -* hide `hidden` options from help output even if they are in a group ([#1221](https://github.com/yargs/yargs/issues/1221)) ([da54028](https://github.com/yargs/yargs/commit/da54028)) -* improve Norwegian Bokmål translations ([#1208](https://github.com/yargs/yargs/issues/1208)) ([a458fa4](https://github.com/yargs/yargs/commit/a458fa4)) -* improve Norwegian Nynorsk translations ([#1207](https://github.com/yargs/yargs/issues/1207)) ([d422eb5](https://github.com/yargs/yargs/commit/d422eb5)) - - - - -## [12.0.2](https://github.com/yargs/yargs/compare/v12.0.1...v12.0.2) (2018-09-04) - - -### Bug Fixes - -* middleware should work regardless of when method is called ([664b265](https://github.com/yargs/yargs/commit/664b265)), closes [#1178](https://github.com/yargs/yargs/issues/1178) -* translation not working when using __ with a single parameter ([#1183](https://github.com/yargs/yargs/issues/1183)) ([f449aea](https://github.com/yargs/yargs/commit/f449aea)) -* upgrade os-locale to version that addresses license issue ([#1195](https://github.com/yargs/yargs/issues/1195)) ([efc0970](https://github.com/yargs/yargs/commit/efc0970)) - - - - -## [12.0.1](https://github.com/yargs/yargs/compare/v12.0.0...v12.0.1) (2018-06-29) - - - - -# [12.0.0](https://github.com/yargs/yargs/compare/v11.1.0...v12.0.0) (2018-06-26) - - -### Bug Fixes - -* .argv and .parse() now invoke identical code path ([#1126](https://github.com/yargs/yargs/issues/1126)) ([f13ebf4](https://github.com/yargs/yargs/commit/f13ebf4)) -* remove the trailing white spaces from the help output ([#1090](https://github.com/yargs/yargs/issues/1090)) ([3f0746c](https://github.com/yargs/yargs/commit/3f0746c)) -* **completion:** Avoid default command and recommendations during completion ([#1123](https://github.com/yargs/yargs/issues/1123)) ([036e7c5](https://github.com/yargs/yargs/commit/036e7c5)) - - -### Chores - -* test Node.js 6, 8 and 10 ([#1160](https://github.com/yargs/yargs/issues/1160)) ([84f9d2b](https://github.com/yargs/yargs/commit/84f9d2b)) -* upgrade to version of yargs-parser that does not populate value for unset boolean ([#1104](https://github.com/yargs/yargs/issues/1104)) ([d4705f4](https://github.com/yargs/yargs/commit/d4705f4)) - - -### Features - -* add support for global middleware, useful for shared tasks like metrics ([#1119](https://github.com/yargs/yargs/issues/1119)) ([9d71ac7](https://github.com/yargs/yargs/commit/9d71ac7)) -* allow setting scriptName $0 ([#1143](https://github.com/yargs/yargs/issues/1143)) ([a2f2eae](https://github.com/yargs/yargs/commit/a2f2eae)) -* remove `setPlaceholderKeys` ([#1105](https://github.com/yargs/yargs/issues/1105)) ([6ee2c82](https://github.com/yargs/yargs/commit/6ee2c82)) - - -### BREAKING CHANGES - -* Options absent from `argv` (not set via CLI argument) are now absent from the parsed result object rather than being set with `undefined` -* drop Node 4 from testing matrix, such that we'll gradually start drifting away from supporting Node 4. -* yargs-parser does not populate 'false' when boolean flag is not passed -* tests that assert against help output will need to be updated - - - - -# [11.1.0](https://github.com/yargs/yargs/compare/v11.0.0...v11.1.0) (2018-03-04) - - -### Bug Fixes - -* choose correct config directory when require.main does not exist ([#1056](https://github.com/yargs/yargs/issues/1056)) ([a04678c](https://github.com/yargs/yargs/commit/a04678c)) - - -### Features - -* allow hidden options to be displayed with --show-hidden ([#1061](https://github.com/yargs/yargs/issues/1061)) ([ea862ae](https://github.com/yargs/yargs/commit/ea862ae)) -* extend *.rc files in addition to json ([#1080](https://github.com/yargs/yargs/issues/1080)) ([11691a6](https://github.com/yargs/yargs/commit/11691a6)) - - - - -# [11.0.0](https://github.com/yargs/yargs/compare/v10.1.2...v11.0.0) (2018-01-22) - - -### Bug Fixes - -* Set implicit nargs=1 when type=number requiresArg=true ([#1050](https://github.com/yargs/yargs/issues/1050)) ([2b56812](https://github.com/yargs/yargs/commit/2b56812)) - - -### Features - -* requiresArg is now simply an alias for nargs(1) ([#1054](https://github.com/yargs/yargs/issues/1054)) ([a3ddacc](https://github.com/yargs/yargs/commit/a3ddacc)) - - -### BREAKING CHANGES - -* requiresArg now has significantly different error output, matching nargs. - -[Historical Versions](/docs/CHANGELOG-historical.md) diff --git a/README.md b/README.md index f73236d0c..0457fc4dc 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,14 @@
-[![Build Status][travis-image]][travis-url] +![ci](https://github.com/yargs/yargs/workflows/ci/badge.svg) [![NPM version][npm-image]][npm-url] [![js-standard-style][standard-image]][standard-url] [![Coverage][coverage-image]][coverage-url] [![Conventional Commits][conventional-commits-image]][conventional-commits-url] [![Slack][slack-image]][slack-url] -## Description : +## Description Yargs helps you build interactive command line tools, by parsing arguments and generating an elegant user interface. It gives you: @@ -40,7 +40,7 @@ Bleeding edge version with the most recent features: npm i yargs@next ``` -## Usage : +## Usage ### Simple Example @@ -88,7 +88,9 @@ require('yargs') // eslint-disable-line Run the example above with `--help` to see the help for the application. -## TypeScript +## Supported Platforms + +### TypeScript yargs has type definitions at [@types/yargs][type-definitions]. @@ -98,15 +100,50 @@ npm i @types/yargs --save-dev See usage examples in [docs](/docs/typescript.md). -## Webpack +### Deno + +As of `v16`, `yargs` supports [Deno](https://github.com/denoland/deno): + +```typescript +import { Yargs, YargsType, Arguments } from 'https://deno.land/x/yargs/deno.ts' + +Yargs() + .command('download ', 'download a list of files', (yargs: YargsType) => { + return yargs.positional('files', { + describe: 'a list of files to do something with' + }) + }, (argv: Arguments) => { + console.info(argv) + }) + .strictCommands() + .demandCommand(1) + .parse(Deno.args) +``` + +### ESM + +As of `v16`,`yargs` supports ESM imports: + +```js +import { Yargs, getProcessArgvWithoutBin } from 'yargs' + +Yargs(getProcessArgvWithoutBin()) + .command('curl ', 'fetch the contents of the URL', () => {}, (argv) => { + console.info(argv) + }) + .demandCommand(1) + .argv +``` + +### Usage in Browser -See usage examples of yargs with webpack in [docs](/docs/webpack.md). +See examples of using yargs in the browser in [docs](/docs/browser.md). -## Community : +## Community Having problems? want to contribute? join our [community slack](http://devtoolscommunity.herokuapp.com). -## Documentation : +## Documentation ### Table of Contents @@ -131,8 +168,6 @@ 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). -[travis-url]: https://travis-ci.org/yargs/yargs -[travis-image]: https://img.shields.io/travis/yargs/yargs/master.svg [npm-url]: https://www.npmjs.com/package/yargs [npm-image]: https://img.shields.io/npm/v/yargs.svg [standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg diff --git a/browser.mjs b/browser.mjs new file mode 100644 index 000000000..f3d32f2b2 --- /dev/null +++ b/browser.mjs @@ -0,0 +1,7 @@ +// Bootstrap yargs for browser: +import browserPlatformShim from './lib/platform-shims/browser.mjs' +import { YargsWithShim } from './build/lib/yargs-factory.js' + +const Yargs = YargsWithShim(browserPlatformShim) + +export { Yargs } diff --git a/deno.ts b/deno.ts new file mode 100644 index 000000000..d985e1cd1 --- /dev/null +++ b/deno.ts @@ -0,0 +1,16 @@ +// Bootstrap yargs for Deno platform: +import denoPlatformShim from './lib/platform-shims/deno.ts' +import { YargsWithShim } from './build/lib/yargs-factory.js' +import { YargsInstance as YargsType, Arguments } from './build/lib/yargs-factory.d.ts' + +const WrappedYargs = YargsWithShim(denoPlatformShim) + +function Yargs (args?: string[]): YargsType { + return WrappedYargs(args) +} + +export { + Arguments, + Yargs, + YargsType +} diff --git a/docs/CHANGELOG-historical.md b/docs/CHANGELOG-historical.md index ded558e3e..1bfaf1b4f 100644 --- a/docs/CHANGELOG-historical.md +++ b/docs/CHANGELOG-historical.md @@ -1,3 +1,123 @@ + +## [12.0.5](https://github.com/yargs/yargs/compare/v12.0.4...v12.0.5) (2018-11-19) + + +### Bug Fixes + +* allows camel-case, variadic arguments, and strict mode to be combined ([#1247](https://github.com/yargs/yargs/issues/1247)) ([eacc035](https://github.com/yargs/yargs/commit/eacc035)) + + + + +## [12.0.4](https://github.com/yargs/yargs/compare/v12.0.3...v12.0.4) (2018-11-10) + + +### Bug Fixes + +* don't load config when processing positionals ([5d0dc92](https://github.com/yargs/yargs/commit/5d0dc92)) + + + + +## [12.0.3](https://github.com/yargs/yargs/compare/v12.0.2...v12.0.3) (2018-10-06) + + +### Bug Fixes + +* $0 contains first arg in bundled electron apps ([#1206](https://github.com/yargs/yargs/issues/1206)) ([567820b](https://github.com/yargs/yargs/commit/567820b)) +* accept single function for middleware ([66fd6f7](https://github.com/yargs/yargs/commit/66fd6f7)), closes [#1214](https://github.com/yargs/yargs/issues/1214) [#1214](https://github.com/yargs/yargs/issues/1214) +* hide `hidden` options from help output even if they are in a group ([#1221](https://github.com/yargs/yargs/issues/1221)) ([da54028](https://github.com/yargs/yargs/commit/da54028)) +* improve Norwegian Bokmål translations ([#1208](https://github.com/yargs/yargs/issues/1208)) ([a458fa4](https://github.com/yargs/yargs/commit/a458fa4)) +* improve Norwegian Nynorsk translations ([#1207](https://github.com/yargs/yargs/issues/1207)) ([d422eb5](https://github.com/yargs/yargs/commit/d422eb5)) + + + + +## [12.0.2](https://github.com/yargs/yargs/compare/v12.0.1...v12.0.2) (2018-09-04) + + +### Bug Fixes + +* middleware should work regardless of when method is called ([664b265](https://github.com/yargs/yargs/commit/664b265)), closes [#1178](https://github.com/yargs/yargs/issues/1178) +* translation not working when using __ with a single parameter ([#1183](https://github.com/yargs/yargs/issues/1183)) ([f449aea](https://github.com/yargs/yargs/commit/f449aea)) +* upgrade os-locale to version that addresses license issue ([#1195](https://github.com/yargs/yargs/issues/1195)) ([efc0970](https://github.com/yargs/yargs/commit/efc0970)) + + + + +## [12.0.1](https://github.com/yargs/yargs/compare/v12.0.0...v12.0.1) (2018-06-29) + + + + +# [12.0.0](https://github.com/yargs/yargs/compare/v11.1.0...v12.0.0) (2018-06-26) + + +### Bug Fixes + +* .argv and .parse() now invoke identical code path ([#1126](https://github.com/yargs/yargs/issues/1126)) ([f13ebf4](https://github.com/yargs/yargs/commit/f13ebf4)) +* remove the trailing white spaces from the help output ([#1090](https://github.com/yargs/yargs/issues/1090)) ([3f0746c](https://github.com/yargs/yargs/commit/3f0746c)) +* **completion:** Avoid default command and recommendations during completion ([#1123](https://github.com/yargs/yargs/issues/1123)) ([036e7c5](https://github.com/yargs/yargs/commit/036e7c5)) + + +### Chores + +* test Node.js 6, 8 and 10 ([#1160](https://github.com/yargs/yargs/issues/1160)) ([84f9d2b](https://github.com/yargs/yargs/commit/84f9d2b)) +* upgrade to version of yargs-parser that does not populate value for unset boolean ([#1104](https://github.com/yargs/yargs/issues/1104)) ([d4705f4](https://github.com/yargs/yargs/commit/d4705f4)) + + +### Features + +* add support for global middleware, useful for shared tasks like metrics ([#1119](https://github.com/yargs/yargs/issues/1119)) ([9d71ac7](https://github.com/yargs/yargs/commit/9d71ac7)) +* allow setting scriptName $0 ([#1143](https://github.com/yargs/yargs/issues/1143)) ([a2f2eae](https://github.com/yargs/yargs/commit/a2f2eae)) +* remove `setPlaceholderKeys` ([#1105](https://github.com/yargs/yargs/issues/1105)) ([6ee2c82](https://github.com/yargs/yargs/commit/6ee2c82)) + + +### BREAKING CHANGES + +* Options absent from `argv` (not set via CLI argument) are now absent from the parsed result object rather than being set with `undefined` +* drop Node 4 from testing matrix, such that we'll gradually start drifting away from supporting Node 4. +* yargs-parser does not populate 'false' when boolean flag is not passed +* tests that assert against help output will need to be updated + + + + +# [11.1.0](https://github.com/yargs/yargs/compare/v11.0.0...v11.1.0) (2018-03-04) + + +### Bug Fixes + +* choose correct config directory when require.main does not exist ([#1056](https://github.com/yargs/yargs/issues/1056)) ([a04678c](https://github.com/yargs/yargs/commit/a04678c)) + + +### Features + +* allow hidden options to be displayed with --show-hidden ([#1061](https://github.com/yargs/yargs/issues/1061)) ([ea862ae](https://github.com/yargs/yargs/commit/ea862ae)) +* extend *.rc files in addition to json ([#1080](https://github.com/yargs/yargs/issues/1080)) ([11691a6](https://github.com/yargs/yargs/commit/11691a6)) + + + + +# [11.0.0](https://github.com/yargs/yargs/compare/v10.1.2...v11.0.0) (2018-01-22) + + +### Bug Fixes + +* Set implicit nargs=1 when type=number requiresArg=true ([#1050](https://github.com/yargs/yargs/issues/1050)) ([2b56812](https://github.com/yargs/yargs/commit/2b56812)) + + +### Features + +* requiresArg is now simply an alias for nargs(1) ([#1054](https://github.com/yargs/yargs/issues/1054)) ([a3ddacc](https://github.com/yargs/yargs/commit/a3ddacc)) + + +### BREAKING CHANGES + +* requiresArg now has significantly different error output, matching nargs. + +[Historical Versions](/docs/CHANGELOG-historical.md) + ## [10.1.2](https://github.com/yargs/yargs/compare/v10.1.1...v10.1.2) (2018-01-17) diff --git a/docs/browser.md b/docs/browser.md new file mode 100644 index 000000000..c47b4ccd1 --- /dev/null +++ b/docs/browser.md @@ -0,0 +1,32 @@ +# Running yargs in the browser + +Newer versions of yargs have a `./browser.mjs` entrypoint, which can be used +through a CDN like [unpkg.com](https://unpkg.com/) to load yargs directly in +the browser: + +```html + +``` + +A full example can be found in [example/yargs.html](/example/yargs.html), or +on [jsfiddle](https://jsfiddle.net/bencoe/m9fv2oet/3/). + +## Bundling + +Even though yargs can run directly in the browser, you will still likely +want to use a tool like [rollup.js](https://rollupjs.org/guide/en/) to create +a bundle for the browser. diff --git a/docs/webpack.md b/docs/webpack.md deleted file mode 100644 index 012a846e0..000000000 --- a/docs/webpack.md +++ /dev/null @@ -1,103 +0,0 @@ -# Webpack usage examples - -## Install dependencies - -```bash -$ npm install --save-dev webpack webpack-cli yargs -``` - -Additional dependencies for typescript users: - -```bash -$ npm install --save-dev ts-loader typescript @types/yargs -``` - -## Sample program - -Create `src/index.js`: -```js -const yargs = require('yargs') - -console.log(yargs.parse()) -``` - -Or for typescript users, `src/index.ts`: -```ts -import yargs = require('yargs'); - -console.log(yargs.parse()); -``` - -along with its `tsconfig.json`: -```json -{ - "compilerOptions": { - "sourceMap": true - } -} -``` - -## Webpack configuration - -Create `webpack.config.js`: -```js -const path = require('path'); - -module.exports = { - entry: './src/index.js', - output: { - path: path.resolve(__dirname, 'dist'), - filename: 'index.js' - }, - stats: { - // Ignore warnings due to yarg's dynamic module loading - warningsFilter: [/node_modules\/yargs/] - }, - target: 'node' -} -``` - -For typescript users, replace : - -```js -module.exports = { - entry: './src/index.js', - ... -} -``` - -by: - -```js -module.exports = { - entry: './src/index.ts', - module: { - rules: [ - { - test: /\.ts$/, - use: [ - 'ts-loader', - ] - } - ] - }, - resolve: { - extensions: ['.ts', '.js'], - }, - ... -} -``` - -## Build - -```bash -$ ./node_modules/.bin/webpack --mode=production -``` - -## Run - -```bash -$ rm -rf node_modules -$ node dist/index.js -{ _: [], '$0': 'dist/index.js' } -``` diff --git a/example/yargs.html b/example/yargs.html new file mode 100644 index 000000000..2d6f6d3b5 --- /dev/null +++ b/example/yargs.html @@ -0,0 +1,50 @@ + +
+ +
+ + + + + + diff --git a/index.js b/index.cjs similarity index 83% rename from index.js rename to index.cjs index 7dc62de99..22369b6fb 100644 --- a/index.js +++ b/index.cjs @@ -2,15 +2,14 @@ // classic singleton yargs API, to use yargs // without running as a singleton do: // require('yargs/yargs')(process.argv.slice(2)) -const yargs = require('./yargs') -const processArgv = require('./build/lib/process-argv') +const Yargs = require('./build/index.cjs') -Argv(processArgv.getProcessArgvWithoutBin()) +Argv(Yargs.processArgv.getProcessArgvWithoutBin()) module.exports = Argv function Argv (processArgs, cwd) { - const argv = yargs(processArgs, cwd, require) + const argv = Yargs(processArgs, cwd, require) singletonify(argv) return argv } diff --git a/index.mjs b/index.mjs new file mode 100644 index 000000000..a8c2d2254 --- /dev/null +++ b/index.mjs @@ -0,0 +1,13 @@ +'use strict' + +// Bootstraps yargs for ESM: +import esmPlatformShim from './lib/platform-shims/esm.mjs' +import { getProcessArgvWithoutBin } from './build/lib/utils/process-argv.js' +import { YargsWithShim } from './build/lib/yargs-factory.js' + +const Yargs = YargsWithShim(esmPlatformShim) + +export { + getProcessArgvWithoutBin, + Yargs, +} diff --git a/lib/argsert.ts b/lib/argsert.ts index 9c0d2d3ab..be730a2fc 100644 --- a/lib/argsert.ts +++ b/lib/argsert.ts @@ -1,5 +1,5 @@ -import { YError } from './yerror' -import { parseCommand, ParsedCommand } from './parse-command' +import { YError } from './yerror.js' +import { parseCommand, ParsedCommand } from './parse-command.js' const positionName = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth'] export function argsert (callerArguments: any[], length?: number): void diff --git a/lib/cjs.ts b/lib/cjs.ts new file mode 100644 index 000000000..d03effda2 --- /dev/null +++ b/lib/cjs.ts @@ -0,0 +1,38 @@ +'use strict' +// Bootstraps yargs for a CommonJS runtime: + +import { argsert } from './argsert.js' +import { isPromise } from './utils/is-promise.js' +import { objFilter } from './utils/obj-filter.js' +import { globalMiddlewareFactory } from './middleware.js' +import { parseCommand } from './parse-command.js' +import * as processArgv from './utils/process-argv.js' +import { YargsWithShim, rebase } from './yargs-factory.js' +import { YError } from './yerror.js' +import cjsPlatformShim from './platform-shims/cjs.js' + +// See https://github.com/yargs/yargs#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) : 10 +if (process && process.version) { + const major = Number(process.version.match(/v([^.]+)/)![1]) + if (major < minNodeVersion) { + throw Error(`yargs supports a minimum Node.js version of ${minNodeVersion}. Read our version support policy: https://github.com/yargs/yargs#supported-nodejs-versions`) + } +} + +const Parser = require('yargs-parser') +const Yargs = YargsWithShim(cjsPlatformShim) + +export default Object.assign(Yargs, { + argsert, + globalMiddlewareFactory, + isPromise, + objFilter, + parseCommand, + Parser, + processArgv, + rebase, + YError +}) diff --git a/lib/command.ts b/lib/command.ts index 26dc8b248..d943c84e8 100644 --- a/lib/command.ts +++ b/lib/command.ts @@ -1,16 +1,11 @@ -import { Dictionary, assertNotStrictEqual } from './common-types' -import { isPromise } from './is-promise' -import { applyMiddleware, commandMiddlewareFactory, Middleware } from './middleware' -import { parseCommand, Positional } from './parse-command' -import * as path from 'path' -import { RequireDirectoryOptions } from 'require-directory' -import { UsageInstance } from './usage' -import { inspect } from 'util' -import { ValidationInstance } from './validation' -import { YargsInstance, isYargsInstance, Options, OptionDefinition, Context, Configuration, Arguments, DetailedArguments } from './yargs' -import requireDirectory = require('require-directory') -import whichModule = require('which-module') -import Parser = require('yargs-parser') +import { Dictionary, assertNotStrictEqual, RequireDirectoryOptions, PlatformShim } from './typings/common-types.js' +import { isPromise } from './utils/is-promise.js' +import { applyMiddleware, commandMiddlewareFactory, Middleware } from './middleware.js' +import { parseCommand, Positional } from './parse-command.js' +import { UsageInstance } from './usage.js' +import { ValidationInstance } from './validation.js' +import { YargsInstance, isYargsInstance, Options, OptionDefinition, Context, Configuration, Arguments, DetailedArguments } from './yargs-factory.js' +import whichModule from './utils/which-module.js' const DEFAULT_MARKER = /(^\*)|(^\$0)/ @@ -21,7 +16,8 @@ export function command ( yargs: YargsInstance, usage: UsageInstance, validation: ValidationInstance, - globalMiddleware: Middleware[] = [] + globalMiddleware: Middleware[] = [], + shim: PlatformShim ) { const self: CommandInstance = {} as CommandInstance let handlers: Dictionary = {} @@ -127,26 +123,26 @@ export function command ( } return visited } - requireDirectory({ require: req, filename: callerFile } as NodeModule, dir, opts) + shim.requireDirectory({ require: req, filename: callerFile }, dir, opts) } // lookup module object from require()d command and derive name // if module was not require()d and no name given, throw error function moduleName (obj: CommandHandlerDefinition) { const mod = whichModule(obj) - if (!mod) throw new Error(`No command name given for module: ${inspect(obj)}`) + if (!mod) throw new Error(`No command name given for module: ${shim.inspect(obj)}`) return commandFromFilename(mod.filename) } // derive command name from filename function commandFromFilename (filename: string) { - return path.basename(filename, path.extname(filename)) + return shim.path.basename(filename, shim.path.extname(filename)) } function extractDesc ({ describe, description, desc }: CommandHandlerDefinition) { for (const test of [describe, description, desc]) { if (typeof test === 'string' || test === false) return test - assertNotStrictEqual(test, true as true) + assertNotStrictEqual(test, true as true, shim) } return false } @@ -284,7 +280,7 @@ export function command ( } self.runDefaultBuilderOn = function (yargs) { - assertNotStrictEqual(defaultCommand, undefined) + assertNotStrictEqual(defaultCommand, undefined, shim) if (shouldUpdateUsage(yargs)) { // build the root-level command string from the default string. const commandString = DEFAULT_MARKER.test(defaultCommand.original) @@ -368,7 +364,7 @@ export function command ( const config: Configuration = Object.assign({}, options.configuration, { 'populate--': true }) - const parsed = Parser.detailed(unparsed, Object.assign({}, options, { + const parsed = shim.Parser.detailed(unparsed, Object.assign({}, options, { configuration: config })) @@ -445,7 +441,7 @@ export function command ( } self.unfreeze = () => { const frozen = frozens.pop() - assertNotStrictEqual(frozen, undefined) + assertNotStrictEqual(frozen, undefined, shim) ;({ handlers, aliasMap, @@ -461,9 +457,9 @@ export interface CommandInstance { addDirectory( dir: string, context: Context, - req: NodeRequireFunction, + req: Function, callerFile: string, - opts?: RequireDirectoryOptions + opts?: RequireDirectoryOptions ): void addHandler ( cmd: string | string[] | CommandHandlerDefinition, diff --git a/lib/common-types.ts b/lib/common-types.ts deleted file mode 100644 index 5404bc7e1..000000000 --- a/lib/common-types.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { notStrictEqual, strictEqual } from 'assert' - -/** - * An object whose all properties have the same type. - */ -export type Dictionary = { [key: string]: T } - -/** - * Returns the keys of T that match Dictionary and are not arrays. - */ -export type DictionaryKeyof = Exclude>, KeyOf> - -/** - * Returns the keys of T that match U. - */ -export type KeyOf = Exclude<{ [K in keyof T]: T[K] extends U ? K : never }[keyof T], undefined> - -/** - * An array whose first element is not undefined. - */ -export type NotEmptyArray = [T, ...T[]] - -/** - * Returns the type of a Dictionary or array values. - */ -export type ValueOf = T extends (infer U)[] ? U : T[keyof T]; - -/** - * Typing wrapper around assert.notStrictEqual() - */ -export function assertNotStrictEqual (actual: T|N, expected: N, message ?: string | Error) -: asserts actual is Exclude { - notStrictEqual(actual, expected, message) -} - -/** - * Asserts actual is a single key, not a key array or a key map. - */ -export function assertSingleKey (actual: string | string[] | Dictionary): asserts actual is string { - strictEqual(typeof actual, 'string') -} - -/** - * Typing wrapper around Object.keys() - */ -export function objectKeys (object: T) { - return Object.keys(object) as (keyof T)[] -} diff --git a/lib/completion.ts b/lib/completion.ts index 77075abda..bbb5002fe 100644 --- a/lib/completion.ts +++ b/lib/completion.ts @@ -1,16 +1,15 @@ -import { CommandInstance, isCommandBuilderCallback } from './command' -import * as templates from './completion-templates' -import { isPromise } from './is-promise' -import { parseCommand } from './parse-command' -import * as path from 'path' -import { UsageInstance } from './usage' -import { YargsInstance } from './yargs' -import { Arguments, DetailedArguments } from 'yargs-parser/build/lib/yargs-parser-types' -import { assertNotStrictEqual } from './common-types' +import { CommandInstance, isCommandBuilderCallback } from './command.js' +import { PlatformShim, assertNotStrictEqual } from './typings/common-types.js' +import * as templates from './completion-templates.js' +import { isPromise } from './utils/is-promise.js' +import { parseCommand } from './parse-command.js' +import { UsageInstance } from './usage.js' +import { YargsInstance } from './yargs-factory.js' +import { Arguments, DetailedArguments } from './typings/yargs-parser-types.js' // add bash completions to your // yargs-powered applications. -export function completion (yargs: YargsInstance, usage: UsageInstance, command: CommandInstance) { +export function completion (yargs: YargsInstance, usage: UsageInstance, command: CommandInstance, shim: PlatformShim) { const self: CompletionInstance = { completionKey: 'get-yargs-completions' } as CompletionInstance @@ -20,8 +19,8 @@ export function completion (yargs: YargsInstance, usage: UsageInstance, command: aliases = parsed.aliases } - const zshShell = (process.env.SHELL && process.env.SHELL.indexOf('zsh') !== -1) || - (process.env.ZSH_NAME && process.env.ZSH_NAME.indexOf('zsh') !== -1) + const zshShell = (shim.getEnv('SHELL') && shim.getEnv('SHELL')!.indexOf('zsh') !== -1) || + (shim.getEnv('ZSH_NAME') && shim.getEnv('ZSH_NAME')!.indexOf('zsh') !== -1) // get a list of completion commands. // 'args' is the array of strings from the line to be completed self.getCompletion = function getCompletion (args, done) { @@ -33,7 +32,7 @@ export function completion (yargs: YargsInstance, usage: UsageInstance, command: // a custom completion function can be provided // to completion(). function runCompletionFunction (argv: Arguments) { - assertNotStrictEqual(completionFunction, null) + assertNotStrictEqual(completionFunction, null, shim) if (isSyncCompletionFunction(completionFunction)) { const result = completionFunction(current, argv) @@ -41,9 +40,9 @@ export function completion (yargs: YargsInstance, usage: UsageInstance, command: // promise based completion function. if (isPromise(result)) { return result.then((list) => { - process.nextTick(() => { done(list) }) + shim.process.nextTick(() => { done(list) }) }).catch((err) => { - process.nextTick(() => { throw err }) + shim.process.nextTick(() => { throw err }) }) } @@ -122,7 +121,7 @@ export function completion (yargs: YargsInstance, usage: UsageInstance, command: // generate the completion script to add to your .bashrc. self.generateCompletionScript = function generateCompletionScript ($0, cmd) { let script = zshShell ? templates.completionZshTemplate : templates.completionShTemplate - const name = path.basename($0) + const name = shim.path.basename($0) // add ./to applications not yet installed as bin. if ($0.match(/\.js$/)) $0 = `./${$0}` diff --git a/lib/middleware.ts b/lib/middleware.ts index 1186dcdda..c6662baac 100644 --- a/lib/middleware.ts +++ b/lib/middleware.ts @@ -1,6 +1,6 @@ -import { argsert } from './argsert' -import { isPromise } from './is-promise' -import { YargsInstance, Arguments } from './yargs' +import { argsert } from './argsert.js' +import { isPromise } from './utils/is-promise.js' +import { YargsInstance, Arguments } from './yargs-factory.js' export function globalMiddlewareFactory (globalMiddleware: Middleware[], context: T) { return function (callback: MiddlewareCallback | MiddlewareCallback[], applyBeforeValidation = false) { diff --git a/lib/parse-command.ts b/lib/parse-command.ts index 980fb4e8b..2f0b0dfef 100644 --- a/lib/parse-command.ts +++ b/lib/parse-command.ts @@ -1,4 +1,4 @@ -import { NotEmptyArray } from './common-types' +import { NotEmptyArray } from './typings/common-types.js' export function parseCommand (cmd: string) { const extraSpacesStrippedCommand = cmd.replace(/\s{2,}/g, ' ') diff --git a/lib/platform-shims/browser.mjs b/lib/platform-shims/browser.mjs new file mode 100644 index 000000000..b69e2ed4c --- /dev/null +++ b/lib/platform-shims/browser.mjs @@ -0,0 +1,91 @@ +'use strict' + +import cliui from 'https://unpkg.com/cliui@7.0.1/index.mjs' +import Parser from "https://unpkg.com/yargs-parser@19.0.0/browser.js"; +import { getProcessArgvBin } from '../../build/lib/utils/process-argv.js' +import { YError } from '../../build/lib/yerror.js' + +const REQUIRE_ERROR = 'require is not supported in browser' +const REQUIRE_DIRECTORY_ERROR = 'loading a directory of commands is not supported in browser' + +export default { + assert: { + notStrictEqual: (a, b) => { + // noop. + }, + strictEqual: (a, b) => { + // noop. + } + }, + cliui, + findUp: () => undefined, + getEnv: (key) => { + // There is no environment in browser: + return undefined + }, + inspect: console.log, + getCallerFile: () => { + throw new YError(REQUIRE_DIRECTORY_ERROR) + }, + getProcessArgvBin, + mainFilename: 'yargs', + Parser, + path: { + basename: (str) => str, + dirname: (str) => str, + extname: (str) => str, + relative: (str) => str + }, + process: { + argv: () => [], + cwd: () => '', + execPath: () => '', + // exit is noop browser: + exit: () => {}, + nextTick: (cb) => { + window.setTimeout(cb, 1) + }, + stdColumns: 80 + }, + readFileSync: () => { + return '' + }, + require: () => { + throw new YError(REQUIRE_ERROR) + }, + requireDirectory: () => { + throw new YError(REQUIRE_DIRECTORY_ERROR) + }, + stringWidth: (str) => { + return [...str].length + }, + // TODO: replace this with y18n once it's ported to ESM: + y18n: { + __: (...str) => { + if (str.length === 0) return '' + const args = str.slice(1) + return sprintf(str[0], ...args) + }, + __n: (str1, str2, count, ...args) => { + if (count === 1) { + return sprintf(str1, ...args) + } else { + return sprintf(str2, ...args) + } + }, + getLocale: () => { + return 'en_US' + }, + setLocale: () => {}, + updateLocale: () => {} + } +} + +function sprintf(_str, ...args) { + let str = '' + const split = _str.split('%s') + split.forEach((token, i) => { + str += `${token}${split[i + 1] !== undefined && args[i] ? args[i] : ''}` + }) + return str +} diff --git a/lib/platform-shims/cjs.ts b/lib/platform-shims/cjs.ts new file mode 100644 index 000000000..b4220be28 --- /dev/null +++ b/lib/platform-shims/cjs.ts @@ -0,0 +1,44 @@ +import { notStrictEqual, strictEqual } from 'assert' +import * as processArgv from '../utils/process-argv.js' + +const { readFileSync } = require('fs') +const { inspect } = require('util') +const { resolve } = require('path') +const y18n = require('y18n') +const Parser = require('yargs-parser') + +export default { + assert: { + notStrictEqual, + strictEqual + }, + cliui: require('cliui'), + findUp: require('escalade/sync'), + getEnv: (key: string) => { + return process.env[key] + }, + getCallerFile: require('get-caller-file'), + getProcessArgvBin: processArgv.getProcessArgvBin, + inspect, + mainFilename: require?.main?.filename ?? process.cwd(), + Parser, + path: require('path'), + process: { + argv: () => process.argv, + cwd: process.cwd, + execPath: () => process.execPath, + exit: () => { + process.exit() + }, + nextTick: process.nextTick, + stdColumns: typeof process.stdout.columns !== 'undefined' ? process.stdout.columns : null + }, + readFileSync, + require: (require as any), + requireDirectory: require('require-directory'), + stringWidth: require('string-width'), + y18n: y18n({ + directory: resolve(__dirname, '../locales'), + updateFiles: false + }) +} diff --git a/lib/platform-shims/deno.ts b/lib/platform-shims/deno.ts new file mode 100644 index 000000000..106d63de6 --- /dev/null +++ b/lib/platform-shims/deno.ts @@ -0,0 +1,116 @@ + +/* global Deno */ + +import { assertNotEquals, assertStrictEquals } from 'https://deno.land/std/testing/asserts.ts' +import { basename, dirname, extname, posix } from 'https://deno.land/std/path/mod.ts' +import { sprintf } from 'https://deno.land/std/fmt/printf.ts' + +import cliui from 'https://deno.land/x/cliui@v7.0.0-deno/deno.ts' +import escalade from 'https://deno.land/x/escalade@v3.0.3/sync.ts' +import Parser from 'https://deno.land/x/yargs_parser@v19.0.1-deno/deno.ts' +import { YError } from '../../build/lib/yerror.js' + +const REQUIRE_ERROR = 'require is not supported by ESM' +const REQUIRE_DIRECTORY_ERROR = 'loading a directory of commands is not supported yet for ESM' + +// Deno removes argv[0] and argv[1 from Deno.args: +const argv = ['deno run', ...Deno.args] + +// Yargs supports environment variables with prefixes, e.g., MY_APP_FOO, +// MY_APP_BAR. Environment variables are also used to detect locale. +let cwd: string = '' +let env: {[key: string]: string} = {} +try { + cwd = Deno.cwd() + env = Deno.env.toObject() +} catch (err) { + if (err.name !== 'PermissionDenied') { + throw err + } +} + +const path = { + basename: basename, + dirname: dirname, + extname: extname, + relative: (p1: string, p2: string) => { + try { + return posix.relative(p1, p2) + } catch (err) { + // Some yargs featuers require read access to the file system, + // e.g., support for multiple locales. + if (err.name !== 'PermissionDenied') { + throw err + } + return p1 + } + }, + resolve: posix.resolve +} + +// TODO: replace with Deno.consoleSize(Deno.stdout.rid) +// once this feature is stable: +const columns = 80 + +export default { + assert: { + notStrictEqual: assertNotEquals, + strictEqual: assertStrictEquals + }, + cliui, + findUp: escalade, + getEnv: (key: string) => { + return env[key] + }, + inspect: Deno.inspect, + getCallerFile: () => undefined, + getProcessArgvBin: () => { + return 'deno' + }, + mainFilename: cwd, + Parser, + path, + process: { + argv: () => argv, + cwd: () => cwd, + execPath: () => { + try { + return Deno.execPath() + } catch (_err) { + return 'deno' + } + }, + exit: Deno.exit, + nextTick: window.queueMicrotask, + stdColumns: columns ?? null + }, + readFileSync: Deno.readTextFileSync, + require: () => { + throw new YError(REQUIRE_ERROR) + }, + requireDirectory: () => { + throw new YError(REQUIRE_DIRECTORY_ERROR) + }, + stringWidth: (str: string) => { + return [...str].length + }, + y18n: { + __: (...str: string[]) => { + if (str.length === 0) return '' + const args = str.slice(1) + return sprintf(str[0], ...args) + }, + __n: (str1: string, str2: string, count: number, ...args: string[]) => { + if (count === 1) { + return sprintf(str1, ...args) + } else { + return sprintf(str2, ...args) + } + }, + getLocale: (): string => { + return 'en_US' + }, + setLocale: () => {}, + updateLocale: () => {} + } +} diff --git a/lib/platform-shims/esm.mjs b/lib/platform-shims/esm.mjs new file mode 100644 index 000000000..abd652b80 --- /dev/null +++ b/lib/platform-shims/esm.mjs @@ -0,0 +1,80 @@ +'use strict' + +import { notStrictEqual, strictEqual } from 'assert' +import cliui from 'cliui' +import escalade from 'escalade/sync' +import { format, inspect } from 'util' +import { readFileSync } from 'fs' +import { fileURLToPath } from 'url'; +import Parser from 'yargs-parser' +import { basename, dirname, extname, relative, resolve } from 'path' +import { getProcessArgvBin } from '../../build/lib/utils/process-argv.js' +import { YError } from '../../build/lib/yerror.js' + +const REQUIRE_ERROR = 'require is not supported by ESM' +const REQUIRE_DIRECTORY_ERROR = 'loading a directory of commands is not supported yet for ESM' + +const mainFilename = fileURLToPath(import.meta.url).split('node_modules')[0] + +export default { + assert: { + notStrictEqual, + strictEqual + }, + cliui, + findUp: escalade, + getEnv: (key) => { + return process.env[key] + }, + inspect, + getCallerFile: () => { + throw new YError(REQUIRE_DIRECTORY_ERROR) + }, + getProcessArgvBin, + mainFilename: mainFilename || process.cwd(), + Parser, + path: { + basename, + dirname, + extname, + relative + }, + process: { + argv: () => process.argv, + cwd: process.cwd, + execPath: () => process.execPath, + exit: process.exit, + nextTick: process.nextTick, + stdColumns: typeof process.stdout.columns !== 'undefined' ? process.stdout.columns : null + }, + readFileSync, + require: () => { + throw new YError(REQUIRE_ERROR) + }, + requireDirectory: () => { + throw new YError(REQUIRE_DIRECTORY_ERROR) + }, + stringWidth: (str) => { + return [...str].length + }, + // TODO: replace this with y18n once it's ported to ESM: + y18n: { + __: (...str) => { + if (str.length === 0) return '' + const args = str.slice(1) + return format(str[0], ...args) + }, + __n: (str1, str2, count, ...args) => { + if (count === 1) { + return format(str1, ...args) + } else { + return format(str2, ...args) + } + }, + getLocale: () => { + return 'en_US' + }, + setLocale: () => {}, + updateLocale: () => {} + } +} diff --git a/lib/typings/common-types.ts b/lib/typings/common-types.ts new file mode 100644 index 000000000..d6ac7c0e1 --- /dev/null +++ b/lib/typings/common-types.ts @@ -0,0 +1,108 @@ +import { Parser } from 'yargs-parser/build/lib/yargs-parser-types.d.js' + +/** + * An object whose all properties have the same type. + */ +export type Dictionary = { [key: string]: T } + +/** + * Returns the keys of T that match Dictionary and are not arrays. + */ +export type DictionaryKeyof = Exclude>, KeyOf> + +/** + * Returns the keys of T that match U. + */ +export type KeyOf = Exclude<{ [K in keyof T]: T[K] extends U ? K : never }[keyof T], undefined> + +/** + * An array whose first element is not undefined. + */ +export type NotEmptyArray = [T, ...T[]] + +/** + * Returns the type of a Dictionary or array values. + */ +export type ValueOf = T extends (infer U)[] ? U : T[keyof T]; + +/** + * Typing wrapper around assert.notStrictEqual() + */ +export function assertNotStrictEqual (actual: T|N, expected: N, shim: PlatformShim, message ?: string | Error) +: asserts actual is Exclude { + shim.assert.notStrictEqual(actual, expected, message) +} + +/** + * Asserts actual is a single key, not a key array or a key map. + */ +export function assertSingleKey (actual: string | string[] | Dictionary, shim: PlatformShim): asserts actual is string { + shim.assert.strictEqual(typeof actual, 'string') +} + +/** + * Typing wrappefr around Object.keys() + */ +export function objectKeys (object: T) { + return Object.keys(object) as (keyof T)[] +} + +export interface RequireDirectoryOptions { + extensions?: ReadonlyArray; + visit?: (commandObject: any, pathToFile: string, filename?: string) => any; + recurse?: boolean; +} + +// Dependencies that might vary between CJS, ESM, and Deno are isolated: +export interface PlatformShim { + assert: { + notStrictEqual: (expected: any, observed: any, message?: string|Error) => void, + strictEqual: (expected: any, observed: any, message?: string|Error) => void + }, + findUp: (startDir: string, fn: (dir: string[], names: string[]) => (string|undefined)) => string; + getCallerFile: () => string; + getEnv: (key: string) => (string|undefined); + getProcessArgvBin: () => string; + inspect: (obj: object) => string; + mainFilename: string; + requireDirectory: Function + stringWidth: (str: string) => number; + cliui: Function; + Parser: Parser; + path: { + basename: (p1: string, p2?: string) => string, + extname: (path: string) => string, + dirname: (path: string) => string, + relative: (p1: string, p2: string) => string; + resolve: (p1: string, p2: string) => string; + }, + process: { + argv: () => string[], + cwd: () => string; + execPath: () => string, + exit: (code: number) => void, + nextTick: (cb: Function) => void, + stdColumns: (number|null) + }, + readFileSync: (path: string, encoding: string) => string; + require: RequireType; + y18n: Y18N, +} + +export interface RequireType { + (path: string): Function; + main: MainType; +} + +export interface MainType { + filename: string; + children: MainType[]; +} + +export interface Y18N { + __(str: string, ...args: string[]): string; + __n(str: string, ...args: (string|number)[]): string; + getLocale(): string; + setLocale(locale: string): void; + updateLocale(obj: {[key: string]: string}): void; +} diff --git a/lib/typings/require-directory.d.ts b/lib/typings/require-directory.d.ts deleted file mode 100644 index c3e805029..000000000 --- a/lib/typings/require-directory.d.ts +++ /dev/null @@ -1,84 +0,0 @@ -// TODO: update @types/require-directory with this - -// Type definitions for require-directory 2.1 -// Project: https://github.com/troygoode/node-require-directory/ -// Definitions by: Ihor Chulinda -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.4 -/// - -/* eslint no-redeclare: "off" */ -declare namespace requireDirectory { - /** - * @description function that checks path for whitelisting/blacklisting - * @param path path of required module - * @returns true if path have to be whitelisted/blacklisted, false otherwise - */ - type CheckPathFn = (path: string) => boolean; - - interface RequireDirectoryResult { - /** - * @description module itself or hash of modules in subdirectory with name of this directory - */ - [index: string]: RequireDirectoryResult | T; - } - interface RequireDirectoryOptions { - /** - * @description array of file extensions that will be included in resulting hash as modules - * @default "['js', 'json', 'coffee']" - */ - extensions?: string[]; - /** - * @description option to include subdirectories - * @default true - */ - recurse?: boolean; - /** - * @description RegExp or function for whitelisting modules - * @default undefined - */ - include?: RegExp | CheckPathFn; - /** - * @description RegExp or function for blacklisting modules - * @default undefined - */ - exclude?: RegExp | CheckPathFn; - /** - * @description function for renaming modules in resulting hash - * @param name name of required module - * @returns transformed name of module - * @default "change nothing" - */ - rename?(name: string): string; - /** - * @description function that will be called for each required module - * @param obj required module - * @param joined required module path - * @param filename require module filename - * @returns transformed module OR nothing (in second case module itself will be added to hash) - * @default "change nothing" - */ - visit?(obj: T, joined: string, filename: string): U | void; - } - - /** - * @description default options that is used for "require-directory" module - */ - const defaults: RequireDirectoryOptions -} - -/** - * @description function for requiring directory content as hash of modules - * @param m module for which has will be created - * @param path path to directory, if you want to build hash for another one (default to __dirname) - * @param options object with options for require-directory call - * @returns hash of modules in specified directory - */ -declare function requireDirectory( - m: NodeModule, - path?: string | requireDirectory.RequireDirectoryOptions, - options?: requireDirectory.RequireDirectoryOptions): requireDirectory.RequireDirectoryResult; - -declare module 'require-directory' { - export = requireDirectory; -} diff --git a/lib/typings/require-main-filename.d.ts b/lib/typings/require-main-filename.d.ts deleted file mode 100644 index 30ca73474..000000000 --- a/lib/typings/require-main-filename.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -// TODO: either create @types/require-main-filename or or convert require-main-filename to typescript - -/** - * Returns the entry point of the current application. - * - * `require.main.filename` is great for figuring out the entry point for the current application. - * This can be combined with a module like pkg-conf to, as if by magic, load top-level configuration. - * - * Unfortunately, `require.main.filename` sometimes fails when an application is executed - * with an alternative process manager, e.g., iisnode. - * - * `require-main-filename` is a shim that addresses this problem. - * - * @param _require require function - * @returns hash of modules in specified directory - */ -declare function requireMainFilename(_require: NodeRequire): string; - -declare module 'require-main-filename' { - export = requireMainFilename; -} diff --git a/lib/typings/set-blocking.d.ts b/lib/typings/set-blocking.d.ts deleted file mode 100644 index a4e982a20..000000000 --- a/lib/typings/set-blocking.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -// TODO: either create @types/set-blocking with this or convert set-blocking to typescript - -declare function setBlocking(blocking: boolean): void; - -declare module 'set-blocking' { - export = setBlocking; -} diff --git a/lib/typings/which-module.d.ts b/lib/typings/which-module.d.ts deleted file mode 100644 index 035006cad..000000000 --- a/lib/typings/which-module.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -// TODO: create @types/which-module from this - -/** - * Return the module object, if any, that represents the given argument in the require.cache. - * - * @param exported anything that was previously require()d or imported as a module, submodule, or dependency - * - which means exported is identical to the module.exports returned by this method. - * If exported did not come from the exports of a module in require.cache, then this method returns null - */ -declare function whichModule(exported: any): NodeModule | null; - -declare module 'which-module' { - export = whichModule; -} diff --git a/lib/typings/y18n.d.ts b/lib/typings/y18n.d.ts deleted file mode 100644 index 961623ddb..000000000 --- a/lib/typings/y18n.d.ts +++ /dev/null @@ -1,64 +0,0 @@ -// TODO: either update @types/y18n with this or convert y18n to typescript -// Forked from: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a9cb5fa/types/y18n/index.d.ts - -/* eslint no-redeclare: "off" */ -declare namespace y18n { - interface Config { - /** - * The locale directory, default ./locales. - */ - directory?: string; - /** - * Should newly observed strings be updated in file, default true. - */ - updateFiles?: boolean; - /** - * What locale should be used. - */ - locale?: string; - /** - * Should fallback to a language-only file (e.g. en.json) be allowed - * if a file matching the locale does not exist (e.g. en_US.json), default true. - */ - fallbackToLanguage?: boolean; - } - - export class Y18N { - /** - * Create an instance of y18n with the config provided - */ - constructor(config?: Config); - - /** - * Print a localized string, %s will be replaced with args. - */ - __(str: string, arg1?: string, arg2?: string, arg3?: string): string; - - /** - * Print a localized string with appropriate pluralization. - * If %d is provided in the string, the quantity will replace this placeholder. - */ - __n(singular: string, plural: string, quantity: number, ...param: any[]): string; - - /** - * Set the current locale being used. - */ - setLocale(str: string): void; - - /** - * What locale is currently being used? - */ - getLocale(): string; - - /** - * Update the current locale with the key value pairs in obj. - */ - updateLocale(obj: { [key: string]: string }): void; - } -} - -declare function y18n (opts?: y18n.Config): y18n.Y18N; - -declare module 'y18n' { - export = y18n; -} diff --git a/lib/typings/yargs-parser-types.ts b/lib/typings/yargs-parser-types.ts new file mode 100644 index 000000000..127817602 --- /dev/null +++ b/lib/typings/yargs-parser-types.ts @@ -0,0 +1,165 @@ +// Taken from yargs-parser@19.0.1 +// TODO: update this file periodically. +import type { Dictionary, ValueOf } from './common-types.js' + +type KeyOf = { + [K in keyof T]: string extends K ? never : number extends K ? never : K +} extends { [_ in keyof T]: infer U } ? U : never; + +export declare type ArgsInput = string | any[]; +export declare 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 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 declare type ArrayOption = string | { + key: string; + boolean?: boolean; + string?: boolean; + number?: boolean; + integer?: boolean; +}; +export declare type CoerceCallback = (arg: any) => any; +export declare 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 PlatformShim { + cwd: Function; + format: Function; + normalize: Function; + require: Function; + resolve: Function; + env: Function; +} +export declare 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; +} +export declare type StringFlag = Dictionary; +export declare type BooleanFlag = Dictionary; +export declare type NumberFlag = Dictionary; +export declare type ConfigsFlag = Dictionary; +export declare type CoercionsFlag = Dictionary; +export declare 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 declare type Flag = ValueOf>; +export declare type FlagValue = ValueOf; +export declare type FlagsKey = KeyOf>; +export declare type ArrayFlagsKey = Extract; +export interface DefaultValuesForType { + boolean: boolean; + string: string; + number: undefined; + array: any[]; +} +export declare type DefaultValuesForTypeKey = KeyOf; diff --git a/lib/usage.ts b/lib/usage.ts index 46c312c62..2d75c8e71 100644 --- a/lib/usage.ts +++ b/lib/usage.ts @@ -1,17 +1,13 @@ // this file handles outputting usage instructions, // failures, etc. keeps logging in one place. -import { Dictionary, assertNotStrictEqual } from './common-types' -import { objFilter } from './obj-filter' -import * as path from 'path' -import { YargsInstance } from './yargs' -import { YError } from './yerror' -import { Y18N } from 'y18n' -import { DetailedArguments } from 'yargs-parser/build/lib/yargs-parser-types' -import decamelize = require('decamelize') -import setBlocking = require('set-blocking') -import stringWidth = require('string-width') - -export function usage (yargs: YargsInstance, y18n: Y18N) { +import { Dictionary, assertNotStrictEqual, PlatformShim, Y18N } from './typings/common-types.js' +import { objFilter } from './utils/obj-filter.js' +import { YargsInstance } from './yargs-factory.js' +import { YError } from './yerror.js' +import { DetailedArguments } from 'yargs-parser/build/lib/yargs-parser-types.js' +import setBlocking from './utils/set-blocking.js' + +export function usage (yargs: YargsInstance, y18n: Y18N, shim: PlatformShim) { const __ = y18n.__ const self = {} as UsageInstance @@ -156,7 +152,7 @@ export function usage (yargs: YargsInstance, y18n: Y18N) { normalizeAliases() // handle old demanded API - const base$0 = yargs.customScriptName ? yargs.$0 : path.basename(yargs.$0) + const base$0 = yargs.customScriptName ? yargs.$0 : shim.path.basename(yargs.$0) const demandedOptions = yargs.getDemandedOptions() const demandedCommands = yargs.getDemandedCommands() const deprecatedOptions = yargs.getDeprecatedOptions() @@ -175,7 +171,7 @@ export function usage (yargs: YargsInstance, y18n: Y18N) { }, {} as Dictionary)) const theWrap = getWrap() - const ui = require('cliui')({ + const ui = shim.cliui({ width: theWrap, wrap: !!theWrap }) @@ -426,7 +422,7 @@ export function usage (yargs: YargsInstance, y18n: Y18N) { // column might be of the form "text" // or { text: "text", indent: 4 } width = Math.max( - stringWidth(modifier ? `${modifier} ${getText(v[0])}` : getText(v[0])) + getIndentation(v[0]), + shim.stringWidth(modifier ? `${modifier} ${getText(v[0])}` : getText(v[0])) + getIndentation(v[0]), width ) }) @@ -505,7 +501,7 @@ export function usage (yargs: YargsInstance, y18n: Y18N) { } self.functionDescription = (fn) => { - const description = fn.name ? decamelize(fn.name, '-') : __('generated-value') + const description = fn.name ? shim.Parser.decamelize(fn.name, '-') : __('generated-value') return ['(', description, ')'].join('') } @@ -554,8 +550,8 @@ export function usage (yargs: YargsInstance, y18n: Y18N) { const maxWidth = 80 // CI is not a TTY /* c8 ignore next 2 */ - if (typeof process === 'object' && process.stdout && process.stdout.columns) { - return Math.min(maxWidth, process.stdout.columns) + if (shim.process.stdColumns) { + return Math.min(maxWidth, shim.process.stdColumns) } else { return maxWidth } @@ -601,7 +597,7 @@ export function usage (yargs: YargsInstance, y18n: Y18N) { } self.unfreeze = function unfreeze () { const frozen = frozens.pop() - assertNotStrictEqual(frozen, undefined) + assertNotStrictEqual(frozen, undefined, shim) ;({ failMessage, failureOutput, diff --git a/lib/apply-extends.ts b/lib/utils/apply-extends.ts similarity index 80% rename from lib/apply-extends.ts rename to lib/utils/apply-extends.ts index 38dc9df73..b8c57515f 100644 --- a/lib/apply-extends.ts +++ b/lib/utils/apply-extends.ts @@ -1,38 +1,10 @@ - -import { Dictionary } from './common-types' -import * as fs from 'fs' -import * as path from 'path' -import { YError } from './yerror' +import { Dictionary, PlatformShim } from '../typings/common-types.js' +import { YError } from '../yerror.js' let previouslyVisitedConfigs: string[] = [] - -function checkForCircularExtends (cfgPath: string) { - if (previouslyVisitedConfigs.indexOf(cfgPath) > -1) { - throw new YError(`Circular extended configurations: '${cfgPath}'.`) - } -} - -function getPathToDefaultConfig (cwd: string, pathToExtend: string) { - return path.resolve(cwd, pathToExtend) -} - -function mergeDeep (config1: Dictionary, config2: Dictionary) { - const target: Dictionary = {} - function isObject (obj: Dictionary | any): obj is Dictionary { - return obj && typeof obj === 'object' && !Array.isArray(obj) - } - Object.assign(target, config1) - for (const key of Object.keys(config2)) { - if (isObject(config2[key]) && isObject(target[key])) { - target[key] = mergeDeep(config1[key], config2[key]) - } else { - target[key] = config2[key] - } - } - return target -} - -export function applyExtends (config: Dictionary, cwd: string, mergeExtends = false): Dictionary { +let shim: PlatformShim +export function applyExtends (config: Dictionary, cwd: string, mergeExtends: boolean, _shim: PlatformShim): Dictionary { + shim = _shim let defaultConfig = {} if (Object.prototype.hasOwnProperty.call(config, 'extends')) { @@ -57,12 +29,38 @@ export function applyExtends (config: Dictionary, cwd: string, mergeExtends = fa previouslyVisitedConfigs.push(pathToDefault) - defaultConfig = isPath ? JSON.parse(fs.readFileSync(pathToDefault, 'utf8')) : require(config.extends) + defaultConfig = isPath ? JSON.parse(shim.readFileSync(pathToDefault, 'utf8')) : require(config.extends) delete config.extends - defaultConfig = applyExtends(defaultConfig, path.dirname(pathToDefault), mergeExtends) + defaultConfig = applyExtends(defaultConfig, shim.path.dirname(pathToDefault), mergeExtends, shim) } previouslyVisitedConfigs = [] return mergeExtends ? mergeDeep(defaultConfig, config) : Object.assign({}, defaultConfig, config) } + +function checkForCircularExtends (cfgPath: string) { + if (previouslyVisitedConfigs.indexOf(cfgPath) > -1) { + throw new YError(`Circular extended configurations: '${cfgPath}'.`) + } +} + +function getPathToDefaultConfig (cwd: string, pathToExtend: string) { + return shim.path.resolve(cwd, pathToExtend) +} + +function mergeDeep (config1: Dictionary, config2: Dictionary) { + const target: Dictionary = {} + function isObject (obj: Dictionary | any): obj is Dictionary { + return obj && typeof obj === 'object' && !Array.isArray(obj) + } + Object.assign(target, config1) + for (const key of Object.keys(config2)) { + if (isObject(config2[key]) && isObject(target[key])) { + target[key] = mergeDeep(config1[key], config2[key]) + } else { + target[key] = config2[key] + } + } + return target +} diff --git a/lib/is-promise.ts b/lib/utils/is-promise.ts similarity index 100% rename from lib/is-promise.ts rename to lib/utils/is-promise.ts diff --git a/lib/levenshtein.ts b/lib/utils/levenshtein.ts similarity index 100% rename from lib/levenshtein.ts rename to lib/utils/levenshtein.ts diff --git a/lib/obj-filter.ts b/lib/utils/obj-filter.ts similarity index 84% rename from lib/obj-filter.ts rename to lib/utils/obj-filter.ts index c4767189c..c0d932f3f 100644 --- a/lib/obj-filter.ts +++ b/lib/utils/obj-filter.ts @@ -1,4 +1,4 @@ -import { objectKeys } from './common-types' +import { objectKeys } from '../typings/common-types.js' export function objFilter ( original = {} as T, diff --git a/lib/process-argv.ts b/lib/utils/process-argv.ts similarity index 100% rename from lib/process-argv.ts rename to lib/utils/process-argv.ts diff --git a/lib/utils/set-blocking.ts b/lib/utils/set-blocking.ts new file mode 100644 index 000000000..a378ce935 --- /dev/null +++ b/lib/utils/set-blocking.ts @@ -0,0 +1,17 @@ +interface WriteStreamWithHandle { + _handle: { + setBlocking: Function; + }, + isTTY: boolean; +} + +export default function setBlocking (blocking: boolean) { + // Deno and browser have no process object: + if (typeof process === 'undefined') return; + [process.stdout, process.stderr].forEach((_stream) => { + const stream = (_stream as any) as WriteStreamWithHandle + if (stream._handle && stream.isTTY && typeof stream._handle.setBlocking === 'function') { + stream._handle.setBlocking(blocking) + } + }) +} diff --git a/lib/utils/which-module.ts b/lib/utils/which-module.ts new file mode 100644 index 000000000..96d788db9 --- /dev/null +++ b/lib/utils/which-module.ts @@ -0,0 +1,8 @@ +export default function whichModule (exported: object) { + if (typeof require === 'undefined') return null + for (var i = 0, files = Object.keys(require.cache), mod; i < files.length; i++) { + mod = require.cache[files[i]] + if (mod!.exports === exported) return mod + } + return null +} diff --git a/lib/validation.ts b/lib/validation.ts index 34abde2e4..809e4cde3 100644 --- a/lib/validation.ts +++ b/lib/validation.ts @@ -1,16 +1,16 @@ -import { argsert } from './argsert' -import { Dictionary, assertNotStrictEqual } from './common-types' -import { levenshtein as distance } from './levenshtein' -import { objFilter } from './obj-filter' -import { UsageInstance } from './usage' -import { YargsInstance, Arguments } from './yargs' -import { DetailedArguments } from 'yargs-parser/build/lib/yargs-parser-types' -import { Y18N } from 'y18n' +import { argsert } from './argsert.js' +import { Dictionary, assertNotStrictEqual, Y18N, PlatformShim } from './typings/common-types.js' +import { levenshtein as distance } from './utils/levenshtein.js' +import { objFilter } from './utils/obj-filter.js' +import { UsageInstance } from './usage.js' +import { YargsInstance, Arguments } from './yargs-factory.js' +import { DetailedArguments } from 'yargs-parser/build/lib/yargs-parser-types.js' + const specialKeys = ['$0', '--', '_'] // validation-type-stuff, missing params, // bad implications, custom checks. -export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y18N) { +export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y18N, shim: PlatformShim) { const __ = y18n.__ const __n = y18n.__n const self = {} as ValidationInstance @@ -37,8 +37,8 @@ export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y1 'Not enough non-option arguments: got %s, need at least %s', 'Not enough non-option arguments: got %s, need at least %s', _s, - _s, - demandedCommands._.min + _s.toString(), + demandedCommands._.min.toString() ) ) } @@ -56,8 +56,8 @@ export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y1 'Too many non-option arguments: got %s, maximum of %s', 'Too many non-option arguments: got %s, maximum of %s', _s, - _s, - demandedCommands._.max + _s.toString(), + demandedCommands._.max.toString() ) ) } @@ -74,8 +74,8 @@ export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y1 'Not enough non-option arguments: got %s, need at least %s', 'Not enough non-option arguments: got %s, need at least %s', observed, - observed, - required + observed + '', + required + '' ) ) } @@ -269,7 +269,7 @@ export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y1 if (Array.isArray(value)) { value.forEach((i) => self.implies(key, i)) } else { - assertNotStrictEqual(value, undefined) + assertNotStrictEqual(value, undefined, shim) implied[key].push(value) } } @@ -394,7 +394,7 @@ export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y1 } self.unfreeze = function unfreeze () { const frozen = frozens.pop() - assertNotStrictEqual(frozen, undefined) + assertNotStrictEqual(frozen, undefined, shim) ;({ implied, checks, diff --git a/lib/yargs.ts b/lib/yargs-factory.ts similarity index 94% rename from lib/yargs.ts rename to lib/yargs-factory.ts index c0fdea021..1f5c1de29 100644 --- a/lib/yargs.ts +++ b/lib/yargs-factory.ts @@ -1,5 +1,10 @@ -import { CommandInstance, CommandHandler, CommandBuilderDefinition, CommandBuilder, CommandHandlerCallback, FinishCommandHandler, command as Command, CommandHandlerDefinition } from './command' -import { Dictionary, assertNotStrictEqual, KeyOf, DictionaryKeyof, ValueOf, objectKeys, assertSingleKey } from './common-types' +// Platform agnostic entrypoint for yargs, i.e., this factory is used to +// create an instance of yargs for CJS, ESM, Deno. +// +// Works by accepting a shim which shims methods that contain platform +// specific logic. +import { CommandInstance, CommandHandler, CommandBuilderDefinition, CommandBuilder, CommandHandlerCallback, FinishCommandHandler, command as Command, CommandHandlerDefinition } from './command.js' +import { Dictionary, assertNotStrictEqual, KeyOf, DictionaryKeyof, ValueOf, objectKeys, assertSingleKey, RequireDirectoryOptions, PlatformShim, RequireType } from './typings/common-types.js' import { Arguments as ParserArguments, DetailedArguments as ParserDetailedArguments, @@ -7,30 +12,25 @@ import { Options as ParserOptions, ConfigCallback, CoerceCallback -} from 'yargs-parser/build/lib/yargs-parser-types' -import { YError } from './yerror' -import { UsageInstance, FailureFunction, usage as Usage } from './usage' -import { argsert } from './argsert' -import * as fs from 'fs' - -import { completion as Completion, CompletionInstance, CompletionFunction } from './completion' -import * as path from 'path' - -import { validation as Validation, ValidationInstance, KeyOrPos } from './validation' -import { Y18N } from 'y18n' -import { objFilter } from './obj-filter' -import { applyExtends } from './apply-extends' -import { globalMiddlewareFactory, MiddlewareCallback, Middleware } from './middleware' -import * as processArgv from './process-argv' -import { RequireDirectoryOptions } from 'require-directory' -import { isPromise } from './is-promise' -import Parser = require('yargs-parser') -import y18nFactory = require('y18n') -import setBlocking = require('set-blocking') -import findUp = require('find-up') -import requireMainFilename = require('require-main-filename') - -export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), parentRequire = require) { +} from './typings/yargs-parser-types.js' +import { YError } from './yerror.js' +import { UsageInstance, FailureFunction, usage as Usage } from './usage.js' +import { argsert } from './argsert.js' +import { completion as Completion, CompletionInstance, CompletionFunction } from './completion.js' +import { validation as Validation, ValidationInstance, KeyOrPos } from './validation.js' +import { objFilter } from './utils/obj-filter.js' +import { applyExtends } from './utils/apply-extends.js' +import { globalMiddlewareFactory, MiddlewareCallback, Middleware } from './middleware.js' +import { isPromise } from './utils/is-promise.js' +import setBlocking from './utils/set-blocking.js' + +let shim: PlatformShim +export function YargsWithShim (_shim: PlatformShim) { + shim = _shim + return Yargs +} + +function Yargs (processArgs: string | string[] = [], cwd = shim.process.cwd(), parentRequire?: RequireType): YargsInstance { const self = {} as YargsInstance let command: CommandInstance let completion: CompletionInstance | null = null @@ -42,10 +42,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), let validation: ValidationInstance let handlerFinishCommand: FinishCommandHandler | null = null - const y18n = y18nFactory({ - directory: path.resolve(__dirname, '../../locales'), - updateFiles: false - }) + const y18n = shim.y18n self.middleware = globalMiddlewareFactory(globalMiddleware, self) @@ -58,10 +55,10 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), // ignore the node bin, specify this in your // bin file with #!/usr/bin/env node let default$0: string[] - if (/\b(node|iojs|electron)(\.exe)?$/.test(process.argv[0])) { - default$0 = process.argv.slice(1, 2) + if (/\b(node|iojs|electron)(\.exe)?$/.test(shim.process.argv()[0])) { + default$0 = shim.process.argv().slice(1, 2) } else { - default$0 = process.argv.slice(0, 1) + default$0 = shim.process.argv().slice(0, 1) } self.$0 = default$0 @@ -71,9 +68,9 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), }) .join(' ').trim() - if (process.env._ !== undefined && processArgv.getProcessArgvBin() === process.env._) { - self.$0 = process.env._.replace( - `${path.dirname(process.execPath)}/`, '' + if (shim.getEnv('_') && shim.getProcessArgvBin() === shim.getEnv('_')) { + self.$0 = shim.getEnv('_')!.replace( + `${shim.path.dirname(shim.process.execPath())}/`, '' ) } @@ -133,7 +130,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), ] arrayOptions.forEach(k => { - tmpOptions[k] = (options[k] || []).filter(k => !localLookup[k]) + tmpOptions[k] = (options[k] || []).filter((k: string) => !localLookup[k]) }) objectOptions.forEach(>(k: K) => { @@ -145,10 +142,10 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), // if this is the first time being executed, create // instances of all our helpers -- otherwise just reset. - usage = usage ? usage.reset(localLookup) : Usage(self, y18n) - validation = validation ? validation.reset(localLookup) : Validation(self, usage, y18n) - command = command ? command.reset() : Command(self, usage, validation, globalMiddleware) - if (!completion) completion = Completion(self, usage, command) + usage = usage ? usage.reset(localLookup) : Usage(self, y18n, shim) + validation = validation ? validation.reset(localLookup) : Validation(self, usage, y18n, shim) + command = command ? command.reset() : Command(self, usage, validation, globalMiddleware, shim) + if (!completion) completion = Completion(self, usage, command, shim) completionCommand = null output = '' @@ -185,7 +182,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), } function unfreeze () { const frozen = frozens.pop() - assertNotStrictEqual(frozen, undefined) + assertNotStrictEqual(frozen, undefined, shim) let configObjects: Dictionary[] ;({ options, @@ -306,11 +303,11 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), ) { argsert(' [*] [string]', [key, value, defaultDescription], arguments.length) if (defaultDescription) { - assertSingleKey(key) + assertSingleKey(key, shim) options.defaultDescription[key] = defaultDescription } if (typeof value === 'function') { - assertSingleKey(key) + assertSingleKey(key, shim) if (!options.defaultDescription[key]) options.defaultDescription[key] = usage.functionDescription(value) value = value.call() } @@ -432,7 +429,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), argsert('[object|string] [string|function] [function]', [key, msg, parseFn], arguments.length) // allow a config object to be provided directly. if ((typeof key === 'object') && !Array.isArray(key)) { - key = applyExtends(key, cwd, self.getParserConfiguration()['deep-merge-config']) + key = applyExtends(key, cwd, self.getParserConfiguration()['deep-merge-config'] || false, shim) options.configObjects = (options.configObjects || []).concat(key) return self } @@ -478,8 +475,8 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), self.commandDir = function (dir, opts) { argsert(' [object]', [dir, opts], arguments.length) - const req = parentRequire || require - command.addDirectory(dir, self.getContext(), req, require('get-caller-file')(), opts) + const req = parentRequire || shim.require + command.addDirectory(dir, self.getContext(), req, shim.getCallerFile(), opts) return self } @@ -495,7 +492,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), // options are provided. if (Array.isArray(max)) { max.forEach((key) => { - assertNotStrictEqual(msg, true as true) + assertNotStrictEqual(msg, true as true, shim) demandOption(key, msg) }) max = Infinity @@ -505,11 +502,11 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), } if (typeof keys === 'number') { - assertNotStrictEqual(msg, true as true) + assertNotStrictEqual(msg, true as true, shim) self.demandCommand(keys, max, msg, msg) } else if (Array.isArray(keys)) { keys.forEach((key) => { - assertNotStrictEqual(msg, true as true) + assertNotStrictEqual(msg, true as true, shim) demandOption(key, msg) }) } else { @@ -593,7 +590,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), argsert(' [string|boolean] [function|object] [function]', [msg, description, builder, handler], arguments.length) if (description !== undefined) { - assertNotStrictEqual(msg, null) + assertNotStrictEqual(msg, null, shim) // .usage() can be used as an alias for defining // a default command. if ((msg || '').match(/^\$0( |$)/)) { @@ -656,7 +653,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), // If an object exists in the key, add it to options.configObjects if (obj[key] && typeof obj[key] === 'object') { - conf = applyExtends(obj[key], rootPath || cwd, self.getParserConfiguration()['deep-merge-config']) + conf = applyExtends(obj[key], rootPath || cwd, self.getParserConfiguration()['deep-merge-config'] || false, shim) options.configObjects = (options.configObjects || []).concat(conf) } @@ -670,20 +667,24 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), let obj = {} try { - let startDir = rootPath || requireMainFilename(parentRequire) + let startDir = rootPath || shim.mainFilename // When called in an environment that lacks require.main.filename, such as a jest test runner, // startDir is already process.cwd(), and should not be shortened. // Whether or not it is _actually_ a directory (e.g., extensionless bin) is irrelevant, find-up handles it. - if (!rootPath && path.extname(startDir)) { - startDir = path.dirname(startDir) + if (!rootPath && shim.path.extname(startDir)) { + startDir = shim.path.dirname(startDir) } - const pkgJsonPath = findUp.sync('package.json', { - cwd: startDir + const pkgJsonPath = shim.findUp(startDir, (dir: string[], names: string[]) => { + if (names.includes('package.json')) { + return 'package.json' + } else { + return undefined + } }) - assertNotStrictEqual(pkgJsonPath, undefined) - obj = JSON.parse(fs.readFileSync(pkgJsonPath).toString()) + assertNotStrictEqual(pkgJsonPath, undefined, shim) + obj = JSON.parse(shim.readFileSync(pkgJsonPath, 'utf8')) } catch (noop) {} pkgs[npath] = obj || {} @@ -1139,7 +1140,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), self.exit = (code, err) => { hasOutput = true exitError = err - if (exitProcess) process.exit(code) + if (exitProcess) shim.process.exit(code) } // we use a custom logger that buffers output, @@ -1182,7 +1183,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), self.terminalWidth = () => { argsert([], 0) - return typeof process.stdout.columns !== 'undefined' ? process.stdout.columns : null + return shim.process.stdColumns } Object.defineProperty(self, 'argv', { @@ -1206,7 +1207,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), const config = Object.assign({}, options.configuration, { 'populate--': true }) - const parsed = Parser.detailed(args, Object.assign({}, options, { + const parsed = shim.Parser.detailed(args, Object.assign({}, options, { configuration: config })) as DetailedArguments @@ -1387,7 +1388,7 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), function guessLocale () { if (!detectLocale) return - const locale = process.env.LC_ALL || process.env.LC_MESSAGES || process.env.LANG || process.env.LANGUAGE || 'en_US' + const locale = shim.getEnv('LC_ALL') || shim.getEnv('LC_MESSAGES') || shim.getEnv('LANG') || shim.getEnv('LANGUAGE') || 'en_US' self.locale(locale.replace(/[.:].*/, '')) } @@ -1398,14 +1399,13 @@ export function Yargs (processArgs: string | string[] = [], cwd = process.cwd(), return self } - // rebase an absolute path to a relative one with respect to a base directory // exported for tests export interface RebaseFunction { (base: string, dir: string): string } -export const rebase: RebaseFunction = (base, dir) => path.relative(base, dir) +export const rebase: RebaseFunction = (base, dir) => shim.path.relative(base, dir) /** Instance of the yargs module. */ export interface YargsInstance { @@ -1462,7 +1462,7 @@ export interface YargsInstance { commandMiddleware ?: Middleware[], deprecated ?: boolean ): YargsInstance - commandDir (dir: string, opts?: RequireDirectoryOptions): YargsInstance + commandDir (dir: string, opts?: RequireDirectoryOptions): YargsInstance completion: { (cmd?: string, fn?: CompletionFunction): YargsInstance (cmd?: string, desc?: string | false, fn?: CompletionFunction): YargsInstance @@ -1553,6 +1553,7 @@ export interface YargsInstance { options: YargsInstance['option'] parse: { (): Arguments | Promise + (args: string | string[]): Arguments | Promise (args: string | string[], context: object, parseCallback?: ParseCallback): Arguments | Promise (args: string | string[], parseCallback: ParseCallback): Arguments | Promise (args: string | string[], shortCircuit: boolean): Arguments | Promise @@ -1609,10 +1610,13 @@ export interface Context { fullCommands: string[] } -type LoggerInstance = Pick +interface LoggerInstance { + error: Function, + log: Function +} export interface Options extends ParserOptions { - __: Y18N['__'] + __: (format: any, ...param: any[]) => string alias: Dictionary array: string[] boolean: string[] @@ -1727,5 +1731,6 @@ export interface Arguments extends ParserArguments { } export interface DetailedArguments extends ParserDetailedArguments { - argv: Arguments + argv: Arguments; + aliases: Dictionary; } diff --git a/package.json b/package.json index d565c939a..4c57fd4d9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,18 @@ "name": "yargs", "version": "15.4.0", "description": "yargs the modern, pirate-themed, successor to optimist.", - "main": "./index.js", + "main": "./index.cjs", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.cjs" + }, + "./yargs": { + "require": "./build/index.cjs" + } + }, + "type": "module", + "module": "./build/index.mjs", "contributors": [ { "name": "Yargs Contributors", @@ -10,39 +21,38 @@ } ], "files": [ - "index.js", - "yargs.js", - "yargs.d.ts", + "browser.mjs", + "index.cjs", + "index.mjs", "build", "locales", - "LICENSE" + "LICENSE", + "lib/platform-shims/*.mjs", + "!*.d.ts" ], "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^3.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.0", + "escalade": "^3.0.2", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", "string-width": "^4.2.0", - "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^19.0.0-beta.1" + "yargs-parser": "^19.0.1" }, "devDependencies": { "@types/chai": "^4.2.11", "@types/mocha": "^8.0.0", - "@types/node": "^10.0.3", + "@types/node": "^14.0.27", "@typescript-eslint/eslint-plugin": "^3.0.0", "@typescript-eslint/parser": "^3.0.0", + "@wessberg/rollup-plugin-ts": "^1.3.2", "c8": "^7.0.0", "chai": "^4.2.0", "chalk": "^4.0.0", "coveralls": "^3.0.9", "cpr": "^3.0.1", + "cross-env": "^7.0.2", "cross-spawn": "^7.0.0", - "es6-promise": "^4.2.5", "eslint": "^6.8.0", "eslint-plugin-import": "^2.20.1", "eslint-plugin-node": "^11.0.0", @@ -50,20 +60,26 @@ "hashish": "0.0.4", "mocha": "^8.0.0", "rimraf": "^3.0.2", + "rollup": "^2.23.0", + "rollup-plugin-cleanup": "^3.1.1", "standardx": "^5.0.0", "typescript": "^3.7.0", "which": "^2.0.0", "yargs-test-extends": "^1.0.1" }, "scripts": { - "fix": "standardx --fix ./*.ts && standardx --fix **/*.ts", + "check": "standardx './*.ts' && standardx '**/*.ts'", + "fix": "standardx --fix './*.ts' && standardx --fix '**/*.ts'", "posttest": "npm run check", - "test": "c8 mocha --require ./test/before.js --timeout=12000 --check-leaks", + "test": "c8 mocha ./test/*.cjs --require ./test/before.cjs --timeout=12000 --check-leaks", + "test:esm": "c8 mocha ./test/esm/*.mjs --check-leaks", "coverage": "c8 report --check-coverage", - "check": "standardx ./*.ts && standardx **/*.ts", - "compile": "rimraf build && tsc", "prepare": "npm run compile", - "pretest": "npm run compile -- -p tsconfig.test.json" + "pretest": "npm run compile -- -p tsconfig.test.json && cross-env NODE_ENV=test npm run build:cjs", + "compile": "rimraf build && tsc", + "postcompile": "npm run build:cjs", + "build:cjs": "rollup -c rollup.config.cjs", + "postbuild:cjs": "rimraf ./build/index.cjs.d.ts" }, "repository": { "type": "git", @@ -73,6 +89,8 @@ "standardx": { "ignore": [ "build", + "index.cjs", + "yargs.cjs", "**/example/**" ] }, diff --git a/rollup.config.cjs b/rollup.config.cjs new file mode 100644 index 000000000..835ef1156 --- /dev/null +++ b/rollup.config.cjs @@ -0,0 +1,23 @@ +const cleanup = require('rollup-plugin-cleanup') +const ts = require('@wessberg/rollup-plugin-ts') + +const output = { + format: 'cjs', + file: './build/index.cjs', + exports: 'default' +} + +const plugins = [ + ts(), + cleanup({ + comments: 'none', + extensions: ['*'] + }) +] +if (process.env.NODE_ENV === 'test') output.sourcemap = true + +module.exports = { + input: './lib/cjs.ts', + output, + plugins +} diff --git a/test/argsert.ts b/test/argsert.cjs similarity index 84% rename from test/argsert.ts rename to test/argsert.cjs index b6524ed55..7f6e4a04a 100644 --- a/test/argsert.ts +++ b/test/argsert.cjs @@ -1,13 +1,13 @@ /* global describe, it */ -import { argsert } from '../lib/argsert' -import { checkOutput } from './helpers/utils' -import { should } from 'chai' +const { argsert } = require('../build/index.cjs') +const { checkOutput } = require('./helpers/utils.cjs') +const { should } = require('chai') should() describe('Argsert', () => { it('does not warn if optional argument is not provided', () => { - const o = checkOutput(function (...args: any[]) { + const o = checkOutput(function (...args) { argsert('[object]', [].slice.call(args)) }) @@ -16,7 +16,7 @@ describe('Argsert', () => { it('warn if wrong type is provided for optional argument', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert('[object|number]', [].slice.call(args)) } @@ -28,7 +28,7 @@ describe('Argsert', () => { it('does not warn if optional argument is valid', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert('[object]', [].slice.call(args)) } @@ -39,7 +39,7 @@ describe('Argsert', () => { }) it('warns if required argument is not provided', () => { - const o = checkOutput(function (...args: any[]) { + const o = checkOutput(function (...args) { argsert('', [].slice.call(args)) }) @@ -48,7 +48,7 @@ describe('Argsert', () => { it('warns if required argument is of wrong type', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert('', [].slice.call(args)) } @@ -60,7 +60,7 @@ describe('Argsert', () => { it('supports a combination of required and optional arguments', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert(' [string|object]', [].slice.call(args)) } @@ -72,7 +72,7 @@ describe('Argsert', () => { it('warns if too many arguments are provided', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert(' [batman]', [].slice.call(args)) } @@ -84,7 +84,7 @@ describe('Argsert', () => { it('warn with argument position if wrong type is provided for argument', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert(' ', [].slice.call(args)) } @@ -96,7 +96,7 @@ describe('Argsert', () => { it('warn with generic argument position if wrong type is provided for seventh or greater argument', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert(' ', [].slice.call(args)) } @@ -108,7 +108,7 @@ describe('Argsert', () => { it('configures function to accept 0 parameters, if only arguments object is provided', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert([].slice.call(args)) } @@ -120,7 +120,7 @@ describe('Argsert', () => { it('allows for any type if * is provided', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert('<*>', [].slice.call(args)) } @@ -132,7 +132,7 @@ describe('Argsert', () => { it('should ignore trailing undefined values', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert('<*>', [].slice.call(args)) } @@ -144,7 +144,7 @@ describe('Argsert', () => { it('should not ignore undefined values that are not trailing', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert('<*>', [].slice.call(args)) } @@ -156,7 +156,7 @@ describe('Argsert', () => { it('supports null as special type', () => { const o = checkOutput(() => { - function foo (...args: any[]) { + function foo (...args) { argsert('', [].slice.call(args)) } foo(null) diff --git a/test/before.js b/test/before.cjs similarity index 100% rename from test/before.js rename to test/before.cjs diff --git a/test/command.js b/test/command.cjs similarity index 99% rename from test/command.js rename to test/command.cjs index 0d36bfd3e..59eb1dc7e 100644 --- a/test/command.js +++ b/test/command.cjs @@ -1,8 +1,8 @@ 'use strict' /* global describe, it, beforeEach */ -const yargs = require('../') +const yargs = require('../index.cjs') const expect = require('chai').expect -const checkOutput = require('../build/test/helpers/utils').checkOutput +const checkOutput = require('./helpers/utils.cjs').checkOutput require('chai').should() const noop = () => {} diff --git a/test/completion.js b/test/completion.cjs similarity index 99% rename from test/completion.js rename to test/completion.cjs index 16235303e..70fd403e7 100644 --- a/test/completion.js +++ b/test/completion.cjs @@ -1,10 +1,7 @@ 'use strict' /* global describe, it, beforeEach, after */ -const checkUsage = require('../build/test/helpers/utils').checkOutput -const yargs = require('../') - -/* polyfill Promise for older Node.js */ -require('es6-promise').polyfill() +const checkUsage = require('./helpers/utils.cjs').checkOutput +const yargs = require('../index.cjs') require('chai').should() diff --git a/test/deno/platform-shim.test.ts b/test/deno/platform-shim.test.ts new file mode 100644 index 000000000..aca9a3013 --- /dev/null +++ b/test/deno/platform-shim.test.ts @@ -0,0 +1,22 @@ +/* global Deno */ + +import { + assertEquals +} from 'https://deno.land/std/testing/asserts.ts' +import shim from '../../lib/platform-shims/deno.ts' + +// y18n. +Deno.test('__ behaves like sprintf', () => { + const str = shim.y18n.__('hello %s, goodnight %s', 'world', 'moon') + assertEquals(str, 'hello world, goodnight moon') +}) + +Deno.test('__n uses first string if singular', () => { + const str = shim.y18n.__n('Missing required argument: %s', 'Missing required arguments: %s', 1, 'foo, bar') + assertEquals(str, 'Missing required argument: foo, bar') +}) + +Deno.test('__n uses second string if plural', () => { + const str = shim.y18n.__n('Missing required argument: %s', 'Missing required arguments: %s', 2, 'foo, bar') + assertEquals(str, 'Missing required arguments: foo, bar') +}) diff --git a/test/deno/yargs.test.ts b/test/deno/yargs.test.ts new file mode 100644 index 000000000..803497f72 --- /dev/null +++ b/test/deno/yargs.test.ts @@ -0,0 +1,26 @@ +/* global Deno */ + +import { + assertMatch +} from 'https://deno.land/std/testing/asserts.ts' +import { Yargs, Arguments } from '../../deno.ts' + +Deno.test('demandCommand(1) throw error if no command provided', () => { + let err: Error|null = null + Yargs() + .demandCommand(1) + .parse(Deno.args, (_err: Error) => { + err = _err + }) + assertMatch(err!.message, /Not enough non-option/) +}) + +// TODO: we should think of a way to support this functionality +Deno.test('guesses version # based on package.json', () => { + let output: string|null = null + Yargs() + .parse('--version', (_err: Error, argv: Arguments, _output: string) => { + output = _output + }) + assertMatch('' + output, /[0-9]+\.[0-9]+\.[0-9]+/) +}) diff --git a/test/esm/platform-shim-test.mjs b/test/esm/platform-shim-test.mjs new file mode 100644 index 000000000..bef2496c4 --- /dev/null +++ b/test/esm/platform-shim-test.mjs @@ -0,0 +1,25 @@ +/* global describe, it */ + +import * as assert from 'assert' +import shim from '../../lib/platform-shims/esm.mjs' + +describe('platform-shim', () => { + describe('y18n', () => { + describe('__',() => { + it('behaves like sprintf', () => { + const str = shim.y18n.__('hello %s, goodnight %s', 'world', 'moon') + assert.strictEqual(str, 'hello world, goodnight moon') + }) + }) + describe('__n',() => { + it('uses first string if singular', () => { + const str = shim.y18n.__n('Missing required argument: %s', 'Missing required arguments: %s', 1, 'foo, bar') + assert.strictEqual(str, 'Missing required argument: foo, bar') + }) + it('uses second string if plural', () => { + const str = shim.y18n.__n('Missing required argument: %s', 'Missing required arguments: %s', 2, 'foo, bar') + assert.strictEqual(str, 'Missing required arguments: foo, bar') + }) + }) + }) +}) diff --git a/test/esm/yargs-test.mjs b/test/esm/yargs-test.mjs new file mode 100644 index 000000000..b509f2b6d --- /dev/null +++ b/test/esm/yargs-test.mjs @@ -0,0 +1,31 @@ +/* global describe, it */ + +import * as assert from 'assert' +import { Yargs, getProcessArgvWithoutBin } from '../../index.mjs' + +describe('ESM', () => { + describe('parser', () => { + it('parses process.argv by default', () => { + const parsed = Yargs(['--goodnight', 'moon']).parse() + assert.strictEqual(parsed.goodnight, 'moon') + }) + }) + describe('commandDir', () => { + it('throws an error if commndDir() used in ESM mode', () => { + let err; + try { + Yargs().commandDir('./') + } catch (_err) { + err = _err + } + assert.match(err.message, /not supported yet for ESM/) + }) + }) + describe('getProcessArgvWithoutBin', () => { + it('hides bin for standard node.js application', () => { + process.argv = ['node', 'foo.js', '--apple', '--banana'] + const args = getProcessArgvWithoutBin() + assert.deepEqual(args, ['--apple', '--banana']) + }) + }) +}) diff --git a/test/fixtures/bin.js b/test/fixtures/bin.js index 04b4dbf3c..76889cb82 100755 --- a/test/fixtures/bin.js +++ b/test/fixtures/bin.js @@ -1,5 +1,5 @@ #!/usr/bin/env node -var argv = require('../../index') +var argv = require('../../') .help('help') .completion() .argv diff --git a/test/fixtures/issue-497.js b/test/fixtures/issue-497.js index 0cda3b2cc..fbec4e4de 100755 --- a/test/fixtures/issue-497.js +++ b/test/fixtures/issue-497.js @@ -4,7 +4,7 @@ process.stdout.isTTY = true process.stderr.isTTY = true -var yargs = require('../../index') +var yargs = require('../../') var y = yargs.command('download ', 'make a get HTTP request') .help() diff --git a/test/fixtures/no-extension b/test/fixtures/no-extension index 9b2721f6b..b0efd6c9e 100755 --- a/test/fixtures/no-extension +++ b/test/fixtures/no-extension @@ -2,7 +2,7 @@ 'use strict' -var parser = require('../../yargs.js')(process.argv.slice(2)) +var parser = require('../../')(process.argv.slice(2)) console.log(parser.parserConfiguration({ 'dot-notation': false, diff --git a/test/fixtures/no-require-main.js b/test/fixtures/no-require-main.js index d415412cc..63b325735 100755 --- a/test/fixtures/no-require-main.js +++ b/test/fixtures/no-require-main.js @@ -5,7 +5,7 @@ // for some unknown reason, a test environment has decided to omit require.main delete require.main -var parser = require('../../yargs.js')(process.argv.slice(2), undefined, require) +var parser = require('../../')(process.argv.slice(2), undefined, require) console.log(parser.parserConfiguration({ 'dot-notation': false, diff --git a/test/fixtures/normal-bin.js b/test/fixtures/normal-bin.js index ae4d395ee..426e50e3c 100755 --- a/test/fixtures/normal-bin.js +++ b/test/fixtures/normal-bin.js @@ -1,5 +1,5 @@ #!/usr/bin/env node -var argv = require('../../index.js') +var argv = require('../../') .help('help') .version() .parserConfiguration({ diff --git a/test/fixtures/opt-assignment-and-positional-command-arg.js b/test/fixtures/opt-assignment-and-positional-command-arg.js index 3c1e2b96a..7ded499df 100755 --- a/test/fixtures/opt-assignment-and-positional-command-arg.js +++ b/test/fixtures/opt-assignment-and-positional-command-arg.js @@ -1,5 +1,5 @@ #!/usr/bin/env node -require('../../index') +require('../../') .option('foo', { nargs: 1 }) diff --git a/test/fixtures/symlink-bin.js b/test/fixtures/symlink-bin.js index e6ce6b934..da53b4bba 100755 --- a/test/fixtures/symlink-bin.js +++ b/test/fixtures/symlink-bin.js @@ -1,5 +1,5 @@ #!/usr/bin/env node -var argv = require('./yargs-symlink/index.js') +var argv = require('./yargs-symlink') .help('help') .version() .parserConfiguration({ diff --git a/test/helpers/utils.ts b/test/helpers/utils.cjs similarity index 56% rename from test/helpers/utils.ts rename to test/helpers/utils.cjs index 9f56d5d3d..03166511c 100644 --- a/test/helpers/utils.ts +++ b/test/helpers/utils.cjs @@ -1,17 +1,10 @@ 'use strict' -import * as Hash from 'hashish' -import { CheckOutputResult } from '../types' -import { format } from 'util' +const Hash = require('hashish') +const { format } = require('util') // capture terminal output, so that we might // assert against it. -export function checkOutput (f: () => T, argv?: string[]): CheckOutputResult -export function checkOutput(f: () => T, argv: string[] | undefined, cb: (err: Error | null, result: CheckOutputResult) => any): void -export function checkOutput ( - f: () => T, - argv?: string[], - cb?: (err: Error | null, result: CheckOutputResult) => any -): CheckOutputResult | void { +exports.checkOutput = function checkOutput(f, argv, cb) { let exit = false const _exit = process.exit const _emit = process.emit @@ -21,33 +14,33 @@ export function checkOutput ( const _log = console.log const _warn = console.warn - process.exit = (() => { exit = true }) as NodeJS.Process['exit'] + process.exit = (() => { exit = true }) process.env = Hash.merge(process.env, { _: 'node' }) process.argv = argv || ['./usage'] - const errors: string[] = [] - const logs: string[] = [] - const warnings: string[] = [] + const errors = [] + const logs = [] + const warnings = [] console.error = (...msg) => { errors.push(format(...msg)) } console.log = (...msg) => { logs.push(format(...msg)) } console.warn = (...msg) => { warnings.push(format(...msg)) } - let result: T + let result if (typeof cb === 'function') { process.exit = (() => { exit = true cb(null, done()) - }) as NodeJS.Process['exit'] - process.emit = function emit (this: NodeJS.Process, ev: string, value: any) { + }) + process.emit = function emit (ev, value) { if (ev === 'uncaughtException') { cb(value, done()) return true } - return _emit.apply(this, arguments as any) - } as NodeJS.Process['emit'] + return _emit.apply(this, arguments) + } f() } else { @@ -71,7 +64,7 @@ export function checkOutput ( console.warn = _warn } - function done (): CheckOutputResult { + function done () { reset() return { @@ -82,4 +75,4 @@ export function checkOutput ( result } } -} +} \ No newline at end of file diff --git a/test/integration.js b/test/integration.cjs similarity index 100% rename from test/integration.js rename to test/integration.cjs diff --git a/test/is-promise.ts b/test/is-promise.cjs similarity index 90% rename from test/is-promise.ts rename to test/is-promise.cjs index a3fd4797e..10210bd51 100644 --- a/test/is-promise.ts +++ b/test/is-promise.cjs @@ -1,6 +1,6 @@ /* global describe, it */ -import { expect } from 'chai' -import { isPromise } from '../lib/is-promise' +const { expect } = require('chai') +const { isPromise } = require('../build/index.cjs') describe('isPromise', () => { it('returns `false` on non promise value', () => { diff --git a/test/middleware.js b/test/middleware.cjs similarity index 97% rename from test/middleware.js rename to test/middleware.cjs index 868e65fa0..336ba8bd2 100644 --- a/test/middleware.js +++ b/test/middleware.cjs @@ -2,16 +2,21 @@ /* global describe, it, beforeEach, afterEach */ const { expect } = require('chai') -const { globalMiddlewareFactory } = require('../build/lib/middleware') +const { globalMiddlewareFactory } = require('../build/index.cjs') let yargs require('chai').should() +function clearRequireCache() { + delete require.cache[require.resolve('../index.cjs')] + delete require.cache[require.resolve('../build/index.cjs')] +} + describe('middleware', () => { beforeEach(() => { - yargs = require('../') + yargs = require('../index.cjs') }) afterEach(() => { - delete require.cache[require.resolve('../')] + clearRequireCache() }) it('should add a list of callbacks to global middleware', () => { diff --git a/test/obj-filter.ts b/test/obj-filter.cjs similarity index 59% rename from test/obj-filter.ts rename to test/obj-filter.cjs index 6d007adb1..0e23a4336 100644 --- a/test/obj-filter.ts +++ b/test/obj-filter.cjs @@ -1,14 +1,13 @@ /* global describe, it */ -import { objFilter } from '../lib/obj-filter' -import chai = require('chai') -chai.should() +const { objFilter } = require('../build/index.cjs') +const { expect } = require('chai') describe('ObjFilter', () => { it('returns a new reference to the original object if no filter function is given', () => { const original = { foo: 'bar', baz: 'foo' } const result = objFilter(original) - original.should.not.equal(result) - original.should.deep.equal(result) + expect(original).to.eql(result) + expect(original).to.deep.eql(result) }) }) diff --git a/test/parse-command.ts b/test/parse-command.cjs similarity index 68% rename from test/parse-command.ts rename to test/parse-command.cjs index 7ec02279f..042f6abcf 100644 --- a/test/parse-command.ts +++ b/test/parse-command.cjs @@ -1,6 +1,6 @@ /* global describe, it */ -import { expect } from 'chai' -import { parseCommand } from '../lib/parse-command' +const { expect } = require('chai') +const { parseCommand } = require('../build/index.cjs') describe('parseCommand', () => { it('should throw if no command is specified', () => { diff --git a/test/parser.js b/test/parser.cjs similarity index 80% rename from test/parser.js rename to test/parser.cjs index 8b9eecd68..1bb80ef82 100644 --- a/test/parser.js +++ b/test/parser.cjs @@ -1,7 +1,7 @@ 'use strict' /* global it */ -const yargs = require('../yargs') +const yargs = require('../build/index.cjs') const Parser = require('yargs-parser') require('chai').should() diff --git a/test/types/check-output-result.ts b/test/types/check-output-result.ts deleted file mode 100644 index 9a75b4a37..000000000 --- a/test/types/check-output-result.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface CheckOutputResult { - errors: string[] - logs: string[] - warnings: string[] - exit: boolean - result: T -} diff --git a/test/types/hashish.d.ts b/test/types/hashish.d.ts deleted file mode 100644 index 159909ebb..000000000 --- a/test/types/hashish.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -// TODO: create @types/hashish from this start (or switch to another dependency?) - -declare module 'hashish' { - export function merge (...objects: Partial[]): T -} diff --git a/test/types/index.ts b/test/types/index.ts deleted file mode 100644 index 937913a50..000000000 --- a/test/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './check-output-result' diff --git a/test/usage.js b/test/usage.cjs similarity index 99% rename from test/usage.js rename to test/usage.cjs index 935bbc2fd..61f302e34 100644 --- a/test/usage.js +++ b/test/usage.cjs @@ -1,12 +1,11 @@ 'use strict' /* global describe, it, beforeEach */ -const checkUsage = require('../build/test/helpers/utils').checkOutput +const checkUsage = require('./helpers/utils.cjs').checkOutput const chalk = require('chalk') const path = require('path') -const yargs = require('../') -const rebase = require('../yargs').rebase -const { YError } = require('../build/lib/yerror') +const yargs = require('../index.cjs') +const { rebase, YError } = require('../build/index.cjs') const should = require('chai').should() diff --git a/test/validation.js b/test/validation.cjs similarity index 98% rename from test/validation.js rename to test/validation.cjs index 8d438eaa2..c131160d6 100644 --- a/test/validation.js +++ b/test/validation.cjs @@ -1,10 +1,10 @@ 'use strict' /* global describe, it, beforeEach */ -const checkUsage = require('../build/test/helpers/utils').checkOutput +const checkUsage = require('./helpers/utils.cjs').checkOutput const expect = require('chai').expect const english = require('../locales/en.json') -let yargs = require('../') +let yargs = require('../index.cjs') require('chai').should() @@ -734,7 +734,7 @@ describe('validation tests', () => { }) it('should be displayed in the help message with its default name', () => { - const checkUsage = require('../build/test/helpers/utils').checkOutput + const checkUsage = require('./helpers/utils.cjs').checkOutput const r = checkUsage(() => yargs(['--help']) .config() .help('help') @@ -751,7 +751,7 @@ describe('validation tests', () => { }) it('should allow help message to be overridden', () => { - const checkUsage = require('../build/test/helpers/utils').checkOutput + const checkUsage = require('./helpers/utils.cjs').checkOutput const r = checkUsage(() => yargs(['--help']) .config('settings', 'pork chop sandwiches') .help('help') @@ -768,7 +768,7 @@ describe('validation tests', () => { }) it('outputs an error returned by the parsing function', () => { - const checkUsage = require('../build/test/helpers/utils').checkOutput + const checkUsage = require('./helpers/utils.cjs').checkOutput const r = checkUsage(() => yargs(['--settings=./package.json']) .config('settings', 'path to config file', configPath => Error('someone set us up the bomb')) .help('help') @@ -786,7 +786,7 @@ describe('validation tests', () => { }) it('outputs an error if thrown by the parsing function', () => { - const checkUsage = require('../build/test/helpers/utils').checkOutput + const checkUsage = require('./helpers/utils.cjs').checkOutput const r = checkUsage(() => yargs(['--settings=./package.json']) .config('settings', 'path to config file', (configPath) => { throw Error('someone set us up the bomb') diff --git a/test/yargs.js b/test/yargs.cjs similarity index 99% rename from test/yargs.js rename to test/yargs.cjs index 6860d30ea..d2326cd71 100644 --- a/test/yargs.js +++ b/test/yargs.cjs @@ -4,16 +4,19 @@ const expect = require('chai').expect const fs = require('fs') const path = require('path') -const checkOutput = require('../build/test/helpers/utils').checkOutput +const checkOutput = require('./helpers/utils.cjs').checkOutput const english = require('../locales/en.json') let yargs -const { YError } = require('../build/lib/yerror') - require('chai').should() const noop = () => {} const implicationsFailedPattern = new RegExp(english['Implications failed:']) +function clearRequireCache() { + delete require.cache[require.resolve('../index.cjs')] + delete require.cache[require.resolve('../build/index.cjs')] +} + describe('yargs dsl tests', () => { const oldProcess = { versions: {} } @@ -21,14 +24,14 @@ describe('yargs dsl tests', () => { oldProcess.argv = process.argv oldProcess.defaultApp = process.defaultApp oldProcess.versions.electron = process.versions.electron - yargs = require('../') + yargs = require('../index.cjs') }) afterEach(() => { process.argv = oldProcess.argv process.defaultApp = oldProcess.defaultApp process.versions.electron = oldProcess.versions.electron - delete require.cache[require.resolve('../')] + clearRequireCache() }) it('should use bin name for $0, eliminating path', () => { @@ -41,10 +44,10 @@ describe('yargs dsl tests', () => { }) it('should not remove the 1st argument of bundled electron apps', () => { - delete require.cache[require.resolve('../')] + clearRequireCache() process.argv = ['/usr/local/bin/app', '-f', 'toto', 'tutu'] process.versions.electron = '10.0.0-nightly.20200211' - yargs = require('../') + yargs = require('../index.cjs') const argv = yargs.parse() argv.should.have.property('f') argv.f.should.equal('toto') @@ -52,7 +55,7 @@ describe('yargs dsl tests', () => { }) it('should remove the 1st argument of unbundled electron apps', () => { - delete require.cache[require.resolve('../')] + clearRequireCache() process.argv = ['/usr/local/bin/electron', 'app.js', '-f', 'toto', 'tutu'] process.versions.electron = '10.0.0-nightly.20200211' // Same syntax as in electron @@ -61,7 +64,7 @@ describe('yargs dsl tests', () => { enumerable: true, value: true }) - yargs = require('../') + yargs = require('../index.cjs') const argv = yargs.parse() argv.should.have.property('f') argv.f.should.equal('toto') @@ -94,7 +97,6 @@ describe('yargs dsl tests', () => { }) .parse() ) - r.errors[2].should.match(implicationsFailedPattern) }) @@ -655,8 +657,8 @@ describe('yargs dsl tests', () => { describe('locale', () => { function loadLocale (locale) { - delete require.cache[require.resolve('../')] - yargs = require('../') + clearRequireCache() + yargs = require('../index.cjs') process.env.LC_ALL = locale } @@ -1365,6 +1367,7 @@ describe('yargs dsl tests', () => { }) it('protects against circular extended configurations', () => { + const {YError} = require('../build/index.cjs') expect(() => { yargs.config({ extends: './test/fixtures/extends/circular_1.json' }) }).to.throw(YError) @@ -2144,8 +2147,8 @@ describe('yargs dsl tests', () => { describe('yargs context', () => { beforeEach(() => { - delete require.cache[require.resolve('../')] - yargs = require('../') + clearRequireCache() + yargs = require('../index.cjs') }) it('should begin with initial state', () => { @@ -2586,9 +2589,9 @@ describe('yargs dsl tests', () => { it('throws error for unsupported Node.js versions', () => { process.env.YARGS_MIN_NODE_VERSION = '55' - delete require.cache[require.resolve('../yargs')] + clearRequireCache() expect(() => { - require('../yargs') + require('../index.cjs') }).to.throw(/yargs supports a minimum Node.js version of 55/) delete process.env.YARGS_MIN_NODE_VERSION }) diff --git a/tsconfig.json b/tsconfig.json index a6b82cad6..1975ea093 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,15 +1,19 @@ { "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { - "lib": [ - "es2017" - ], "outDir": "build", "rootDir": ".", "sourceMap": false, - "target": "es2017" + "target": "es2017", + "moduleResolution": "node", + "module": "es2015", + "removeComments": true }, "include": [ "lib/**/*.ts" + ], + "exclude": [ + "lib/cjs.ts", + "lib/platform-shims/*.ts" ] } diff --git a/tsconfig.test.json b/tsconfig.test.json index 75a19fe08..032808bd4 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -4,7 +4,10 @@ "sourceMap": true }, "include": [ - "lib/**/*.ts", - "test/**/*.ts" + "lib/**/*.ts" + ], + "exclude": [ + "lib/cjs.ts", + "lib/platform-shims/*.ts" ] } diff --git a/yargs-logo.png b/yargs-logo.png deleted file mode 100644 index a2f478ceafa6605142a57d04e8458ea3c1428f33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20447 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 diff --git a/yargs.d.ts b/yargs.d.ts deleted file mode 100644 index 4e055e771..000000000 --- a/yargs.d.ts +++ /dev/null @@ -1,795 +0,0 @@ -/* -* MIT License -* -* Copyright (c) 2016 Martin Poelstra, Mizunashi Mana, Jeffery Grajkowski, -* Jeff Kenney, Jimi (Dimitris) Charalampidis, Steffen Viken Valvåg, -* Emily Marigold Klassen, ExE Boss, and Aankhen. -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import { YargsInstance, RebaseFunction } from './build/lib/yargs' -import { Parser, DetailedArguments, Configuration } from 'yargs-parser/build/lib/yargs-parser-types' - -declare namespace yargs { - type BuilderCallback = ((args: YargsInstance) => PromiseLike>) | ((args: YargsInstance) => YargsInstance) | ((args: YargsInstance) => void); - - type ParserConfigurationOptions = Configuration & { - /** Sort commands alphabetically. Default is `false` */ - 'sort-commands': boolean; - }; - - /** - * The type parameter `T` is the expected shape of the parsed options. - * `Arguments` is those options plus `_` and `$0`, and an indexer falling - * back to `unknown` for unknown options. - * - * For the return type / `argv` property, we create a mapped type over - * `Arguments` to simplify the inferred type signature in client code. - */ - interface YargsInstance { - - /** - * Set key names as equivalent such that updates to a key will propagate to aliases and vice-versa. - * - * Optionally `.alias()` can take an object that maps keys to aliases. - * Each key of this object should be the canonical version of the option, and each value should be a string or an array of strings. - */ - // Aliases for previously declared options can inherit the types of those options. - alias(shortName: K1, longName: K2 | ReadonlyArray): YargsInstance; - alias(shortName: K2, longName: K1 | ReadonlyArray): YargsInstance; - alias(shortName: string | ReadonlyArray, longName: string | ReadonlyArray): YargsInstance; - alias(aliases: { [shortName: string]: string | ReadonlyArray }): YargsInstance; - - /** - * Get the arguments as a plain old object. - * - * Arguments without a corresponding flag show up in the `argv._` array. - * - * The script name or node command is available at `argv.$0` similarly to how `$0` works in bash or perl. - * - * If `yargs` is executed in an environment that embeds node and there's no script name (e.g. Electron or nw.js), - * it will ignore the first parameter since it expects it to be the script name. In order to override - * this behavior, use `.parse(process.argv.slice(1))` instead of .argv and the first parameter won't be ignored. - */ - argv: { [key in keyof Arguments]: Arguments[key] }; - - /** - * Tell the parser to interpret `key` as an array. - * If `.array('foo')` is set, `--foo foo bar` will be parsed as `['foo', 'bar']` rather than as `'foo'`. - * Also, if you use the option multiple times all the values will be flattened in one array so `--foo foo --foo bar` will be parsed as `['foo', 'bar']` - * - * When the option is used with a positional, use `--` to tell `yargs` to stop adding values to the array. - */ - array(key: K | ReadonlyArray): YargsInstance & { [key in K]: ToArray }>; - array(key: K | ReadonlyArray): YargsInstance | undefined }>; - - /** - * Interpret `key` as a boolean. If a non-flag option follows `key` in `process.argv`, that string won't get set as the value of `key`. - * - * `key` will default to `false`, unless a `default(key, undefined)` is explicitly set. - * - * If `key` is an array, interpret all the elements as booleans. - */ - boolean(key: K | ReadonlyArray): YargsInstance & { [key in K]: boolean | undefined }>; - boolean(key: K | ReadonlyArray): YargsInstance; - - /** - * Check that certain conditions are met in the provided arguments. - * @param func Called with two arguments, the parsed `argv` hash and an array of options and their aliases. - * If `func` throws or returns a non-truthy value, show the thrown error, usage information, and exit. - * @param global Indicates whether `check()` should be enabled both at the top-level and for each sub-command. - */ - check(func: (argv: Arguments, aliases: { [alias: string]: string }) => any, global?: boolean): YargsInstance; - - /** - * Limit valid values for key to a predefined set of choices, given as an array or as an individual value. - * If this method is called multiple times, all enumerated values will be merged together. - * Choices are generally strings or numbers, and value matching is case-sensitive. - * - * Optionally `.choices()` can take an object that maps multiple keys to their choices. - * - * Choices can also be specified as choices in the object given to `option()`. - */ - choices>(key: K, values: C): YargsInstance & { [key in K]: C[number] | undefined }>; - choices>(key: K, values: C): YargsInstance; - choices }>(choices: C): YargsInstance & { [key in keyof C]: C[key][number] | undefined }>; - - /** - * Provide a synchronous function to coerce or transform the value(s) given on the command line for `key`. - * - * The coercion function should accept one argument, representing the parsed value from the command line, and should return a new value or throw an error. - * The returned value will be used as the value for `key` (or one of its aliases) in `argv`. - * - * If the function throws, the error will be treated as a validation failure, delegating to either a custom `.fail()` handler or printing the error message in the console. - * - * Coercion will be applied to a value after all other modifications, such as `.normalize()`. - * - * Optionally `.coerce()` can take an object that maps several keys to their respective coercion function. - * - * You can also map the same function to several keys at one time. Just pass an array of keys as the first argument to `.coerce()`. - * - * If you are using dot-notion or arrays, .e.g., `user.email` and `user.password`, coercion will be applied to the final object that has been parsed - */ - coerce(key: K | ReadonlyArray, func: (arg: any) => V): YargsInstance & { [key in K]: V | undefined }>; - coerce(key: K | ReadonlyArray, func: (arg: any) => V): YargsInstance; - coerce any }>(opts: O): YargsInstance & { [key in keyof O]: ReturnType | undefined }>; - - /** - * Define the commands exposed by your application. - * @param command Should be a string representing the command or an array of strings representing the command and its aliases. - * @param description Use to provide a description for each command your application accepts (the values stored in `argv._`). - * Set `description` to false to create a hidden command. Hidden commands don't show up in the help output and aren't available for completion. - * @param [builder] Object to give hints about the options that your command accepts. - * Can also be a function. This function is executed with a yargs instance, and can be used to provide advanced command specific help. - * - * Note that when `void` is returned, the handler `argv` object type will not include command-specific arguments. - * @param [handler] Function, which will be executed with the parsed `argv` object. - */ - command(command: string | ReadonlyArray, description: string, builder?: BuilderCallback, handler?: (args: Arguments) => void): YargsInstance; - command(command: string | ReadonlyArray, description: string, builder?: O, handler?: (args: Arguments>) => void): YargsInstance; - command(command: string | ReadonlyArray, description: string, module: CommandModule): YargsInstance; - command(command: string | ReadonlyArray, showInHelp: false, builder?: BuilderCallback, handler?: (args: Arguments) => void): YargsInstance; - command(command: string | ReadonlyArray, showInHelp: false, builder?: O, handler?: (args: Arguments>) => void): YargsInstance; - command(command: string | ReadonlyArray, showInHelp: false, module: CommandModule): YargsInstance; - command(module: CommandModule): YargsInstance; - - // Advanced API - /** Apply command modules from a directory relative to the module calling this method. */ - commandDir(dir: string, opts?: RequireDirectoryOptions): YargsInstance; - - /** - * Enable bash/zsh-completion shortcuts for commands and options. - * - * If invoked without parameters, `.completion()` will make completion the command to output the completion script. - * - * @param [cmd] When present in `argv._`, will result in the `.bashrc` or `.zshrc` completion script being outputted. - * To enable bash/zsh completions, concat the generated script to your `.bashrc` or `.bash_profile` (or `.zshrc` for zsh). - * @param [description] Provide a description in your usage instructions for the command that generates the completion scripts. - * @param [func] Rather than relying on yargs' default completion functionality, which shiver me timbers is pretty awesome, you can provide your own completion method. - */ - completion(): YargsInstance; - completion(cmd: string, func?: AsyncCompletionFunction): YargsInstance; - completion(cmd: string, func?: SyncCompletionFunction): YargsInstance; - completion(cmd: string, func?: PromiseCompletionFunction): YargsInstance; - completion(cmd: string, description?: string | false, func?: AsyncCompletionFunction): YargsInstance; - completion(cmd: string, description?: string | false, func?: SyncCompletionFunction): YargsInstance; - completion(cmd: string, description?: string | false, func?: PromiseCompletionFunction): YargsInstance; - - /** - * Tells the parser that if the option specified by `key` is passed in, it should be interpreted as a path to a JSON config file. - * The file is loaded and parsed, and its properties are set as arguments. - * Because the file is loaded using Node's require(), the filename MUST end in `.json` to be interpreted correctly. - * - * If invoked without parameters, `.config()` will make --config the option to pass the JSON config file. - * - * @param [description] Provided to customize the config (`key`) option in the usage string. - * @param [explicitConfigurationObject] An explicit configuration `object` - */ - config(): YargsInstance; - config(key: string | ReadonlyArray, description?: string, parseFn?: (configPath: string) => object): YargsInstance; - config(key: string | ReadonlyArray, parseFn: (configPath: string) => object): YargsInstance; - config(explicitConfigurationObject: object): YargsInstance; - - /** - * Given the key `x` is set, the key `y` must not be set. `y` can either be a single string or an array of argument names that `x` conflicts with. - * - * Optionally `.conflicts()` can accept an object specifying multiple conflicting keys. - */ - conflicts(key: string, value: string | ReadonlyArray): YargsInstance; - conflicts(conflicts: { [key: string]: string | ReadonlyArray }): YargsInstance; - - /** - * Interpret `key` as a boolean flag, but set its parsed value to the number of flag occurrences rather than `true` or `false`. Default value is thus `0`. - */ - count(key: K | ReadonlyArray): YargsInstance & { [key in K]: number }>; - count(key: K | ReadonlyArray): YargsInstance; - - /** - * Set `argv[key]` to `value` if no option was specified in `process.argv`. - * - * Optionally `.default()` can take an object that maps keys to default values. - * - * The default value can be a `function` which returns a value. The name of the function will be used in the usage string. - * - * Optionally, `description` can also be provided and will take precedence over displaying the value in the usage instructions. - */ - default(key: K, value: V, description?: string): YargsInstance & { [key in K]: V }>; - default(key: K, value: V, description?: string): YargsInstance; - default(defaults: D, description?: string): YargsInstance & D>; - - /** - * @deprecated since version 6.6.0 - * Use '.demandCommand()' or '.demandOption()' instead - */ - demand(key: K | ReadonlyArray, msg?: string | true): YargsInstance>; - demand(key: K | ReadonlyArray, msg?: string | true): YargsInstance; - demand(key: string | ReadonlyArray, required?: boolean): YargsInstance; - demand(positionals: number, msg: string): YargsInstance; - demand(positionals: number, required?: boolean): YargsInstance; - demand(positionals: number, max: number, msg?: string): YargsInstance; - - /** - * @param key If is a string, show the usage information and exit if key wasn't specified in `process.argv`. - * If is an array, demand each element. - * @param msg If string is given, it will be printed when the argument is missing, instead of the standard error message. - * @param demand Controls whether the option is demanded; this is useful when using .options() to specify command line parameters. - */ - demandOption(key: K | ReadonlyArray, msg?: string | true): YargsInstance>; - demandOption(key: K | ReadonlyArray, msg?: string | true): YargsInstance; - demandOption(key: string | ReadonlyArray, demand?: boolean): YargsInstance; - - /** - * Demand in context of commands. - * You can demand a minimum and a maximum number a user can have within your program, as well as provide corresponding error messages if either of the demands is not met. - */ - demandCommand(): YargsInstance; - demandCommand(min: number, minMsg?: string): YargsInstance; - demandCommand(min: number, max?: number, minMsg?: string, maxMsg?: string): YargsInstance; - - /** - * Describe a `key` for the generated usage information. - * - * Optionally `.describe()` can take an object that maps keys to descriptions. - */ - describe(key: string | ReadonlyArray, description: string): YargsInstance; - describe(descriptions: { [key: string]: string }): YargsInstance; - - /** Should yargs attempt to detect the os' locale? Defaults to `true`. */ - detectLocale(detect: boolean): YargsInstance; - - /** - * Tell yargs to parse environment variables matching the given prefix and apply them to argv as though they were command line arguments. - * - * Use the "__" separator in the environment variable to indicate nested options. (e.g. prefix_nested__foo => nested.foo) - * - * If this method is called with no argument or with an empty string or with true, then all env vars will be applied to argv. - * - * Program arguments are defined in this order of precedence: - * 1. Command line args - * 2. Env vars - * 3. Config file/objects - * 4. Configured defaults - * - * Env var parsing is disabled by default, but you can also explicitly disable it by calling `.env(false)`, e.g. if you need to undo previous configuration. - */ - env(): YargsInstance; - env(prefix: string): YargsInstance; - env(enable: boolean): YargsInstance; - - /** A message to print at the end of the usage instructions */ - epilog(msg: string): YargsInstance; - /** A message to print at the end of the usage instructions */ - epilogue(msg: string): YargsInstance; - - /** - * Give some example invocations of your program. - * Inside `cmd`, the string `$0` will get interpolated to the current script name or node command for the present script similar to how `$0` works in bash or perl. - * Examples will be printed out as part of the help message. - */ - example(command: string, description: string): YargsInstance; - - /** Manually indicate that the program should exit, and provide context about why we wanted to exit. Follows the behavior set by `.exitProcess().` */ - exit(code: number, err: Error): void; - - /** - * By default, yargs exits the process when the user passes a help flag, the user uses the `.version` functionality, validation fails, or the command handler fails. - * Calling `.exitProcess(false)` disables this behavior, enabling further actions after yargs have been validated. - */ - exitProcess(enabled: boolean): YargsInstance; - - /** - * Method to execute when a failure occurs, rather than printing the failure message. - * @param func Is called with the failure message that would have been printed, the Error instance originally thrown and yargs state when the failure occurred. - */ - fail(func: (msg: string, err: Error, yargs: YargsInstance) => any): YargsInstance; - - /** - * Allows to programmatically get completion choices for any line. - * @param args An array of the words in the command line to complete. - * @param done The callback to be called with the resulting completions. - */ - getCompletion(args: ReadonlyArray, done: (completions: ReadonlyArray) => void): YargsInstance; - - /** - * Indicate that an option (or group of options) should not be reset when a command is executed - * - * Options default to being global. - */ - global(key: string | ReadonlyArray): YargsInstance; - - /** Given a key, or an array of keys, places options under an alternative heading when displaying usage instructions */ - group(key: string | ReadonlyArray, groupName: string): YargsInstance; - - /** Hides a key from the generated usage information. Unless a `--show-hidden` option is also passed with `--help` (see `showHidden()`). */ - hide(key: string): YargsInstance; - - /** - * Configure an (e.g. `--help`) and implicit command that displays the usage string and exits the process. - * By default yargs enables help on the `--help` option. - * - * Note that any multi-char aliases (e.g. `help`) used for the help option will also be used for the implicit command. - * If there are no multi-char aliases (e.g. `h`), then all single-char aliases will be used for the command. - * - * If invoked without parameters, `.help()` will use `--help` as the option and help as the implicit command to trigger help output. - * - * @param [description] Customizes the description of the help option in the usage string. - * @param [enableExplicit] If `false` is provided, it will disable --help. - */ - help(): YargsInstance; - help(enableExplicit: boolean): YargsInstance; - help(option: string, enableExplicit: boolean): YargsInstance; - help(option: string, description?: string, enableExplicit?: boolean): YargsInstance; - - /** - * Given the key `x` is set, it is required that the key `y` is set. - * y` can either be the name of an argument to imply, a number indicating the position of an argument or an array of multiple implications to associate with `x`. - * - * Optionally `.implies()` can accept an object specifying multiple implications. - */ - implies(key: string, value: string | ReadonlyArray): YargsInstance; - implies(implies: { [key: string]: string | ReadonlyArray }): YargsInstance; - - /** - * Return the locale that yargs is currently using. - * - * By default, yargs will auto-detect the operating system's locale so that yargs-generated help content will display in the user's language. - */ - locale(): string; - /** - * Override the auto-detected locale from the user's operating system with a static locale. - * Note that the OS locale can be modified by setting/exporting the `LC_ALL` environment variable. - */ - locale(loc: string): YargsInstance; - - /** - * Define global middleware functions to be called first, in list order, for all cli command. - * @param callbacks Can be a function or a list of functions. Each callback gets passed a reference to argv. - * @param [applyBeforeValidation] Set to `true` to apply middleware before validation. This will execute the middleware prior to validation checks, but after parsing. - */ - middleware(callbacks: MiddlewareFunction | ReadonlyArray>, applyBeforeValidation?: boolean): YargsInstance; - - /** - * The number of arguments that should be consumed after a key. This can be a useful hint to prevent parsing ambiguity. - * - * Optionally `.nargs()` can take an object of `key`/`narg` pairs. - */ - nargs(key: string, count: number): YargsInstance; - nargs(nargs: { [key: string]: number }): YargsInstance; - - /** The key provided represents a path and should have `path.normalize()` applied. */ - normalize(key: K | ReadonlyArray): YargsInstance & { [key in K]: ToString }>; - normalize(key: K | ReadonlyArray): YargsInstance; - - /** - * Tell the parser to always interpret key as a number. - * - * If `key` is an array, all elements will be parsed as numbers. - * - * If the option is given on the command line without a value, `argv` will be populated with `undefined`. - * - * If the value given on the command line cannot be parsed as a number, `argv` will be populated with `NaN`. - * - * Note that decimals, hexadecimals, and scientific notation are all accepted. - */ - number(key: K | ReadonlyArray): YargsInstance & { [key in K]: ToNumber }>; - number(key: K | ReadonlyArray): YargsInstance; - - /** - * Method to execute when a command finishes successfully. - * @param func Is called with the successful result of the command that finished. - */ - onFinishCommand(func: (result: any) => void): YargsInstance; - - /** - * This method can be used to make yargs aware of options that could exist. - * You can also pass an opt object which can hold further customization, like `.alias()`, `.demandOption()` etc. for that option. - */ - option(key: K, options: O): YargsInstance & { [key in K]: InferredOptionType }>; - option(key: K, options: O): YargsInstance }>; - option(options: O): YargsInstance & InferredOptionTypes>; - - /** - * This method can be used to make yargs aware of options that could exist. - * You can also pass an opt object which can hold further customization, like `.alias()`, `.demandOption()` etc. for that option. - */ - options(key: K, options: O): YargsInstance & { [key in K]: InferredOptionType }>; - options(key: K, options: O): YargsInstance }>; - options(options: O): YargsInstance & InferredOptionTypes>; - - /** - * Parse `args` instead of `process.argv`. Returns the `argv` object. `args` may either be a pre-processed argv array, or a raw argument string. - * - * Note: Providing a callback to parse() disables the `exitProcess` setting until after the callback is invoked. - * @param [context] Provides a useful mechanism for passing state information to commands - */ - parse(): { [key in keyof Arguments]: Arguments[key] }; - parse(arg: string | ReadonlyArray, context?: object, parseCallback?: ParseCallback): { [key in keyof Arguments]: Arguments[key] }; - - /** - * If the arguments have not been parsed, this property is `false`. - * - * If the arguments have been parsed, this contain detailed parsed arguments. - */ - parsed: DetailedArguments | false; - - /** Allows to configure advanced yargs features. */ - parserConfiguration(configuration: Partial): YargsInstance; - - /** - * Similar to `config()`, indicates that yargs should interpret the object from the specified key in package.json as a configuration object. - * @param [cwd] If provided, the package.json will be read from this location - */ - pkgConf(key: string | ReadonlyArray, cwd?: string): YargsInstance; - - /** - * Allows you to configure a command's positional arguments with an API similar to `.option()`. - * `.positional()` should be called in a command's builder function, and is not available on the top-level yargs instance. If so, it will throw an error. - */ - positional(key: K, opt: O): YargsInstance & { [key in K]: InferredOptionType }>; - positional(key: K, opt: O): YargsInstance }>; - - /** Should yargs provide suggestions regarding similar commands if no matching command is found? */ - recommendCommands(): YargsInstance; - - /** - * @deprecated since version 6.6.0 - * Use '.demandCommand()' or '.demandOption()' instead - */ - require(key: K | ReadonlyArray, msg?: string | true): YargsInstance>; - require(key: string, msg: string): YargsInstance; - require(key: string, required: boolean): YargsInstance; - require(keys: ReadonlyArray, msg: string): YargsInstance; - require(keys: ReadonlyArray, required: boolean): YargsInstance; - require(positionals: number, required: boolean): YargsInstance; - require(positionals: number, msg: string): YargsInstance; - - /** - * @deprecated since version 6.6.0 - * Use '.demandCommand()' or '.demandOption()' instead - */ - required(key: K | ReadonlyArray, msg?: string | true): YargsInstance>; - required(key: string, msg: string): YargsInstance; - required(key: string, required: boolean): YargsInstance; - required(keys: ReadonlyArray, msg: string): YargsInstance; - required(keys: ReadonlyArray, required: boolean): YargsInstance; - required(positionals: number, required: boolean): YargsInstance; - required(positionals: number, msg: string): YargsInstance; - - requiresArg(key: string | ReadonlyArray): YargsInstance; - - /** - * @deprecated since version 6.6.0 - * Use '.global()' instead - */ - reset(): YargsInstance; - - /** Set the name of your script ($0). Default is the base filename executed by node (`process.argv[1]`) */ - scriptName($0: string): YargsInstance; - - /** - * Generate a bash completion script. - * Users of your application can install this script in their `.bashrc`, and yargs will provide completion shortcuts for commands and options. - */ - showCompletionScript(): YargsInstance; - - /** - * Configure the `--show-hidden` option that displays the hidden keys (see `hide()`). - * @param option If `boolean`, it enables/disables this option altogether. i.e. hidden keys will be permanently hidden if first argument is `false`. - * If `string` it changes the key name ("--show-hidden"). - * @param description Changes the default description ("Show hidden options") - */ - showHidden(option?: string | boolean): YargsInstance; - showHidden(option: string, description?: string): YargsInstance; - - /** - * Print the usage data using the console function consoleLevel for printing. - * @param [consoleLevel='error'] - */ - showHelp(consoleLevel?: string): YargsInstance; - - /** - * Provide the usage data as a string. - * @param printCallback a function with a single argument. - */ - showHelp(printCallback: (s: string) => void): YargsInstance; - - /** - * By default, yargs outputs a usage string if any error is detected. - * Use the `.showHelpOnFail()` method to customize this behavior. - * @param enable If `false`, the usage string is not output. - * @param [message] Message that is output after the error message. - */ - showHelpOnFail(enable: boolean, message?: string): YargsInstance; - - /** Specifies either a single option key (string), or an array of options. If any of the options is present, yargs validation is skipped. */ - skipValidation(key: string | ReadonlyArray): YargsInstance; - - /** - * Any command-line argument given that is not demanded, or does not have a corresponding description, will be reported as an error. - * - * Unrecognized commands will also be reported as errors. - */ - strict(): YargsInstance; - strict(enabled: boolean): YargsInstance; - - /** - * Tell the parser logic not to interpret `key` as a number or boolean. This can be useful if you need to preserve leading zeros in an input. - * - * If `key` is an array, interpret all the elements as strings. - * - * `.string('_')` will result in non-hyphenated arguments being interpreted as strings, regardless of whether they resemble numbers. - */ - string(key: K | ReadonlyArray): YargsInstance & { [key in K]: ToString }>; - string(key: K | ReadonlyArray): YargsInstance; - - // Intended to be used with '.wrap()' - terminalWidth(): number; - - updateLocale(obj: { [key: string]: string }): YargsInstance; - - /** - * Override the default strings used by yargs with the key/value pairs provided in obj - * - * If you explicitly specify a locale(), you should do so before calling `updateStrings()`. - */ - updateStrings(obj: { [key: string]: string }): YargsInstance; - - /** - * Set a usage message to show which commands to use. - * Inside `message`, the string `$0` will get interpolated to the current script name or node command for the present script similar to how `$0` works in bash or perl. - * - * If the optional `description`/`builder`/`handler` are provided, `.usage()` acts an an alias for `.command()`. - * This allows you to use `.usage()` to configure the default command that will be run as an entry-point to your application - * and allows you to provide configuration for the positional arguments accepted by your program: - */ - usage(message: string): YargsInstance; - usage(command: string | ReadonlyArray, description: string, builder?: (args: YargsInstance) => YargsInstance, handler?: (args: Arguments) => void): YargsInstance; - usage(command: string | ReadonlyArray, showInHelp: boolean, builder?: (args: YargsInstance) => YargsInstance, handler?: (args: Arguments) => void): YargsInstance; - usage(command: string | ReadonlyArray, description: string, builder?: O, handler?: (args: Arguments>) => void): YargsInstance; - usage(command: string | ReadonlyArray, showInHelp: boolean, builder?: O, handler?: (args: Arguments>) => void): YargsInstance; - - /** - * Add an option (e.g. `--version`) that displays the version number (given by the version parameter) and exits the process. - * By default yargs enables version for the `--version` option. - * - * If no arguments are passed to version (`.version()`), yargs will parse the package.json of your module and use its version value. - * - * If the boolean argument `false` is provided, it will disable `--version`. - */ - version(): YargsInstance; - version(version: string): YargsInstance; - version(enable: boolean): YargsInstance; - version(optionKey: string, version: string): YargsInstance; - version(optionKey: string, description: string, version: string): YargsInstance; - - /** - * Format usage output to wrap at columns many columns. - * - * By default wrap will be set to `Math.min(80, windowWidth)`. Use `.wrap(null)` to specify no column limit (no right-align). - * Use `.wrap(yargs.terminalWidth())` to maximize the width of yargs' usage instructions. - */ - wrap(columns: number | null): YargsInstance; - } - - type Arguments = T & { - /** Non-option arguments */ - _: string[]; - /** The script name or node command */ - $0: string; - /** All remaining options */ - [argName: string]: unknown; - }; - - interface RequireDirectoryOptions { - /** Look for command modules in all subdirectories and apply them as a flattened (non-hierarchical) list. */ - recurse?: boolean; - /** The types of files to look for when requiring command modules. */ - extensions?: ReadonlyArray; - /** - * A synchronous function called for each command module encountered. - * Accepts `commandObject`, `pathToFile`, and `filename` as arguments. - * Returns `commandObject` to include the command; any falsy value to exclude/skip it. - */ - visit?: (commandObject: any, pathToFile?: string, filename?: string) => any; - /** Whitelist certain modules */ - include?: RegExp | ((pathToFile: string) => boolean); - /** Blacklist certain modules. */ - exclude?: RegExp | ((pathToFile: string) => boolean); - } - - interface Options { - /** string or array of strings, alias(es) for the canonical option key, see `alias()` */ - alias?: string | ReadonlyArray; - /** boolean, interpret option as an array, see `array()` */ - array?: boolean; - /** boolean, interpret option as a boolean flag, see `boolean()` */ - boolean?: boolean; - /** value or array of values, limit valid option arguments to a predefined set, see `choices()` */ - choices?: Choices; - /** function, coerce or transform parsed command line values into another value, see `coerce()` */ - coerce?: (arg: any) => any; - /** boolean, interpret option as a path to a JSON config file, see `config()` */ - config?: boolean; - /** function, provide a custom config parsing function, see `config()` */ - configParser?: (configPath: string) => object; - /** string or object, require certain keys not to be set, see `conflicts()` */ - conflicts?: string | ReadonlyArray | { [key: string]: string | ReadonlyArray }; - /** boolean, interpret option as a count of boolean flags, see `count()` */ - count?: boolean; - /** value, set a default value for the option, see `default()` */ - default?: any; - /** string, use this description for the default value in help content, see `default()` */ - defaultDescription?: string; - /** - * @deprecated since version 6.6.0 - * Use 'demandOption' instead - */ - demand?: boolean | string; - /** boolean or string, demand the option be given, with optional error message, see `demandOption()` */ - demandOption?: boolean | string; - /** string, the option description for help content, see `describe()` */ - desc?: string; - /** string, the option description for help content, see `describe()` */ - describe?: string; - /** string, the option description for help content, see `describe()` */ - description?: string; - /** boolean, indicate that this key should not be reset when a command is invoked, see `global()` */ - global?: boolean; - /** string, when displaying usage instructions place the option under an alternative group heading, see `group()` */ - group?: string; - /** don't display option in help output. */ - hidden?: boolean; - /** string or object, require certain keys to be set, see `implies()` */ - implies?: string | ReadonlyArray | { [key: string]: string | ReadonlyArray }; - /** number, specify how many arguments should be consumed for the option, see `nargs()` */ - nargs?: number; - /** boolean, apply path.normalize() to the option, see `normalize()` */ - normalize?: boolean; - /** boolean, interpret option as a number, `number()` */ - number?: boolean; - /** - * @deprecated since version 6.6.0 - * Use 'demandOption' instead - */ - require?: boolean | string; - /** - * @deprecated since version 6.6.0 - * Use 'demandOption' instead - */ - required?: boolean | string; - /** boolean, require the option be specified with a value, see `requiresArg()` */ - requiresArg?: boolean; - /** boolean, skips validation if the option is present, see `skipValidation()` */ - skipValidation?: boolean; - /** boolean, interpret option as a string, see `string()` */ - string?: boolean; - type?: 'array' | 'count' | PositionalOptionsType; - } - - interface PositionalOptions { - /** string or array of strings, see `alias()` */ - alias?: string | ReadonlyArray; - /** boolean, interpret option as an array, see `array()` */ - array?: boolean; - /** value or array of values, limit valid option arguments to a predefined set, see `choices()` */ - choices?: Choices; - /** function, coerce or transform parsed command line values into another value, see `coerce()` */ - coerce?: (arg: any) => any; - /** string or object, require certain keys not to be set, see `conflicts()` */ - conflicts?: string | ReadonlyArray | { [key: string]: string | ReadonlyArray }; - /** value, set a default value for the option, see `default()` */ - default?: any; - /** boolean or string, demand the option be given, with optional error message, see `demandOption()` */ - demandOption?: boolean | string; - /** string, the option description for help content, see `describe()` */ - desc?: string; - /** string, the option description for help content, see `describe()` */ - describe?: string; - /** string, the option description for help content, see `describe()` */ - description?: string; - /** string or object, require certain keys to be set, see `implies()` */ - implies?: string | ReadonlyArray | { [key: string]: string | ReadonlyArray }; - /** boolean, apply path.normalize() to the option, see normalize() */ - normalize?: boolean; - type?: PositionalOptionsType; - } - - /** Remove keys K in T */ - type Omit = { [key in Exclude]: T[key] }; - - /** Remove undefined as a possible value for keys K in T */ - type Defined = Omit & { [key in K]: Exclude }; - - /** Convert T to T[] and T | undefined to T[] | undefined */ - type ToArray = Array> | Extract; - - /** Gives string[] if T is an array type, otherwise string. Preserves | undefined. */ - type ToString = (Exclude extends any[] ? string[] : string) | Extract; - - /** Gives number[] if T is an array type, otherwise number. Preserves | undefined. */ - type ToNumber = (Exclude extends any[] ? number[] : number) | Extract; - - type InferredOptionType = - O extends { default: infer D } ? D : - O extends { type: 'count' } ? number : - O extends { count: true } ? number : - O extends { required: string | true } ? RequiredOptionType : - O extends { require: string | true } ? RequiredOptionType : - O extends { demand: string | true } ? RequiredOptionType : - O extends { demandOption: string | true } ? RequiredOptionType : - RequiredOptionType | undefined; - - type RequiredOptionType = - O extends { type: 'array', string: true } ? string[] : - O extends { type: 'array', number: true } ? number[] : - O extends { type: 'array', normalize: true } ? string[] : - O extends { type: 'string', array: true } ? string[] : - O extends { type: 'number', array: true } ? number[] : - O extends { string: true, array: true } ? string[] : - O extends { number: true, array: true } ? number[] : - O extends { normalize: true, array: true } ? string[] : - O extends { type: 'array' } ? Array : - O extends { type: 'boolean' } ? boolean : - O extends { type: 'number' } ? number : - O extends { type: 'string' } ? string : - O extends { array: true } ? Array : - O extends { boolean: true } ? boolean : - O extends { number: true } ? number : - O extends { string: true } ? string : - O extends { normalize: true } ? string : - O extends { choices: ReadonlyArray } ? C : - O extends { coerce: (arg: any) => infer T } ? T : - unknown; - - type InferredOptionTypes = { [key in keyof O]: InferredOptionType }; - - interface CommandModule { - /** array of strings (or a single string) representing aliases of `exports.command`, positional args defined in an alias are ignored */ - aliases?: ReadonlyArray | string; - /** object declaring the options the command accepts, or a function accepting and returning a yargs instance */ - builder?: CommandBuilder; - /** string (or array of strings) that executes this command when given on the command line, first string may contain positional args */ - command?: ReadonlyArray | string; - /** string used as the description for the command in help text, use `false` for a hidden command */ - describe?: string | false; - /** a function which will be passed the parsed argv. */ - handler: (args: Arguments) => void; - } - - type ParseCallback = (err: Error | undefined, argv: Arguments, output: string) => void; - type CommandBuilder = { [key: string]: Options } | ((args: YargsInstance) => YargsInstance) | ((args: YargsInstance) => PromiseLike>); - type SyncCompletionFunction = (current: string, argv: any) => string[]; - type AsyncCompletionFunction = (current: string, argv: any, done: (completion: ReadonlyArray) => void) => void; - type PromiseCompletionFunction = (current: string, argv: any) => Promise; - type MiddlewareFunction = (args: Arguments) => void; - type Choices = ReadonlyArray; - type PositionalOptionsType = 'boolean' | 'number' | 'string'; - - // Aliases for old @types/yargs names - type Argv = YargsInstance; -} - -declare interface yargs { - (processArgs?: string | string[], cwd?: string, parentRequire?: NodeRequire): YargsInstance - rebase: RebaseFunction - Parser: Parser -} - -export = yargs; diff --git a/yargs.js b/yargs.js index 83fafe3b7..44425c3c2 100644 --- a/yargs.js +++ b/yargs.js @@ -1,21 +1,5 @@ -'use strict' - -// See https://github.com/yargs/yargs#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) : 10 -if (process && process.version) { - const major = Number(process.version.match(/v([^.]+)/)[1]) - if (major < minNodeVersion) { - throw Error(`yargs supports a minimum Node.js version of ${minNodeVersion}. Read our version support policy: https://github.com/yargs/yargs#supported-nodejs-versions`) - } -} - -const { Yargs, rebase } = require('./build/lib/yargs') -const Parser = require('yargs-parser') - -exports = module.exports = Yargs -exports.rebase = rebase - -// allow consumers to directly use the version of yargs-parser used by yargs -exports.Parser = Parser +// CJS import shim for older versions of Node.js. +// this can be removed once all supported Node.js versions support +// export maps: +const Yargs = require('./build/index.cjs') +module.exports = Yargs