Update docs app to use vanilla decoders.

This commit is contained in:
Dillon Kearns 2022-01-26 09:47:18 -08:00
parent 4d2a96ad99
commit 2dd7394f07
14 changed files with 78 additions and 358 deletions

View File

@ -11,6 +11,7 @@
"direct": {
"MartinSStewart/elm-serialize": "1.2.5",
"avh4/elm-color": "1.0.0",
"danfishgold/base64-bytes": "1.1.0",
"danyx23/elm-mimetype": "4.0.1",
"dillonkearns/elm-bcp47-language-tag": "1.0.1",
"dillonkearns/elm-markdown": "7.0.0",
@ -18,6 +19,7 @@
"dillonkearns/elm-rss": "2.0.2",
"dillonkearns/elm-sitemap": "1.0.2",
"elm/browser": "1.0.2",
"elm/bytes": "1.0.8",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/http": "2.0.0",
@ -28,9 +30,12 @@
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2",
"elm-community/dict-extra": "2.4.0",
"elm-community/json-extra": "4.3.0",
"elm-community/list-extra": "8.3.0",
"jluckyiv/elm-utc-date-strings": "1.0.0",
"justinmimbs/date": "3.2.1",
"lamdera/codecs": "1.0.0",
"lamdera/core": "1.0.0",
"matheus23/elm-default-tailwind-modules": "2.0.1",
"miniBill/elm-codec": "2.0.0",
"noahzgordon/elm-color-extra": "1.0.2",
@ -38,15 +43,14 @@
"robinheghan/murmur3": "1.0.0",
"rtfeldman/elm-css": "16.1.1",
"tripokey/elm-fuzzy": "5.2.1",
"turboMaCk/non-empty-list-alias": "1.2.0",
"vito/elm-ansi": "10.0.1",
"zwilias/json-decode-exploration": "6.0.0"
},
"indirect": {
"bburdette/toop": "1.0.1",
"billstclair/elm-xml-eeue56": "2.0.0",
"danfishgold/base64-bytes": "1.1.0",
"dmy/elm-imf-date-time": "1.0.1",
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/random": "1.0.0",
"fredcy/elm-parseint": "2.0.1",
@ -54,6 +58,7 @@
"lazamar/dict-parser": "1.0.2",
"mgold/elm-nonempty-list": "4.2.0",
"rtfeldman/elm-hex": "1.0.0",
"rtfeldman/elm-iso8601-date-strings": "1.1.4",
"ryannhg/date-format": "2.3.0"
}
},

View File

