From 824f642038d1b02ede68b6261d1d65163390929a Mon Sep 17 00:00:00 2001 From: Francis Date: Thu, 8 May 2014 07:50:37 -0700 Subject: [PATCH 01/60] Eliminate `longest` fn. Pull request removes `longest` since it is not used anywhere within `index.js`. --- index.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/index.js b/index.js index 584f551..d181233 100644 --- a/index.js +++ b/index.js @@ -182,6 +182,3 @@ function isNumber (x) { return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); } -function longest (xs) { - return Math.max.apply(null, xs.map(function (x) { return x.length })); -} From f0d143e8726f539321a433ad6ee05948ccb3d95f Mon Sep 17 00:00:00 2001 From: James Halliday Date: Thu, 8 May 2014 07:56:06 -0700 Subject: [PATCH 02/60] 0.0.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index af6250b..3d47fae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "0.0.8", + "version": "0.0.9", "description": "parse argument options", "main": "index.js", "devDependencies": { From 1ab743bad4484d69f1259bed42f9531de01119de Mon Sep 17 00:00:00 2001 From: Trevor Senior Date: Wed, 30 Apr 2014 18:06:05 -0400 Subject: [PATCH 03/60] aliased values treated as strings --- index.js | 13 ++++++++----- test/parse.js | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index d181233..71fb830 100644 --- a/index.js +++ b/index.js @@ -7,10 +7,6 @@ module.exports = function (args, opts) { flags.bools[key] = true; }); - [].concat(opts.string).filter(Boolean).forEach(function (key) { - flags.strings[key] = true; - }); - var aliases = {}; Object.keys(opts.alias || {}).forEach(function (key) { aliases[key] = [].concat(opts.alias[key]); @@ -20,7 +16,14 @@ module.exports = function (args, opts) { })); }); }); - + + [].concat(opts.string).filter(Boolean).forEach(function (key) { + flags.strings[key] = true; + if (aliases[key]) { + flags.strings[aliases[key]] = true; + } + }); + var defaults = opts['default'] || {}; var argv = { _ : [] }; diff --git a/test/parse.js b/test/parse.js index 8a90646..319e683 100644 --- a/test/parse.js +++ b/test/parse.js @@ -183,6 +183,29 @@ test('empty strings', function(t) { }); +test('string and alias', function(t) { + var x = parse([ '--str', '000123' ], { + string: 's', + alias: { s: 'str' } + }); + + t.equal(x.str, '000123'); + t.equal(typeof x.str, 'string'); + t.equal(x.s, '000123'); + t.equal(typeof x.s, 'string'); + + var y = parse([ '-s', '000123' ], { + string: 'str', + alias: { str: 's' } + }); + + t.equal(y.str, '000123'); + t.equal(typeof y.str, 'string'); + t.equal(y.s, '000123'); + t.equal(typeof y.s, 'string'); + t.end(); +}); + test('slashBreak', function (t) { t.same( parse([ '-I/foo/bar/baz' ]), From 3662624be976d5489d486a856849c048d13be903 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 11 May 2014 23:37:56 +0200 Subject: [PATCH 04/60] another test for higher coverage --- test/dotted.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/dotted.js b/test/dotted.js index ef0ae34..d8b3e85 100644 --- a/test/dotted.js +++ b/test/dotted.js @@ -14,3 +14,9 @@ test('dotted default', function (t) { t.equal(argv.aa.bb, 11); t.end(); }); + +test('dotted default with no alias', function (t) { + var argv = parse('', {default: {'a.b': 11}}); + t.equal(argv.a.b, 11); + t.end(); +}); From 9bf2d36f1d3b8795be90b8f7de0a937f098aa394 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 11 May 2014 23:39:27 +0200 Subject: [PATCH 05/60] dedicated num test --- test/num.js | 28 ++++++++++++++++++++++++++++ test/parse.js | 26 -------------------------- 2 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 test/num.js diff --git a/test/num.js b/test/num.js new file mode 100644 index 0000000..507dc97 --- /dev/null +++ b/test/num.js @@ -0,0 +1,28 @@ +var parse = require('../'); +var test = require('tape'); + +test('nums', function (t) { + var argv = parse([ + '-x', '1234', + '-y', '5.67', + '-z', '1e7', + '-w', '10f', + '--hex', '0xdeadbeef', + '789' + ]); + t.deepEqual(argv, { + x : 1234, + y : 5.67, + z : 1e7, + w : '10f', + hex : 0xdeadbeef, + _ : [ 789 ] + }); + t.deepEqual(typeof argv.x, 'number'); + t.deepEqual(typeof argv.y, 'number'); + t.deepEqual(typeof argv.z, 'number'); + t.deepEqual(typeof argv.w, 'string'); + t.deepEqual(typeof argv.hex, 'number'); + t.deepEqual(typeof argv._[0], 'number'); + t.end(); +}); diff --git a/test/parse.js b/test/parse.js index 319e683..edcdd71 100644 --- a/test/parse.js +++ b/test/parse.js @@ -42,32 +42,6 @@ test('comprehensive', function (t) { t.end(); }); -test('nums', function (t) { - var argv = parse([ - '-x', '1234', - '-y', '5.67', - '-z', '1e7', - '-w', '10f', - '--hex', '0xdeadbeef', - '789' - ]); - t.deepEqual(argv, { - x : 1234, - y : 5.67, - z : 1e7, - w : '10f', - hex : 0xdeadbeef, - _ : [ 789 ] - }); - t.deepEqual(typeof argv.x, 'number'); - t.deepEqual(typeof argv.y, 'number'); - t.deepEqual(typeof argv.z, 'number'); - t.deepEqual(typeof argv.w, 'string'); - t.deepEqual(typeof argv.hex, 'number'); - t.deepEqual(typeof argv._[0], 'number'); - t.end(); -}); - test('flag boolean', function (t) { var argv = parse([ '-t', 'moo' ], { boolean: 't' }); t.deepEqual(argv, { t : true, _ : [ 'moo' ] }); From b2bb04436599d77a2ce029e8e555e25b3aa55d13 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 11 May 2014 23:40:29 +0200 Subject: [PATCH 06/60] cover the case of already numbers, at 100% coverage --- test/num.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/num.js b/test/num.js index 507dc97..2cc77f4 100644 --- a/test/num.js +++ b/test/num.js @@ -26,3 +26,11 @@ test('nums', function (t) { t.deepEqual(typeof argv._[0], 'number'); t.end(); }); + +test('already a number', function (t) { + var argv = parse([ '-x', 1234, 789 ]); + t.deepEqual(argv, { x : 1234, _ : [ 789 ] }); + t.deepEqual(typeof argv.x, 'number'); + t.deepEqual(typeof argv._[0], 'number'); + t.end(); +}); From 46e448f9f513cfeb2bcc8b688b9b47ba1e515c2b Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 11 May 2014 23:42:27 +0200 Subject: [PATCH 07/60] dedicated boolean test --- test/bool.js | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/parse.js | 118 ------------------------------------------------- 2 files changed, 119 insertions(+), 118 deletions(-) create mode 100644 test/bool.js diff --git a/test/bool.js b/test/bool.js new file mode 100644 index 0000000..749e083 --- /dev/null +++ b/test/bool.js @@ -0,0 +1,119 @@ +var parse = require('../'); +var test = require('tape'); + +test('flag boolean default false', function (t) { + var argv = parse(['moo'], { + boolean: ['t', 'verbose'], + default: { verbose: false, t: false } + }); + + t.deepEqual(argv, { + verbose: false, + t: false, + _: ['moo'] + }); + + t.deepEqual(typeof argv.verbose, 'boolean'); + t.deepEqual(typeof argv.t, 'boolean'); + t.end(); + +}); + +test('boolean groups', function (t) { + var argv = parse([ '-x', '-z', 'one', 'two', 'three' ], { + boolean: ['x','y','z'] + }); + + t.deepEqual(argv, { + x : true, + y : false, + z : true, + _ : [ 'one', 'two', 'three' ] + }); + + t.deepEqual(typeof argv.x, 'boolean'); + t.deepEqual(typeof argv.y, 'boolean'); + t.deepEqual(typeof argv.z, 'boolean'); + t.end(); +}); +test('boolean and alias with chainable api', function (t) { + var aliased = [ '-h', 'derp' ]; + var regular = [ '--herp', 'derp' ]; + var opts = { + herp: { alias: 'h', boolean: true } + }; + var aliasedArgv = parse(aliased, { + boolean: 'herp', + alias: { h: 'herp' } + }); + var propertyArgv = parse(regular, { + boolean: 'herp', + alias: { h: 'herp' } + }); + var expected = { + herp: true, + h: true, + '_': [ 'derp' ] + }; + + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + t.end(); +}); + +test('boolean and alias with options hash', function (t) { + var aliased = [ '-h', 'derp' ]; + var regular = [ '--herp', 'derp' ]; + var opts = { + alias: { 'h': 'herp' }, + boolean: 'herp' + }; + var aliasedArgv = parse(aliased, opts); + var propertyArgv = parse(regular, opts); + var expected = { + herp: true, + h: true, + '_': [ 'derp' ] + }; + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + t.end(); +}); + +test('boolean and alias using explicit true', function (t) { + var aliased = [ '-h', 'true' ]; + var regular = [ '--herp', 'true' ]; + var opts = { + alias: { h: 'herp' }, + boolean: 'h' + }; + var aliasedArgv = parse(aliased, opts); + var propertyArgv = parse(regular, opts); + var expected = { + herp: true, + h: true, + '_': [ ] + }; + + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + t.end(); +}); + +// regression, see https://github.com/substack/node-optimist/issues/71 +test('boolean and --x=true', function(t) { + var parsed = parse(['--boool', '--other=true'], { + boolean: 'boool' + }); + + t.same(parsed.boool, true); + t.same(parsed.other, 'true'); + + parsed = parse(['--boool', '--other=false'], { + boolean: 'boool' + }); + + t.same(parsed.boool, true); + t.same(parsed.other, 'false'); + t.end(); +}); diff --git a/test/parse.js b/test/parse.js index edcdd71..7b4a2a1 100644 --- a/test/parse.js +++ b/test/parse.js @@ -66,42 +66,6 @@ test('flag boolean value', function (t) { t.end(); }); -test('flag boolean default false', function (t) { - var argv = parse(['moo'], { - boolean: ['t', 'verbose'], - default: { verbose: false, t: false } - }); - - t.deepEqual(argv, { - verbose: false, - t: false, - _: ['moo'] - }); - - t.deepEqual(typeof argv.verbose, 'boolean'); - t.deepEqual(typeof argv.t, 'boolean'); - t.end(); - -}); - -test('boolean groups', function (t) { - var argv = parse([ '-x', '-z', 'one', 'two', 'three' ], { - boolean: ['x','y','z'] - }); - - t.deepEqual(argv, { - x : true, - y : false, - z : true, - _ : [ 'one', 'two', 'three' ] - }); - - t.deepEqual(typeof argv.x, 'boolean'); - t.deepEqual(typeof argv.y, 'boolean'); - t.deepEqual(typeof argv.z, 'boolean'); - t.end(); -}); - test('newlines in params' , function (t) { var args = parse([ '-s', "X\nX" ]) t.deepEqual(args, { _ : [], s : "X\nX" }); @@ -231,85 +195,3 @@ test('nested dotted objects', function (t) { t.same(argv.beep, { boop : true }); t.end(); }); - -test('boolean and alias with chainable api', function (t) { - var aliased = [ '-h', 'derp' ]; - var regular = [ '--herp', 'derp' ]; - var opts = { - herp: { alias: 'h', boolean: true } - }; - var aliasedArgv = parse(aliased, { - boolean: 'herp', - alias: { h: 'herp' } - }); - var propertyArgv = parse(regular, { - boolean: 'herp', - alias: { h: 'herp' } - }); - var expected = { - herp: true, - h: true, - '_': [ 'derp' ] - }; - - t.same(aliasedArgv, expected); - t.same(propertyArgv, expected); - t.end(); -}); - -test('boolean and alias with options hash', function (t) { - var aliased = [ '-h', 'derp' ]; - var regular = [ '--herp', 'derp' ]; - var opts = { - alias: { 'h': 'herp' }, - boolean: 'herp' - }; - var aliasedArgv = parse(aliased, opts); - var propertyArgv = parse(regular, opts); - var expected = { - herp: true, - h: true, - '_': [ 'derp' ] - }; - t.same(aliasedArgv, expected); - t.same(propertyArgv, expected); - t.end(); -}); - -test('boolean and alias using explicit true', function (t) { - var aliased = [ '-h', 'true' ]; - var regular = [ '--herp', 'true' ]; - var opts = { - alias: { h: 'herp' }, - boolean: 'h' - }; - var aliasedArgv = parse(aliased, opts); - var propertyArgv = parse(regular, opts); - var expected = { - herp: true, - h: true, - '_': [ ] - }; - - t.same(aliasedArgv, expected); - t.same(propertyArgv, expected); - t.end(); -}); - -// regression, see https://github.com/substack/node-optimist/issues/71 -test('boolean and --x=true', function(t) { - var parsed = parse(['--boool', '--other=true'], { - boolean: 'boool' - }); - - t.same(parsed.boool, true); - t.same(parsed.other, 'true'); - - parsed = parse(['--boool', '--other=false'], { - boolean: 'boool' - }); - - t.same(parsed.boool, true); - t.same(parsed.other, 'false'); - t.end(); -}); From f69fd1932fdb97963379a83a7e6b705df20c5631 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 11 May 2014 23:42:47 +0200 Subject: [PATCH 08/60] 0.0.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3d47fae..4e3278a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "0.0.9", + "version": "0.0.10", "description": "parse argument options", "main": "index.js", "devDependencies": { From ce4a1e63a7e8d5ab88d2a3768adefa6af98a445a Mon Sep 17 00:00:00 2001 From: ELLIOTTCABLE Date: Sun, 11 May 2014 18:30:50 -0500 Subject: [PATCH 09/60] Provide a mechanism to segregate -- arguments --- index.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 71fb830..6bed6e1 100644 --- a/index.js +++ b/index.js @@ -143,9 +143,17 @@ module.exports = function (args, opts) { } }); - notFlags.forEach(function(key) { - argv._.push(key); - }); + if (opts['--']) { + argv['--'] = new Array(); + notFlags.forEach(function(key) { + argv['--'].push(key); + }); + } + else { + notFlags.forEach(function(key) { + argv._.push(key); + }); + } return argv; }; From 715c1e3714be223f998f6c537af6b505f0236c16 Mon Sep 17 00:00:00 2001 From: ELLIOTTCABLE Date: Sun, 11 May 2014 19:23:58 -0500 Subject: [PATCH 10/60] Adding a test-case for notFlags segregation --- test/dash.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/dash.js b/test/dash.js index 8b034b9..5a4fa5b 100644 --- a/test/dash.js +++ b/test/dash.js @@ -22,3 +22,10 @@ test('-a -- b', function (t) { t.deepEqual(parse([ '--a', '--', 'b' ]), { a: true, _: [ 'b' ] }); t.deepEqual(parse([ '--a', '--', 'b' ]), { a: true, _: [ 'b' ] }); }); + +test('move arguments after the -- into their own `--` array', function(t) { + t.plan(1); + t.deepEqual( + parse([ '--name', 'John', 'before', '--', 'after' ], { '--': true }), + { name: 'John', _: [ 'before' ], '--': [ 'after' ] }); +}); From 14db0e6dbc6d2b9e472adaa54dad7004b364634f Mon Sep 17 00:00:00 2001 From: James Halliday Date: Mon, 12 May 2014 03:22:31 +0200 Subject: [PATCH 11/60] documented argv['--'] --- readme.markdown | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/readme.markdown b/readme.markdown index c256353..0dc9394 100644 --- a/readme.markdown +++ b/readme.markdown @@ -59,6 +59,17 @@ strings * `opts.alias` - an object mapping string names to strings or arrays of string argument names to use as aliases * `opts.default` - an object mapping string argument names to default values +* `opts['--']` - when true, populate `argv._` with everything before the `--` +and `argv['--']` with everything after the `--`. Here's an example: + +``` +> require('./')('one two three -- four five --six'.split(' '), { '--': true }) +{ _: [ 'one', 'two', 'three' ], + '--': [ 'four', 'five', '--six' ] } +``` + +Note that with `opts['--']` set, parsing for arguments still stops after the +`--`. # install From 1f976263c6ebd2f5c196ccb3f4a5e2f95d3d6d57 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Mon, 12 May 2014 03:23:02 +0200 Subject: [PATCH 12/60] 0.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e3278a..3e33333 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "0.0.10", + "version": "0.1.0", "description": "parse argument options", "main": "index.js", "devDependencies": { From 450a97f6e2bc85c7a4a13185c19a818d9a5ebe69 Mon Sep 17 00:00:00 2001 From: Max Ogden Date: Tue, 17 Jun 2014 20:18:02 -0700 Subject: [PATCH 13/60] support all-boolean mode --- index.js | 13 +++++++++---- readme.markdown | 4 +++- test/all_bool.js | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 test/all_bool.js diff --git a/index.js b/index.js index 6bed6e1..9549c96 100644 --- a/index.js +++ b/index.js @@ -2,10 +2,14 @@ module.exports = function (args, opts) { if (!opts) opts = {}; var flags = { bools : {}, strings : {} }; - - [].concat(opts['boolean']).filter(Boolean).forEach(function (key) { - flags.bools[key] = true; - }); + + if (typeof opts['boolean'] === 'boolean' && opts['boolean']) { + flags.allBools = true; + } else { + [].concat(opts['boolean']).filter(Boolean).forEach(function (key) { + flags.bools[key] = true; + }); + } var aliases = {}; Object.keys(opts.alias || {}).forEach(function (key) { @@ -68,6 +72,7 @@ module.exports = function (args, opts) { var next = args[i + 1]; if (next !== undefined && !/^-/.test(next) && !flags.bools[key] + && !flags.allBools && (aliases[key] ? !flags.bools[aliases[key]] : true)) { setArg(key, next); i++; diff --git a/readme.markdown b/readme.markdown index 0dc9394..8253221 100644 --- a/readme.markdown +++ b/readme.markdown @@ -55,7 +55,9 @@ options can be: * `opts.string` - a string or array of strings argument names to always treat as strings -* `opts.boolean` - a string or array of strings to always treat as booleans +* `opts.boolean` - a boolean, string or array of strings to always treat as +booleans. if `true` will treat all double hyphenated arguments without equal signs +as boolean (e.g. affects `--foo`, not `-f` or `--foo=bar`) * `opts.alias` - an object mapping string names to strings or arrays of string argument names to use as aliases * `opts.default` - an object mapping string argument names to default values diff --git a/test/all_bool.js b/test/all_bool.js new file mode 100644 index 0000000..4575ec0 --- /dev/null +++ b/test/all_bool.js @@ -0,0 +1,32 @@ +var parse = require('../'); +var test = require('tape'); + +test('flag boolean true (default all --args to boolean)', function (t) { + var argv = parse(['moo', '--honk', 'cow'], { + boolean: true + }); + + t.deepEqual(argv, { + honk: true, + _: ['moo', 'cow'] + }); + + t.deepEqual(typeof argv.honk, 'boolean'); + t.end(); +}); + +test('flag boolean true only affects double hyphen arguments without equals signs', function (t) { + var argv = parse(['moo', '--honk', 'cow', '-p', '55', '--tacos=good'], { + boolean: true + }); + + t.deepEqual(argv, { + honk: true, + tacos: 'good', + p: '55', + _: ['moo', 'cow'] + }); + + t.deepEqual(typeof argv.honk, 'boolean'); + t.end(); +}); From f904dcc3c28f10eb11840091e9f0bab9d9519b5c Mon Sep 17 00:00:00 2001 From: James Halliday Date: Thu, 19 Jun 2014 22:56:34 +0800 Subject: [PATCH 14/60] 0.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3e33333..5935fc3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "0.1.0", + "version": "0.2.0", "description": "parse argument options", "main": "index.js", "devDependencies": { From 471c7e4a7e910fc7ad8f9df850a186daf32c64e9 Mon Sep 17 00:00:00 2001 From: Jason Diamond Date: Thu, 7 Aug 2014 20:44:24 -0700 Subject: [PATCH 15/60] added stopEarly option --- index.js | 4 ++++ readme.markdown | 2 ++ test/stop_early.js | 15 +++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 test/stop_early.js diff --git a/index.js b/index.js index 9549c96..3baad4e 100644 --- a/index.js +++ b/index.js @@ -135,6 +135,10 @@ module.exports = function (args, opts) { argv._.push( flags.strings['_'] || !isNumber(arg) ? arg : Number(arg) ); + if (opts.stopEarly) { + argv._.push.apply(argv._, args.slice(i + 1)); + break; + } } } diff --git a/readme.markdown b/readme.markdown index 8253221..f3e4fac 100644 --- a/readme.markdown +++ b/readme.markdown @@ -61,6 +61,8 @@ as boolean (e.g. affects `--foo`, not `-f` or `--foo=bar`) * `opts.alias` - an object mapping string names to strings or arrays of string argument names to use as aliases * `opts.default` - an object mapping string argument names to default values +# `opts.stopEarly` - when true, populate `argv._` with everything after the +first non-option * `opts['--']` - when true, populate `argv._` with everything before the `--` and `argv['--']` with everything after the `--`. Here's an example: diff --git a/test/stop_early.js b/test/stop_early.js new file mode 100644 index 0000000..bdf9fbc --- /dev/null +++ b/test/stop_early.js @@ -0,0 +1,15 @@ +var parse = require('../'); +var test = require('tape'); + +test('stops parsing on the first non-option when stopEarly is set', function (t) { + var argv = parse(['--aaa', 'bbb', 'ccc', '--ddd'], { + stopEarly: true + }); + + t.deepEqual(argv, { + aaa: 'bbb', + _: ['ccc', '--ddd'] + }); + + t.end(); +}); From fef6ae79c38b9dc1c49569abb7cd04eb965eac5e Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 10 Aug 2014 18:07:51 -0700 Subject: [PATCH 16/60] fix list --- readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index f3e4fac..d0206e9 100644 --- a/readme.markdown +++ b/readme.markdown @@ -61,7 +61,7 @@ as boolean (e.g. affects `--foo`, not `-f` or `--foo=bar`) * `opts.alias` - an object mapping string names to strings or arrays of string argument names to use as aliases * `opts.default` - an object mapping string argument names to default values -# `opts.stopEarly` - when true, populate `argv._` with everything after the +* `opts.stopEarly` - when true, populate `argv._` with everything after the first non-option * `opts['--']` - when true, populate `argv._` with everything before the `--` and `argv['--']` with everything after the `--`. Here's an example: From 13077b369b092797bb176fd18131d07b0d6c2d1c Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 10 Aug 2014 18:08:18 -0700 Subject: [PATCH 17/60] 1.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5935fc3..14a43f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "0.2.0", + "version": "1.0.0", "description": "parse argument options", "main": "index.js", "devDependencies": { From 6f3cc5d4e84524932a6ef2ce3592acc67cdd4383 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Sun, 10 Aug 2014 21:13:30 -0400 Subject: [PATCH 18/60] add support for handling "unknown" options not registered with the parser. --- index.js | 49 +++++++++++++++-------- readme.markdown | 3 ++ test/unknown.js | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 17 deletions(-) create mode 100644 test/unknown.js diff --git a/index.js b/index.js index 3baad4e..cb0afc2 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,11 @@ module.exports = function (args, opts) { if (!opts) opts = {}; - var flags = { bools : {}, strings : {} }; + var flags = { bools : {}, strings : {}, unknownFn: null }; + + if (typeof opts['unknown'] === 'function') { + flags.unknownFn = opts['unknown']; + } if (typeof opts['boolean'] === 'boolean' && opts['boolean']) { flags.allBools = true; @@ -42,7 +46,16 @@ module.exports = function (args, opts) { args = args.slice(0, args.indexOf('--')); } - function setArg (key, val) { + function argDefined(key, arg) { + return (flags.allBools && /^--[^=]+$/.test(arg)) || + flags.strings[key] || flags.bools[key] || aliases[key]; + } + + function setArg (key, val, arg) { + if (arg && flags.unknownFn && !argDefined(key, arg)) { + if (flags.unknownFn(arg) === false) return; + } + var value = !flags.strings[key] && isNumber(val) ? Number(val) : val ; @@ -61,11 +74,11 @@ module.exports = function (args, opts) { // 'dotall' regex modifier. See: // http://stackoverflow.com/a/1068308/13216 var m = arg.match(/^--([^=]+)=([\s\S]*)$/); - setArg(m[1], m[2]); + setArg(m[1], m[2], arg); } else if (/^--no-.+/.test(arg)) { var key = arg.match(/^--no-(.+)/)[1]; - setArg(key, false); + setArg(key, false, arg); } else if (/^--.+/.test(arg)) { var key = arg.match(/^--(.+)/)[1]; @@ -74,15 +87,15 @@ module.exports = function (args, opts) { && !flags.bools[key] && !flags.allBools && (aliases[key] ? !flags.bools[aliases[key]] : true)) { - setArg(key, next); + setArg(key, next, arg); i++; } else if (/^(true|false)$/.test(next)) { - setArg(key, next === 'true'); + setArg(key, next === 'true', arg); i++; } else { - setArg(key, flags.strings[key] ? '' : true); + setArg(key, flags.strings[key] ? '' : true, arg); } } else if (/^-[^-]+/.test(arg)) { @@ -93,24 +106,24 @@ module.exports = function (args, opts) { var next = arg.slice(j+2); if (next === '-') { - setArg(letters[j], next) + setArg(letters[j], next, arg) continue; } if (/[A-Za-z]/.test(letters[j]) && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { - setArg(letters[j], next); + setArg(letters[j], next, arg); broken = true; break; } if (letters[j+1] && letters[j+1].match(/\W/)) { - setArg(letters[j], arg.slice(j+2)); + setArg(letters[j], arg.slice(j+2), arg); broken = true; break; } else { - setArg(letters[j], flags.strings[letters[j]] ? '' : true); + setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg); } } @@ -119,22 +132,24 @@ module.exports = function (args, opts) { if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1]) && !flags.bools[key] && (aliases[key] ? !flags.bools[aliases[key]] : true)) { - setArg(key, args[i+1]); + setArg(key, args[i+1], arg); i++; } else if (args[i+1] && /true|false/.test(args[i+1])) { - setArg(key, args[i+1] === 'true'); + setArg(key, args[i+1] === 'true', arg); i++; } else { - setArg(key, flags.strings[key] ? '' : true); + setArg(key, flags.strings[key] ? '' : true, arg); } } } else { - argv._.push( - flags.strings['_'] || !isNumber(arg) ? arg : Number(arg) - ); + if (!flags.unknownFn || flags.unknownFn(arg) !== false) { + argv._.push( + flags.strings['_'] || !isNumber(arg) ? arg : Number(arg) + ); + } if (opts.stopEarly) { argv._.push.apply(argv._, args.slice(i + 1)); break; diff --git a/readme.markdown b/readme.markdown index d0206e9..30a74cf 100644 --- a/readme.markdown +++ b/readme.markdown @@ -65,6 +65,9 @@ argument names to use as aliases first non-option * `opts['--']` - when true, populate `argv._` with everything before the `--` and `argv['--']` with everything after the `--`. Here's an example: +* `opts.unknown` - a function which is invoked with a command line parameter not +defined in the `opts` configuration object. If the function returns `false`, the +unknown option is not added to `argv`. ``` > require('./')('one two three -- four five --six'.split(' '), { '--': true }) diff --git a/test/unknown.js b/test/unknown.js new file mode 100644 index 0000000..43fe8dd --- /dev/null +++ b/test/unknown.js @@ -0,0 +1,101 @@ +var parse = require('../'); +var test = require('tape'); + +test('boolean and alias is not unknown', function (t) { + var unknown = []; + function unknownFn(arg) { + unknown.push(arg); + return false; + } + var aliased = [ '-h', 'true', '--derp', 'true' ]; + var regular = [ '--herp', 'true', '-d', 'true' ]; + var opts = { + alias: { h: 'herp' }, + boolean: 'h', + unknown: unknownFn + }; + var aliasedArgv = parse(aliased, opts); + var propertyArgv = parse(regular, opts); + + t.same(unknown, ['--derp', '-d']); + t.end(); +}); + +test('flag boolean true any double hyphen argument is not unknown', function (t) { + var unknown = []; + function unknownFn(arg) { + unknown.push(arg); + return false; + } + var argv = parse(['--honk', '--tacos=good', 'cow', '-p', '55'], { + boolean: true, + unknown: unknownFn + }); + t.same(unknown, ['--tacos=good', 'cow', '-p']); + t.same(argv, { + honk: true, + _: [] + }); + t.end(); +}); + +test('string and alias is not unknown', function (t) { + var unknown = []; + function unknownFn(arg) { + unknown.push(arg); + return false; + } + var aliased = [ '-h', 'hello', '--derp', 'goodbye' ]; + var regular = [ '--herp', 'hello', '-d', 'moon' ]; + var opts = { + alias: { h: 'herp' }, + string: 'h', + unknown: unknownFn + }; + var aliasedArgv = parse(aliased, opts); + var propertyArgv = parse(regular, opts); + + t.same(unknown, ['--derp', '-d']); + t.end(); +}); + +test('default and alias is not unknown', function (t) { + var unknown = []; + function unknownFn(arg) { + unknown.push(arg); + return false; + } + var aliased = [ '-h', 'hello' ]; + var regular = [ '--herp', 'hello' ]; + var opts = { + default: { 'h': 'bar' }, + alias: { 'h': 'herp' }, + unknown: unknownFn + }; + var aliasedArgv = parse(aliased, opts); + var propertyArgv = parse(regular, opts); + + t.same(unknown, []); + t.end(); +}); + +test('value following -- is not unknown', function (t) { + var unknown = []; + function unknownFn(arg) { + unknown.push(arg); + return false; + } + var aliased = [ '--bad', '--', 'good', 'arg' ]; + var opts = { + '--': true, + unknown: unknownFn + }; + var argv = parse(aliased, opts); + + t.same(unknown, ['--bad']); + t.same(argv, { + '--': ['good', 'arg'], + '_': [] + }) + t.end(); +}); From a6972da89e56bf77642f8ec05a13b6558db93498 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 10 Aug 2014 19:10:53 -0700 Subject: [PATCH 19/60] extra fn to get 100% coverage again --- test/unknown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unknown.js b/test/unknown.js index 43fe8dd..462a36b 100644 --- a/test/unknown.js +++ b/test/unknown.js @@ -77,6 +77,7 @@ test('default and alias is not unknown', function (t) { t.same(unknown, []); t.end(); + unknownFn(); // exercise fn for 100% coverage }); test('value following -- is not unknown', function (t) { From 02ed37115194d3697ff358e8e25e5e66bab1d9f8 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 10 Aug 2014 19:11:20 -0700 Subject: [PATCH 20/60] reformat package.json --- package.json | 76 ++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/package.json b/package.json index 14a43f2..67779e4 100644 --- a/package.json +++ b/package.json @@ -1,40 +1,40 @@ { - "name": "minimist", - "version": "1.0.0", - "description": "parse argument options", - "main": "index.js", - "devDependencies": { - "tape": "~1.0.4", - "tap": "~0.4.0" - }, - "scripts": { - "test": "tap test/*.js" - }, - "testling" : { - "files" : "test/*.js", - "browsers" : [ - "ie/6..latest", - "ff/5", "firefox/latest", - "chrome/10", "chrome/latest", - "safari/5.1", "safari/latest", - "opera/12" - ] - }, - "repository": { - "type": "git", - "url": "git://github.com/substack/minimist.git" - }, - "homepage": "https://github.com/substack/minimist", - "keywords": [ - "argv", - "getopt", - "parser", - "optimist" - ], - "author": { - "name": "James Halliday", - "email": "mail@substack.net", - "url": "http://substack.net" - }, - "license": "MIT" + "name": "minimist", + "version": "1.0.0", + "description": "parse argument options", + "main": "index.js", + "devDependencies": { + "tape": "~1.0.4", + "tap": "~0.4.0" + }, + "scripts": { + "test": "tap test/*.js" + }, + "testling" : { + "files" : "test/*.js", + "browsers" : [ + "ie/6..latest", + "ff/5", "firefox/latest", + "chrome/10", "chrome/latest", + "safari/5.1", "safari/latest", + "opera/12" + ] + }, + "repository": { + "type": "git", + "url": "git://github.com/substack/minimist.git" + }, + "homepage": "https://github.com/substack/minimist", + "keywords": [ + "argv", + "getopt", + "parser", + "optimist" + ], + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "license": "MIT" } From e5531ba0479da3b8138d3d8cac545d84ccb1c8df Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 10 Aug 2014 20:18:05 -0700 Subject: [PATCH 21/60] coverage script --- package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 67779e4..866cf2b 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,12 @@ "main": "index.js", "devDependencies": { "tape": "~1.0.4", - "tap": "~0.4.0" + "tap": "~0.4.0", + "covert": "^1.0.0" }, "scripts": { - "test": "tap test/*.js" + "test": "tap test/*.js", + "coverage": "covert test/*.js" }, "testling" : { "files" : "test/*.js", From e2563e462be40c344c6c65b7cde85091fe261976 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sun, 10 Aug 2014 20:18:24 -0700 Subject: [PATCH 22/60] 1.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 866cf2b..739179e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.0.0", + "version": "1.1.0", "description": "parse argument options", "main": "index.js", "devDependencies": { From 8c444fe89384ded7d441c120915ea60620b01dd3 Mon Sep 17 00:00:00 2001 From: Dominic Tarr Date: Wed, 11 Mar 2015 11:34:43 +1300 Subject: [PATCH 23/60] test for setting a boolean to a null default --- test/default_bool.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/default_bool.js b/test/default_bool.js index f0041ee..780a311 100644 --- a/test/default_bool.js +++ b/test/default_bool.js @@ -18,3 +18,18 @@ test('boolean default false', function (t) { t.equal(argv.somefalse, false); t.end(); }); + +test('boolean default to null', function (t) { + var argv = parse([], { + boolean: 'maybe', + default: { maybe: null } + }); + t.equal(argv.maybe, null); + var argv = parse(['--maybe'], { + boolean: 'maybe', + default: { maybe: null } + }); + t.equal(argv.maybe, true); + t.end(); + +}) From 6863198e36139830ff1f20ffdceaddd93f2c1db9 Mon Sep 17 00:00:00 2001 From: Dominic Tarr Date: Wed, 11 Mar 2015 11:35:08 +1300 Subject: [PATCH 24/60] check that they type of a value is a boolean, not just that it is currently set to a boolean --- index.js | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index cb0afc2..ce93d19 100644 --- a/index.js +++ b/index.js @@ -65,6 +65,25 @@ module.exports = function (args, opts) { setKey(argv, x.split('.'), value); }); } + + function setKey (obj, keys, value) { + var o = obj; + keys.slice(0,-1).forEach(function (key) { + if (o[key] === undefined) o[key] = {}; + o = o[key]; + }); + + var key = keys[keys.length - 1]; + if (o[key] === undefined || flags.bools[key]) { + o[key] = value; + } + else if (Array.isArray(o[key])) { + o[key].push(value); + } + else { + o[key] = [ o[key], value ]; + } + } for (var i = 0; i < args.length; i++) { var arg = args[i]; @@ -192,25 +211,6 @@ function hasKey (obj, keys) { return key in o; } -function setKey (obj, keys, value) { - var o = obj; - keys.slice(0,-1).forEach(function (key) { - if (o[key] === undefined) o[key] = {}; - o = o[key]; - }); - - var key = keys[keys.length - 1]; - if (o[key] === undefined || typeof o[key] === 'boolean') { - o[key] = value; - } - else if (Array.isArray(o[key])) { - o[key].push(value); - } - else { - o[key] = [ o[key], value ]; - } -} - function isNumber (x) { if (typeof x === 'number') return true; if (/^0x[0-9a-f]+$/i.test(x)) return true; From e5f419a3b5b3bc3f9e5ac71b7040621af70ed2dd Mon Sep 17 00:00:00 2001 From: Dominic Tarr Date: Wed, 11 Mar 2015 12:03:43 +1300 Subject: [PATCH 25/60] if the previous value was a boolean, without an default (or with an alias) don't make an array either --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index ce93d19..185a045 100644 --- a/index.js +++ b/index.js @@ -74,7 +74,7 @@ module.exports = function (args, opts) { }); var key = keys[keys.length - 1]; - if (o[key] === undefined || flags.bools[key]) { + if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') { o[key] = value; } else if (Array.isArray(o[key])) { From 806712df91604ed02b8e39aa372b84aea659ee34 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Tue, 10 Mar 2015 19:27:22 -0700 Subject: [PATCH 26/60] upgrade tape, fix type issues from old tape version --- package.json | 19 +++++++++++-------- test/all_bool.js | 2 +- test/parse_modified.js | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 739179e..b97622b 100644 --- a/package.json +++ b/package.json @@ -4,21 +4,24 @@ "description": "parse argument options", "main": "index.js", "devDependencies": { - "tape": "~1.0.4", + "covert": "^1.0.0", "tap": "~0.4.0", - "covert": "^1.0.0" + "tape": "^3.5.0" }, "scripts": { "test": "tap test/*.js", "coverage": "covert test/*.js" }, - "testling" : { - "files" : "test/*.js", - "browsers" : [ + "testling": { + "files": "test/*.js", + "browsers": [ "ie/6..latest", - "ff/5", "firefox/latest", - "chrome/10", "chrome/latest", - "safari/5.1", "safari/latest", + "ff/5", + "firefox/latest", + "chrome/10", + "chrome/latest", + "safari/5.1", + "safari/latest", "opera/12" ] }, diff --git a/test/all_bool.js b/test/all_bool.js index 4575ec0..ac83548 100644 --- a/test/all_bool.js +++ b/test/all_bool.js @@ -23,7 +23,7 @@ test('flag boolean true only affects double hyphen arguments without equals sign t.deepEqual(argv, { honk: true, tacos: 'good', - p: '55', + p: 55, _: ['moo', 'cow'] }); diff --git a/test/parse_modified.js b/test/parse_modified.js index 21851b0..ab620dc 100644 --- a/test/parse_modified.js +++ b/test/parse_modified.js @@ -5,5 +5,5 @@ test('parse with modifier functions' , function (t) { t.plan(1); var argv = parse([ '-b', '123' ], { boolean: 'b' }); - t.deepEqual(argv, { b: true, _: ['123'] }); + t.deepEqual(argv, { b: true, _: [123] }); }); From bc9d1c466541eb52ae85e6682a4b809f4c32fe1f Mon Sep 17 00:00:00 2001 From: James Halliday Date: Tue, 10 Mar 2015 19:30:05 -0700 Subject: [PATCH 27/60] 1.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b97622b..4247f4d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.1.0", + "version": "1.1.1", "description": "parse argument options", "main": "index.js", "devDependencies": { From 61ed1d034b9ec7282764ce76f3992b1a0b4906ae Mon Sep 17 00:00:00 2001 From: James Halliday Date: Fri, 3 Apr 2015 14:58:09 -0700 Subject: [PATCH 28/60] use non-ancient npm, node 0.12 and iojs --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index cc4dba2..943a508 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,3 +2,7 @@ language: node_js node_js: - "0.8" - "0.10" + - "0.12" + - "iojs" +before_install: + - npm install -g npm@2.7.5 From 25cf778b1220e7838a526832ad6972f75244054f Mon Sep 17 00:00:00 2001 From: James Halliday Date: Fri, 3 Apr 2015 15:02:48 -0700 Subject: [PATCH 29/60] an older npm for 0.8 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 943a508..74c57bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,4 @@ node_js: - "0.12" - "iojs" before_install: - - npm install -g npm@2.7.5 + - npm install -g npm@~1.4.6 From 8f3dc27cf833f1d54671b6d0bcb55c2fe19672a9 Mon Sep 17 00:00:00 2001 From: Jonas Aschenbrenner Date: Wed, 22 Jul 2015 16:08:47 +0200 Subject: [PATCH 30/60] Convert boolean arguments to boolean values When passing the boolean argument with `--boool=true` or `--boool=false`. --- index.js | 7 ++++++- test/bool.js | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 185a045..bf96360 100644 --- a/index.js +++ b/index.js @@ -93,7 +93,12 @@ module.exports = function (args, opts) { // 'dotall' regex modifier. See: // http://stackoverflow.com/a/1068308/13216 var m = arg.match(/^--([^=]+)=([\s\S]*)$/); - setArg(m[1], m[2], arg); + var key = m[1]; + var value = m[2]; + if (flags.bools[key]) { + value = value !== 'false'; + } + setArg(key, value, arg); } else if (/^--no-.+/.test(arg)) { var key = arg.match(/^--no-(.+)/)[1]; diff --git a/test/bool.js b/test/bool.js index 749e083..5792f88 100644 --- a/test/bool.js +++ b/test/bool.js @@ -117,3 +117,27 @@ test('boolean and --x=true', function(t) { t.same(parsed.other, 'false'); t.end(); }); + +test('boolean --boool=true', function (t) { + var parsed = parse(['--boool=true'], { + default: { + boool: false + }, + boolean: ['boool'] + }); + + t.same(parsed.boool, true); + t.end(); +}); + +test('boolean --boool=false', function (t) { + var parsed = parse(['--boool=false'], { + default: { + boool: true + }, + boolean: ['boool'] + }); + + t.same(parsed.boool, false); + t.end(); +}); From a8e2fe153a22dad7a0da67fd6465fab4cfa63e37 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Wed, 22 Jul 2015 12:54:34 -0700 Subject: [PATCH 31/60] 1.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4247f4d..450972f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.1.1", + "version": "1.1.2", "description": "parse argument options", "main": "index.js", "devDependencies": { From 0fa3c5b3dd98551ddecf5392831b4c21211743fc Mon Sep 17 00:00:00 2001 From: Jeff Barczewski Date: Thu, 6 Aug 2015 12:12:43 -0500 Subject: [PATCH 32/60] add failing test - boolean alias array When using a boolean value that has an array of aliases the aliases swallow the next value ```javascript var regular = [ '--herp', 'derp' ]; var opts = { alias: { 'h': ['herp', 'harp'] }, boolean: 'h' }; var argv = parse(regular, opts); assert.strictEqual(argv.herp, true); // fails with 'derp' assert.strictEqual(argv._[0], 'derp'); // fails undefined ``` --- test/bool.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/bool.js b/test/bool.js index 5792f88..14b0717 100644 --- a/test/bool.js +++ b/test/bool.js @@ -80,6 +80,29 @@ test('boolean and alias with options hash', function (t) { t.end(); }); +test('boolean and alias array with options hash', function (t) { + var aliased = [ '-h', 'derp' ]; + var regular = [ '--herp', 'derp' ]; + var alt = [ '--harp', 'derp' ]; + var opts = { + alias: { 'h': ['herp', 'harp'] }, + boolean: 'h' + }; + var aliasedArgv = parse(aliased, opts); + var propertyArgv = parse(regular, opts); + var altPropertyArgv = parse(alt, opts); + var expected = { + harp: true, + herp: true, + h: true, + '_': [ 'derp' ] + }; + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + t.same(altPropertyArgv, expected); + t.end(); +}); + test('boolean and alias using explicit true', function (t) { var aliased = [ '-h', 'true' ]; var regular = [ '--herp', 'true' ]; From 9c0a6e7de25a273b11bbf9a7464f0bd833779795 Mon Sep 17 00:00:00 2001 From: Jeff Barczewski Date: Thu, 6 Aug 2015 13:06:50 -0500 Subject: [PATCH 33/60] fix boolean values with multiple aliases When using a boolean value that has an array of aliases the aliases show not swallow the next value but should be treated like other booleans ```javascript var regular = [ '--herp', 'derp' ]; var alt = [ '--harp', 'derp' ]; var opts = { alias: { 'h': ['herp', 'harp'] }, boolean: 'h' }; var argv = parse(regular, opts); assert.strictEqual(argv.herp, true); assert.strictEqual(argv.harp, true); assert.strictEqual(argv._[0], 'derp'); var argvAlt = parse(alt, opts); assert.strictEqual(argv.herp, true); assert.strictEqual(argv.harp, true); assert.strictEqual(argv._[0], 'derp'); ``` --- index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index bf96360..de61285 100644 --- a/index.js +++ b/index.js @@ -85,6 +85,12 @@ module.exports = function (args, opts) { } } + function aliasIsBoolean(key) { + return aliases[key].some(function (x) { + return flags.bools[x]; + }); + } + for (var i = 0; i < args.length; i++) { var arg = args[i]; @@ -110,7 +116,7 @@ module.exports = function (args, opts) { if (next !== undefined && !/^-/.test(next) && !flags.bools[key] && !flags.allBools - && (aliases[key] ? !flags.bools[aliases[key]] : true)) { + && (aliases[key] ? !aliasIsBoolean(key) : true)) { setArg(key, next, arg); i++; } @@ -155,7 +161,7 @@ module.exports = function (args, opts) { if (!broken && key !== '-') { if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1]) && !flags.bools[key] - && (aliases[key] ? !flags.bools[aliases[key]] : true)) { + && (aliases[key] ? !aliasIsBoolean(key) : true)) { setArg(key, args[i+1], arg); i++; } From 8a5d94cf17fb8b126cf6c8fbf2a7713df76d16cd Mon Sep 17 00:00:00 2001 From: James Halliday Date: Thu, 6 Aug 2015 16:08:52 -0700 Subject: [PATCH 34/60] 1.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 450972f..1271939 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.1.2", + "version": "1.1.3", "description": "parse argument options", "main": "index.js", "devDependencies": { From 86b321affe648a8e016c095a4f0efa9d9074f502 Mon Sep 17 00:00:00 2001 From: Karissa McKelvey Date: Mon, 24 Aug 2015 14:32:43 +0100 Subject: [PATCH 35/60] enforce space between arg key and value --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index de61285..bc346cb 100644 --- a/index.js +++ b/index.js @@ -148,7 +148,7 @@ module.exports = function (args, opts) { } if (letters[j+1] && letters[j+1].match(/\W/)) { - setArg(letters[j], arg.slice(j+2), arg); + setArg(letters[j], arg.slice(j+3), arg); broken = true; break; } From 63416b8cd1d0d70e4714564cce465a36e4dd26d7 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Mon, 24 Aug 2015 08:48:44 -0500 Subject: [PATCH 36/60] failing -k=v short test --- test/kv_short.js | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 test/kv_short.js diff --git a/test/kv_short.js b/test/kv_short.js new file mode 100644 index 0000000..7442b6d --- /dev/null +++ b/test/kv_short.js @@ -0,0 +1,9 @@ +var parse = require('../'); +var test = require('tape'); + +test('short -k=v' , function (t) { + t.plan(1); + + var argv = parse([ '-b=123' ]); + t.deepEqual(argv, { b: 123, _: [] }); +}); From 6bbe14529166245e86424f220a2321442fe88dc3 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Mon, 24 Aug 2015 08:52:29 -0500 Subject: [PATCH 37/60] kv short fix --- index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index bc346cb..6a0559d 100644 --- a/index.js +++ b/index.js @@ -140,6 +140,12 @@ module.exports = function (args, opts) { continue; } + if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) { + setArg(letters[j], next.split('=')[1], arg); + broken = true; + break; + } + if (/[A-Za-z]/.test(letters[j]) && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { setArg(letters[j], next, arg); @@ -148,7 +154,7 @@ module.exports = function (args, opts) { } if (letters[j+1] && letters[j+1].match(/\W/)) { - setArg(letters[j], arg.slice(j+3), arg); + setArg(letters[j], arg.slice(j+2), arg); broken = true; break; } From f72ab7f4572adc52902c9b6873cc969192f01b10 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Mon, 24 Aug 2015 08:53:37 -0500 Subject: [PATCH 38/60] failing kv short test --- test/kv_short.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/kv_short.js b/test/kv_short.js index 7442b6d..b32cae5 100644 --- a/test/kv_short.js +++ b/test/kv_short.js @@ -7,3 +7,10 @@ test('short -k=v' , function (t) { var argv = parse([ '-b=123' ]); t.deepEqual(argv, { b: 123, _: [] }); }); + +test('multi short -k=v' , function (t) { + t.plan(1); + + var argv = parse([ '-a=whatever -b=robots' ]); + t.deepEqual(argv, { a: 'whatever', b: 'robots', _: [] }); +}); From f5a48c3e50e40ca54f00c8e84de4b4d6e9897fa8 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Mon, 24 Aug 2015 08:56:31 -0500 Subject: [PATCH 39/60] fixed kv test --- test/kv_short.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kv_short.js b/test/kv_short.js index b32cae5..f813b30 100644 --- a/test/kv_short.js +++ b/test/kv_short.js @@ -11,6 +11,6 @@ test('short -k=v' , function (t) { test('multi short -k=v' , function (t) { t.plan(1); - var argv = parse([ '-a=whatever -b=robots' ]); + var argv = parse([ '-a=whatever', '-b=robots' ]); t.deepEqual(argv, { a: 'whatever', b: 'robots', _: [] }); }); From dc624482fcfec5bc669c68cdb861f00573ed4e64 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Mon, 24 Aug 2015 08:56:42 -0500 Subject: [PATCH 40/60] 1.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1271939..326480c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.1.3", + "version": "1.2.0", "description": "parse argument options", "main": "index.js", "devDependencies": { From 5fa440ef0f7d067e12baa6694570e7ce7b453340 Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Sat, 29 Aug 2015 09:18:22 +0200 Subject: [PATCH 41/60] move the `opts['--']` example back where it belongs It was accidentally separated from the `opts['--']` bullet point be the new option added in commit 6f3cc5d4. --- readme.markdown | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/readme.markdown b/readme.markdown index 30a74cf..2bcb88f 100644 --- a/readme.markdown +++ b/readme.markdown @@ -65,19 +65,20 @@ argument names to use as aliases first non-option * `opts['--']` - when true, populate `argv._` with everything before the `--` and `argv['--']` with everything after the `--`. Here's an example: + + ``` + > require('./')('one two three -- four five --six'.split(' '), { '--': true }) + { _: [ 'one', 'two', 'three' ], + '--': [ 'four', 'five', '--six' ] } + ``` + + Note that with `opts['--']` set, parsing for arguments still stops after the + `--`. + * `opts.unknown` - a function which is invoked with a command line parameter not defined in the `opts` configuration object. If the function returns `false`, the unknown option is not added to `argv`. -``` -> require('./')('one two three -- four five --six'.split(' '), { '--': true }) -{ _: [ 'one', 'two', 'three' ], - '--': [ 'four', 'five', '--six' ] } -``` - -Note that with `opts['--']` set, parsing for arguments still stops after the -`--`. - # install With [npm](https://npmjs.org) do: From ac3fc796e63b95128fdbdf67ea7fad71bd59aa76 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 7 Aug 2019 11:12:37 +0200 Subject: [PATCH 42/60] fix bad boolean regexp --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 6a0559d..388a963 100644 --- a/index.js +++ b/index.js @@ -171,7 +171,7 @@ module.exports = function (args, opts) { setArg(key, args[i+1], arg); i++; } - else if (args[i+1] && /true|false/.test(args[i+1])) { + else if (args[i+1] && /^(true|false)$/.test(args[i+1])) { setArg(key, args[i+1] === 'true', arg); i++; } From 6be5dae35a32a987bcf4137fcd6c19c5200ee909 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 7 Aug 2019 11:35:33 +0200 Subject: [PATCH 43/60] add test --- test/bool.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/bool.js b/test/bool.js index 14b0717..5f7dbde 100644 --- a/test/bool.js +++ b/test/bool.js @@ -164,3 +164,15 @@ test('boolean --boool=false', function (t) { t.same(parsed.boool, false); t.end(); }); + +test('boolean using something similar to true', function (t) { + var opts = { boolean: 'h' }; + var result = parse(['-h', 'true.txt'], opts); + var expected = { + h: true, + '_': ['true.txt'] + }; + + t.same(result, expected); + t.end(); +}); \ No newline at end of file From 29783cdf94cc9a0663bb31f5eb9a4eff9c515bf6 Mon Sep 17 00:00:00 2001 From: substack Date: Tue, 10 Mar 2020 08:05:49 -1000 Subject: [PATCH 44/60] 1.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 326480c..bc64cf7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.2.0", + "version": "1.2.1", "description": "parse argument options", "main": "index.js", "devDependencies": { From 0efed0340ec8433638758f7ca0c77cb20a0bfbab Mon Sep 17 00:00:00 2001 From: substack Date: Tue, 10 Mar 2020 08:23:44 -1000 Subject: [PATCH 45/60] failing test for protocol pollution --- test/proto.js | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 test/proto.js diff --git a/test/proto.js b/test/proto.js new file mode 100644 index 0000000..015ea60 --- /dev/null +++ b/test/proto.js @@ -0,0 +1,8 @@ +var parse = require('../'); +var test = require('tape'); + +test('proto pollution', function (t) { + var argv = parse(['--__proto__.x','123']); + t.equal({}.x, undefined); + t.end(); +}); From 47acf72c715a630bf9ea013867f47f1dd69dfc54 Mon Sep 17 00:00:00 2001 From: substack Date: Tue, 10 Mar 2020 08:24:38 -1000 Subject: [PATCH 46/60] console.dir -> console.log --- example/parse.js | 2 +- readme.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/parse.js b/example/parse.js index abff3e8..f7c8d49 100644 --- a/example/parse.js +++ b/example/parse.js @@ -1,2 +1,2 @@ var argv = require('../')(process.argv.slice(2)); -console.dir(argv); +console.log(argv); diff --git a/readme.markdown b/readme.markdown index 2bcb88f..dba4e5e 100644 --- a/readme.markdown +++ b/readme.markdown @@ -13,7 +13,7 @@ fanciful decoration. ``` js var argv = require('minimist')(process.argv.slice(2)); -console.dir(argv); +console.log(argv); ``` ``` From 63e7ed05aa4b1889ec2f3b196426db4500cbda94 Mon Sep 17 00:00:00 2001 From: substack Date: Tue, 10 Mar 2020 08:36:30 -1000 Subject: [PATCH 47/60] don't assign onto __proto__ --- index.js | 1 + test/proto.js | 1 + 2 files changed, 2 insertions(+) diff --git a/index.js b/index.js index 388a963..3b13f44 100644 --- a/index.js +++ b/index.js @@ -70,6 +70,7 @@ module.exports = function (args, opts) { var o = obj; keys.slice(0,-1).forEach(function (key) { if (o[key] === undefined) o[key] = {}; + if (o[key] === {}.__proto__) o[key] = {}; o = o[key]; }); diff --git a/test/proto.js b/test/proto.js index 015ea60..87490c3 100644 --- a/test/proto.js +++ b/test/proto.js @@ -4,5 +4,6 @@ var test = require('tape'); test('proto pollution', function (t) { var argv = parse(['--__proto__.x','123']); t.equal({}.x, undefined); + t.equal(argv.__proto__.x, 123); t.end(); }); From 67d3722413448d00a62963d2d30c34656a92d7e2 Mon Sep 17 00:00:00 2001 From: substack Date: Tue, 10 Mar 2020 08:36:41 -1000 Subject: [PATCH 48/60] cleanup --- readme.markdown | 4 ---- 1 file changed, 4 deletions(-) diff --git a/readme.markdown b/readme.markdown index dba4e5e..c58e258 100644 --- a/readme.markdown +++ b/readme.markdown @@ -5,10 +5,6 @@ parse argument options This module is the guts of optimist's argument parser without all the fanciful decoration. -[![browser support](https://ci.testling.com/substack/minimist.png)](http://ci.testling.com/substack/minimist) - -[![build status](https://secure.travis-ci.org/substack/minimist.png)](http://travis-ci.org/substack/minimist) - # example ``` js From f34df077a6b2bee1344188849a95e66777109e89 Mon Sep 17 00:00:00 2001 From: substack Date: Tue, 10 Mar 2020 08:36:58 -1000 Subject: [PATCH 49/60] 1.2.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bc64cf7..1750cc2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.2.1", + "version": "1.2.2", "description": "parse argument options", "main": "index.js", "devDependencies": { From 13c01a5327736903704984b7f65616b8476850cc Mon Sep 17 00:00:00 2001 From: substack Date: Tue, 10 Mar 2020 09:04:33 -1000 Subject: [PATCH 50/60] more failing proto pollution tests --- test/proto.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/proto.js b/test/proto.js index 87490c3..a2499ec 100644 --- a/test/proto.js +++ b/test/proto.js @@ -5,5 +5,33 @@ test('proto pollution', function (t) { var argv = parse(['--__proto__.x','123']); t.equal({}.x, undefined); t.equal(argv.__proto__.x, 123); + t.equal(argv.x, undefined); + t.end(); +}); + +test('proto pollution (array)', function (t) { + var argv = parse(['--x','4','--x','5','--x.__proto__.z','789']); + t.equal({}.z, undefined); + t.deepEqual(argv.x, [4,5]); + t.equal(argv.x.z, undefined); + t.equal(argv.x.__proto__.z, 789); + t.end(); +}); + +test('proto pollution (number)', function (t) { + var argv = parse(['--x','5','--x.__proto__.z','100']); + t.equal({}.z, undefined); + t.equal((4).z, undefined); + t.equal(argv.x, 5); + t.equal(argv.x.z, undefined); + t.end(); +}); + +test('proto pollution (string)', function (t) { + var argv = parse(['--x','abc','--x.__proto__.z','def']); + t.equal({}.z, undefined); + t.equal('...'.z, undefined); + t.equal(argv.x, 'abc'); + t.equal(argv.x.z, undefined); t.end(); }); From 38a4d1caead72ef99e824bb420a2528eec03d9ab Mon Sep 17 00:00:00 2001 From: substack Date: Tue, 10 Mar 2020 09:08:00 -1000 Subject: [PATCH 51/60] even more aggressive checks for protocol pollution --- index.js | 14 +++++++++++--- test/proto.js | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 3b13f44..d2afe5e 100644 --- a/index.js +++ b/index.js @@ -68,13 +68,21 @@ module.exports = function (args, opts) { function setKey (obj, keys, value) { var o = obj; - keys.slice(0,-1).forEach(function (key) { + for (var i = 0; i < keys.length-1; i++) { + var key = keys[i]; + if (key === '__proto__') return; if (o[key] === undefined) o[key] = {}; - if (o[key] === {}.__proto__) o[key] = {}; + if (o[key] === Object.prototype || o[key] === Number.prototype + || o[key] === String.prototype) o[key] = {}; + if (o[key] === Array.prototype) o[key] = []; o = o[key]; - }); + } var key = keys[keys.length - 1]; + if (key === '__proto__') return; + if (o === Object.prototype || o === Number.prototype + || o === String.prototype) o = {}; + if (o === Array.prototype) o = []; if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') { o[key] = value; } diff --git a/test/proto.js b/test/proto.js index a2499ec..7713559 100644 --- a/test/proto.js +++ b/test/proto.js @@ -4,7 +4,7 @@ var test = require('tape'); test('proto pollution', function (t) { var argv = parse(['--__proto__.x','123']); t.equal({}.x, undefined); - t.equal(argv.__proto__.x, 123); + t.equal(argv.__proto__.x, undefined); t.equal(argv.x, undefined); t.end(); }); @@ -14,7 +14,7 @@ test('proto pollution (array)', function (t) { t.equal({}.z, undefined); t.deepEqual(argv.x, [4,5]); t.equal(argv.x.z, undefined); - t.equal(argv.x.__proto__.z, 789); + t.equal(argv.x.__proto__.z, undefined); t.end(); }); From 6457d7440a47f329c12c4a5abfbce211c4235b93 Mon Sep 17 00:00:00 2001 From: substack Date: Tue, 10 Mar 2020 09:08:08 -1000 Subject: [PATCH 52/60] 1.2.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1750cc2..8c70ca3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.2.2", + "version": "1.2.3", "description": "parse argument options", "main": "index.js", "devDependencies": { From 1043d212c3caaf871966e710f52cfdf02f9eea4b Mon Sep 17 00:00:00 2001 From: substack Date: Wed, 11 Mar 2020 09:20:03 -1000 Subject: [PATCH 53/60] additional test for constructor prototype pollution --- test/proto.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/proto.js b/test/proto.js index 7713559..8649107 100644 --- a/test/proto.js +++ b/test/proto.js @@ -35,3 +35,10 @@ test('proto pollution (string)', function (t) { t.equal(argv.x.z, undefined); t.end(); }); + +test('proto pollution (constructor)', function (t) { + var argv = parse(['--constructor.prototype.y','123']); + t.equal({}.y, undefined); + t.equal(argv.y, undefined); + t.end(); +}); From 4cf1354839cb972e38496d35e12f806eea92c11f Mon Sep 17 00:00:00 2001 From: substack Date: Wed, 11 Mar 2020 09:24:47 -1000 Subject: [PATCH 54/60] security notice --- readme.markdown | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/readme.markdown b/readme.markdown index c58e258..5fd97ab 100644 --- a/readme.markdown +++ b/readme.markdown @@ -29,6 +29,13 @@ $ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz beep: 'boop' } ``` +# security + +Previous versions had a prototype pollution bug that could cause privilege +escalation in some circumstances when handling untrusted user input. + +Please use version 1.2.3 or later: https://snyk.io/vuln/SNYK-JS-MINIMIST-559764 + # methods ``` js From 278677b171d956b46613a158c6c486c3ef979b20 Mon Sep 17 00:00:00 2001 From: substack Date: Wed, 11 Mar 2020 09:24:53 -1000 Subject: [PATCH 55/60] 1.2.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c70ca3..0e6f8f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.2.3", + "version": "1.2.4", "description": "parse argument options", "main": "index.js", "devDependencies": { From aeb3e27dae0412de5c0494e9563a5f10c82cc7a9 Mon Sep 17 00:00:00 2001 From: substack Date: Thu, 12 Mar 2020 12:16:00 -1000 Subject: [PATCH 56/60] 1.2.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0e6f8f0..c091d41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.2.4", + "version": "1.2.5", "description": "parse argument options", "main": "index.js", "devDependencies": { From bc8ecee43875261f4f17eb20b1243d3ed15e70eb Mon Sep 17 00:00:00 2001 From: substack Date: Mon, 21 Mar 2022 16:38:16 -1000 Subject: [PATCH 57/60] test from prototype pollution PR --- test/proto.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/proto.js b/test/proto.js index 8649107..4ac62df 100644 --- a/test/proto.js +++ b/test/proto.js @@ -42,3 +42,19 @@ test('proto pollution (constructor)', function (t) { t.equal(argv.y, undefined); t.end(); }); + +test('proto pollution (constructor function)', function (t) { + var argv = parse(['--_.concat.constructor.prototype.y', '123']); + function fnToBeTested() {} + t.equal(fnToBeTested.y, undefined); + t.equal(argv.y, undefined); + t.end(); +}); + +// powered by snyk - https://github.com/backstage/backstage/issues/10343 +test('proto pollution (constructor function) snyk', function (t) { + var argv = parse('--_.constructor.constructor.prototype.foo bar'.split(' ')); + t.equal((function(){}).foo, undefined); + t.equal(argv.y, undefined); + t.end(); +}) From c2b981977fa834b223b408cfb860f933c9811e4d Mon Sep 17 00:00:00 2001 From: substack Date: Mon, 21 Mar 2022 16:45:18 -1000 Subject: [PATCH 58/60] isConstructorOrProto adapted from PR --- index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index d2afe5e..d9c3eb7 100644 --- a/index.js +++ b/index.js @@ -70,7 +70,7 @@ module.exports = function (args, opts) { var o = obj; for (var i = 0; i < keys.length-1; i++) { var key = keys[i]; - if (key === '__proto__') return; + if (isConstructorOrProto(o, key)) return; if (o[key] === undefined) o[key] = {}; if (o[key] === Object.prototype || o[key] === Number.prototype || o[key] === String.prototype) o[key] = {}; @@ -79,7 +79,7 @@ module.exports = function (args, opts) { } var key = keys[keys.length - 1]; - if (key === '__proto__') return; + if (isConstructorOrProto(o, key)) return; if (o === Object.prototype || o === Number.prototype || o === String.prototype) o = {}; if (o === Array.prototype) o = []; @@ -243,3 +243,7 @@ function isNumber (x) { return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); } + +function isConstructorOrProto (obj, key) { + return key === 'constructor' && typeof obj[key] === 'function' || key === '__proto__'; +} From ef88b9325f77b5ee643ccfc97e2ebda577e4c4e2 Mon Sep 17 00:00:00 2001 From: substack Date: Mon, 21 Mar 2022 16:45:32 -1000 Subject: [PATCH 59/60] security notice for additional prototype pollution issue --- readme.markdown | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 5fd97ab..859d1ab 100644 --- a/readme.markdown +++ b/readme.markdown @@ -34,7 +34,10 @@ $ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz Previous versions had a prototype pollution bug that could cause privilege escalation in some circumstances when handling untrusted user input. -Please use version 1.2.3 or later: https://snyk.io/vuln/SNYK-JS-MINIMIST-559764 +Please use version 1.2.6 or later: + +* https://security.snyk.io/vuln/SNYK-JS-MINIMIST-2429795 (version <=1.2.5) +* https://snyk.io/vuln/SNYK-JS-MINIMIST-559764 (version <=1.2.3) # methods From 7efb22a518b53b06f5b02a1038a88bd6290c2846 Mon Sep 17 00:00:00 2001 From: substack Date: Mon, 21 Mar 2022 16:45:59 -1000 Subject: [PATCH 60/60] 1.2.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c091d41..c225853 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minimist", - "version": "1.2.5", + "version": "1.2.6", "description": "parse argument options", "main": "index.js", "devDependencies": {