diff --git a/index.js b/index.js index ac5b0ad..87f12bd 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,6 @@ const { ArrayPrototypeShift, ArrayPrototypeSlice, ArrayPrototypePush, - ObjectDefineProperty, ObjectEntries, ObjectPrototypeHasOwnProperty: ObjectHasOwn, StringPrototypeCharAt, @@ -117,19 +116,9 @@ function checkOptionUsage(longOption, optionValue, options, */ function storeOption(longOption, optionValue, options, values) { if (longOption === '__proto__') { - return; + return; // No. Just no. } - // Can be removed when value has a null prototype - const safeAssignProperty = (obj, prop, value) => { - ObjectDefineProperty(obj, prop, { - value, - writable: true, - enumerable: true, - configurable: true - }); - }; - // We store based on the option value rather than option type, // preserving the users intent for author to deal with. const newValue = optionValue ?? true; @@ -138,13 +127,14 @@ function storeOption(longOption, optionValue, options, values) { // values[longOption] starts out not present, // first value is added as new array [newValue], // subsequent values are pushed to existing array. - if (ObjectHasOwn(values, longOption)) { + // (note: values has null prototype, so simpler usage) + if (values[longOption]) { ArrayPrototypePush(values[longOption], newValue); } else { - safeAssignProperty(values, longOption, [newValue]); + values[longOption] = [newValue]; } } else { - safeAssignProperty(values, longOption, newValue); + values[longOption] = newValue; } } @@ -184,7 +174,7 @@ const parseArgs = (config = { __proto__: null }) => { ); const result = { - values: {}, + values: { __proto__: null }, positionals: [] }; diff --git a/test/dash.js b/test/dash.js index 931b04f..dab82b2 100644 --- a/test/dash.js +++ b/test/dash.js @@ -12,10 +12,10 @@ const { parseArgs } = require('../index.js'); // A different usage and example is `git switch -` to switch back to the previous branch. test("dash: when args include '-' used as positional then result has '-' in positionals", (t) => { - const passedArgs = ['-']; - const expected = { values: {}, positionals: ['-'] }; + const args = ['-']; + const expected = { values: { __proto__: null }, positionals: ['-'] }; - const result = parseArgs({ args: passedArgs }); + const result = parseArgs({ args }); t.deepEqual(result, expected); t.end(); @@ -23,11 +23,11 @@ test("dash: when args include '-' used as positional then result has '-' in posi // If '-' is a valid positional, it is symmetrical to allow it as an option value too. test("dash: when args include '-' used as space-separated option value then result has '-' in option value", (t) => { - const passedArgs = ['-v', '-']; - const passedOptions = { v: { type: 'string' } }; - const expected = { values: { v: '-' }, positionals: [] }; + const args = ['-v', '-']; + const options = { v: { type: 'string' } }; + const expected = { values: { __proto__: null, v: '-' }, positionals: [] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); diff --git a/test/index.js b/test/index.js index 492eeb9..0d2be1b 100644 --- a/test/index.js +++ b/test/index.js @@ -8,200 +8,200 @@ const { parseArgs } = require('../index'); // Test results are as we expect test('when short option used as flag then stored as flag', () => { - const passedArgs = ['-f']; - const expected = { values: { f: true }, positionals: [] }; - const args = parseArgs({ strict: false, args: passedArgs }); - assert.deepStrictEqual(args, expected); + const args = ['-f']; + const expected = { values: { __proto__: null, f: true }, positionals: [] }; + const result = parseArgs({ strict: false, args }); + assert.deepStrictEqual(result, expected); }); test('when short option used as flag before positional then stored as flag and positional (and not value)', () => { - const passedArgs = ['-f', 'bar']; - const expected = { values: { f: true }, positionals: [ 'bar' ] }; - const args = parseArgs({ strict: false, args: passedArgs }); - assert.deepStrictEqual(args, expected); + const args = ['-f', 'bar']; + const expected = { values: { __proto__: null, f: true }, positionals: [ 'bar' ] }; + const result = parseArgs({ strict: false, args }); + assert.deepStrictEqual(result, expected); }); test('when short option `type: "string"` used with value then stored as value', () => { - const passedArgs = ['-f', 'bar']; - const passedOptions = { f: { type: 'string' } }; - const expected = { values: { f: 'bar' }, positionals: [] }; - const args = parseArgs({ args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const args = ['-f', 'bar']; + const options = { f: { type: 'string' } }; + const expected = { values: { __proto__: null, f: 'bar' }, positionals: [] }; + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expected); }); test('when short option listed in short used as flag then long option stored as flag', () => { - const passedArgs = ['-f']; - const passedOptions = { foo: { short: 'f', type: 'boolean' } }; - const expected = { values: { foo: true }, positionals: [] }; - const args = parseArgs({ args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const args = ['-f']; + const options = { foo: { short: 'f', type: 'boolean' } }; + const expected = { values: { __proto__: null, foo: true }, positionals: [] }; + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expected); }); test('when short option listed in short and long listed in `type: "string"` and ' + 'used with value then long option stored as value', () => { - const passedArgs = ['-f', 'bar']; - const passedOptions = { foo: { short: 'f', type: 'string' } }; - const expected = { values: { foo: 'bar' }, positionals: [] }; - const args = parseArgs({ args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const args = ['-f', 'bar']; + const options = { foo: { short: 'f', type: 'string' } }; + const expected = { values: { __proto__: null, foo: 'bar' }, positionals: [] }; + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expected); }); test('when short option `type: "string"` used without value then stored as flag', () => { - const passedArgs = ['-f']; - const passedOptions = { f: { type: 'string' } }; - const expected = { values: { f: true }, positionals: [] }; - const args = parseArgs({ strict: false, args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const args = ['-f']; + const options = { f: { type: 'string' } }; + const expected = { values: { __proto__: null, f: true }, positionals: [] }; + const result = parseArgs({ strict: false, args, options }); + assert.deepStrictEqual(result, expected); }); test('short option group behaves like multiple short options', () => { - const passedArgs = ['-rf']; - const passedOptions = { }; - const expected = { values: { r: true, f: true }, positionals: [] }; - const args = parseArgs({ strict: false, args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const args = ['-rf']; + const options = { }; + const expected = { values: { __proto__: null, r: true, f: true }, positionals: [] }; + const result = parseArgs({ strict: false, args, options }); + assert.deepStrictEqual(result, expected); }); test('short option group does not consume subsequent positional', () => { - const passedArgs = ['-rf', 'foo']; - const passedOptions = { }; - const expected = { values: { r: true, f: true }, positionals: ['foo'] }; - const args = parseArgs({ strict: false, args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const args = ['-rf', 'foo']; + const options = { }; + const expected = { values: { __proto__: null, r: true, f: true }, positionals: ['foo'] }; + const result = parseArgs({ strict: false, args, options }); + assert.deepStrictEqual(result, expected); }); // See: Guideline 5 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html test('if terminal of short-option group configured `type: "string"`, subsequent positional is stored', () => { - const passedArgs = ['-rvf', 'foo']; - const passedOptions = { f: { type: 'string' } }; - const expected = { values: { r: true, v: true, f: 'foo' }, positionals: [] }; - const args = parseArgs({ strict: false, args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const args = ['-rvf', 'foo']; + const options = { f: { type: 'string' } }; + const expected = { values: { __proto__: null, r: true, v: true, f: 'foo' }, positionals: [] }; + const result = parseArgs({ strict: false, args, options }); + assert.deepStrictEqual(result, expected); }); test('handles short-option groups in conjunction with long-options', () => { - const passedArgs = ['-rf', '--foo', 'foo']; - const passedOptions = { foo: { type: 'string' } }; - const expected = { values: { r: true, f: true, foo: 'foo' }, positionals: [] }; - const args = parseArgs({ strict: false, args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const args = ['-rf', '--foo', 'foo']; + const options = { foo: { type: 'string' } }; + const expected = { values: { __proto__: null, r: true, f: true, foo: 'foo' }, positionals: [] }; + const result = parseArgs({ strict: false, args, options }); + assert.deepStrictEqual(result, expected); }); test('handles short-option groups with "short" alias configured', () => { - const passedArgs = ['-rf']; - const passedOptions = { remove: { short: 'r', type: 'boolean' } }; - const expected = { values: { remove: true, f: true }, positionals: [] }; - const args = parseArgs({ strict: false, args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const args = ['-rf']; + const options = { remove: { short: 'r', type: 'boolean' } }; + const expected = { values: { __proto__: null, remove: true, f: true }, positionals: [] }; + const result = parseArgs({ strict: false, args, options }); + assert.deepStrictEqual(result, expected); }); test('Everything after a bare `--` is considered a positional argument', () => { - const passedArgs = ['--', 'barepositionals', 'mopositionals']; - const expected = { values: {}, positionals: ['barepositionals', 'mopositionals'] }; - const args = parseArgs({ args: passedArgs }); - assert.deepStrictEqual(args, expected, Error('testing bare positionals')); + const args = ['--', 'barepositionals', 'mopositionals']; + const expected = { values: { __proto__: null }, positionals: ['barepositionals', 'mopositionals'] }; + const result = parseArgs({ args }); + assert.deepStrictEqual(result, expected, Error('testing bare positionals')); }); test('args are true', () => { - const passedArgs = ['--foo', '--bar']; - const expected = { values: { foo: true, bar: true }, positionals: [] }; - const args = parseArgs({ strict: false, args: passedArgs }); - assert.deepStrictEqual(args, expected, Error('args are true')); + const args = ['--foo', '--bar']; + const expected = { values: { __proto__: null, foo: true, bar: true }, positionals: [] }; + const result = parseArgs({ strict: false, args }); + assert.deepStrictEqual(result, expected, Error('args are true')); }); test('arg is true and positional is identified', () => { - const passedArgs = ['--foo=a', '--foo', 'b']; - const expected = { values: { foo: true }, positionals: ['b'] }; - const args = parseArgs({ strict: false, args: passedArgs }); - assert.deepStrictEqual(args, expected, Error('arg is true and positional is identified')); + const args = ['--foo=a', '--foo', 'b']; + const expected = { values: { __proto__: null, foo: true }, positionals: ['b'] }; + const result = parseArgs({ strict: false, args }); + assert.deepStrictEqual(result, expected, Error('arg is true and positional is identified')); }); test('args equals are passed `type: "string"`', () => { - const passedArgs = ['--so=wat']; - const passedOptions = { so: { type: 'string' } }; - const expected = { values: { so: 'wat' }, positionals: [] }; - const args = parseArgs({ args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected, Error('arg value is passed')); + const args = ['--so=wat']; + const options = { so: { type: 'string' } }; + const expected = { values: { __proto__: null, so: 'wat' }, positionals: [] }; + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expected, Error('arg value is passed')); }); test('when args include single dash then result stores dash as positional', () => { - const passedArgs = ['-']; - const expected = { values: { }, positionals: ['-'] }; - const args = parseArgs({ args: passedArgs }); - assert.deepStrictEqual(args, expected); + const args = ['-']; + const expected = { values: { __proto__: null }, positionals: ['-'] }; + const result = parseArgs({ args }); + assert.deepStrictEqual(result, expected); }); test('zero config args equals are parsed as if `type: "string"`', () => { - const passedArgs = ['--so=wat']; - const passedOptions = { }; - const expected = { values: { so: 'wat' }, positionals: [] }; - const args = parseArgs({ strict: false, args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected, Error('arg value is passed')); + const args = ['--so=wat']; + const options = { }; + const expected = { values: { __proto__: null, so: 'wat' }, positionals: [] }; + const result = parseArgs({ strict: false, args, options }); + assert.deepStrictEqual(result, expected, Error('arg value is passed')); }); test('same arg is passed twice `type: "string"` and last value is recorded', () => { - const passedArgs = ['--foo=a', '--foo', 'b']; - const passedOptions = { foo: { type: 'string' } }; - const expected = { values: { foo: 'b' }, positionals: [] }; - const args = parseArgs({ args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected, Error('last arg value is passed')); + const args = ['--foo=a', '--foo', 'b']; + const options = { foo: { type: 'string' } }; + const expected = { values: { __proto__: null, foo: 'b' }, positionals: [] }; + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expected, Error('last arg value is passed')); }); test('args equals pass string including more equals', () => { - const passedArgs = ['--so=wat=bing']; - const passedOptions = { so: { type: 'string' } }; - const expected = { values: { so: 'wat=bing' }, positionals: [] }; - const args = parseArgs({ args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected, Error('arg value is passed')); + const args = ['--so=wat=bing']; + const options = { so: { type: 'string' } }; + const expected = { values: { __proto__: null, so: 'wat=bing' }, positionals: [] }; + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expected, Error('arg value is passed')); }); test('first arg passed for `type: "string"` and "multiple" is in array', () => { - const passedArgs = ['--foo=a']; - const passedOptions = { foo: { type: 'string', multiple: true } }; - const expected = { values: { foo: ['a'] }, positionals: [] }; - const args = parseArgs({ args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected, Error('first multiple in array')); + const args = ['--foo=a']; + const options = { foo: { type: 'string', multiple: true } }; + const expected = { values: { __proto__: null, foo: ['a'] }, positionals: [] }; + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expected, Error('first multiple in array')); }); test('args are passed `type: "string"` and "multiple"', () => { - const passedArgs = ['--foo=a', '--foo', 'b']; - const passedOptions = { + const args = ['--foo=a', '--foo', 'b']; + const options = { foo: { type: 'string', multiple: true, }, }; - const expected = { values: { foo: ['a', 'b'] }, positionals: [] }; - const args = parseArgs({ args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected, Error('both arg values are passed')); + const expected = { values: { __proto__: null, foo: ['a', 'b'] }, positionals: [] }; + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expected, Error('both arg values are passed')); }); test('when expecting `multiple:true` boolean option and option used multiple times then result includes array of ' + 'booleans matching usage', () => { - const passedArgs = ['--foo', '--foo']; - const passedOptions = { + const args = ['--foo', '--foo']; + const options = { foo: { type: 'boolean', multiple: true, }, }; - const expected = { values: { foo: [true, true] }, positionals: [] }; - const args = parseArgs({ args: passedArgs, options: passedOptions }); - assert.deepStrictEqual(args, expected); + const expected = { values: { __proto__: null, foo: [true, true] }, positionals: [] }; + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expected); }); test('order of option and positional does not matter (per README)', () => { - const passedArgs1 = ['--foo=bar', 'baz']; - const passedArgs2 = ['baz', '--foo=bar']; - const passedOptions = { foo: { type: 'string' } }; - const expected = { values: { foo: 'bar' }, positionals: ['baz'] }; + const args1 = ['--foo=bar', 'baz']; + const args2 = ['baz', '--foo=bar']; + const options = { foo: { type: 'string' } }; + const expected = { values: { __proto__: null, foo: 'bar' }, positionals: ['baz'] }; assert.deepStrictEqual( - parseArgs({ args: passedArgs1, options: passedOptions }), + parseArgs({ args: args1, options }), expected, Error('option then positional') ); assert.deepStrictEqual( - parseArgs({ args: passedArgs2, options: passedOptions }), + parseArgs({ args: args2, options }), expected, Error('positional then option') ); @@ -214,7 +214,7 @@ test('correct default args when use node -p', () => { process.execArgv = ['-p', '0']; const result = parseArgs({ strict: false }); - const expected = { values: { foo: true }, + const expected = { values: { __proto__: null, foo: true }, positionals: [] }; assert.deepStrictEqual(result, expected); process.argv = holdArgv; @@ -228,7 +228,7 @@ test('correct default args when use node --print', () => { process.execArgv = ['--print', '0']; const result = parseArgs({ strict: false }); - const expected = { values: { foo: true }, + const expected = { values: { __proto__: null, foo: true }, positionals: [] }; assert.deepStrictEqual(result, expected); process.argv = holdArgv; @@ -242,7 +242,7 @@ test('correct default args when use node -e', () => { process.execArgv = ['-e', '0']; const result = parseArgs({ strict: false }); - const expected = { values: { foo: true }, + const expected = { values: { __proto__: null, foo: true }, positionals: [] }; assert.deepStrictEqual(result, expected); process.argv = holdArgv; @@ -255,7 +255,7 @@ test('correct default args when use node --eval', () => { const holdExecArgv = process.execArgv; process.execArgv = ['--eval', '0']; const result = parseArgs({ strict: false }); - const expected = { values: { foo: true }, + const expected = { values: { __proto__: null, foo: true }, positionals: [] }; assert.deepStrictEqual(result, expected); process.argv = holdArgv; @@ -269,7 +269,7 @@ test('correct default args when normal arguments', () => { process.execArgv = []; const result = parseArgs({ strict: false }); - const expected = { values: { foo: true }, + const expected = { values: { __proto__: null, foo: true }, positionals: [] }; assert.deepStrictEqual(result, expected); process.argv = holdArgv; @@ -278,22 +278,22 @@ test('correct default args when normal arguments', () => { test('excess leading dashes on options are retained', () => { // Enforce a design decision for an edge case. - const passedArgs = ['---triple']; - const passedOptions = { }; + const args = ['---triple']; + const options = { }; const expected = { - values: { '-triple': true }, + values: { '__proto__': null, '-triple': true }, positionals: [] }; - const result = parseArgs({ strict: false, args: passedArgs, options: passedOptions }); + const result = parseArgs({ strict: false, args, options }); assert.deepStrictEqual(result, expected, Error('excess option dashes are retained')); }); // Test bad inputs test('invalid argument passed for options', () => { - const passedArgs = ['--so=wat']; - const passedOptions = 'bad value'; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = ['--so=wat']; + const options = 'bad value'; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_INVALID_ARG_TYPE' }); }); @@ -306,17 +306,17 @@ test('type property missing for option then throw', () => { }); test('boolean passed to "type" option', () => { - const passedArgs = ['--so=wat']; - const passedOptions = { foo: { type: true } }; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = ['--so=wat']; + const options = { foo: { type: true } }; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_INVALID_ARG_TYPE' }); }); test('invalid union value passed to "type" option', () => { - const passedArgs = ['--so=wat']; - const passedOptions = { foo: { type: 'str' } }; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = ['--so=wat']; + const options = { foo: { type: 'str' } }; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_INVALID_ARG_TYPE' }); }); @@ -324,57 +324,71 @@ test('invalid union value passed to "type" option', () => { // Test strict mode test('unknown long option --bar', () => { - const passedArgs = ['--foo', '--bar']; - const passedOptions = { foo: { type: 'boolean' } }; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = ['--foo', '--bar']; + const options = { foo: { type: 'boolean' } }; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_PARSE_ARGS_UNKNOWN_OPTION' }); }); test('unknown short option -b', () => { - const passedArgs = ['--foo', '-b']; - const passedOptions = { foo: { type: 'boolean' } }; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = ['--foo', '-b']; + const options = { foo: { type: 'boolean' } }; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_PARSE_ARGS_UNKNOWN_OPTION' }); }); test('unknown option -r in short option group -bar', () => { - const passedArgs = ['-bar']; - const passedOptions = { b: { type: 'boolean' }, a: { type: 'boolean' } }; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = ['-bar']; + const options = { b: { type: 'boolean' }, a: { type: 'boolean' } }; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_PARSE_ARGS_UNKNOWN_OPTION' }); }); test('unknown option with explicit value', () => { - const passedArgs = ['--foo', '--bar=baz']; - const passedOptions = { foo: { type: 'boolean' } }; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = ['--foo', '--bar=baz']; + const options = { foo: { type: 'boolean' } }; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_PARSE_ARGS_UNKNOWN_OPTION' }); }); test('string option used as boolean', () => { - const passedArgs = ['--foo']; - const passedOptions = { foo: { type: 'string' } }; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = ['--foo']; + const options = { foo: { type: 'string' } }; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_PARSE_ARGS_INVALID_OPTION_VALUE' }); }); test('boolean option used with value', () => { - const passedArgs = ['--foo=bar']; - const passedOptions = { foo: { type: 'boolean' } }; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = ['--foo=bar']; + const options = { foo: { type: 'boolean' } }; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_PARSE_ARGS_INVALID_OPTION_VALUE' }); }); test('invalid short option length', () => { - const passedArgs = []; - const passedOptions = { foo: { short: 'fo', type: 'boolean' } }; - assert.throws(() => { parseArgs({ args: passedArgs, options: passedOptions }); }, { + const args = []; + const options = { foo: { short: 'fo', type: 'boolean' } }; + assert.throws(() => { parseArgs({ args, options }); }, { code: 'ERR_INVALID_ARG_VALUE' }); }); + +test('null prototype: when no options then values.toString is undefined', () => { + const result = parseArgs({ args: [] }); + assert.strictEqual(result.values.toString, undefined); +}); + +test('null prototype: when --toString then values.toString is true', () => { + const args = ['--toString']; + const options = { toString: { type: 'boolean' } }; + const expectedResult = { values: { __proto__: null, toString: true }, positionals: [] }; + + const result = parseArgs({ args, options }); + assert.deepStrictEqual(result, expectedResult); +}); diff --git a/test/prototype-pollution.js b/test/prototype-pollution.js index f1c82c4..a8a5d2f 100644 --- a/test/prototype-pollution.js +++ b/test/prototype-pollution.js @@ -22,10 +22,10 @@ function restoreObjectPrototype(prop, oldDescriptor) { } test('should not allow __proto__ key to be set on object', (t) => { - const passedArgs = ['--__proto__=hello']; - const expected = { values: {}, positionals: [] }; + const args = ['--__proto__=hello']; + const expected = { values: { __proto__: null }, positionals: [] }; - const result = parseArgs({ strict: false, args: passedArgs }); + const result = parseArgs({ strict: false, args }); t.deepEqual(result, expected); t.end(); @@ -34,7 +34,7 @@ test('should not allow __proto__ key to be set on object', (t) => { test('when prototype has multiple then ignored', (t) => { const args = ['--foo', '1', '--foo', '2']; const options = { foo: { type: 'string' } }; - const expectedResult = { values: { foo: '2' }, positionals: [] }; + const expectedResult = { values: { __proto__: null, foo: '2' }, positionals: [] }; const holdDescriptor = setObjectPrototype('multiple', true); const result = parseArgs({ args, options }); diff --git a/test/short-option-combined-with-value.js b/test/short-option-combined-with-value.js index 61255b1..ca0ec6a 100644 --- a/test/short-option-combined-with-value.js +++ b/test/short-option-combined-with-value.js @@ -5,55 +5,55 @@ const test = require('tape'); const { parseArgs } = require('../index.js'); test('when combine string short with plain text then parsed as value', (t) => { - const passedArgs = ['-aHELLO']; - const passedOptions = { alpha: { short: 'a', type: 'string' } }; - const expected = { values: { alpha: 'HELLO' }, positionals: [] }; + const args = ['-aHELLO']; + const options = { alpha: { short: 'a', type: 'string' } }; + const expected = { values: { __proto__: null, alpha: 'HELLO' }, positionals: [] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); }); test('when combine low-config string short with plain text then parsed as value', (t) => { - const passedArgs = ['-aHELLO']; - const passedOptions = { a: { type: 'string' } }; - const expected = { values: { a: 'HELLO' }, positionals: [] }; + const args = ['-aHELLO']; + const options = { a: { type: 'string' } }; + const expected = { values: { __proto__: null, a: 'HELLO' }, positionals: [] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); }); test('when combine string short with value like short option then parsed as value', (t) => { - const passedArgs = ['-a-b']; - const passedOptions = { alpha: { short: 'a', type: 'string' } }; - const expected = { values: { alpha: '-b' }, positionals: [] }; + const args = ['-a-b']; + const options = { alpha: { short: 'a', type: 'string' } }; + const expected = { values: { __proto__: null, alpha: '-b' }, positionals: [] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); }); test('when combine string short with value like long option then parsed as value', (t) => { - const passedArgs = ['-a--bar']; - const passedOptions = { alpha: { short: 'a', type: 'string' } }; - const expected = { values: { alpha: '--bar' }, positionals: [] }; + const args = ['-a--bar']; + const options = { alpha: { short: 'a', type: 'string' } }; + const expected = { values: { __proto__: null, alpha: '--bar' }, positionals: [] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); }); test('when combine string short with value like negative number then parsed as value', (t) => { - const passedArgs = ['-a-5']; - const passedOptions = { alpha: { short: 'a', type: 'string' } }; - const expected = { values: { alpha: '-5' }, positionals: [] }; + const args = ['-a-5']; + const options = { alpha: { short: 'a', type: 'string' } }; + const expected = { values: { __proto__: null, alpha: '-5' }, positionals: [] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); @@ -61,21 +61,21 @@ test('when combine string short with value like negative number then parsed as v test('when combine string short with value which matches configured flag then parsed as value', (t) => { - const passedArgs = ['-af']; - const passedOptions = { alpha: { short: 'a', type: 'string' }, file: { short: 'f', type: 'boolean' } }; - const expected = { values: { alpha: 'f' }, positionals: [] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const args = ['-af']; + const options = { alpha: { short: 'a', type: 'string' }, file: { short: 'f', type: 'boolean' } }; + const expected = { values: { __proto__: null, alpha: 'f' }, positionals: [] }; + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); }); test('when combine string short with value including equals then parsed with equals in value', (t) => { - const passedArgs = ['-a=5']; - const passedOptions = { alpha: { short: 'a', type: 'string' } }; - const expected = { values: { alpha: '=5' }, positionals: [] }; + const args = ['-a=5']; + const options = { alpha: { short: 'a', type: 'string' } }; + const expected = { values: { __proto__: null, alpha: '=5' }, positionals: [] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); diff --git a/test/short-option-groups.js b/test/short-option-groups.js index f95b6fa..7b528f0 100644 --- a/test/short-option-groups.js +++ b/test/short-option-groups.js @@ -5,56 +5,45 @@ const test = require('tape'); const { parseArgs } = require('../index.js'); test('when pass zero-config group of booleans then parsed as booleans', (t) => { - const passedArgs = ['-rf', 'p']; - const passedOptions = { }; - const expected = { values: { r: true, f: true }, positionals: ['p'] }; + const args = ['-rf', 'p']; + const options = { }; + const expected = { values: { __proto__: null, r: true, f: true }, positionals: ['p'] }; - const result = parseArgs({ strict: false, args: passedArgs, options: passedOptions }); + const result = parseArgs({ strict: false, args, options }); t.deepEqual(result, expected); t.end(); }); test('when pass full-config group of booleans then parsed as booleans', (t) => { - const passedArgs = ['-rf', 'p']; - const passedOptions = { r: { type: 'boolean' }, f: { type: 'boolean' } }; - const expected = { values: { r: true, f: true }, positionals: ['p'] }; + const args = ['-rf', 'p']; + const options = { r: { type: 'boolean' }, f: { type: 'boolean' } }; + const expected = { values: { __proto__: null, r: true, f: true }, positionals: ['p'] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); }); test('when pass group with string option on end then parsed as booleans and string option', (t) => { - const passedArgs = ['-rf', 'p']; - const passedOptions = { r: { type: 'boolean' }, f: { type: 'string' } }; - const expected = { values: { r: true, f: 'p' }, positionals: [] }; + const args = ['-rf', 'p']; + const options = { r: { type: 'boolean' }, f: { type: 'string' } }; + const expected = { values: { __proto__: null, r: true, f: 'p' }, positionals: [] }; - const result = parseArgs({ args: passedArgs, options: passedOptions }); + const result = parseArgs({ args, options }); t.deepEqual(result, expected); t.end(); }); test('when pass group with string option in middle and strict:false then parsed as booleans and string option with trailing value', (t) => { - const passedArgs = ['-afb', 'p']; - const passedOptions = { f: { type: 'string' } }; - const expected = { values: { a: true, f: 'b' }, positionals: ['p'] }; + const args = ['-afb', 'p']; + const options = { f: { type: 'string' } }; + const expected = { values: { __proto__: null, a: true, f: 'b' }, positionals: ['p'] }; - const result = parseArgs({ args: passedArgs, options: passedOptions, strict: false }); + const result = parseArgs({ args, options, strict: false }); t.deepEqual(result, expected); t.end(); }); - -// Hopefully coming: -// test('when pass group with string option in middle and strict:true then error', (t) => { -// const passedArgs = ['-afb', 'p']; -// const passedOptions = { f: { type: 'string' } }; -// -// t.throws(() => { -// parseArgs({ args: passedArgs, options: passedOptions, strict: true }); -// }); -// t.end(); -// }); diff --git a/test/store-user-intent.js b/test/store-user-intent.js index d5340a9..661acb0 100644 --- a/test/store-user-intent.js +++ b/test/store-user-intent.js @@ -17,36 +17,36 @@ const { parseArgs } = require('../index.js'); // user's intentions. test('when use string short option used as boolean then result as if boolean', (t) => { - const passedArgs = ['-o']; + const args = ['-o']; const stringOptions = { opt: { short: 'o', type: 'string' } }; const booleanOptions = { opt: { short: 'o', type: 'boolean' } }; - const stringConfigResult = parseArgs({ args: passedArgs, options: stringOptions, strict: false }); - const booleanConfigResult = parseArgs({ args: passedArgs, options: booleanOptions, strict: false }); + const stringConfigResult = parseArgs({ args, options: stringOptions, strict: false }); + const booleanConfigResult = parseArgs({ args, options: booleanOptions, strict: false }); t.deepEqual(stringConfigResult, booleanConfigResult); t.end(); }); test('when use string long option used as boolean then result as if boolean', (t) => { - const passedArgs = ['--opt']; + const args = ['--opt']; const stringOptions = { opt: { short: 'o', type: 'string' } }; const booleanOptions = { opt: { short: 'o', type: 'boolean' } }; - const stringConfigResult = parseArgs({ args: passedArgs, options: stringOptions, strict: false }); - const booleanConfigResult = parseArgs({ args: passedArgs, options: booleanOptions, strict: false }); + const stringConfigResult = parseArgs({ args, options: stringOptions, strict: false }); + const booleanConfigResult = parseArgs({ args, options: booleanOptions, strict: false }); t.deepEqual(stringConfigResult, booleanConfigResult); t.end(); }); test('when use boolean long option used as string then result as if string', (t) => { - const passedArgs = ['--bool=OOPS']; + const args = ['--bool=OOPS']; const stringOptions = { bool: { type: 'string' } }; const booleanOptions = { bool: { type: 'boolean' } }; - const stringConfigResult = parseArgs({ args: passedArgs, options: stringOptions, strict: false }); - const booleanConfigResult = parseArgs({ args: passedArgs, options: booleanOptions, strict: false }); + const stringConfigResult = parseArgs({ args, options: stringOptions, strict: false }); + const booleanConfigResult = parseArgs({ args, options: booleanOptions, strict: false }); t.deepEqual(booleanConfigResult, stringConfigResult); t.end();