Add generateFiles hook.

This commit is contained in:
Dillon Kearns 2020-01-05 16:36:50 -08:00
parent 815dec7d98
commit a0b735379a
7 changed files with 345 additions and 69 deletions

View File

@ -9,6 +9,7 @@
"dependencies": {
"direct": {
"avh4/elm-color": "1.0.0",
"billstclair/elm-xml-eeue56": "1.0.1",
"dillonkearns/elm-markdown": "1.1.3",
"dillonkearns/elm-oembed": "1.0.0",
"elm/browser": "1.0.2",

View File

@ -0,0 +1,84 @@
module Feed exposing (fileToGenerate)
import Dict
import Metadata exposing (Metadata(..))
import Pages
import Pages.PagePath as PagePath exposing (PagePath)
import RssFeed
import Time
import Xml
import Xml.Encode exposing (..)
fileToGenerate :
String
->
List
{ path : PagePath Pages.PathKey
, frontmatter : Metadata
}
->
{ path : List String
, content : String
}
fileToGenerate siteTagline siteMetadata =
{ path = [ "feed.xml" ]
, content =
generate siteTagline siteMetadata |> Xml.Encode.encode 0
}
generate :
String
->
List
{ path : PagePath Pages.PathKey
, frontmatter : Metadata
}
-> Xml.Value
generate siteTagline siteMetadata =
RssFeed.generate
{ title = "elm-pages Blog"
, description = siteTagline
, url = "https://elm-pages.com/blog"
, lastBuildTime = Pages.builtAt
, generator =
Just
{ name = "elm-pages"
, uri = Just "https://elm-pages.com"
, version = Nothing
}
, items = siteMetadata |> List.filterMap metadataToRssItem
}
metadataToRssItem :
{ path : PagePath Pages.PathKey
, frontmatter : Metadata
}
-> Maybe RssFeed.Item
metadataToRssItem page =
case page.frontmatter of
Article article ->
Just
{ title = article.title
, description = article.description
, url = PagePath.toString page.path
, guid = PagePath.toString page.path
, categories = []
, author = article.author.name
, pubDate = article.published
, content = Nothing
}
Page pageMetadata ->
Nothing
Doc docMetadata ->
Nothing
Author author ->
Nothing
BlogIndex ->
Nothing

View File

@ -10,6 +10,7 @@ import Element.Background
import Element.Border
import Element.Font as Font
import Element.Region
import Feed
import Head
import Head.Seo as Seo
import Html exposing (Html)
@ -62,11 +63,27 @@ main =
, documents = [ markdownDocument ]
, manifest = manifest
, canonicalSiteUrl = canonicalSiteUrl
, generateFiles = generateFiles
, onPageChange = OnPageChange
, internals = Pages.internals
}
generateFiles :
List
{ path : PagePath Pages.PathKey
, frontmatter : Metadata
}
->
List
{ path : List String
, content : String
}
generateFiles siteMetadata =
[ Feed.fileToGenerate siteTagline siteMetadata
]
markdownDocument : ( String, Pages.Document.DocumentHandler Metadata ( MarkdownRenderer.TableOfContents, List (Element Msg) ) )
markdownDocument =
Pages.Document.parser

View File

@ -0,0 +1,131 @@
module RssFeed exposing (Item, generate)
import Date exposing (Date)
import Dict
import Time
import Xml
import Xml.Encode exposing (..)
type alias Item =
{ title : String
, description : String
, url : String
, guid : String
, categories : List String
, author : String
, pubDate : Date
, content : Maybe String
{-
lat optional number The latitude coordinate of the item.
long optional number The longitude coordinate of the item.
custom_elements optional array Put additional elements in the item (node-xml syntax)
enclosure optional object An enclosure object
-}
}
generate :
{ title : String
, description : String
, url : String
, lastBuildTime : Time.Posix
, generator :
Maybe
{ name : String
, uri : Maybe String
, version : Maybe String
}
, items : List Item
}
-> Xml.Value
generate feed =
let
lastBuildTimeString =
-- TODO
--feed.lastBuildTime
""
in
object
[ ( "rss"
, Dict.fromList
[ ( "xmlns", string "http://www.w3.org/2005/Atom" )
, ( "xmlns:dc", string "http://purl.org/dc/elements/1.1/" )
, ( "xmlns:content", string "http://purl.org/rss/1.0/modules/content/" )
, ( "xmlns:atom", string "http://www.w3.org/2005/Atom" )
, ( "version", string "2.0" )
]
, object
[ ( "channel"
, Dict.empty
, list
([ keyValue "title" feed.title
, keyValue "description" feed.description
, keyValue "link" feed.url
, keyValue "lastBuildDate" lastBuildTimeString
]
++ List.map itemXml feed.items
++ ([ feed.generator |> Maybe.map generatorXml
]
|> List.filterMap identity
)
)
)
]
)
]
itemXml : Item -> Xml.Value
itemXml item =
object
[ ( "item"
, Dict.empty
, list
([ keyValue "title" item.title
, keyValue "description" item.description
, keyValue "link" item.url
, keyValue "guid" item.guid
, keyValue "pubDate" (formatDate item.pubDate)
]
++ ([ item.content |> Maybe.map (\content -> keyValue "content" content)
]
|> List.filterMap identity
)
)
)
]
formatDate : Date -> String
formatDate date =
Date.toIsoString date
--Date.format "EE, dd MM yyyy" date
generatorXml :
{ name : String
, uri : Maybe String
, version : Maybe String
}
-> Xml.Value
generatorXml generator =
Xml.Encode.object
[ ( "generator"
, [ generator.uri |> Maybe.map (\uri -> ( "uri", string uri ))
, generator.version |> Maybe.map (\version -> ( "version", string version ))
]
|> List.filterMap identity
|> Dict.fromList
, Xml.Encode.string generator.name
)
]
keyValue : String -> String -> Xml.Value
keyValue key value =
object [ ( key, Dict.empty, string value ) ]

View File

@ -497,6 +497,16 @@ application :
, content : Content
, toJsPort : Json.Encode.Value -> Cmd Never
, manifest : Manifest.Config pathKey
, generateFiles :
List
{ path : PagePath pathKey
, frontmatter : metadata
}
->
List
{ path : List String
, content : String
}
, canonicalSiteUrl : String
, pathKey : pathKey
, onPageChange : PagePath pathKey -> userMsg
@ -564,6 +574,16 @@ cliApplication :
, content : Content
, toJsPort : Json.Encode.Value -> Cmd Never
, manifest : Manifest.Config pathKey
, generateFiles :
List
{ path : PagePath pathKey
, frontmatter : metadata
}
->
List
{ path : List String
, content : String
}
, canonicalSiteUrl : String
, pathKey : pathKey
, onPageChange : PagePath pathKey -> userMsg

View File

@ -150,34 +150,47 @@ type Msg
= GotStaticHttpResponse { request : { masked : RequestDetails, unmasked : RequestDetails }, response : Result Http.Error String }
type alias Config pathKey userMsg userModel metadata view =
{ init : Maybe (PagePath pathKey) -> ( userModel, Cmd userMsg )
, update : userMsg -> userModel -> ( userModel, Cmd userMsg )
, subscriptions : userModel -> Sub userMsg
, view :
List ( PagePath pathKey, metadata )
->
{ path : PagePath pathKey
, frontmatter : metadata
}
->
StaticHttp.Request
{ view : userModel -> view -> { title : String, body : Html userMsg }
, head : List (Head.Tag pathKey)
}
, document : Pages.Document.Document metadata view
, content : Content
, toJsPort : Json.Encode.Value -> Cmd Never
, manifest : Manifest.Config pathKey
, generateFiles :
List
{ path : PagePath pathKey
, frontmatter : metadata
}
->
List
{ path : List String
, content : String
}
, canonicalSiteUrl : String
, pathKey : pathKey
, onPageChange : PagePath pathKey -> userMsg
}
cliApplication :
(Msg -> msg)
-> (msg -> Maybe Msg)
-> (Model -> model)
-> (model -> Maybe Model)
->
{ init : Maybe (PagePath pathKey) -> ( userModel, Cmd userMsg )
, update : userMsg -> userModel -> ( userModel, Cmd userMsg )
, subscriptions : userModel -> Sub userMsg
, view :
List ( PagePath pathKey, metadata )
->
{ path : PagePath pathKey
, frontmatter : metadata
}
->
StaticHttp.Request
{ view : userModel -> view -> { title : String, body : Html userMsg }
, head : List (Head.Tag pathKey)
}
, document : Pages.Document.Document metadata view
, content : Content
, toJsPort : Json.Encode.Value -> Cmd Never
, manifest : Manifest.Config pathKey
, canonicalSiteUrl : String
, pathKey : pathKey
, onPageChange : PagePath pathKey -> userMsg
}
-> Config pathKey userMsg userModel metadata view
-> Platform.Program Flags model msg
cliApplication cliMsgConstructor narrowMsg toModel fromModel config =
let
@ -199,7 +212,7 @@ cliApplication cliMsgConstructor narrowMsg toModel fromModel config =
\msg model ->
case ( narrowMsg msg, fromModel model ) of
( Just cliMsg, Just cliModel ) ->
update config cliMsg cliModel
update siteMetadata config cliMsg cliModel
|> Tuple.mapSecond (perform cliMsgConstructor config.toJsPort)
|> Tuple.mapFirst toModel
@ -270,21 +283,7 @@ init :
(Model -> model)
-> ContentCache.ContentCache metadata view
-> Result (List BuildError) (List ( PagePath pathKey, metadata ))
->
{ config
| view :
List ( PagePath pathKey, metadata )
->
{ path : PagePath pathKey
, frontmatter : metadata
}
->
StaticHttp.Request
{ view : userModel -> view -> { title : String, body : Html userMsg }
, head : List (Head.Tag pathKey)
}
, manifest : Manifest.Config pathKey
}
-> Config pathKey userMsg userModel metadata view
-> Decode.Value
-> ( model, Effect pathKey )
init toModel contentCache siteMetadata config flags =
@ -320,7 +319,7 @@ init toModel contentCache siteMetadata config flags =
staticResponsesInit []
( updatedRawResponses, effect ) =
sendStaticResponsesIfDone mode secrets Dict.empty [] staticResponses config.manifest
sendStaticResponsesIfDone config siteMetadata mode secrets Dict.empty [] staticResponses
in
( Model staticResponses secrets [] updatedRawResponses mode |> toModel
, effect
@ -346,6 +345,8 @@ init toModel contentCache siteMetadata config flags =
staticResponsesInit []
in
updateAndSendPortIfDone
config
siteMetadata
(Model
staticResponses
secrets
@ -354,10 +355,11 @@ init toModel contentCache siteMetadata config flags =
mode
)
toModel
config.manifest
Err metadataParserErrors ->
updateAndSendPortIfDone
config
siteMetadata
(Model Dict.empty
secrets
(metadataParserErrors |> List.map Tuple.second)
@ -365,10 +367,11 @@ init toModel contentCache siteMetadata config flags =
mode
)
toModel
config.manifest
Err error ->
updateAndSendPortIfDone
config
siteMetadata
(Model Dict.empty
SecretsDict.masked
[ { title = "Internal Error"
@ -379,20 +382,25 @@ init toModel contentCache siteMetadata config flags =
Dev
)
toModel
config.manifest
updateAndSendPortIfDone : Model -> (Model -> model) -> Manifest.Config pathKey -> ( model, Effect pathKey )
updateAndSendPortIfDone model toModel manifest =
updateAndSendPortIfDone :
Config pathKey userMsg userModel metadata view
-> Result (List BuildError) (List ( PagePath pathKey, metadata ))
-> Model
-> (Model -> model)
-> ( model, Effect pathKey )
updateAndSendPortIfDone config siteMetadata model toModel =
let
( updatedAllRawResponses, effect ) =
sendStaticResponsesIfDone
config
siteMetadata
model.mode
model.secrets
model.allRawResponses
model.errors
model.staticResponses
manifest
in
( { model | allRawResponses = updatedAllRawResponses } |> toModel
, effect
@ -404,24 +412,12 @@ type alias PageErrors =
update :
{ config
| view :
List ( PagePath pathKey, metadata )
->
{ path : PagePath pathKey
, frontmatter : metadata
}
->
StaticHttp.Request
{ view : userModel -> view -> { title : String, body : Html userMsg }
, head : List (Head.Tag pathKey)
}
, manifest : Manifest.Config pathKey
}
Result (List BuildError) (List ( PagePath pathKey, metadata ))
-> Config pathKey userMsg userModel metadata view
-> Msg
-> Model
-> ( Model, Effect pathKey )
update config msg model =
update siteMetadata config msg model =
case msg of
GotStaticHttpResponse { request, response } ->
let
@ -478,7 +474,7 @@ update config msg model =
}
( updatedAllRawResponses, effect ) =
sendStaticResponsesIfDone updatedModel.mode updatedModel.secrets updatedModel.allRawResponses updatedModel.errors updatedModel.staticResponses config.manifest
sendStaticResponsesIfDone config siteMetadata updatedModel.mode updatedModel.secrets updatedModel.allRawResponses updatedModel.errors updatedModel.staticResponses
in
( { updatedModel | allRawResponses = updatedAllRawResponses }
, effect
@ -607,8 +603,16 @@ isJust maybeValue =
False
sendStaticResponsesIfDone : Mode -> SecretsDict -> Dict String (Maybe String) -> List BuildError -> StaticResponses -> Manifest.Config pathKey -> ( Dict String (Maybe String), Effect pathKey )
sendStaticResponsesIfDone mode secrets allRawResponses errors staticResponses manifest =
sendStaticResponsesIfDone :
Config pathKey userMsg userModel metadata view
-> Result (List BuildError) (List ( PagePath pathKey, metadata ))
-> Mode
-> SecretsDict
-> Dict String (Maybe String)
-> List BuildError
-> StaticResponses
-> ( Dict String (Maybe String), Effect pathKey )
sendStaticResponsesIfDone config siteMetadata mode secrets allRawResponses errors staticResponses =
let
pendingRequests =
staticResponses
@ -759,6 +763,17 @@ sendStaticResponsesIfDone mode secrets allRawResponses errors staticResponses ma
let
updatedAllRawResponses =
Dict.empty
generatedFiles =
siteMetadata
|> Result.withDefault []
|> List.map
(\( pagePath, metadata ) ->
{ path = pagePath
, frontmatter = metadata
}
)
|> config.generateFiles
in
( updatedAllRawResponses
, SendJsData
@ -766,11 +781,8 @@ sendStaticResponsesIfDone mode secrets allRawResponses errors staticResponses ma
Success
(ToJsSuccessPayload
(encodeStaticResponses mode staticResponses)
manifest
[ { path = [ "hello.txt" ]
, content = "Hello generated files!"
}
]
config.manifest
generatedFiles
)
else

View File

@ -77,6 +77,16 @@ application :
}
, documents : List ( String, Document.DocumentHandler metadata view )
, manifest : Pages.Manifest.Config pathKey
, generateFiles :
List
{ path : PagePath pathKey
, frontmatter : metadata
}
->
List
{ path : List String
, content : String
}
, onPageChange : PagePath pathKey -> userMsg
, canonicalSiteUrl : String
, internals : Pages.Internal.Internal pathKey
@ -97,6 +107,7 @@ application config =
, subscriptions = config.subscriptions
, document = Document.fromList config.documents
, content = config.internals.content
, generateFiles = config.generateFiles
, toJsPort = config.internals.toJsPort
, manifest = config.manifest
, canonicalSiteUrl = config.canonicalSiteUrl