diff --git a/index.d.ts b/index.d.ts index df3f10e..56db00d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -32,7 +32,7 @@ declare namespace meow { /** Define argument flags. - The key is the flag name and the value is an object with any of: + The key is the flag name in camel-case 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. @@ -42,6 +42,8 @@ declare namespace meow { - `isMultiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) Multiple values are provided by specifying the flag multiple times, for example, `$ foo -u rainbow -u cat`. Space- or comma-separated values are *not* supported. + Note that flags are always defined using a camel-case key (`myKey`), but will match arguments in kebab-case (`--my-key`). + @example ``` flags: { diff --git a/index.js b/index.js index dccbcb5..75994fa 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ const path = require('path'); const buildParserOptions = require('minimist-options'); const parseArguments = require('yargs-parser'); const camelCaseKeys = require('camelcase-keys'); +const decamelize = require('decamelize'); const decamelizeKeys = require('decamelize-keys'); const trimNewlines = require('trim-newlines'); const redent = require('redent'); @@ -50,7 +51,14 @@ const getMissingRequiredFlags = (flags, receivedFlags, input) => { const reportMissingRequiredFlags = missingRequiredFlags => { console.error(`Missing required flag${missingRequiredFlags.length > 1 ? 's' : ''}`); for (const flag of missingRequiredFlags) { - console.error(`\t--${flag.key}${flag.alias ? `, -${flag.alias}` : ''}`); + console.error(`\t--${decamelize(flag.key, '-')}${flag.alias ? `, -${flag.alias}` : ''}`); + } +}; + +const validateOptions = ({flags}) => { + const invalidFlags = Object.keys(flags).filter(flagKey => flagKey.includes('-') && flagKey !== '--'); + if (invalidFlags.length > 0) { + throw new Error(`Flag keys may not contain '-': ${invalidFlags.join(', ')}`); } }; @@ -117,6 +125,7 @@ const meow = (helpText, options) => { hardRejection(); } + validateOptions(options); let parserOptions = { arguments: options.input, ...buildParserFlags(options) diff --git a/package.json b/package.json index 89485ca..fd367ac 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "dependencies": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", "decamelize-keys": "^1.1.0", "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", diff --git a/readme.md b/readme.md index 1c547dc..b395915 100644 --- a/readme.md +++ b/readme.md @@ -132,7 +132,7 @@ Type: `object` Define argument flags. -The key is the flag name and the value is an object with any of: +The key is the flag name in camel-case 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. @@ -145,6 +145,8 @@ The key is the flag name and the value is an object with any of: - `isMultiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) - Multiple values are provided by specifying the flag multiple times, for example, `$ foo -u rainbow -u cat`. Space- or comma-separated values are [currently *not* supported](https://github.com/sindresorhus/meow/issues/164). +Note that flags are always defined using a camel-case key (`myKey`), but will match arguments in kebab-case (`--my-key`). + Example: ```js diff --git a/test/fixtures/fixture-required.js b/test/fixtures/fixture-required.js index e34577b..2f3690e 100755 --- a/test/fixtures/fixture-required.js +++ b/test/fixtures/fixture-required.js @@ -18,6 +18,10 @@ const cli = meow({ type: 'number', isRequired: true }, + kebabCase: { + type: 'string', + isRequired: true + }, notRequired: { type: 'string' } diff --git a/test/is-required-flag.js b/test/is-required-flag.js index a8c5730..4586b28 100644 --- a/test/is-required-flag.js +++ b/test/is-required-flag.js @@ -15,7 +15,8 @@ test('spawn cli and test not specifying required flags', async t => { t.regex(stderr, /Missing required flag/); t.regex(stderr, /--test, -t/); t.regex(stderr, /--number/); - t.notRegex(stderr, /--notRequired/); + t.regex(stderr, /--kebab-case/); + t.notRegex(stderr, /--not-required/); } }); @@ -24,7 +25,9 @@ test('spawn cli and test specifying all required flags', async t => { '-t', 'test', '--number', - '6' + '6', + '--kebab-case', + 'test' ]); t.is(stdout, 'test,6'); }); @@ -63,7 +66,7 @@ test('spawn cli and test setting isRequired as a function and specifying only th const {stderr, message} = error; t.regex(message, /Command failed with exit code 2/); t.regex(stderr, /Missing required flag/); - t.regex(stderr, /--withTrigger/); + t.regex(stderr, /--with-trigger/); } }); diff --git a/test/test.js b/test/test.js index cfae265..c8dc19d 100644 --- a/test/test.js +++ b/test/test.js @@ -99,6 +99,13 @@ test('single character flag casing should be preserved', t => { t.deepEqual(meow({argv: ['-F']}).flags, {F: true}); }); +test('flag declared in kebab-case is an error', t => { + const error = t.throws(() => { + meow({flags: {'kebab-case': 'boolean', test: 'boolean', 'another-one': 'boolean'}}); + }); + t.is(error.message, 'Flag keys may not contain \'-\': kebab-case, another-one'); +}); + test('type inference', t => { t.is(meow({argv: ['5']}).input[0], '5'); t.is(meow({argv: ['5']}, {input: 'string'}).input[0], '5');