SubCmd
SubcommandParserConfig sub_state
finish : CliBuilder state fromAction toAction, { name : Str, description ? Str, mapper : state -> commonState } -> { name : Str, parser : ArgParser commonState, config : SubcommandConfig }
Bundle a CLI builder into a subcommand.
Subcommands use the same CLI builder that top-level CLIs do,
so they are composed using the same tools. The difference lies in
how subcommands are prepared for usage by parents. In addition to
providing a name
and a description
, you also provide a mapper
,
which is a function that converts the subcommand's data into a common
type that all subcommands under a parent command need to share. This
is required since the parent command will have a field (added with
the [field] function) that must have a unified type.
fooSubcommand = { Cli.weave <- foo: Opt.str { short: "f" }, bar: Opt.str { short: "b" }, } |> SubCmd.finish { name: "foobar", description: "Foo and bar subcommand", mapper: FooBar }
optional : List (SubcommandParserConfig sub_state) -> CliBuilder (Result sub_state [NoSubcommand]) GetOptionsAction GetParamsAction
Use previously defined subcommands as data in a parent CLI builder.
Once all options have been parsed, we then check the first parameter passed to see if it's one of the provided subcommands. If so, we parse the remaining arguments as that subcommand's data, and otherwise continue parsing the current command.
The optional
function can only be used after all Opt
fields have been
registered (if any) as we don't want to parse options for a subcommand
instead of a parent, and cannot be used after any parameters have been
registered. This is enforced using the type state pattern, where we encode
the state of the program into its types. If you're curious, check the
internal Builder
module to see how this works using the action
type
variable.
expect foo_subcommand = Opt.str { short: "f" } |> SubCmd.finish { name: "foo", description: "Foo subcommand", mapper: Foo } bar_subcommand = Opt.str { short: "b" } |> SubCmd.finish { name: "bar", description: "Bar subcommand", mapper: Bar } { parser } = SubCmd.optional [foo_subcommand, bar_subcommand], |> Cli.finish { name: "example" } |> Cli.assert_valid parser ["example", "bar", "-b", "abc"] == SuccessfullyParsed (Ok (Bar "abc"))
required : List (SubcommandParserConfig sub_data) -> CliBuilder sub_data GetOptionsAction GetParamsAction
Use previously defined subcommands as data in a parent CLI builder.
Once all options have been parsed, we then check the first parameter passed to see if it's one of the provided subcommands. If so, we parse the remaining arguments as that subcommand's data, and otherwise we fail parsing.
The required
function can only be used after all Opt
fields have been
registered (if any) as we don't want to parse options for a subcommand
instead of a parent, and cannot be used after any parameters have been
registered. This is enforced using the type state pattern, where we encode
the state of the program into its types. If you're curious, check the
internal Builder
module to see how this works using the action
type
variable.
expect foo_subcommand = Opt.str { short: "f" } |> SubCmd.finish { name: "foo", description: "Foo subcommand", mapper: Foo } bar_subcommand = Opt.str { short: "b" } |> SubCmd.finish { name: "bar", description: "Bar subcommand", mapper: Bar } { parser } = SubCmd.required [foo_subcommand, bar_subcommand], |> Cli.finish { name: "example" } |> Cli.assertValid parser ["example", "bar", "-b", "abc"] == SuccessfullyParsed (Bar "abc")