eco-pro / project-metadata-utils / Elm.Docs

When packages are published to package.elm-lang.org, documentation is generated for all of the exposed modules (and all of the exposed values). These docs are formatted as JSON for easy consumption by anyone.

This module helps you decode the JSON docs into nice Elm values! It is currently used by package.elm-lang.org to help turn JSON into nice web pages!

Decode Docs

decoder : Json.Decode.Decoder Module

Decode the JSON documentation produced by elm-make for an individual module. The documentation for a whole package is an array of module docs, so you may need to say (Decode.list Docs.decoder) depending on what you want to do.

Work with Docs


type alias Module =
{ name : String
, comment : String
, unions : List Union
, aliases : List Alias
, values : List Value
, binops : List Binop 
}

All the documentation for a particular module.

The actual exposed stuff is broken into categories.


type alias Alias =
{ name : String
, comment : String
, args : List String
, tipe : Elm.Type.Type 
}

Documentation for a type alias. For example, if you had the source code:

{-| pair of values -}
type alias Pair a = ( a, a )

When it became an Alias it would be like this:

{ name = "Pair"
, comment = " pair of values "
, args = ["a"]
, tipe = Tuple [ Var "a", Var "a" ]
}


type alias Union =
{ name : String
, comment : String
, args : List String
, tags : List ( String
, List Elm.Type.Type ) 
}

Documentation for a union type. For example, if you had the source code:

{-| maybe -}
type Maybe a = Nothing | Just a

When it became a Union it would be like this:

{ name = "Maybe"
, comment = " maybe "
, args = ["a"]
, tipe =
    [ ("Nothing", [])
    , ("Just", [Var "a"])
    ]
}


type alias Value =
{ name : String
, comment : String
, tipe : Elm.Type.Type 
}

Documentation for values and functions. For example, if you had the source code:

{-| do not do anything -}
identity : a -> a
identity value =
  value

The Value would look like this:

{ name = "identity"
, comment = " do not do anything "
, tipe = Lambda (Var "a") (Var "a")
}


type alias Binop =
{ name : String
, comment : String
, tipe : Elm.Type.Type
, associativity : Associativity
, precedence : Basics.Int 
}

Documentation for binary operators. The content for (+) might look something like this:

{ name = "+"
, comment = "Add numbers"
, tipe = Lambda (Var "number") (Lambda (Var "number") (Var "number"))
, associativity = Left
, precedence = 6
}


type Associativity
    = Left
    | None
    | Right

The associativity of an infix operator. This determines how we add parentheses around everything. Here are some examples:

1 + 2 + 3 + 4

We have to do the operations in some order, so which of these interpretations should we choose?

((1 + 2) + 3) + 4   -- left-associative
1 + (2 + (3 + 4))   -- right-associative

This is really important for operators like (|>)!

Some operators are non-associative though, meaning we do not try to add missing parentheses. (==) is a nice example. 1 == 2 == 3 just is not allowed!

Split Docs into Blocks

toBlocks : Module -> List Block

The module comment describes exactly how the generated docs should look. It is a mix of markdown and @docs declarations that specify when other documentation should appear. Matching all this information up is somewhat tricky though.

So calling toBlocks on a Module gives you a List Block with all the information necessary to visualize the docs as intended.


type Block
    = MarkdownBlock String
    | UnionBlock Union
    | AliasBlock Alias
    | ValueBlock Value
    | BinopBlock Binop
    | UnknownBlock String

This type represents a Block of documentation to show to the user. After getting a List Block from toBlocks, everything is in the right order and you can focus on turning the blocks into HTML exactly how you want.

Note: This should never produce an UnknownBlock but I figured it would be better to let the block visualizer decide what to do in that case.