dillonkearns/elm-cli-options-parser/1.0.0

NOTE: this package is not compatible with Elm 0.19.1

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 { version = "1.2.3" }
        |> Program.add
            (OptionsParser.build GreetOptions
                |> with (Option.requiredKeywordArg "name")
                |> with (Option.optionalKeywordArg "greeting")
            )
build : cliOptions -> OptionsParser cliOptions AnyOptions

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

buildSubCommand : String -> cliOptions -> OptionsParser cliOptions 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:

  • At least the number of required arguments
  • Can be any number greater than that if there are restArgs
  • Could be up to as many as (the number of required arguments) + (the number of optional arguments) if there are no rest args
Option from to BeginningOption
-> OptionsParser (to -> cliOptions) AnyOptions
-> OptionsParser cliOptions AnyOptions

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

Option from to OptionalPositionalArgOption
-> OptionsParser (to -> cliOptions) AnyOptions
-> OptionsParser cliOptions NoBeginningOptions

For chaining on Cli.Option.optionalPositionalArgs.

Option from to RestArgsOption
-> OptionsParser (to -> cliOptions) startingBuilderState
-> OptionsParser cliOptions NoMoreOptions

For chaining on Cli.Option.restArgs.

String
-> OptionsParser cliOptions AnyOptions
-> OptionsParser cliOptions 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 { version = "1.2.3" }
        |> 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
            )
value
-> OptionsParser (value -> cliOptions) AnyOptions
-> OptionsParser cliOptions 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 { version = "1.2.3" }
        |> Program.add
            (OptionsParser.build GreetOptions
                |> OptionsParser.with (Option.requiredKeywordArg "name")
                |> OptionsParser.with (Option.optionalKeywordArg "greeting")
                |> OptionsParser.hardcoded "any hardcoded value"
            )

Meta-Data

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 UsageSpec

Low-level function, for internal use.

synopsis : String -> OptionsParser decodesTo builderState -> String

Low-level function, for internal use.

List String
-> OptionsParser cliOptions builderState
-> MatchResult cliOptions

Low-level function, for internal use.

end :
OptionsParser cliOptions builderState
-> OptionsParser cliOptions NoMoreOptions

Low-level function, for internal use.