Skip to content

Commit 1609709

Browse files
alexmcmanussindresorhus
andauthoredJan 7, 2021
Fix reporting missing required flags (#168)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent 1d1b6ab commit 1609709

File tree

7 files changed

+34
-6
lines changed

7 files changed

+34
-6
lines changed
 

‎index.d.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ declare namespace meow {
3232
/**
3333
Define argument flags.
3434
35-
The key is the flag name and the value is an object with any of:
35+
The key is the flag name in camel-case and the value is an object with any of:
3636
3737
- `type`: Type of value. (Possible values: `string` `boolean` `number`)
3838
- `alias`: Usually used to define a short flag alias.
@@ -42,6 +42,8 @@ declare namespace meow {
4242
- `isMultiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false)
4343
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.
4444
45+
Note that flags are always defined using a camel-case key (`myKey`), but will match arguments in kebab-case (`--my-key`).
46+
4547
@example
4648
```
4749
flags: {

‎index.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const path = require('path');
33
const buildParserOptions = require('minimist-options');
44
const parseArguments = require('yargs-parser');
55
const camelCaseKeys = require('camelcase-keys');
6+
const decamelize = require('decamelize');
67
const decamelizeKeys = require('decamelize-keys');
78
const trimNewlines = require('trim-newlines');
89
const redent = require('redent');
@@ -50,7 +51,14 @@ const getMissingRequiredFlags = (flags, receivedFlags, input) => {
5051
const reportMissingRequiredFlags = missingRequiredFlags => {
5152
console.error(`Missing required flag${missingRequiredFlags.length > 1 ? 's' : ''}`);
5253
for (const flag of missingRequiredFlags) {
53-
console.error(`\t--${flag.key}${flag.alias ? `, -${flag.alias}` : ''}`);
54+
console.error(`\t--${decamelize(flag.key, '-')}${flag.alias ? `, -${flag.alias}` : ''}`);
55+
}
56+
};
57+
58+
const validateOptions = ({flags}) => {
59+
const invalidFlags = Object.keys(flags).filter(flagKey => flagKey.includes('-') && flagKey !== '--');
60+
if (invalidFlags.length > 0) {
61+
throw new Error(`Flag keys may not contain '-': ${invalidFlags.join(', ')}`);
5462
}
5563
};
5664

@@ -125,6 +133,7 @@ const meow = (helpText, options) => {
125133
hardRejection();
126134
}
127135

136+
validateOptions(options);
128137
let parserOptions = {
129138
arguments: options.input,
130139
...buildParserFlags(options)

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"dependencies": {
4343
"@types/minimist": "^1.2.0",
4444
"camelcase-keys": "^6.2.2",
45+
"decamelize": "^1.2.0",
4546
"decamelize-keys": "^1.1.0",
4647
"hard-rejection": "^2.1.0",
4748
"minimist-options": "4.1.0",

‎readme.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ Type: `object`
132132
133133
Define argument flags.
134134
135-
The key is the flag name and the value is an object with any of:
135+
The key is the flag name in camel-case and the value is an object with any of:
136136
137137
- `type`: Type of value. (Possible values: `string` `boolean` `number`)
138138
- `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:
145145
- `isMultiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false)
146146
- 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).
147147
148+
Note that flags are always defined using a camel-case key (`myKey`), but will match arguments in kebab-case (`--my-key`).
149+
148150
Example:
149151
150152
```js

‎test/fixtures/fixture-required.js

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ const cli = meow({
1818
type: 'number',
1919
isRequired: true
2020
},
21+
kebabCase: {
22+
type: 'string',
23+
isRequired: true
24+
},
2125
notRequired: {
2226
type: 'string'
2327
}

‎test/is-required-flag.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ test('spawn cli and test not specifying required flags', async t => {
1515
t.regex(stderr, /Missing required flag/);
1616
t.regex(stderr, /--test, -t/);
1717
t.regex(stderr, /--number/);
18-
t.notRegex(stderr, /--notRequired/);
18+
t.regex(stderr, /--kebab-case/);
19+
t.notRegex(stderr, /--not-required/);
1920
}
2021
});
2122

@@ -24,7 +25,9 @@ test('spawn cli and test specifying all required flags', async t => {
2425
'-t',
2526
'test',
2627
'--number',
27-
'6'
28+
'6',
29+
'--kebab-case',
30+
'test'
2831
]);
2932
t.is(stdout, 'test,6');
3033
});
@@ -63,7 +66,7 @@ test('spawn cli and test setting isRequired as a function and specifying only th
6366
const {stderr, message} = error;
6467
t.regex(message, /Command failed with exit code 2/);
6568
t.regex(stderr, /Missing required flag/);
66-
t.regex(stderr, /--withTrigger/);
69+
t.regex(stderr, /--with-trigger/);
6770
}
6871
});
6972

‎test/test.js

+7
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ test('single character flag casing should be preserved', t => {
9999
t.deepEqual(meow({argv: ['-F']}).flags, {F: true});
100100
});
101101

102+
test('flag declared in kebab-case is an error', t => {
103+
const error = t.throws(() => {
104+
meow({flags: {'kebab-case': 'boolean', test: 'boolean', 'another-one': 'boolean'}});
105+
});
106+
t.is(error.message, 'Flag keys may not contain \'-\': kebab-case, another-one');
107+
});
108+
102109
test('type inference', t => {
103110
t.is(meow({argv: ['5']}).input[0], '5');
104111
t.is(meow({argv: ['5']}, {input: 'string'}).input[0], '5');

0 commit comments

Comments
 (0)
Please sign in to comment.