From d8bcbcc5502c47701778c0a926155345b45c9511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Sat, 11 Apr 2020 01:03:41 +0200 Subject: [PATCH 01/17] :see_no_evil: Ignore .vscode directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 239ecff..84e2ef1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules yarn.lock +.vscode From 15e8bd25933aed9160ff5af018d42665763ffcfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Sat, 11 Apr 2020 01:05:10 +0200 Subject: [PATCH 02/17] :label: TypeScript type for multiple option --- index.d.ts | 5 ++++- index.test-d.ts | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index c4dce28..3a6a3e6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -7,6 +7,7 @@ declare namespace meow { readonly type?: Type; readonly alias?: string; readonly default?: Default; + readonly multiple?: boolean; } type StringFlag = Flag<'string', string>; @@ -24,6 +25,7 @@ declare namespace meow { - `type`: Type of value. (Possible values: `string` `boolean` `number`) - `alias`: Usually used to define a short flag alias. - `default`: Default value when the flag is not specified. + - `multiple`: Indicates a flag can be set multiple times. Returns an array. (Default: false) @example ``` @@ -31,7 +33,8 @@ declare namespace meow { unicorn: { type: 'string', alias: 'u', - default: 'rainbow' + default: ['rainbow', 'cat'], + multiple: true } } ``` diff --git a/index.test-d.ts b/index.test-d.ts index 791c8cf..640b8ca 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -35,8 +35,8 @@ const result = meow('Help text', { foo: {type: 'boolean', alias: 'f'}, 'foo-bar': {type: 'number'}, bar: {type: 'string', default: ''} - }} -); + } +}); expectType(result.input); expectType(result.pkg); From 8ada7b6eb9bf262d12f70f0cd862aa99b3dd0a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Sat, 11 Apr 2020 01:05:34 +0200 Subject: [PATCH 03/17] :pencil: Document multiple option --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 8071317..35f55c0 100644 --- a/readme.md +++ b/readme.md @@ -97,6 +97,7 @@ The key is the flag name and the value is an object with any of: - `type`: Type of value. (Possible values: `string` `boolean` `number`) - `alias`: Usually used to define a short flag alias. - `default`: Default value when the flag is not specified. +- `multiple`: Indicates a flag can be set multiple times. Returns an array. (Default: false) Example: @@ -105,7 +106,8 @@ flags: { unicorn: { type: 'string', alias: 'u', - default: 'rainbow' + default: ['rainbow', 'cat'], + multiple: true } } ``` From c1f2641a0e4d2a9308251514540e0b75fa0fb135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Sat, 11 Apr 2020 23:19:50 +0200 Subject: [PATCH 04/17] :sparkle: Add `multiple` setting to flags --- index.js | 62 +++++++++++++++------- package.json | 1 + test.js | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 20 deletions(-) diff --git a/index.js b/index.js index 4b802db..6ec67c6 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ const redent = require('redent'); const readPkgUp = require('read-pkg-up'); const hardRejection = require('hard-rejection'); const normalizePackageData = require('normalize-package-data'); +const arrify = require('arrify'); // Prevent caching of this module so module.parent is always accurate delete require.cache[__filename]; @@ -26,6 +27,7 @@ const meow = (helpText, options) => { normalize: false }).packageJson || {}, argv: process.argv.slice(2), + flags: {}, inferType: false, input: 'string', help: helpText, @@ -40,39 +42,57 @@ const meow = (helpText, options) => { hardRejection(); } - const minimistFlags = options.flags && typeof options.booleanDefault !== 'undefined' ? Object.keys(options.flags).reduce( - (flags, flag) => { - if (flags[flag].type === 'boolean' && !Object.prototype.hasOwnProperty.call(flags[flag], 'default')) { - flags[flag].default = options.booleanDefault; - } + const minimistFlags = Object.entries(options.flags).reduce((flags, [flagKey, flagValue]) => { + const flag = {...flagValue}; + const {booleanDefault} = options; - return flags; - }, - options.flags - ) : options.flags; + if ( + typeof booleanDefault !== 'undefined' && + flag.type === 'boolean' && + !Object.prototype.hasOwnProperty.call(flag, 'default') + ) { + flag.default = flag.multiple ? [booleanDefault] : booleanDefault; + } + + if (flag.multiple) { + flag.type = 'array'; + delete flag.multiple; + } + + flags[flagKey] = flag; - let minimistoptions = { + return flags; + }, {}); + + let minimistOptions = { arguments: options.input, ...minimistFlags }; - minimistoptions = decamelizeKeys(minimistoptions, '-', {exclude: ['stopEarly', '--']}); + minimistOptions = decamelizeKeys(minimistOptions, '-', {exclude: ['stopEarly', '--']}); if (options.inferType) { - delete minimistoptions.arguments; + delete minimistOptions.arguments; } - minimistoptions = buildMinimistOptions(minimistoptions); + minimistOptions = buildMinimistOptions(minimistOptions); - if (minimistoptions['--']) { - minimistoptions.configuration = { - ...minimistoptions.configuration, + if (minimistOptions['--']) { + minimistOptions.configuration = { + ...minimistOptions.configuration, 'populate--': true }; } + if (minimistOptions.array !== undefined) { + minimistOptions.array = arrify(minimistOptions.array).map(flagKey => ({ + key: flagKey, + [options.flags[flagKey].type || 'string']: true + })); + } + const {pkg} = options; - const argv = yargs(options.argv, minimistoptions); + const argv = yargs(options.argv, minimistOptions); let help = redent(trimNewlines((options.help || '').replace(/\t+\n*$/, '')), 2); normalizePackageData(pkg); @@ -112,10 +132,12 @@ const meow = (helpText, options) => { const flags = camelcaseKeys(argv, {exclude: ['--', /^\w$/]}); const unnormalizedFlags = {...flags}; - if (options.flags !== undefined) { - for (const flagValue of Object.values(options.flags)) { - delete flags[flagValue.alias]; + for (const [flagKey, flagValue] of Object.entries(options.flags).filter(([key]) => key !== '--')) { + if (!flagValue.multiple && Array.isArray(flags[flagKey])) { + throw new Error(`Only one value allowed for --${flagKey}.`) } + + delete flags[flagValue.alias]; } return { diff --git a/package.json b/package.json index 23e555a..3b25579 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ ], "dependencies": { "@types/minimist": "^1.2.0", + "arrify": "^2.0.1", "camelcase-keys": "^6.1.1", "decamelize-keys": "^1.1.0", "hard-rejection": "^2.0.0", diff --git a/test.js b/test.js index d3e40ec..992a5f2 100644 --- a/test.js +++ b/test.js @@ -307,3 +307,146 @@ test('supports `number` flag type - throws on incorrect default value', t => { }); }); }); + +test('multiple flag set once returns array', t => { + t.deepEqual(meow({ + argv: ['--foo=bar'], + flags: { + foo: { + type: 'string', + multiple: true + } + } + }).flags, { + foo: ['bar'] + }); +}); + +test('multiple flag set multiple times', t => { + t.deepEqual(meow({ + argv: ['--foo=bar', '--foo=baz'], + flags: { + foo: { + type: 'string', + multiple: true + } + } + }).flags, { + foo: ['bar', 'baz'] + }); +}); + +test('multiple flag with space separated values', t => { + t.deepEqual(meow({ + argv: ['--foo', 'bar', 'baz'], + flags: { + foo: { + type: 'string', + multiple: true + } + } + }).flags, { + foo: ['bar', 'baz'] + }); +}); + +test('single flag set more than once => throws', t => { + t.throws(() => { + meow({ + argv: ['--foo=bar', '--foo=baz'], + flags: { + foo: { + type: 'string' + } + } + }); + }, {message: 'Only one value allowed for --foo.'}); +}); + +test('multiple boolean flag', t => { + t.deepEqual(meow({ + argv: ['--foo', '--foo=false'], + flags: { + foo: { + type: 'boolean', + multiple: true + } + } + }).flags, { + foo: [true, false] + }); +}); + +test('multiple boolean flag is false by default', t => { + t.deepEqual(meow({ + argv: [], + flags: { + foo: { + type: 'boolean', + multiple: true + } + } + }).flags, { + foo: [false] + }); +}); + +test('multiple flag with `booleanDefault: undefined` => filter out unset boolean args', t => { + t.deepEqual(meow({ + argv: ['--foo'], + booleanDefault: undefined, + flags: { + foo: { + type: 'boolean', + multiple: true + }, + bar: { + type: 'boolean', + multiple: true + } + } + }).flags, { + foo: [true] + }); +}); + +test('multiple number flag', t => { + t.deepEqual(meow({ + argv: ['--foo=1.3', '--foo=-1'], + flags: { + foo: { + type: 'number', + multiple: true + } + } + }).flags, { + foo: [1.3, -1] + }); +}); + +test('multiple flag default values', t => { + t.deepEqual(meow({ + argv: [], + flags: { + string: { + type: 'string', + multiple: true, + default: ['foo'] + }, + boolean: { + type: 'boolean', + multiple: true, + default: [true] + }, + number: { + type: 'number', + multiple: true, + default: [0.5] + } + } + }).flags, { + string: ['foo'], + boolean: [true], + number: [0.5] + }); +}); From 56785a41fa8f6a79068af2a5de3a494a89fb4e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Sat, 11 Apr 2020 23:38:59 +0200 Subject: [PATCH 05/17] :rotating_light: Add missing semicolon --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 6ec67c6..66534a3 100644 --- a/index.js +++ b/index.js @@ -134,7 +134,7 @@ const meow = (helpText, options) => { for (const [flagKey, flagValue] of Object.entries(options.flags).filter(([key]) => key !== '--')) { if (!flagValue.multiple && Array.isArray(flags[flagKey])) { - throw new Error(`Only one value allowed for --${flagKey}.`) + throw new Error(`Only one value allowed for --${flagKey}.`); } delete flags[flagValue.alias]; From 6ebe454c3a1a1f284d72facb887faeb91825abf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Wed, 15 Apr 2020 14:06:29 +0200 Subject: [PATCH 06/17] :rewind: Revert variable rename - Break out into separate PR --- index.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 66534a3..5b1c1c1 100644 --- a/index.js +++ b/index.js @@ -64,35 +64,35 @@ const meow = (helpText, options) => { return flags; }, {}); - let minimistOptions = { + let minimistoptions = { arguments: options.input, ...minimistFlags }; - minimistOptions = decamelizeKeys(minimistOptions, '-', {exclude: ['stopEarly', '--']}); + minimistoptions = decamelizeKeys(minimistoptions, '-', {exclude: ['stopEarly', '--']}); if (options.inferType) { - delete minimistOptions.arguments; + delete minimistoptions.arguments; } - minimistOptions = buildMinimistOptions(minimistOptions); + minimistoptions = buildMinimistOptions(minimistoptions); - if (minimistOptions['--']) { - minimistOptions.configuration = { - ...minimistOptions.configuration, + if (minimistoptions['--']) { + minimistoptions.configuration = { + ...minimistoptions.configuration, 'populate--': true }; } - if (minimistOptions.array !== undefined) { - minimistOptions.array = arrify(minimistOptions.array).map(flagKey => ({ + if (minimistoptions.array !== undefined) { + minimistoptions.array = arrify(minimistoptions.array).map(flagKey => ({ key: flagKey, [options.flags[flagKey].type || 'string']: true })); } const {pkg} = options; - const argv = yargs(options.argv, minimistOptions); + const argv = yargs(options.argv, minimistoptions); let help = redent(trimNewlines((options.help || '').replace(/\t+\n*$/, '')), 2); normalizePackageData(pkg); From 097cb44dfaae514abec27e5456e29597f9d58a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Thu, 16 Apr 2020 22:47:40 +0200 Subject: [PATCH 07/17] Fix after merge --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index f9d16f7..66534a3 100644 --- a/index.js +++ b/index.js @@ -84,8 +84,8 @@ const meow = (helpText, options) => { }; } - if (minimistoptions.array !== undefined) { - minimistoptions.array = arrify(minimistoptions.array).map(flagKey => ({ + if (minimistOptions.array !== undefined) { + minimistOptions.array = arrify(minimistOptions.array).map(flagKey => ({ key: flagKey, [options.flags[flagKey].type || 'string']: true })); From b6a843b8bb54e6fb2aa0c27dae72fe30892226b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Thu, 23 Apr 2020 22:06:43 +0200 Subject: [PATCH 08/17] Remove .vscode from .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 84e2ef1..239ecff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ node_modules yarn.lock -.vscode From 36389d2103d962e2578dccc4902e59e0280cd19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Thu, 23 Apr 2020 22:11:06 +0200 Subject: [PATCH 09/17] Update error message --- index.js | 2 +- test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 66534a3..f3abfb4 100644 --- a/index.js +++ b/index.js @@ -134,7 +134,7 @@ const meow = (helpText, options) => { for (const [flagKey, flagValue] of Object.entries(options.flags).filter(([key]) => key !== '--')) { if (!flagValue.multiple && Array.isArray(flags[flagKey])) { - throw new Error(`Only one value allowed for --${flagKey}.`); + throw new Error(`The flag --${flagKey} can only be set once.`); } delete flags[flagValue.alias]; diff --git a/test.js b/test.js index 992a5f2..a2b8f30 100644 --- a/test.js +++ b/test.js @@ -360,7 +360,7 @@ test('single flag set more than once => throws', t => { } } }); - }, {message: 'Only one value allowed for --foo.'}); + }, {message: 'The flag --foo can only be set once.'}); }); test('multiple boolean flag', t => { From 7bbc7c17302a4bf094f0c7cf51b25eb8abf738e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Thu, 23 Apr 2020 22:25:59 +0200 Subject: [PATCH 10/17] Add comment as to why we patch `minimist-options` output --- index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/index.js b/index.js index f3abfb4..d94f88d 100644 --- a/index.js +++ b/index.js @@ -85,6 +85,11 @@ const meow = (helpText, options) => { } if (minimistOptions.array !== undefined) { + // `yargs` supports 'string|number|boolean' arrays, + // but `minimist-options` only support 'string' as element type. + // Convert to alternative syntax for coercing values to expected type, + // according to https://github.com/yargs/yargs-parser#requireyargs-parserargs-opts + // Open issue to add support to `minimist-options`: https://github.com/vadimdemedes/minimist-options/issues/18 minimistOptions.array = arrify(minimistOptions.array).map(flagKey => ({ key: flagKey, [options.flags[flagKey].type || 'string']: true From 42e8366d1de7f1c5aed31306ef5a609a251363ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Thu, 23 Apr 2020 22:34:56 +0200 Subject: [PATCH 11/17] Attempt to clarify docs --- index.d.ts | 14 +++++++------- readme.md | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index 3a6a3e6..7b6a915 100644 --- a/index.d.ts +++ b/index.d.ts @@ -25,7 +25,7 @@ declare namespace meow { - `type`: Type of value. (Possible values: `string` `boolean` `number`) - `alias`: Usually used to define a short flag alias. - `default`: Default value when the flag is not specified. - - `multiple`: Indicates a flag can be set multiple times. Returns an array. (Default: false) + - `multiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) @example ``` @@ -177,12 +177,12 @@ declare namespace meow { type TypedFlags = { [F in keyof Flags]: Flags[F] extends {type: 'number'} - ? number - : Flags[F] extends {type: 'string'} - ? string - : Flags[F] extends {type: 'boolean'} - ? boolean - : unknown; + ? number + : Flags[F] extends {type: 'string'} + ? string + : Flags[F] extends {type: 'boolean'} + ? boolean + : unknown; }; interface Result { diff --git a/readme.md b/readme.md index 35f55c0..db2e39a 100644 --- a/readme.md +++ b/readme.md @@ -97,7 +97,7 @@ The key is the flag name and the value is an object with any of: - `type`: Type of value. (Possible values: `string` `boolean` `number`) - `alias`: Usually used to define a short flag alias. - `default`: Default value when the flag is not specified. -- `multiple`: Indicates a flag can be set multiple times. Returns an array. (Default: false) +- `multiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) Example: From a4d4a36fe9cce33193da108b48574a8d5a028a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Thu, 23 Apr 2020 23:21:03 +0200 Subject: [PATCH 12/17] Modularize main function --- index.js | 79 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/index.js b/index.js index d94f88d..9064524 100644 --- a/index.js +++ b/index.js @@ -15,6 +15,46 @@ const arrify = require('arrify'); delete require.cache[__filename]; const parentDir = path.dirname(module.parent.filename); +const buildMinimistFlags = ({flags, booleanDefault}) => + Object.entries(flags).reduce((minimistFlags, [flagKey, flagValue]) => { + const flag = {...flagValue}; + + if ( + typeof booleanDefault !== 'undefined' && + flag.type === 'boolean' && + !Object.prototype.hasOwnProperty.call(flag, 'default') + ) { + flag.default = flag.multiple ? [booleanDefault] : booleanDefault; + } + + if (flag.multiple) { + flag.type = 'array'; + delete flag.multiple; + } + + minimistFlags[flagKey] = flag; + + return minimistFlags; + }, {}); + +/** + * Convert to alternative syntax for coercing values to expected type, + * according to https://github.com/yargs/yargs-parser#requireyargs-parserargs-opts. + */ +const convertToTypedArrayOption = (arrayOption, flags) => + arrify(arrayOption).map(flagKey => ({ + key: flagKey, + [flags[flagKey].type || 'string']: true + })); + +const validateFlags = (flags, options) => { + for (const [flagKey, flagValue] of Object.entries(options.flags)) { + if (flagKey !== '--' && !flagValue.multiple && Array.isArray(flags[flagKey])) { + throw new Error(`The flag --${flagKey} can only be set once.`); + } + } +}; + const meow = (helpText, options) => { if (typeof helpText !== 'string') { options = helpText; @@ -42,31 +82,9 @@ const meow = (helpText, options) => { hardRejection(); } - const minimistFlags = Object.entries(options.flags).reduce((flags, [flagKey, flagValue]) => { - const flag = {...flagValue}; - const {booleanDefault} = options; - - if ( - typeof booleanDefault !== 'undefined' && - flag.type === 'boolean' && - !Object.prototype.hasOwnProperty.call(flag, 'default') - ) { - flag.default = flag.multiple ? [booleanDefault] : booleanDefault; - } - - if (flag.multiple) { - flag.type = 'array'; - delete flag.multiple; - } - - flags[flagKey] = flag; - - return flags; - }, {}); - let minimistOptions = { arguments: options.input, - ...minimistFlags + ...buildMinimistFlags(options) }; minimistOptions = decamelizeKeys(minimistOptions, '-', {exclude: ['stopEarly', '--']}); @@ -87,13 +105,8 @@ const meow = (helpText, options) => { if (minimistOptions.array !== undefined) { // `yargs` supports 'string|number|boolean' arrays, // but `minimist-options` only support 'string' as element type. - // Convert to alternative syntax for coercing values to expected type, - // according to https://github.com/yargs/yargs-parser#requireyargs-parserargs-opts - // Open issue to add support to `minimist-options`: https://github.com/vadimdemedes/minimist-options/issues/18 - minimistOptions.array = arrify(minimistOptions.array).map(flagKey => ({ - key: flagKey, - [options.flags[flagKey].type || 'string']: true - })); + // Open issue to add support to `minimist-options`: https://github.com/vadimdemedes/minimist-options/issues/18. + minimistOptions.array = convertToTypedArrayOption(minimistOptions.array, options.flags); } const {pkg} = options; @@ -137,11 +150,9 @@ const meow = (helpText, options) => { const flags = camelcaseKeys(argv, {exclude: ['--', /^\w$/]}); const unnormalizedFlags = {...flags}; - for (const [flagKey, flagValue] of Object.entries(options.flags).filter(([key]) => key !== '--')) { - if (!flagValue.multiple && Array.isArray(flags[flagKey])) { - throw new Error(`The flag --${flagKey} can only be set once.`); - } + validateFlags(flags, options); + for (const flagValue of Object.values(options.flags)) { delete flags[flagValue.alias]; } From 5602f4179f484961b546abc4b349b3f57e7b2825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Thu, 23 Apr 2020 23:25:02 +0200 Subject: [PATCH 13/17] `multiple` -> `isMultiple` --- index.d.ts | 6 +++--- index.js | 8 ++++---- readme.md | 4 ++-- test.js | 22 +++++++++++----------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/index.d.ts b/index.d.ts index 7b6a915..52f8f2c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -7,7 +7,7 @@ declare namespace meow { readonly type?: Type; readonly alias?: string; readonly default?: Default; - readonly multiple?: boolean; + readonly isMultiple?: boolean; } type StringFlag = Flag<'string', string>; @@ -25,7 +25,7 @@ declare namespace meow { - `type`: Type of value. (Possible values: `string` `boolean` `number`) - `alias`: Usually used to define a short flag alias. - `default`: Default value when the flag is not specified. - - `multiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) + - `isMultiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) @example ``` @@ -34,7 +34,7 @@ declare namespace meow { type: 'string', alias: 'u', default: ['rainbow', 'cat'], - multiple: true + isMultiple: true } } ``` diff --git a/index.js b/index.js index 9064524..802153c 100644 --- a/index.js +++ b/index.js @@ -24,12 +24,12 @@ const buildMinimistFlags = ({flags, booleanDefault}) => flag.type === 'boolean' && !Object.prototype.hasOwnProperty.call(flag, 'default') ) { - flag.default = flag.multiple ? [booleanDefault] : booleanDefault; + flag.default = flag.isMultiple ? [booleanDefault] : booleanDefault; } - if (flag.multiple) { + if (flag.isMultiple) { flag.type = 'array'; - delete flag.multiple; + delete flag.isMultiple; } minimistFlags[flagKey] = flag; @@ -49,7 +49,7 @@ const convertToTypedArrayOption = (arrayOption, flags) => const validateFlags = (flags, options) => { for (const [flagKey, flagValue] of Object.entries(options.flags)) { - if (flagKey !== '--' && !flagValue.multiple && Array.isArray(flags[flagKey])) { + if (flagKey !== '--' && !flagValue.isMultiple && Array.isArray(flags[flagKey])) { throw new Error(`The flag --${flagKey} can only be set once.`); } } diff --git a/readme.md b/readme.md index db2e39a..a448f6d 100644 --- a/readme.md +++ b/readme.md @@ -97,7 +97,7 @@ The key is the flag name and the value is an object with any of: - `type`: Type of value. (Possible values: `string` `boolean` `number`) - `alias`: Usually used to define a short flag alias. - `default`: Default value when the flag is not specified. -- `multiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) +- `isMultiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) Example: @@ -107,7 +107,7 @@ flags: { type: 'string', alias: 'u', default: ['rainbow', 'cat'], - multiple: true + isMultiple: true } } ``` diff --git a/test.js b/test.js index a2b8f30..091d89c 100644 --- a/test.js +++ b/test.js @@ -314,7 +314,7 @@ test('multiple flag set once returns array', t => { flags: { foo: { type: 'string', - multiple: true + isMultiple: true } } }).flags, { @@ -328,7 +328,7 @@ test('multiple flag set multiple times', t => { flags: { foo: { type: 'string', - multiple: true + isMultiple: true } } }).flags, { @@ -342,7 +342,7 @@ test('multiple flag with space separated values', t => { flags: { foo: { type: 'string', - multiple: true + isMultiple: true } } }).flags, { @@ -369,7 +369,7 @@ test('multiple boolean flag', t => { flags: { foo: { type: 'boolean', - multiple: true + isMultiple: true } } }).flags, { @@ -383,7 +383,7 @@ test('multiple boolean flag is false by default', t => { flags: { foo: { type: 'boolean', - multiple: true + isMultiple: true } } }).flags, { @@ -398,11 +398,11 @@ test('multiple flag with `booleanDefault: undefined` => filter out unset boolean flags: { foo: { type: 'boolean', - multiple: true + isMultiple: true }, bar: { type: 'boolean', - multiple: true + isMultiple: true } } }).flags, { @@ -416,7 +416,7 @@ test('multiple number flag', t => { flags: { foo: { type: 'number', - multiple: true + isMultiple: true } } }).flags, { @@ -430,17 +430,17 @@ test('multiple flag default values', t => { flags: { string: { type: 'string', - multiple: true, + isMultiple: true, default: ['foo'] }, boolean: { type: 'boolean', - multiple: true, + isMultiple: true, default: [true] }, number: { type: 'number', - multiple: true, + isMultiple: true, default: [0.5] } } From 5fb9b1a6803465f366d9edf22a38c94173dd0320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Mon, 27 Apr 2020 16:46:28 +0200 Subject: [PATCH 14/17] Revert formatting change --- index.d.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.d.ts b/index.d.ts index 52f8f2c..be10981 100644 --- a/index.d.ts +++ b/index.d.ts @@ -177,12 +177,12 @@ declare namespace meow { type TypedFlags = { [F in keyof Flags]: Flags[F] extends {type: 'number'} - ? number - : Flags[F] extends {type: 'string'} - ? string - : Flags[F] extends {type: 'boolean'} - ? boolean - : unknown; + ? number + : Flags[F] extends {type: 'string'} + ? string + : Flags[F] extends {type: 'boolean'} + ? boolean + : unknown; }; interface Result { From 88b76f0eb5483277f26f022af7d583b5094a425e Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 5 May 2020 23:26:00 +0800 Subject: [PATCH 15/17] Update index.js --- index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 80238e6..d2974d4 100644 --- a/index.js +++ b/index.js @@ -38,9 +38,8 @@ const buildParserFlags = ({flags, booleanDefault}) => }, {}); /** - * Convert to alternative syntax for coercing values to expected type, - * according to https://github.com/yargs/yargs-parser#requireyargs-parserargs-opts. - */ +Convert to alternative syntax for coercing values to expected type, according to https://github.com/yargs/yargs-parser#requireyargs-parserargs-opts. +*/ const convertToTypedArrayOption = (arrayOption, flags) => arrify(arrayOption).map(flagKey => ({ key: flagKey, From f2a3ad13a036699091682ca1a1e99e374df4e61c Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 5 May 2020 23:27:40 +0800 Subject: [PATCH 16/17] Update test.js --- test.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test.js b/test.js index 091d89c..7822d0b 100644 --- a/test.js +++ b/test.js @@ -308,7 +308,7 @@ test('supports `number` flag type - throws on incorrect default value', t => { }); }); -test('multiple flag set once returns array', t => { +test('isMultiple - flag set once returns array', t => { t.deepEqual(meow({ argv: ['--foo=bar'], flags: { @@ -322,7 +322,7 @@ test('multiple flag set once returns array', t => { }); }); -test('multiple flag set multiple times', t => { +test('isMultiple - flag set multiple times', t => { t.deepEqual(meow({ argv: ['--foo=bar', '--foo=baz'], flags: { @@ -336,7 +336,7 @@ test('multiple flag set multiple times', t => { }); }); -test('multiple flag with space separated values', t => { +test('isMultiple - flag with space separated values', t => { t.deepEqual(meow({ argv: ['--foo', 'bar', 'baz'], flags: { @@ -363,7 +363,7 @@ test('single flag set more than once => throws', t => { }, {message: 'The flag --foo can only be set once.'}); }); -test('multiple boolean flag', t => { +test('isMultiple - boolean flag', t => { t.deepEqual(meow({ argv: ['--foo', '--foo=false'], flags: { @@ -377,7 +377,7 @@ test('multiple boolean flag', t => { }); }); -test('multiple boolean flag is false by default', t => { +test('isMultiple - boolean flag is false by default', t => { t.deepEqual(meow({ argv: [], flags: { @@ -391,7 +391,7 @@ test('multiple boolean flag is false by default', t => { }); }); -test('multiple flag with `booleanDefault: undefined` => filter out unset boolean args', t => { +test('isMultiple - flag with `booleanDefault: undefined` => filter out unset boolean args', t => { t.deepEqual(meow({ argv: ['--foo'], booleanDefault: undefined, @@ -410,7 +410,7 @@ test('multiple flag with `booleanDefault: undefined` => filter out unset boolean }); }); -test('multiple number flag', t => { +test('isMultiple - number flag', t => { t.deepEqual(meow({ argv: ['--foo=1.3', '--foo=-1'], flags: { @@ -424,7 +424,7 @@ test('multiple number flag', t => { }); }); -test('multiple flag default values', t => { +test('isMultiple - flag default values', t => { t.deepEqual(meow({ argv: [], flags: { From ed116eb30527b94dd45ddb59afc1c456598ed2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20L=C3=B6fgren?= Date: Tue, 5 May 2020 17:44:20 +0200 Subject: [PATCH 17/17] Add multiple default values test --- test.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test.js b/test.js index 7822d0b..59209f5 100644 --- a/test.js +++ b/test.js @@ -450,3 +450,30 @@ test('isMultiple - flag default values', t => { number: [0.5] }); }); + +test('isMultiple - multiple flag default values', t => { + t.deepEqual(meow({ + argv: [], + flags: { + string: { + type: 'string', + isMultiple: true, + default: ['foo', 'bar'] + }, + boolean: { + type: 'boolean', + isMultiple: true, + default: [true, false] + }, + number: { + type: 'number', + isMultiple: true, + default: [0.5, 1] + } + } + }).flags, { + string: ['foo', 'bar'], + boolean: [true, false], + number: [0.5, 1] + }); +});