Skip to content

Commit

Permalink
feat: add requires and excludes (#434)
Browse files Browse the repository at this point in the history
  • Loading branch information
hongaar committed Apr 3, 2023
1 parent e5333cf commit 24982cb
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 7 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,10 @@ Adds a positional argument to the command.
string, it will be used as the question text.
- `alias` (string|array) alias or aliases for the argument.
- `coerce` (function) transform function for this argument value (untyped).
- `requires` (string|array) make another option or argument required if the
argument is present
- `excludes` (string|array) exclude another options or argument if the
argument is present

#### `command.option(name, options)`

Expand All @@ -504,7 +508,7 @@ Adds an option to the command.
- Name (string, required) is used to identify the option.
- Options (object, optional) can be provided to change the behavior of the
option. Object with any of these keys:
- `description` (string, optional) is used in help output.
- `description` (string) is used in help output.
- `type` (string) one of `"array"|"boolean"|"count"|"number"|"string"` which
determines the runtime type of the argument. Use count for the number of
times an option was provided (e.g. verbosity levels).
Expand All @@ -516,6 +520,11 @@ Adds an option to the command.
string, it will be used as the question text.
- `alias` (string|array) alias or aliases for the option.
- `coerce` (function) transform function for this option value (untyped).
- `required` (boolean) makes the option required.
- `requires` (string|array) make another option or argument required if the
option is present
- `excludes` (string|array) exclude another options or argument if the option
is present

#### `command.add(command)`

Expand Down
30 changes: 29 additions & 1 deletion examples/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,40 @@ const defaultValues = command("default")
console.log("Args are", args);
});

const constraints = command("constraint")
.argument("arg", {
description: "Required argument",
})
.argument("optionalArg", {
description: "Required argument",
optional: true,
})
.option("opt", { description: "Required option", required: true })
.option("opt1a", {
description: "Also requires option 1a",
requires: "opt1b",
})
.option("opt1b", {
description: "Also requires option 1b",
requires: "opt1a",
})
.option("opt2", { description: "Forbids option 1a", excludes: "opt1a" })
.option("opt3", {
description: "Also requires optionalArg",
requires: "optionalArg",
})

.action((args) => {
console.log("Args are", args);
});

const app = program()
.description("All argument and option types")
.add(string)
.add(number)
.add(boolean)
.add(choices)
.add(defaultValues);
.add(defaultValues)
.add(constraints);

app.runOrRepl();
2 changes: 1 addition & 1 deletion src/argument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ export class Argument extends BaseArg {
* it. See http://yargs.js.org/docs/#api-positionalkey-opt
*/
toYargs<T>(yargs: Argv<T>) {
return yargs.positional(this.name, this.options);
return yargs.positional(this.name, BaseArg.getYargsOptions(this.options));
}
}
12 changes: 12 additions & 0 deletions src/baseArg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type { OptionOptions } from "./option.js";

export interface BaseArgOptions {
prompt?: true | string;
requires?: string | string[];
excludes?: string | string[];
}

// prettier-ignore
Expand Down Expand Up @@ -121,4 +123,14 @@ export class BaseArg {
getOptions() {
return this.options;
}

protected static getYargsOptions<T extends BaseArgOptions>(options: T) {
const { requires, excludes, ...rest } = options;

return {
implies: requires,
conflicts: excludes,
...rest,
};
}
}
8 changes: 5 additions & 3 deletions src/option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ type IgnoreOptions =
| "normalize"
| "number"
| "require"
| "required"
| "requiresArg"
| "skipValidation"
| "string"
| "implies";

export interface OptionOptions
extends Omit<BaseOptions, IgnoreOptions>,
BaseArgOptions {}
BaseArgOptions {
required?: true;
}

export function option(name: string) {
return new Option(name);
Expand All @@ -50,6 +51,7 @@ export class Option extends BaseArg {

configure(options: OptionOptions) {
this.options = options;

return this;
}

Expand All @@ -58,6 +60,6 @@ export class Option extends BaseArg {
* it. See http://yargs.js.org/docs/#api-positionalkey-opt
*/
toYargs<T>(yargs: Argv<T>) {
return yargs.option(this.name, this.options);
return yargs.option(this.name, BaseArg.getYargsOptions(this.options));
}
}
18 changes: 17 additions & 1 deletion tests/types/command.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,23 @@ cmd.argument("foo", { optional: true, default: false }).action((args) => {
expectType<{ foo: boolean }>(args);
});

// @todo: option types
// String option types
cmd.option("foo").action((args) => {
// Default type
expectType<{ foo: unknown }>(args);
});
cmd.option("foo", { type: "string" }).action((args) => {
// Explicit string type
expectType<{ foo: string | undefined }>(args);
});
cmd.option("foo", { default: "string" }).action((args) => {
// Implicit string type
expectType<{ foo: string }>(args);
});
cmd.option("foo", { type: "string", required: true }).action((args) => {
// Required explicit string type
expectType<{ foo: string }>(args);
});

// @fixme: unspecified options are omitted by yargs but are always present in
// the args.

0 comments on commit 24982cb

Please sign in to comment.