elm-pages-v3-beta/plugins/MarkdownCodec.elm

223 lines
8.7 KiB
Elm
Raw Normal View History

2021-08-11 23:03:52 +03:00
module MarkdownCodec exposing (isPlaceholder, noteTitle, titleAndDescription, withFrontmatter, withoutFrontmatter)
2021-06-18 19:01:03 +03:00
import DataSource exposing (DataSource)
import DataSource.File as StaticFile
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Extra
import List.Extra
2021-06-18 19:01:03 +03:00
import Markdown.Block as Block exposing (Block)
import Markdown.Parser
import Markdown.Renderer
import MarkdownExtra
2021-06-18 19:01:03 +03:00
2021-08-11 23:03:52 +03:00
isPlaceholder : String -> DataSource (Maybe ())
isPlaceholder filePath =
filePath
|> StaticFile.bodyWithoutFrontmatter
|> DataSource.andThen
(\rawContent ->
Markdown.Parser.parse rawContent
|> Result.mapError (\_ -> "Markdown error")
|> Result.map
(\blocks ->
List.any
(\block ->
case block of
Block.Heading _ inlines ->
False
_ ->
True
)
blocks
|> not
)
|> DataSource.fromResult
)
|> DataSource.map
(\bool ->
if bool then
Nothing
else
Just ()
)
noteTitle : String -> DataSource String
noteTitle filePath =
titleFromFrontmatter filePath
|> DataSource.andThen
(\maybeTitle ->
maybeTitle
|> Maybe.map DataSource.succeed
|> Maybe.withDefault
(StaticFile.bodyWithoutFrontmatter filePath
|> DataSource.andThen
(\rawContent ->
Markdown.Parser.parse rawContent
|> Result.mapError (\_ -> "Markdown error")
|> Result.map
(\blocks ->
List.Extra.findMap
(\block ->
case block of
Block.Heading Block.H1 inlines ->
Just (Block.extractInlineText inlines)
_ ->
Nothing
)
blocks
)
|> Result.andThen (Result.fromMaybe <| "Expected to find an H1 heading for page " ++ filePath)
|> DataSource.fromResult
)
)
)
titleAndDescription : String -> DataSource { title : String, description : String }
titleAndDescription filePath =
filePath
|> StaticFile.onlyFrontmatter
(Decode.map2 (\title description -> { title = title, description = description })
(Json.Decode.Extra.optionalField "title" Decode.string)
(Json.Decode.Extra.optionalField "description" Decode.string)
)
|> DataSource.andThen
(\metadata ->
Maybe.map2 (\title description -> { title = title, description = description })
metadata.title
metadata.description
|> Maybe.map DataSource.succeed
|> Maybe.withDefault
(StaticFile.bodyWithoutFrontmatter filePath
|> DataSource.andThen
(\rawContent ->
Markdown.Parser.parse rawContent
|> Result.mapError (\_ -> "Markdown error")
|> Result.map
(\blocks ->
Maybe.map
(\title ->
{ title = title
, description =
case metadata.description of
Just description ->
description
Nothing ->
findDescription blocks
}
)
(case metadata.title of
Just title ->
Just title
Nothing ->
findH1 blocks
)
)
|> Result.andThen (Result.fromMaybe <| "Expected to find an H1 heading for page " ++ filePath)
|> DataSource.fromResult
)
)
)
findH1 : List Block -> Maybe String
findH1 blocks =
List.Extra.findMap
(\block ->
case block of
Block.Heading Block.H1 inlines ->
Just (Block.extractInlineText inlines)
_ ->
Nothing
2021-06-23 08:14:48 +03:00
)
blocks
findDescription : List Block -> String
findDescription blocks =
blocks
|> List.Extra.findMap
(\block ->
case block of
Block.Paragraph inlines ->
Just (MarkdownExtra.extractInlineText inlines)
_ ->
Nothing
)
|> Maybe.withDefault ""
titleFromFrontmatter : String -> DataSource (Maybe String)
titleFromFrontmatter filePath =
StaticFile.onlyFrontmatter
(Json.Decode.Extra.optionalField "title" Decode.string)
filePath
2021-06-23 08:14:48 +03:00
withoutFrontmatter :
Markdown.Renderer.Renderer view
-> String
-> DataSource (List Block)
withoutFrontmatter renderer filePath =
2021-08-11 23:03:52 +03:00
(filePath
|> StaticFile.bodyWithoutFrontmatter
|> DataSource.andThen
(\rawBody ->
rawBody
|> Markdown.Parser.parse
|> Result.mapError (\_ -> "Couldn't parse markdown.")
|> DataSource.fromResult
)
)
|> DataSource.andThen
(\blocks ->
blocks
|> Markdown.Renderer.render renderer
-- we don't want to encode the HTML since it contains functions so it's not serializable
-- but we can at least make sure there are no errors turning it into HTML before encoding it
|> Result.map (\_ -> blocks)
|> DataSource.fromResult
)
withFrontmatter :
(frontmatter -> List Block -> value)
2021-06-23 08:14:48 +03:00
-> Decoder frontmatter
-> Markdown.Renderer.Renderer view
-> String
-> DataSource value
withFrontmatter constructor frontmatterDecoder_ renderer filePath =
DataSource.map2 constructor
(StaticFile.onlyFrontmatter
frontmatterDecoder_
filePath
)
(StaticFile.bodyWithoutFrontmatter
filePath
|> DataSource.andThen
(\rawBody ->
rawBody
|> Markdown.Parser.parse
|> Result.mapError (\_ -> "Couldn't parse markdown.")
|> DataSource.fromResult
)
|> DataSource.andThen
(\blocks ->
blocks
|> Markdown.Renderer.render renderer
-- we don't want to encode the HTML since it contains functions so it's not serializable
-- but we can at least make sure there are no errors turning it into HTML before encoding it
|> Result.map (\_ -> blocks)
|> DataSource.fromResult
)
)