Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to new record builder syntax #2

Merged
merged 2 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ main =
Task.err (Exit 1 "")

cliParser =
Cli.weave {
alpha: <- Opt.u64 { short: "a", help: "Set the alpha level." },
force: <- Opt.flag { short: "f", help: "Force the task to complete." },
file: <- Param.maybeStr { name: "file", help: "The file to process." },
files: <- Param.strList { name: "files", help: "The rest of the files." },
{ Cli.weave <-
alpha: Opt.u64 { short: "a", help: "Set the alpha level." },
force: Opt.flag { short: "f", help: "Force the task to complete." },
file: Param.maybeStr { name: "file", help: "The file to process." },
files: Param.strList { name: "files", help: "The rest of the files." },
}
|> Cli.finish {
name: "basic",
Expand Down
10 changes: 5 additions & 5 deletions examples/basic.roc
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ main =
Task.err (Exit 1 "")

cliParser =
Cli.weave {
alpha: <- Opt.u64 { short: "a", help: "Set the alpha level." },
force: <- Opt.flag { short: "f", help: "Force the task to complete." },
file: <- Param.maybeStr { name: "file", help: "The file to process." },
files: <- Param.strList { name: "files", help: "The rest of the files." },
{ Cli.weave <-
alpha: Opt.u64 { short: "a", help: "Set the alpha level." },
force: Opt.flag { short: "f", help: "Force the task to complete." },
file: Param.maybeStr { name: "file", help: "The file to process." },
files: Param.strList { name: "files", help: "The rest of the files." },
}
|> Cli.finish {
name: "basic",
Expand Down
38 changes: 38 additions & 0 deletions examples/default-values.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
weaver: "../package/main.roc",
}

import pf.Stdout
import pf.Arg
import pf.Task exposing [Task]
import weaver.Opt
import weaver.Cli
import weaver.Param

main =
args = Arg.list!

when Cli.parseOrDisplayMessage cliParser args is
Ok data ->
Stdout.line! "Successfully parsed! Here's what I got:"
Stdout.line! ""
Stdout.line! (Inspect.toStr data)

Err message ->
Stdout.line! message

Task.err (Exit 1 "")

cliParser =
{ Cli.weave <-
alpha: Opt.maybeU64 { short: "a", long: "alpha", help: "Set the alpha level. [default: 123]" }
|> Cli.map \a -> Result.withDefault a 123,,
file: Param.maybeStr { name: "file", help: "The file to process. [default: NONE]" }
|> Cli.map \f -> Result.withDefault f "NONE",
}
|> Cli.finish {
name: "default-values",
version: "v0.0.1",
}
|> Cli.assertValid
33 changes: 33 additions & 0 deletions examples/single-arg.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
weaver: "../package/main.roc",
}

import pf.Stdout
import pf.Arg
import pf.Task exposing [Task]
import weaver.Opt
import weaver.Cli

main =
args = Arg.list!

when Cli.parseOrDisplayMessage cliParser args is
Ok data ->
Stdout.line! "Successfully parsed! Here's what I got:"
Stdout.line! ""
Stdout.line! (Inspect.toStr data)

Err message ->
Stdout.line! message

Task.err (Exit 1 "")

cliParser =
Opt.u64 { short: "a", long: "alpha", help: "Set the alpha level." }
|> Cli.map Alpha
|> Cli.finish {
name: "single-arg",
version: "v0.0.1",
}
|> Cli.assertValid
37 changes: 18 additions & 19 deletions examples/subcommands.roc
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ main =
Task.err (Exit 1 "")

cliParser =
Cli.weave {
force: <- Opt.flag { short: "f", help: "Force the task to complete." },
sc: <- Subcommand.optional [subcommandParser1, subcommandParser2],
file: <- Param.maybeStr { name: "file", help: "The file to process." },
files: <- Param.strList { name: "files", help: "The rest of the files." },
{ Cli.weave <-
force: Opt.flag { short: "f", help: "Force the task to complete." },
sc: Subcommand.optional [subcommandParser1, subcommandParser2],
file: Param.maybeStr { name: "file", help: "The file to process." },
files: Param.strList { name: "files", help: "The rest of the files." },
}
|> Cli.finish {
name: "subcommands",
Expand All @@ -41,34 +41,33 @@ cliParser =
|> Cli.assertValid

subcommandParser1 =
Cli.weave {
d: <- Opt.maybeU64 { short: "d", help: "A non-overlapping subcommand flag with s2." },
volume: <- Opt.maybeU64 { short: "v", long: "volume", help: "How loud to grind the gears." },
sc: <- Subcommand.optional [subSubcommandParser1, subSubcommandParser2],
{ Cli.weave <-
d: Opt.maybeU64 { short: "d", help: "A non-overlapping subcommand flag with s2." },
volume: Opt.maybeU64 { short: "v", long: "volume", help: "How loud to grind the gears." },
sc: Subcommand.optional [subSubcommandParser1, subSubcommandParser2],
}
|> Subcommand.finish { name: "s1", description: "A first subcommand.", mapper: S1 }

subcommandParser2 =
Cli.weave {
d: <- Opt.maybeU64 { short: "d", help: "This doesn't overlap with s1's -d flag." },
}
Opt.maybeU64 { short: "d", help: "This doesn't overlap with s1's -d flag." }
|> Cli.map DFlag
|> Subcommand.finish {
name: "s2",
description: "Another subcommand.",
mapper: S2,
}

subSubcommandParser1 =
Cli.weave {
a: <- Opt.u64 { short: "a", help: "An example short flag for a sub-subcommand." },
b: <- Opt.u64 { short: "b", help: "Another example short flag for a sub-subcommand." },
{ Cli.weave <-
a: Opt.u64 { short: "a", help: "An example short flag for a sub-subcommand." },
b: Opt.u64 { short: "b", help: "Another example short flag for a sub-subcommand." },
}
|> Subcommand.finish { name: "ss1", description: "A sub-subcommand.", mapper: SS1 }

subSubcommandParser2 =
Cli.weave {
a: <- Opt.u64 { short: "a", help: "Set the alpha level." },
c: <- Opt.u64 { short: "c", long: "create", help: "Create a doohickey." },
data: <- Param.str { name: "data", help: "Data to manipulate." },
{ Cli.weave <-
a: Opt.u64 { short: "a", help: "Set the alpha level." },
c: Opt.u64 { short: "c", long: "create", help: "Create a doohickey." },
data: Param.str { name: "data", help: "Data to manipulate." },
}
|> Subcommand.finish { name: "ss2", description: "Another sub-subcommand.", mapper: SS2 }
100 changes: 77 additions & 23 deletions package/Builder.roc
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ module [
GetParamsAction,
StopCollectingAction,
CliBuilder,
fromState,
addOptions,
addParameters,
fromArgParser,
fromFullParser,
addOption,
addParameter,
addSubcommands,
updateParser,
bindParser,
map,
combine,
intoParts,
checkForHelpAndVersion,
]
Expand All @@ -18,6 +21,7 @@ import Base exposing [
ArgParserState,
ArgParserResult,
onSuccessfulArgParse,
mapSuccessfullyParsed,
ArgExtractErr,
OptionConfig,
helpOption,
Expand All @@ -31,35 +35,49 @@ GetOptionsAction : { getOptions : {} }
GetParamsAction : { getParams : {} }
StopCollectingAction : []

CliBuilder state action := {
parser : ArgParser state,
CliBuilder data fromAction toAction := {
parser : ArgParser data,
options : List OptionConfig,
parameters : List ParameterConfig,
subcommands : Dict Str SubcommandConfig,
}

fromState : base -> CliBuilder base GetOptionsAction
fromState = \base ->
fromArgParser : (List Arg -> Result { data : data, remainingArgs : List Arg } ArgExtractErr) -> CliBuilder data fromAction toAction
fromArgParser = \parser ->
newParser = \{ args, subcommandPath } ->
when parser args is
Ok { data, remainingArgs } -> SuccessfullyParsed { data, remainingArgs, subcommandPath }
Err err -> IncorrectUsage err { subcommandPath }

@CliBuilder {
parser: newParser,
options: [],
parameters: [],
subcommands: Dict.empty {},
}

fromFullParser : ArgParser data -> CliBuilder data fromAction toAction
fromFullParser = \parser ->
@CliBuilder {
parser: \{ args, subcommandPath } -> SuccessfullyParsed { data: base, remainingArgs: args, subcommandPath },
parser,
options: [],
parameters: [],
subcommands: Dict.empty {},
}

addOptions : CliBuilder state action, List OptionConfig -> CliBuilder state action
addOptions = \@CliBuilder builder, newOptions ->
@CliBuilder { builder & options: List.concat builder.options newOptions }
addOption : CliBuilder state fromAction toAction, OptionConfig -> CliBuilder state fromAction toAction
addOption = \@CliBuilder builder, newOption ->
@CliBuilder { builder & options: List.append builder.options newOption }

addParameters : CliBuilder state action, List ParameterConfig -> CliBuilder state action
addParameters = \@CliBuilder builder, newParameters ->
@CliBuilder { builder & parameters: List.concat builder.parameters newParameters }
addParameter : CliBuilder state fromAction toAction, ParameterConfig -> CliBuilder state fromAction toAction
addParameter = \@CliBuilder builder, newParameter ->
@CliBuilder { builder & parameters: List.append builder.parameters newParameter }

addSubcommands : CliBuilder state action, Dict Str SubcommandConfig -> CliBuilder state action
addSubcommands : CliBuilder state fromAction toAction, Dict Str SubcommandConfig -> CliBuilder state fromAction toAction
addSubcommands = \@CliBuilder builder, newSubcommands ->
@CliBuilder { builder & subcommands: Dict.insertAll builder.subcommands newSubcommands }

setParser : CliBuilder state action, ArgParser nextState -> CliBuilder nextState nextAction
setParser : CliBuilder state fromAction toAction, ArgParser nextState -> CliBuilder nextState fromAction toAction
setParser = \@CliBuilder builder, parser ->
@CliBuilder {
options: builder.options,
Expand All @@ -68,7 +86,7 @@ setParser = \@CliBuilder builder, parser ->
parser,
}

updateParser : CliBuilder state action, ({ data : state, remainingArgs : List Arg } -> Result { data : nextState, remainingArgs : List Arg } ArgExtractErr) -> CliBuilder nextState nextAction
updateParser : CliBuilder state fromAction toAction, ({ data : state, remainingArgs : List Arg } -> Result { data : nextState, remainingArgs : List Arg } ArgExtractErr) -> CliBuilder nextState fromAction toAction
updateParser = \@CliBuilder builder, updater ->
newParser =
{ data, remainingArgs, subcommandPath } <- onSuccessfulArgParse builder.parser
Expand All @@ -79,7 +97,7 @@ updateParser = \@CliBuilder builder, updater ->

setParser (@CliBuilder builder) newParser

bindParser : CliBuilder state action, (ArgParserState state -> ArgParserResult (ArgParserState nextState)) -> CliBuilder nextState nextAction
bindParser : CliBuilder state fromAction toAction, (ArgParserState state -> ArgParserResult (ArgParserState nextState)) -> CliBuilder nextState fromAction toAction
bindParser = \@CliBuilder builder, updater ->
newParser : ArgParser nextState
newParser =
Expand All @@ -89,7 +107,7 @@ bindParser = \@CliBuilder builder, updater ->
setParser (@CliBuilder builder) newParser

intoParts :
CliBuilder state action
CliBuilder state fromAction toAction
-> {
parser : ArgParser state,
options : List OptionConfig,
Expand All @@ -98,6 +116,42 @@ intoParts :
}
intoParts = \@CliBuilder builder -> builder

map : CliBuilder a fromAction toAction, (a -> b) -> CliBuilder b fromAction toAction
map = \@CliBuilder builder, mapper ->
combinedParser = \input ->
builder.parser input
|> mapSuccessfullyParsed \{ data, remainingArgs, subcommandPath } ->
{ data: mapper data, remainingArgs, subcommandPath }

@CliBuilder {
parser: combinedParser,
options: builder.options,
parameters: builder.parameters,
subcommands: builder.subcommands,
}

combine : CliBuilder a action1 action2, CliBuilder b action2 action3, (a, b -> c) -> CliBuilder c action1 action3
combine = \@CliBuilder left, @CliBuilder right, combiner ->
combinedParser = \input ->
when left.parser input is
ShowVersion -> ShowVersion
ShowHelp sp -> ShowHelp sp
IncorrectUsage argExtractErr sp -> IncorrectUsage argExtractErr sp
SuccessfullyParsed { data, remainingArgs, subcommandPath } ->
when right.parser { args: remainingArgs, subcommandPath } is
ShowVersion -> ShowVersion
ShowHelp sp -> ShowHelp sp
IncorrectUsage argExtractErr sp -> IncorrectUsage argExtractErr sp
SuccessfullyParsed { data: data2, remainingArgs: restOfArgs, subcommandPath: nextSp } ->
SuccessfullyParsed { data: combiner data data2, remainingArgs: restOfArgs, subcommandPath: nextSp }

@CliBuilder {
parser: combinedParser,
options: List.concat left.options right.options,
parameters: List.concat left.parameters right.parameters,
subcommands: Dict.insertAll left.subcommands right.subcommands,
}

flagWasPassed : OptionConfig, List Arg -> Bool
flagWasPassed = \option, args ->
List.any args \arg ->
Expand All @@ -107,7 +161,7 @@ flagWasPassed = \option, args ->
Long long -> long.name == option.long
Parameter _p -> Bool.false

checkForHelpAndVersion : CliBuilder state action -> CliBuilder state action
checkForHelpAndVersion : CliBuilder state fromAction toAction -> CliBuilder state fromAction toAction
checkForHelpAndVersion = \@CliBuilder builder ->
newParser = \{ args, subcommandPath } ->
when builder.parser { args, subcommandPath } is
Expand All @@ -130,15 +184,15 @@ checkForHelpAndVersion = \@CliBuilder builder ->

expect
{ parser } =
fromState (\x -> { x })
|> updateParser \{ data, remainingArgs } -> Ok { data: data (Inspect.toStr remainingArgs), remainingArgs: [] }
fromArgParser \args -> Ok { data: Inspect.toStr args, remainingArgs: [] }
|> map Inspected
|> intoParts

out = parser { args: [Parameter "123"], subcommandPath: [] }

out
== SuccessfullyParsed {
data: { x: "[(Parameter \"123\")]" },
data: Inspected "[(Parameter \"123\")]",
remainingArgs: [],
subcommandPath: [],
}
Expand Down
Loading
Loading