elm-pages 2.1.6 → 2.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/generator/review/elm.json +34 -0
- package/generator/review/src/ReviewConfig.elm +10 -0
- package/generator/src/basepath-middleware.js +15 -9
- package/generator/src/build.js +100 -6
- package/generator/src/cli.js +13 -9
- package/generator/src/compile-elm.js +43 -0
- package/generator/src/dev-server.js +63 -11
- package/generator/src/error-formatter.js +62 -9
- package/generator/src/generate-template-module-connector.js +17 -4
- package/generator/src/init.js +4 -0
- package/generator/src/pre-render-html.js +19 -12
- package/generator/src/render-worker.js +0 -1
- package/generator/src/render.js +1 -2
- package/generator/src/seo-renderer.js +21 -2
- package/generator/static-code/hmr.js +43 -6
- package/generator/template/elm-tooling.json +9 -0
- package/generator/template/package.json +5 -1
- package/package.json +16 -9
- package/src/ApiRoute.elm +178 -0
- package/src/AriaLiveAnnouncer.elm +36 -0
- package/src/BuildError.elm +60 -0
- package/src/DataSource/File.elm +288 -0
- package/src/DataSource/Glob.elm +1050 -0
- package/src/DataSource/Http.elm +467 -0
- package/src/DataSource/Internal/Glob.elm +74 -0
- package/src/DataSource/Port.elm +87 -0
- package/src/DataSource/ServerRequest.elm +60 -0
- package/src/DataSource.elm +801 -0
- package/src/Head/Seo.elm +516 -0
- package/src/Head/Twitter.elm +109 -0
- package/src/Head.elm +452 -0
- package/src/HtmlPrinter.elm +27 -0
- package/src/Internal/ApiRoute.elm +89 -0
- package/src/Internal/OptimizedDecoder.elm +18 -0
- package/src/KeepOrDiscard.elm +6 -0
- package/src/OptimizedDecoder/Pipeline.elm +335 -0
- package/src/OptimizedDecoder.elm +818 -0
- package/src/Pages/ContentCache.elm +248 -0
- package/src/Pages/Flags.elm +26 -0
- package/src/Pages/Http.elm +10 -0
- package/src/Pages/Internal/ApplicationType.elm +6 -0
- package/src/Pages/Internal/NotFoundReason.elm +256 -0
- package/src/Pages/Internal/Platform/Cli.elm +1015 -0
- package/src/Pages/Internal/Platform/Effect.elm +14 -0
- package/src/Pages/Internal/Platform/StaticResponses.elm +540 -0
- package/src/Pages/Internal/Platform/ToJsPayload.elm +138 -0
- package/src/Pages/Internal/Platform.elm +745 -0
- package/src/Pages/Internal/RoutePattern.elm +122 -0
- package/src/Pages/Internal/Router.elm +116 -0
- package/src/Pages/Internal/StaticHttpBody.elm +54 -0
- package/src/Pages/Internal/String.elm +39 -0
- package/src/Pages/Manifest/Category.elm +240 -0
- package/src/Pages/Manifest.elm +412 -0
- package/src/Pages/PageUrl.elm +38 -0
- package/src/Pages/ProgramConfig.elm +73 -0
- package/src/Pages/Review/NoContractViolations.elm +397 -0
- package/src/Pages/Secrets.elm +83 -0
- package/src/Pages/SiteConfig.elm +13 -0
- package/src/Pages/StaticHttp/Request.elm +42 -0
- package/src/Pages/StaticHttpRequest.elm +320 -0
- package/src/Pages/Url.elm +60 -0
- package/src/Path.elm +96 -0
- package/src/QueryParams.elm +216 -0
- package/src/RenderRequest.elm +163 -0
- package/src/RequestsAndPending.elm +20 -0
- package/src/Secrets.elm +111 -0
- package/src/SecretsDict.elm +45 -0
- package/src/StructuredData.elm +236 -0
- package/src/TerminalText.elm +242 -0
- package/src/Test/Html/Internal/ElmHtml/Constants.elm +53 -0
- package/src/Test/Html/Internal/ElmHtml/Helpers.elm +17 -0
- package/src/Test/Html/Internal/ElmHtml/InternalTypes.elm +529 -0
- package/src/Test/Html/Internal/ElmHtml/Markdown.elm +56 -0
- package/src/Test/Html/Internal/ElmHtml/ToString.elm +197 -0
- package/src/Test/Internal/KernelConstants.elm +34 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
module RenderRequest exposing
|
|
2
|
+
( IncludeHtml(..)
|
|
3
|
+
, RenderRequest(..)
|
|
4
|
+
, RequestPayload(..)
|
|
5
|
+
, decoder
|
|
6
|
+
, default
|
|
7
|
+
, maybeRequestPayload
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
import ApiRoute
|
|
11
|
+
import HtmlPrinter
|
|
12
|
+
import Internal.ApiRoute
|
|
13
|
+
import Json.Decode as Decode
|
|
14
|
+
import Json.Encode as Encode
|
|
15
|
+
import Pages.ProgramConfig exposing (ProgramConfig)
|
|
16
|
+
import Path exposing (Path)
|
|
17
|
+
import Regex
|
|
18
|
+
import Url exposing (Url)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
type RequestPayload route
|
|
22
|
+
= Page { path : Path, frontmatter : route }
|
|
23
|
+
| Api ( String, ApiRoute.ApiRoute ApiRoute.Response )
|
|
24
|
+
| NotFound Path
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
type RenderRequest route
|
|
28
|
+
= SinglePage IncludeHtml (RequestPayload route) Decode.Value
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
default : RenderRequest route
|
|
32
|
+
default =
|
|
33
|
+
SinglePage
|
|
34
|
+
HtmlAndJson
|
|
35
|
+
(NotFound (Path.fromString "/error"))
|
|
36
|
+
Encode.null
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
maybeRequestPayload : RenderRequest route -> Maybe Decode.Value
|
|
40
|
+
maybeRequestPayload renderRequest =
|
|
41
|
+
case renderRequest of
|
|
42
|
+
SinglePage _ _ rawJson ->
|
|
43
|
+
Just rawJson
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
type IncludeHtml
|
|
47
|
+
= HtmlAndJson
|
|
48
|
+
| OnlyJson
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
decoder :
|
|
52
|
+
ProgramConfig userMsg userModel (Maybe route) siteData pageData sharedData
|
|
53
|
+
-> Decode.Decoder (RenderRequest (Maybe route))
|
|
54
|
+
decoder config =
|
|
55
|
+
Decode.field "request"
|
|
56
|
+
(Decode.map3
|
|
57
|
+
(\includeHtml requestThing payload ->
|
|
58
|
+
SinglePage includeHtml requestThing payload
|
|
59
|
+
)
|
|
60
|
+
(Decode.field "kind" Decode.string
|
|
61
|
+
|> Decode.andThen
|
|
62
|
+
(\kind ->
|
|
63
|
+
case kind of
|
|
64
|
+
"single-page" ->
|
|
65
|
+
Decode.field "jsonOnly" Decode.bool
|
|
66
|
+
|> Decode.map
|
|
67
|
+
(\jsonOnly ->
|
|
68
|
+
if jsonOnly then
|
|
69
|
+
OnlyJson
|
|
70
|
+
|
|
71
|
+
else
|
|
72
|
+
HtmlAndJson
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
_ ->
|
|
76
|
+
Decode.fail "Unhandled"
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
(requestPayloadDecoder config)
|
|
80
|
+
(Decode.field "payload" Decode.value)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
{-
|
|
86
|
+
payload: modifiedRequest,
|
|
87
|
+
kind: "single-page",
|
|
88
|
+
jsonOnly: isJson,
|
|
89
|
+
-}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
requestPayloadDecoder :
|
|
93
|
+
ProgramConfig userMsg userModel (Maybe route) siteData pageData sharedData
|
|
94
|
+
-> Decode.Decoder (RequestPayload (Maybe route))
|
|
95
|
+
requestPayloadDecoder config =
|
|
96
|
+
(Decode.string
|
|
97
|
+
|> Decode.map
|
|
98
|
+
(\rawPath ->
|
|
99
|
+
let
|
|
100
|
+
path : String
|
|
101
|
+
path =
|
|
102
|
+
rawPath
|
|
103
|
+
|> dropTrailingIndexHtml
|
|
104
|
+
|
|
105
|
+
route : Maybe route
|
|
106
|
+
route =
|
|
107
|
+
pathToUrl path |> config.urlToRoute
|
|
108
|
+
|
|
109
|
+
apiRoute : Maybe (ApiRoute.ApiRoute ApiRoute.Response)
|
|
110
|
+
apiRoute =
|
|
111
|
+
Internal.ApiRoute.firstMatch (String.dropLeft 1 path)
|
|
112
|
+
(config.apiRoutes HtmlPrinter.htmlToString)
|
|
113
|
+
in
|
|
114
|
+
case route of
|
|
115
|
+
Just _ ->
|
|
116
|
+
if isFile rawPath then
|
|
117
|
+
case apiRoute of
|
|
118
|
+
Just justApi ->
|
|
119
|
+
( path, justApi ) |> Api
|
|
120
|
+
|
|
121
|
+
Nothing ->
|
|
122
|
+
NotFound (Path.fromString path)
|
|
123
|
+
|
|
124
|
+
else
|
|
125
|
+
Page
|
|
126
|
+
{ frontmatter = route
|
|
127
|
+
, path = config.routeToPath route |> Path.join
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
Nothing ->
|
|
131
|
+
case apiRoute of
|
|
132
|
+
Just justApi ->
|
|
133
|
+
( path, justApi ) |> Api
|
|
134
|
+
|
|
135
|
+
Nothing ->
|
|
136
|
+
NotFound (Path.fromString path)
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
|> Decode.field "path"
|
|
140
|
+
|> Decode.field "payload"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
isFile : String -> Bool
|
|
144
|
+
isFile rawPath =
|
|
145
|
+
rawPath
|
|
146
|
+
|> String.contains "."
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
pathToUrl : String -> Url
|
|
150
|
+
pathToUrl path =
|
|
151
|
+
{ protocol = Url.Https
|
|
152
|
+
, host = "TODO"
|
|
153
|
+
, port_ = Nothing
|
|
154
|
+
, path = path
|
|
155
|
+
, query = Nothing
|
|
156
|
+
, fragment = Nothing
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
dropTrailingIndexHtml : String -> String
|
|
161
|
+
dropTrailingIndexHtml =
|
|
162
|
+
Regex.replace (Regex.fromString "/index\\.html$" |> Maybe.withDefault Regex.never)
|
|
163
|
+
(\_ -> "")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module RequestsAndPending exposing (RequestsAndPending, decoder, get)
|
|
2
|
+
|
|
3
|
+
import Dict exposing (Dict)
|
|
4
|
+
import Json.Decode as Decode
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
type alias RequestsAndPending =
|
|
8
|
+
Dict String (Maybe String)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
get : String -> RequestsAndPending -> Maybe String
|
|
12
|
+
get key requestsAndPending =
|
|
13
|
+
requestsAndPending
|
|
14
|
+
|> Dict.get key
|
|
15
|
+
|> Maybe.andThen identity
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
decoder : Decode.Decoder RequestsAndPending
|
|
19
|
+
decoder =
|
|
20
|
+
Decode.dict (Decode.string |> Decode.map Just)
|
package/src/Secrets.elm
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
module Secrets exposing
|
|
2
|
+
( Value
|
|
3
|
+
, lookup
|
|
4
|
+
, map
|
|
5
|
+
, maskedLookup
|
|
6
|
+
, succeed
|
|
7
|
+
, with
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
import BuildError exposing (BuildError)
|
|
11
|
+
import Fuzzy
|
|
12
|
+
import SecretsDict exposing (SecretsDict)
|
|
13
|
+
import TerminalText as Terminal
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
type Value value
|
|
17
|
+
= Value (SecretsDict -> Result (List BuildError) value)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
lookup : SecretsDict -> Value a -> Result (List BuildError) a
|
|
21
|
+
lookup secrets (Value lookupSecrets) =
|
|
22
|
+
lookupSecrets secrets
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
maskedLookup : Value value -> value
|
|
26
|
+
maskedLookup (Value lookupSecrets) =
|
|
27
|
+
case lookupSecrets SecretsDict.masked of
|
|
28
|
+
Ok value ->
|
|
29
|
+
value
|
|
30
|
+
|
|
31
|
+
Err _ ->
|
|
32
|
+
-- crash
|
|
33
|
+
maskedLookup (Value lookupSecrets)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
succeed : value -> Value value
|
|
37
|
+
succeed value =
|
|
38
|
+
Value (\_ -> Ok value)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
buildError : String -> SecretsDict -> BuildError
|
|
42
|
+
buildError secretName secretsDict =
|
|
43
|
+
let
|
|
44
|
+
availableEnvironmentVariables : List String
|
|
45
|
+
availableEnvironmentVariables =
|
|
46
|
+
SecretsDict.available secretsDict
|
|
47
|
+
in
|
|
48
|
+
{ title = "Missing Secret"
|
|
49
|
+
, message =
|
|
50
|
+
[ Terminal.text "I expected to find this Secret in your environment variables but didn't find a match:\n\nSecrets.get \""
|
|
51
|
+
, Terminal.text secretName
|
|
52
|
+
, Terminal.text "\"\n "
|
|
53
|
+
, Terminal.red <| underlineText (secretName |> String.length)
|
|
54
|
+
, Terminal.text "\n\nSo maybe "
|
|
55
|
+
, Terminal.yellow <| secretName
|
|
56
|
+
, Terminal.text " should be "
|
|
57
|
+
, Terminal.green <| (sortMatches secretName availableEnvironmentVariables |> List.head |> Maybe.withDefault "")
|
|
58
|
+
]
|
|
59
|
+
, path = "" -- TODO wire in path here?
|
|
60
|
+
, fatal = True
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
underlineText : Int -> String
|
|
65
|
+
underlineText length =
|
|
66
|
+
String.repeat length "^"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
sortMatches : String -> List String -> List String
|
|
70
|
+
sortMatches missingSecret availableSecrets =
|
|
71
|
+
let
|
|
72
|
+
simpleMatch : List Fuzzy.Config -> List String -> String -> String -> Int
|
|
73
|
+
simpleMatch config separators needle hay =
|
|
74
|
+
Fuzzy.match config separators needle hay |> .score
|
|
75
|
+
in
|
|
76
|
+
List.sortBy (simpleMatch [] [] missingSecret) availableSecrets
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
map : (valueA -> valueB) -> Value valueA -> Value valueB
|
|
80
|
+
map mapFunction (Value lookupSecrets) =
|
|
81
|
+
Value
|
|
82
|
+
(\secrets ->
|
|
83
|
+
lookupSecrets secrets
|
|
84
|
+
|> Result.map mapFunction
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
with : String -> Value (String -> value) -> Value value
|
|
89
|
+
with newSecret (Value lookupSecrets) =
|
|
90
|
+
Value <|
|
|
91
|
+
\secrets ->
|
|
92
|
+
case lookupSecrets secrets of
|
|
93
|
+
Ok value ->
|
|
94
|
+
case SecretsDict.get newSecret secrets of
|
|
95
|
+
Just newValue ->
|
|
96
|
+
value newValue |> Ok
|
|
97
|
+
|
|
98
|
+
Nothing ->
|
|
99
|
+
Err [ buildError newSecret secrets ]
|
|
100
|
+
|
|
101
|
+
Err error ->
|
|
102
|
+
case SecretsDict.get newSecret secrets of
|
|
103
|
+
Just _ ->
|
|
104
|
+
Err error
|
|
105
|
+
|
|
106
|
+
Nothing ->
|
|
107
|
+
-- TODO add more errors
|
|
108
|
+
Err
|
|
109
|
+
(buildError newSecret secrets
|
|
110
|
+
:: error
|
|
111
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module SecretsDict exposing (SecretsDict, available, decoder, get, masked, unmasked)
|
|
2
|
+
|
|
3
|
+
import Dict exposing (Dict)
|
|
4
|
+
import Json.Decode as Decode exposing (Decoder)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
available : SecretsDict -> List String
|
|
8
|
+
available secretsDict =
|
|
9
|
+
case secretsDict of
|
|
10
|
+
Masked ->
|
|
11
|
+
[]
|
|
12
|
+
|
|
13
|
+
Unmasked dict ->
|
|
14
|
+
Dict.keys dict
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
decoder : Decoder SecretsDict
|
|
18
|
+
decoder =
|
|
19
|
+
Decode.dict Decode.string
|
|
20
|
+
|> Decode.map Unmasked
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
unmasked : Dict String String -> SecretsDict
|
|
24
|
+
unmasked dict =
|
|
25
|
+
Unmasked dict
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
masked : SecretsDict
|
|
29
|
+
masked =
|
|
30
|
+
Masked
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
get : String -> SecretsDict -> Maybe String
|
|
34
|
+
get secretName secretsDict =
|
|
35
|
+
case secretsDict of
|
|
36
|
+
Masked ->
|
|
37
|
+
Just <| "<" ++ secretName ++ ">"
|
|
38
|
+
|
|
39
|
+
Unmasked dict ->
|
|
40
|
+
dict |> Dict.get secretName
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
type SecretsDict
|
|
44
|
+
= Masked
|
|
45
|
+
| Unmasked (Dict String String)
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
module StructuredData exposing (StructuredData(..), additionalName, article, article_, computerLanguage, elmLang, encode, episode, person, series, softwareSourceCode)
|
|
2
|
+
|
|
3
|
+
import Json.Encode as Encode
|
|
4
|
+
import Pages.Url
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
{-| <https://schema.org/SoftwareSourceCode>
|
|
8
|
+
-}
|
|
9
|
+
softwareSourceCode :
|
|
10
|
+
{ codeRepositoryUrl : String
|
|
11
|
+
, description : String
|
|
12
|
+
, author : String
|
|
13
|
+
, programmingLanguage : Encode.Value
|
|
14
|
+
}
|
|
15
|
+
-> Encode.Value
|
|
16
|
+
softwareSourceCode info =
|
|
17
|
+
Encode.object
|
|
18
|
+
[ ( "@type", Encode.string "SoftwareSourceCode" )
|
|
19
|
+
, ( "codeRepository", Encode.string info.codeRepositoryUrl )
|
|
20
|
+
, ( "description", Encode.string info.description )
|
|
21
|
+
, ( "author", Encode.string info.author )
|
|
22
|
+
, ( "programmingLanguage", info.programmingLanguage )
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
{-| <https://schema.org/ComputerLanguage>
|
|
27
|
+
-}
|
|
28
|
+
computerLanguage : { url : String, name : String, imageUrl : String, identifier : String } -> Encode.Value
|
|
29
|
+
computerLanguage info =
|
|
30
|
+
Encode.object
|
|
31
|
+
[ ( "@type", Encode.string "ComputerLanguage" )
|
|
32
|
+
, ( "url", Encode.string info.url )
|
|
33
|
+
, ( "name", Encode.string info.name )
|
|
34
|
+
, ( "image", Encode.string info.imageUrl )
|
|
35
|
+
, ( "identifier", Encode.string info.identifier )
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
elmLang : Encode.Value
|
|
40
|
+
elmLang =
|
|
41
|
+
computerLanguage
|
|
42
|
+
{ url = "http://elm-lang.org/"
|
|
43
|
+
, name = "Elm"
|
|
44
|
+
, imageUrl = "http://elm-lang.org/"
|
|
45
|
+
, identifier = "http://elm-lang.org/"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
{-| <https://schema.org/Article>
|
|
50
|
+
-}
|
|
51
|
+
article :
|
|
52
|
+
{ title : String
|
|
53
|
+
, description : String
|
|
54
|
+
, author : StructuredData { authorMemberOf | personOrOrganization : () } authorPossibleFields
|
|
55
|
+
, publisher : StructuredData { publisherMemberOf | personOrOrganization : () } publisherPossibleFields
|
|
56
|
+
, url : String
|
|
57
|
+
, imageUrl : Pages.Url.Url
|
|
58
|
+
, datePublished : String
|
|
59
|
+
, mainEntityOfPage : Encode.Value
|
|
60
|
+
}
|
|
61
|
+
-> Encode.Value
|
|
62
|
+
article info =
|
|
63
|
+
Encode.object
|
|
64
|
+
[ ( "@context", Encode.string "http://schema.org/" )
|
|
65
|
+
, ( "@type", Encode.string "Article" )
|
|
66
|
+
, ( "headline", Encode.string info.title )
|
|
67
|
+
, ( "description", Encode.string info.description )
|
|
68
|
+
, ( "image", Encode.string (Pages.Url.toString info.imageUrl) )
|
|
69
|
+
, ( "author", encode info.author )
|
|
70
|
+
, ( "publisher", encode info.publisher )
|
|
71
|
+
, ( "url", Encode.string info.url )
|
|
72
|
+
, ( "datePublished", Encode.string info.datePublished )
|
|
73
|
+
, ( "mainEntityOfPage", info.mainEntityOfPage )
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
type StructuredData memberOf possibleFields
|
|
78
|
+
= StructuredData String (List ( String, Encode.Value ))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
{-| <https://schema.org/Person>
|
|
82
|
+
-}
|
|
83
|
+
person :
|
|
84
|
+
{ name : String
|
|
85
|
+
}
|
|
86
|
+
->
|
|
87
|
+
StructuredData
|
|
88
|
+
{ personOrOrganization : () }
|
|
89
|
+
{ additionalName : ()
|
|
90
|
+
, address : ()
|
|
91
|
+
, affiliation : ()
|
|
92
|
+
}
|
|
93
|
+
person info =
|
|
94
|
+
StructuredData "Person" [ ( "name", Encode.string info.name ) ]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
additionalName : String -> StructuredData memberOf { possibleFields | additionalName : () } -> StructuredData memberOf possibleFields
|
|
98
|
+
additionalName value (StructuredData typeName fields) =
|
|
99
|
+
StructuredData typeName (( "additionalName", Encode.string value ) :: fields)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
{-| <https://schema.org/Article>
|
|
103
|
+
-}
|
|
104
|
+
article_ :
|
|
105
|
+
{ title : String
|
|
106
|
+
, description : String
|
|
107
|
+
, author : String
|
|
108
|
+
, publisher : StructuredData { personOrOrganization : () } possibleFieldsPublisher
|
|
109
|
+
, url : String
|
|
110
|
+
, imageUrl : String
|
|
111
|
+
, datePublished : String
|
|
112
|
+
, mainEntityOfPage : Encode.Value
|
|
113
|
+
}
|
|
114
|
+
-> Encode.Value
|
|
115
|
+
article_ info =
|
|
116
|
+
Encode.object
|
|
117
|
+
[ ( "@context", Encode.string "http://schema.org/" )
|
|
118
|
+
, ( "@type", Encode.string "Article" )
|
|
119
|
+
, ( "headline", Encode.string info.title )
|
|
120
|
+
, ( "description", Encode.string info.description )
|
|
121
|
+
, ( "image", Encode.string info.imageUrl )
|
|
122
|
+
, ( "author", Encode.string info.author )
|
|
123
|
+
, ( "publisher", encode info.publisher )
|
|
124
|
+
, ( "url", Encode.string info.url )
|
|
125
|
+
, ( "datePublished", Encode.string info.datePublished )
|
|
126
|
+
, ( "mainEntityOfPage", info.mainEntityOfPage )
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
encode : StructuredData memberOf possibleFieldsPublisher -> Encode.Value
|
|
131
|
+
encode (StructuredData typeName fields) =
|
|
132
|
+
Encode.object
|
|
133
|
+
(( "@type", Encode.string typeName ) :: fields)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
--example :
|
|
138
|
+
-- StructuredData
|
|
139
|
+
-- { personOrOrganization : () }
|
|
140
|
+
-- { address : ()
|
|
141
|
+
-- , affiliation : ()
|
|
142
|
+
-- }
|
|
143
|
+
--example =
|
|
144
|
+
-- person { name = "Dillon Kearns" }
|
|
145
|
+
-- |> additionalName "Cornelius"
|
|
146
|
+
--organization :
|
|
147
|
+
-- {}
|
|
148
|
+
-- -> StructuredDataHelper { personOrOrganization : () }
|
|
149
|
+
--organization info =
|
|
150
|
+
-- StructuredDataHelper "Organization" []
|
|
151
|
+
--needsPersonOrOrg : StructuredDataHelper {}
|
|
152
|
+
--needsPersonOrOrg =
|
|
153
|
+
-- StructuredDataHelper "" []
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
{-|
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"@context": "http://schema.org/",
|
|
161
|
+
"@type": "PodcastSeries",
|
|
162
|
+
"image": "https://www.relay.fm/inquisitive_artwork.png",
|
|
163
|
+
"url": "http://www.relay.fm/inquisitive",
|
|
164
|
+
"name": "Inquisitive",
|
|
165
|
+
"description": "Inquisitive is a show for the naturally curious. Each week, Myke Hurley takes a look at what makes creative people successful and what steps they have taken to get there.",
|
|
166
|
+
"webFeed": "http://www.relay.fm//inquisitive/feed",
|
|
167
|
+
"author": {
|
|
168
|
+
"@type": "Person",
|
|
169
|
+
"name": "Myke Hurley"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
-}
|
|
176
|
+
series : Encode.Value
|
|
177
|
+
series =
|
|
178
|
+
Encode.object
|
|
179
|
+
[ ( "@context", Encode.string "http://schema.org/" )
|
|
180
|
+
, ( "@type", Encode.string "PodcastSeries" )
|
|
181
|
+
, ( "image", Encode.string "TODO" )
|
|
182
|
+
, ( "url", Encode.string "http://elm-radio.com/episode/getting-started-with-elm-pages" )
|
|
183
|
+
, ( "name", Encode.string "Elm Radio" )
|
|
184
|
+
, ( "description", Encode.string "TODO" )
|
|
185
|
+
, ( "webFeed", Encode.string "https://elm-radio.com/feed.xml" )
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
{-|
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"@context": "http://schema.org/",
|
|
194
|
+
"@type": "PodcastEpisode",
|
|
195
|
+
"url": "http://elm-radio.com/episode/getting-started-with-elm-pages",
|
|
196
|
+
"name": "001: Getting Started with elm-pages",
|
|
197
|
+
"datePublished": "2015-02-18",
|
|
198
|
+
"timeRequired": "PT37M",
|
|
199
|
+
"description": "In the first episode of “Behind the App”, a special series of Inquisitive, we take a look at the beginnings of iOS app development, by focusing on the introduction of the iPhone and the App Store.",
|
|
200
|
+
"associatedMedia": {
|
|
201
|
+
"@type": "MediaObject",
|
|
202
|
+
"contentUrl": "https://cdn.simplecast.com/audio/6a206b/6a206baa-9c8e-4c25-9037-2b674204ba84/ca009f6e-1710-4518-b869-ca34cb0b7d17/001-getting-started-elm-pages_tc.mp3 "
|
|
203
|
+
},
|
|
204
|
+
"partOfSeries": {
|
|
205
|
+
"@type": "PodcastSeries",
|
|
206
|
+
"name": "Elm Radio",
|
|
207
|
+
"url": "https://elm-radio.com"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
-}
|
|
213
|
+
episode : Encode.Value
|
|
214
|
+
episode =
|
|
215
|
+
Encode.object
|
|
216
|
+
[ ( "@context", Encode.string "http://schema.org/" )
|
|
217
|
+
, ( "@type", Encode.string "PodcastEpisode" )
|
|
218
|
+
, ( "url", Encode.string "http://elm-radio.com/episode/getting-started-with-elm-pages" )
|
|
219
|
+
, ( "name", Encode.string "Getting Started with elm-pages" )
|
|
220
|
+
, ( "datePublished", Encode.string "2015-02-18" )
|
|
221
|
+
, ( "timeRequired", Encode.string "PT37M" )
|
|
222
|
+
, ( "description", Encode.string "TODO" )
|
|
223
|
+
, ( "associatedMedia"
|
|
224
|
+
, Encode.object
|
|
225
|
+
[ ( "@type", Encode.string "MediaObject" )
|
|
226
|
+
, ( "contentUrl", Encode.string "https://cdn.simplecast.com/audio/6a206b/6a206baa-9c8e-4c25-9037-2b674204ba84/ca009f6e-1710-4518-b869-ca34cb0b7d17/001-getting-started-elm-pages_tc.mp3" )
|
|
227
|
+
]
|
|
228
|
+
)
|
|
229
|
+
, ( "partOfSeries"
|
|
230
|
+
, Encode.object
|
|
231
|
+
[ ( "@type", Encode.string "PodcastSeries" )
|
|
232
|
+
, ( "name", Encode.string "Elm Radio" )
|
|
233
|
+
, ( "url", Encode.string "https://elm-radio.com" )
|
|
234
|
+
]
|
|
235
|
+
)
|
|
236
|
+
]
|