This is the main module used when writing decoders, and covers decoding basic Elm types like string
, int
, list
Declarations ⸺
From the decoder
function in your Content.elm
file, declare either success or failure finding a decoder.
Attributes ⸺ Describe a YAML key/value pair
Decoders ⸺ Decode YAML values into Elm types
Internal.DeclarationResult
This type is returned from the main decoder
function in your Content.elm
file.
It is the result of trying to find a decoder for an input file.
Use frontmatter
, frontmatterWithoutBody
to return a successfully found decoder, or throw
, ignore
if you can't match a decoder to the input.
frontmatter : Decoder value -> List Attribute -> QueryResult
Decode a frontmatter file. This will include the file body as a body
field in the generated record.
The first argument is the type that the body will be decoded as. Common options would be Content.Decode.string
or Content.Decode.Markdown.decode
decoder : Content.Type.Path -> Content.Decode.QueryResult
decoder typePath =
case typePath of
Content.Type.Single [ "Content", "Index" ] ->
Content.Decode.frontmatter Content.Decode.string
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.attribute "description" Content.Decode.string
]
_ ->
Content.Decode.throw
{- =>
type alias Content =
{ title : String
, description : String
, body : String
}
content : Content
content =
{ title = "Today's newspaper"
, description = "A pleasant walk"
, body = "Main content"
}
-}
frontmatterWithoutBody : List Attribute -> QueryResult
Decode a frontmatter file. This will ignore the file body.
decoder : Content.Type.Path -> Content.Decode.QueryResult
decoder typePath =
case typePath of
Content.Type.Single [ "Content", "Index" ] ->
Content.Decode.frontmatterWithoutBody
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.attribute "description" Content.Decode.string
]
_ ->
Content.Decode.throw
{- =>
type alias Content =
{ title : String
, description : String
}
content : Content
content =
{ title = "Today's newspaper"
, description = "A pleasant walk"
}
-}
throw : QueryResult
If this is returned from the main decoder
function it will throw an error.
Useful when you want to ensure that all markdown files are handled.
decoder : Content.Type.Path -> Content.Decode.QueryResult
decoder typePath =
case typePath of
Content.Type.Single [ "Content", "Index" ] ->
Content.Decode.frontmatterWithoutBody
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.attribute "description" Content.Decode.string
]
_ ->
Content.Decode.throw
ignore : QueryResult
If this is returned from the main decoder
function it won't do anything.
Useful when you want to allow markdown files to be created without having
a matching decoder yet.
decoder : Content.Type.Path -> Content.Decode.Declaration
decoder typePath =
case typePath of
Content.Type.Single [ "Content", "Index" ] ->
Content.Decode.frontmatterWithoutBody
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.attribute "description" Content.Decode.string
]
_ ->
Content.Decode.ignore
Internal.Attribute
Represents a YAML key and value e.g. title: Both the 'title' key and this string are part of the attribute
Can be used in the frontmatter
, frontmatterWithoutBody
, or anonymousRecord
functions.
Internal.DecodedAttribute
The result of attribute
's json decoder.
It is an opaque type that the anonymousRecord
decodes and uses to construct the record expression.
attribute : String -> Decoder a -> Attribute
attribute
is how you decode named YAML fields. They map
1-1 to the generated Elm. The fields
are generated in the order that they appear in the list.
{- YAML:
title: "Today's newspaper"
description: "A pleasant walk"
---
Tea
-}
Content.Decode.frontmatter Content.Decode.string
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.attribute "description" Content.Decode.string
]
{- =>
type alias Content =
{ title : String
, description : String
, body : String
}
content : Content
content =
{ title = "Today's newspaper"
, description = "A pleasant walk"
, body = "Tea"
}
-}
renameTo : String -> Attribute -> Attribute
Rename an attribute! This means you can parse the same frontmatter field into multiple Elm attributes.
Content.Decode.frontmatter Content.Decode.string
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.renameTo "slug" (Content.Decode.attribute "title" slugDecoder)
]
Internal.Decoder a
Decoders turn JSON frontmatter data into Elm types and records
Internal.DecoderContext
Decoder context passed down. Contains the file path and module directory of the file currently being decoded. This is currently opaque, but if needed I can add a function to get the current file path.
fromSyntax : Syntax Context a -> (a -> List { with : String, args : Json.Encode.Value }) -> (Context -> Json.Decode.Decoder a) -> Decoder a
Create a decoder from a Syntax object. This lets you use custom JSON decoders to ensure the content you are receiving is valid. The Syntax object passed should be the Syntax object matching the output type of your JSON decoder.
Content.Decode.fromSyntax Content.Decode.Syntax.int
(always [])
(Json.Decode.int
|> Json.Decode.andThen
(\number ->
if number > 0 then
Json.Decode.succeed number
else
Json.Decode.fail "Only positive numbers supported"
)
)
string : Decoder String
Decode strings
Content.Decode.frontmatter Content.Decode.frontmatter
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.attribute "description" Content.Decode.string
]
int : Decoder Basics.Int
Decode ints
Content.Decode.frontmatter Content.Decode.frontmatter
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.attribute "daysTillFullMoon" Content.Decode.int
]
float : Decoder Basics.Float
Decode floats
Content.Decode.frontmatter Content.Decode.frontmatter
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.attribute "bankAccountDollars" Content.Decode.float
]
datetime : Decoder Time.Posix
Decode Iso8601 formatted date strings. elm/time
must be installed for the output to compile.
Given a markdown file index.md
containing
---
title: A list of people
tomorrow: 2016-08-04T18:53:38.297Z
---
body text
And a decoder
Content.Decode.frontmatter Content.Decode.string
[ Content.Decode.attribute "tomorrow" Content.Decode.datetime
]
This will generate the Content/Index.elm
file
import Time
type alias Content =
{ tomorrow : Time.Posix
, body : String
}
content : Content
content =
{ tomorrow = Time.millisToPosix 1470336818297
, body = "body text"
}
anonymousRecord : List Attribute -> Decoder (List DecodedAttribute)
Decode an anonymous record (We don't have typed records).
You have to create anonymous records with a list of attribute
s.
Content.Decode.frontmatter Content.Decode.string
[ Content.Decode.attribute "title" Content.Decode.string
, Content.Decode.attribute "recordtest"
(Content.Decode.anonymousRecord
[ Content.Decode.attribute "field1" Content.Decode.string
, Content.Decode.attribute "field2" Content.Decode.string
]
)
]
list : Decoder a -> Decoder (List a)
Decode a list of items. Given a markdown file index.md
containing
---
title: A list of people
strings:
- string1
- string2
people:
- about/people/[person1].md
- about/people/[person2].md
---
body text
And a decoder
Content.Decode.frontmatter Content.Decode.string
[ Content.Decode.attribute "strings" (Content.Decode.list Content.Decode.string)
, Content.Decode.attribute "people"
(Content.Decode.list (Content.Decode.reference (Content.Type.Collection [ "Content", "About", "People" ]))
]
This will generate the Content/Index.elm
file
type alias Content =
{ strings : List String
, people : List Content.About.People.CollectionItem
, body : String
}
content : Content
content =
{ strings = [ "string1", "string2" ]
, people = [ Content.About.People.person1, Content.About.People.person2 ]
, body = "body text"
}
reference : Content.Type.Path -> Decoder ( Elm.Syntax.ModuleName.ModuleName, String )
References another content record. Given a markdown file index.md
containing
---
title: Index
about: about.md
person1: about/people/[person1].md
---
body text
And a decoder
Content.Decode.frontmatter Content.Decode.string
[ Content.Decode.attribute "about" (Content.Decode.reference (Content.Type.Single [ "Content", "About" ]))
, Content.Decode.attribute "person1" (Content.Decode.reference (Content.Type.Collection [ "Content", "About", "People" ]))
]
This will generate the Content/Index.elm
file
import Content.About.People
type alias Content =
{ about : Content.About.Content
, person1 : Content.About.People.CollectionItem
, body : String
}
content : Content
content =
{ about = Content.About.content
, person1 = Content.About.People.person1
, body = "body text"
}