Skip to content

Commit 7210bd5

Browse files
committed
feat: Support required arguments in CLI commands
1 parent 4ee6255 commit 7210bd5

File tree

5 files changed

+63
-1
lines changed

5 files changed

+63
-1
lines changed

__e2e__/config.test.ts

+55
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,31 @@ export default {
157157
};
158158
`;
159159

160+
const USER_CONFIG_COMMAND_ARG_REQUIRED = `;
161+
module.exports = {
162+
commands: [
163+
{
164+
name: 'test-command-arg-required',
165+
description: 'test command',
166+
func: () => {
167+
console.log('ok');
168+
},
169+
options: [
170+
{
171+
name: '--required-arg <string>',
172+
description: 'test command arg',
173+
required: true,
174+
},
175+
{
176+
name: '--optional-arg <string>',
177+
description: 'test command arg',
178+
},
179+
],
180+
},
181+
],
182+
};
183+
`;
184+
160185
test('should read user config from react-native.config.js', () => {
161186
writeFiles(path.join(DIR, 'TestProject'), {
162187
'react-native.config.js': USER_CONFIG,
@@ -275,3 +300,33 @@ test('should read config if using import/export in react-native.config.mjs with
275300
const {stdout} = runCLI(path.join(DIR, 'TestProject'), ['test-command-esm']);
276301
expect(stdout).toMatch('test-command-esm');
277302
});
303+
304+
test('should fail if a required arg is missing', () => {
305+
writeFiles(path.join(DIR, 'TestProject'), {
306+
'react-native.config.cjs': USER_CONFIG_COMMAND_ARG_REQUIRED,
307+
});
308+
309+
const {stderr} = runCLI(
310+
path.join(DIR, 'TestProject'),
311+
['test-command-arg-required', '--optional-arg', 'foo'],
312+
{
313+
expectedFailure: true,
314+
},
315+
);
316+
expect(stderr).toContain(
317+
"required option '--required-arg <string>' not specified",
318+
);
319+
});
320+
321+
test('should not fail if an optional arg is missing', () => {
322+
writeFiles(path.join(DIR, 'TestProject'), {
323+
'react-native.config.js': USER_CONFIG_COMMAND_ARG_REQUIRED,
324+
});
325+
326+
const {stdout} = runCLI(path.join(DIR, 'TestProject'), [
327+
'test-command-arg-required',
328+
'--required-arg',
329+
'bar',
330+
]);
331+
expect(stdout).toMatch('ok');
332+
});

docs/plugins.md

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type Command = {
4747
| boolean
4848
| number
4949
| ((config: ConfigT) => string | boolean | number);
50+
required?: boolean;
5051
}>;
5152
examples?: Array<{
5253
desc: string;
@@ -102,6 +103,10 @@ Default value for the option when not provided. Can be either a primitive value
102103

103104
Useful when you want to use project settings as default value for your option.
104105

106+
##### `options.required`
107+
108+
If true and no default is specified, fail with a friendly error if the user doesn't supply this option.
109+
105110
#### `examples`
106111

107112
An array of example usage of the command to be printed to the user.

packages/cli-config/src/schema.ts

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const command = t.object({
2727
default: t
2828
.alternatives()
2929
.try(t.bool(), t.number(), t.string().allow(''), t.func()),
30+
required: t.bool(),
3031
})
3132
.rename('command', 'name', {ignoreUndefined: true}),
3233
),

packages/cli-types/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export type CommandOption<T = (ctx: Config) => OptionValue> = {
2727
description?: string;
2828
parse?: (val: string) => any;
2929
default?: OptionValue | T;
30+
required?: boolean;
3031
};
3132

3233
export type DetachedCommandFunction<Args = Object> = (

packages/cli/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function attachCommand<C extends Command<boolean>>(
127127
cmd.addHelpText('after', printExamples(command.examples));
128128

129129
for (const opt of command.options || []) {
130-
cmd.option(
130+
cmd[opt.required ? 'requiredOption' : 'option'](
131131
opt.name,
132132
opt.description ?? '',
133133
opt.parse || ((val: any) => val),

0 commit comments

Comments
 (0)