elm-pages 3.0.0-beta.4 → 3.0.0-beta.41

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.
Files changed (148) hide show
  1. package/README.md +10 -1
  2. package/adapter/netlify.js +207 -0
  3. package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2828 -2933
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  10. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
  11. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1447 -342
  12. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +17004 -13817
  13. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  14. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  15. package/generator/dead-code-review/elm.json +9 -7
  16. package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +59 -10
  17. package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +52 -36
  18. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmi +0 -0
  19. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
  20. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
  21. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
  22. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  23. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  24. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  25. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
  26. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1447 -342
  27. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +25025 -21739
  28. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  29. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  30. package/generator/review/elm.json +10 -10
  31. package/generator/src/RouteBuilder.elm +121 -114
  32. package/generator/src/SharedTemplate.elm +8 -7
  33. package/generator/src/SiteConfig.elm +3 -2
  34. package/generator/src/basepath-middleware.js +3 -3
  35. package/generator/src/build.js +209 -92
  36. package/generator/src/cli.js +292 -88
  37. package/generator/src/codegen.js +29 -27
  38. package/generator/src/compatibility-key.js +3 -0
  39. package/generator/src/compile-elm.js +43 -26
  40. package/generator/src/config.js +39 -0
  41. package/generator/src/copy-dir.js +2 -2
  42. package/generator/src/dev-server.js +176 -138
  43. package/generator/src/dir-helpers.js +9 -26
  44. package/generator/src/elm-codegen.js +5 -4
  45. package/generator/src/elm-file-constants.js +2 -3
  46. package/generator/src/error-formatter.js +12 -11
  47. package/generator/src/file-helpers.js +3 -4
  48. package/generator/src/generate-template-module-connector.js +23 -23
  49. package/generator/src/init.js +9 -8
  50. package/generator/src/pre-render-html.js +39 -28
  51. package/generator/src/render-test.js +109 -0
  52. package/generator/src/render-worker.js +25 -28
  53. package/generator/src/render.js +321 -142
  54. package/generator/src/request-cache.js +265 -162
  55. package/generator/src/resolve-elm-module.js +64 -0
  56. package/generator/src/rewrite-client-elm-json.js +6 -5
  57. package/generator/src/rewrite-elm-json-help.js +56 -0
  58. package/generator/src/rewrite-elm-json.js +17 -7
  59. package/generator/src/route-codegen-helpers.js +16 -31
  60. package/generator/src/seo-renderer.js +12 -7
  61. package/generator/src/vite-utils.js +77 -0
  62. package/generator/static-code/elm-pages.js +10 -0
  63. package/generator/static-code/hmr.js +79 -13
  64. package/generator/template/app/Api.elm +6 -5
  65. package/generator/template/app/Effect.elm +123 -0
  66. package/generator/template/app/ErrorPage.elm +37 -6
  67. package/generator/template/app/Route/Index.elm +17 -10
  68. package/generator/template/app/Shared.elm +24 -47
  69. package/generator/template/app/Site.elm +19 -6
  70. package/generator/template/app/View.elm +1 -8
  71. package/generator/template/elm-tooling.json +0 -3
  72. package/generator/template/elm.json +32 -24
  73. package/generator/template/package.json +10 -4
  74. package/package.json +30 -27
  75. package/src/ApiRoute.elm +199 -61
  76. package/src/BackendTask/Custom.elm +325 -0
  77. package/src/BackendTask/Env.elm +90 -0
  78. package/src/{DataSource → BackendTask}/File.elm +171 -56
  79. package/src/{DataSource → BackendTask}/Glob.elm +136 -125
  80. package/src/BackendTask/Http.elm +679 -0
  81. package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
  82. package/src/BackendTask/Internal/Request.elm +69 -0
  83. package/src/BackendTask/Random.elm +79 -0
  84. package/src/BackendTask/Time.elm +47 -0
  85. package/src/BackendTask.elm +531 -0
  86. package/src/FatalError.elm +90 -0
  87. package/src/Head/Seo.elm +4 -4
  88. package/src/Head.elm +237 -7
  89. package/src/HtmlPrinter.elm +7 -3
  90. package/src/Internal/ApiRoute.elm +7 -5
  91. package/src/PageServerResponse.elm +6 -1
  92. package/src/Pages/ConcurrentSubmission.elm +127 -0
  93. package/src/Pages/Form.elm +340 -0
  94. package/src/Pages/FormData.elm +18 -0
  95. package/src/Pages/GeneratorProgramConfig.elm +15 -0
  96. package/src/Pages/Internal/FatalError.elm +5 -0
  97. package/src/Pages/Internal/Msg.elm +93 -0
  98. package/src/Pages/Internal/NotFoundReason.elm +4 -4
  99. package/src/Pages/Internal/Platform/Cli.elm +617 -768
  100. package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
  101. package/src/Pages/Internal/Platform/Effect.elm +1 -2
  102. package/src/Pages/Internal/Platform/GeneratorApplication.elm +379 -0
  103. package/src/Pages/Internal/Platform/StaticResponses.elm +65 -276
  104. package/src/Pages/Internal/Platform/ToJsPayload.elm +6 -9
  105. package/src/Pages/Internal/Platform.elm +359 -225
  106. package/src/Pages/Internal/ResponseSketch.elm +2 -2
  107. package/src/Pages/Internal/Script.elm +17 -0
  108. package/src/Pages/Internal/StaticHttpBody.elm +35 -1
  109. package/src/Pages/Manifest.elm +52 -11
  110. package/src/Pages/Navigation.elm +87 -0
  111. package/src/Pages/PageUrl.elm +26 -12
  112. package/src/Pages/ProgramConfig.elm +35 -23
  113. package/src/Pages/Script.elm +166 -0
  114. package/src/Pages/SiteConfig.elm +3 -2
  115. package/src/Pages/StaticHttp/Request.elm +2 -2
  116. package/src/Pages/StaticHttpRequest.elm +23 -99
  117. package/src/Pages/Url.elm +3 -3
  118. package/src/PagesMsg.elm +88 -0
  119. package/src/QueryParams.elm +21 -172
  120. package/src/RenderRequest.elm +7 -7
  121. package/src/RequestsAndPending.elm +37 -20
  122. package/src/Result/Extra.elm +26 -0
  123. package/src/Scaffold/Form.elm +569 -0
  124. package/src/Scaffold/Route.elm +1411 -0
  125. package/src/Server/Request.elm +74 -72
  126. package/src/Server/Session.elm +62 -42
  127. package/src/Server/SetCookie.elm +80 -32
  128. package/src/Stub.elm +53 -0
  129. package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
  130. package/src/{Path.elm → UrlPath.elm} +33 -36
  131. package/src/DataSource/Env.elm +0 -38
  132. package/src/DataSource/Http.elm +0 -446
  133. package/src/DataSource/Internal/Request.elm +0 -20
  134. package/src/DataSource/Port.elm +0 -90
  135. package/src/DataSource.elm +0 -538
  136. package/src/Form/Field.elm +0 -717
  137. package/src/Form/FieldStatus.elm +0 -36
  138. package/src/Form/FieldView.elm +0 -417
  139. package/src/Form/FormData.elm +0 -22
  140. package/src/Form/Validation.elm +0 -391
  141. package/src/Form/Value.elm +0 -118
  142. package/src/Form.elm +0 -1683
  143. package/src/FormDecoder.elm +0 -102
  144. package/src/Pages/FormState.elm +0 -256
  145. package/src/Pages/Generate.elm +0 -800
  146. package/src/Pages/Internal/Form.elm +0 -17
  147. package/src/Pages/Msg.elm +0 -79
  148. package/src/Pages/Transition.elm +0 -70
