dillonkearns / elm-cli-options-parser / Cli.OptionsParser

Types


type OptionsParser cliOptions builderState

An OptionsParser represents one possible way to interpret command line arguments. A Cli.Program.Config can be built up using one or more OptionsParsers. It will try each parser in order until one succeeds. If none succeed, it will print an error message with information for the user of the Command-Line Interface.

Start the Pipeline

You build up an OptionsParser similarly to the way you build a decoder using the elm-decode-pipeline pattern. That is, you start the pipeline by giving it a constructor function, and then for each argument of your constructor function, you have a corresponding

|> with (Option.someKindOfOption)

in the exact same order.

For example, if we define a type alias for a record with two attributes, Elm generates a 2-argument constructor function for that record type. Here Elm gives us a GreetOptions function of the type String -> Maybe String -> GreetOptions (this is just a core Elm language feature). That is, if we pass in a String and a Maybe String as the 1st and 2nd arguments to the GreetOptions function, it will build up a record of that type.

So in this example, we call OptionsParser.build with our GreetOptions constructor function. Then we chain on with once for each of those two arguments. Note that the first with will give us a String, and the second will give us a Maybe String, so it matches up perfectly with the order of our constructor's arguments.

import Cli.Option as Option
import Cli.OptionsParser as OptionsParser exposing (with)
import Cli.Program as Program

type alias GreetOptions =
    { name : String
    , maybeGreeting : Maybe String
    }

programConfig : Program.Config GreetOptions
programConfig =
    Program.config
        |> Program.add
            (OptionsParser.build GreetOptions
                |> with (Option.requiredKeywordArg "name")
                |> with (Option.optionalKeywordArg "greeting")
            )

build : cliOptions -> OptionsParser cliOptions BuilderState.AnyOptions

Start an OptionsParser pipeline with no sub-command (see the OptionsParser terminilogy legend).

buildSubCommand : String -> cliOptions -> OptionsParser cliOptions BuilderState.AnyOptions

Start an OptionsParser pipeline with a sub-command (see the OptionsParser terminilogy legend).

Adding Cli.Option.Options To The Pipeline

Most options can be chained on using with. There are two exceptions, restArgs and optionalPositionalArgs. elm-cli-options-parser enforces that they are added in an unambiguous order (see the Cli.OptionsParser.BuilderState docs). So instead of using with, you add them with their corresponding with... functions.

import Cli.Option
import Cli.OptionsParser as OptionsParser exposing (with)

type GitOptionsParser
    = Init
    | Log LogOptions -- ...

type alias LogOptions =
    { maybeAuthorPattern : Maybe String
    , maybeNumberToDisplay : Maybe Int
    }

logOptionsParser =
    OptionsParser.buildSubCommand "log" LogOptions
        |> with (Option.optionalKeywordArg "author")
        |> with
            (Option.optionalKeywordArg "max-count"
                |> Option.validateMapIfPresent String.toInt
            )
        |> with (Option.flag "stat")
        |> OptionsParser.withOptionalPositionalArg
            (Option.optionalPositionalArg "revision range")
        |> OptionsParser.withRestArgs
            (Option.restArgs "rest args")

User Error Message on Invalid Number of Positional Args

The User of the Command-Line Interface will get an error message if there is no OptionsParser that succeeds. And an OptionsParser will only succeed if a valid number of positional arguments is passed in, as defined by these rules:

with : Cli.Option.Option from to Cli.Option.BeginningOption -> OptionsParser (to -> cliOptions) BuilderState.AnyOptions -> OptionsParser cliOptions BuilderState.AnyOptions

For chaining on any Cli.Option.Option besides a restArg or an optionalPositionalArg. See the Cli.Option module.

withOptionalPositionalArg : Cli.Option.Option from to Cli.Option.OptionalPositionalArgOption -> OptionsParser (to -> cliOptions) BuilderState.AnyOptions -> OptionsParser cliOptions BuilderState.NoBeginningOptions

For chaining on Cli.Option.optionalPositionalArgs.

