import { spawnPromisified } from '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import assert from 'node:assert'; import { suite, test } from 'node:test'; import { parseArgs } from 'node:util'; test('when short option used as flag then stored as flag', () => { 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 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 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 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 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 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 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 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 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 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 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('handles short-option followed by its value', () => { const args = ['-fFILE']; const options = { foo: { short: 'f', type: 'string' } }; const expected = { values: { __proto__: null, foo: 'FILE' }, positionals: [] }; const result = parseArgs({ strict: false, args, options }); assert.deepStrictEqual(result, expected); }); test('Everything after a bare `--` is considered a positional argument', () => { const args = ['--', 'barepositionals', 'mopositionals']; const expected = { values: { __proto__: null }, positionals: ['barepositionals', 'mopositionals'] }; const result = parseArgs({ allowPositionals: true, args }); assert.deepStrictEqual(result, expected, Error('testing bare positionals')); }); test('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 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 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 args = ['-']; const expected = { values: { __proto__: null }, positionals: ['-'] }; const result = parseArgs({ allowPositionals: true, args }); assert.deepStrictEqual(result, expected); }); test('zero config args equals are parsed as if `type: "string"`', () => { 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 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 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 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 args = ['--foo=a', '--foo', 'b']; const options = { foo: { type: 'string', multiple: true, }, }; 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 args = ['--foo', '--foo']; const options = { foo: { type: 'boolean', multiple: true, }, }; 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 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({ allowPositionals: true, args: args1, options }), expected, Error('option then positional') ); assert.deepStrictEqual( parseArgs({ allowPositionals: true, args: args2, options }), expected, Error('positional then option') ); }); suite('correct default args', () => { const expected = { code: 0, signal: null, stderr: '', stdout: { foo: true, bar: true } }; suite('with CLI flags', () => { const evalCode = "JSON.stringify(require('util').parseArgs({ strict: false }).values)"; const evalCodePrinted = `process.stdout.write(${evalCode})`; const execArgsTests = { '-e