From 7c24670452c081c4229c53d075c28181684e2cb7 Mon Sep 17 00:00:00 2001 From: Curtis Date: Thu, 21 May 2020 15:43:29 -0500 Subject: [PATCH 1/6] chore(ts): init typescript conf + tsify tokenize-arg-string --- .editorconfig | 12 ++ .eslintrc | 21 +++ .gitignore | 1 + .mocharc.json | 6 + .nycrc | 13 ++ index.js | 2 +- ...e-arg-string.js => tokenize-arg-string.ts} | 10 +- package.json | 36 ++++- test/tokenize-arg-string.js | 70 --------- test/tokenize-arg-string.ts | 133 ++++++++++++++++++ tsconfig.json | 15 ++ tsconfig.test.json | 10 ++ 12 files changed, 246 insertions(+), 83 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintrc create mode 100644 .mocharc.json create mode 100644 .nycrc rename lib/{tokenize-arg-string.js => tokenize-arg-string.ts} (78%) delete mode 100644 test/tokenize-arg-string.js create mode 100644 test/tokenize-arg-string.ts create mode 100644 tsconfig.json create mode 100644 tsconfig.test.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..4039ff11 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..5ce8c64a --- /dev/null +++ b/.eslintrc @@ -0,0 +1,21 @@ +{ + "overrides": [ + { + "files": "*.ts", + "parser": "@typescript-eslint/parser", + "rules": { + "no-unused-vars": "off", + "no-useless-constructor": "off", + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-useless-constructor": "error" + } + } + ], + "parserOptions": { + "ecmaVersion": 2017, + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint/eslint-plugin" + ] +} diff --git a/.gitignore b/.gitignore index a7502d1d..791cb484 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea +build/ .nyc_output node_modules .DS_Store diff --git a/.mocharc.json b/.mocharc.json new file mode 100644 index 00000000..ef1c3645 --- /dev/null +++ b/.mocharc.json @@ -0,0 +1,6 @@ +{ + "spec": [ + "build/test", + "test" + ] +} diff --git a/.nycrc b/.nycrc new file mode 100644 index 00000000..89f6c3a0 --- /dev/null +++ b/.nycrc @@ -0,0 +1,13 @@ +{ + "exclude": [ + "build/test/**", + "test/**" + ], + "reporter": [ + "html", + "text" + ], + "lines": 100, + "branches": "97", + "statements": "100" +} diff --git a/index.js b/index.js index c14c1fc7..bd3e282e 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ const camelCase = require('camelcase') const decamelize = require('decamelize') const path = require('path') -const tokenizeArgString = require('./lib/tokenize-arg-string') +const { tokenizeArgString } = require('./build/lib/tokenize-arg-string') const util = require('util') function parse (args, opts) { diff --git a/lib/tokenize-arg-string.js b/lib/tokenize-arg-string.ts similarity index 78% rename from lib/tokenize-arg-string.js rename to lib/tokenize-arg-string.ts index 260c67c1..52827080 100644 --- a/lib/tokenize-arg-string.js +++ b/lib/tokenize-arg-string.ts @@ -1,5 +1,5 @@ // take an un-split argv string and tokenize it. -module.exports = function (argString) { +export function tokenizeArgString (argString: string | any[]): string[] { if (Array.isArray(argString)) { return argString.map(e => typeof e !== 'string' ? e + '' : e) } @@ -7,10 +7,10 @@ module.exports = function (argString) { argString = argString.trim() let i = 0 - let prevC = null - let c = null - let opening = null - const args = [] + let prevC: string | null = null + let c: string | null = null + let opening: string | null = null + const args: string[] = [] for (let ii = 0; ii < argString.length; ii++) { prevC = c diff --git a/package.json b/package.json index 636ff176..d872f7c3 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,14 @@ "description": "the mighty option parser used by yargs", "main": "index.js", "scripts": { - "fix": "standard --fix", - "test": "c8 --reporter=text --reporter=html mocha test/*.js", - "posttest": "standard", - "coverage": "c8 report --check-coverage check-coverage --lines=100 --branches=97 --statements=100" + "fix": "standardx --fix && standardx --fix **/*.ts", + "pretest": "npm run compile -- -p tsconfig.test.json", + "test": "c8 --reporter=text --reporter=html mocha test/*.js", + "posttest": "npm run check", + "coverage": "c8 report --check-coverage", + "check": "standardx && standardx **/*.ts", + "compile": "rimraf build && tsc", + "prepare": "npm run compile" }, "repository": { "type": "git", @@ -27,20 +31,38 @@ "author": "Ben Coe ", "license": "ISC", "devDependencies": { + "@types/chai": "^4.2.11", + "@types/mocha": "^7.0.2", + "@types/node": "^10.0.3", + "@typescript-eslint/eslint-plugin": "^2.25.0", + "@typescript-eslint/parser": "^2.25.0", "c8": "^7.0.1", "chai": "^4.2.0", + "eslint": "^7.0.0", + "eslint-plugin-import": "^2.20.1", + "eslint-plugin-node": "^11.0.0", + "gts": "^2.0.0-alpha.4", "mocha": "^7.0.0", - "standard": "^14.3.1" + "rimraf": "^3.0.2", + "standardx": "^5.0.0", + "typescript": "^3.7.0" }, "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" }, "files": [ - "lib", - "index.js" + "index.js", + "build", + "lib/**/*.js" ], "engines": { "node": ">=6" + }, + "standardx": { + "ignore": [ + "build", + "example.js" + ] } } diff --git a/test/tokenize-arg-string.js b/test/tokenize-arg-string.js deleted file mode 100644 index 2f35895c..00000000 --- a/test/tokenize-arg-string.js +++ /dev/null @@ -1,70 +0,0 @@ -/* global describe, it */ - -const tokenizeArgString = require('../lib/tokenize-arg-string') - -require('chai').should() -const expect = require('chai').expect - -describe('TokenizeArgString', function () { - it('handles unquoted string', function () { - const args = tokenizeArgString('--foo 99') - args[0].should.equal('--foo') - args[1].should.equal('99') - }) - - it('handles unquoted numbers', function () { - const args = tokenizeArgString(['--foo', 9]) - args[0].should.equal('--foo') - args[1].should.equal('9') - }) - - it('handles quoted string with no spaces', function () { - const args = tokenizeArgString("--foo 'hello'") - args[0].should.equal('--foo') - args[1].should.equal("'hello'") - }) - - it('handles single quoted string with spaces', function () { - const args = tokenizeArgString("--foo 'hello world' --bar='foo bar'") - args[0].should.equal('--foo') - args[1].should.equal("'hello world'") - args[2].should.equal("--bar='foo bar'") - }) - - it('handles double quoted string with spaces', function () { - const args = tokenizeArgString('--foo "hello world" --bar="foo bar"') - args[0].should.equal('--foo') - args[1].should.equal('"hello world"') - args[2].should.equal('--bar="foo bar"') - }) - - it('handles single quoted empty string', function () { - const args = tokenizeArgString('--foo \'\' --bar=\'\'') - args[0].should.equal('--foo') - args[1].should.equal("''") - args[2].should.equal("--bar=''") - }) - - it('handles double quoted empty string', function () { - const args = tokenizeArgString('--foo "" --bar=""') - args[0].should.equal('--foo') - args[1].should.equal('""') - args[2].should.equal('--bar=""') - }) - - it('handles quoted string with embedded quotes', function () { - var args = tokenizeArgString('--foo "hello \'world\'" --bar=\'foo "bar"\'') - args[0].should.equal('--foo') - args[1].should.equal('"hello \'world\'"') - args[2].should.equal('--bar=\'foo "bar"\'') - }) - - // https://github.com/yargs/yargs-parser/pull/100 - // https://github.com/yargs/yargs-parser/pull/106 - it('ignores unneeded spaces', function () { - const args = tokenizeArgString(' foo bar "foo bar" ') - args[0].should.equal('foo') - expect(args[1]).equal('bar') - expect(args[2]).equal('"foo bar"') - }) -}) diff --git a/test/tokenize-arg-string.ts b/test/tokenize-arg-string.ts new file mode 100644 index 00000000..7621d45c --- /dev/null +++ b/test/tokenize-arg-string.ts @@ -0,0 +1,133 @@ +/* global describe, it */ +import { expect, should } from 'chai' +import { tokenizeArgString } from '../lib/tokenize-arg-string' + +should() + +describe('TokenizeArgString', function () { + it('handles unquoted string', function () { + const args = tokenizeArgString('--foo 99') + args[0].should.equal('--foo') + args[1].should.equal('99') + }) + + it('handles unquoted numbers', function () { + const args = tokenizeArgString(['--foo', 9]) + args[0].should.equal('--foo') + args[1].should.equal('9') + }) + + it('handles quoted string with no spaces', function () { + const args = tokenizeArgString("--foo 'hello'") + args[0].should.equal('--foo') + args[1].should.equal("'hello'") + }) + + it('handles single quoted string with spaces', function () { + const args = tokenizeArgString("--foo 'hello world' --bar='foo bar'") + args[0].should.equal('--foo') + args[1].should.equal("'hello world'") + args[2].should.equal("--bar='foo bar'") + }) + + it('handles double quoted string with spaces', function () { + const args = tokenizeArgString('--foo "hello world" --bar="foo bar"') + args[0].should.equal('--foo') + args[1].should.equal('"hello world"') + args[2].should.equal('--bar="foo bar"') + }) + + it('handles single quoted empty string', function () { + const args = tokenizeArgString('--foo \'\' --bar=\'\'') + args[0].should.equal('--foo') + args[1].should.equal("''") + args[2].should.equal("--bar=''") + }) + + it('handles double quoted empty string', function () { + const args = tokenizeArgString('--foo "" --bar=""') + args[0].should.equal('--foo') + args[1].should.equal('""') + args[2].should.equal('--bar=""') + }) + + it('handles quoted string with embedded quotes', function () { + var args = tokenizeArgString('--foo "hello \'world\'" --bar=\'foo "bar"\'') + args[0].should.equal('--foo') + args[1].should.equal('"hello \'world\'"') + args[2].should.equal('--bar=\'foo "bar"\'') + }) + + // https://github.com/yargs/yargs-parser/pull/100 + // https://github.com/yargs/yargs-parser/pull/106 + it('ignores unneeded spaces', function () { + const args = tokenizeArgString(' foo bar "foo bar" ') + args[0].should.equal('foo') + expect(args[1]).equal('bar') + expect(args[2]).equal('"foo bar"') + }) + + it('handles boolean options', function () { + const args = tokenizeArgString('--foo -bar') + expect(args[0]).to.equal(('--foo')) + expect(args[1]).to.equal(('-bar')) + }) + + it('handles empty string', function () { + const args = tokenizeArgString('') + expect(args.length).to.equal(0) + }) + + it('handles array with unquoted string', function () { + const args = tokenizeArgString(['--foo', '99']) + args[0].should.equal('--foo') + args[1].should.equal('99') + }) + + it('handles array with quoted string with no spaces', function () { + const args = tokenizeArgString(['--foo', "'hello'"]) + args[0].should.equal('--foo') + args[1].should.equal("'hello'") + }) + + it('handles array with single quoted string with spaces', function () { + const args = tokenizeArgString(['--foo', "'hello world'", "--bar='foo bar'"]) + args[0].should.equal('--foo') + args[1].should.equal("'hello world'") + args[2].should.equal("--bar='foo bar'") + }) + + it('handles array with double quoted string with spaces', function () { + const args = tokenizeArgString(['--foo', '"hello world"', '--bar="foo bar"']) + args[0].should.equal('--foo') + args[1].should.equal('"hello world"') + args[2].should.equal('--bar="foo bar"') + }) + + it('handles array with single quoted empty string', function () { + const args = tokenizeArgString(['--foo', "''", "--bar=''"]) + args[0].should.equal('--foo') + args[1].should.equal("''") + args[2].should.equal("--bar=''") + }) + + it('handles array with double quoted empty string', function () { + const args = tokenizeArgString(['--foo', '""', '--bar=""']) + args[0].should.equal('--foo') + args[1].should.equal('""') + args[2].should.equal('--bar=""') + }) + + it('handles array with quoted string with embedded quotes', function () { + var args = tokenizeArgString(['--foo', '"hello \'world\'"', '--bar=\'foo "bar"\'']) + args[0].should.equal('--foo') + args[1].should.equal('"hello \'world\'"') + args[2].should.equal('--bar=\'foo "bar"\'') + }) + + it('handles array with boolean options', function () { + const args = tokenizeArgString(['--foo', '-bar']) + expect(args[0]).to.equal('--foo') + expect(args[1]).to.equal('-bar') + }) +}) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..a6b82cad --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "./node_modules/gts/tsconfig-google.json", + "compilerOptions": { + "lib": [ + "es2017" + ], + "outDir": "build", + "rootDir": ".", + "sourceMap": false, + "target": "es2017" + }, + "include": [ + "lib/**/*.ts" + ] +} diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 00000000..75a19fe0 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "sourceMap": true + }, + "include": [ + "lib/**/*.ts", + "test/**/*.ts" + ] +} From 88fc8573a007c7668aa098ee1cd6bc3fdf9f0464 Mon Sep 17 00:00:00 2001 From: QmarkC Date: Wed, 3 Jun 2020 18:50:32 -0500 Subject: [PATCH 2/6] fix(deps): update dependency decamelize to v3 (#274) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d872f7c3..ae05049e 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ }, "dependencies": { "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "decamelize": "^3.2.0" }, "files": [ "index.js", From 0c8001d581bb658d1b8d53318d24c474c36e3c89 Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Sat, 6 Jun 2020 10:11:10 -0700 Subject: [PATCH 3/6] build!: drops Node 6. begin following Node.js LTS schedule (#278) --- .github/workflows/ci.yaml | 2 +- README.md | 6 ++++++ index.js | 13 ++++++++++++- package.json | 2 +- test/yargs-parser.js | 9 +++++++++ 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 82416464..0213d80f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [8, 10, 12, 13] + node: [10, 12, 14] steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 diff --git a/README.md b/README.md index bae61c2a..eff195c3 100644 --- a/README.md +++ b/README.md @@ -439,6 +439,12 @@ node example.js --unknown-option --known-option 2 --string-option --unknown-opti { _: ['--unknown-option'], knownOption: 2, stringOption: '--unknown-option2' } ``` +## Supported Node.js Versions + +Libraries in this ecosystem make a best effort to track +[Node.js' release schedule](https://nodejs.org/en/about/releases/). Here's [a +post on why we think this is important](https://medium.com/the-node-js-collection/maintainers-should-consider-following-node-js-release-schedule-ab08ed4de71a). + ## Special Thanks The yargs project evolves from optimist and minimist. It owes its diff --git a/index.js b/index.js index bd3e282e..4522fcc1 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,17 @@ const path = require('path') const { tokenizeArgString } = require('./build/lib/tokenize-arg-string') const util = require('util') +// See https://github.com/yargs/yargs-parser#supported-nodejs-versions for our +// version support policy. The YARGS_MIN_NODE_VERSION is used for testing only. +const minNodeVersion = (process && process.env && process.env.YARGS_MIN_NODE_VERSION) + ? Number(process.env.YARGS_MIN_NODE_VERSION) : 10 +if (process && process.version) { + const major = Number(process.version.match(/v([^.]+)/)[1]) + if (major < minNodeVersion) { + throw Error(`yargs parser supports a minimum Node.js version of ${minNodeVersion}. Read our version support policy: https://github.com/yargs/yargs-parser#supported-nodejs-versions`) + } +} + function parse (args, opts) { opts = Object.assign(Object.create(null), opts) // allow a string argument to be passed in rather @@ -626,8 +637,8 @@ function parse (args, opts) { } function applyEnvVars (argv, configOnly) { + if (!process) return if (typeof envPrefix === 'undefined') return - const prefix = typeof envPrefix === 'string' ? envPrefix : '' Object.keys(process.env).forEach(function (envVar) { if (prefix === '' || envVar.lastIndexOf(prefix, 0) === 0) { diff --git a/package.json b/package.json index ae05049e..1928ad0e 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "lib/**/*.js" ], "engines": { - "node": ">=6" + "node": ">=10" }, "standardx": { "ignore": [ diff --git a/test/yargs-parser.js b/test/yargs-parser.js index f5cbc183..e017a08b 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -3823,4 +3823,13 @@ describe('yargs-parser', function () { } }) }) + + it('throws error for unsupported Node.js versions', () => { + process.env.YARGS_MIN_NODE_VERSION = '55' + delete require.cache[require.resolve('../')] + expect(() => { + require('../') + }).to.throw(/yargs parser supports a minimum Node.js version of 55/) + delete process.env.YARGS_MIN_NODE_VERSION + }) }) From 37e6354ffe7f3494383f135ea503d0af978573ca Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Sat, 6 Jun 2020 10:29:04 -0700 Subject: [PATCH 4/6] build: switch to release-please action (#280) --- .github/release-please.yml | 2 -- .github/workflows/release-please.yml | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) delete mode 100644 .github/release-please.yml create mode 100644 .github/workflows/release-please.yml diff --git a/.github/release-please.yml b/.github/release-please.yml deleted file mode 100644 index 3c065997..00000000 --- a/.github/release-please.yml +++ /dev/null @@ -1,2 +0,0 @@ -releaseType: node -handleGHRelease: true diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 00000000..70660547 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,14 @@ +on: + push: + branches: + - master +name: release-please +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: bcoe/release-please-action@v1.2.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + release-type: node + package-name: yargs-parser From 729ff4d37b093f67f66ed05c418eb9dc17919c7c Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Sat, 6 Jun 2020 10:38:05 -0700 Subject: [PATCH 5/6] feat(deps): update to latest camelcase/decamelize (#281) --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 1928ad0e..1b44cd1b 100644 --- a/package.json +++ b/package.json @@ -36,20 +36,20 @@ "@types/node": "^10.0.3", "@typescript-eslint/eslint-plugin": "^2.25.0", "@typescript-eslint/parser": "^2.25.0", - "c8": "^7.0.1", + "c8": "^7.1.2", "chai": "^4.2.0", "eslint": "^7.0.0", "eslint-plugin-import": "^2.20.1", "eslint-plugin-node": "^11.0.0", "gts": "^2.0.0-alpha.4", - "mocha": "^7.0.0", + "mocha": "^7.2.0", "rimraf": "^3.0.2", "standardx": "^5.0.0", "typescript": "^3.7.0" }, "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^3.2.0" + "camelcase": "^6.0.0", + "decamelize": "^4.0.0" }, "files": [ "index.js", From b6b92375fc1e4ee2d2d6429cb84b08a14144efa9 Mon Sep 17 00:00:00 2001 From: Curtis Date: Tue, 9 Jun 2020 09:35:25 -0500 Subject: [PATCH 6/6] chore(ts): update ecmaVersion to match node v10 engine --- .eslintrc | 2 +- tsconfig.json | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.eslintrc b/.eslintrc index 5ce8c64a..ac6ca880 100644 --- a/.eslintrc +++ b/.eslintrc @@ -12,7 +12,7 @@ } ], "parserOptions": { - "ecmaVersion": 2017, + "ecmaVersion": 2018, "sourceType": "module" }, "plugins": [ diff --git a/tsconfig.json b/tsconfig.json index a6b82cad..c28e1966 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,9 @@ { "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { - "lib": [ - "es2017" - ], "outDir": "build", "rootDir": ".", - "sourceMap": false, - "target": "es2017" + "sourceMap": false }, "include": [ "lib/**/*.ts"