withRestArgs : Cli.Option.Option from to Cli.Option.RestArgsOption -> OptionsParser (to -> cliOptions) startingBuilderState -> OptionsParser cliOptions BuilderState.NoMoreOptions

For chaining on Cli.Option.restArgs.

expectFlag : String -> OptionsParser cliOptions BuilderState.AnyOptions -> OptionsParser cliOptions BuilderState.AnyOptions

The OptionsParser will only match if the given flag is present. Often its best to use a subcommand in these cases.

Mapping and Transforming

map : (cliOptions -> mappedCliOptions) -> OptionsParser cliOptions builderState -> OptionsParser mappedCliOptions builderState

Map the CLI options returned in the OptionsParser using the supplied map function.

This is very handy when you want a type alias for a record with options for a a given OptionsParser, but you need all of your OptionsParser to map into a single union type.

import Cli.Option as Option
import Cli.OptionsParser as OptionsParser
import Cli.Program as Program
import Ports

type CliOptions
    = Hello HelloOptions
    | Goodbye GoodbyeOptions

type alias HelloOptions =
    { name : String
    , maybeHello : Maybe String
    }

type alias GoodbyeOptions =
    { name : String
    , maybeGoodbye : Maybe String
    }

programConfig : Program.Config CliOptions
programConfig =
    Program.config
        |> Program.add
            (OptionsParser.buildSubCommand "hello" HelloOptions
                |> OptionsParser.with (Option.requiredKeywordArg "name")
                |> OptionsParser.with (Option.optionalKeywordArg "greeting")
                |> OptionsParser.map Hello
            )
        |> Program.add
            (OptionsParser.buildSubCommand "goodbye" GoodbyeOptions
                |> OptionsParser.with (Option.requiredKeywordArg "name")
                |> OptionsParser.with (Option.optionalKeywordArg "goodbye")
                |> OptionsParser.map Goodbye
            )

hardcoded : value -> OptionsParser (value -> cliOptions) BuilderState.AnyOptions -> OptionsParser cliOptions BuilderState.AnyOptions

Use a fixed value for the next step in the pipeline. This doesn't use any input from the user, it just passes the supplied value through in the chain.

import Cli.Option as Option
import Cli.OptionsParser as OptionsParser
import Cli.Program as Program

type alias GreetOptions =
    { name : String
    , maybeGreeting : Maybe String
    , hardcodedValue : String
    }

programConfig : Program.Config GreetOptions
programConfig =
    Program.config
        |> Program.add
            (OptionsParser.build GreetOptions
                |> OptionsParser.with (Option.requiredKeywordArg "name")
                |> OptionsParser.with (Option.optionalKeywordArg "greeting")
                |> OptionsParser.hardcoded "any hardcoded value"
            )

Meta-Data

withDoc : String -> OptionsParser cliOptions anything -> OptionsParser cliOptions anything

Add documentation for the optionsParser. The output shows up after a # in the help output:

$ git --help
git init # initialize a git repository
...
  import Cli.OptionsParser as OptionsParser exposing (OptionsParser, with)

  type GitOptionsParser =
    Init
    | Clone String

  gitInitOptionsParser : OptionsParser GitOptionsParser
  gitInitOptionsParser =
    OptionsParser.build Init
     |> OptionsParser.end
     |> OptionsParser.withDoc "initialize a git repository"

Low-Level Functions

You shouldn't need to use these functions to build a command line utility.

getSubCommand : OptionsParser cliOptions builderState -> Maybe String

Low-level function, for internal use.

getUsageSpecs : OptionsParser decodesTo builderState -> List Cli.UsageSpec.UsageSpec

Low-level function, for internal use.

synopsis : String -> OptionsParser decodesTo builderState -> String

Low-level function, for internal use.

tryMatch : List String -> OptionsParser cliOptions builderState -> MatchResult cliOptions

Low-level function, for internal use.

end : OptionsParser cliOptions builderState -> OptionsParser cliOptions BuilderState.NoMoreOptions

Low-level function, for internal use.