Skip to content

Commit

Permalink
Fix reporting missing required flags (#168)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
alexmcmanus and sindresorhus committed Jan 7, 2021
1 parent 1d1b6ab commit 1609709
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 6 deletions.
4 changes: 3 additions & 1 deletion index.d.ts
Expand Up @@ -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.
Expand All @@ -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: {
Expand Down
11 changes: 10 additions & 1 deletion index.js
Expand Up @@ -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');
Expand Down Expand Up @@ -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(', ')}`);
}
};

Expand Down Expand Up @@ -125,6 +133,7 @@ const meow = (helpText, options) => {
hardRejection();
}

validateOptions(options);
let parserOptions = {
arguments: options.input,
...buildParserFlags(options)
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -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",
Expand Down
4 changes: 3 additions & 1 deletion readme.md
Expand Up @@ -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.
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/fixture-required.js
Expand Up @@ -18,6 +18,10 @@ const cli = meow({
type: 'number',
isRequired: true
},
kebabCase: {
type: 'string',
isRequired: true
},
notRequired: {
type: 'string'
}
Expand Down
9 changes: 6 additions & 3 deletions test/is-required-flag.js
Expand Up @@ -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/);
}
});

Expand All @@ -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');
});
Expand Down Expand Up @@ -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/);
}
});

Expand Down
7 changes: 7 additions & 0 deletions test/test.js
Expand Up @@ -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');
Expand Down

0 comments on commit 1609709

Please sign in to comment.