elm-pages 3.0.0-beta.15 → 3.0.0-beta.16
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/codegen/elm-pages-codegen.js +66 -115
- 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/Pages-Review-DeadCodeEliminateDataTest.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/js/Runner.elm.js +20 -20
- 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/src/Pages/Review/DeadCodeEliminateData.elm +5 -5
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +21 -21
- 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/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/src/RouteBuilder.elm +23 -23
- package/generator/src/SharedTemplate.elm +2 -2
- package/generator/src/SiteConfig.elm +2 -2
- package/generator/src/cli.js +2 -2
- package/generator/src/compatibility-key.js +1 -1
- package/generator/src/render.js +5 -5
- package/package.json +1 -1
- package/src/ApiRoute.elm +13 -13
- package/src/BackendTask/Env.elm +9 -8
- package/src/BackendTask/File.elm +49 -10
- package/src/BackendTask/Glob.elm +6 -6
- package/src/BackendTask/Http.elm +12 -12
- package/src/BackendTask/Port.elm +22 -14
- package/src/BackendTask.elm +8 -22
- package/src/{Exception.elm → FatalError.elm} +37 -31
- package/src/Form.elm +3 -3
- package/src/Internal/ApiRoute.elm +5 -5
- package/src/Pages/Generate.elm +1 -1
- package/src/Pages/Internal/FatalError.elm +5 -0
- package/src/Pages/Internal/Platform/Cli.elm +4 -4
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +7 -7
- package/src/Pages/Internal/Platform/StaticResponses.elm +10 -9
- package/src/Pages/Internal/Script.elm +2 -2
- package/src/Pages/Manifest.elm +2 -2
- package/src/Pages/ProgramConfig.elm +7 -7
- package/src/Pages/Script.elm +4 -4
- package/src/Pages/SiteConfig.elm +2 -2
- package/src/Server/Request.elm +3 -3
package/src/BackendTask/File.elm
CHANGED
|
@@ -51,7 +51,7 @@ plain old JSON in Elm.
|
|
|
51
51
|
import BackendTask exposing (BackendTask)
|
|
52
52
|
import BackendTask.Http
|
|
53
53
|
import BackendTask.Internal.Request
|
|
54
|
-
import
|
|
54
|
+
import FatalError exposing (FatalError)
|
|
55
55
|
import Json.Decode as Decode exposing (Decoder)
|
|
56
56
|
import TerminalText
|
|
57
57
|
|
|
@@ -141,7 +141,15 @@ It's common to parse the body with a markdown parser or other format.
|
|
|
141
141
|
)
|
|
142
142
|
|
|
143
143
|
-}
|
|
144
|
-
bodyWithFrontmatter :
|
|
144
|
+
bodyWithFrontmatter :
|
|
145
|
+
(String -> Decoder frontmatter)
|
|
146
|
+
-> String
|
|
147
|
+
->
|
|
148
|
+
BackendTask
|
|
149
|
+
{ fatal : FatalError
|
|
150
|
+
, recoverable : FileReadError Decode.Error
|
|
151
|
+
}
|
|
152
|
+
frontmatter
|
|
145
153
|
bodyWithFrontmatter frontmatterDecoder filePath =
|
|
146
154
|
read filePath
|
|
147
155
|
(body
|
|
@@ -213,7 +221,15 @@ the [`BackendTask`](BackendTask) API along with [`BackendTask.Glob`](BackendTask
|
|
|
213
221
|
|> BackendTask.resolve
|
|
214
222
|
|
|
215
223
|
-}
|
|
216
|
-
onlyFrontmatter :
|
|
224
|
+
onlyFrontmatter :
|
|
225
|
+
Decoder frontmatter
|
|
226
|
+
-> String
|
|
227
|
+
->
|
|
228
|
+
BackendTask
|
|
229
|
+
{ fatal : FatalError
|
|
230
|
+
, recoverable : FileReadError Decode.Error
|
|
231
|
+
}
|
|
232
|
+
frontmatter
|
|
217
233
|
onlyFrontmatter frontmatterDecoder filePath =
|
|
218
234
|
read filePath
|
|
219
235
|
(frontmatter frontmatterDecoder)
|
|
@@ -240,7 +256,14 @@ Hey there! This is my first post :)
|
|
|
240
256
|
Then data will yield the value `"Hey there! This is my first post :)"`.
|
|
241
257
|
|
|
242
258
|
-}
|
|
243
|
-
bodyWithoutFrontmatter :
|
|
259
|
+
bodyWithoutFrontmatter :
|
|
260
|
+
String
|
|
261
|
+
->
|
|
262
|
+
BackendTask
|
|
263
|
+
{ fatal : FatalError
|
|
264
|
+
, recoverable : FileReadError decoderError
|
|
265
|
+
}
|
|
266
|
+
String
|
|
244
267
|
bodyWithoutFrontmatter filePath =
|
|
245
268
|
read filePath
|
|
246
269
|
body
|
|
@@ -264,7 +287,7 @@ You could read a file called `hello.txt` in your root project directory like thi
|
|
|
264
287
|
File.rawFile "hello.txt"
|
|
265
288
|
|
|
266
289
|
-}
|
|
267
|
-
rawFile : String -> BackendTask
|
|
290
|
+
rawFile : String -> BackendTask { fatal : FatalError, recoverable : FileReadError decoderError } String
|
|
268
291
|
rawFile filePath =
|
|
269
292
|
read filePath (Decode.field "rawFile" Decode.string)
|
|
270
293
|
|
|
@@ -286,7 +309,15 @@ The Decode will strip off any unused JSON data.
|
|
|
286
309
|
"elm.json"
|
|
287
310
|
|
|
288
311
|
-}
|
|
289
|
-
jsonFile :
|
|
312
|
+
jsonFile :
|
|
313
|
+
Decoder a
|
|
314
|
+
-> String
|
|
315
|
+
->
|
|
316
|
+
BackendTask
|
|
317
|
+
{ fatal : FatalError
|
|
318
|
+
, recoverable : FileReadError Decode.Error
|
|
319
|
+
}
|
|
320
|
+
a
|
|
290
321
|
jsonFile jsonFileDecoder filePath =
|
|
291
322
|
rawFile filePath
|
|
292
323
|
|> BackendTask.andThen
|
|
@@ -295,13 +326,14 @@ jsonFile jsonFileDecoder filePath =
|
|
|
295
326
|
|> Decode.decodeString jsonFileDecoder
|
|
296
327
|
|> Result.mapError
|
|
297
328
|
(\jsonDecodeError ->
|
|
298
|
-
|
|
329
|
+
FatalError.recoverable
|
|
299
330
|
{ title = "JSON Decoding Error"
|
|
300
331
|
, body =
|
|
301
332
|
[ TerminalText.text (Decode.errorToString jsonDecodeError)
|
|
302
333
|
]
|
|
303
334
|
|> TerminalText.toString
|
|
304
335
|
}
|
|
336
|
+
(DecodingError jsonDecodeError)
|
|
305
337
|
)
|
|
306
338
|
|> BackendTask.fromResult
|
|
307
339
|
)
|
|
@@ -314,7 +346,7 @@ body =
|
|
|
314
346
|
Decode.field "withoutFrontmatter" Decode.string
|
|
315
347
|
|
|
316
348
|
|
|
317
|
-
read : String -> Decoder a -> BackendTask
|
|
349
|
+
read : String -> Decoder a -> BackendTask { fatal : FatalError, recoverable : FileReadError error } a
|
|
318
350
|
read filePath decoder =
|
|
319
351
|
BackendTask.Internal.Request.request
|
|
320
352
|
{ name = "read-file"
|
|
@@ -330,10 +362,16 @@ read filePath decoder =
|
|
|
330
362
|
|> BackendTask.andThen BackendTask.fromResult
|
|
331
363
|
|
|
332
364
|
|
|
333
|
-
errorDecoder :
|
|
365
|
+
errorDecoder :
|
|
366
|
+
String
|
|
367
|
+
->
|
|
368
|
+
Decoder
|
|
369
|
+
{ fatal : FatalError.FatalError
|
|
370
|
+
, recoverable : FileReadError decoding
|
|
371
|
+
}
|
|
334
372
|
errorDecoder filePath =
|
|
335
373
|
Decode.succeed
|
|
336
|
-
(
|
|
374
|
+
(FatalError.recoverable
|
|
337
375
|
{ title = "File Doesn't Exist"
|
|
338
376
|
, body =
|
|
339
377
|
[ TerminalText.text "Couldn't find file at path `"
|
|
@@ -342,4 +380,5 @@ errorDecoder filePath =
|
|
|
342
380
|
]
|
|
343
381
|
|> TerminalText.toString
|
|
344
382
|
}
|
|
383
|
+
FileDoesntExist
|
|
345
384
|
)
|
package/src/BackendTask/Glob.elm
CHANGED
|
@@ -229,7 +229,7 @@ import BackendTask exposing (BackendTask)
|
|
|
229
229
|
import BackendTask.Http
|
|
230
230
|
import BackendTask.Internal.Glob exposing (Glob(..))
|
|
231
231
|
import BackendTask.Internal.Request
|
|
232
|
-
import
|
|
232
|
+
import FatalError exposing (FatalError, Recoverable)
|
|
233
233
|
import Json.Decode as Decode
|
|
234
234
|
import Json.Encode as Encode
|
|
235
235
|
import List.Extra
|
|
@@ -1054,7 +1054,7 @@ so it's ideal to make this kind of assertion rather than having fallback behavio
|
|
|
1054
1054
|
issues (like if we had instead ignored the case where there are two or more matching blog post files).
|
|
1055
1055
|
|
|
1056
1056
|
-}
|
|
1057
|
-
expectUniqueMatch : Glob a -> BackendTask (
|
|
1057
|
+
expectUniqueMatch : Glob a -> BackendTask (Recoverable String) a
|
|
1058
1058
|
expectUniqueMatch glob =
|
|
1059
1059
|
glob
|
|
1060
1060
|
|> toBackendTask
|
|
@@ -1066,14 +1066,14 @@ expectUniqueMatch glob =
|
|
|
1066
1066
|
|
|
1067
1067
|
[] ->
|
|
1068
1068
|
BackendTask.fail <|
|
|
1069
|
-
|
|
1070
|
-
|
|
1069
|
+
FatalError.recoverable
|
|
1070
|
+
{ title = "Non-Unique Glob", body = "No files matched the pattern: " ++ toPatternString glob }
|
|
1071
1071
|
("No files matched the pattern: " ++ toPatternString glob)
|
|
1072
1072
|
|
|
1073
1073
|
_ ->
|
|
1074
1074
|
BackendTask.fail <|
|
|
1075
|
-
|
|
1076
|
-
"
|
|
1075
|
+
FatalError.recoverable
|
|
1076
|
+
{ title = "Non-Unique Glob", body = "Expected a unique match, but more than one file matched." }
|
|
1077
1077
|
"More than one file matched."
|
|
1078
1078
|
)
|
|
1079
1079
|
|
package/src/BackendTask/Http.elm
CHANGED
|
@@ -104,7 +104,7 @@ import Base64
|
|
|
104
104
|
import Bytes exposing (Bytes)
|
|
105
105
|
import Bytes.Decode
|
|
106
106
|
import Dict exposing (Dict)
|
|
107
|
-
import
|
|
107
|
+
import FatalError exposing (FatalError, Recoverable)
|
|
108
108
|
import Json.Decode
|
|
109
109
|
import Json.Encode as Encode
|
|
110
110
|
import Pages.Internal.StaticHttpBody as Body
|
|
@@ -157,10 +157,10 @@ type alias Body =
|
|
|
157
157
|
|
|
158
158
|
import BackendTask
|
|
159
159
|
import BackendTask.Http
|
|
160
|
-
import
|
|
160
|
+
import FatalError exposing (FatalError)
|
|
161
161
|
import Json.Decode as Decode exposing (Decoder)
|
|
162
162
|
|
|
163
|
-
getRequest : BackendTask (
|
|
163
|
+
getRequest : BackendTask (FatalError Error) Int
|
|
164
164
|
getRequest =
|
|
165
165
|
BackendTask.Http.getJson
|
|
166
166
|
"https://api.github.com/repos/dillonkearns/elm-pages"
|
|
@@ -170,7 +170,7 @@ type alias Body =
|
|
|
170
170
|
getJson :
|
|
171
171
|
String
|
|
172
172
|
-> Json.Decode.Decoder a
|
|
173
|
-
-> BackendTask (
|
|
173
|
+
-> BackendTask (Recoverable Error) a
|
|
174
174
|
getJson url decoder =
|
|
175
175
|
getWithOptions
|
|
176
176
|
{ url = url
|
|
@@ -189,9 +189,9 @@ use the more flexible `getWithOptions`.
|
|
|
189
189
|
|
|
190
190
|
import BackendTask
|
|
191
191
|
import BackendTask.Http
|
|
192
|
-
import
|
|
192
|
+
import FatalError exposing (FatalError)
|
|
193
193
|
|
|
194
|
-
getRequest : BackendTask (
|
|
194
|
+
getRequest : BackendTask (FatalError Error) String
|
|
195
195
|
getRequest =
|
|
196
196
|
BackendTask.Http.get
|
|
197
197
|
"https://api.github.com/repos/dillonkearns/elm-pages"
|
|
@@ -201,7 +201,7 @@ use the more flexible `getWithOptions`.
|
|
|
201
201
|
get :
|
|
202
202
|
String
|
|
203
203
|
-> Expect a
|
|
204
|
-
-> BackendTask
|
|
204
|
+
-> BackendTask { fatal : FatalError, recoverable : Error } a
|
|
205
205
|
get url expect =
|
|
206
206
|
getWithOptions
|
|
207
207
|
{ url = url
|
|
@@ -231,7 +231,7 @@ getWithOptions :
|
|
|
231
231
|
, timeoutInMs : Maybe Int
|
|
232
232
|
, cachePath : Maybe String
|
|
233
233
|
}
|
|
234
|
-
-> BackendTask (
|
|
234
|
+
-> BackendTask (Recoverable Error) a
|
|
235
235
|
getWithOptions request__ =
|
|
236
236
|
let
|
|
237
237
|
request_ : HashRequest.Request
|
|
@@ -258,7 +258,7 @@ post :
|
|
|
258
258
|
String
|
|
259
259
|
-> Body
|
|
260
260
|
-> Expect a
|
|
261
|
-
-> BackendTask (
|
|
261
|
+
-> BackendTask (Recoverable Error) a
|
|
262
262
|
post url body expect =
|
|
263
263
|
request
|
|
264
264
|
{ url = url
|
|
@@ -397,7 +397,7 @@ request :
|
|
|
397
397
|
, timeoutInMs : Maybe Int
|
|
398
398
|
}
|
|
399
399
|
-> Expect a
|
|
400
|
-
-> BackendTask (
|
|
400
|
+
-> BackendTask (Recoverable Error) a
|
|
401
401
|
request request__ expect =
|
|
402
402
|
let
|
|
403
403
|
request_ : HashRequest.Request
|
|
@@ -475,7 +475,7 @@ with this as a low-level detail, or you can use functions like [BackendTask.Http
|
|
|
475
475
|
requestRaw :
|
|
476
476
|
HashRequest.Request
|
|
477
477
|
-> Expect a
|
|
478
|
-
-> BackendTask (
|
|
478
|
+
-> BackendTask (Recoverable Error) a
|
|
479
479
|
requestRaw request__ expect =
|
|
480
480
|
let
|
|
481
481
|
request_ : HashRequest.Request
|
|
@@ -573,7 +573,7 @@ requestRaw request__ expect =
|
|
|
573
573
|
|> BackendTask.fromResult
|
|
574
574
|
|> BackendTask.mapError
|
|
575
575
|
(\error ->
|
|
576
|
-
|
|
576
|
+
FatalError.recoverable (errorToString error) error
|
|
577
577
|
)
|
|
578
578
|
)
|
|
579
579
|
|
package/src/BackendTask/Port.elm
CHANGED
|
@@ -14,20 +14,20 @@ A `BackendTask.Port` will call an async JavaScript function with the given name
|
|
|
14
14
|
|
|
15
15
|
@docs get
|
|
16
16
|
|
|
17
|
-
Here is the Elm code and corresponding JavaScript definition for getting an environment variable (or an `
|
|
18
|
-
we're using `BackendTask.
|
|
17
|
+
Here is the Elm code and corresponding JavaScript definition for getting an environment variable (or an `FatalError BackendTask.Port.Error` if it isn't found). In this example,
|
|
18
|
+
we're using `BackendTask.allowFatal` to let the framework treat that as an unexpected exception, but we could also handle the possible failures of the `FatalError` (see [`FatalError`](FatalError)).
|
|
19
19
|
|
|
20
20
|
import BackendTask exposing (BackendTask)
|
|
21
21
|
import BackendTask.Port
|
|
22
22
|
import Json.Encode
|
|
23
23
|
import OptimizedDecoder as Decode
|
|
24
24
|
|
|
25
|
-
data : BackendTask
|
|
25
|
+
data : BackendTask FatalError String
|
|
26
26
|
data =
|
|
27
27
|
BackendTask.Port.get "environmentVariable"
|
|
28
28
|
(Json.Encode.string "EDITOR")
|
|
29
29
|
Decode.string
|
|
30
|
-
|> BackendTask.
|
|
30
|
+
|> BackendTask.allowFatal
|
|
31
31
|
|
|
32
32
|
-- will resolve to "VIM" if you run `EDITOR=vim elm-pages dev`
|
|
33
33
|
|
|
@@ -78,14 +78,18 @@ to handle possible errors, but you can throw a JSON value and handle it in Elm i
|
|
|
78
78
|
import BackendTask
|
|
79
79
|
import BackendTask.Http
|
|
80
80
|
import BackendTask.Internal.Request
|
|
81
|
-
import
|
|
81
|
+
import FatalError exposing (FatalError, Recoverable)
|
|
82
82
|
import Json.Decode as Decode exposing (Decoder)
|
|
83
83
|
import Json.Encode as Encode
|
|
84
84
|
import TerminalText
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
{-| -}
|
|
88
|
-
get :
|
|
88
|
+
get :
|
|
89
|
+
String
|
|
90
|
+
-> Encode.Value
|
|
91
|
+
-> Decoder b
|
|
92
|
+
-> BackendTask.BackendTask { fatal : FatalError, recoverable : Error } b
|
|
89
93
|
get portName input decoder =
|
|
90
94
|
BackendTask.Internal.Request.request
|
|
91
95
|
{ name = "port"
|
|
@@ -101,7 +105,7 @@ get portName input decoder =
|
|
|
101
105
|
|> Decode.andThen
|
|
102
106
|
(\errorKind ->
|
|
103
107
|
if errorKind == "PortNotDefined" then
|
|
104
|
-
|
|
108
|
+
FatalError.recoverable
|
|
105
109
|
{ title = "Port Error"
|
|
106
110
|
, body =
|
|
107
111
|
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I expected to find a port named `"
|
|
@@ -110,6 +114,7 @@ get portName input decoder =
|
|
|
110
114
|
]
|
|
111
115
|
|> TerminalText.toString
|
|
112
116
|
}
|
|
117
|
+
(PortNotDefined { name = portName })
|
|
113
118
|
|> Decode.succeed
|
|
114
119
|
|
|
115
120
|
else if errorKind == "ExportIsNotFunction" then
|
|
@@ -118,7 +123,7 @@ get portName input decoder =
|
|
|
118
123
|
|> Decode.map (Maybe.withDefault "")
|
|
119
124
|
|> Decode.map
|
|
120
125
|
(\incorrectPortType ->
|
|
121
|
-
|
|
126
|
+
FatalError.recoverable
|
|
122
127
|
{ title = "Port Error"
|
|
123
128
|
, body =
|
|
124
129
|
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I found an export called `"
|
|
@@ -128,16 +133,18 @@ get portName input decoder =
|
|
|
128
133
|
]
|
|
129
134
|
|> TerminalText.toString
|
|
130
135
|
}
|
|
136
|
+
ExportIsNotFunction
|
|
131
137
|
)
|
|
132
138
|
|
|
133
139
|
else if errorKind == "MissingPortsFile" then
|
|
134
|
-
|
|
140
|
+
FatalError.recoverable
|
|
135
141
|
{ title = "Port Error"
|
|
136
142
|
, body =
|
|
137
143
|
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I couldn't find your port-data-source file. Be sure to create a 'port-data-source.ts' or 'port-data-source.js' file."
|
|
138
144
|
]
|
|
139
145
|
|> TerminalText.toString
|
|
140
146
|
}
|
|
147
|
+
MissingPortsFile
|
|
141
148
|
|> Decode.succeed
|
|
142
149
|
|
|
143
150
|
else if errorKind == "ErrorInPortsFile" then
|
|
@@ -146,8 +153,7 @@ get portName input decoder =
|
|
|
146
153
|
|> Decode.map (Maybe.withDefault "")
|
|
147
154
|
|> Decode.map
|
|
148
155
|
(\errorMessage ->
|
|
149
|
-
|
|
150
|
-
ErrorInPortsFile
|
|
156
|
+
FatalError.recoverable
|
|
151
157
|
{ title = "Port Error"
|
|
152
158
|
, body =
|
|
153
159
|
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I couldn't import the port definitions file, because of this exception:\n\n"
|
|
@@ -156,6 +162,7 @@ get portName input decoder =
|
|
|
156
162
|
]
|
|
157
163
|
|> TerminalText.toString
|
|
158
164
|
}
|
|
165
|
+
ErrorInPortsFile
|
|
159
166
|
)
|
|
160
167
|
|
|
161
168
|
else if errorKind == "PortCallException" then
|
|
@@ -164,8 +171,7 @@ get portName input decoder =
|
|
|
164
171
|
|> Decode.map (Maybe.withDefault Encode.null)
|
|
165
172
|
|> Decode.map
|
|
166
173
|
(\portCallError ->
|
|
167
|
-
|
|
168
|
-
(PortCallException portCallError)
|
|
174
|
+
FatalError.recoverable
|
|
169
175
|
{ title = "Port Error"
|
|
170
176
|
, body =
|
|
171
177
|
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I was able to import the port definitions file, but when running it I encountered this exception:\n\n"
|
|
@@ -174,10 +180,11 @@ get portName input decoder =
|
|
|
174
180
|
]
|
|
175
181
|
|> TerminalText.toString
|
|
176
182
|
}
|
|
183
|
+
(PortCallException portCallError)
|
|
177
184
|
)
|
|
178
185
|
|
|
179
186
|
else
|
|
180
|
-
|
|
187
|
+
FatalError.recoverable
|
|
181
188
|
{ title = "Port Error"
|
|
182
189
|
, body =
|
|
183
190
|
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I expected to find a port named `"
|
|
@@ -186,6 +193,7 @@ get portName input decoder =
|
|
|
186
193
|
]
|
|
187
194
|
|> TerminalText.toString
|
|
188
195
|
}
|
|
196
|
+
ErrorInPortsFile
|
|
189
197
|
|> Decode.succeed
|
|
190
198
|
)
|
|
191
199
|
|> Decode.map Err
|
package/src/BackendTask.elm
CHANGED
|
@@ -5,7 +5,7 @@ module BackendTask exposing
|
|
|
5
5
|
, andThen, resolve, combine
|
|
6
6
|
, andMap
|
|
7
7
|
, map2, map3, map4, map5, map6, map7, map8, map9
|
|
8
|
-
,
|
|
8
|
+
, allowFatal, mapError, onError, toResult
|
|
9
9
|
)
|
|
10
10
|
|
|
11
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
|
|
@@ -80,13 +80,13 @@ Any place in your `elm-pages` app where the framework lets you pass in a value o
|
|
|
80
80
|
@docs map2, map3, map4, map5, map6, map7, map8, map9
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
##
|
|
83
|
+
## FatalError Handling
|
|
84
84
|
|
|
85
|
-
@docs
|
|
85
|
+
@docs allowFatal, mapError, onError, toResult
|
|
86
86
|
|
|
87
87
|
-}
|
|
88
88
|
|
|
89
|
-
import
|
|
89
|
+
import FatalError exposing (FatalError)
|
|
90
90
|
import Json.Encode
|
|
91
91
|
import Pages.StaticHttpRequest exposing (RawRequest(..))
|
|
92
92
|
|
|
@@ -524,28 +524,14 @@ map9 combineFn request1 request2 request3 request4 request5 request6 request7 re
|
|
|
524
524
|
|
|
525
525
|
|
|
526
526
|
{-| -}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|> onError
|
|
531
|
-
(\exception ->
|
|
532
|
-
case exception of
|
|
533
|
-
Exception error _ ->
|
|
534
|
-
fail error
|
|
535
|
-
)
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
{-| -}
|
|
539
|
-
throw : BackendTask (Exception error) data -> BackendTask Throwable data
|
|
540
|
-
throw backendTask =
|
|
541
|
-
backendTask
|
|
542
|
-
|> onError (Exception.throw >> fail)
|
|
527
|
+
allowFatal : BackendTask { error | fatal : FatalError } data -> BackendTask FatalError data
|
|
528
|
+
allowFatal backendTask =
|
|
529
|
+
mapError .fatal backendTask
|
|
543
530
|
|
|
544
531
|
|
|
545
532
|
{-| -}
|
|
546
|
-
toResult : BackendTask
|
|
533
|
+
toResult : BackendTask error data -> BackendTask noError (Result error data)
|
|
547
534
|
toResult backendTask =
|
|
548
535
|
backendTask
|
|
549
|
-
|> catch
|
|
550
536
|
|> andThen (Ok >> succeed)
|
|
551
537
|
|> onError (Err >> succeed)
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
module
|
|
1
|
+
module FatalError exposing
|
|
2
|
+
( FatalError, fromString, recoverable
|
|
3
|
+
, Recoverable
|
|
4
|
+
)
|
|
2
5
|
|
|
3
6
|
{-| The Elm language doesn't have the concept of exceptions or special control flow for errors. It just has
|
|
4
7
|
Custom Types, and by convention types like `Result` and the `Err` variant are used to represent possible failure states
|
|
5
8
|
and combine together different error states.
|
|
6
9
|
|
|
7
10
|
`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 `
|
|
11
|
+
a type, which is just a regular old Elm type, called `FatalError`. Why? Because this plain old Elm type does have one
|
|
9
12
|
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
|
|
13
|
+
because an `elm-pages` app has several places that accept a value of type `BackendTask FatalError.FatalError value`.
|
|
11
14
|
This design lets the `elm-pages` framework do some of the work for you.
|
|
12
15
|
|
|
13
16
|
For example, if you wanted to handle possible errors to present them to the user
|
|
@@ -15,34 +18,34 @@ For example, if you wanted to handle possible errors to present them to the user
|
|
|
15
18
|
type alias Data =
|
|
16
19
|
String
|
|
17
20
|
|
|
18
|
-
data : RouteParams -> BackendTask
|
|
21
|
+
data : RouteParams -> BackendTask FatalError Data
|
|
19
22
|
data routeParams =
|
|
20
23
|
BackendTask.Http.getJson "https://api.github.com/repos/dillonkearns/elm-pages"
|
|
21
24
|
(Decode.field "description" Decode.string)
|
|
22
25
|
|> BackendTask.onError
|
|
23
26
|
(\error ->
|
|
24
|
-
case
|
|
27
|
+
case FatalError.unwrap error of
|
|
25
28
|
BackendTask.Http.BadStatus metadata string ->
|
|
26
29
|
if metadata.statusCode == 401 || metadata.statusCode == 403 || metadata.statusCode == 404 then
|
|
27
30
|
BackendTask.succeed "Either this repo doesn't exist or you don't have access to it."
|
|
28
31
|
|
|
29
32
|
else
|
|
30
33
|
-- we're only handling these expected error cases. In the case of an HTTP timeout,
|
|
31
|
-
-- we'll let the error propagate as a
|
|
32
|
-
BackendTask.fail error |> BackendTask.
|
|
34
|
+
-- we'll let the error propagate as a FatalError
|
|
35
|
+
BackendTask.fail error |> BackendTask.allowFatal
|
|
33
36
|
|
|
34
37
|
_ ->
|
|
35
|
-
BackendTask.fail error |> BackendTask.
|
|
38
|
+
BackendTask.fail error |> BackendTask.allowFatal
|
|
36
39
|
)
|
|
37
40
|
|
|
38
41
|
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
42
|
you can let the framework handle it if the error ever does unexpectedly occur.
|
|
40
43
|
|
|
41
|
-
data : RouteParams -> BackendTask
|
|
44
|
+
data : RouteParams -> BackendTask FatalError Data
|
|
42
45
|
data routeParams =
|
|
43
46
|
BackendTask.Http.getJson "https://api.github.com/repos/dillonkearns/elm-pages"
|
|
44
47
|
(Decode.field "description" Decode.string)
|
|
45
|
-
|> BackendTask.
|
|
48
|
+
|> BackendTask.allowFatal
|
|
46
49
|
|
|
47
50
|
This is especially useful for pages generated at build-time (`RouteBuilder.preRender`) where you want the build
|
|
48
51
|
to fail if anything unexpected happens. With pre-rendered routes, you know that these error cases won't
|
|
@@ -54,42 +57,45 @@ issue.
|
|
|
54
57
|
In the case of server-rendered Routes (`RouteBuilder.serverRender`), `elm-pages` will show your 500 error page
|
|
55
58
|
when these errors occur.
|
|
56
59
|
|
|
57
|
-
@docs
|
|
60
|
+
@docs FatalError, fromString, recoverable
|
|
58
61
|
|
|
59
|
-
|
|
62
|
+
@docs Recoverable
|
|
60
63
|
|
|
64
|
+
-}
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
type alias Throwable =
|
|
64
|
-
Exception ()
|
|
66
|
+
import Pages.Internal.FatalError
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
{-| -}
|
|
68
|
-
type
|
|
69
|
-
|
|
70
|
+
type alias Recoverable error =
|
|
71
|
+
{ fatal : FatalError
|
|
72
|
+
, recoverable : error
|
|
73
|
+
}
|
|
70
74
|
|
|
71
75
|
|
|
72
76
|
{-| -}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
fromStringWithValue string ()
|
|
77
|
+
type alias FatalError =
|
|
78
|
+
Pages.Internal.FatalError.FatalError
|
|
76
79
|
|
|
77
80
|
|
|
78
81
|
{-| -}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
build : { title : String, body : String } -> FatalError
|
|
83
|
+
build info =
|
|
84
|
+
Pages.Internal.FatalError.FatalError info
|
|
82
85
|
|
|
83
86
|
|
|
84
87
|
{-| -}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
fromString : String -> FatalError
|
|
89
|
+
fromString string =
|
|
90
|
+
build
|
|
91
|
+
{ title = "Custom Error"
|
|
92
|
+
, body = string
|
|
93
|
+
}
|
|
90
94
|
|
|
91
95
|
|
|
92
96
|
{-| -}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
recoverable : { title : String, body : String } -> value -> Recoverable value
|
|
98
|
+
recoverable info value =
|
|
99
|
+
{ fatal = build info
|
|
100
|
+
, recoverable = value
|
|
101
|
+
}
|
package/src/Form.elm
CHANGED
|
@@ -269,7 +269,7 @@ Totally customizable. Uses [`Form.FieldView`](Form-FieldView) to render all of t
|
|
|
269
269
|
|
|
270
270
|
import BackendTask exposing (BackendTask)
|
|
271
271
|
import Dict exposing (Dict)
|
|
272
|
-
import
|
|
272
|
+
import FatalError exposing (FatalError)
|
|
273
273
|
import Form.Field as Field exposing (Field(..))
|
|
274
274
|
import Form.FieldStatus as FieldStatus exposing (FieldStatus)
|
|
275
275
|
import Form.FieldView
|
|
@@ -682,7 +682,7 @@ toServerForm :
|
|
|
682
682
|
->
|
|
683
683
|
Form
|
|
684
684
|
error
|
|
685
|
-
{ combine : Validation.Validation error (BackendTask
|
|
685
|
+
{ combine : Validation.Validation error (BackendTask FatalError (Validation.Validation error combined kind constraints)) kind constraints
|
|
686
686
|
, view : viewFn
|
|
687
687
|
}
|
|
688
688
|
data
|
|
@@ -695,7 +695,7 @@ toServerForm (Form a b c) =
|
|
|
695
695
|
{ result : Dict String (List error)
|
|
696
696
|
, isMatchCandidate : Bool
|
|
697
697
|
, combineAndView :
|
|
698
|
-
{ combine : Validation.Validation error (BackendTask
|
|
698
|
+
{ combine : Validation.Validation error (BackendTask FatalError (Validation.Validation error combined kind constraints)) kind constraints
|
|
699
699
|
, view : viewFn
|
|
700
700
|
}
|
|
701
701
|
}
|
|
@@ -9,7 +9,7 @@ module Internal.ApiRoute exposing
|
|
|
9
9
|
)
|
|
10
10
|
|
|
11
11
|
import BackendTask exposing (BackendTask)
|
|
12
|
-
import
|
|
12
|
+
import FatalError exposing (FatalError)
|
|
13
13
|
import Head
|
|
14
14
|
import Json.Decode
|
|
15
15
|
import Pattern exposing (Pattern)
|
|
@@ -46,12 +46,12 @@ tryMatchDone path (ApiRoute handler) =
|
|
|
46
46
|
type ApiRoute response
|
|
47
47
|
= ApiRoute
|
|
48
48
|
{ regex : Regex
|
|
49
|
-
, matchesToResponse : Json.Decode.Value -> String -> BackendTask
|
|
50
|
-
, buildTimeRoutes : BackendTask
|
|
51
|
-
, handleRoute : String -> BackendTask
|
|
49
|
+
, matchesToResponse : Json.Decode.Value -> String -> BackendTask FatalError (Maybe response)
|
|
50
|
+
, buildTimeRoutes : BackendTask FatalError (List String)
|
|
51
|
+
, handleRoute : String -> BackendTask FatalError Bool
|
|
52
52
|
, pattern : Pattern
|
|
53
53
|
, kind : String
|
|
54
|
-
, globalHeadTags : Maybe (BackendTask
|
|
54
|
+
, globalHeadTags : Maybe (BackendTask FatalError (List Head.Tag))
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
|
package/src/Pages/Generate.elm
CHANGED
|
@@ -1409,6 +1409,6 @@ throwableTask : Elm.Annotation.Annotation -> Elm.Annotation.Annotation
|
|
|
1409
1409
|
throwableTask dataType =
|
|
1410
1410
|
Elm.Annotation.namedWith [ "BackendTask" ]
|
|
1411
1411
|
"BackendTask"
|
|
1412
|
-
[ Elm.Annotation.named [ "
|
|
1412
|
+
[ Elm.Annotation.named [ "FatalError" ] "FatalError"
|
|
1413
1413
|
, dataType
|
|
1414
1414
|
]
|