elm-pages 3.0.0-beta.10 → 3.0.0-beta.12
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/README.md +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15156 -13244
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/dead-code-review/elm.json +6 -5
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +1 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14574 -12631
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/review/elm.json +6 -6
- package/generator/src/build.js +6 -9
- package/generator/src/cli.js +120 -42
- package/generator/src/codegen.js +11 -10
- package/generator/src/compatibility-key.js +1 -1
- package/generator/src/elm-codegen.js +3 -0
- package/generator/src/render-worker.js +1 -1
- package/generator/src/render.js +222 -37
- package/generator/src/request-cache.js +1 -0
- package/generator/src/rewrite-elm-json.js +3 -3
- package/package.json +12 -12
- package/src/ApiRoute.elm +147 -9
- package/src/DataSource/Env.elm +27 -3
- package/src/DataSource.elm +11 -22
- package/src/Form.elm +32 -32
- package/src/Head.elm +112 -8
- package/src/MultiDict.elm +49 -0
- package/src/Pages/Generate.elm +4 -1
- package/src/Pages/GeneratorProgramConfig.elm +15 -0
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +455 -0
- package/src/Pages/Manifest.elm +24 -0
- package/src/Pages/Script.elm +100 -0
- package/src/PairingHeap.elm +137 -0
- package/src/Parser/Extra/String.elm +33 -0
- package/src/Parser/Extra.elm +69 -0
- package/src/ProgramTest/ComplexQuery.elm +360 -0
- package/src/ProgramTest/EffectSimulation.elm +122 -0
- package/src/ProgramTest/Failure.elm +367 -0
- package/src/ProgramTest/HtmlHighlighter.elm +116 -0
- package/src/ProgramTest/HtmlParserHacks.elm +58 -0
- package/src/ProgramTest/HtmlRenderer.elm +73 -0
- package/src/ProgramTest/Program.elm +30 -0
- package/src/ProgramTest/StringLines.elm +26 -0
- package/src/ProgramTest/TestHtmlHacks.elm +132 -0
- package/src/ProgramTest/TestHtmlParser.elm +201 -0
- package/src/ProgramTest.elm +2339 -0
- package/src/Query/Extra.elm +55 -0
- package/src/Result/Extra.elm +21 -0
- package/src/Server/Request.elm +2 -2
- package/src/SimulatedEffect/Cmd.elm +69 -0
- package/src/SimulatedEffect/Http.elm +330 -0
- package/src/SimulatedEffect/Navigation.elm +69 -0
- package/src/SimulatedEffect/Ports.elm +62 -0
- package/src/SimulatedEffect/Process.elm +24 -0
- package/src/SimulatedEffect/Sub.elm +48 -0
- package/src/SimulatedEffect/Task.elm +252 -0
- package/src/SimulatedEffect/Time.elm +25 -0
- package/src/SimulatedEffect.elm +42 -0
- package/src/String/Extra.elm +6 -0
- package/src/Test/Http.elm +145 -0
- package/src/TestResult.elm +35 -0
- package/src/TestState.elm +305 -0
- package/src/Url/Extra.elm +100 -0
- package/src/Vendored/Diff.elm +321 -0
- package/src/Vendored/Failure.elm +217 -0
- package/src/Vendored/FormatMonochrome.elm +44 -0
- package/src/Vendored/Highlightable.elm +53 -0
package/src/Head.elm
CHANGED
|
@@ -9,14 +9,118 @@ module Head exposing
|
|
|
9
9
|
, toJson, canonicalLink
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
{-| This module contains
|
|
13
|
-
|
|
14
|
-
when
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
{-| This module contains functions for building up
|
|
13
|
+
tags with metadata that will be rendered into the page's `<head>` tag
|
|
14
|
+
when your page is pre-rendered (or server-rendered, in the case of your server-rendered Route Modules). See also [`Head.Seo`](Head-Seo),
|
|
15
|
+
which has some helper functions for defining OpenGraph and Twitter tags.
|
|
16
|
+
|
|
17
|
+
One of the unique benefits of using `elm-pages` is that all of your routes (both pre-rendered and server-rendered) fully
|
|
18
|
+
render the HTML of your page. That includes the full initial `view` (with the DataSource resolved, and the `Model` from `init`).
|
|
19
|
+
The HTML response also includes all of the `Head` tags, which are defined in two places:
|
|
20
|
+
|
|
21
|
+
1. `app/Site.elm` - there is a `head` definition in `Site.elm` where you define global head tags that will be included on every rendered page.
|
|
22
|
+
|
|
23
|
+
2. In each Route Module - there is a `head` function where you have access to both the resolved `DataSource` and the `RouteParams` for the page and can return head tags based on that.
|
|
24
|
+
|
|
25
|
+
Here is a common set of global head tags that we can define in `Site.elm`:
|
|
26
|
+
|
|
27
|
+
module Site exposing (canonicalUrl, config)
|
|
28
|
+
|
|
29
|
+
import DataSource exposing (DataSource)
|
|
30
|
+
import Head
|
|
31
|
+
import MimeType
|
|
32
|
+
import SiteConfig exposing (SiteConfig)
|
|
33
|
+
|
|
34
|
+
config : SiteConfig
|
|
35
|
+
config =
|
|
36
|
+
{ canonicalUrl = "<https://elm-pages.com">
|
|
37
|
+
, head = head
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
head : DataSource (List Head.Tag)
|
|
41
|
+
head =
|
|
42
|
+
[ Head.metaName "viewport" (Head.raw "width=device-width,initial-scale=1")
|
|
43
|
+
, Head.metaName "mobile-web-app-capable" (Head.raw "yes")
|
|
44
|
+
, Head.metaName "theme-color" (Head.raw "#ffffff")
|
|
45
|
+
, Head.metaName "apple-mobile-web-app-capable" (Head.raw "yes")
|
|
46
|
+
, Head.metaName "apple-mobile-web-app-status-bar-style" (Head.raw "black-translucent")
|
|
47
|
+
, Head.icon [ ( 32, 32 ) ] MimeType.Png (cloudinaryIcon MimeType.Png 32)
|
|
48
|
+
, Head.icon [ ( 16, 16 ) ] MimeType.Png (cloudinaryIcon MimeType.Png 16)
|
|
49
|
+
, Head.appleTouchIcon (Just 180) (cloudinaryIcon MimeType.Png 180)
|
|
50
|
+
, Head.appleTouchIcon (Just 192) (cloudinaryIcon MimeType.Png 192)
|
|
51
|
+
]
|
|
52
|
+
|> DataSource.succeed
|
|
53
|
+
|
|
54
|
+
And here is a `head` function for a Route Module for a blog post. Note that we have access to our `DataSource` Data and
|
|
55
|
+
are using it to populate article metadata like the article's image, publish date, etc.
|
|
56
|
+
|
|
57
|
+
import Article
|
|
58
|
+
import DataSource
|
|
59
|
+
import Date
|
|
60
|
+
import Head
|
|
61
|
+
import Head.Seo
|
|
62
|
+
import Path
|
|
63
|
+
import Route exposing (Route)
|
|
64
|
+
import RouteBuilder exposing (StatelessRoute, StaticPayload)
|
|
65
|
+
|
|
66
|
+
type alias RouteParams =
|
|
67
|
+
{ slug : String }
|
|
68
|
+
|
|
69
|
+
type alias Data =
|
|
70
|
+
{ metadata : ArticleMetadata
|
|
71
|
+
, body : List Markdown.Block.Block
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
route : StatelessRoute RouteParams Data ActionData
|
|
75
|
+
route =
|
|
76
|
+
RouteBuilder.preRender
|
|
77
|
+
{ data = data
|
|
78
|
+
, head = head
|
|
79
|
+
, pages = pages
|
|
80
|
+
}
|
|
81
|
+
|> RouteBuilder.buildNoState { view = view }
|
|
82
|
+
|
|
83
|
+
head :
|
|
84
|
+
StaticPayload Data ActionData RouteParams
|
|
85
|
+
-> List Head.Tag
|
|
86
|
+
head static =
|
|
87
|
+
let
|
|
88
|
+
metadata =
|
|
89
|
+
static.data.metadata
|
|
90
|
+
in
|
|
91
|
+
Head.Seo.summaryLarge
|
|
92
|
+
{ canonicalUrlOverride = Nothing
|
|
93
|
+
, siteName = "elm-pages"
|
|
94
|
+
, image =
|
|
95
|
+
{ url = metadata.image
|
|
96
|
+
, alt = metadata.description
|
|
97
|
+
, dimensions = Nothing
|
|
98
|
+
, mimeType = Nothing
|
|
99
|
+
}
|
|
100
|
+
, description = metadata.description
|
|
101
|
+
, locale = Nothing
|
|
102
|
+
, title = metadata.title
|
|
103
|
+
}
|
|
104
|
+
|> Head.Seo.article
|
|
105
|
+
{ tags = []
|
|
106
|
+
, section = Nothing
|
|
107
|
+
, publishedTime = Just (DateOrDateTime.Date metadata.published)
|
|
108
|
+
, modifiedTime = Nothing
|
|
109
|
+
, expirationTime = Nothing
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
## Why is pre-rendered HTML important? Does it still matter for SEO?
|
|
114
|
+
|
|
115
|
+
Many search engines are able to execute JavaScript now. However, not all are, and even with crawlers like Google, there
|
|
116
|
+
is a longer lead time for your pages to be indexed when you have HTML with a blank page that is only visible after the JavaScript executes.
|
|
117
|
+
|
|
118
|
+
But most importantly, many tools that unfurl links will not execute JavaScript at all, but rather simply do a simple pass to parse your `<head>` tags.
|
|
119
|
+
It is not viable or reliable to add `<head>` tags for metadata on the client-side, it must be present in the initial HTML payload. Otherwise you may not
|
|
120
|
+
get unfurling preview content when you share a link to your site on Slack, Twitter, etc.
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
## Building up Head Tags
|
|
20
124
|
|
|
21
125
|
@docs Tag, metaName, metaProperty, metaRedirect
|
|
22
126
|
@docs rssLink, sitemapLink, rootLanguage, manifestLink
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module MultiDict exposing (MultiDict, empty, get, insert, keys, remove, set)
|
|
2
|
+
|
|
3
|
+
import Dict exposing (Dict)
|
|
4
|
+
import List.Extra
|
|
5
|
+
import List.Nonempty as NonEmpty
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
type alias NonEmpty a =
|
|
9
|
+
NonEmpty.Nonempty a
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
type MultiDict k v
|
|
13
|
+
= MultiDict (Dict k (NonEmpty v))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
empty : MultiDict k v
|
|
17
|
+
empty =
|
|
18
|
+
MultiDict Dict.empty
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
insert : comparable -> v -> MultiDict comparable v -> MultiDict comparable v
|
|
22
|
+
insert key value (MultiDict dict) =
|
|
23
|
+
MultiDict
|
|
24
|
+
(Dict.update key (Maybe.map (NonEmpty.cons value) >> Maybe.withDefault (NonEmpty.fromElement value) >> Just) dict)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
get : comparable -> MultiDict comparable v -> List v
|
|
28
|
+
get key (MultiDict dict) =
|
|
29
|
+
Dict.get key dict
|
|
30
|
+
|> Maybe.map NonEmpty.toList
|
|
31
|
+
|> Maybe.withDefault []
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
keys : MultiDict k v -> List k
|
|
35
|
+
keys (MultiDict dict) =
|
|
36
|
+
Dict.toList dict
|
|
37
|
+
|> List.concatMap (\( k, vs ) -> List.repeat (NonEmpty.length vs) k)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
remove : comparable -> v -> MultiDict comparable v -> MultiDict comparable v
|
|
41
|
+
remove key value (MultiDict dict) =
|
|
42
|
+
MultiDict
|
|
43
|
+
(Dict.update key (Maybe.andThen (NonEmpty.toList >> List.Extra.remove value >> NonEmpty.fromList)) dict)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
set : comparable -> List v -> MultiDict comparable v -> MultiDict comparable v
|
|
47
|
+
set key values (MultiDict dict) =
|
|
48
|
+
MultiDict
|
|
49
|
+
(Dict.update key (\_ -> NonEmpty.fromList values) dict)
|
package/src/Pages/Generate.elm
CHANGED
|
@@ -5,7 +5,10 @@ module Pages.Generate exposing
|
|
|
5
5
|
, preRender, single
|
|
6
6
|
)
|
|
7
7
|
|
|
8
|
-
{-|
|
|
8
|
+
{-| This module provides some functions for scaffolding code for a new Route Module. It uses [`elm-codegen`'s API](https://package.elm-lang.org/packages/mdgriffith/elm-codegen/latest/) for generating code.
|
|
9
|
+
|
|
10
|
+
Typically you'll want to use this via the `elm-pages codegen` CLI command. The default starter template includes a file that uses these functions, which you can tweak to customize your scaffolding commands.
|
|
11
|
+
Learn more about [the `elm-pages run` CLI command in its docs page](https://elm-pages.com/docs/run-command).
|
|
9
12
|
|
|
10
13
|
|
|
11
14
|
## Initializing the Generator Builder
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Pages.GeneratorProgramConfig exposing (GeneratorProgramConfig)
|
|
2
|
+
|
|
3
|
+
import Json.Decode as Decode
|
|
4
|
+
import Json.Encode
|
|
5
|
+
import Pages.Internal.Platform.ToJsPayload
|
|
6
|
+
import Pages.Script exposing (Script)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
type alias GeneratorProgramConfig =
|
|
10
|
+
{ data : Script
|
|
11
|
+
, toJsPort : Json.Encode.Value -> Cmd Never
|
|
12
|
+
, fromJsPort : Sub Decode.Value
|
|
13
|
+
, gotBatchSub : Sub Decode.Value
|
|
14
|
+
, sendPageData : Pages.Internal.Platform.ToJsPayload.NewThingForPort -> Cmd Never
|
|
15
|
+
}
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
module Pages.Internal.Platform.GeneratorApplication exposing (Flags, Model, Msg(..), init, requestDecoder, update, app)
|
|
2
|
+
|
|
3
|
+
{-| Exposed for internal use only (used in generated code).
|
|
4
|
+
|
|
5
|
+
@docs Flags, Model, Msg, init, requestDecoder, update, app
|
|
6
|
+
|
|
7
|
+
-}
|
|
8
|
+
|
|
9
|
+
import BuildError exposing (BuildError)
|
|
10
|
+
import Cli.Program as Program exposing (FlagsIncludingArgv)
|
|
11
|
+
import Codec
|
|
12
|
+
import DataSource exposing (DataSource)
|
|
13
|
+
import Dict
|
|
14
|
+
import HtmlPrinter
|
|
15
|
+
import Json.Decode as Decode
|
|
16
|
+
import Json.Encode
|
|
17
|
+
import Pages.GeneratorProgramConfig exposing (GeneratorProgramConfig)
|
|
18
|
+
import Pages.Internal.Platform.CompatibilityKey
|
|
19
|
+
import Pages.Internal.Platform.Effect as Effect exposing (Effect)
|
|
20
|
+
import Pages.Internal.Platform.StaticResponses as StaticResponses exposing (StaticResponses)
|
|
21
|
+
import Pages.Internal.Platform.ToJsPayload as ToJsPayload
|
|
22
|
+
import Pages.Script exposing (Script(..))
|
|
23
|
+
import Pages.StaticHttp.Request
|
|
24
|
+
import Pages.StaticHttpRequest as StaticHttpRequest
|
|
25
|
+
import RequestsAndPending exposing (RequestsAndPending)
|
|
26
|
+
import TerminalText as Terminal
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
{-| -}
|
|
30
|
+
type alias Flags =
|
|
31
|
+
{ compatibilityKey : Int
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
{-| -}
|
|
36
|
+
type alias Model =
|
|
37
|
+
{ staticResponses : StaticResponses
|
|
38
|
+
, errors : List BuildError
|
|
39
|
+
, allRawResponses : RequestsAndPending
|
|
40
|
+
, done : Bool
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
{-| -}
|
|
45
|
+
type Msg
|
|
46
|
+
= GotDataBatch
|
|
47
|
+
(List
|
|
48
|
+
{ request : Pages.StaticHttp.Request.Request
|
|
49
|
+
, response : RequestsAndPending.Response
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
| GotBuildError BuildError
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
{-| -}
|
|
56
|
+
app :
|
|
57
|
+
GeneratorProgramConfig
|
|
58
|
+
-> Program.StatefulProgram Model Msg (DataSource ()) Flags
|
|
59
|
+
app config =
|
|
60
|
+
let
|
|
61
|
+
cliConfig : Program.Config (DataSource ())
|
|
62
|
+
cliConfig =
|
|
63
|
+
case config.data of
|
|
64
|
+
Generator theCliConfig ->
|
|
65
|
+
theCliConfig HtmlPrinter.htmlToString
|
|
66
|
+
in
|
|
67
|
+
Program.stateful
|
|
68
|
+
{ init =
|
|
69
|
+
\flags cliOptions ->
|
|
70
|
+
init cliOptions flags
|
|
71
|
+
|> Tuple.mapSecond (perform config)
|
|
72
|
+
, update =
|
|
73
|
+
\cliOptions msg model ->
|
|
74
|
+
update cliOptions msg model
|
|
75
|
+
|> Tuple.mapSecond (perform config)
|
|
76
|
+
, subscriptions =
|
|
77
|
+
\_ ->
|
|
78
|
+
Sub.batch
|
|
79
|
+
[ config.fromJsPort
|
|
80
|
+
|> Sub.map
|
|
81
|
+
(\jsonValue ->
|
|
82
|
+
let
|
|
83
|
+
decoder : Decode.Decoder Msg
|
|
84
|
+
decoder =
|
|
85
|
+
Decode.field "tag" Decode.string
|
|
86
|
+
|> Decode.andThen
|
|
87
|
+
(\tag ->
|
|
88
|
+
case tag of
|
|
89
|
+
"BuildError" ->
|
|
90
|
+
Decode.field "data"
|
|
91
|
+
(Decode.map2
|
|
92
|
+
(\message title ->
|
|
93
|
+
{ title = title
|
|
94
|
+
, message = message
|
|
95
|
+
, fatal = True
|
|
96
|
+
, path = "" -- TODO wire in current path here
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
(Decode.field "message" Decode.string |> Decode.map Terminal.fromAnsiString)
|
|
100
|
+
(Decode.field "title" Decode.string)
|
|
101
|
+
)
|
|
102
|
+
|> Decode.map GotBuildError
|
|
103
|
+
|
|
104
|
+
_ ->
|
|
105
|
+
Decode.fail "Unhandled msg"
|
|
106
|
+
)
|
|
107
|
+
in
|
|
108
|
+
Decode.decodeValue decoder jsonValue
|
|
109
|
+
|> Result.mapError
|
|
110
|
+
(\error ->
|
|
111
|
+
("From location 1: "
|
|
112
|
+
++ (error
|
|
113
|
+
|> Decode.errorToString
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
|> BuildError.internal
|
|
117
|
+
|> GotBuildError
|
|
118
|
+
)
|
|
119
|
+
|> mergeResult
|
|
120
|
+
)
|
|
121
|
+
, config.gotBatchSub
|
|
122
|
+
|> Sub.map
|
|
123
|
+
(\newBatch ->
|
|
124
|
+
Decode.decodeValue batchDecoder newBatch
|
|
125
|
+
|> Result.map GotDataBatch
|
|
126
|
+
|> Result.mapError
|
|
127
|
+
(\error ->
|
|
128
|
+
("From location 2: "
|
|
129
|
+
++ (error
|
|
130
|
+
|> Decode.errorToString
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
|> BuildError.internal
|
|
134
|
+
|> GotBuildError
|
|
135
|
+
)
|
|
136
|
+
|> mergeResult
|
|
137
|
+
)
|
|
138
|
+
]
|
|
139
|
+
, config = cliConfig
|
|
140
|
+
, printAndExitFailure =
|
|
141
|
+
\string ->
|
|
142
|
+
ToJsPayload.Errors
|
|
143
|
+
[ { title = "Invalid CLI arguments"
|
|
144
|
+
, path = ""
|
|
145
|
+
, message =
|
|
146
|
+
[ Terminal.text string
|
|
147
|
+
]
|
|
148
|
+
, fatal = True
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
|> Codec.encodeToValue (ToJsPayload.successCodecNew2 "" "")
|
|
152
|
+
|> config.toJsPort
|
|
153
|
+
|> Cmd.map never
|
|
154
|
+
, printAndExitSuccess = \string -> config.toJsPort (Json.Encode.string string) |> Cmd.map never
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
batchDecoder : Decode.Decoder (List { request : Pages.StaticHttp.Request.Request, response : RequestsAndPending.Response })
|
|
159
|
+
batchDecoder =
|
|
160
|
+
Decode.map2 (\request response -> { request = request, response = response })
|
|
161
|
+
(Decode.field "request" requestDecoder)
|
|
162
|
+
(Decode.field "response" RequestsAndPending.decoder)
|
|
163
|
+
|> Decode.list
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
mergeResult : Result a a -> a
|
|
167
|
+
mergeResult r =
|
|
168
|
+
case r of
|
|
169
|
+
Ok rr ->
|
|
170
|
+
rr
|
|
171
|
+
|
|
172
|
+
Err rr ->
|
|
173
|
+
rr
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
{-| -}
|
|
177
|
+
requestDecoder : Decode.Decoder Pages.StaticHttp.Request.Request
|
|
178
|
+
requestDecoder =
|
|
179
|
+
Pages.StaticHttp.Request.codec
|
|
180
|
+
|> Codec.decoder
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
flatten : GeneratorProgramConfig -> List Effect -> Cmd Msg
|
|
184
|
+
flatten config list =
|
|
185
|
+
Cmd.batch (flattenHelp [] config list)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
flattenHelp : List (Cmd Msg) -> GeneratorProgramConfig -> List Effect -> List (Cmd Msg)
|
|
189
|
+
flattenHelp soFar config list =
|
|
190
|
+
case list of
|
|
191
|
+
first :: rest ->
|
|
192
|
+
flattenHelp
|
|
193
|
+
(perform config first :: soFar)
|
|
194
|
+
config
|
|
195
|
+
rest
|
|
196
|
+
|
|
197
|
+
[] ->
|
|
198
|
+
soFar
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
perform :
|
|
202
|
+
GeneratorProgramConfig
|
|
203
|
+
-> Effect
|
|
204
|
+
-> Cmd Msg
|
|
205
|
+
perform config effect =
|
|
206
|
+
let
|
|
207
|
+
canonicalSiteUrl : String
|
|
208
|
+
canonicalSiteUrl =
|
|
209
|
+
""
|
|
210
|
+
in
|
|
211
|
+
case effect of
|
|
212
|
+
Effect.NoEffect ->
|
|
213
|
+
Cmd.none
|
|
214
|
+
|
|
215
|
+
Effect.Batch list ->
|
|
216
|
+
flatten config list
|
|
217
|
+
|
|
218
|
+
Effect.FetchHttp unmasked ->
|
|
219
|
+
ToJsPayload.DoHttp unmasked unmasked.useCache
|
|
220
|
+
|> Codec.encoder (ToJsPayload.successCodecNew2 canonicalSiteUrl "")
|
|
221
|
+
|> config.toJsPort
|
|
222
|
+
|> Cmd.map never
|
|
223
|
+
|
|
224
|
+
Effect.SendSinglePage info ->
|
|
225
|
+
let
|
|
226
|
+
currentPagePath : String
|
|
227
|
+
currentPagePath =
|
|
228
|
+
case info of
|
|
229
|
+
ToJsPayload.PageProgress toJsSuccessPayloadNew ->
|
|
230
|
+
toJsSuccessPayloadNew.route
|
|
231
|
+
|
|
232
|
+
_ ->
|
|
233
|
+
""
|
|
234
|
+
in
|
|
235
|
+
info
|
|
236
|
+
|> Codec.encoder (ToJsPayload.successCodecNew2 canonicalSiteUrl currentPagePath)
|
|
237
|
+
|> config.toJsPort
|
|
238
|
+
|> Cmd.map never
|
|
239
|
+
|
|
240
|
+
Effect.SendSinglePageNew rawBytes info ->
|
|
241
|
+
let
|
|
242
|
+
currentPagePath : String
|
|
243
|
+
currentPagePath =
|
|
244
|
+
case info of
|
|
245
|
+
ToJsPayload.PageProgress toJsSuccessPayloadNew ->
|
|
246
|
+
toJsSuccessPayloadNew.route
|
|
247
|
+
|
|
248
|
+
_ ->
|
|
249
|
+
""
|
|
250
|
+
in
|
|
251
|
+
{ oldThing =
|
|
252
|
+
info
|
|
253
|
+
|> Codec.encoder (ToJsPayload.successCodecNew2 canonicalSiteUrl currentPagePath)
|
|
254
|
+
, binaryPageData = rawBytes
|
|
255
|
+
}
|
|
256
|
+
|> config.sendPageData
|
|
257
|
+
|> Cmd.map never
|
|
258
|
+
|
|
259
|
+
Effect.Continue ->
|
|
260
|
+
Cmd.none
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
-- TODO use Json.Decode.Value for flagsDecoder instead of hardcoded record flags
|
|
265
|
+
--flagsDecoder :
|
|
266
|
+
-- Decode.Decoder
|
|
267
|
+
-- { staticHttpCache : RequestsAndPending
|
|
268
|
+
-- , compatibilityKey : Int
|
|
269
|
+
-- }
|
|
270
|
+
--flagsDecoder =
|
|
271
|
+
-- Decode.map3
|
|
272
|
+
-- (\staticHttpCache compatibilityKey ->
|
|
273
|
+
-- { staticHttpCache = staticHttpCache
|
|
274
|
+
-- , isDevServer = isDevServer
|
|
275
|
+
-- , compatibilityKey = compatibilityKey
|
|
276
|
+
-- }
|
|
277
|
+
-- )
|
|
278
|
+
-- (Decode.succeed Dict.empty)
|
|
279
|
+
-- (Decode.field "compatibilityKey" Decode.int)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
{-| -}
|
|
283
|
+
init :
|
|
284
|
+
DataSource ()
|
|
285
|
+
-> FlagsIncludingArgv Flags
|
|
286
|
+
-> ( Model, Effect )
|
|
287
|
+
init execute flags =
|
|
288
|
+
if flags.compatibilityKey == Pages.Internal.Platform.CompatibilityKey.currentCompatibilityKey then
|
|
289
|
+
initLegacy execute { staticHttpCache = Dict.empty }
|
|
290
|
+
|
|
291
|
+
else
|
|
292
|
+
let
|
|
293
|
+
elmPackageAheadOfNpmPackage : Bool
|
|
294
|
+
elmPackageAheadOfNpmPackage =
|
|
295
|
+
Pages.Internal.Platform.CompatibilityKey.currentCompatibilityKey > flags.compatibilityKey
|
|
296
|
+
|
|
297
|
+
message : String
|
|
298
|
+
message =
|
|
299
|
+
"The NPM package and Elm package you have installed are incompatible. If you are updating versions, be sure to update both the elm-pages Elm and NPM package.\n\n"
|
|
300
|
+
++ (if elmPackageAheadOfNpmPackage then
|
|
301
|
+
"The elm-pages Elm package is ahead of the elm-pages NPM package. Try updating the elm-pages NPM package?"
|
|
302
|
+
|
|
303
|
+
else
|
|
304
|
+
"The elm-pages NPM package is ahead of the elm-pages Elm package. Try updating the elm-pages Elm package?"
|
|
305
|
+
)
|
|
306
|
+
in
|
|
307
|
+
updateAndSendPortIfDone execute
|
|
308
|
+
{ staticResponses = StaticResponses.empty
|
|
309
|
+
, errors =
|
|
310
|
+
[ { title = "Incompatible NPM and Elm package versions"
|
|
311
|
+
, message = [ Terminal.text <| message ]
|
|
312
|
+
, fatal = True
|
|
313
|
+
, path = ""
|
|
314
|
+
}
|
|
315
|
+
]
|
|
316
|
+
, allRawResponses = Dict.empty
|
|
317
|
+
, done = False
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
initLegacy :
|
|
322
|
+
DataSource ()
|
|
323
|
+
-> { staticHttpCache : RequestsAndPending }
|
|
324
|
+
-> ( Model, Effect )
|
|
325
|
+
initLegacy execute { staticHttpCache } =
|
|
326
|
+
let
|
|
327
|
+
staticResponses : StaticResponses
|
|
328
|
+
staticResponses =
|
|
329
|
+
StaticResponses.renderApiRequest execute
|
|
330
|
+
|
|
331
|
+
initialModel : Model
|
|
332
|
+
initialModel =
|
|
333
|
+
{ staticResponses = staticResponses
|
|
334
|
+
, errors = []
|
|
335
|
+
, allRawResponses = staticHttpCache
|
|
336
|
+
, done = False
|
|
337
|
+
}
|
|
338
|
+
in
|
|
339
|
+
StaticResponses.nextStep initialModel Nothing
|
|
340
|
+
|> nextStepToEffect execute
|
|
341
|
+
initialModel
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
updateAndSendPortIfDone :
|
|
345
|
+
DataSource ()
|
|
346
|
+
-> Model
|
|
347
|
+
-> ( Model, Effect )
|
|
348
|
+
updateAndSendPortIfDone execute model =
|
|
349
|
+
StaticResponses.nextStep
|
|
350
|
+
model
|
|
351
|
+
Nothing
|
|
352
|
+
|> nextStepToEffect execute model
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
{-| -}
|
|
356
|
+
update :
|
|
357
|
+
DataSource ()
|
|
358
|
+
-> Msg
|
|
359
|
+
-> Model
|
|
360
|
+
-> ( Model, Effect )
|
|
361
|
+
update execute msg model =
|
|
362
|
+
case msg of
|
|
363
|
+
GotDataBatch batch ->
|
|
364
|
+
let
|
|
365
|
+
updatedModel : Model
|
|
366
|
+
updatedModel =
|
|
367
|
+
model
|
|
368
|
+
|> StaticResponses.batchUpdate batch
|
|
369
|
+
in
|
|
370
|
+
StaticResponses.nextStep
|
|
371
|
+
updatedModel
|
|
372
|
+
Nothing
|
|
373
|
+
|> nextStepToEffect execute updatedModel
|
|
374
|
+
|
|
375
|
+
GotBuildError buildError ->
|
|
376
|
+
let
|
|
377
|
+
updatedModel : Model
|
|
378
|
+
updatedModel =
|
|
379
|
+
{ model
|
|
380
|
+
| errors =
|
|
381
|
+
buildError :: model.errors
|
|
382
|
+
}
|
|
383
|
+
in
|
|
384
|
+
StaticResponses.nextStep
|
|
385
|
+
updatedModel
|
|
386
|
+
Nothing
|
|
387
|
+
|> nextStepToEffect execute updatedModel
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
nextStepToEffect :
|
|
391
|
+
DataSource ()
|
|
392
|
+
-> Model
|
|
393
|
+
-> ( StaticResponses, StaticResponses.NextStep route )
|
|
394
|
+
-> ( Model, Effect )
|
|
395
|
+
nextStepToEffect execute model ( updatedStaticResponsesModel, nextStep ) =
|
|
396
|
+
case nextStep of
|
|
397
|
+
StaticResponses.Continue updatedAllRawResponses httpRequests _ ->
|
|
398
|
+
let
|
|
399
|
+
updatedModel : Model
|
|
400
|
+
updatedModel =
|
|
401
|
+
{ model
|
|
402
|
+
| allRawResponses = updatedAllRawResponses
|
|
403
|
+
, staticResponses = updatedStaticResponsesModel
|
|
404
|
+
}
|
|
405
|
+
in
|
|
406
|
+
if List.isEmpty httpRequests then
|
|
407
|
+
nextStepToEffect execute
|
|
408
|
+
updatedModel
|
|
409
|
+
(StaticResponses.nextStep
|
|
410
|
+
updatedModel
|
|
411
|
+
Nothing
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
else
|
|
415
|
+
( updatedModel
|
|
416
|
+
, (httpRequests
|
|
417
|
+
|> List.map Effect.FetchHttp
|
|
418
|
+
)
|
|
419
|
+
|> Effect.Batch
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
StaticResponses.Finish toJsPayload ->
|
|
423
|
+
case toJsPayload of
|
|
424
|
+
StaticResponses.ApiResponse ->
|
|
425
|
+
let
|
|
426
|
+
apiResponse : Effect
|
|
427
|
+
apiResponse =
|
|
428
|
+
StaticHttpRequest.resolve
|
|
429
|
+
execute
|
|
430
|
+
model.allRawResponses
|
|
431
|
+
|> Result.mapError (StaticHttpRequest.toBuildError "TODO - path from request")
|
|
432
|
+
|> (\response ->
|
|
433
|
+
case response of
|
|
434
|
+
Ok () ->
|
|
435
|
+
{ body = Json.Encode.null
|
|
436
|
+
, staticHttpCache = Dict.empty
|
|
437
|
+
, statusCode = 200
|
|
438
|
+
}
|
|
439
|
+
|> ToJsPayload.SendApiResponse
|
|
440
|
+
|> Effect.SendSinglePage
|
|
441
|
+
|
|
442
|
+
Err error ->
|
|
443
|
+
[ error ]
|
|
444
|
+
|> ToJsPayload.Errors
|
|
445
|
+
|> Effect.SendSinglePage
|
|
446
|
+
)
|
|
447
|
+
in
|
|
448
|
+
( model
|
|
449
|
+
, apiResponse
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
StaticResponses.Errors errors ->
|
|
453
|
+
( model
|
|
454
|
+
, errors |> ToJsPayload.Errors |> Effect.SendSinglePage
|
|
455
|
+
)
|