From b1b420014dca32e45a720f99c7a67700013f1b4e Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Fri, 7 Jun 2019 14:55:02 -0400 Subject: [PATCH 01/10] feature: add configuration option "ignore-unknown-options" --- index.js | 89 ++++++++++++++++++++----- test/yargs-parser.js | 155 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+), 17 deletions(-) diff --git a/index.js b/index.js index cf7872c5..63818667 100644 --- a/index.js +++ b/index.js @@ -26,7 +26,8 @@ function parse (args, opts) { 'set-placeholder-key': false, 'halt-at-non-option': false, 'strip-aliased': false, - 'strip-dashed': false + 'strip-dashed': false, + 'ignore-unknown-options': false }, opts.configuration) var defaults = opts.default || {} var configObjects = opts.configObjects || [] @@ -159,12 +160,18 @@ function parse (args, opts) { } else if (checkAllAliases(m[1], flags.arrays)) { args.splice(i + 1, 0, m[2]) i = eatArray(i, m[1], args) - } else { + } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(m[1])) { setArg(m[1], m[2]) + } else { + argv._.push(maybeCoerceNumber('_', arg)) } } else if (arg.match(negatedBoolean) && configuration['boolean-negation']) { key = arg.match(negatedBoolean)[1] - setArg(key, checkAllAliases(key, flags.arrays) ? [false] : false) + if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { + setArg(key, checkAllAliases(key, flags.arrays) ? [false] : false) + } else { + argv._.push(maybeCoerceNumber('_', arg)) + } // -- separated by space. } else if (arg.match(/^--.+/) || ( @@ -179,7 +186,7 @@ function parse (args, opts) { // array format = '--foo a b c' } else if (checkAllAliases(key, flags.arrays)) { i = eatArray(i, key, args) - } else { + } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { next = args[i + 1] if (next !== undefined && (!next.match(/^-/) || @@ -194,29 +201,40 @@ function parse (args, opts) { } else { setArg(key, defaultValue(key)) } + } else { + argv._.push(maybeCoerceNumber('_', arg)) } // dot-notation flag separated by '='. } else if (arg.match(/^-.\..+=/)) { m = arg.match(/^-([^=]+)=([\s\S]*)$/) - setArg(m[1], m[2]) + if (!configuration['ignore-unknown-options'] || hasAnyFlag(m[1])) { + setArg(m[1], m[2]) + } else { + argv._.push(maybeCoerceNumber('_', arg)) + } // dot-notation flag separated by space. } else if (arg.match(/^-.\..+/)) { next = args[i + 1] key = arg.match(/^-(.\..+)/)[1] - if (next !== undefined && !next.match(/^-/) && - !checkAllAliases(key, flags.bools) && - !checkAllAliases(key, flags.counts)) { - setArg(key, next) - i++ + if(!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { + if (next !== undefined && !next.match(/^-/) && + !checkAllAliases(key, flags.bools) && + !checkAllAliases(key, flags.counts)) { + setArg(key, next) + i++ + } else { + setArg(key, defaultValue(key)) + } } else { - setArg(key, defaultValue(key)) + argv._.push(maybeCoerceNumber('_', arg)) } } else if (arg.match(/^-[^-]+/) && !arg.match(negative)) { letters = arg.slice(1, -1).split('') broken = false + unmatched = [] for (var j = 0; j < letters.length; j++) { next = arg.slice(j + 2) @@ -233,8 +251,12 @@ function parse (args, opts) { } else if (checkAllAliases(key, flags.arrays)) { args.splice(i + 1, 0, value) i = eatArray(i, key, args) - } else { + } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { setArg(key, value) + } else { + unmatched.push(key); + unmatched.push('='); + unmatched.push(value); } broken = true @@ -242,24 +264,41 @@ function parse (args, opts) { } if (next === '-') { - setArg(letters[j], next) + if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { + setArg(letters[j], next) + } else { + unmatched.push(letters[j]); + unmatched.push(next); + } continue } // current letter is an alphabetic character and next value is a number if (/[A-Za-z]/.test(letters[j]) && /^-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { - setArg(letters[j], next) + if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { + setArg(letters[j], next) + } else { + unmatched.push(letters[j]); + unmatched.push(next); + } broken = true break } if (letters[j + 1] && letters[j + 1].match(/\W/)) { - setArg(letters[j], next) + if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { + setArg(letters[j], next) + } else { + unmatched.push(letters[j]); + unmatched.push(next); + } broken = true break - } else { + } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { setArg(letters[j], defaultValue(letters[j])) + } else { + unmatched.push(letters[j]) } } @@ -273,7 +312,7 @@ function parse (args, opts) { // array format = '-f a b c' } else if (checkAllAliases(key, flags.arrays)) { i = eatArray(i, key, args) - } else { + } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { next = args[i + 1] if (next !== undefined && (!/^(-|--)[^-]/.test(next) || @@ -288,8 +327,13 @@ function parse (args, opts) { } else { setArg(key, defaultValue(key)) } + } else { + unmatched.push(key); } } + if (unmatched.length > 0) { + argv._.push(maybeCoerceNumber('_', ['-', ...unmatched].join(''))) + } } else if (arg === '--') { notFlags = args.slice(i + 1) break @@ -756,6 +800,17 @@ function parse (args, opts) { return isSet } + + function hasAnyFlag (key) { + var isSet = false + var toCheck = [].concat(Object.values(flags)) + + toCheck.forEach(function (flag) { + if (flag[key]) isSet = flag[key] + }) + + return isSet + } // make a best effor to pick a default value // for an option based on name and type. diff --git a/test/yargs-parser.js b/test/yargs-parser.js index cb1342cf..84cb7248 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -3069,4 +3069,159 @@ describe('yargs-parser', function () { }) }) }) + describe('ignore-unknown-options', function () { + it('should ignore unknown options in long format separated by =', function () { + const argv = parser('--known-arg=1 --unknown-arg=2', { + number: ['known-arg'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['--unknown-arg=2'], + 'known-arg': 1, + 'knownArg': 1 + }) + }) + it('should ignore unknown options in boolean negations', function () { + const argv = parser('--no-known-arg --no-unknown-arg', { + boolean: ['known-arg'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['--no-unknown-arg'], + 'known-arg': false, + 'knownArg': false + }) + }) + it('should ignore unknown options in long format separated by space', function () { + const argv = parser('--known-arg 1 --unknown-arg 2', { + number: ['known-arg'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['--unknown-arg', 2], + 'known-arg': 1, + 'knownArg': 1 + }) + }) + it('should ignore unknown options in short dot format separated by equals', function () { + const argv = parser('-k.arg=1 -u.arg=2', { + number: ['k.arg'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-u.arg=2'], + 'k': { + 'arg': 1 + } + }) + }) + it('should ignore unknown options in short dot format separated by space', function () { + const argv = parser('-k.arg 1 -u.arg 2', { + number: ['k.arg'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-u.arg', 2], + 'k': { + 'arg': 1 + } + }) + }) + it('should ignore unknown options in short format separated by equals', function () { + const argv = parser('-k=1 -u=2', { + number: ['k'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-u=2'], + 'k': 1 + }) + }) + it('should ignore unknown options in short format followed by hyphen', function () { + const argv = parser('-k- -u-', { + string: ['k'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-u-'], + 'k': '-' + }) + }) + it('should ignore unknown options in short format separated by space', function () { + const argv = parser('-k 1 -u 2', { + number: ['k'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-u', 2], + 'k': 1 + }) + }) + it('should ignore unknown options in short format followed by a number', function () { + const argv = parser('-k1 -u2', { + number: ['k'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-u2'], + 'k': 1 + }) + }) + it('should ignore unknown options in short format followed by a non-word character', function () { + const argv = parser('-k/1/ -u/2/', { + string: ['k'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-u/2/'], + 'k': '/1/' + }) + }) + }) + it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is before the end', function () { + const argv = parser('-kuv', { + boolean: ['k', 'v'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-u'], + 'k': true, + 'v': true + }) + it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is at the end', function () { + const argv = parser('-kvu', { + boolean: ['k', 'v'], + configuration: { + 'ignore-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-u'], + 'k': true, + 'v': true + }) + }) + }) }) From 5a313962d2adf566099bcae79e7da8a5fed9b7c0 Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Sun, 9 Jun 2019 08:58:47 -0400 Subject: [PATCH 02/10] fix formatting and add a missing "let" keyword --- index.js | 26 +++++++++++++------------- test/yargs-parser.js | 14 +++++++------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/index.js b/index.js index 63818667..2e810bd7 100644 --- a/index.js +++ b/index.js @@ -219,7 +219,7 @@ function parse (args, opts) { next = args[i + 1] key = arg.match(/^-(.\..+)/)[1] - if(!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { + if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { if (next !== undefined && !next.match(/^-/) && !checkAllAliases(key, flags.bools) && !checkAllAliases(key, flags.counts)) { @@ -234,7 +234,7 @@ function parse (args, opts) { } else if (arg.match(/^-[^-]+/) && !arg.match(negative)) { letters = arg.slice(1, -1).split('') broken = false - unmatched = [] + let unmatched = [] for (var j = 0; j < letters.length; j++) { next = arg.slice(j + 2) @@ -254,9 +254,9 @@ function parse (args, opts) { } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { setArg(key, value) } else { - unmatched.push(key); - unmatched.push('='); - unmatched.push(value); + unmatched.push(key) + unmatched.push('=') + unmatched.push(value) } broken = true @@ -267,8 +267,8 @@ function parse (args, opts) { if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { setArg(letters[j], next) } else { - unmatched.push(letters[j]); - unmatched.push(next); + unmatched.push(letters[j]) + unmatched.push(next) } continue } @@ -279,8 +279,8 @@ function parse (args, opts) { if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { setArg(letters[j], next) } else { - unmatched.push(letters[j]); - unmatched.push(next); + unmatched.push(letters[j]) + unmatched.push(next) } broken = true break @@ -290,8 +290,8 @@ function parse (args, opts) { if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { setArg(letters[j], next) } else { - unmatched.push(letters[j]); - unmatched.push(next); + unmatched.push(letters[j]) + unmatched.push(next) } broken = true break @@ -328,7 +328,7 @@ function parse (args, opts) { setArg(key, defaultValue(key)) } } else { - unmatched.push(key); + unmatched.push(key) } } if (unmatched.length > 0) { @@ -800,7 +800,7 @@ function parse (args, opts) { return isSet } - + function hasAnyFlag (key) { var isSet = false var toCheck = [].concat(Object.values(flags)) diff --git a/test/yargs-parser.js b/test/yargs-parser.js index 84cb7248..a7261712 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -3146,7 +3146,7 @@ describe('yargs-parser', function () { }) argv.should.deep.equal({ _: ['-u=2'], - 'k': 1 + 'k': 1 }) }) it('should ignore unknown options in short format followed by hyphen', function () { @@ -3158,7 +3158,7 @@ describe('yargs-parser', function () { }) argv.should.deep.equal({ _: ['-u-'], - 'k': '-' + 'k': '-' }) }) it('should ignore unknown options in short format separated by space', function () { @@ -3170,7 +3170,7 @@ describe('yargs-parser', function () { }) argv.should.deep.equal({ _: ['-u', 2], - 'k': 1 + 'k': 1 }) }) it('should ignore unknown options in short format followed by a number', function () { @@ -3182,7 +3182,7 @@ describe('yargs-parser', function () { }) argv.should.deep.equal({ _: ['-u2'], - 'k': 1 + 'k': 1 }) }) it('should ignore unknown options in short format followed by a non-word character', function () { @@ -3194,7 +3194,7 @@ describe('yargs-parser', function () { }) argv.should.deep.equal({ _: ['-u/2/'], - 'k': '/1/' + 'k': '/1/' }) }) }) @@ -3207,7 +3207,7 @@ describe('yargs-parser', function () { }) argv.should.deep.equal({ _: ['-u'], - 'k': true, + 'k': true, 'v': true }) it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is at the end', function () { @@ -3219,7 +3219,7 @@ describe('yargs-parser', function () { }) argv.should.deep.equal({ _: ['-u'], - 'k': true, + 'k': true, 'v': true }) }) From a49e4b971da2737fa4c03ddae424360e1a4261f3 Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Fri, 14 Jun 2019 10:29:56 -0400 Subject: [PATCH 03/10] don't coerce number, change to "parse-unknown-options: false", fix node 6 support --- index.js | 39 ++++++++++++++++++++------------------- test/yargs-parser.js | 26 +++++++++++++------------- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/index.js b/index.js index 2e810bd7..3dcc2b3f 100644 --- a/index.js +++ b/index.js @@ -27,7 +27,7 @@ function parse (args, opts) { 'halt-at-non-option': false, 'strip-aliased': false, 'strip-dashed': false, - 'ignore-unknown-options': false + 'parse-unknown-options': true }, opts.configuration) var defaults = opts.default || {} var configObjects = opts.configObjects || [] @@ -160,17 +160,17 @@ function parse (args, opts) { } else if (checkAllAliases(m[1], flags.arrays)) { args.splice(i + 1, 0, m[2]) i = eatArray(i, m[1], args) - } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(m[1])) { + } else if (configuration['parse-unknown-options'] || hasAnyFlag(m[1])) { setArg(m[1], m[2]) } else { - argv._.push(maybeCoerceNumber('_', arg)) + argv._.push(arg) } } else if (arg.match(negatedBoolean) && configuration['boolean-negation']) { key = arg.match(negatedBoolean)[1] - if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { + if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { setArg(key, checkAllAliases(key, flags.arrays) ? [false] : false) } else { - argv._.push(maybeCoerceNumber('_', arg)) + argv._.push(arg) } // -- separated by space. @@ -186,7 +186,7 @@ function parse (args, opts) { // array format = '--foo a b c' } else if (checkAllAliases(key, flags.arrays)) { i = eatArray(i, key, args) - } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { + } else if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { next = args[i + 1] if (next !== undefined && (!next.match(/^-/) || @@ -202,16 +202,16 @@ function parse (args, opts) { setArg(key, defaultValue(key)) } } else { - argv._.push(maybeCoerceNumber('_', arg)) + argv._.push(arg) } // dot-notation flag separated by '='. } else if (arg.match(/^-.\..+=/)) { m = arg.match(/^-([^=]+)=([\s\S]*)$/) - if (!configuration['ignore-unknown-options'] || hasAnyFlag(m[1])) { + if (configuration['parse-unknown-options'] || hasAnyFlag(m[1])) { setArg(m[1], m[2]) } else { - argv._.push(maybeCoerceNumber('_', arg)) + argv._.push(arg) } // dot-notation flag separated by space. @@ -219,7 +219,7 @@ function parse (args, opts) { next = args[i + 1] key = arg.match(/^-(.\..+)/)[1] - if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { + if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { if (next !== undefined && !next.match(/^-/) && !checkAllAliases(key, flags.bools) && !checkAllAliases(key, flags.counts)) { @@ -229,7 +229,7 @@ function parse (args, opts) { setArg(key, defaultValue(key)) } } else { - argv._.push(maybeCoerceNumber('_', arg)) + argv._.push(arg) } } else if (arg.match(/^-[^-]+/) && !arg.match(negative)) { letters = arg.slice(1, -1).split('') @@ -251,7 +251,7 @@ function parse (args, opts) { } else if (checkAllAliases(key, flags.arrays)) { args.splice(i + 1, 0, value) i = eatArray(i, key, args) - } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { + } else if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { setArg(key, value) } else { unmatched.push(key) @@ -264,7 +264,7 @@ function parse (args, opts) { } if (next === '-') { - if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { + if (configuration['parse-unknown-options'] || hasAnyFlag(letters[j])) { setArg(letters[j], next) } else { unmatched.push(letters[j]) @@ -276,7 +276,7 @@ function parse (args, opts) { // current letter is an alphabetic character and next value is a number if (/[A-Za-z]/.test(letters[j]) && /^-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { - if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { + if (configuration['parse-unknown-options'] || hasAnyFlag(letters[j])) { setArg(letters[j], next) } else { unmatched.push(letters[j]) @@ -287,7 +287,7 @@ function parse (args, opts) { } if (letters[j + 1] && letters[j + 1].match(/\W/)) { - if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { + if (configuration['parse-unknown-options'] || hasAnyFlag(letters[j])) { setArg(letters[j], next) } else { unmatched.push(letters[j]) @@ -295,7 +295,7 @@ function parse (args, opts) { } broken = true break - } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(letters[j])) { + } else if (configuration['parse-unknown-options'] || hasAnyFlag(letters[j])) { setArg(letters[j], defaultValue(letters[j])) } else { unmatched.push(letters[j]) @@ -312,7 +312,7 @@ function parse (args, opts) { // array format = '-f a b c' } else if (checkAllAliases(key, flags.arrays)) { i = eatArray(i, key, args) - } else if (!configuration['ignore-unknown-options'] || hasAnyFlag(key)) { + } else if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { next = args[i + 1] if (next !== undefined && (!/^(-|--)[^-]/.test(next) || @@ -332,7 +332,7 @@ function parse (args, opts) { } } if (unmatched.length > 0) { - argv._.push(maybeCoerceNumber('_', ['-', ...unmatched].join(''))) + argv._.push(['-', ...unmatched].join('')) } } else if (arg === '--') { notFlags = args.slice(i + 1) @@ -803,7 +803,8 @@ function parse (args, opts) { function hasAnyFlag (key) { var isSet = false - var toCheck = [].concat(Object.values(flags)) + // XXX Switch to [].concat(...Object.values(flags)) once node.js 6 is dropped + var toCheck = [].concat(...Object.keys(flags).map(k => flags[k])) toCheck.forEach(function (flag) { if (flag[key]) isSet = flag[key] diff --git a/test/yargs-parser.js b/test/yargs-parser.js index a7261712..fe9901bd 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -3069,12 +3069,12 @@ describe('yargs-parser', function () { }) }) }) - describe('ignore-unknown-options', function () { + describe('parse-unknown-options = false', function () { it('should ignore unknown options in long format separated by =', function () { const argv = parser('--known-arg=1 --unknown-arg=2', { number: ['known-arg'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3087,7 +3087,7 @@ describe('yargs-parser', function () { const argv = parser('--no-known-arg --no-unknown-arg', { boolean: ['known-arg'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3100,7 +3100,7 @@ describe('yargs-parser', function () { const argv = parser('--known-arg 1 --unknown-arg 2', { number: ['known-arg'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3113,7 +3113,7 @@ describe('yargs-parser', function () { const argv = parser('-k.arg=1 -u.arg=2', { number: ['k.arg'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3127,7 +3127,7 @@ describe('yargs-parser', function () { const argv = parser('-k.arg 1 -u.arg 2', { number: ['k.arg'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3141,7 +3141,7 @@ describe('yargs-parser', function () { const argv = parser('-k=1 -u=2', { number: ['k'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3153,7 +3153,7 @@ describe('yargs-parser', function () { const argv = parser('-k- -u-', { string: ['k'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3165,7 +3165,7 @@ describe('yargs-parser', function () { const argv = parser('-k 1 -u 2', { number: ['k'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3177,7 +3177,7 @@ describe('yargs-parser', function () { const argv = parser('-k1 -u2', { number: ['k'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3189,7 +3189,7 @@ describe('yargs-parser', function () { const argv = parser('-k/1/ -u/2/', { string: ['k'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3202,7 +3202,7 @@ describe('yargs-parser', function () { const argv = parser('-kuv', { boolean: ['k', 'v'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ @@ -3214,7 +3214,7 @@ describe('yargs-parser', function () { const argv = parser('-kvu', { boolean: ['k', 'v'], configuration: { - 'ignore-unknown-options': true + 'parse-unknown-options': false } }) argv.should.deep.equal({ From 487c62ee498844b89ff71ae75ea3d0b5d23c1d07 Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Wed, 26 Jun 2019 12:41:56 -0400 Subject: [PATCH 04/10] re-arrange tests --- test/yargs-parser.js | 417 ++++++++++++++++++++++--------------------- 1 file changed, 209 insertions(+), 208 deletions(-) diff --git a/test/yargs-parser.js b/test/yargs-parser.js index fe9901bd..beced79a 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -9,7 +9,7 @@ var path = require('path') describe('yargs-parser', function () { it('should parse a "short boolean"', function () { - var parse = parser([ '-b' ]) + var parse = parser(['-b']) parse.should.not.have.property('--') parse.should.have.property('b').to.be.ok.and.be.a('boolean') parse.should.have.property('_').with.length(0) @@ -166,7 +166,7 @@ describe('yargs-parser', function () { }) it('should not set the next value as the value of a short option if that option is explicitly defined as a boolean', function () { - var parse = parser([ '-t', 'moo' ], { + var parse = parser(['-t', 'moo'], { boolean: 't' }) parse.should.have.property('t', true).and.be.a('boolean') @@ -208,7 +208,7 @@ describe('yargs-parser', function () { }) it('should allow defining options as boolean in groups', function () { - var parse = parser([ '-x', '-z', 'one', 'two', 'three' ], { + var parse = parser(['-x', '-z', 'one', 'two', 'three'], { boolean: ['x', 'y', 'z'] }) parse.should.have.property('x', true).and.be.a('boolean') @@ -243,25 +243,25 @@ describe('yargs-parser', function () { }) it('should not convert numbers to type number if explicitly defined as strings', function () { - var s = parser([ '-s', '0001234' ], { + var s = parser(['-s', '0001234'], { string: 's' }).s s.should.be.a('string').and.equal('0001234') - var x = parser([ '-x', '56' ], { + var x = parser(['-x', '56'], { string: ['x'] }).x x.should.be.a('string').and.equal('56') }) it('should default numbers to undefined', function () { - var n = parser([ '-n' ], { + var n = parser(['-n'], { number: ['n'] }).n expect(n).to.equal(undefined) }) it('should default number to NaN if value is not a valid number', function () { - var n = parser([ '-n', 'string' ], { + var n = parser(['-n', 'string'], { number: ['n'] }).n expect(n).to.deep.equal(NaN) @@ -269,24 +269,24 @@ describe('yargs-parser', function () { // Fixes: https://github.com/bcoe/yargs/issues/68 it('should parse flag arguments with no right-hand value as strings, if defined as strings', function () { - var s = parser([ '-s' ], { + var s = parser(['-s'], { string: ['s'] }).s s.should.be.a('string').and.equal('') - s = parser([ '-sf' ], { + s = parser(['-sf'], { string: ['s'] }).s s.should.be.a('string').and.equal('') - s = parser([ '--string' ], { + s = parser(['--string'], { string: ['string'] }).string s.should.be.a('string').and.equal('') }) it('should leave all non-hyphenated values as strings if _ is defined as a string', function () { - var s = parser([ ' ', ' ' ], { + var s = parser([' ', ' '], { string: ['_'] })._ s.should.have.length(2) @@ -296,7 +296,7 @@ describe('yargs-parser', function () { describe('normalize', function () { it('should normalize redundant paths', function () { - var a = parser([ '-s', ['', 'tmp', '..', ''].join(path.sep) ], { + var a = parser(['-s', ['', 'tmp', '..', ''].join(path.sep)], { alias: { s: ['save'] }, @@ -316,7 +316,7 @@ describe('yargs-parser', function () { }) it('should normalize when key is also an array', function () { - var a = parser([ '-s', ['', 'tmp', '..', ''].join(path.sep), ['', 'path', 'to', 'new', 'dir', '..', '..', ''].join(path.sep) ], { + var a = parser(['-s', ['', 'tmp', '..', ''].join(path.sep), ['', 'path', 'to', 'new', 'dir', '..', '..', ''].join(path.sep)], { alias: { s: ['save'] }, @@ -331,7 +331,7 @@ describe('yargs-parser', function () { describe('alias', function () { it('should set alias value to the same value as the full option', function () { - var argv = parser([ '-f', '11', '--zoom', '55' ], { + var argv = parser(['-f', '11', '--zoom', '55'], { alias: { z: ['zoom'] } @@ -342,7 +342,7 @@ describe('yargs-parser', function () { }) it('should allow multiple aliases to be specified', function () { - var argv = parser([ '-f', '11', '--zoom', '55' ], { + var argv = parser(['-f', '11', '--zoom', '55'], { alias: { z: ['zm', 'zoom'] } @@ -385,7 +385,7 @@ describe('yargs-parser', function () { }) it('should allow transitive aliases to be specified', function () { - var argv = parser([ '-f', '11', '--zoom', '55' ], { + var argv = parser(['-f', '11', '--zoom', '55'], { alias: { z: 'zm', zm: 'zoom' @@ -431,7 +431,7 @@ describe('yargs-parser', function () { // See: https://github.com/chevex/yargs/issues/12 it('should load options and values from default config if specified', function () { - var argv = parser([ '--foo', 'bar' ], { + var argv = parser(['--foo', 'bar'], { alias: { z: 'zoom' }, @@ -520,7 +520,7 @@ describe('yargs-parser', function () { }) it("should allow config to be set as flag in 'option'", function () { - var argv = parser([ '--settings', jsonPath, '--foo', 'bar' ], { + var argv = parser(['--settings', jsonPath, '--foo', 'bar'], { alias: { z: 'zoom' }, @@ -534,7 +534,7 @@ describe('yargs-parser', function () { it('should load options and values from a JS file when config has .js extention', function () { var jsPath = path.resolve(__dirname, './fixtures/settings.js') - var argv = parser([ '--settings', jsPath, '--foo', 'bar' ], { + var argv = parser(['--settings', jsPath, '--foo', 'bar'], { config: ['settings'] }) @@ -599,7 +599,7 @@ describe('yargs-parser', function () { it('allows a custom parsing function to be provided', function () { var jsPath = path.resolve(__dirname, './fixtures/config.txt') - var argv = parser([ '--settings', jsPath, '--foo', 'bar' ], { + var argv = parser(['--settings', jsPath, '--foo', 'bar'], { config: { settings: function (configPath) { // as an example, parse an environment @@ -624,7 +624,7 @@ describe('yargs-parser', function () { it('allows a custom parsing function to be provided as an alias', function () { var jsPath = path.resolve(__dirname, './fixtures/config.json') - var argv = parser([ '--settings', jsPath, '--foo', 'bar' ], { + var argv = parser(['--settings', jsPath, '--foo', 'bar'], { config: { s: function (configPath) { return JSON.parse(fs.readFileSync(configPath, 'utf-8')) @@ -666,7 +666,7 @@ describe('yargs-parser', function () { describe('config objects', function () { it('should load options from config object', function () { - var argv = parser([ '--foo', 'bar' ], { + var argv = parser(['--foo', 'bar'], { configObjects: [{ apple: 'apple', banana: 42, @@ -855,7 +855,7 @@ describe('yargs-parser', function () { } }) - ;('foo.bar' in argv).should.equal(false) + ; ('foo.bar' in argv).should.equal(false) }) it('should respect .string() for dot notation arguments', function () { @@ -912,7 +912,7 @@ describe('yargs-parser', function () { }) it('should set boolean and alias using explicit true', function () { - var aliased = [ '-h', 'true' ] + var aliased = ['-h', 'true'] var aliasedArgv = parser(aliased, { boolean: ['h'], alias: { @@ -978,12 +978,12 @@ describe('yargs-parser', function () { }) it('should set n to the numeric value 123', function () { - var argv = parser([ '-n123' ]) + var argv = parser(['-n123']) argv.should.have.property('n', 123) }) it('should set n to the numeric value 123, with n at the end of a group', function () { - var argv = parser([ '-ab5n123' ]) + var argv = parser(['-ab5n123']) argv.should.have.property('a', true) argv.should.have.property('b', true) argv.should.have.property('5', true) @@ -992,12 +992,12 @@ describe('yargs-parser', function () { }) it('should set n to the numeric value 123, with = as separator', function () { - var argv = parser([ '-n=123' ]) + var argv = parser(['-n=123']) argv.should.have.property('n', 123) }) it('should set n to the numeric value 123, with n at the end of a group and = as separator', function () { - var argv = parser([ '-ab5n=123' ]) + var argv = parser(['-ab5n=123']) argv.should.have.property('a', true) argv.should.have.property('b', true) argv.should.have.property('5', true) @@ -1008,7 +1008,7 @@ describe('yargs-parser', function () { describe('whitespace', function () { it('should be whitespace', function () { - var argv = parser([ '-x', '\t' ]) + var argv = parser(['-x', '\t']) argv.should.have.property('x', '\t') }) }) @@ -1049,7 +1049,7 @@ describe('yargs-parser', function () { function checkStringArg (opts, hasAlias) { it('should set defaults even if arg looks like a string', function () { - var result = parser([ '--flag', 'extra' ], opts) + var result = parser(['--flag', 'extra'], opts) result.should.have.property('flag', true) result.should.have.property('_').and.deep.equal(['extra']) if (hasAlias) { @@ -1215,7 +1215,7 @@ describe('yargs-parser', function () { } it('should provide count options with dashes as camelCase properties', function () { - var result = parser([ '--some-option', '--some-option', '--some-option' ], { + var result = parser(['--some-option', '--some-option', '--some-option'], { count: ['some-option'] }) @@ -1352,7 +1352,7 @@ describe('yargs-parser', function () { }) it('should set - as the value of s when s is set as a string', function () { - var argv = parser([ '-s', '-' ], { + var argv = parser(['-s', '-'], { string: ['s'] }) @@ -1406,13 +1406,13 @@ describe('yargs-parser', function () { }) it('should not consume the next argument', function () { - var parsed = parser([ '-v', 'moo' ], { + var parsed = parser(['-v', 'moo'], { count: 'v' }) parsed.v.should.equal(1) parsed.should.have.property('_').and.deep.equal(['moo']) - parsed = parser([ '--verbose', 'moomoo', '--verbose' ], { + parsed = parser(['--verbose', 'moomoo', '--verbose'], { count: 'verbose' }) parsed.verbose.should.equal(2) @@ -1709,7 +1709,7 @@ describe('yargs-parser', function () { describe('nargs', function () { it('should allow the number of arguments following a key to be specified', function () { - var result = parser([ '--foo', 'apple', 'bar' ], { + var result = parser(['--foo', 'apple', 'bar'], { narg: { foo: 2 } @@ -1744,7 +1744,7 @@ describe('yargs-parser', function () { }) it('should apply nargs to flag arguments', function () { - var result = parser([ '-f', 'apple', 'bar', 'blerg' ], { + var result = parser(['-f', 'apple', 'bar', 'blerg'], { narg: { f: 2 } @@ -1793,7 +1793,7 @@ describe('yargs-parser', function () { }) it('allows multiple nargs to be set at the same time', function () { - var result = parser([ '--foo', 'apple', 'bar', '--bar', 'banana', '-f' ], { + var result = parser(['--foo', 'apple', 'bar', '--bar', 'banana', '-f'], { narg: { foo: 2, bar: 1 @@ -2689,6 +2689,162 @@ describe('yargs-parser', function () { }) }) }) + + describe('parse-unknown-options = false', function () { + it('should ignore unknown options in long format separated by =', function () { + const argv = parser('--known-arg=1 --unknown-arg=2', { + number: ['known-arg'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['--unknown-arg=2'], + 'known-arg': 1, + 'knownArg': 1 + }) + }) + it('should ignore unknown options in boolean negations', function () { + const argv = parser('--no-known-arg --no-unknown-arg', { + boolean: ['known-arg'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['--no-unknown-arg'], + 'known-arg': false, + 'knownArg': false + }) + }) + it('should ignore unknown options in long format separated by space', function () { + const argv = parser('--known-arg 1 --unknown-arg 2', { + number: ['known-arg'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['--unknown-arg', 2], + 'known-arg': 1, + 'knownArg': 1 + }) + }) + it('should ignore unknown options in short dot format separated by equals', function () { + const argv = parser('-k.arg=1 -u.arg=2', { + number: ['k.arg'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['-u.arg=2'], + 'k': { + 'arg': 1 + } + }) + }) + it('should ignore unknown options in short dot format separated by space', function () { + const argv = parser('-k.arg 1 -u.arg 2', { + number: ['k.arg'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['-u.arg', 2], + 'k': { + 'arg': 1 + } + }) + }) + it('should ignore unknown options in short format separated by equals', function () { + const argv = parser('-k=1 -u=2', { + number: ['k'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['-u=2'], + 'k': 1 + }) + }) + it('should ignore unknown options in short format followed by hyphen', function () { + const argv = parser('-k- -u-', { + string: ['k'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['-u-'], + 'k': '-' + }) + }) + it('should ignore unknown options in short format separated by space', function () { + const argv = parser('-k 1 -u 2', { + number: ['k'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['-u', 2], + 'k': 1 + }) + }) + it('should ignore unknown options in short format followed by a number', function () { + const argv = parser('-k1 -u2', { + number: ['k'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['-u2'], + 'k': 1 + }) + }) + it('should ignore unknown options in short format followed by a non-word character', function () { + const argv = parser('-k/1/ -u/2/', { + string: ['k'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['-u/2/'], + 'k': '/1/' + }) + }) + it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is before the end', function () { + const argv = parser('-kuv', { + boolean: ['k', 'v'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['-u'], + 'k': true, + 'v': true + }) + it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is at the end', function () { + const argv = parser('-kvu', { + boolean: ['k', 'v'], + configuration: { + 'parse-unknown-options': false + } + }) + argv.should.deep.equal({ + _: ['-u'], + 'k': true, + 'v': true + }) + }) + }) + }) }) // addresses: https://github.com/yargs/yargs-parser/issues/41 @@ -2832,9 +2988,9 @@ describe('yargs-parser', function () { bar: fancyNumberParser } }) - ;(typeof parsed.foo).should.equal('string') + ; (typeof parsed.foo).should.equal('string') parsed.foo.should.equal('88888889999990000998989898989898') - ;(typeof parsed.bar).should.equal('number') + ; (typeof parsed.bar).should.equal('number') parsed.bar.should.equal(998) }) @@ -2868,7 +3024,7 @@ describe('yargs-parser', function () { runcount++ return undefined } - parser([ '--foo', 'bar' ], { + parser(['--foo', 'bar'], { alias: { foo: ['f', 'foo-bar', 'bar'], b: ['bar'] @@ -2883,7 +3039,7 @@ describe('yargs-parser', function () { // see: https://github.com/yargs/yargs-parser/issues/37 it('normalizes all paths in array when provided via config object', function () { - var argv = parser([ '--foo', 'bar' ], { + var argv = parser(['--foo', 'bar'], { array: ['a'], normalize: ['a'], configObjects: [{ 'a': ['bin/../a.txt', 'bin/../b.txt'] }] @@ -2893,17 +3049,17 @@ describe('yargs-parser', function () { // see: https://github.com/yargs/yargs/issues/963 it('does not magically convert numeric strings larger than Number.MAX_SAFE_INTEGER', () => { - const argv = parser([ '--foo', '93940495950949399948393' ]) + const argv = parser(['--foo', '93940495950949399948393']) argv.foo.should.equal('93940495950949399948393') }) it('does not magically convert scientific notation larger than Number.MAX_SAFE_INTEGER', () => { - const argv = parser([ '--foo', '33e99999' ]) + const argv = parser(['--foo', '33e99999']) argv.foo.should.equal('33e99999') }) it('converts numeric options larger than Number.MAX_SAFE_INTEGER to number', () => { - const argv = parser([ '--foo', '93940495950949399948393' ], { + const argv = parser(['--foo', '93940495950949399948393'], { number: ['foo'] }) argv.foo.should.equal(9.39404959509494e+22) @@ -2930,21 +3086,21 @@ describe('yargs-parser', function () { // see: https://github.com/yargs/yargs-parser/issues/101 describe('dot-notation array arguments combined with string arguments', function () { it('parses correctly when dot-notation argument is first', function () { - var argv = parser([ '--foo.bar', 'baz', '--foo', 'bux' ]) + var argv = parser(['--foo.bar', 'baz', '--foo', 'bux']) Array.isArray(argv.foo).should.equal(true) argv.foo[0].bar.should.equal('baz') argv.foo[1].should.equal('bux') }) it('parses correctly when dot-notation argument is last', function () { - var argv = parser([ '--foo', 'bux', '--foo.bar', 'baz' ]) + var argv = parser(['--foo', 'bux', '--foo.bar', 'baz']) Array.isArray(argv.foo).should.equal(true) argv.foo[0].should.equal('bux') argv.foo[1].bar.should.equal('baz') }) it('parses correctly when there are multiple dot-notation arguments', function () { - var argv = parser([ '--foo.first', 'firstvalue', '--foo', 'bux', '--foo.bar', 'baz', '--foo.bla', 'banana' ]) + var argv = parser(['--foo.first', 'firstvalue', '--foo', 'bux', '--foo.bar', 'baz', '--foo.bla', 'banana']) Array.isArray(argv.foo).should.equal(true) argv.foo.length.should.equal(4) argv.foo[0].first.should.equal('firstvalue') @@ -2983,7 +3139,7 @@ describe('yargs-parser', function () { // see: https://github.com/yargs/yargs-parser/issues/144 it('number/string types should use default when no right-hand value', () => { - let argv = parser([ '--foo' ], { + let argv = parser(['--foo'], { number: ['foo'], default: { foo: 99 @@ -2991,7 +3147,7 @@ describe('yargs-parser', function () { }) argv.foo.should.equal(99) - argv = parser([ '-b' ], { + argv = parser(['-b'], { alias: { bar: 'b' }, @@ -3005,7 +3161,7 @@ describe('yargs-parser', function () { describe('stripping', function () { it('strip-dashed removes expected fields from argv', function () { - const argv = parser([ '--test-value', '1' ], { + const argv = parser(['--test-value', '1'], { number: ['test-value'], alias: { 'test-value': ['alt-test'] @@ -3022,7 +3178,7 @@ describe('yargs-parser', function () { }) it('strip-aliased removes expected fields from argv', function () { - const argv = parser([ '--test-value', '1' ], { + const argv = parser(['--test-value', '1'], { number: ['test-value'], alias: { 'test-value': ['alt-test'] @@ -3039,7 +3195,7 @@ describe('yargs-parser', function () { }) it('strip-aliased and strip-dashed combined removes expected fields from argv', function () { - const argv = parser([ '--test-value', '1' ], { + const argv = parser(['--test-value', '1'], { number: ['test-value'], alias: { 'test-value': ['alt-test'] @@ -3056,7 +3212,7 @@ describe('yargs-parser', function () { }) it('ignores strip-dashed if camel-case-expansion is disabled', function () { - const argv = parser([ '--test-value', '1' ], { + const argv = parser(['--test-value', '1'], { number: ['test-value'], configuration: { 'camel-case-expansion': false, @@ -3069,159 +3225,4 @@ describe('yargs-parser', function () { }) }) }) - describe('parse-unknown-options = false', function () { - it('should ignore unknown options in long format separated by =', function () { - const argv = parser('--known-arg=1 --unknown-arg=2', { - number: ['known-arg'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['--unknown-arg=2'], - 'known-arg': 1, - 'knownArg': 1 - }) - }) - it('should ignore unknown options in boolean negations', function () { - const argv = parser('--no-known-arg --no-unknown-arg', { - boolean: ['known-arg'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['--no-unknown-arg'], - 'known-arg': false, - 'knownArg': false - }) - }) - it('should ignore unknown options in long format separated by space', function () { - const argv = parser('--known-arg 1 --unknown-arg 2', { - number: ['known-arg'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['--unknown-arg', 2], - 'known-arg': 1, - 'knownArg': 1 - }) - }) - it('should ignore unknown options in short dot format separated by equals', function () { - const argv = parser('-k.arg=1 -u.arg=2', { - number: ['k.arg'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u.arg=2'], - 'k': { - 'arg': 1 - } - }) - }) - it('should ignore unknown options in short dot format separated by space', function () { - const argv = parser('-k.arg 1 -u.arg 2', { - number: ['k.arg'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u.arg', 2], - 'k': { - 'arg': 1 - } - }) - }) - it('should ignore unknown options in short format separated by equals', function () { - const argv = parser('-k=1 -u=2', { - number: ['k'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u=2'], - 'k': 1 - }) - }) - it('should ignore unknown options in short format followed by hyphen', function () { - const argv = parser('-k- -u-', { - string: ['k'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u-'], - 'k': '-' - }) - }) - it('should ignore unknown options in short format separated by space', function () { - const argv = parser('-k 1 -u 2', { - number: ['k'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u', 2], - 'k': 1 - }) - }) - it('should ignore unknown options in short format followed by a number', function () { - const argv = parser('-k1 -u2', { - number: ['k'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u2'], - 'k': 1 - }) - }) - it('should ignore unknown options in short format followed by a non-word character', function () { - const argv = parser('-k/1/ -u/2/', { - string: ['k'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u/2/'], - 'k': '/1/' - }) - }) - }) - it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is before the end', function () { - const argv = parser('-kuv', { - boolean: ['k', 'v'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u'], - 'k': true, - 'v': true - }) - it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is at the end', function () { - const argv = parser('-kvu', { - boolean: ['k', 'v'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u'], - 'k': true, - 'v': true - }) - }) - }) }) From a6a820a8d418e77382a00719e219e258be876f39 Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Wed, 26 Jun 2019 13:05:52 -0400 Subject: [PATCH 05/10] test more than just numeric and boolean arguments --- test/yargs-parser.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/yargs-parser.js b/test/yargs-parser.js index beced79a..4a7fce0a 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -2718,29 +2718,29 @@ describe('yargs-parser', function () { }) }) it('should ignore unknown options in long format separated by space', function () { - const argv = parser('--known-arg 1 --unknown-arg 2', { - number: ['known-arg'], + const argv = parser('--known-arg a --unknown-arg b', { + string: ['known-arg'], configuration: { 'parse-unknown-options': false } }) argv.should.deep.equal({ - _: ['--unknown-arg', 2], - 'known-arg': 1, - 'knownArg': 1 + _: ['--unknown-arg', 'b'], + 'known-arg': 'a', + 'knownArg': 'a' }) }) it('should ignore unknown options in short dot format separated by equals', function () { - const argv = parser('-k.arg=1 -u.arg=2', { - number: ['k.arg'], + const argv = parser('-k.arg=a -u.arg=b', { + string: ['k.arg'], configuration: { 'parse-unknown-options': false } }) argv.should.deep.equal({ - _: ['-u.arg=2'], + _: ['-u.arg=b'], 'k': { - 'arg': 1 + 'arg': 'a' } }) }) @@ -2759,15 +2759,15 @@ describe('yargs-parser', function () { }) }) it('should ignore unknown options in short format separated by equals', function () { - const argv = parser('-k=1 -u=2', { - number: ['k'], + const argv = parser('-k=a -u=b', { + string: ['k'], configuration: { 'parse-unknown-options': false } }) argv.should.deep.equal({ - _: ['-u=2'], - 'k': 1 + _: ['-u=b'], + 'k': 'a' }) }) it('should ignore unknown options in short format followed by hyphen', function () { From d5641ac87fcd60640f94a0113a76a116ed3c6cdd Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Mon, 5 Aug 2019 13:44:59 -0400 Subject: [PATCH 06/10] implement code review feedback --- index.js | 89 ++++++++++++++++---------------------------- test/yargs-parser.js | 56 +++++++++++++--------------- 2 files changed, 58 insertions(+), 87 deletions(-) diff --git a/index.js b/index.js index 3dcc2b3f..43f21b5a 100644 --- a/index.js +++ b/index.js @@ -27,7 +27,7 @@ function parse (args, opts) { 'halt-at-non-option': false, 'strip-aliased': false, 'strip-dashed': false, - 'parse-unknown-options': true + 'collect-unknown-options': false }, opts.configuration) var defaults = opts.default || {} var configObjects = opts.configObjects || [] @@ -143,8 +143,10 @@ function parse (args, opts) { var next var value + if (configuration['collect-unknown-options'] && !checkFlags(arg, /^-+([^=]+?)=[\s\S]*$/, /^-+no-([^=]+?)=[\s\S]*$/, /^-+([^=]+?)$/, /^-+no-([^=]+?)$/, /^-+([^=]+?)-$/, /^-+([^=]+?)\d+$/, /^-+([^=]+?)\W+.*$/)) { + argv._.push(arg) // -- separated by = - if (arg.match(/^--.+=/) || ( + } else if (arg.match(/^--.+=/) || ( !configuration['short-option-groups'] && arg.match(/^-.+=/) )) { // Using [\s\S] instead of . because js doesn't support the @@ -160,18 +162,12 @@ function parse (args, opts) { } else if (checkAllAliases(m[1], flags.arrays)) { args.splice(i + 1, 0, m[2]) i = eatArray(i, m[1], args) - } else if (configuration['parse-unknown-options'] || hasAnyFlag(m[1])) { - setArg(m[1], m[2]) } else { - argv._.push(arg) + setArg(m[1], m[2]) } } else if (arg.match(negatedBoolean) && configuration['boolean-negation']) { key = arg.match(negatedBoolean)[1] - if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { - setArg(key, checkAllAliases(key, flags.arrays) ? [false] : false) - } else { - argv._.push(arg) - } + setArg(key, checkAllAliases(key, flags.arrays) ? [false] : false) // -- separated by space. } else if (arg.match(/^--.+/) || ( @@ -186,7 +182,7 @@ function parse (args, opts) { // array format = '--foo a b c' } else if (checkAllAliases(key, flags.arrays)) { i = eatArray(i, key, args) - } else if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { + } else { next = args[i + 1] if (next !== undefined && (!next.match(/^-/) || @@ -201,35 +197,25 @@ function parse (args, opts) { } else { setArg(key, defaultValue(key)) } - } else { - argv._.push(arg) } // dot-notation flag separated by '='. } else if (arg.match(/^-.\..+=/)) { m = arg.match(/^-([^=]+)=([\s\S]*)$/) - if (configuration['parse-unknown-options'] || hasAnyFlag(m[1])) { - setArg(m[1], m[2]) - } else { - argv._.push(arg) - } + setArg(m[1], m[2]) // dot-notation flag separated by space. } else if (arg.match(/^-.\..+/)) { next = args[i + 1] key = arg.match(/^-(.\..+)/)[1] - if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { - if (next !== undefined && !next.match(/^-/) && - !checkAllAliases(key, flags.bools) && - !checkAllAliases(key, flags.counts)) { - setArg(key, next) - i++ - } else { - setArg(key, defaultValue(key)) - } + if (next !== undefined && !next.match(/^-/) && + !checkAllAliases(key, flags.bools) && + !checkAllAliases(key, flags.counts)) { + setArg(key, next) + i++ } else { - argv._.push(arg) + setArg(key, defaultValue(key)) } } else if (arg.match(/^-[^-]+/) && !arg.match(negative)) { letters = arg.slice(1, -1).split('') @@ -251,12 +237,8 @@ function parse (args, opts) { } else if (checkAllAliases(key, flags.arrays)) { args.splice(i + 1, 0, value) i = eatArray(i, key, args) - } else if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { - setArg(key, value) } else { - unmatched.push(key) - unmatched.push('=') - unmatched.push(value) + setArg(key, value) } broken = true @@ -264,41 +246,24 @@ function parse (args, opts) { } if (next === '-') { - if (configuration['parse-unknown-options'] || hasAnyFlag(letters[j])) { - setArg(letters[j], next) - } else { - unmatched.push(letters[j]) - unmatched.push(next) - } + setArg(letters[j], next) continue } // current letter is an alphabetic character and next value is a number if (/[A-Za-z]/.test(letters[j]) && /^-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { - if (configuration['parse-unknown-options'] || hasAnyFlag(letters[j])) { - setArg(letters[j], next) - } else { - unmatched.push(letters[j]) - unmatched.push(next) - } + setArg(letters[j], next) broken = true break } if (letters[j + 1] && letters[j + 1].match(/\W/)) { - if (configuration['parse-unknown-options'] || hasAnyFlag(letters[j])) { - setArg(letters[j], next) - } else { - unmatched.push(letters[j]) - unmatched.push(next) - } + setArg(letters[j], next) broken = true break - } else if (configuration['parse-unknown-options'] || hasAnyFlag(letters[j])) { - setArg(letters[j], defaultValue(letters[j])) } else { - unmatched.push(letters[j]) + setArg(letters[j], defaultValue(letters[j])) } } @@ -312,7 +277,7 @@ function parse (args, opts) { // array format = '-f a b c' } else if (checkAllAliases(key, flags.arrays)) { i = eatArray(i, key, args) - } else if (configuration['parse-unknown-options'] || hasAnyFlag(key)) { + } else { next = args[i + 1] if (next !== undefined && (!/^(-|--)[^-]/.test(next) || @@ -327,8 +292,6 @@ function parse (args, opts) { } else { setArg(key, defaultValue(key)) } - } else { - unmatched.push(key) } } if (unmatched.length > 0) { @@ -813,6 +776,18 @@ function parse (args, opts) { return isSet } + function checkFlags (arg, ...patterns) { + var hasFlag = false + var toCheck = [].concat(...patterns) + toCheck.forEach(function (pattern) { + var match = arg.match(pattern) + if (match && hasAnyFlag(match[1])) { + hasFlag = true + } + }) + return hasFlag + } + // make a best effor to pick a default value // for an option based on name and type. function defaultValue (key) { diff --git a/test/yargs-parser.js b/test/yargs-parser.js index 4a7fce0a..16a3709e 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -2690,12 +2690,12 @@ describe('yargs-parser', function () { }) }) - describe('parse-unknown-options = false', function () { + describe('collect-unknown-options = true', function () { it('should ignore unknown options in long format separated by =', function () { const argv = parser('--known-arg=1 --unknown-arg=2', { number: ['known-arg'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ @@ -2708,7 +2708,7 @@ describe('yargs-parser', function () { const argv = parser('--no-known-arg --no-unknown-arg', { boolean: ['known-arg'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ @@ -2721,7 +2721,7 @@ describe('yargs-parser', function () { const argv = parser('--known-arg a --unknown-arg b', { string: ['known-arg'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ @@ -2734,7 +2734,7 @@ describe('yargs-parser', function () { const argv = parser('-k.arg=a -u.arg=b', { string: ['k.arg'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ @@ -2748,11 +2748,11 @@ describe('yargs-parser', function () { const argv = parser('-k.arg 1 -u.arg 2', { number: ['k.arg'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ - _: ['-u.arg', 2], + _: ['-u.arg', '2'], 'k': { 'arg': 1 } @@ -2762,7 +2762,7 @@ describe('yargs-parser', function () { const argv = parser('-k=a -u=b', { string: ['k'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ @@ -2774,7 +2774,7 @@ describe('yargs-parser', function () { const argv = parser('-k- -u-', { string: ['k'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ @@ -2786,11 +2786,11 @@ describe('yargs-parser', function () { const argv = parser('-k 1 -u 2', { number: ['k'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ - _: ['-u', 2], + _: ['-u', '2'], 'k': 1 }) }) @@ -2798,7 +2798,7 @@ describe('yargs-parser', function () { const argv = parser('-k1 -u2', { number: ['k'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ @@ -2810,7 +2810,7 @@ describe('yargs-parser', function () { const argv = parser('-k/1/ -u/2/', { string: ['k'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ @@ -2822,26 +2822,22 @@ describe('yargs-parser', function () { const argv = parser('-kuv', { boolean: ['k', 'v'], configuration: { - 'parse-unknown-options': false + 'collect-unknown-options': true } }) argv.should.deep.equal({ - _: ['-u'], - 'k': true, - 'v': true - }) - it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is at the end', function () { - const argv = parser('-kvu', { - boolean: ['k', 'v'], - configuration: { - 'parse-unknown-options': false - } - }) - argv.should.deep.equal({ - _: ['-u'], - 'k': true, - 'v': true - }) + _: ['-kuv'] + }) + }) + it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is at the end', function () { + const argv = parser('-kvu', { + boolean: ['k', 'v'], + configuration: { + 'collect-unknown-options': true + } + }) + argv.should.deep.equal({ + _: ['-kvu'] }) }) }) From 727a01963c3e6a9eaf2a956483cea2e62f5bcf8e Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Mon, 5 Aug 2019 13:52:02 -0400 Subject: [PATCH 07/10] clean up some stuff that i forgot to remove --- index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/index.js b/index.js index 43f21b5a..4cf34eef 100644 --- a/index.js +++ b/index.js @@ -220,7 +220,6 @@ function parse (args, opts) { } else if (arg.match(/^-[^-]+/) && !arg.match(negative)) { letters = arg.slice(1, -1).split('') broken = false - let unmatched = [] for (var j = 0; j < letters.length; j++) { next = arg.slice(j + 2) @@ -294,9 +293,6 @@ function parse (args, opts) { } } } - if (unmatched.length > 0) { - argv._.push(['-', ...unmatched].join('')) - } } else if (arg === '--') { notFlags = args.slice(i + 1) break From d3feabab74b2442b125122f0d9ccec12d770cea3 Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Mon, 5 Aug 2019 14:44:26 -0400 Subject: [PATCH 08/10] rename checkFlags to hasFlagsMatching, and handle short flags --- index.js | 27 +++++++++++++++++++++++++-- test/yargs-parser.js | 8 +++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 4cf34eef..00193292 100644 --- a/index.js +++ b/index.js @@ -143,7 +143,7 @@ function parse (args, opts) { var next var value - if (configuration['collect-unknown-options'] && !checkFlags(arg, /^-+([^=]+?)=[\s\S]*$/, /^-+no-([^=]+?)=[\s\S]*$/, /^-+([^=]+?)$/, /^-+no-([^=]+?)$/, /^-+([^=]+?)-$/, /^-+([^=]+?)\d+$/, /^-+([^=]+?)\W+.*$/)) { + if (configuration['collect-unknown-options'] && !arg.match(negative) && !hasAllShortFlags(arg) && !hasFlagsMatching(arg, /^-+([^=]+?)=[\s\S]*$/, /^-+no-([^=]+?)=[\s\S]*$/, /^-+([^=]+?)$/, /^-+no-([^=]+?)$/, /^-+([^=]+?)-$/, /^-+([^=]+?)\d+$/, /^-+([^=]+?)\W+.*$/)) { argv._.push(arg) // -- separated by = } else if (arg.match(/^--.+=/) || ( @@ -772,7 +772,7 @@ function parse (args, opts) { return isSet } - function checkFlags (arg, ...patterns) { + function hasFlagsMatching (arg, ...patterns) { var hasFlag = false var toCheck = [].concat(...patterns) toCheck.forEach(function (pattern) { @@ -784,6 +784,29 @@ function parse (args, opts) { return hasFlag } + function hasAllShortFlags (arg) { + if (arg.match(negative) || !arg.match(/^-[^-]+/)) { return false } + var hasAllFlags = true + var letters = arg.slice(1).split('') + var next + for (var j = 0; j < letters.length; j++) { + next = arg.slice(j + 2) + + if (!hasAnyFlag(letters[j])) { + hasAllFlags = false + break + } + + if ((letters[j + 1] && letters[j + 1] === '=') || + next === '-' || + (/[A-Za-z]/.test(letters[j]) && /^-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) || + (letters[j + 1] && letters[j + 1].match(/\W/))) { + break + } + } + return hasAllFlags + } + // make a best effor to pick a default value // for an option based on name and type. function defaultValue (key) { diff --git a/test/yargs-parser.js b/test/yargs-parser.js index 16a3709e..3f8de157 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -2829,15 +2829,17 @@ describe('yargs-parser', function () { _: ['-kuv'] }) }) - it('should ignore unknown options in short format with multiple flags in one argument where an unknown flag is at the end', function () { - const argv = parser('-kvu', { + it('should parse known options in short format with multiple flags in one argument where no unknown flag is in the argument', function () { + const argv = parser('-kv', { boolean: ['k', 'v'], configuration: { 'collect-unknown-options': true } }) argv.should.deep.equal({ - _: ['-kvu'] + _: [], + k: true, + v: true }) }) }) From 267459b535015258b1fb4bdd4c238f5634fdb866 Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Tue, 6 Aug 2019 14:55:08 -0400 Subject: [PATCH 09/10] extract the logic into an "isUnknownOption" function, and add some comments explaining the checks and patterns --- index.js | 23 ++++++++++++++++++++++- test/yargs-parser.js | 12 ++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 00193292..08f9852c 100644 --- a/index.js +++ b/index.js @@ -143,7 +143,7 @@ function parse (args, opts) { var next var value - if (configuration['collect-unknown-options'] && !arg.match(negative) && !hasAllShortFlags(arg) && !hasFlagsMatching(arg, /^-+([^=]+?)=[\s\S]*$/, /^-+no-([^=]+?)=[\s\S]*$/, /^-+([^=]+?)$/, /^-+no-([^=]+?)$/, /^-+([^=]+?)-$/, /^-+([^=]+?)\d+$/, /^-+([^=]+?)\W+.*$/)) { + if (configuration['collect-unknown-options'] && isUnknownOption(arg)) { argv._.push(arg) // -- separated by = } else if (arg.match(/^--.+=/) || ( @@ -784,7 +784,9 @@ function parse (args, opts) { return hasFlag } + // based on a simplified version of the short flag group parsing logic function hasAllShortFlags (arg) { + // if this is a negative number, or doesn't start with a single hyphen, it's not a short flag group if (arg.match(negative) || !arg.match(/^-[^-]+/)) { return false } var hasAllFlags = true var letters = arg.slice(1).split('') @@ -807,6 +809,25 @@ function parse (args, opts) { return hasAllFlags } + function isUnknownOption (arg) { + // ignore negative numbers + if (arg.match(negative)) { return false } + // if this is a short option group and all of them are configured, it isn't unknown + if (hasAllShortFlags(arg)) { return false } + // e.g. '--count=2' + const flagWithEquals = /^-+([^=]+?)=[\s\S]*$/ + // e.g. '-a' or '--arg' + const normalFlag = /^-+([^=]+?)$/ + // e.g. '-a-' + const flagEndingInHyphen = /^-+([^=]+?)-$/ + // e.g. '-abc123' + const flagEndingInDigits = /^-+([^=]+?)\d+$/ + // e.g. '-a/usr/local' + const flagEndingInNonWordCharacters = /^-+([^=]+?)\W+.*$/ + // check the different types of flag styles, including negatedBoolean, a pattern defined near the start of the parse method + return !hasFlagsMatching(arg, flagWithEquals, negatedBoolean, normalFlag, flagEndingInHyphen, flagEndingInDigits, flagEndingInNonWordCharacters) + } + // make a best effor to pick a default value // for an option based on name and type. function defaultValue (key) { diff --git a/test/yargs-parser.js b/test/yargs-parser.js index 3f8de157..27f80740 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -2842,6 +2842,18 @@ describe('yargs-parser', function () { v: true }) }) + it('should parse negative numbers', function () { + const argv = parser('-k -33', { + boolean: ['k'], + configuration: { + 'collect-unknown-options': true + } + }) + argv.should.deep.equal({ + _: [-33], + k: true + }) + }) }) }) From 61e6d11a28b3bcad80ad1c6a36d48da5a2880aeb Mon Sep 17 00:00:00 2001 From: Eric Henderson Date: Wed, 21 Aug 2019 12:59:01 -0400 Subject: [PATCH 10/10] update README.md --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 95d70b9e..f754df09 100644 --- a/README.md +++ b/README.md @@ -386,6 +386,28 @@ node example.js --test-field 1 { _: [], testField: 1 } ``` +### collect unknown options + +* default: `false` +* key: `collect-unknown-options` + +Should unknown options be collected into `_`? An unknown option is one that is not +configured in `opts`. + +_If disabled_ + +```sh +node example.js --unknown-option --known-option 2 +{ _: [], unknownOption: true, knownOption: 2 } +``` + +_If enabled_ + +```sh +node example.js --unknown-option --known-option 2 +{ _: ['--unknown-option'], knownOption: 2 } +``` + ## Special Thanks The yargs project evolves from optimist and minimist. It owes its