From d5b2caf698fb9cdacb62825a7f668a44763f6df8 Mon Sep 17 00:00:00 2001 From: Sam Mohr Date: Sat, 21 Dec 2024 02:49:20 -0800 Subject: [PATCH 1/2] Handle non-UTF-8 CLI args --- README.md | 6 +- examples/basic.roc | 6 +- examples/default-values.roc | 6 +- examples/single-arg.roc | 6 +- examples/subcommands.roc | 6 +- package/Arg.roc | 98 ++++++ package/Base.roc | 13 +- package/Builder.roc | 15 +- package/Cli.roc | 26 +- package/CliTest.roc | 4 +- package/ErrorFormatter.roc | 9 +- package/Extract.roc | 47 +-- package/Opt.roc | 590 ++++++++++++++++++++++++++++++++---- package/Param.roc | 540 +++++++++++++++++++++++++++++---- package/Parser.roc | 66 ++-- package/SubCmd.roc | 3 +- 16 files changed, 1225 insertions(+), 216 deletions(-) create mode 100644 package/Arg.roc diff --git a/README.md b/README.md index 437f66e..b82d5cf 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,9 @@ import weaver.Opt import weaver.Cli import weaver.Param -main! = \{} -> - args = Arg.list! {} - +main! = \args -> data = - Cli.parse_or_display_message cli_parser args + Cli.parse_or_display_message cli_parser args Arg.to_os_raw |> try Result.onErr! \message -> try Stdout.line! message Err (Exit 1 "") diff --git a/examples/basic.roc b/examples/basic.roc index 2b5cfc4..6f879d7 100644 --- a/examples/basic.roc +++ b/examples/basic.roc @@ -9,11 +9,9 @@ import weaver.Opt import weaver.Cli import weaver.Param -main! = \{} -> - args = Arg.list! {} - +main! = \args -> data = - Cli.parse_or_display_message cli_parser args + Cli.parse_or_display_message cli_parser args Arg.to_os_raw |> try Result.onErr! \message -> try Stdout.line! message Err (Exit 1 "") diff --git a/examples/default-values.roc b/examples/default-values.roc index 86e1ab5..9ca2fac 100644 --- a/examples/default-values.roc +++ b/examples/default-values.roc @@ -9,11 +9,9 @@ import weaver.Opt import weaver.Cli import weaver.Param -main! = \{} -> - args = Arg.list! {} - +main! = \args -> data = - Cli.parse_or_display_message cli_parser args + Cli.parse_or_display_message cli_parser args Arg.to_os_raw |> try Result.onErr! \message -> try Stdout.line! message Err (Exit 1 "") diff --git a/examples/single-arg.roc b/examples/single-arg.roc index d36c218..2dd6788 100644 --- a/examples/single-arg.roc +++ b/examples/single-arg.roc @@ -8,11 +8,9 @@ import pf.Stdout import weaver.Opt import weaver.Cli -main! = \{} -> - args = Arg.list! {} - +main! = \args -> data = - Cli.parse_or_display_message cli_parser args + Cli.parse_or_display_message cli_parser args Arg.to_os_raw |> try Result.onErr! \message -> try Stdout.line! message Err (Exit 1 "") diff --git a/examples/subcommands.roc b/examples/subcommands.roc index 5503c27..804d8f4 100644 --- a/examples/subcommands.roc +++ b/examples/subcommands.roc @@ -10,11 +10,9 @@ import weaver.Cli import weaver.Param import weaver.SubCmd -main! = \{} -> - args = Arg.list! {} - +main! = \args -> data = - Cli.parse_or_display_message cli_parser args + Cli.parse_or_display_message cli_parser args Arg.to_os_raw |> try Result.onErr! \message -> try Stdout.line! message Err (Exit 1 "") diff --git a/package/Arg.roc b/package/Arg.roc new file mode 100644 index 0000000..d229822 --- /dev/null +++ b/package/Arg.roc @@ -0,0 +1,98 @@ +module [ + Arg, + from_raw_arg, + to_raw_arg, + from_str, + to_str, + to_bytes, + display, +] + +## An OS-aware representation of a command-line argument. +## +## Though we tend to think of args as Unicode strings, most operating systems +## represent command-line arguments as lists of bytes that aren't necessarily +## UTF-8 encoded. Windows doesn't even use bytes, but U16s. +## +## Most of the time, you will pass these to packages and they will handle the +## encoding for you, but for quick-and-dirty code you can use [display] to +## convert these to [Str] in a lossy way. +Arg := [Unix (List U8), Windows (List U16)] implements [Eq, Inspect { toInspector: arg_inspector }] + +arg_inspector : Arg -> Inspector f where f implements InspectFormatter +arg_inspector = \arg -> Inspect.str (display arg) + +## Wrap a raw, OS-aware numeric list into an [Arg]. +from_raw_arg : [Unix (List U8), Windows (List U16)] -> Arg +from_raw_arg = \raw_arg -> @Arg raw_arg + +## Unwrap an [Arg] into a raw, OS-aware numeric list. +## +## This is a good way to pass [Arg]s to Roc packages. +to_raw_arg : Arg -> [Unix (List U8), Windows (List U16)] +to_raw_arg = \@Arg raw_arg -> raw_arg + +## Encode a UTF-8 [Str] to a Unix-flavored [Arg]. +from_str : Str -> Arg +from_str = \str -> + @Arg (Unix (Str.toUtf8 str)) + +## Attempt to decode an [Arg] to a UTF-8 [Str]. +to_str : Arg -> Result Str [InvalidUnicode] +to_str = \@Arg arg -> + # TODO: update when Unicode -> Str conversion is ready: + # https://github.com/roc-lang/roc/issues/7390 + when arg is + Unix unix -> + Str.fromUtf8 unix + |> Result.mapErr \_err -> InvalidUnicode + + Windows _windows -> Err InvalidUnicode + +## Convert an [Arg] to a list of bytes. +to_bytes : Arg -> List U8 +to_bytes = \@Arg arg -> + when arg is + Unix unix -> unix + Windows windows -> + # avoid intermediate list resizing allocations by + # appending to a list instead of using `List.join_map` + helper = \codepoints, bytes -> + when codepoints is + [] -> bytes + [codepoint, .. as rest] -> + lower = codepoint |> Num.toU8 + upper = + codepoint + |> Num.shiftRightBy 8 + |> Num.toU8 + + updatedBytes = + bytes + |> List.append upper + |> List.append lower + + helper rest updatedBytes + + bytesOut = List.withCapacity (2 * List.len windows) + + helper windows bytesOut + +## Convert an Arg to a `Str` for display purposes. +## +## NB: This currently only supports valid UTF-8 Unix strings. Once Roc adds +## support for lossy conversion of Unicode to Str, this will replace invalid +## codepoints with the Unicode replacement character "\uFFFD". +display : Arg -> Str +display = \@Arg arg -> + # TODO: update when Unicode -> Str conversion is ready: + # https://github.com/roc-lang/roc/issues/7390 + when arg is + Unix unix -> + when Str.fromUtf8 unix is + Ok str -> str + Err err -> crash "Invalid UTF-8 string: $(Inspect.toStr err)" + + Windows _windows -> + crash "Windows args cannot currently be displayed" + diff --git a/package/Base.roc b/package/Base.roc index 0d796a0..8303d67 100644 --- a/package/Base.roc +++ b/package/Base.roc @@ -34,7 +34,8 @@ module [ SubcommandsConfig, ] -import Parser exposing [Arg] +import Arg exposing [Arg] +import Parser exposing [ParsedArg] ## The result of attempting to parse args into config data. ArgParserResult a : [ @@ -46,11 +47,11 @@ ArgParserResult a : [ ## The parameters that an [ArgParser] takes to extract data ## from args. -ArgParserParams : { args : List Arg, subcommand_path : List Str } +ArgParserParams : { args : List ParsedArg, subcommand_path : List Str } ## The intermediate state that an [ArgParser] passes between ## different parsing steps. -ArgParserState a : { data : a, remaining_args : List Arg, subcommand_path : List Str } +ArgParserState a : { data : a, remaining_args : List ParsedArg, subcommand_path : List Str } ## A function that takes command line arguments and a subcommand, ## and attempts to extract configuration data from said arguments. @@ -95,7 +96,7 @@ ArgExtractErr : [ MissingParam ParameterConfig, UnrecognizedShortArg Str, UnrecognizedLongArg Str, - ExtraParamProvided Str, + ExtraParamProvided Arg, ] str_type_name = "str" @@ -113,12 +114,12 @@ Plurality : [Optional, One, Many] ## The two built-in flags that we parse automatically. SpecialFlags : { help : Bool, version : Bool } -InvalidValue : [InvalidNumStr, InvalidValue Str] +InvalidValue : [InvalidNumStr, InvalidValue Str, InvalidUnicode] DefaultValue a : [NoDefault, Value a, Generate ({} -> a)] ## A parser that extracts an argument value from a string. -ValueParser a : Str -> Result a InvalidValue +ValueParser a : Arg -> Result a InvalidValue OptionConfigBaseParams : { short ? Str, diff --git a/package/Builder.roc b/package/Builder.roc index 52c51c4..52a764e 100644 --- a/package/Builder.roc +++ b/package/Builder.roc @@ -16,6 +16,7 @@ module [ check_for_help_and_version, ] +import Arg import Base exposing [ ArgParser, ArgParserState, @@ -29,7 +30,7 @@ import Base exposing [ ParameterConfig, SubcommandConfig, ] -import Parser exposing [Arg] +import Parser exposing [ParsedArg] GetOptionsAction : { get_options : {} } GetParamsAction : { get_params : {} } @@ -42,7 +43,7 @@ CliBuilder data from_action to_action := { subcommands : Dict Str SubcommandConfig, } -from_arg_parser : (List Arg -> Result { data : data, remaining_args : List Arg } ArgExtractErr) -> CliBuilder data from_action to_action +from_arg_parser : (List ParsedArg -> Result { data : data, remaining_args : List ParsedArg } ArgExtractErr) -> CliBuilder data from_action to_action from_arg_parser = \parser -> new_parser = \{ args, subcommand_path } -> when parser args is @@ -86,7 +87,7 @@ set_parser = \@CliBuilder builder, parser -> parser, } -update_parser : CliBuilder state from_action to_action, ({ data : state, remaining_args : List Arg } -> Result { data : next_state, remaining_args : List Arg } ArgExtractErr) -> CliBuilder next_state from_action to_action +update_parser : CliBuilder state from_action to_action, ({ data : state, remaining_args : List ParsedArg } -> Result { data : next_state, remaining_args : List ParsedArg } ArgExtractErr) -> CliBuilder next_state from_action to_action update_parser = \@CliBuilder builder, updater -> new_parser = on_successful_arg_parse builder.parser \{ data, remaining_args, subcommand_path } -> @@ -152,7 +153,7 @@ combine = \@CliBuilder left, @CliBuilder right, combiner -> subcommands: Dict.insertAll left.subcommands right.subcommands, } -flag_was_passed : OptionConfig, List Arg -> Bool +flag_was_passed : OptionConfig, List ParsedArg -> Bool flag_was_passed = \option, args -> List.any args \arg -> when arg is @@ -188,7 +189,7 @@ expect |> map Inspected |> into_parts - out = parser { args: [Parameter "123"], subcommand_path: [] } + out = parser { args: [Parameter (Arg.from_str "123")], subcommand_path: [] } out == SuccessfullyParsed { @@ -198,7 +199,7 @@ expect } expect - args = [Parameter "-h"] + args = [Parameter (Arg.from_str "-h")] flag_was_passed help_option args |> Bool.not @@ -213,6 +214,6 @@ expect flag_was_passed help_option args expect - args = [Long { name: "help", value: Ok "123" }] + args = [Long { name: "help", value: Ok (Arg.from_str "123") }] flag_was_passed help_option args diff --git a/package/Cli.roc b/package/Cli.roc index 5c7e627..6469530 100644 --- a/package/Cli.roc +++ b/package/Cli.roc @@ -76,7 +76,7 @@ ## ## expect ## cliParser -## |> Cli.parse_or_display_message ["example", "-a", "123", "-vvv", "file.txt", "file-2.txt"] +## |> Cli.parse_or_display_message ["example", "-a", "123", "-vvv", "file.txt", "file-2.txt"] Arg.to_os_raw ## == Ok { alpha: 123, verbosity: 3, files: ["file.txt", "file-2.txt"] } ## ``` ## @@ -110,7 +110,8 @@ import Base exposing [ CliConfigParams, map_successfully_parsed, ] -import Parser exposing [Arg, parse_args] +import Arg exposing [Arg] +import Parser exposing [ParsedArg, parse_args] import Builder exposing [CliBuilder] import Validate exposing [validate_cli, CliValidationErr] import ErrorFormatter exposing [ @@ -122,7 +123,7 @@ import Help exposing [help_text, usage_help] ## A parser that interprets command line arguments and returns well-formed data. CliParser state : { config : CliConfig, - parser : List Str -> ArgParserResult state, + parser : List Arg -> ArgParserResult state, text_style : TextStyle, } @@ -171,7 +172,7 @@ weave = \left, right, combiner -> Builder.combine left right combiner ## Fail the parsing process if any arguments are left over after parsing. -ensure_all_args_were_parsed : List Arg -> Result {} ArgExtractErr +ensure_all_args_were_parsed : List ParsedArg -> Result {} ArgExtractErr ensure_all_args_were_parsed = \remaining_args -> when remaining_args is [] -> Ok {} @@ -337,7 +338,7 @@ assert_valid = \result -> ## ## expect ## exampleCli -## |> Cli.parse_or_display_message ["example", "-h"] +## |> Cli.parse_or_display_message ["example", "-h"] Arg.to_os_raw ## == Err ## """ ## example v0.1.0 @@ -356,17 +357,17 @@ assert_valid = \result -> ## ## expect ## exampleCli -## |> Cli.parse_or_display_message ["example", "-V"] +## |> Cli.parse_or_display_message ["example", "-V"] Arg.to_os_raw ## == Err "v0.1.0" ## ## expect ## exampleCli -## |> Cli.parse_or_display_message ["example", "-v"] +## |> Cli.parse_or_display_message ["example", "-v"] Arg.to_os_raw ## == Ok { verbosity: 1 } ## ## expect ## exampleCli -## |> Cli.parse_or_display_message ["example", "-x"] +## |> Cli.parse_or_display_message ["example", "-x"] Arg.to_os_raw ## == Err ## """ ## Error: The argument -x was not recognized. @@ -375,8 +376,13 @@ assert_valid = \result -> ## example [OPTIONS] ## """ ## ``` -parse_or_display_message : CliParser data, List Str -> Result data Str -parse_or_display_message = \parser, args -> +parse_or_display_message : CliParser data, List arg, (arg -> [Unix (List U8), Windows (List U16)]) -> Result data Str +parse_or_display_message = \parser, external_args, to_raw_arg -> + args = + external_args + |> List.map to_raw_arg + |> List.map Arg.from_raw_arg + when parser.parser args is SuccessfullyParsed data -> Ok data ShowHelp { subcommand_path } -> Err (help_text parser.config subcommand_path parser.text_style) diff --git a/package/CliTest.roc b/package/CliTest.roc index ac47203..122f8df 100644 --- a/package/CliTest.roc +++ b/package/CliTest.roc @@ -11,7 +11,7 @@ basic_cli = expect basic_cli - |> Cli.parse_or_display_message ["basic-cli", "-a", "123"] + |> Cli.parse_or_display_message ["basic-cli", "-a", "123"] \a -> Unix (Str.toUtf8 a) == Ok (Alpha 123) expect @@ -29,5 +29,5 @@ expect """ basic_cli - |> Cli.parse_or_display_message ["basic-cli", "-h"] + |> Cli.parse_or_display_message ["basic-cli", "-h"] \a -> Unix (Str.toUtf8 a) == Err help_message diff --git a/package/ErrorFormatter.roc b/package/ErrorFormatter.roc index 5eaddd8..b85d4c4 100644 --- a/package/ErrorFormatter.roc +++ b/package/ErrorFormatter.roc @@ -2,6 +2,7 @@ ## they are readable for developers and users on failure. module [format_arg_extract_err, format_cli_validation_err] +import Arg import Base exposing [ ArgExtractErr, ExpectedValue, @@ -67,6 +68,9 @@ format_arg_extract_err = \err -> InvalidValue reason -> "The value provided to $(option_display_name option) was not a valid $(option_type_name option): $(reason)" + InvalidUnicode -> + "The value provided to $(option_display_name option) was not valid UTF-8." + InvalidParamValue value_err param -> when value_err is InvalidNumStr -> @@ -75,6 +79,9 @@ format_arg_extract_err = \err -> InvalidValue reason -> "The value provided to the '$(param |> .name)' parameter was not a valid $(param |> .type |> full_type_name): $(reason)." + InvalidUnicode -> + "The value provided to the '$(param |> .name)' parameter was not valid UTF-8." + MissingParam parameter -> "The '$(parameter |> .name)' parameter did not receive a value." @@ -85,7 +92,7 @@ format_arg_extract_err = \err -> "The argument --$(long) was not recognized." ExtraParamProvided param -> - "The parameter \"$(param)\" was not expected." + "The parameter \"$(Arg.display param)\" was not expected." ## Render [CliValidationErr] errors as readable messages. ## diff --git a/package/Extract.roc b/package/Extract.roc index 6fdf20a..8913f77 100644 --- a/package/Extract.roc +++ b/package/Extract.roc @@ -1,22 +1,23 @@ module [extract_param_values, extract_option_values] +import Arg exposing [Arg] import Base exposing [ArgExtractErr, OptionConfig, ParameterConfig] -import Parser exposing [Arg, ArgValue] +import Parser exposing [ParsedArg, ArgValue] ExtractParamValuesParams : { - args : List Arg, + args : List ParsedArg, param : ParameterConfig, } ExtractParamValuesState : { action : [GetParam, StopParsing], - values : List Str, - remaining_args : List Arg, + values : List Arg, + remaining_args : List ParsedArg, } ExtractParamValuesOutput : { - values : List Str, - remaining_args : List Arg, + values : List Arg, + remaining_args : List ParsedArg, } extract_param_values : ExtractParamValuesParams -> Result ExtractParamValuesOutput ArgExtractErr @@ -37,7 +38,7 @@ extract_param_values = \{ args, param } -> Result.map state_after \{ values, remaining_args } -> { values, remaining_args } -extract_single_param : ExtractParamValuesState, ParameterConfig, Arg -> Result ExtractParamValuesState ArgExtractErr +extract_single_param : ExtractParamValuesState, ParameterConfig, ParsedArg -> Result ExtractParamValuesState ArgExtractErr extract_single_param = \state, param, arg -> when arg is Short short -> @@ -60,19 +61,19 @@ extract_single_param = \state, param, arg -> Many -> Ok { state & values: state.values |> List.append p } ExtractOptionValuesParams : { - args : List Arg, + args : List ParsedArg, option : OptionConfig, } ExtractOptionValuesOutput : { values : List ArgValue, - remaining_args : List Arg, + remaining_args : List ParsedArg, } ExtractOptionValueWalkerState : { action : [FindOption, GetValue], values : List ArgValue, - remaining_args : List Arg, + remaining_args : List ParsedArg, } extract_option_values : ExtractOptionValuesParams -> Result ExtractOptionValuesOutput ArgExtractErr @@ -95,7 +96,7 @@ extract_option_values = \{ args, option } -> GetValue -> Err (NoValueProvidedForOption option) FindOption -> Ok { values, remaining_args } -find_option_for_extraction : ExtractOptionValueWalkerState, Arg, OptionConfig -> Result ExtractOptionValueWalkerState ArgExtractErr +find_option_for_extraction : ExtractOptionValueWalkerState, ParsedArg, OptionConfig -> Result ExtractOptionValueWalkerState ArgExtractErr find_option_for_extraction = \state, arg, option -> when arg is Short short -> @@ -160,16 +161,20 @@ find_options_in_short_group = \state, option, short_group -> values: state.values |> List.concat values, } -get_value_for_extraction : ExtractOptionValueWalkerState, Arg, OptionConfig -> Result ExtractOptionValueWalkerState ArgExtractErr +get_value_for_extraction : ExtractOptionValueWalkerState, ParsedArg, OptionConfig -> Result ExtractOptionValueWalkerState ArgExtractErr get_value_for_extraction = \state, arg, option -> value = when arg is - Short s -> Ok "-$(s)" - ShortGroup { names, complete: Complete } -> Ok "-$(Str.joinWith names "")" - ShortGroup { names, complete: Partial } -> Err (CannotUsePartialShortGroupAsValue option names) - Long { name, value: Ok val } -> Ok "--$(name)=$(val)" - Long { name, value: Err NoValue } -> Ok "--$(name)" - Parameter p -> Ok p - - Result.map value \val -> - { state & action: FindOption, values: state.values |> List.append (Ok val) } + Short s -> Arg.from_str "-$(s)" + ShortGroup { names, complete: Complete } -> Arg.from_str "-$(Str.joinWith names "")" + ShortGroup { names, complete: Partial } -> + return Err (CannotUsePartialShortGroupAsValue option names) + + Long { name, value: Ok val } -> + # Using [Arg.display] is safe here because `val` must be valid UTF-8 to be `Ok` + Arg.from_str "--$(name)=$(Arg.display val)" + + Long { name, value: Err NoValue } -> Arg.from_str "--$(name)" + Parameter p -> p + + Ok { state & action: FindOption, values: state.values |> List.append (Ok value) } diff --git a/package/Opt.roc b/package/Opt.roc index 55b2436..4de5cfc 100644 --- a/package/Opt.roc +++ b/package/Opt.roc @@ -5,6 +5,12 @@ module [ list, flag, count, + arg, + maybe_arg, + arg_list, + bytes, + maybe_bytes, + bytes_list, str, maybe_str, str_list, @@ -49,6 +55,7 @@ module [ i128_list, ] +import Arg exposing [Arg] import Builder exposing [CliBuilder, GetOptionsAction] import Base exposing [ ArgExtractErr, @@ -95,12 +102,12 @@ get_maybe_value = \values, option -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Str -> Result Color [InvalidValue Str] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] ## parse_color = \color -> -## when color is -## "green" -> Ok Green -## "red" -> Ok Red -## "blue" -> Ok Blue +## when Arg.to_str color is +## Ok "green" -> Ok Green +## Ok "red" -> Ok Red +## Ok "blue" -> Ok Blue ## other -> Err (InvalidValue "'$(other)' is not a valid color, must be green, red, or blue") ## ## { parser } = @@ -148,12 +155,12 @@ single = \{ parser, type, short ? "", long ? "", help ? "", default ? NoDefault ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Str -> Result Color [InvalidValue Str] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] ## parse_color = \color -> -## when color is -## "green" -> Ok Green -## "red" -> Ok Red -## "blue" -> Ok Blue +## when Arg.to_str color is +## Ok "green" -> Ok Green +## Ok "red" -> Ok Red +## Ok "blue" -> Ok Blue ## other -> Err (InvalidValue "'$(other)' is not a valid color, must be green, red, or blue") ## ## { parser } = @@ -196,12 +203,12 @@ maybe = \{ parser, type, short ? "", long ? "", help ? "" } -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Str -> Result Color [InvalidValue Str] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] ## parse_color = \color -> -## when color is -## "green" -> Ok Green -## "red" -> Ok Red -## "blue" -> Ok Blue +## when Arg.to_str color is +## Ok "green" -> Ok Green +## Ok "red" -> Ok Red +## Ok "blue" -> Ok Blue ## other -> Err (InvalidValue "'$(other)' is not a valid color, must be green, red, or blue") ## ## { parser } = @@ -282,7 +289,7 @@ count = \{ short ? "", long ? "", help ? "" } -> builder_with_option_parser option value_parser -## Add a required option that takes a string to your CLI builder. +## Add a required option that takes an [Arg] to your CLI builder. ## ## Parsing arguments will fail if the option is not given as an argument ## or a value is not provided to the option. @@ -290,6 +297,160 @@ count = \{ short ? "", long ? "", help ? "" } -> ## ```roc ## expect ## { parser } = +## Opt.arg { long: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example", "--answer=abc"] +## == SuccessfullyParsed (Arg.from_str "abc") +## ``` +arg : DefaultableOptionConfigBaseParams Arg -> CliBuilder Arg GetOptionsAction GetOptionsAction +arg = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: Ok, + type: str_type_name, + short, + long, + help, + default, + } + +## Add an optional option that takes an [Arg] to your CLI builder. +## +## Parsing arguments will fail if more than one instance of the argument +## is provided or there is no value given for the option call. +## +## ```roc +## expect +## { parser } = +## Opt.maybe_arg { long: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example"] +## == SuccessfullyParsed (Err NoValue) +## ``` +maybe_arg : OptionConfigBaseParams -> CliBuilder (Result Arg [NoValue]) GetOptionsAction GetOptionsAction +maybe_arg = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: Ok, + type: str_type_name, + short, + long, + help, + } + +## Add an option that takes an [Arg] and can be given multiple times +## to your CLI builder. +## +## Parsing arguments will fail if any calls of the option don't provide +## a value. +## +## ```roc +## expect +## { parser } = +## Opt.arg_list { long: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example", "-a", "abc", "--answer", "def", "--answer=ghi"] +## == SuccessfullyParsed (List.map ["abc", "def", "ghi"] Arg.from_str) +## ``` +arg_list : OptionConfigBaseParams -> CliBuilder (List Arg) GetOptionsAction GetOptionsAction +arg_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: Ok, + type: str_type_name, + short, + long, + help, + } + +## Add a required option that takes a byte list to your CLI builder. +## +## Parsing arguments will fail if the option is not given as an argument +## or a value is not provided to the option. +## +## ```roc +## expect +## { parser } = +## Opt.bytes { long: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example", "--answer=abc"] +## == SuccessfullyParsed [97, 98, 99] +## ``` +bytes : DefaultableOptionConfigBaseParams (List U8) -> CliBuilder (List U8) GetOptionsAction GetOptionsAction +bytes = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Ok (Arg.to_bytes a), + type: str_type_name, + short, + long, + help, + default, + } + +## Add an optional option that takes a byte list to your CLI builder. +## +## Parsing arguments will fail if more than one instance of the argument +## is provided or there is no value given for the option call. +## +## ```roc +## expect +## { parser } = +## Opt.maybe_bytes { long: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example"] +## == SuccessfullyParsed (Err NoValue) +## ``` +maybe_bytes : OptionConfigBaseParams -> CliBuilder (Result (List U8) [NoValue]) GetOptionsAction GetOptionsAction +maybe_bytes = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Ok (Arg.to_bytes a), + type: str_type_name, + short, + long, + help, + } + +## Add an option that takes a byte list and can be given multiple times +## to your CLI builder. +## +## Parsing arguments will fail if any calls of the option don't provide +## a value. +## +## ```roc +## expect +## { parser } = +## Opt.bytes_list { long: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example", "-a", "abc", "--answer", "def", "--answer=ghi"] +## == SuccessfullyParsed [[97, 98, 99], [100, 101, 102], [103, 104, 105]] +## ``` +bytes_list : OptionConfigBaseParams -> CliBuilder (List (List U8)) GetOptionsAction GetOptionsAction +bytes_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Ok (Arg.to_bytes a), + type: str_type_name, + short, + long, + help, + } + +## Add a required option that takes a string to your CLI builder. +## +## Parsing arguments will fail if the option is not given as an argument, +## a value is not provided to the option, or the value is not valid UTF-8. +## +## ```roc +## expect +## { parser } = ## Opt.str { long: "answer" }, ## |> Cli.finish { name: "example" } ## |> Cli.assert_valid @@ -298,12 +459,21 @@ count = \{ short ? "", long ? "", help ? "" } -> ## == SuccessfullyParsed "abc" ## ``` str : DefaultableOptionConfigBaseParams Str -> CliBuilder Str GetOptionsAction GetOptionsAction -str = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Ok, type: str_type_name, short, long, help, default } +str = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: Arg.to_str, + type: str_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes a string to your CLI builder. ## ## Parsing arguments will fail if more than one instance of the argument -## is provided or there is no value given for the option call. +## is provided, there is no value given for the option call, or the value +## is not valid UTF-8. ## ## ```roc ## expect @@ -316,13 +486,20 @@ str = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_str : OptionConfigBaseParams -> CliBuilder (Result Str [NoValue]) GetOptionsAction GetOptionsAction -maybe_str = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Ok, type: str_type_name, short, long, help } +maybe_str = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: Arg.to_str, + type: str_type_name, + short, + long, + help, + } ## Add an option that takes a string and can be given multiple times ## to your CLI builder. ## ## Parsing arguments will fail if any calls of the option don't provide -## a value. +## a value or any of the values are not valid UTF-8. ## ## ```roc ## expect @@ -335,7 +512,14 @@ maybe_str = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Ok, type: s ## == SuccessfullyParsed ["abc", "def", "ghi"] ## ``` str_list : OptionConfigBaseParams -> CliBuilder (List Str) GetOptionsAction GetOptionsAction -str_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Ok, type: str_type_name, short, long, help } +str_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: Arg.to_str, + type: str_type_name, + short, + long, + help, + } ## Add a required option that takes a `Dec` to your CLI builder. ## @@ -353,7 +537,15 @@ str_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Ok, type: str ## == SuccessfullyParsed 42.5 ## ``` dec : DefaultableOptionConfigBaseParams Dec -> CliBuilder Dec GetOptionsAction GetOptionsAction -dec = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toDec, type: num_type_name, short, long, help, default } +dec = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toDec, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes a `Dec` to your CLI builder. ## @@ -371,7 +563,14 @@ dec = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_dec : OptionConfigBaseParams -> CliBuilder (Result Dec [NoValue]) GetOptionsAction GetOptionsAction -maybe_dec = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toDec, type: num_type_name, short, long, help } +maybe_dec = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toDec, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes a `Dec` and can be given multiple times ## to your CLI builder. @@ -390,7 +589,14 @@ maybe_dec = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toDec, ## == SuccessfullyParsed [1.0, 2.0, -3.0] ## ``` dec_list : OptionConfigBaseParams -> CliBuilder (List Dec) GetOptionsAction GetOptionsAction -dec_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toDec, type: num_type_name, short, long, help } +dec_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toDec, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes a `F32` to your CLI builder. ## @@ -408,7 +614,15 @@ dec_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toDec, ty ## == SuccessfullyParsed 42.5 ## ``` f32 : DefaultableOptionConfigBaseParams F32 -> CliBuilder F32 GetOptionsAction GetOptionsAction -f32 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toF32, type: num_type_name, short, long, help, default } +f32 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toF32, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes a `F32` to your CLI builder. ## @@ -426,7 +640,14 @@ f32 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_f32 : OptionConfigBaseParams -> CliBuilder (Result F32 [NoValue]) GetOptionsAction GetOptionsAction -maybe_f32 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toF32, type: num_type_name, short, long, help } +maybe_f32 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toF32, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes a `F32` and can be given multiple times ## to your CLI builder. @@ -445,7 +666,14 @@ maybe_f32 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toF32, ## == SuccessfullyParsed [1.0, 2.0, -3.0] ## ``` f32_list : OptionConfigBaseParams -> CliBuilder (List F32) GetOptionsAction GetOptionsAction -f32_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toF32, type: num_type_name, short, long, help } +f32_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toF32, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes a `F64` to your CLI builder. ## @@ -463,7 +691,15 @@ f32_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toF32, ty ## == SuccessfullyParsed 42.5 ## ``` f64 : DefaultableOptionConfigBaseParams F64 -> CliBuilder F64 GetOptionsAction GetOptionsAction -f64 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toF64, type: num_type_name, short, long, help, default } +f64 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toF64, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes a `F64` to your CLI builder. ## @@ -481,7 +717,14 @@ f64 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_f64 : OptionConfigBaseParams -> CliBuilder (Result F64 [NoValue]) GetOptionsAction GetOptionsAction -maybe_f64 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toF64, type: num_type_name, short, long, help } +maybe_f64 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toF64, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes a `F64` and can be given multiple times ## to your CLI builder. @@ -500,7 +743,14 @@ maybe_f64 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toF64, ## == SuccessfullyParsed [1.0, 2.0, -3.0] ## ``` f64_list : OptionConfigBaseParams -> CliBuilder (List F64) GetOptionsAction GetOptionsAction -f64_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toF64, type: num_type_name, short, long, help } +f64_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toF64, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes a `U8` to your CLI builder. ## @@ -518,7 +768,15 @@ f64_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toF64, ty ## == SuccessfullyParsed 42 ## ``` u8 : DefaultableOptionConfigBaseParams U8 -> CliBuilder U8 GetOptionsAction GetOptionsAction -u8 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toU8, type: num_type_name, short, long, help, default } +u8 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU8, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes a `U8` to your CLI builder. ## @@ -536,7 +794,14 @@ u8 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { pars ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u8 : OptionConfigBaseParams -> CliBuilder (Result U8 [NoValue]) GetOptionsAction GetOptionsAction -maybe_u8 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU8, type: num_type_name, short, long, help } +maybe_u8 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU8, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes a `U8` and can be given multiple times ## to your CLI builder. @@ -555,7 +820,14 @@ maybe_u8 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU8, ty ## == SuccessfullyParsed [1, 2, 3] ## ``` u8_list : OptionConfigBaseParams -> CliBuilder (List U8) GetOptionsAction GetOptionsAction -u8_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU8, type: num_type_name, short, long, help } +u8_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU8, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes a `U16` to your CLI builder. ## @@ -573,7 +845,15 @@ u8_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU8, type ## == SuccessfullyParsed 42 ## ``` u16 : DefaultableOptionConfigBaseParams U16 -> CliBuilder U16 GetOptionsAction GetOptionsAction -u16 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toU16, type: num_type_name, short, long, help, default } +u16 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU16, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes a `U16` to your CLI builder. ## @@ -591,7 +871,14 @@ u16 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u16 : OptionConfigBaseParams -> CliBuilder (Result U16 [NoValue]) GetOptionsAction GetOptionsAction -maybe_u16 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU16, type: num_type_name, short, long, help } +maybe_u16 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU16, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes a `U16` and can be given multiple times ## to your CLI builder. @@ -610,7 +897,14 @@ maybe_u16 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU16, ## == SuccessfullyParsed [1, 2, 3] ## ``` u16_list : OptionConfigBaseParams -> CliBuilder (List U16) GetOptionsAction GetOptionsAction -u16_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU16, type: num_type_name, short, long, help } +u16_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU16, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes a `U32` to your CLI builder. ## @@ -628,7 +922,15 @@ u16_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU16, ty ## == SuccessfullyParsed 42 ## ``` u32 : DefaultableOptionConfigBaseParams U32 -> CliBuilder U32 GetOptionsAction GetOptionsAction -u32 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toU32, type: num_type_name, short, long, help, default } +u32 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU32, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes a `U32` to your CLI builder. ## @@ -646,7 +948,14 @@ u32 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u32 : OptionConfigBaseParams -> CliBuilder (Result U32 [NoValue]) GetOptionsAction GetOptionsAction -maybe_u32 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU32, type: num_type_name, short, long, help } +maybe_u32 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU32, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes a `U32` and can be given multiple times ## to your CLI builder. @@ -665,7 +974,14 @@ maybe_u32 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU32, ## == SuccessfullyParsed [1, 2, 3] ## ``` u32_list : OptionConfigBaseParams -> CliBuilder (List U32) GetOptionsAction GetOptionsAction -u32_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU32, type: num_type_name, short, long, help } +u32_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU32, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes a `U64` to your CLI builder. ## @@ -683,7 +999,15 @@ u32_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU32, ty ## == SuccessfullyParsed 42 ## ``` u64 : DefaultableOptionConfigBaseParams U64 -> CliBuilder U64 GetOptionsAction GetOptionsAction -u64 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toU64, type: num_type_name, short, long, help, default } +u64 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU64, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes a `U64` to your CLI builder. ## @@ -701,7 +1025,14 @@ u64 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u64 : OptionConfigBaseParams -> CliBuilder (Result U64 [NoValue]) GetOptionsAction GetOptionsAction -maybe_u64 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU64, type: num_type_name, short, long, help } +maybe_u64 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU64, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes a `U64` and can be given multiple times ## to your CLI builder. @@ -720,7 +1051,14 @@ maybe_u64 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU64, ## == SuccessfullyParsed [1, 2, 3] ## ``` u64_list : OptionConfigBaseParams -> CliBuilder (List U64) GetOptionsAction GetOptionsAction -u64_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU64, type: num_type_name, short, long, help } +u64_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU64, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes a `U128` to your CLI builder. ## @@ -738,7 +1076,15 @@ u64_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU64, ty ## == SuccessfullyParsed 42 ## ``` u128 : DefaultableOptionConfigBaseParams U128 -> CliBuilder U128 GetOptionsAction GetOptionsAction -u128 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toU128, type: num_type_name, short, long, help, default } +u128 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU128, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes a `U128` to your CLI builder. ## @@ -756,7 +1102,14 @@ u128 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { pa ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u128 : OptionConfigBaseParams -> CliBuilder (Result U128 [NoValue]) GetOptionsAction GetOptionsAction -maybe_u128 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU128, type: num_type_name, short, long, help } +maybe_u128 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU128, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes a `U128` and can be given multiple times ## to your CLI builder. @@ -775,7 +1128,14 @@ maybe_u128 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toU128 ## == SuccessfullyParsed [1, 2, 3] ## ``` u128_list : OptionConfigBaseParams -> CliBuilder (List U128) GetOptionsAction GetOptionsAction -u128_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU128, type: num_type_name, short, long, help } +u128_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU128, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes an `I8` to your CLI builder. ## @@ -793,7 +1153,15 @@ u128_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toU128, ## == SuccessfullyParsed 42 ## ``` i8 : DefaultableOptionConfigBaseParams I8 -> CliBuilder I8 GetOptionsAction GetOptionsAction -i8 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toI8, type: num_type_name, short, long, help, default } +i8 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI8, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes an `I8` to your CLI builder. ## @@ -811,7 +1179,14 @@ i8 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { pars ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i8 : OptionConfigBaseParams -> CliBuilder (Result I8 [NoValue]) GetOptionsAction GetOptionsAction -maybe_i8 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI8, type: num_type_name, short, long, help } +maybe_i8 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI8, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes an `I8` and can be given multiple times ## to your CLI builder. @@ -830,7 +1205,14 @@ maybe_i8 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI8, ty ## == SuccessfullyParsed [1, 2, 3] ## ``` i8_list : OptionConfigBaseParams -> CliBuilder (List I8) GetOptionsAction GetOptionsAction -i8_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toI8, type: num_type_name, short, long, help } +i8_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI8, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes an `I16` to your CLI builder. ## @@ -848,7 +1230,15 @@ i8_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toI8, type ## == SuccessfullyParsed 42 ## ``` i16 : DefaultableOptionConfigBaseParams I16 -> CliBuilder I16 GetOptionsAction GetOptionsAction -i16 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toI16, type: num_type_name, short, long, help, default } +i16 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI16, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes an `I16` to your CLI builder. ## @@ -866,7 +1256,14 @@ i16 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i16 : OptionConfigBaseParams -> CliBuilder (Result I16 [NoValue]) GetOptionsAction GetOptionsAction -maybe_i16 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI16, type: num_type_name, short, long, help } +maybe_i16 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI16, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes an `I16` and can be given multiple times ## to your CLI builder. @@ -885,7 +1282,14 @@ maybe_i16 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI16, ## == SuccessfullyParsed [1, 2, 3] ## ``` i16_list : OptionConfigBaseParams -> CliBuilder (List I16) GetOptionsAction GetOptionsAction -i16_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toI16, type: num_type_name, short, long, help } +i16_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI16, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes an `I32` to your CLI builder. ## @@ -903,7 +1307,15 @@ i16_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toI16, ty ## == SuccessfullyParsed 42 ## ``` i32 : DefaultableOptionConfigBaseParams I32 -> CliBuilder I32 GetOptionsAction GetOptionsAction -i32 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toI32, type: num_type_name, short, long, help, default } +i32 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI32, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes an `I32` to your CLI builder. ## @@ -921,7 +1333,14 @@ i32 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i32 : OptionConfigBaseParams -> CliBuilder (Result I32 [NoValue]) GetOptionsAction GetOptionsAction -maybe_i32 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI32, type: num_type_name, short, long, help } +maybe_i32 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI32, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes an `I32` and can be given multiple times ## to your CLI builder. @@ -940,7 +1359,14 @@ maybe_i32 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI32, ## == SuccessfullyParsed [1, 2, 3] ## ``` i32_list : OptionConfigBaseParams -> CliBuilder (List I32) GetOptionsAction GetOptionsAction -i32_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toI32, type: num_type_name, short, long, help } +i32_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI32, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes an `I64` to your CLI builder. ## @@ -958,7 +1384,15 @@ i32_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toI32, ty ## == SuccessfullyParsed 42 ## ``` i64 : DefaultableOptionConfigBaseParams I64 -> CliBuilder I64 GetOptionsAction GetOptionsAction -i64 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toI64, type: num_type_name, short, long, help, default } +i64 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI64, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes an `I64` to your CLI builder. ## @@ -976,7 +1410,14 @@ i64 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { par ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i64 : OptionConfigBaseParams -> CliBuilder (Result I64 [NoValue]) GetOptionsAction GetOptionsAction -maybe_i64 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI64, type: num_type_name, short, long, help } +maybe_i64 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI64, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes an `I64` and can be given multiple times ## to your CLI builder. @@ -995,7 +1436,14 @@ maybe_i64 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI64, ## == SuccessfullyParsed [1, 2, 3] ## ``` i64_list : OptionConfigBaseParams -> CliBuilder (List I64) GetOptionsAction GetOptionsAction -i64_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toI64, type: num_type_name, short, long, help } +i64_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI64, + type: num_type_name, + short, + long, + help, + } ## Add a required option that takes an `I128` to your CLI builder. ## @@ -1013,7 +1461,15 @@ i64_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toI64, ty ## == SuccessfullyParsed 42 ## ``` i128 : DefaultableOptionConfigBaseParams I128 -> CliBuilder I128 GetOptionsAction GetOptionsAction -i128 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { parser: Str.toI128, type: num_type_name, short, long, help, default } +i128 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI128, + type: num_type_name, + short, + long, + help, + default, + } ## Add an optional option that takes an `I128` to your CLI builder. ## @@ -1031,7 +1487,14 @@ i128 = \{ short ? "", long ? "", help ? "", default ? NoDefault } -> single { pa ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i128 : OptionConfigBaseParams -> CliBuilder (Result I128 [NoValue]) GetOptionsAction GetOptionsAction -maybe_i128 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI128, type: num_type_name, short, long, help } +maybe_i128 = \{ short ? "", long ? "", help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI128, + type: num_type_name, + short, + long, + help, + } ## Add an option that takes an `I128` and can be given multiple times ## to your CLI builder. @@ -1050,4 +1513,11 @@ maybe_i128 = \{ short ? "", long ? "", help ? "" } -> maybe { parser: Str.toI128 ## == SuccessfullyParsed [1, 2, 3] ## ``` i128_list : OptionConfigBaseParams -> CliBuilder (List I128) GetOptionsAction GetOptionsAction -i128_list = \{ short ? "", long ? "", help ? "" } -> list { parser: Str.toI128, type: num_type_name, short, long, help } +i128_list = \{ short ? "", long ? "", help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI128, + type: num_type_name, + short, + long, + help, + } diff --git a/package/Param.roc b/package/Param.roc index 3c650b6..15639dc 100644 --- a/package/Param.roc +++ b/package/Param.roc @@ -2,6 +2,12 @@ module [ single, maybe, list, + arg, + maybe_arg, + arg_list, + bytes, + maybe_bytes, + bytes_list, str, maybe_str, str_list, @@ -46,6 +52,7 @@ module [ i128_list, ] +import Arg exposing [Arg] import Builder exposing [ CliBuilder, GetParamsAction, @@ -64,7 +71,7 @@ import Base exposing [ import Parser exposing [ArgValue] import Extract exposing [extract_param_values] -builder_with_parameter_parser : ParameterConfig, (List Str -> Result data ArgExtractErr) -> CliBuilder data from_action to_action +builder_with_parameter_parser : ParameterConfig, (List Arg -> Result data ArgExtractErr) -> CliBuilder data from_action to_action builder_with_parameter_parser = \param, value_parser -> arg_parser = \args -> { values, remaining_args } = try extract_param_values { args, param } @@ -96,12 +103,12 @@ builder_with_parameter_parser = \param, value_parser -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Str -> Result Color [InvalidValue Str] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] ## parse_color = \color -> -## when color is -## "green" -> Ok Green -## "red" -> Ok Red -## "blue" -> Ok Blue +## when Arg.to_str color is +## Ok "green" -> Ok Green +## Ok "red" -> Ok Red +## Ok "blue" -> Ok Blue ## other -> Err (InvalidValue "'$(other)' is not a valid color, must be green, red, or blue") ## ## { parser } = @@ -151,12 +158,12 @@ single = \{ parser, type, name, help ? "", default ? NoDefault } -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Str -> Result Color [InvalidValue Str] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] ## parse_color = \color -> -## when color is -## "green" -> Ok Green -## "red" -> Ok Red -## "blue" -> Ok Blue +## when Arg.to_str color is +## Ok "green" -> Ok Green +## Ok "red" -> Ok Red +## Ok "blue" -> Ok Blue ## other -> Err (InvalidValue "'$(other)' is not a valid color, must be green, red, or blue") ## ## { parser } = @@ -202,12 +209,12 @@ maybe = \{ parser, type, name, help ? "" } -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Str -> Result Color [InvalidValue Str] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] ## parse_color = \color -> -## when color is -## "green" -> Ok Green -## "red" -> Ok Red -## "blue" -> Ok Blue +## when Arg.to_str color is +## Ok "green" -> Ok Green +## Ok "red" -> Ok Red +## Ok "blue" -> Ok Blue ## other -> Err (InvalidValue "'$(other)' is not a valid color, must be green, red, or blue") ## ## { parser } = @@ -228,13 +235,156 @@ list = \{ parser, type, name, help ? "" } -> builder_with_parameter_parser param value_parser -## Add a required string parameter to your CLI builder. +## Add a required [Arg] parameter to your CLI builder. +## +## Parsing arguments will fail if the parameter is not provided. +## +## ```roc +## expect +## { parser } = +## Param.arg { name: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example", "abc"] +## == SuccessfullyParsed (Arg.from_str "abc") +## ``` +arg : DefaultableParameterConfigBaseParams Arg -> CliBuilder Arg {}action GetParamsAction +arg = \{ name, help ? "", default ? NoDefault } -> + single { + parser: Ok, + type: str_type_name, + name, + help, + default, + } + +## Add an optional [Arg] parameter to your CLI builder. +## +## Parsing arguments cannot fail because of this parameter. +## +## ```roc +## expect +## { parser } = +## Param.maybe_arg { name: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example"] +## == SuccessfullyParsed (Err NoValue) +## ``` +maybe_arg : ParameterConfigBaseParams -> CliBuilder ArgValue {}action GetParamsAction +maybe_arg = \{ name, help ? "" } -> + maybe { + parser: Ok, + type: str_type_name, + name, + help, + } + +## Add an [Arg] parameter that can be provided multiple times +## to your CLI builder. +## +## Parsing arguments cannot fail because of this parameter. +## +## ```roc +## expect +## { parser } = +## Param.arg_list { name: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example", "abc", "def", "ghi"] +## == SuccessfullyParsed (List.map ["abc", "def", "ghi"] Arg.from_str) +## ``` +arg_list : ParameterConfigBaseParams -> CliBuilder (List Arg) {}action StopCollectingAction +arg_list = \{ name, help ? "" } -> + list { + parser: Ok, + type: str_type_name, + name, + help, + } + +## Add a required byte list parameter to your CLI builder. ## ## Parsing arguments will fail if the parameter is not provided. ## ## ```roc ## expect ## { parser } = +## Param.arg { name: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example", "abc"] +## == SuccessfullyParsed [97, 98, 99] +## ``` +bytes : DefaultableParameterConfigBaseParams (List U8) -> CliBuilder (List U8) {}action GetParamsAction +bytes = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Ok (Arg.to_bytes a), + type: str_type_name, + name, + help, + default, + } + +## Add an optional byte list parameter to your CLI builder. +## +## Parsing arguments cannot fail because of this parameter. +## +## ```roc +## expect +## { parser } = +## Param.maybe_bytes { name: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example"] +## == SuccessfullyParsed (Err NoValue) +## ``` +maybe_bytes : ParameterConfigBaseParams -> CliBuilder (Result (List U8) [NoValue]) {}action GetParamsAction +maybe_bytes = \{ name, help ? "" } -> + maybe { + parser: \a -> Ok (Arg.to_bytes a), + type: str_type_name, + name, + help, + } + +## Add a byte list parameter that can be provided multiple times +## to your CLI builder. +## +## Parsing arguments cannot fail because of this parameter. +## +## ```roc +## expect +## { parser } = +## Param.bytes_list { name: "answer" }, +## |> Cli.finish { name: "example" } +## |> Cli.assert_valid +## +## parser ["example", "abc", "def", "ghi"] +## == SuccessfullyParsed [[97, 98, 99], [100, 101, 102], [103, 104, 105]] +## ``` +bytes_list : ParameterConfigBaseParams -> CliBuilder (List (List U8)) {}action StopCollectingAction +bytes_list = \{ name, help ? "" } -> + list { + parser: \a -> Ok (Arg.to_bytes a), + type: str_type_name, + name, + help, + } + +## Add a required string parameter to your CLI builder. +## +## Parsing arguments will fail if the parameter is not provided +## or if it is not valid UTF-8. +## +## ```roc +## expect +## { parser } = ## Param.str { name: "answer" }, ## |> Cli.finish { name: "example" } ## |> Cli.assert_valid @@ -243,11 +393,18 @@ list = \{ parser, type, name, help ? "" } -> ## == SuccessfullyParsed "abc" ## ``` str : DefaultableParameterConfigBaseParams Str -> CliBuilder Str {}action GetParamsAction -str = \{ name, help ? "", default ? NoDefault } -> single { parser: Ok, type: str_type_name, name, help, default } +str = \{ name, help ? "", default ? NoDefault } -> + single { + parser: Arg.to_str, + type: str_type_name, + name, + help, + default, + } ## Add an optional string parameter to your CLI builder. ## -## Parsing arguments cannot fail because of this parameter. +## Parsing arguments will fail if the parameter is not valid UTF-8. ## ## ```roc ## expect @@ -259,13 +416,19 @@ str = \{ name, help ? "", default ? NoDefault } -> single { parser: Ok, type: st ## parser ["example"] ## == SuccessfullyParsed (Err NoValue) ## ``` -maybe_str : ParameterConfigBaseParams -> CliBuilder ArgValue {}action GetParamsAction -maybe_str = \{ name, help ? "" } -> maybe { parser: Ok, type: str_type_name, name, help } +maybe_str : ParameterConfigBaseParams -> CliBuilder (Result Str [NoValue]) {}action GetParamsAction +maybe_str = \{ name, help ? "" } -> + maybe { + parser: Arg.to_str, + type: str_type_name, + name, + help, + } ## Add a string parameter that can be provided multiple times ## to your CLI builder. ## -## Parsing arguments cannot fail because of this parameter. +## Parsing arguments will fail if any of the arguments are not valid UTF-8. ## ## ```roc ## expect @@ -278,7 +441,13 @@ maybe_str = \{ name, help ? "" } -> maybe { parser: Ok, type: str_type_name, nam ## == SuccessfullyParsed ["abc", "def", "ghi"] ## ``` str_list : ParameterConfigBaseParams -> CliBuilder (List Str) {}action StopCollectingAction -str_list = \{ name, help ? "" } -> list { parser: Ok, type: str_type_name, name, help } +str_list = \{ name, help ? "" } -> + list { + parser: Arg.to_str, + type: str_type_name, + name, + help, + } ## Add a required `Dec` parameter to your CLI builder. ## @@ -296,7 +465,14 @@ str_list = \{ name, help ? "" } -> list { parser: Ok, type: str_type_name, name, ## == SuccessfullyParsed 42.5 ## ``` dec : DefaultableParameterConfigBaseParams Dec -> CliBuilder Dec {}action GetParamsAction -dec = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toDec, type: num_type_name, name, help, default } +dec = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toDec, + type: num_type_name, + name, + help, + default, + } ## Add an optional `Dec` parameter to your CLI builder. ## @@ -313,7 +489,13 @@ dec = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toDec, t ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_dec : ParameterConfigBaseParams -> CliBuilder (Result Dec [NoValue]) {}action GetParamsAction -maybe_dec = \{ name, help ? "" } -> maybe { parser: Str.toDec, type: num_type_name, name, help } +maybe_dec = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toDec, + type: num_type_name, + name, + help, + } ## Add a `Dec` parameter that can be provided multiple times ## to your CLI builder. @@ -332,7 +514,13 @@ maybe_dec = \{ name, help ? "" } -> maybe { parser: Str.toDec, type: num_type_na ## == SuccessfullyParsed [12.0, 34.0, -56.0] ## ``` dec_list : ParameterConfigBaseParams -> CliBuilder (List Dec) {}action StopCollectingAction -dec_list = \{ name, help ? "" } -> list { parser: Str.toDec, type: num_type_name, name, help } +dec_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toDec, + type: num_type_name, + name, + help, + } ## Add a required `F32` parameter to your CLI builder. ## @@ -350,7 +538,14 @@ dec_list = \{ name, help ? "" } -> list { parser: Str.toDec, type: num_type_name ## == SuccessfullyParsed 42.5 ## ``` f32 : DefaultableParameterConfigBaseParams F32 -> CliBuilder F32 {}action GetParamsAction -f32 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toF32, type: num_type_name, name, help, default } +f32 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toF32, + type: num_type_name, + name, + help, + default, + } ## Add an optional `F32` parameter to your CLI builder. ## @@ -367,7 +562,13 @@ f32 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toF32, t ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_f32 : ParameterConfigBaseParams -> CliBuilder (Result F32 [NoValue]) {}action GetParamsAction -maybe_f32 = \{ name, help ? "" } -> maybe { parser: Str.toF32, type: num_type_name, name, help } +maybe_f32 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toF32, + type: num_type_name, + name, + help, + } ## Add a `F32` parameter that can be provided multiple times ## to your CLI builder. @@ -386,7 +587,13 @@ maybe_f32 = \{ name, help ? "" } -> maybe { parser: Str.toF32, type: num_type_na ## == SuccessfullyParsed [12.0, 34.0, -56.0] ## ``` f32_list : ParameterConfigBaseParams -> CliBuilder (List F32) {}action StopCollectingAction -f32_list = \{ name, help ? "" } -> list { parser: Str.toF32, type: num_type_name, name, help } +f32_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toF32, + type: num_type_name, + name, + help, + } ## Add a required `F64` parameter to your CLI builder. ## @@ -404,7 +611,14 @@ f32_list = \{ name, help ? "" } -> list { parser: Str.toF32, type: num_type_name ## == SuccessfullyParsed 42.5 ## ``` f64 : DefaultableParameterConfigBaseParams F64 -> CliBuilder F64 {}action GetParamsAction -f64 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toF64, type: num_type_name, name, help, default } +f64 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toF64, + type: num_type_name, + name, + help, + default, + } ## Add an optional `F64` parameter to your CLI builder. ## @@ -421,7 +635,13 @@ f64 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toF64, t ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_f64 : ParameterConfigBaseParams -> CliBuilder (Result F64 [NoValue]) {}action GetParamsAction -maybe_f64 = \{ name, help ? "" } -> maybe { parser: Str.toF64, type: num_type_name, name, help } +maybe_f64 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toF64, + type: num_type_name, + name, + help, + } ## Add a `F64` parameter that can be provided multiple times ## to your CLI builder. @@ -440,7 +660,13 @@ maybe_f64 = \{ name, help ? "" } -> maybe { parser: Str.toF64, type: num_type_na ## == SuccessfullyParsed [12, 34, -56.0] ## ``` f64_list : ParameterConfigBaseParams -> CliBuilder (List F64) {}action StopCollectingAction -f64_list = \{ name, help ? "" } -> list { parser: Str.toF64, type: num_type_name, name, help } +f64_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toF64, + type: num_type_name, + name, + help, + } ## Add a required `U8` parameter to your CLI builder. ## @@ -458,7 +684,14 @@ f64_list = \{ name, help ? "" } -> list { parser: Str.toF64, type: num_type_name ## == SuccessfullyParsed 42 ## ``` u8 : DefaultableParameterConfigBaseParams U8 -> CliBuilder U8 {}action GetParamsAction -u8 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU8, type: num_type_name, name, help, default } +u8 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU8, + type: num_type_name, + name, + help, + default, + } ## Add an optional `U8` parameter to your CLI builder. ## @@ -475,7 +708,13 @@ u8 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU8, typ ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u8 : ParameterConfigBaseParams -> CliBuilder (Result U8 [NoValue]) {}action GetParamsAction -maybe_u8 = \{ name, help ? "" } -> maybe { parser: Str.toU8, type: num_type_name, name, help } +maybe_u8 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU8, + type: num_type_name, + name, + help, + } ## Add a `U8` parameter that can be provided multiple times ## to your CLI builder. @@ -494,7 +733,13 @@ maybe_u8 = \{ name, help ? "" } -> maybe { parser: Str.toU8, type: num_type_name ## == SuccessfullyParsed [12, 34, 56] ## ``` u8_list : ParameterConfigBaseParams -> CliBuilder (List U8) {}action StopCollectingAction -u8_list = \{ name, help ? "" } -> list { parser: Str.toU8, type: num_type_name, name, help } +u8_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU8, + type: num_type_name, + name, + help, + } ## Add a required `U16` parameter to your CLI builder. ## @@ -512,7 +757,14 @@ u8_list = \{ name, help ? "" } -> list { parser: Str.toU8, type: num_type_name, ## == SuccessfullyParsed 42 ## ``` u16 : DefaultableParameterConfigBaseParams U16 -> CliBuilder U16 {}action GetParamsAction -u16 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU16, type: num_type_name, name, help, default } +u16 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU16, + type: num_type_name, + name, + help, + default, + } ## Add an optional `U16` parameter to your CLI builder. ## @@ -529,7 +781,13 @@ u16 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU16, t ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u16 : ParameterConfigBaseParams -> CliBuilder (Result U16 [NoValue]) {}action GetParamsAction -maybe_u16 = \{ name, help ? "" } -> maybe { parser: Str.toU16, type: num_type_name, name, help } +maybe_u16 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU16, + type: num_type_name, + name, + help, + } ## Add a `U16` parameter that can be provided multiple times ## to your CLI builder. @@ -548,7 +806,13 @@ maybe_u16 = \{ name, help ? "" } -> maybe { parser: Str.toU16, type: num_type_na ## == SuccessfullyParsed [12, 34, 56] ## ``` u16_list : ParameterConfigBaseParams -> CliBuilder (List U16) {}action StopCollectingAction -u16_list = \{ name, help ? "" } -> list { parser: Str.toU16, type: num_type_name, name, help } +u16_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU16, + type: num_type_name, + name, + help, + } ## Add a required `U32` parameter to your CLI builder. ## @@ -566,7 +830,14 @@ u16_list = \{ name, help ? "" } -> list { parser: Str.toU16, type: num_type_name ## == SuccessfullyParsed 42 ## ``` u32 : DefaultableParameterConfigBaseParams U32 -> CliBuilder U32 {}action GetParamsAction -u32 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU32, type: num_type_name, name, help, default } +u32 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU32, + type: num_type_name, + name, + help, + default, + } ## Add an optional `U32` parameter to your CLI builder. ## @@ -583,7 +854,13 @@ u32 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU32, t ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u32 : ParameterConfigBaseParams -> CliBuilder (Result U32 [NoValue]) {}action GetParamsAction -maybe_u32 = \{ name, help ? "" } -> maybe { parser: Str.toU32, type: num_type_name, name, help } +maybe_u32 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU32, + type: num_type_name, + name, + help, + } ## Add a `U32` parameter that can be provided multiple times ## to your CLI builder. @@ -602,7 +879,13 @@ maybe_u32 = \{ name, help ? "" } -> maybe { parser: Str.toU32, type: num_type_na ## == SuccessfullyParsed [12, 34, 56] ## ``` u32_list : ParameterConfigBaseParams -> CliBuilder (List U32) {}action StopCollectingAction -u32_list = \{ name, help ? "" } -> list { parser: Str.toU32, type: num_type_name, name, help } +u32_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU32, + type: num_type_name, + name, + help, + } ## Add a required `U64` parameter to your CLI builder. ## @@ -620,7 +903,14 @@ u32_list = \{ name, help ? "" } -> list { parser: Str.toU32, type: num_type_name ## == SuccessfullyParsed 42 ## ``` u64 : DefaultableParameterConfigBaseParams U64 -> CliBuilder U64 {}action GetParamsAction -u64 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU64, type: num_type_name, name, help, default } +u64 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU64, + type: num_type_name, + name, + help, + default, + } ## Add an optional `U64` parameter to your CLI builder. ## @@ -637,7 +927,13 @@ u64 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU64, t ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u64 : ParameterConfigBaseParams -> CliBuilder (Result U64 [NoValue]) {}action GetParamsAction -maybe_u64 = \{ name, help ? "" } -> maybe { parser: Str.toU64, type: num_type_name, name, help } +maybe_u64 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU64, + type: num_type_name, + name, + help, + } ## Add a `U64` parameter that can be provided multiple times ## to your CLI builder. @@ -656,7 +952,13 @@ maybe_u64 = \{ name, help ? "" } -> maybe { parser: Str.toU64, type: num_type_na ## == SuccessfullyParsed [12, 34, 56] ## ``` u64_list : ParameterConfigBaseParams -> CliBuilder (List U64) {}action StopCollectingAction -u64_list = \{ name, help ? "" } -> list { parser: Str.toU64, type: num_type_name, name, help } +u64_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU64, + type: num_type_name, + name, + help, + } ## Add a required `U128` parameter to your CLI builder. ## @@ -674,7 +976,14 @@ u64_list = \{ name, help ? "" } -> list { parser: Str.toU64, type: num_type_name ## == SuccessfullyParsed 42 ## ``` u128 : DefaultableParameterConfigBaseParams U128 -> CliBuilder U128 {}action GetParamsAction -u128 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU128, type: num_type_name, name, help, default } +u128 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toU128, + type: num_type_name, + name, + help, + default, + } ## Add an optional `U128` parameter to your CLI builder. ## @@ -691,7 +1000,13 @@ u128 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toU128, ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_u128 : ParameterConfigBaseParams -> CliBuilder (Result U128 [NoValue]) {}action GetParamsAction -maybe_u128 = \{ name, help ? "" } -> maybe { parser: Str.toU128, type: num_type_name, name, help } +maybe_u128 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toU128, + type: num_type_name, + name, + help, + } ## Add a `U128` parameter that can be provided multiple times ## to your CLI builder. @@ -710,7 +1025,13 @@ maybe_u128 = \{ name, help ? "" } -> maybe { parser: Str.toU128, type: num_type_ ## == SuccessfullyParsed [12, 34, 56] ## ``` u128_list : ParameterConfigBaseParams -> CliBuilder (List U128) {}action StopCollectingAction -u128_list = \{ name, help ? "" } -> list { parser: Str.toU128, type: num_type_name, name, help } +u128_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toU128, + type: num_type_name, + name, + help, + } ## Add a required `I8` parameter to your CLI builder. ## @@ -728,7 +1049,14 @@ u128_list = \{ name, help ? "" } -> list { parser: Str.toU128, type: num_type_na ## == SuccessfullyParsed 42 ## ``` i8 : DefaultableParameterConfigBaseParams I8 -> CliBuilder I8 {}action GetParamsAction -i8 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI8, type: num_type_name, name, help, default } +i8 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI8, + type: num_type_name, + name, + help, + default, + } ## Add an optional `I8` parameter to your CLI builder. ## @@ -745,7 +1073,13 @@ i8 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI8, typ ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i8 : ParameterConfigBaseParams -> CliBuilder (Result I8 [NoValue]) {}action GetParamsAction -maybe_i8 = \{ name, help ? "" } -> maybe { parser: Str.toI8, type: num_type_name, name, help } +maybe_i8 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI8, + type: num_type_name, + name, + help, + } ## Add an `I8` parameter that can be provided multiple times ## to your CLI builder. @@ -764,7 +1098,13 @@ maybe_i8 = \{ name, help ? "" } -> maybe { parser: Str.toI8, type: num_type_name ## == SuccessfullyParsed [12, 34, -56] ## ``` i8_list : ParameterConfigBaseParams -> CliBuilder (List I8) {}action StopCollectingAction -i8_list = \{ name, help ? "" } -> list { parser: Str.toI8, type: num_type_name, name, help } +i8_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI8, + type: num_type_name, + name, + help, + } ## Add a required `I16` parameter to your CLI builder. ## @@ -782,7 +1122,14 @@ i8_list = \{ name, help ? "" } -> list { parser: Str.toI8, type: num_type_name, ## == SuccessfullyParsed 42 ## ``` i16 : DefaultableParameterConfigBaseParams I16 -> CliBuilder I16 {}action GetParamsAction -i16 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI16, type: num_type_name, name, help, default } +i16 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI16, + type: num_type_name, + name, + help, + default, + } ## Add an optional `I16` parameter to your CLI builder. ## @@ -799,7 +1146,13 @@ i16 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI16, t ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i16 : ParameterConfigBaseParams -> CliBuilder (Result I16 [NoValue]) {}action GetParamsAction -maybe_i16 = \{ name, help ? "" } -> maybe { parser: Str.toI16, type: num_type_name, name, help } +maybe_i16 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI16, + type: num_type_name, + name, + help, + } ## Add an `I16` parameter that can be provided multiple times ## to your CLI builder. @@ -818,7 +1171,13 @@ maybe_i16 = \{ name, help ? "" } -> maybe { parser: Str.toI16, type: num_type_na ## == SuccessfullyParsed [12, 34, -56] ## ``` i16_list : ParameterConfigBaseParams -> CliBuilder (List I16) {}action StopCollectingAction -i16_list = \{ name, help ? "" } -> list { parser: Str.toI16, type: num_type_name, name, help } +i16_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI16, + type: num_type_name, + name, + help, + } ## Add a required `I32` parameter to your CLI builder. ## @@ -836,7 +1195,14 @@ i16_list = \{ name, help ? "" } -> list { parser: Str.toI16, type: num_type_name ## == SuccessfullyParsed 42 ## ``` i32 : DefaultableParameterConfigBaseParams I32 -> CliBuilder I32 {}action GetParamsAction -i32 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI32, type: num_type_name, name, help, default } +i32 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI32, + type: num_type_name, + name, + help, + default, + } ## Add an optional `I32` parameter to your CLI builder. ## @@ -853,7 +1219,13 @@ i32 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI32, t ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i32 : ParameterConfigBaseParams -> CliBuilder (Result I32 [NoValue]) {}action GetParamsAction -maybe_i32 = \{ name, help ? "" } -> maybe { parser: Str.toI32, type: num_type_name, name, help } +maybe_i32 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI32, + type: num_type_name, + name, + help, + } ## Add an `I32` parameter that can be provided multiple times ## to your CLI builder. @@ -872,7 +1244,13 @@ maybe_i32 = \{ name, help ? "" } -> maybe { parser: Str.toI32, type: num_type_na ## == SuccessfullyParsed [12, 34, -56] ## ``` i32_list : ParameterConfigBaseParams -> CliBuilder (List I32) {}action StopCollectingAction -i32_list = \{ name, help ? "" } -> list { parser: Str.toI32, type: num_type_name, name, help } +i32_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI32, + type: num_type_name, + name, + help, + } ## Add a required `I64` parameter to your CLI builder. ## @@ -890,7 +1268,14 @@ i32_list = \{ name, help ? "" } -> list { parser: Str.toI32, type: num_type_name ## == SuccessfullyParsed 42 ## ``` i64 : DefaultableParameterConfigBaseParams I64 -> CliBuilder I64 {}action GetParamsAction -i64 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI64, type: num_type_name, name, help, default } +i64 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI64, + type: num_type_name, + name, + help, + default, + } ## Add an optional `I64` parameter to your CLI builder. ## @@ -907,7 +1292,13 @@ i64 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI64, t ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i64 : ParameterConfigBaseParams -> CliBuilder (Result I64 [NoValue]) {}action GetParamsAction -maybe_i64 = \{ name, help ? "" } -> maybe { parser: Str.toI64, type: num_type_name, name, help } +maybe_i64 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI64, + type: num_type_name, + name, + help, + } ## Add an `I64` parameter that can be provided multiple times ## to your CLI builder. @@ -926,7 +1317,13 @@ maybe_i64 = \{ name, help ? "" } -> maybe { parser: Str.toI64, type: num_type_na ## == SuccessfullyParsed [12, 34, -56] ## ``` i64_list : ParameterConfigBaseParams -> CliBuilder (List I64) {}action StopCollectingAction -i64_list = \{ name, help ? "" } -> list { parser: Str.toI64, type: num_type_name, name, help } +i64_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI64, + type: num_type_name, + name, + help, + } ## Add a required `I128` parameter to your CLI builder. ## @@ -944,7 +1341,14 @@ i64_list = \{ name, help ? "" } -> list { parser: Str.toI64, type: num_type_name ## == SuccessfullyParsed 42 ## ``` i128 : DefaultableParameterConfigBaseParams I128 -> CliBuilder I128 {}action GetParamsAction -i128 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI128, type: num_type_name, name, help, default } +i128 = \{ name, help ? "", default ? NoDefault } -> + single { + parser: \a -> Arg.to_str a |> Result.try Str.toI128, + type: num_type_name, + name, + help, + default, + } ## Add an optional `I128` parameter to your CLI builder. ## @@ -961,7 +1365,13 @@ i128 = \{ name, help ? "", default ? NoDefault } -> single { parser: Str.toI128, ## == SuccessfullyParsed (Err NoValue) ## ``` maybe_i128 : ParameterConfigBaseParams -> CliBuilder (Result I128 [NoValue]) {}action GetParamsAction -maybe_i128 = \{ name, help ? "" } -> maybe { parser: Str.toI128, type: num_type_name, name, help } +maybe_i128 = \{ name, help ? "" } -> + maybe { + parser: \a -> Arg.to_str a |> Result.try Str.toI128, + type: num_type_name, + name, + help, + } ## Add an `I128` parameter that can be provided multiple times ## to your CLI builder. @@ -980,4 +1390,10 @@ maybe_i128 = \{ name, help ? "" } -> maybe { parser: Str.toI128, type: num_type_ ## == SuccessfullyParsed [12, 34, -56] ## ``` i128_list : ParameterConfigBaseParams -> CliBuilder (List I128) {}action StopCollectingAction -i128_list = \{ name, help ? "" } -> list { parser: Str.toI128, type: num_type_name, name, help } +i128_list = \{ name, help ? "" } -> + list { + parser: \a -> Arg.to_str a |> Result.try Str.toI128, + type: num_type_name, + name, + help, + } diff --git a/package/Parser.roc b/package/Parser.roc index 18070fc..8425e63 100644 --- a/package/Parser.roc +++ b/package/Parser.roc @@ -1,15 +1,20 @@ -module [parse_args, Arg, ArgValue] +module [parse_args, ParsedArg, ArgValue] -Arg : [ +import Arg exposing [Arg] + +ArgValue : Result Arg [NoValue] + +ParsedArg : [ Short Str, ShortGroup { names : List Str, complete : [Complete, Partial] }, - Long { name : Str, value : Result Str [NoValue] }, - Parameter Str, + Long { name : Str, value : ArgValue }, + Parameter Arg, ] -ArgValue : Result Str [NoValue] +single_dash_arg = Arg.from_str "-" +double_dash_arg = Arg.from_str "--" -parse_args : List Str -> List Arg +parse_args : List Arg -> List ParsedArg parse_args = \args -> starting_state = { parsed_args: [], pass_through: KeepParsing } @@ -21,7 +26,7 @@ parse_args = \args -> KeepParsing -> parsed_arg = parse_arg arg when parsed_arg is - Parameter "--" -> + Parameter a if a == double_dash_arg -> { pass_through: PassThrough, parsed_args } _other -> @@ -35,12 +40,18 @@ parse_args = \args -> state_after.parsed_args -parse_arg : Str -> Arg +parse_arg : Arg -> ParsedArg parse_arg = \arg -> - when Str.splitFirst arg "-" is + str_arg = + when Arg.to_str arg is + Ok str -> str + Err InvalidUnicode -> + return Parameter arg + + when Str.splitFirst str_arg "-" is Ok { before: "", after } -> if after == "" then - Parameter "-" + Parameter single_dash_arg else when Str.splitFirst after "-" is Ok { before: "", after: rest } -> @@ -54,16 +65,16 @@ parse_arg = \arg -> _other -> Parameter arg -parse_long_arg : Str -> Arg +parse_long_arg : Str -> ParsedArg parse_long_arg = \arg -> when Str.splitFirst arg "=" is Ok { before: option, after: value } -> - Long { name: option, value: Ok value } + Long { name: option, value: Ok (Arg.from_str value) } _other -> Long { name: arg, value: Err NoValue } -construct_set_of_options : Str -> Arg +construct_set_of_options : Str -> ParsedArg construct_set_of_options = \combined -> options = combined @@ -75,44 +86,47 @@ construct_set_of_options = \combined -> other -> ShortGroup { names: other, complete: Complete } expect - parsed = parse_arg "-" + parsed = parse_arg (Arg.from_str "-") - parsed == Parameter "-" + parsed == Parameter (Arg.from_str "-") expect - parsed = parse_arg "-a" + parsed = parse_arg (Arg.from_str "-a") parsed == Short "a" expect - parsed = parse_arg "-abc" + parsed = parse_arg (Arg.from_str "-abc") parsed == ShortGroup { names: ["a", "b", "c"], complete: Complete } expect - parsed = parse_arg "--abc" + parsed = parse_arg (Arg.from_str "--abc") parsed == Long { name: "abc", value: Err NoValue } expect - parsed = parse_arg "--abc=xyz" + parsed = parse_arg (Arg.from_str "--abc=xyz") - parsed == Long { name: "abc", value: Ok "xyz" } + parsed == Long { name: "abc", value: Ok (Arg.from_str "xyz") } expect - parsed = parse_arg "123" + parsed = parse_arg (Arg.from_str "123") - parsed == Parameter "123" + parsed == Parameter (Arg.from_str "123") expect - parsed = parse_args ["this-wont-show", "-a", "123", "--passed", "-bcd", "xyz", "--", "--subject=world"] + parsed = + ["this-wont-show", "-a", "123", "--passed", "-bcd", "xyz", "--", "--subject=world"] + |> List.map Arg.from_str + |> parse_args parsed == [ Short "a", - Parameter "123", + Parameter (Arg.from_str "123"), Long { name: "passed", value: Err NoValue }, ShortGroup { names: ["b", "c", "d"], complete: Complete }, - Parameter "xyz", - Parameter "--subject=world", + Parameter (Arg.from_str "xyz"), + Parameter (Arg.from_str "--subject=world"), ] diff --git a/package/SubCmd.roc b/package/SubCmd.roc index 95109b1..6e67ee8 100644 --- a/package/SubCmd.roc +++ b/package/SubCmd.roc @@ -1,5 +1,6 @@ module [finish, optional, required, SubcommandParserConfig] +import Arg import Base exposing [ ArgParser, ArgParserState, @@ -65,7 +66,7 @@ get_first_arg_to_check_for_subcommand_call : get_first_arg_to_check_for_subcommand_call = \{ remaining_args, subcommand_path }, subcommand_parsers, callback -> find_subcommand = \param -> subcommand_parsers - |> List.findFirst \sc -> Ok sc.name == param + |> List.findFirst \sc -> Ok sc.name == (param |> Result.try Arg.to_str) when List.first remaining_args is Err ListWasEmpty -> callback (find_subcommand (Err NoValue)) From 49e0c18cb27de85ce7761881db41e548e7b362d9 Mon Sep 17 00:00:00 2001 From: Sam Mohr Date: Sat, 21 Dec 2024 15:34:58 -0800 Subject: [PATCH 2/2] Rename InvalidUnicode tag to InvalidUtf8 --- package/Arg.roc | 6 +++--- package/Base.roc | 2 +- package/ErrorFormatter.roc | 4 ++-- package/Opt.roc | 6 +++--- package/Param.roc | 6 +++--- package/Parser.roc | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package/Arg.roc b/package/Arg.roc index d229822..76b272c 100644 --- a/package/Arg.roc +++ b/package/Arg.roc @@ -38,16 +38,16 @@ from_str = \str -> @Arg (Unix (Str.toUtf8 str)) ## Attempt to decode an [Arg] to a UTF-8 [Str]. -to_str : Arg -> Result Str [InvalidUnicode] +to_str : Arg -> Result Str [InvalidUtf8] to_str = \@Arg arg -> # TODO: update when Unicode -> Str conversion is ready: # https://github.com/roc-lang/roc/issues/7390 when arg is Unix unix -> Str.fromUtf8 unix - |> Result.mapErr \_err -> InvalidUnicode + |> Result.mapErr \_err -> InvalidUtf8 - Windows _windows -> Err InvalidUnicode + Windows _windows -> Err InvalidUtf8 ## Convert an [Arg] to a list of bytes. to_bytes : Arg -> List U8 diff --git a/package/Base.roc b/package/Base.roc index 8303d67..b451e1d 100644 --- a/package/Base.roc +++ b/package/Base.roc @@ -114,7 +114,7 @@ Plurality : [Optional, One, Many] ## The two built-in flags that we parse automatically. SpecialFlags : { help : Bool, version : Bool } -InvalidValue : [InvalidNumStr, InvalidValue Str, InvalidUnicode] +InvalidValue : [InvalidNumStr, InvalidValue Str, InvalidUtf8] DefaultValue a : [NoDefault, Value a, Generate ({} -> a)] diff --git a/package/ErrorFormatter.roc b/package/ErrorFormatter.roc index b85d4c4..4978429 100644 --- a/package/ErrorFormatter.roc +++ b/package/ErrorFormatter.roc @@ -68,7 +68,7 @@ format_arg_extract_err = \err -> InvalidValue reason -> "The value provided to $(option_display_name option) was not a valid $(option_type_name option): $(reason)" - InvalidUnicode -> + InvalidUtf8 -> "The value provided to $(option_display_name option) was not valid UTF-8." InvalidParamValue value_err param -> @@ -79,7 +79,7 @@ format_arg_extract_err = \err -> InvalidValue reason -> "The value provided to the '$(param |> .name)' parameter was not a valid $(param |> .type |> full_type_name): $(reason)." - InvalidUnicode -> + InvalidUtf8 -> "The value provided to the '$(param |> .name)' parameter was not valid UTF-8." MissingParam parameter -> diff --git a/package/Opt.roc b/package/Opt.roc index 4de5cfc..c2a5ebd 100644 --- a/package/Opt.roc +++ b/package/Opt.roc @@ -102,7 +102,7 @@ get_maybe_value = \values, option -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUtf8] ## parse_color = \color -> ## when Arg.to_str color is ## Ok "green" -> Ok Green @@ -155,7 +155,7 @@ single = \{ parser, type, short ? "", long ? "", help ? "", default ? NoDefault ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUtf8] ## parse_color = \color -> ## when Arg.to_str color is ## Ok "green" -> Ok Green @@ -203,7 +203,7 @@ maybe = \{ parser, type, short ? "", long ? "", help ? "" } -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUtf8] ## parse_color = \color -> ## when Arg.to_str color is ## Ok "green" -> Ok Green diff --git a/package/Param.roc b/package/Param.roc index 15639dc..4195da4 100644 --- a/package/Param.roc +++ b/package/Param.roc @@ -103,7 +103,7 @@ builder_with_parameter_parser = \param, value_parser -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUtf8] ## parse_color = \color -> ## when Arg.to_str color is ## Ok "green" -> Ok Green @@ -158,7 +158,7 @@ single = \{ parser, type, name, help ? "", default ? NoDefault } -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUtf8] ## parse_color = \color -> ## when Arg.to_str color is ## Ok "green" -> Ok Green @@ -209,7 +209,7 @@ maybe = \{ parser, type, name, help ? "" } -> ## expect ## Color : [Green, Red, Blue] ## -## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUnicode] +## parse_color : Arg -> Result Color [InvalidValue Str, InvalidUtf8] ## parse_color = \color -> ## when Arg.to_str color is ## Ok "green" -> Ok Green diff --git a/package/Parser.roc b/package/Parser.roc index 8425e63..afb1c76 100644 --- a/package/Parser.roc +++ b/package/Parser.roc @@ -45,7 +45,7 @@ parse_arg = \arg -> str_arg = when Arg.to_str arg is Ok str -> str - Err InvalidUnicode -> + Err InvalidUtf8 -> return Parameter arg when Str.splitFirst str_arg "-" is