@ -5,8 +5,8 @@ import Article
import DataSource exposing (DataSource)
import DataSource.Http
import Html exposing (Html)
import Json.Decode as Decode
import Json.Encode
import OptimizedDecoder as Decode
import Pages
import Route exposing (Route)
import Rss
@ -25,9 +25,9 @@ routes getStaticRoutes htmlToString =
(\userId ->
DataSource.succeed
(Json.Encode.object
[ ( "id", Json.Encode.int userId )
[ ( "id", Json.Encode.string userId )
, ( "name"
, Html.p [] [ Html.text <| "Data for user " ++ String.fromInt userId ]
, Html.p [] [ Html.text <| "Data for user " ++ userId ]
|> htmlToString
|> Json.Encode.string
)
@ -37,14 +37,14 @@ routes getStaticRoutes htmlToString =
)
|> ApiRoute.literal "users"
|> ApiRoute.slash
|> ApiRoute.int
|> ApiRoute.capture
|> ApiRoute.literal ".json"
|> ApiRoute.preRender
(\route ->
DataSource.succeed
[ route 1
, route 2
, route 3
[ route "1"
, route "2"
, route "3"
]
)
, ApiRoute.succeed

View File

@ -5,7 +5,7 @@ import DataSource
import DataSource.File as File
import DataSource.Glob as Glob
import Date exposing (Date)
import OptimizedDecoder
import Json.Decode as Decode exposing (Decoder)
import Pages.Url exposing (Url)
import Route
@ -67,32 +67,32 @@ type alias ArticleMetadata =
}
frontmatterDecoder : OptimizedDecoder.Decoder ArticleMetadata
frontmatterDecoder : Decoder ArticleMetadata
frontmatterDecoder =
OptimizedDecoder.map5 ArticleMetadata
(OptimizedDecoder.field "title" OptimizedDecoder.string)
(OptimizedDecoder.field "description" OptimizedDecoder.string)
(OptimizedDecoder.field "published"
(OptimizedDecoder.string
|> OptimizedDecoder.andThen
Decode.map5 ArticleMetadata
(Decode.field "title" Decode.string)
(Decode.field "description" Decode.string)
(Decode.field "published"
(Decode.string
|> Decode.andThen
(\isoString ->
case Date.fromIsoString isoString of
Ok date ->
OptimizedDecoder.succeed date
Decode.succeed date
Err error ->
OptimizedDecoder.fail error
Decode.fail error
)
)
)
(OptimizedDecoder.field "image" imageDecoder)
(OptimizedDecoder.field "draft" OptimizedDecoder.bool
|> OptimizedDecoder.maybe
|> OptimizedDecoder.map (Maybe.withDefault False)
(Decode.field "image" imageDecoder)
(Decode.field "draft" Decode.bool
|> Decode.maybe
|> Decode.map (Maybe.withDefault False)
)
imageDecoder : OptimizedDecoder.Decoder Url
imageDecoder : Decoder Url
imageDecoder =
OptimizedDecoder.string
|> OptimizedDecoder.map (\cloudinaryAsset -> Cloudinary.url cloudinaryAsset Nothing 800)
Decode.string
|> Decode.map (\cloudinaryAsset -> Cloudinary.url cloudinaryAsset Nothing 800)

View File

@ -4,7 +4,6 @@ import Css
import Html.Styled exposing (..)
import Html.Styled.Attributes as Attr exposing (css)
import Route
import Serialize as S
import Svg.Styled exposing (path, svg)
import Svg.Styled.Attributes as SvgAttr
import Tailwind.Utilities as Tw
@ -14,14 +13,6 @@ type alias Item =
{ title : String, slug : String }
serialize : S.Codec Never { title : String, slug : String }
serialize =
S.record Item
|> S.field .title S.string
|> S.field .slug S.string
|> S.finishRecord
view : ( Maybe Item, Maybe Item ) -> Html msg
view ( maybeLeft, maybeRight ) =
div

View File

@ -20,7 +20,7 @@ import View exposing (View)
type alias Msg =
Never
()
page : Page RouteParams Data

View File

@ -9,8 +9,11 @@ import Head
import Head.Seo as Seo
import Html.Styled exposing (..)
import Html.Styled.Attributes as Attr exposing (css)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Extra
import Markdown.Parser
import Markdown.Renderer
import MarkdownCodec
import OptimizedDecoder
import Page exposing (Page, StaticPayload)
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
@ -29,7 +32,7 @@ type alias Model =
type alias Msg =
Never
()
type alias RouteParams =
@ -244,28 +247,28 @@ type alias ArticleMetadata =
}
frontmatterDecoder : OptimizedDecoder.Decoder ArticleMetadata
frontmatterDecoder : Decoder ArticleMetadata
frontmatterDecoder =
OptimizedDecoder.map5 ArticleMetadata
(OptimizedDecoder.field "title" OptimizedDecoder.string)
(OptimizedDecoder.field "description" OptimizedDecoder.string)
(OptimizedDecoder.field "published"
(OptimizedDecoder.string
|> OptimizedDecoder.andThen
Decode.map5 ArticleMetadata
(Decode.field "title" Decode.string)
(Decode.field "description" Decode.string)
(Decode.field "published"
(Decode.string
|> Decode.andThen
(\isoString ->
Date.fromIsoString isoString
|> OptimizedDecoder.fromResult
|> Json.Decode.Extra.fromResult
)
)
)
(OptimizedDecoder.field "image" imageDecoder)
(OptimizedDecoder.field "draft" OptimizedDecoder.bool
|> OptimizedDecoder.maybe
|> OptimizedDecoder.map (Maybe.withDefault False)
(Decode.field "image" imageDecoder)
(Decode.field "draft" Decode.bool
|> Decode.maybe
|> Decode.map (Maybe.withDefault False)
)
imageDecoder : OptimizedDecoder.Decoder Pages.Url.Url
imageDecoder : Decode.Decoder Pages.Url.Url
imageDecoder =
OptimizedDecoder.string
|> OptimizedDecoder.map (\cloudinaryAsset -> Cloudinary.url cloudinaryAsset Nothing 800)
Decode.string
|> Decode.map (\cloudinaryAsset -> Cloudinary.url cloudinaryAsset Nothing 800)

View File

@ -11,12 +11,13 @@ import Head.Seo as Seo
import Heroicon
import Html.Styled as Html exposing (Html)
import Html.Styled.Attributes as Attr exposing (css)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Extra
import List.Extra
import Markdown.Block as Block exposing (Block)
import Markdown.Parser
import MarkdownCodec
import NextPrevious
import OptimizedDecoder as Decode exposing (Decoder)
import Page exposing (Page, PageWithState, StaticPayload)
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
@ -34,7 +35,7 @@ type alias Model =
type alias Msg =
Never
()
type alias RouteParams =
@ -157,7 +158,6 @@ titleForSection section =
|> Result.fromMaybe "Expected to find an H1 heading in this markdown."
|> DataSource.fromResult
)
|> DataSource.distillSerializeCodec ("next-previous-" ++ section.slug) NextPrevious.serialize
head :
@ -309,7 +309,7 @@ markdownBodyDecoder rawBody =
rawBody
|> Markdown.Parser.parse
|> Result.mapError (\_ -> "Markdown parsing error")
|> Decode.fromResult
|> Json.Decode.Extra.fromResult
markdownBodyDecoder2 : String -> DataSource (List Block)

View File

@ -47,7 +47,7 @@ type alias Model =
type alias Msg =
Never
()
type alias RouteParams =
@ -105,7 +105,7 @@ data =
DataSource.succeed ()
landingView : Html Never
landingView : Html Msg
landingView =
div
[ css
@ -294,7 +294,7 @@ firstSection :
, svgIcon : String
, code : ( String, String )
}
-> Html Never
-> Html Msg
firstSection info =
div
[ css

View File

@ -22,7 +22,7 @@ type alias Model =
type alias Msg =
Never
()
type alias RouteParams =

View File

@ -2,7 +2,8 @@ module Showcase exposing (..)
import DataSource
import DataSource.Http
import OptimizedDecoder as Decode
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Extra
import Pages.Secrets as Secrets
@ -17,7 +18,7 @@ type alias Entry =
}
decoder : Decode.Decoder (List Entry)
decoder : Decoder (List Entry)
decoder =
Decode.field "records" <|
Decode.list entryDecoder
@ -32,7 +33,7 @@ entryDecoder =
(Decode.field "Live URL" Decode.string)
(Decode.field "Author" Decode.string)
(Decode.field "Author URL" Decode.string)
(Decode.optionalField "Categories" (Decode.list Decode.string) |> Decode.map (Maybe.withDefault []))
(Json.Decode.Extra.optionalField "Categories" (Decode.list Decode.string) |> Decode.map (Maybe.withDefault []))
(Decode.maybe (Decode.field "Repository URL" Decode.string))

View File

@ -9,8 +9,6 @@ import Html.Styled.Attributes as Attr exposing (css)
import List.Extra
import Markdown.Block as Block exposing (Block, Inline)
import Markdown.Parser
import OptimizedDecoder
import Serialize as S
import Tailwind.Breakpoints as Bp
import Tailwind.Utilities as Tw
@ -31,7 +29,6 @@ dataSource docFiles =
)
)
|> DataSource.resolve
|> DataSource.distillSerializeCodec "table-of-contents" serialize
codec : Codec (TableOfContents Data)
@ -60,32 +57,6 @@ dataCodec =
|> Codec.buildObject
serialize : S.Codec e (TableOfContents Data)
serialize =
S.list serializeEntry
serializeEntry : S.Codec e (Entry Data)
serializeEntry =
S.customType
(\vEntry value ->
case value of
Entry data list ->
vEntry data list
)
|> S.variant2 Entry serializeData (S.list (S.lazy (\() -> serializeEntry)))
|> S.finishCustomType
serializeData : S.Codec e Data
serializeData =
S.record Data
|> S.field .anchorId S.string
|> S.field .name S.string
|> S.field .level S.int
|> S.finishRecord
headingsDecoder : String -> String -> DataSource (Entry Data)
headingsDecoder slug rawBody =
rawBody

View File

@ -7,7 +7,7 @@ import SyntaxHighlight
import Tailwind.Utilities as Tw
view : ( String, String ) -> Html Never
view : ( String, String ) -> Html msg
view tab =
div
[ css
@ -82,13 +82,13 @@ elmCodeBlock elmCode =
(Html.pre [] [ Html.code [] [ Html.text elmCode ] ])
codeTabs : ( String, String ) -> Html Never
codeTabs : ( String, String ) -> Html msg
codeTabs fileName =
ul [ css [ Tw.flex, Tw.text_sm, Tw.text_blue_200 ], Attr.style "transform" "translateY(0%) translateZ(0px);" ]
[ codeTab 0 True fileName ]
codeTab : Int -> Bool -> ( String, String ) -> Html Never
codeTab : Int -> Bool -> ( String, String ) -> Html msg
codeTab index isCurrent ( fileName, fileContents ) =
li
[ css [ Tw.flex_none ]

View File

@ -2,13 +2,13 @@ module MarkdownCodec exposing (isPlaceholder, noteTitle, titleAndDescription, wi
import DataSource exposing (DataSource)
import DataSource.File as StaticFile
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Extra
import List.Extra
import Markdown.Block as Block exposing (Block)
import Markdown.Parser
import Markdown.Renderer
import MarkdownExtra
import OptimizedDecoder exposing (Decoder)
import Serialize as S
isPlaceholder : String -> DataSource (Maybe ())
@ -35,7 +35,6 @@ isPlaceholder filePath =
)
|> DataSource.fromResult
)
|> DataSource.distillSerializeCodec (filePath ++ "-is-placeholder") S.bool
|> DataSource.map
(\bool ->
if bool then
@ -77,16 +76,15 @@ noteTitle filePath =
)
)
)
|> DataSource.distillSerializeCodec ("note-title-" ++ filePath) S.string
titleAndDescription : String -> DataSource { title : String, description : String }
titleAndDescription filePath =
filePath
|> StaticFile.onlyFrontmatter
(OptimizedDecoder.map2 (\title description -> { title = title, description = description })
(OptimizedDecoder.optionalField "title" OptimizedDecoder.string)
(OptimizedDecoder.optionalField "description" OptimizedDecoder.string)
(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 ->
@ -161,7 +159,7 @@ findDescription blocks =
titleFromFrontmatter : String -> DataSource (Maybe String)
titleFromFrontmatter filePath =
StaticFile.onlyFrontmatter
(OptimizedDecoder.optionalField "title" OptimizedDecoder.string)
(Json.Decode.Extra.optionalField "title" Decode.string)
filePath
@ -180,8 +178,6 @@ withoutFrontmatter renderer filePath =
|> DataSource.fromResult
)
)
|> DataSource.distillSerializeCodec ("markdown-blocks-" ++ filePath)
(S.list codec)
|> DataSource.andThen
(\blocks ->
blocks
@ -212,8 +208,6 @@ withFrontmatter constructor frontmatterDecoder renderer filePath =
|> DataSource.fromResult
)
)
|> DataSource.distillSerializeCodec ("markdown-blocks-" ++ filePath)
(S.list codec)
|> DataSource.andThen
(\blocks ->
blocks
@ -221,248 +215,3 @@ withFrontmatter constructor frontmatterDecoder renderer filePath =
|> DataSource.fromResult
)
)
codec : S.Codec Never Block
codec =
S.customType
(\encodeThematicBreak encodeHtmlBlock encodeUnorderedList encodeOrderedList encodeBlockQuote encodeHeading encodeParagraph encodeTable encodeCodeBlock value ->
case value of
Block.ThematicBreak ->
encodeThematicBreak
Block.HtmlBlock html ->
encodeHtmlBlock html
Block.UnorderedList listSpacing listItems ->
encodeUnorderedList listSpacing listItems
Block.OrderedList listSpacing int lists ->
encodeOrderedList listSpacing int lists
Block.BlockQuote blocks ->
encodeBlockQuote blocks
Block.Heading headingLevel inlines ->
encodeHeading headingLevel inlines
Block.Paragraph inlines ->
encodeParagraph inlines
Block.Table header rows ->
encodeTable header rows
Block.CodeBlock record ->
encodeCodeBlock record
)
|> S.variant0 Block.ThematicBreak
|> S.variant1 Block.HtmlBlock htmlCodec
|> S.variant2 Block.UnorderedList listSpacingCodec (S.list listItemCodec)
|> S.variant3 Block.OrderedList listSpacingCodec S.int (S.list (S.list (S.lazy (\() -> codec))))
|> S.variant1 Block.BlockQuote (S.list (S.lazy (\() -> codec)))
|> S.variant2 Block.Heading headingCodec (S.list inlineCodec)
|> S.variant1 Block.Paragraph (S.list inlineCodec)
|> S.variant2 Block.Table tableHeaderCodec (S.list (S.list (S.list inlineCodec)))
|> S.variant1 Block.CodeBlock
(S.record (\body language -> { body = body, language = language })
|> S.field .body S.string
|> S.field .language (S.maybe S.string)
|> S.finishRecord
)
|> S.finishCustomType
listSpacingCodec : S.Codec e Block.ListSpacing
listSpacingCodec =
S.customType
(\vLoose vTight value ->
case value of
Block.Loose ->
vLoose
Block.Tight ->
vTight
)
|> S.variant0 Block.Loose
|> S.variant0 Block.Tight
|> S.finishCustomType
tableHeaderCodec :
S.Codec
Never
(List
{ label : List Block.Inline
, alignment : Maybe Block.Alignment
}
)
tableHeaderCodec =
S.record (\label alignment -> { label = label, alignment = alignment })
|> S.field .label (S.list inlineCodec)
|> S.field .alignment (S.maybe alignmentCodec)
|> S.finishRecord
|> S.list
alignmentCodec : S.Codec Never Block.Alignment
alignmentCodec =
S.customType
(\encodeAlignLeft encodeAlignRight encodeAlignCenter value ->
case value of
Block.AlignLeft ->
encodeAlignLeft
Block.AlignRight ->
encodeAlignRight
Block.AlignCenter ->
encodeAlignCenter
)
|> S.variant0 Block.AlignLeft
|> S.variant0 Block.AlignRight
|> S.variant0 Block.AlignCenter
|> S.finishCustomType
headingCodec : S.Codec Never Block.HeadingLevel
headingCodec =
S.customType
(\encodeH1 encodeH2 encodeH3 encodeH4 encodeH5 encodeH6 value ->
case value of
Block.H1 ->
encodeH1
Block.H2 ->
encodeH2
Block.H3 ->
encodeH3
Block.H4 ->
encodeH4
Block.H5 ->
encodeH5
Block.H6 ->
encodeH6
)
|> S.variant0 Block.H1
|> S.variant0 Block.H2
|> S.variant0 Block.H3
|> S.variant0 Block.H4
|> S.variant0 Block.H5
|> S.variant0 Block.H6
|> S.finishCustomType
inlineCodec : S.Codec Never Block.Inline
inlineCodec =
S.customType
(\encodeHardLineBreak encodeHtmlInline encodeLink encodeImage encodeEmphasis encodeStrong encodeStrikethrough encodeCodeSpan encodeText value ->
case value of
Block.HardLineBreak ->
encodeHardLineBreak
Block.HtmlInline html ->
encodeHtmlInline html
Block.Link string maybeString inlines ->
encodeLink string maybeString inlines
Block.Image string maybeString inlines ->
encodeImage string maybeString inlines
Block.Emphasis inlines ->
encodeEmphasis inlines
Block.Strong inlines ->
encodeStrong inlines
Block.Strikethrough inlines ->
encodeStrikethrough inlines
Block.CodeSpan string ->
encodeCodeSpan string
Block.Text string ->
encodeText string
)
|> S.variant0 Block.HardLineBreak
|> S.variant1 Block.HtmlInline htmlCodec
|> S.variant3 Block.Link S.string (S.maybe S.string) (S.list (S.lazy (\() -> inlineCodec)))
|> S.variant3 Block.Image S.string (S.maybe S.string) (S.list (S.lazy (\() -> inlineCodec)))
|> S.variant1 Block.Emphasis (S.list (S.lazy (\() -> inlineCodec)))
|> S.variant1 Block.Strong (S.list (S.lazy (\() -> inlineCodec)))
|> S.variant1 Block.Strikethrough (S.list (S.lazy (\() -> inlineCodec)))
|> S.variant1 Block.CodeSpan S.string
|> S.variant1 Block.Text S.string
|> S.finishCustomType
htmlCodec : S.Codec Never (Block.Html Block)
htmlCodec =
S.customType
(\encodeHtmlElement encodeHtmlComment encodeProcessingInstruction encodeHtmlDeclaration encodeCdata value ->
case value of
Block.HtmlElement tag attributes children ->
encodeHtmlElement tag attributes children
Block.HtmlComment comment ->
encodeHtmlComment comment
Block.ProcessingInstruction string ->
encodeProcessingInstruction string
Block.HtmlDeclaration string1 string2 ->
encodeHtmlDeclaration string1 string2
Block.Cdata string ->
encodeCdata string
)
|> S.variant3 Block.HtmlElement S.string (S.list htmlAttributeCodec) (S.list (S.lazy (\() -> codec)))
|> S.variant1 Block.HtmlComment S.string
|> S.variant1 Block.ProcessingInstruction S.string
|> S.variant2 Block.HtmlDeclaration S.string S.string
|> S.variant1 Block.Cdata S.string
|> S.finishCustomType
htmlAttributeCodec : S.Codec Never { name : String, value : String }
htmlAttributeCodec =
S.record (\name value -> { name = name, value = value })
|> S.field .name S.string
|> S.field .value S.string
|> S.finishRecord
listItemCodec : S.Codec Never (Block.ListItem Block.Block)
listItemCodec =
S.customType
(\encodeListItem value ->
case value of
Block.ListItem task children ->
encodeListItem task children
)
|> S.variant2 Block.ListItem taskCodec (S.list (S.lazy (\() -> codec)))
|> S.finishCustomType
taskCodec : S.Codec Never Block.Task
taskCodec =
S.customType
(\encodeNoTask encodeIncompleteTask encodeCompletedTask value ->
case value of
Block.NoTask ->
encodeNoTask
Block.IncompleteTask ->
encodeIncompleteTask
Block.CompletedTask ->
encodeCompletedTask
)
|> S.variant0 Block.NoTask
|> S.variant0 Block.IncompleteTask
|> S.variant0 Block.CompletedTask
|> S.finishCustomType

View File

@ -152,7 +152,7 @@ This is my first post!
Then we could read that title for our blog post list page using our `blogPosts` `DataSource` that we defined above.
import DataSource.File
import OptimizedDecoder as Decode exposing (Decoder)
import Json.Decode as Decode exposing (Decoder)
titles : DataSource (List BlogPost)
titles =
@ -213,8 +213,8 @@ That will give us
import DataSource exposing (DataSource)
import DataSource.Http
import DataSource.Internal.Glob exposing (Glob(..))
import Json.Decode as Decode
import List.Extra
import OptimizedDecoder
import Regex
import Secrets
@ -945,9 +945,9 @@ toNonEmptyWithDefault default list =
toDataSource : Glob a -> DataSource (List a)
toDataSource glob =
DataSource.Http.get (Secrets.succeed <| "glob://" ++ DataSource.Internal.Glob.toPattern glob)
(OptimizedDecoder.string
|> OptimizedDecoder.list
|> OptimizedDecoder.map
(Decode.string
|> Decode.list
|> Decode.map
(\rawGlob -> rawGlob |> List.map (\matchedPath -> DataSource.Internal.Glob.run matchedPath glob |> .match))
)