feat: add configuration option to "collect-unknown-options" (#181) · yargs/yargs-parser@7909cc4

@@ -26,7 +26,8 @@ function parse (args, opts) {

2626

'set-placeholder-key': false,

2727

'halt-at-non-option': false,

2828

'strip-aliased': false,

29-

'strip-dashed': false

29+

'strip-dashed': false,

30+

'collect-unknown-options': false

3031

}, opts.configuration)

3132

var defaults = opts.default || {}

3233

var configObjects = opts.configObjects || []

@@ -142,8 +143,10 @@ function parse (args, opts) {

142143

var next

143144

var value

144145146+

if (configuration['collect-unknown-options'] && isUnknownOption(arg)) {

147+

argv._.push(arg)

145148

// -- separated by =

146-

if (arg.match(/^--.+=/) || (

149+

} else if (arg.match(/^--.+=/) || (

147150

!configuration['short-option-groups'] && arg.match(/^-.+=/)

148151

)) {

149152

// Using [\s\S] instead of . because js doesn't support the

@@ -757,6 +760,74 @@ function parse (args, opts) {

757760

return isSet

758761

}

759762763+

function hasAnyFlag (key) {

764+

var isSet = false

765+

// XXX Switch to [].concat(...Object.values(flags)) once node.js 6 is dropped

766+

var toCheck = [].concat(...Object.keys(flags).map(k => flags[k]))

767+768+

toCheck.forEach(function (flag) {

769+

if (flag[key]) isSet = flag[key]

770+

})

771+772+

return isSet

773+

}

774+775+

function hasFlagsMatching (arg, ...patterns) {

776+

var hasFlag = false

777+

var toCheck = [].concat(...patterns)

778+

toCheck.forEach(function (pattern) {

779+

var match = arg.match(pattern)

780+

if (match && hasAnyFlag(match[1])) {

781+

hasFlag = true

782+

}

783+

})

784+

return hasFlag

785+

}

786+787+

// based on a simplified version of the short flag group parsing logic

788+

function hasAllShortFlags (arg) {

789+

// if this is a negative number, or doesn't start with a single hyphen, it's not a short flag group

790+

if (arg.match(negative) || !arg.match(/^-[^-]+/)) { return false }

791+

var hasAllFlags = true

792+

var letters = arg.slice(1).split('')

793+

var next

794+

for (var j = 0; j < letters.length; j++) {

795+

next = arg.slice(j + 2)

796+797+

if (!hasAnyFlag(letters[j])) {

798+

hasAllFlags = false

799+

break

800+

}

801+802+

if ((letters[j + 1] && letters[j + 1] === '=') ||

803+

next === '-' ||

804+

(/[A-Za-z]/.test(letters[j]) && /^-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) ||

805+

(letters[j + 1] && letters[j + 1].match(/\W/))) {

806+

break

807+

}

808+

}

809+

return hasAllFlags

810+

}

811+812+

function isUnknownOption (arg) {

813+

// ignore negative numbers

814+

if (arg.match(negative)) { return false }

815+

// if this is a short option group and all of them are configured, it isn't unknown

816+

if (hasAllShortFlags(arg)) { return false }

817+

// e.g. '--count=2'

818+

const flagWithEquals = /^-+([^=]+?)=[\s\S]*$/

819+

// e.g. '-a' or '--arg'

820+

const normalFlag = /^-+([^=]+?)$/

821+

// e.g. '-a-'

822+

const flagEndingInHyphen = /^-+([^=]+?)-$/

823+

// e.g. '-abc123'

824+

const flagEndingInDigits = /^-+([^=]+?)\d+$/

825+

// e.g. '-a/usr/local'

826+

const flagEndingInNonWordCharacters = /^-+([^=]+?)\W+.*$/

827+

// check the different types of flag styles, including negatedBoolean, a pattern defined near the start of the parse method

828+

return !hasFlagsMatching(arg, flagWithEquals, negatedBoolean, normalFlag, flagEndingInHyphen, flagEndingInDigits, flagEndingInNonWordCharacters)

829+

}

830+760831

// make a best effor to pick a default value

761832

// for an option based on name and type.

762833

function defaultValue (key) {