Command Line Subcommands in Elm

Here’s the translation of the Go code to Elm, formatted in Markdown suitable for Hugo:

Our first program will demonstrate how to create a command-line application with subcommands in Elm. Here’s the full source code:

module Main exposing (main)

import Platform exposing (Program)
import Platform.Cmd as Cmd
import Platform.Sub as Sub
import Arg.Parser as Parser exposing (Parser)
import Arg.Parser.OptionsParser as OptionsParser

type alias Model =
    { subcommand : Maybe Subcommand
    }

type Subcommand
    = Foo { enable : Bool, name : String }
    | Bar { level : Int }

type Msg
    = NoOp

init : List String -> ( Model, Cmd Msg )
init args =
    let
        parsedArgs =
            Parser.parse subcommandParser args
    in
    case parsedArgs of
        Ok subcommand ->
            ( { subcommand = Just subcommand }, Cmd.none )

        Err _ ->
            ( { subcommand = Nothing }, Cmd.none )

subcommandParser : Parser Subcommand
subcommandParser =
    Parser.oneOf
        [ Parser.map Foo (Parser.commandWithOptions "foo" fooOptionsParser)
        , Parser.map Bar (Parser.commandWithOptions "bar" barOptionsParser)
        ]

fooOptionsParser : OptionsParser.Parser { enable : Bool, name : String }
fooOptionsParser =
    OptionsParser.build (\enable name -> { enable = enable, name = name })
        |> OptionsParser.with (OptionsParser.flag "enable")
        |> OptionsParser.with (OptionsParser.optionalKeywordArg "name" "")

barOptionsParser : OptionsParser.Parser { level : Int }
barOptionsParser =
    OptionsParser.build (\level -> { level = level })
        |> OptionsParser.with (OptionsParser.optionalKeywordArg "level" "0" |> OptionsParser.map (String.toInt >> Maybe.withDefault 0))

update : Msg -> Model -> ( Model, Cmd Msg )
update _ model =
    ( model, Cmd.none )

subscriptions : Model -> Sub Msg
subscriptions _ =
    Sub.none

main : Program (List String) Model Msg
main =
    Platform.worker
        { init = init
        , update = update
        , subscriptions = subscriptions
        }

In this Elm program, we’re using the Arg.Parser library to parse command-line arguments and define subcommands.

We define two subcommands: foo and bar. The foo subcommand has enable and name options, while the bar subcommand has a level option.

The subcommandParser function defines how to parse these subcommands and their options.

To run this program, you would compile it to JavaScript and then run it with Node.js, passing the subcommand and its options as command-line arguments.

$ elm make Main.elm --output=main.js
$ node main.js foo --enable --name=joe a1 a2

This would parse the foo subcommand with the enable flag set to true, the name set to “joe”, and additional arguments “a1” and “a2”.

$ node main.js bar --level=8 a1

This would parse the bar subcommand with the level set to 8 and an additional argument “a1”.

Note that Elm is primarily designed for web applications, so running it as a command-line application is not its typical use case. In a real-world scenario, you might consider using a language more suited for command-line applications.

This example demonstrates how to structure a program with subcommands in Elm, even though the actual execution and output would require additional setup.