@@ -0,0 +1,531 @@
1
+ module BackendTask exposing
2
+ ( BackendTask
3
+ , map, succeed, fail
4
+ , fromResult
5
+ , andThen, resolve, combine
6
+ , andMap
7
+ , map2, map3, map4, map5, map6, map7, map8, map9
8
+ , allowFatal, mapError, onError, toResult
9
+ )
10
+
11
+ {-| In an `elm-pages` app, each Route Module can define a value `data` which is a `BackendTask` that will be resolved **before** `init` is called. That means it is also available
12
+ when the page's HTML is pre-rendered during the build step. You can also access the resolved data in `head` to use it for the page's SEO meta tags.
13
+
14
+ A `BackendTask` lets you pull in data from:
15
+
16
+ - Local files ([`BackendTask.File`](BackendTask-File))
17
+ - HTTP requests ([`BackendTask.Http`](BackendTask-Http))
18
+ - Globs, i.e. listing out local files based on a pattern like `content/*.txt` ([`BackendTask.Glob`](BackendTask-Glob))
19
+ - Ports, i.e. getting JSON data from running custom NodeJS, similar to a port in a vanilla Elm app except run at build-time in NodeJS, rather than at run-time in the browser ([`BackendTask.Custom`](BackendTask-Custom))
20
+ - Hardcoded data (`BackendTask.succeed "Hello!"`)
21
+ - Or any combination of the above, using `BackendTask.map2`, `BackendTask.andThen`, or other combining/continuing helpers from this module
22
+
23
+
24
+ ## BackendTask's vs. Effect's/Cmd's
25
+
26
+ BackendTask's are always resolved before the page is rendered and sent to the browser. A BackendTask is never executed
27
+ in the Browser. Instead, the resolved data from the BackendTask is passed down to the Browser - it has been resolved
28
+ before any client-side JavaScript ever executes. In the case of a pre-rendered route, this is during the CLI build phase,
29
+ and for server-rendered routes its BackendTask is resolved on the server.
30
+
31
+ Effect's/Cmd's are never executed on the CLI or server, they are only executed in the Browser. The data from a Route Module's
32
+ `init` function is used to render the initial HTML on the server or build step, but the Effect isn't executed and `update` is never called
33
+ before the page is hydrated in the Browser. This gives a deterministic mental model of what the first render will look like,
34
+ and a nicely typed way to define the initial `Data` you have to render your initial view.
35
+
36
+ Because `elm-pages` hydrates into a full Elm single-page app, it does need the data in order to initialize the Elm app.
37
+ So why not just get the data the old-fashioned way, with `elm/http`, for example?
38
+
39
+ A few reasons:
40
+
41
+ 1. BackendTask's allow you to pull in data that you wouldn't normally be able to access from an Elm app, like local files, or listings of files in a folder. Not only that, but the dev server knows to automatically hot reload the data when the files it depends on change, so you can edit the files you used in your BackendTask and see the page hot reload as you save!
42
+ 2. You can pre-render HTML for your pages, including the SEO meta tags, with all that rich, well-typed Elm data available! That's something you can't accomplish with a vanilla Elm app, and it's one of the main use cases for elm-pages.
43
+ 3. Because `elm-pages` has a build step, you know that your `BackendTask.Http` requests succeeded, your decoders succeeded, your custom BackendTask validations succeeded, and everything went smoothly. If something went wrong, you get a build failure and can deal with the issues before the site goes live. That means your users won't see those errors, and as a developer you don't need to handle those error cases in your code! Think of it as "parse, don't validate", but for your entire build. In the case of server-rendered routes, a BackendTask failure will render a 500 page, so more care needs to be taken to make sure all common errors are handled properly, but the tradeoff is that you can use BackendTask's to pull in highly dynamic data and even render user-specific pages.
44
+ 4. For static routes, you don't have to worry about an API being down, or hitting it repeatedly. You can build in data and it will end up as optimized binary-encoded data served up with all the other assets of your site. If your CDN (static site host) is down, then the rest of your site is probably down anyway. If your site host is up, then so is all of your `BackendTask` data. Also, it will be served up extremely quickly without needing to wait for any database queries to be performed, `andThen` requests to be resolved, etc., because all of that work and waiting was done at build-time!
45
+
46
+
47
+ ## Mental Model
48
+
49
+ You can think of a BackendTask as a declarative (not imperative) definition of data. It represents where to get the data from, and how to transform it (map, combine with other BackendTasks, etc.).
50
+
51
+
52
+ ## How do I actually use a BackendTask?
53
+
54
+ This is very similar to Cmd's in Elm. You don't perform a Cmd just by running that code, as you might in a language like JavaScript. Instead, a Cmd _will not do anything_ unless you pass it to The Elm Architecture to have it perform it for you.
55
+ You pass a Cmd to The Elm Architecture by returning it in `init` or `update`. So actually a `Cmd` is just data describing a side-effect that the Elm runtime can perform, and how to build a `Msg` once it's done.
56
+
57
+ `BackendTask`'s are very similar. A `BackendTask` doesn't do anything just by "running" it. Just like a `Cmd`, it's only data that describes a side-effect to perform. Specifically, it describes a side-effect that the _elm-pages runtime_ can perform.
58
+ There are a few places where we can pass a `BackendTask` to the `elm-pages` runtime so it can perform it. Most commonly, you give a field called `data` in your Route Module's definition. Instead of giving a `Msg` when the side-effects are complete,
59
+ the page will render once all of the side-effects have run and all the data is resolved. `elm-pages` makes the resolved data available your Route Module's `init`, `view`, `update`, and `head` functions, similar to how a regular Elm app passes `Msg`'s in
60
+ to `update`.
61
+
62
+ Any place in your `elm-pages` app where the framework lets you pass in a value of type `BackendTask` is a place where you can give `elm-pages` a BackendTask to perform (for example, `Site.head` where you define global head tags for your site).
63
+
64
+
65
+ ## Basics
66
+
67
+ @docs BackendTask
68
+
69
+ @docs map, succeed, fail
70
+
71
+ @docs fromResult
72
+
73
+
74
+ ## Chaining Requests
75
+
76
+ @docs andThen, resolve, combine
77
+
78
+ @docs andMap
79
+
80
+ @docs map2, map3, map4, map5, map6, map7, map8, map9
81
+
82
+
83
+ ## FatalError Handling
84
+
85
+ @docs allowFatal, mapError, onError, toResult
86
+
87
+ -}
88
+
89
+ import FatalError exposing (FatalError)
90
+ import Json.Encode
91
+ import Pages.StaticHttpRequest exposing (RawRequest(..))
92
+
93
+
94
+ {-| A BackendTask represents data that will be gathered at build time. Multiple `BackendTask`s can be combined together using the `mapN` functions,
95
+ very similar to how you can manipulate values with Json Decoders in Elm.
96
+ -}
97
+ type alias BackendTask error value =
98
+ RawRequest error value
99
+
100
+
101
+ {-| Transform a request into an arbitrary value. The same underlying task will be performed,
102
+ but mapping allows you to change the resulting values by applying functions to the results.
103
+
104
+ import BackendTask
105
+ import BackendTask.Http
106
+ import Json.Decode as Decode exposing (Decoder)
107
+
108
+ starsMessage =
109
+ BackendTask.Http.getJson
110
+ "https://api.github.com/repos/dillonkearns/elm-pages"
111
+ (Decode.field "stargazers_count" Decode.int)
112
+ |> BackendTask.map
113
+ (\stars -> "⭐️ " ++ String.fromInt stars)
114
+
115
+ -}
116
+ map : (a -> b) -> BackendTask error a -> BackendTask error b
117
+ map fn requestInfo =
118
+ case requestInfo of
119
+ ApiRoute value ->
120
+ ApiRoute (Result.map fn value)
121
+
122
+ Request urls lookupFn ->
123
+ Request
124
+ urls
125
+ (mapLookupFn fn lookupFn)
126
+
127
+
128
+ mapLookupFn : (a -> b) -> (d -> c -> BackendTask error a) -> d -> c -> BackendTask error b
129
+ mapLookupFn fn lookupFn maybeMock requests =
130
+ map fn (lookupFn maybeMock requests)
131
+
132
+
133
+ {-| Helper to remove an inner layer of Request wrapping.
134
+ -}
135
+ resolve : BackendTask error (List (BackendTask error value)) -> BackendTask error (List value)
136
+ resolve =
137
+ andThen combine
138
+
139
+
140
+ {-| Turn a list of `BackendTask`s into a single one.
141
+
142
+ import BackendTask
143
+ import Json.Decode as Decode exposing (Decoder)
144
+
145
+ type alias Pokemon =
146
+ { name : String
147
+ , sprite : String
148
+ }
149
+
150
+ pokemonDetailRequest : BackendTask (List Pokemon)
151
+ pokemonDetailRequest =
152
+ BackendTask.Http.getJson
153
+ "https://pokeapi.co/api/v2/pokemon/?limit=3"
154
+ (Decode.field "results"
155
+ (Decode.list
156
+ (Decode.map2 Tuple.pair
157
+ (Decode.field "name" Decode.string)
158
+ (Decode.field "url" Decode.string)
159
+ |> Decode.map
160
+ (\( name, url ) ->
161
+ BackendTask.Http.getJson url
162
+ (Decode.at
163
+ [ "sprites", "front_default" ]
164
+ Decode.string
165
+ |> Decode.map (Pokemon name)
166
+ )
167
+ )
168
+ )
169
+ )
170
+ )
171
+ |> BackendTask.andThen BackendTask.combine
172
+
173
+ -}
174
+ combine : List (BackendTask error value) -> BackendTask error (List value)
175
+ combine items =
176
+ List.foldl (map2 (::)) (succeed []) items |> map List.reverse
177
+
178
+
179
+ {-| Like map, but it takes in two `Request`s.
180
+
181
+ view siteMetadata page =
182
+ StaticHttp.map2
183
+ (\elmPagesStars elmMarkdownStars ->
184
+ { view =
185
+ \model viewForPage ->
186
+ { title = "Repo Stargazers"
187
+ , body = starsView elmPagesStars elmMarkdownStars
188
+ }
189
+ , head = head elmPagesStars elmMarkdownStars
190
+ }
191
+ )
192
+ (get
193
+ (Secrets.succeed "https://api.github.com/repos/dillonkearns/elm-pages")
194
+ (Decode.field "stargazers_count" Decode.int)
195
+ )
196
+ (get
197
+ (Secrets.succeed "https://api.github.com/repos/dillonkearns/elm-markdown")
198
+ (Decode.field "stargazers_count" Decode.int)
199
+ )
200
+
201
+ -}
202
+ map2 : (a -> b -> c) -> BackendTask error a -> BackendTask error b -> BackendTask error c
203
+ map2 fn request1 request2 =
204
+ -- elm-review: known-unoptimized-recursion
205
+ -- TODO try to find a way to optimize tail-call recursion here
206
+ case ( request1, request2 ) of
207
+ ( ApiRoute value1, ApiRoute value2 ) ->
208
+ ApiRoute (Result.map2 fn value1 value2)
209
+
210
+ ( Request urls1 lookupFn1, Request urls2 lookupFn2 ) ->
211
+ Request
212
+ (urls1 ++ urls2)
213
+ (\resolver responses ->
214
+ map2 fn
215
+ (lookupFn1 resolver responses)
216
+ (lookupFn2 resolver responses)
217
+ )
218
+
219
+ ( Request urls1 lookupFn1, ApiRoute value2 ) ->
220
+ Request
221
+ urls1
222
+ (\resolver responses ->
223
+ map2 fn
224
+ (lookupFn1 resolver responses)
225
+ (ApiRoute value2)
226
+ )
227
+
228
+ ( ApiRoute value2, Request urls1 lookupFn1 ) ->
229
+ Request
230
+ urls1
231
+ (\resolver responses ->
232
+ map2 fn
233
+ (ApiRoute value2)
234
+ (lookupFn1 resolver responses)
235
+ )
236
+
237
+
238
+ {-| Build off of the response from a previous `BackendTask` request to build a follow-up request. You can use the data
239
+ from the previous response to build up the URL, headers, etc. that you send to the subsequent request.
240
+
241
+ import BackendTask
242
+ import Json.Decode as Decode exposing (Decoder)
243
+
244
+ licenseData : BackendTask String
245
+ licenseData =
246
+ BackendTask.Http.get
247
+ (Secrets.succeed "https://api.github.com/repos/dillonkearns/elm-pages")
248
+ (Decode.at [ "license", "url" ] Decode.string)
249
+ |> BackendTask.andThen
250
+ (\licenseUrl ->
251
+ BackendTask.Http.get (Secrets.succeed licenseUrl) (Decode.field "description" Decode.string)
252
+ )
253
+
254
+ -}
255
+ andThen : (a -> BackendTask error b) -> BackendTask error a -> BackendTask error b
256
+ andThen fn requestInfo =
257
+ -- elm-review: known-unoptimized-recursion
258
+ -- TODO try to find a way to optimize recursion here
259
+ case requestInfo of
260
+ ApiRoute a ->
261
+ case a of
262
+ Ok okA ->
263
+ fn okA
264
+
265
+ Err errA ->
266
+ fail errA
267
+
268
+ Request urls lookupFn ->
269
+ if List.isEmpty urls then
270
+ andThen fn (lookupFn Nothing (Json.Encode.object []))
271
+
272
+ else
273
+ Request urls
274
+ (\maybeMockResolver responses ->
275
+ lookupFn maybeMockResolver responses
276
+ |> andThen fn
277
+ )
278
+
279
+
280
+ {-| -}
281
+ onError : (error -> BackendTask mappedError value) -> BackendTask error value -> BackendTask mappedError value
282
+ onError fromError backendTask =
283
+ -- elm-review: known-unoptimized-recursion
284
+ case backendTask of
285
+ ApiRoute a ->
286
+ case a of
287
+ Ok okA ->
288
+ succeed okA
289
+
290
+ Err errA ->
291
+ fromError errA
292
+
293
+ Request urls lookupFn ->
294
+ if List.isEmpty urls then
295
+ onError fromError (lookupFn Nothing (Json.Encode.object []))
296
+
297
+ else
298
+ Request urls
299
+ (\maybeMockResolver responses ->
300
+ lookupFn maybeMockResolver responses
301
+ |> onError fromError
302
+ )
303
+
304
+
305
+ {-| A helper for combining `BackendTask`s in pipelines.
306
+ -}
307
+ andMap : BackendTask error a -> BackendTask error (a -> b) -> BackendTask error b
308
+ andMap =
309
+ map2 (|>)
310
+
311
+
312
+ {-| This is useful for prototyping with some hardcoded data, or for having a view that doesn't have any StaticHttp data.
313
+
314
+ import BackendTask
315
+
316
+ view :
317
+ List ( PagePath, Metadata )
318
+ ->
319
+ { path : PagePath
320
+ , frontmatter : Metadata
321
+ }
322
+ ->
323
+ StaticHttp.Request
324
+ { view : Model -> View -> { title : String, body : Html Msg }
325
+ , head : List (Head.Tag Pages.PathKey)
326
+ }
327
+ view siteMetadata page =
328
+ StaticHttp.succeed
329
+ { view =
330
+ \model viewForPage ->
331
+ mainView model viewForPage
332
+ , head = head page.frontmatter
333
+ }
334
+
335
+ -}
336
+ succeed : a -> BackendTask error a
337
+ succeed value =
338
+ ApiRoute (Ok value)
339
+
340
+
341
+ {-| -}
342
+ fail : error -> BackendTask error a
343
+ fail error =
344
+ ApiRoute (Err error)
345
+
346
+
347
+ {-| Turn `Ok` into `BackendTask.succeed` and `Err` into `BackendTask.fail`.
348
+ -}
349
+ fromResult : Result error value -> BackendTask error value
350
+ fromResult result =
351
+ case result of
352
+ Ok okValue ->
353
+ succeed okValue
354
+
355
+ Err error ->
356
+ fail error
357
+
358
+
359
+ {-| -}
360
+ mapError : (error -> errorMapped) -> BackendTask error value -> BackendTask errorMapped value
361
+ mapError mapFn requestInfo =
362
+ case requestInfo of
363
+ ApiRoute value ->
364
+ ApiRoute (Result.mapError mapFn value)
365
+
366
+ Request urls lookupFn ->
367
+ Request
368
+ urls
369
+ (mapLookupFnError mapFn lookupFn)
370
+
371
+
372
+ mapLookupFnError : (error -> errorMapped) -> (d -> c -> BackendTask error a) -> d -> c -> BackendTask errorMapped a
373
+ mapLookupFnError fn lookupFn maybeMock requests =
374
+ mapError fn (lookupFn maybeMock requests)
375
+
376
+
377
+ {-| -}
378
+ map3 :
379
+ (value1 -> value2 -> value3 -> valueCombined)
380
+ -> BackendTask error value1
381
+ -> BackendTask error value2
382
+ -> BackendTask error value3
383
+ -> BackendTask error valueCombined
384
+ map3 combineFn request1 request2 request3 =
385
+ succeed combineFn
386
+ |> map2 (|>) request1
387
+ |> map2 (|>) request2
388
+ |> map2 (|>) request3
389
+
390
+
391
+ {-| -}
392
+ map4 :
393
+ (value1 -> value2 -> value3 -> value4 -> valueCombined)
394
+ -> BackendTask error value1
395
+ -> BackendTask error value2
396
+ -> BackendTask error value3
397
+ -> BackendTask error value4
398
+ -> BackendTask error valueCombined
399
+ map4 combineFn request1 request2 request3 request4 =
400
+ succeed combineFn
401
+ |> map2 (|>) request1
402
+ |> map2 (|>) request2
403
+ |> map2 (|>) request3
404
+ |> map2 (|>) request4
405
+
406
+
407
+ {-| -}
408
+ map5 :
409
+ (value1 -> value2 -> value3 -> value4 -> value5 -> valueCombined)
410
+ -> BackendTask error value1
411
+ -> BackendTask error value2
412
+ -> BackendTask error value3
413
+ -> BackendTask error value4
414
+ -> BackendTask error value5
415
+ -> BackendTask error valueCombined
416
+ map5 combineFn request1 request2 request3 request4 request5 =
417
+ succeed combineFn
418
+ |> map2 (|>) request1
419
+ |> map2 (|>) request2
420
+ |> map2 (|>) request3
421
+ |> map2 (|>) request4
422
+ |> map2 (|>) request5
423
+
424
+
425
+ {-| -}
426
+ map6 :
427
+ (value1 -> value2 -> value3 -> value4 -> value5 -> value6 -> valueCombined)
428
+ -> BackendTask error value1
429
+ -> BackendTask error value2
430
+ -> BackendTask error value3
431
+ -> BackendTask error value4
432
+ -> BackendTask error value5
433
+ -> BackendTask error value6
434
+ -> BackendTask error valueCombined
435
+ map6 combineFn request1 request2 request3 request4 request5 request6 =
436
+ succeed combineFn
437
+ |> map2 (|>) request1
438
+ |> map2 (|>) request2
439
+ |> map2 (|>) request3
440
+ |> map2 (|>) request4
441
+ |> map2 (|>) request5
442
+ |> map2 (|>) request6
443
+
444
+
445
+ {-| -}
446
+ map7 :
447
+ (value1 -> value2 -> value3 -> value4 -> value5 -> value6 -> value7 -> valueCombined)
448
+ -> BackendTask error value1
449
+ -> BackendTask error value2
450
+ -> BackendTask error value3
451
+ -> BackendTask error value4
452
+ -> BackendTask error value5
453
+ -> BackendTask error value6
454
+ -> BackendTask error value7
455
+ -> BackendTask error valueCombined
456
+ map7 combineFn request1 request2 request3 request4 request5 request6 request7 =
457
+ succeed combineFn
458
+ |> map2 (|>) request1
459
+ |> map2 (|>) request2
460
+ |> map2 (|>) request3
461
+ |> map2 (|>) request4
462
+ |> map2 (|>) request5
463
+ |> map2 (|>) request6
464
+ |> map2 (|>) request7
465
+
466
+
467
+ {-| -}
468
+ map8 :
469
+ (value1 -> value2 -> value3 -> value4 -> value5 -> value6 -> value7 -> value8 -> valueCombined)
470
+ -> BackendTask error value1
471
+ -> BackendTask error value2
472
+ -> BackendTask error value3
473
+ -> BackendTask error value4
474
+ -> BackendTask error value5
475
+ -> BackendTask error value6
476
+ -> BackendTask error value7
477
+ -> BackendTask error value8
478
+ -> BackendTask error valueCombined
479
+ map8 combineFn request1 request2 request3 request4 request5 request6 request7 request8 =
480
+ succeed combineFn
481
+ |> map2 (|>) request1
482
+ |> map2 (|>) request2
483
+ |> map2 (|>) request3
484
+ |> map2 (|>) request4
485
+ |> map2 (|>) request5
486
+ |> map2 (|>) request6
487
+ |> map2 (|>) request7
488
+ |> map2 (|>) request8
489
+
490
+
491
+ {-| -}
492
+ map9 :
493
+ (value1 -> value2 -> value3 -> value4 -> value5 -> value6 -> value7 -> value8 -> value9 -> valueCombined)
494
+ -> BackendTask error value1
495
+ -> BackendTask error value2
496
+ -> BackendTask error value3
497
+ -> BackendTask error value4
498
+ -> BackendTask error value5
499
+ -> BackendTask error value6
500
+ -> BackendTask error value7
501
+ -> BackendTask error value8
502
+ -> BackendTask error value9
503
+ -> BackendTask error valueCombined
504
+ map9 combineFn request1 request2 request3 request4 request5 request6 request7 request8 request9 =
505
+ succeed combineFn
506
+ |> map2 (|>) request1
507
+ |> map2 (|>) request2
508
+ |> map2 (|>) request3
509
+ |> map2 (|>) request4
510
+ |> map2 (|>) request5
511
+ |> map2 (|>) request6
512
+ |> map2 (|>) request7
513
+ |> map2 (|>) request8
514
+ |> map2 (|>) request9
515
+
516
+
517
+ {-| Ignore any recoverable error data and propagate the `FatalError`. Similar to a `Cmd` in The Elm Architecture,
518
+ a `FatalError` will not do anything except if it is returned at the top-level of your application. Read more
519
+ in the [`FatalError` docs](FatalError).
520
+ -}
521
+ allowFatal : BackendTask { error | fatal : FatalError } data -> BackendTask FatalError data
522
+ allowFatal backendTask =
523
+ mapError .fatal backendTask
524
+
525
+
526
+ {-| -}
527
+ toResult : BackendTask error data -> BackendTask noError (Result error data)
528
+ toResult backendTask =
529
+ backendTask
530
+ |> andThen (Ok >> succeed)
531
+ |> onError (Err >> succeed)
@@ -0,0 +1,90 @@
1
+ module FatalError exposing (FatalError, build, fromString, recoverable)
2
+
3
+ {-| The Elm language doesn't have the concept of exceptions or special control flow for errors. It just has
4
+ Custom Types, and by convention types like `Result` and the `Err` variant are used to represent possible failure states
5
+ and combine together different error states.
6
+
7
+ `elm-pages` doesn't change that, Elm still doesn't have special exception control flow at the language level. It does have
8
+ a type, which is just a regular old Elm type, called `FatalError`. Why? Because this plain old Elm type does have one
9
+ special characteristic - the `elm-pages` framework knows how to turn it into an error message. This becomes interesting
10
+ because an `elm-pages` app has several places that accept a value of type `BackendTask FatalError.FatalError value`.
11
+ This design lets the `elm-pages` framework do some of the work for you.
12
+
13
+ For example, if you wanted to handle possible errors to present them to the user
14
+
15
+ type alias Data =
16
+ String
17
+
18
+ data : RouteParams -> BackendTask FatalError Data
19
+ data routeParams =
20
+ BackendTask.Http.getJson "https://api.github.com/repos/dillonkearns/elm-pages"
21
+ (Decode.field "description" Decode.string)
22
+ |> BackendTask.onError
23
+ (\error ->
24
+ case FatalError.unwrap error of
25
+ BackendTask.Http.BadStatus metadata string ->
26
+ if metadata.statusCode == 401 || metadata.statusCode == 403 || metadata.statusCode == 404 then
27
+ BackendTask.succeed "Either this repo doesn't exist or you don't have access to it."
28
+
29
+ else
30
+ -- we're only handling these expected error cases. In the case of an HTTP timeout,
31
+ -- we'll let the error propagate as a FatalError
32
+ BackendTask.fail error |> BackendTask.allowFatal
33
+
34
+ _ ->
35
+ BackendTask.fail error |> BackendTask.allowFatal
36
+ )
37
+
38
+ This can be a lot of work for all possible errors, though. If you don't expect this kind of error (it's an _exceptional_ case),
39
+ you can let the framework handle it if the error ever does unexpectedly occur.
40
+
41
+ data : RouteParams -> BackendTask FatalError Data
42
+ data routeParams =
43
+ BackendTask.Http.getJson "https://api.github.com/repos/dillonkearns/elm-pages"
44
+ (Decode.field "description" Decode.string)
45
+ |> BackendTask.allowFatal
46
+
47
+ This is especially useful for pages generated at build-time (`RouteBuilder.preRender`) where you want the build
48
+ to fail if anything unexpected happens. With pre-rendered routes, you know that these error cases won't
49
+ be seen by users, so it's often a great idea to just let the framework handle these unexpected errors so a developer can
50
+ debug them and see what went wrong. In the example above, maybe we are only pre-rendering pages for a set of known
51
+ GitHub Repositories, so a Not Found or Unauthorized HTTP error would be unexpected and should stop the build so we can fix the
52
+ issue.
53
+
54
+ In the case of server-rendered Routes (`RouteBuilder.serverRender`), `elm-pages` will show your 500 error page
55
+ when these errors occur.
56
+
57
+ @docs FatalError, build, fromString, recoverable
58
+
59
+ -}
60
+
61
+ import Pages.Internal.FatalError
62
+
63
+
64
+ {-| -}
65
+ type alias FatalError =
66
+ Pages.Internal.FatalError.FatalError
67
+
68
+
69
+ {-| Create a FatalError with a title and body.
70
+ -}
71
+ build : { title : String, body : String } -> FatalError
72
+ build info =
73
+ Pages.Internal.FatalError.FatalError info
74
+
75
+
76
+ {-| -}
77
+ fromString : String -> FatalError
78
+ fromString string =
79
+ build
80
+ { title = "Custom Error"
81
+ , body = string
82
+ }
83
+
84
+
85
+ {-| -}
86
+ recoverable : { title : String, body : String } -> error -> { fatal : FatalError, recoverable : error }
87
+ recoverable info value =
88
+ { fatal = build info
89
+ , recoverable = value
90
+ }
package/src/Head/Seo.elm CHANGED
@@ -1,13 +1,13 @@
1
1
  module Head.Seo exposing (Common, Image, article, audioPlayer, book, profile, song, summary, summaryLarge, videoPlayer, website)
2
2
 
3
- {-| <https://ogp.me/#>
4
- <https://developers.facebook.com/docs/sharing/opengraph>
3
+ {-| <https://developers.facebook.com/docs/sharing/opengraph>
5
4
 
6
5
  This module encapsulates some of the best practices for SEO for your site.
7
6
 
8
- `elm-pages` will pre-render each of the static pages (in your `content` directory) so that
7
+ `elm-pages` pre-renders the HTML for your pages (either at build-time or server-render time) so that
9
8
  web crawlers can efficiently and accurately process it. The functions in this module are for use
10
- with the `head` function that you pass to your Pages config (`Pages.application`).
9
+ with the `head` function in your `Route` modules to help you build up a set of `<meta>` tags that
10
+ includes common meta tags used for rich link previews, namely [OpenGraph tags](https://ogp.me/) and [Twitter card tags](https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards).
11
11
 
12
12
  import Date
13
13
  import Head