///|
fn has_short(opt : StoredOption) -> Bool {
opt.metadata.short != no_short
}
///|
fn build_option_to_flag(
opt : StoredOption,
global? : Bool = false,
) -> @argparse.FlagArg {
let metadata = opt.metadata
let env = metadata.env.map(fn(value) { value[:] })
if has_short(opt) {
@argparse.FlagArg(
opt.name,
short=metadata.short,
about=metadata.description,
env?,
global~,
)
} else {
@argparse.FlagArg(opt.name, about=metadata.description, env?, global~)
}
}
///|
fn build_option_to_option_arg(
opt : StoredOption,
config : Map[String, Json],
interactive? : Bool = false,
global? : Bool = false,
) -> @argparse.OptionArg {
let metadata = opt.metadata
let env = metadata.env.map(fn(value) { value[:] })
let required = metadata.required &&
!config_contains_argument(config, opt) &&
!(interactive && metadata.interactive)
let action = if metadata.multiple {
@argparse.OptionAction::Append
} else {
@argparse.OptionAction::Set
}
match (has_short(opt), metadata.default_value, required) {
(true, Some(dv), _) =>
@argparse.OptionArg(
opt.name,
short=metadata.short,
about=metadata.description,
action~,
env?,
global~,
default_values=[dv],
)
(true, None, true) =>
@argparse.OptionArg(
opt.name,
short=metadata.short,
about=metadata.description,
action~,
env?,
global~,
required=true,
)
(true, None, false) =>
@argparse.OptionArg(
opt.name,
short=metadata.short,
about=metadata.description,
action~,
env?,
global~,
)
(false, Some(dv), _) =>
@argparse.OptionArg(
opt.name,
about=metadata.description,
action~,
env?,
global~,
default_values=[dv],
)
(false, None, true) =>
@argparse.OptionArg(
opt.name,
about=metadata.description,
action~,
env?,
global~,
required=true,
)
(false, None, false) =>
@argparse.OptionArg(
opt.name,
about=metadata.description,
action~,
env?,
global~,
)
}
}
///|
fn build_position(
position : StoredPosition,
config : Map[String, Json],
interactive? : Bool = false,
) -> @argparse.PositionArg {
let metadata = position.metadata
let required = metadata.required &&
!config_contains_argument(config, position) &&
!(interactive && metadata.interactive)
let num_args = match (required, metadata.multiple) {
(true, false) => @argparse.ValueRange::single()
(false, false) => @argparse.ValueRange(lower=0, upper=1)
(true, true) => @argparse.ValueRange(lower=1)
(false, true) => @argparse.ValueRange(lower=0)
}
@argparse.PositionArg(position.name, about=metadata.description, num_args~)
}
///|
fn[T, Metadata] config_contains_argument(
config : Map[String, Json],
argument : ArgDef[T, Metadata],
) -> Bool {
match argument.config {
Some(key) => config.contains(key)
None => false
}
}
///|
fn fallback_to_help_when_no_match(cmd : CommandDef) -> Bool {
cmd.run is None
}
///|
fn build_command_with_config(
cmd : CommandDef,
config : Map[String, Json],
interactive_environment? : Bool = false,
) -> @argparse.Command {
let interactive = interactive_environment && cmd.interactive is Some(_)
let flags : Array[@argparse.FlagArg] = []
let options : Array[@argparse.OptionArg] = []
for opt in cmd.options {
match opt.metadata.type_ {
BoolOpt => flags.push(build_option_to_flag(opt))
StringOpt | IntOpt | Int64Opt | UIntOpt | UInt64Opt | DoubleOpt =>
options.push(build_option_to_option_arg(opt, config, interactive~))
}
}
let positionals = cmd.positionals.map(fn(position) {
build_position(position, config, interactive~)
})
let subcommands = cmd.subcommands.map(fn(sub) {
build_command_with_config(sub, config, interactive_environment~)
})
@argparse.Command(
cmd.name,
about=cmd.description,
flags~,
options~,
positionals~,
subcommands~,
arg_required_else_help=fallback_to_help_when_no_match(cmd),
)
}
///|
pub fn build_command(cmd : CommandDef) -> @argparse.Command {
build_command_with_config(cmd, Map([]))
}