elm-pages 3.0.0-beta.2 → 3.0.0-beta.20

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 (109) hide show
  1. package/README.md +10 -1
  2. package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2420 -1592
  3. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
  10. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
  11. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15215 -13007
  12. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  13. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  14. package/generator/dead-code-review/elm.json +8 -6
  15. package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +189 -17
  16. package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +255 -21
  17. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  18. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  19. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  20. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
  21. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
  22. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14620 -12636
  23. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  24. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  25. package/generator/review/elm.json +8 -8
  26. package/generator/src/RouteBuilder.elm +66 -52
  27. package/generator/src/SharedTemplate.elm +3 -2
  28. package/generator/src/SiteConfig.elm +3 -2
  29. package/generator/src/basepath-middleware.js +3 -3
  30. package/generator/src/build.js +122 -86
  31. package/generator/src/cli.js +247 -51
  32. package/generator/src/codegen.js +29 -27
  33. package/generator/src/compatibility-key.js +1 -0
  34. package/generator/src/compile-elm.js +20 -22
  35. package/generator/src/config.js +39 -0
  36. package/generator/src/copy-dir.js +2 -2
  37. package/generator/src/dev-server.js +119 -110
  38. package/generator/src/dir-helpers.js +9 -26
  39. package/generator/src/elm-codegen.js +5 -4
  40. package/generator/src/elm-file-constants.js +2 -3
  41. package/generator/src/error-formatter.js +12 -11
  42. package/generator/src/file-helpers.js +3 -4
  43. package/generator/src/generate-template-module-connector.js +14 -21
  44. package/generator/src/init.js +8 -7
  45. package/generator/src/pre-render-html.js +41 -28
  46. package/generator/src/render-test.js +109 -0
  47. package/generator/src/render-worker.js +26 -28
  48. package/generator/src/render.js +322 -142
  49. package/generator/src/request-cache.js +200 -162
  50. package/generator/src/rewrite-client-elm-json.js +5 -5
  51. package/generator/src/rewrite-elm-json.js +7 -7
  52. package/generator/src/route-codegen-helpers.js +16 -31
  53. package/generator/src/seo-renderer.js +12 -7
  54. package/generator/src/vite-utils.js +77 -0
  55. package/generator/static-code/hmr.js +16 -2
  56. package/generator/template/app/Api.elm +3 -3
  57. package/generator/template/app/Route/Index.elm +3 -3
  58. package/generator/template/app/Shared.elm +3 -3
  59. package/generator/template/app/Site.elm +9 -4
  60. package/package.json +21 -21
  61. package/src/ApiRoute.elm +199 -61
  62. package/src/BackendTask/Custom.elm +214 -0
  63. package/src/BackendTask/Env.elm +90 -0
  64. package/src/{DataSource → BackendTask}/File.elm +128 -43
  65. package/src/{DataSource → BackendTask}/Glob.elm +136 -125
  66. package/src/BackendTask/Http.elm +673 -0
  67. package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
  68. package/src/BackendTask/Internal/Request.elm +28 -0
  69. package/src/BackendTask/Random.elm +79 -0
  70. package/src/BackendTask/Time.elm +47 -0
  71. package/src/BackendTask.elm +537 -0
  72. package/src/FatalError.elm +89 -0
  73. package/src/Form/Field.elm +1 -1
  74. package/src/Form.elm +72 -92
  75. package/src/Head/Seo.elm +4 -4
  76. package/src/Head.elm +237 -7
  77. package/src/HtmlPrinter.elm +7 -3
  78. package/src/Internal/ApiRoute.elm +7 -5
  79. package/src/PageServerResponse.elm +6 -1
  80. package/src/Pages/Generate.elm +775 -132
  81. package/src/Pages/GeneratorProgramConfig.elm +15 -0
  82. package/src/Pages/Internal/FatalError.elm +5 -0
  83. package/src/Pages/Internal/Form.elm +21 -1
  84. package/src/Pages/Internal/Platform/Cli.elm +479 -747
  85. package/src/Pages/Internal/Platform/Cli.elm.bak +1276 -0
  86. package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
  87. package/src/Pages/Internal/Platform/Effect.elm +1 -2
  88. package/src/Pages/Internal/Platform/GeneratorApplication.elm +373 -0
  89. package/src/Pages/Internal/Platform/StaticResponses.elm +73 -270
  90. package/src/Pages/Internal/Platform/ToJsPayload.elm +4 -7
  91. package/src/Pages/Internal/Platform.elm +54 -53
  92. package/src/Pages/Internal/Script.elm +17 -0
  93. package/src/Pages/Internal/StaticHttpBody.elm +35 -1
  94. package/src/Pages/Manifest.elm +29 -4
  95. package/src/Pages/ProgramConfig.elm +12 -8
  96. package/src/Pages/Script.elm +109 -0
  97. package/src/Pages/SiteConfig.elm +3 -2
  98. package/src/Pages/StaticHttp/Request.elm +2 -2
  99. package/src/Pages/StaticHttpRequest.elm +23 -98
  100. package/src/RequestsAndPending.elm +8 -19
  101. package/src/Result/Extra.elm +21 -0
  102. package/src/Server/Request.elm +43 -34
  103. package/src/Server/Session.elm +166 -100
  104. package/src/Server/SetCookie.elm +89 -31
  105. package/src/DataSource/Env.elm +0 -38
  106. package/src/DataSource/Http.elm +0 -446
  107. package/src/DataSource/Internal/Request.elm +0 -20
  108. package/src/DataSource/Port.elm +0 -90
  109. package/src/DataSource.elm +0 -538
@@ -45,11 +45,6 @@ import Time
45
45
  import Url exposing (Url)
46
46
 
47
47
 
48
- type Transition
49
- = Loading Int Path
50
- | Submitting FormData
51
-
52
-
53
48
  {-| -}
54
49
  type alias Program userModel userMsg pageData actionData sharedData errorPage =
55
50
  Platform.Program Flags (Model userModel pageData actionData sharedData) (Msg userMsg pageData actionData sharedData errorPage)
@@ -423,16 +418,14 @@ update config appMsg model =
423
418
  )
424
419
 
425
420
  else
426
- ( { model
427
- | url = url
428
- }
421
+ ( model
429
422
  , NoEffect
430
423
  )
431
424
  -- TODO is it reasonable to always re-fetch route data if you re-navigate to the current route? Might be a good
432
425
  -- parallel to the browser behavior
433
426
  |> startNewGetLoad url (UpdateCacheAndUrlNew True url Nothing)
434
427
 
435
- FetcherComplete forPageReload fetcherKey transitionId___ userMsgResult ->
428
+ FetcherComplete _ fetcherKey _ userMsgResult ->
436
429
  case userMsgResult of
437
430
  Ok ( userMsg, maybeFetcherDoneActionData ) ->
438
431
  ( { model
@@ -605,27 +598,32 @@ update config appMsg model =
605
598
  , actionData = newActionData
606
599
  }
607
600
 
608
- ( userModel, _ ) =
601
+ ( userModel, userEffect ) =
609
602
  -- TODO if urlWithoutRedirectResolution is different from the url with redirect resolution, then
610
603
  -- instead of calling update, call pushUrl (I think?)
611
604
  -- TODO include user Cmd
612
- config.update model.pageFormState
613
- (model.inFlightFetchers |> toFetcherState)
614
- (model.transition |> Maybe.map Tuple.second)
615
- newSharedData
616
- newPageData
617
- model.key
618
- (config.onPageChange
619
- { protocol = model.url.protocol
620
- , host = model.url.host
621
- , port_ = model.url.port_
622
- , path = urlPathToPath urlWithoutRedirectResolution
623
- , query = urlWithoutRedirectResolution.query
624
- , fragment = urlWithoutRedirectResolution.fragment
625
- , metadata = config.urlToRoute urlWithoutRedirectResolution
626
- }
627
- )
628
- previousPageData.userModel
605
+ if stayingOnSamePath then
606
+ ( previousPageData.userModel, NoEffect )
607
+
608
+ else
609
+ config.update model.pageFormState
610
+ (model.inFlightFetchers |> toFetcherState)
611
+ (model.transition |> Maybe.map Tuple.second)
612
+ newSharedData
613
+ newPageData
614
+ model.key
615
+ (config.onPageChange
616
+ { protocol = model.url.protocol
617
+ , host = model.url.host
618
+ , port_ = model.url.port_
619
+ , path = urlPathToPath urlWithoutRedirectResolution
620
+ , query = urlWithoutRedirectResolution.query
621
+ , fragment = urlWithoutRedirectResolution.fragment
622
+ , metadata = config.urlToRoute urlWithoutRedirectResolution
623
+ }
624
+ )
625
+ previousPageData.userModel
626
+ |> Tuple.mapSecond UserCmd
629
627
 
630
628
  updatedModel : Model userModel pageData actionData sharedData
631
629
  updatedModel =
@@ -656,10 +654,13 @@ update config appMsg model =
656
654
  , currentPath = newUrl.path
657
655
  }
658
656
  , if not stayingOnSamePath && scrollToTopWhenDone then
659
- ScrollToTop
657
+ Batch
658
+ [ ScrollToTop
659
+ , userEffect
660
+ ]
660
661
 
661
662
  else
662
- NoEffect
663
+ userEffect
663
664
  )
664
665
  |> (case maybeUserMsg of
665
666
  Just userMsg ->
@@ -679,10 +680,10 @@ update config appMsg model =
679
680
  Err _ ->
680
681
  {-
681
682
  When there is an error loading the content.dat, we are either
682
- 1) in the dev server, and should show the relevant DataSource error for the page
683
+ 1) in the dev server, and should show the relevant BackendTask error for the page
683
684
  we're navigating to. This could be done more cleanly, but it's simplest to just
684
685
  do a fresh page load and use the code path for presenting an error for a fresh page.
685
- 2) In a production app. That means we had a successful build, so there were no DataSource failures,
686
+ 2) In a production app. That means we had a successful build, so there were no BackendTask failures,
686
687
  so the app must be stale (unless it's in some unexpected state from a bug). In the future,
687
688
  it probably makes sense to include some sort of hash of the app version we are fetching, match
688
689
  it with the current version that's running, and perform this logic when we see there is a mismatch.
@@ -766,7 +767,7 @@ update config appMsg model =
766
767
  toFetcherState : Dict String ( Int, Pages.Transition.FetcherState actionData ) -> Dict String (Pages.Transition.FetcherState actionData)
767
768
  toFetcherState inFlightFetchers =
768
769
  inFlightFetchers
769
- |> Dict.map (\_ ( index, fetcherState ) -> fetcherState)
770
+ |> Dict.map (\_ ( _, fetcherState ) -> fetcherState)
770
771
 
771
772
 
772
773
  performUserMsg :
@@ -828,7 +829,7 @@ perform config model effect =
828
829
  |> Maybe.withDefault Cmd.none
829
830
 
830
831
  FetchPageData transitionKey maybeRequestInfo url toMsg ->
831
- fetchRouteData True transitionKey toMsg config url maybeRequestInfo
832
+ fetchRouteData transitionKey toMsg config url maybeRequestInfo
832
833
 
833
834
  Submit fields ->
834
835
  if fields.method == Get then
@@ -843,7 +844,7 @@ perform config model effect =
843
844
  -- TODO add optional path parameter to Submit variant to allow submitting to other routes
844
845
  model.url
845
846
  in
846
- fetchRouteData False -1 (UpdateCacheAndUrlNew False model.url Nothing) config urlToSubmitTo (Just fields)
847
+ fetchRouteData -1 (UpdateCacheAndUrlNew False model.url Nothing) config urlToSubmitTo (Just fields)
847
848
 
848
849
  SubmitFetcher fetcherKey transitionId formData ->
849
850
  startFetcher2 config False fetcherKey transitionId formData model
@@ -863,7 +864,7 @@ perform config model effect =
863
864
  |> config.perform
864
865
  { fetchRouteData =
865
866
  \fetchInfo ->
866
- fetchRouteData False
867
+ fetchRouteData
867
868
  -1
868
869
  (prepare fetchInfo.toMsg)
869
870
  config
@@ -873,7 +874,7 @@ perform config model effect =
873
874
  ---- TODO map the Msg with the wrapper type (like in the PR branch)
874
875
  , submit =
875
876
  \fetchInfo ->
876
- fetchRouteData False -1 (prepare fetchInfo.toMsg) config (fetchInfo.values.action |> Url.fromString |> Maybe.withDefault model.url) (Just fetchInfo.values)
877
+ fetchRouteData -1 (prepare fetchInfo.toMsg) config (fetchInfo.values.action |> Url.fromString |> Maybe.withDefault model.url) (Just fetchInfo.values)
877
878
  , runFetcher =
878
879
  \(Pages.Fetcher.Fetcher options) ->
879
880
  -- TODO need to get the fetcherId here
@@ -927,7 +928,7 @@ startFetcher fetcherKey transitionId options model =
927
928
  Http.expectBytesResponse (FetcherComplete False fetcherKey model.nextTransitionKey)
928
929
  (\bytes ->
929
930
  case bytes of
930
- Http.GoodStatus_ metadata bytesBody ->
931
+ Http.GoodStatus_ _ bytesBody ->
931
932
  ( options.decoder (Ok bytesBody)
932
933
  |> Just
933
934
  , Nothing
@@ -943,7 +944,7 @@ startFetcher fetcherKey transitionId options model =
943
944
  Http.NetworkError_ ->
944
945
  Err <| Http.NetworkError
945
946
 
946
- Http.BadStatus_ metadata body ->
947
+ Http.BadStatus_ metadata _ ->
947
948
  Err <| Http.BadStatus metadata.statusCode
948
949
  )
949
950
  , tracker = Nothing
@@ -974,7 +975,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
974
975
  Cmd.batch
975
976
  [ cancelStaleFetchers model
976
977
  , case Dict.get fetcherKey model.inFlightFetchers of
977
- Just ( inFlightId, inFlightFetcher ) ->
978
+ Just ( inFlightId, _ ) ->
978
979
  Http.cancel (String.fromInt inFlightId)
979
980
 
980
981
  Nothing ->
@@ -985,7 +986,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
985
986
  Http.expectBytesResponse (FetcherComplete fromPageReload fetcherKey model.nextTransitionKey)
986
987
  (\bytes ->
987
988
  case bytes of
988
- Http.GoodStatus_ metadata bytesBody ->
989
+ Http.GoodStatus_ _ bytesBody ->
989
990
  let
990
991
  decodedAction : Maybe actionData
991
992
  decodedAction =
@@ -993,10 +994,10 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
993
994
  Just (ResponseSketch.RenderPage _ maybeAction) ->
994
995
  maybeAction
995
996
 
996
- Just (ResponseSketch.HotUpdate pageData shared maybeAction) ->
997
+ Just (ResponseSketch.HotUpdate _ _ maybeAction) ->
997
998
  maybeAction
998
999
 
999
- Just (ResponseSketch.NotFound notFound) ->
1000
+ Just (ResponseSketch.NotFound _) ->
1000
1001
  Nothing
1001
1002
 
1002
1003
  _ ->
@@ -1014,7 +1015,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
1014
1015
  Http.NetworkError_ ->
1015
1016
  Err <| Http.NetworkError
1016
1017
 
1017
- Http.BadStatus_ metadata body ->
1018
+ Http.BadStatus_ metadata _ ->
1018
1019
  Err <| Http.BadStatus metadata.statusCode
1019
1020
  )
1020
1021
  , tracker = Just (String.fromInt transitionId)
@@ -1036,7 +1037,7 @@ cancelStaleFetchers model =
1036
1037
  model.inFlightFetchers
1037
1038
  |> Dict.toList
1038
1039
  |> List.filterMap
1039
- (\( fetcherKey, ( id, fetcher ) ) ->
1040
+ (\( _, ( id, fetcher ) ) ->
1040
1041
  case fetcher.status of
1041
1042
  Pages.Transition.FetcherReloading _ ->
1042
1043
  Http.cancel (String.fromInt id)
@@ -1157,14 +1158,13 @@ urlPathToPath urls =
1157
1158
 
1158
1159
 
1159
1160
  fetchRouteData :
1160
- Bool
1161
- -> Int
1161
+ Int
1162
1162
  -> (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ) -> Msg userMsg pageData actionData sharedData errorPage)
1163
1163
  -> ProgramConfig userMsg userModel route pageData actionData sharedData effect (Msg userMsg pageData actionData sharedData errorPage) errorPage
1164
1164
  -> Url
1165
1165
  -> Maybe FormData
1166
1166
  -> Cmd (Msg userMsg pageData actionData sharedData errorPage)
1167
- fetchRouteData forPageDataReload transitionKey toMsg config url details =
1167
+ fetchRouteData transitionKey toMsg config url details =
1168
1168
  {-
1169
1169
  TODO:
1170
1170
  - [X] `toMsg` needs a parameter for the callback Msg so it can pass it on if there is a Redirect response
@@ -1251,7 +1251,7 @@ fetchRouteData forPageDataReload transitionKey toMsg config url details =
1251
1251
  Http.NetworkError_ ->
1252
1252
  Err Http.NetworkError
1253
1253
 
1254
- Http.BadStatus_ metadata body ->
1254
+ Http.BadStatus_ _ body ->
1255
1255
  body
1256
1256
  |> Bytes.Decode.decode config.decodeResponse
1257
1257
  |> Result.fromMaybe "Decoding error"
@@ -1303,7 +1303,7 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
1303
1303
  cancelIfStale : Effect userMsg pageData actionData sharedData userEffect errorPage
1304
1304
  cancelIfStale =
1305
1305
  case model.transition of
1306
- Just ( transitionKey, Pages.Transition.Loading path loadingKind ) ->
1306
+ Just ( transitionKey, Pages.Transition.Loading _ _ ) ->
1307
1307
  CancelRequest transitionKey
1308
1308
 
1309
1309
  _ ->
@@ -1314,13 +1314,13 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
1314
1314
  , transition =
1315
1315
  ( model.nextTransitionKey
1316
1316
  , case model.transition of
1317
- Just ( transitionKey, Pages.Transition.LoadAfterSubmit submitData _ _ ) ->
1317
+ Just ( _, Pages.Transition.LoadAfterSubmit submitData _ _ ) ->
1318
1318
  Pages.Transition.LoadAfterSubmit
1319
1319
  submitData
1320
1320
  (urlToGet.path |> Path.fromString)
1321
1321
  Pages.Transition.Load
1322
1322
 
1323
- Just ( transitionKey, Pages.Transition.Submitting submitData ) ->
1323
+ Just ( _, Pages.Transition.Submitting submitData ) ->
1324
1324
  Pages.Transition.LoadAfterSubmit
1325
1325
  submitData
1326
1326
  (urlToGet.path |> Path.fromString)
@@ -1392,6 +1392,7 @@ loadDataAndUpdateUrl ( newPageData, newSharedData, newActionData ) maybeUserMsg
1392
1392
  , actionData = newActionData
1393
1393
  }
1394
1394
 
1395
+ -- TODO use userEffect here?
1395
1396
  ( userModel, _ ) =
1396
1397
  -- TODO if urlWithoutRedirectResolution is different from the url with redirect resolution, then
1397
1398
  -- instead of calling update, call pushUrl (I think?)
@@ -1467,10 +1468,10 @@ loadDataAndUpdateUrl ( newPageData, newSharedData, newActionData ) maybeUserMsg
1467
1468
  Err _ ->
1468
1469
  {-
1469
1470
  When there is an error loading the content.dat, we are either
1470
- 1) in the dev server, and should show the relevant DataSource error for the page
1471
+ 1) in the dev server, and should show the relevant BackendTask error for the page
1471
1472
  we're navigating to. This could be done more cleanly, but it's simplest to just
1472
1473
  do a fresh page load and use the code path for presenting an error for a fresh page.
1473
- 2) In a production app. That means we had a successful build, so there were no DataSource failures,
1474
+ 2) In a production app. That means we had a successful build, so there were no BackendTask failures,
1474
1475
  so the app must be stale (unless it's in some unexpected state from a bug). In the future,
1475
1476
  it probably makes sense to include some sort of hash of the app version we are fetching, match
1476
1477
  it with the current version that's running, and perform this logic when we see there is a mismatch.
@@ -0,0 +1,17 @@
1
+ module Pages.Internal.Script exposing (Script(..))
2
+
3
+ import BackendTask exposing (BackendTask)
4
+ import Cli.Program as Program
5
+ import FatalError exposing (FatalError)
6
+ import Html exposing (Html)
7
+
8
+
9
+ {-| -}
10
+ type Script
11
+ = Script
12
+ ((Maybe { indent : Int, newLines : Bool }
13
+ -> Html Never
14
+ -> String
15
+ )
16
+ -> Program.Config (BackendTask FatalError ())
17
+ )
@@ -1,6 +1,9 @@
1
1
  module Pages.Internal.StaticHttpBody exposing (Body(..), codec, encode)
2
2
 
3
+ import Base64
4
+ import Bytes exposing (Bytes)
3
5
  import Codec exposing (Codec)
6
+ import Json.Decode
4
7
  import Json.Encode as Encode
5
8
 
6
9
 
@@ -8,6 +11,7 @@ type Body
8
11
  = EmptyBody
9
12
  | StringBody String String
10
13
  | JsonBody Encode.Value
14
+ | BytesBody String Bytes
11
15
 
12
16
 
13
17
  encode : Body -> Encode.Value
@@ -26,6 +30,15 @@ encode body =
26
30
  [ ( "content", content )
27
31
  ]
28
32
 
33
+ BytesBody _ content ->
34
+ encodeWithType "bytes"
35
+ [ ( "content"
36
+ , Base64.fromBytes content
37
+ |> Maybe.withDefault ""
38
+ |> Encode.string
39
+ )
40
+ ]
41
+
29
42
 
30
43
  encodeWithType : String -> List ( String, Encode.Value ) -> Encode.Value
31
44
  encodeWithType typeName otherFields =
@@ -37,7 +50,7 @@ encodeWithType typeName otherFields =
37
50
  codec : Codec Body
38
51
  codec =
39
52
  Codec.custom
40
- (\vEmpty vString vJson value ->
53
+ (\vEmpty vString vJson vBytes value ->
41
54
  case value of
42
55
  EmptyBody ->
43
56
  vEmpty
@@ -47,8 +60,29 @@ codec =
47
60
 
48
61
  JsonBody body ->
49
62
  vJson body
63
+
64
+ BytesBody contentType body ->
65
+ vBytes contentType body
50
66
  )
51
67
  |> Codec.variant0 "EmptyBody" EmptyBody
52
68
  |> Codec.variant2 "StringBody" StringBody Codec.string Codec.string
53
69
  |> Codec.variant1 "JsonBody" JsonBody Codec.value
70
+ |> Codec.variant2 "BytesBody" BytesBody Codec.string bytesCodec
54
71
  |> Codec.buildCustom
72
+
73
+
74
+ bytesCodec : Codec Bytes
75
+ bytesCodec =
76
+ Codec.build (Base64.fromBytes >> Maybe.withDefault "" >> Encode.string)
77
+ (Json.Decode.string
78
+ |> Json.Decode.map Base64.toBytes
79
+ |> Json.Decode.andThen
80
+ (\decodedBytes ->
81
+ case decodedBytes of
82
+ Just bytes ->
83
+ Json.Decode.succeed bytes
84
+
85
+ Nothing ->
86
+ Json.Decode.fail "Couldn't parse bytes."
87
+ )
88
+ )
@@ -2,6 +2,7 @@ module Pages.Manifest exposing
2
2
  ( Config, Icon
3
3
  , init
4
4
  , withBackgroundColor, withCategories, withDisplayMode, withIarcRatingId, withLang, withOrientation, withShortName, withThemeColor
5
+ , withField
5
6
  , DisplayMode(..), Orientation(..), IconPurpose(..)
6
7
  , generator
7
8
  , toJson
@@ -41,6 +42,11 @@ You pass your `Pages.Manifest.Config` record into the `Pages.application` functi
41
42
  @docs withBackgroundColor, withCategories, withDisplayMode, withIarcRatingId, withLang, withOrientation, withShortName, withThemeColor
42
43
 
43
44
 
45
+ ## Arbitrary Fields Escape Hatch
46
+
47
+ @docs withField
48
+
49
+
44
50
  ## Config options
45
51
 
46
52
  @docs DisplayMode, Orientation, IconPurpose
@@ -58,9 +64,11 @@ You pass your `Pages.Manifest.Config` record into the `Pages.application` functi
58
64
  -}
59
65
 
60
66
  import ApiRoute
67
+ import BackendTask exposing (BackendTask)
61
68
  import Color exposing (Color)
62
69
  import Color.Convert
63
- import DataSource exposing (DataSource)
70
+ import Dict exposing (Dict)
71
+ import FatalError exposing (FatalError)
64
72
  import Head
65
73
  import Json.Encode as Encode
66
74
  import LanguageTag exposing (LanguageTag, emptySubtags)
@@ -123,6 +131,7 @@ init options =
123
131
  , shortName = Nothing
124
132
  , icons = options.icons
125
133
  , lang = usEnglish
134
+ , otherFields = Dict.empty
126
135
  }
127
136
 
128
137
 
@@ -191,6 +200,17 @@ withLang languageTag config =
191
200
  { config | lang = languageTag }
192
201
 
193
202
 
203
+ {-| Escape hatch for specifying fields that aren't exposed through this module otherwise. The possible supported properties
204
+ in a manifest file can change over time, so see [MDN manifest.json docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json)
205
+ for a full listing of the current supported properties.
206
+ -}
207
+ withField : String -> Encode.Value -> Config -> Config
208
+ withField name value config =
209
+ { config
210
+ | otherFields = config.otherFields |> Dict.insert name value
211
+ }
212
+
213
+
194
214
  orientationToString : Orientation -> String
195
215
  orientationToString orientation =
196
216
  case orientation of
@@ -239,6 +259,7 @@ type alias Config =
239
259
  , shortName : Maybe String
240
260
  , icons : List Icon
241
261
  , lang : LanguageTag
262
+ , otherFields : Dict String Encode.Value
242
263
  }
243
264
 
244
265
 
@@ -324,16 +345,16 @@ nonEmptyList list =
324
345
 
325
346
  {-| A generator for Api.elm to include a manifest.json.
326
347
  -}
327
- generator : String -> DataSource Config -> ApiRoute.ApiRoute ApiRoute.Response
348
+ generator : String -> BackendTask FatalError Config -> ApiRoute.ApiRoute ApiRoute.Response
328
349
  generator canonicalSiteUrl config =
329
350
  ApiRoute.succeed
330
351
  (config
331
- |> DataSource.map (toJson canonicalSiteUrl >> Encode.encode 0)
352
+ |> BackendTask.map (toJson canonicalSiteUrl >> Encode.encode 0)
332
353
  )
333
354
  |> ApiRoute.literal "manifest.json"
334
355
  |> ApiRoute.single
335
356
  |> ApiRoute.withGlobalHeadTags
336
- (DataSource.succeed
357
+ (BackendTask.succeed
337
358
  [ Head.manifestLink "/manifest.json"
338
359
  ]
339
360
  )
@@ -420,6 +441,10 @@ toJson canonicalSiteUrl config =
420
441
  , Encode.string "/" |> Just
421
442
  )
422
443
  ]
444
+ ++ (config.otherFields
445
+ |> Dict.toList
446
+ |> List.map (Tuple.mapSecond Just)
447
+ )
423
448
  |> encodeMaybeObject
424
449
 
425
450
 
@@ -1,12 +1,13 @@
1
1
  module Pages.ProgramConfig exposing (ProgramConfig)
2
2
 
3
3
  import ApiRoute
4
+ import BackendTask exposing (BackendTask)
4
5
  import Browser.Navigation
5
6
  import Bytes exposing (Bytes)
6
7
  import Bytes.Decode
7
8
  import Bytes.Encode
8
- import DataSource exposing (DataSource)
9
9
  import Dict exposing (Dict)
10
+ import FatalError exposing (FatalError)
10
11
  import Form.FormData exposing (FormData)
11
12
  import Head
12
13
  import Html exposing (Html)
@@ -48,9 +49,9 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
48
49
  -> ( userModel, effect )
49
50
  , update : Pages.FormState.PageFormState -> Dict String (Pages.Transition.FetcherState actionData) -> Maybe Pages.Transition.Transition -> sharedData -> pageData -> Maybe Browser.Navigation.Key -> userMsg -> userModel -> ( userModel, effect )
50
51
  , subscriptions : route -> Path -> userModel -> Sub userMsg
51
- , sharedData : DataSource sharedData
52
- , data : route -> DataSource (PageServerResponse pageData errorPage)
53
- , action : route -> DataSource (PageServerResponse actionData errorPage)
52
+ , sharedData : BackendTask FatalError sharedData
53
+ , data : Decode.Value -> route -> BackendTask FatalError (PageServerResponse pageData errorPage)
54
+ , action : Decode.Value -> route -> BackendTask FatalError (PageServerResponse actionData errorPage)
54
55
  , onActionData : actionData -> Maybe userMsg
55
56
  , view :
56
57
  Pages.FormState.PageFormState
@@ -68,8 +69,8 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
68
69
  { view : userModel -> { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
69
70
  , head : List Head.Tag
70
71
  }
71
- , handleRoute : route -> DataSource (Maybe NotFoundReason)
72
- , getStaticRoutes : DataSource (List route)
72
+ , handleRoute : route -> BackendTask FatalError (Maybe NotFoundReason)
73
+ , getStaticRoutes : BackendTask FatalError (List route)
73
74
  , urlToRoute : Url -> route
74
75
  , routeToPath : route -> List String
75
76
  , site : Maybe SiteConfig
@@ -88,7 +89,10 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
88
89
  }
89
90
  -> userMsg
90
91
  , apiRoutes :
91
- (Html Never -> String)
92
+ (Maybe { indent : Int, newLines : Bool }
93
+ -> Html Never
94
+ -> String
95
+ )
92
96
  -> List (ApiRoute.ApiRoute ApiRoute.Response)
93
97
  , pathPatterns : List RoutePattern
94
98
  , basePath : List String
@@ -98,7 +102,7 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
98
102
  , encodeResponse : ResponseSketch pageData actionData sharedData -> Bytes.Encode.Encoder
99
103
  , encodeAction : actionData -> Bytes.Encode.Encoder
100
104
  , decodeResponse : Bytes.Decode.Decoder (ResponseSketch pageData actionData sharedData)
101
- , globalHeadTags : Maybe ((Html Never -> String) -> DataSource (List Head.Tag))
105
+ , globalHeadTags : Maybe ((Maybe { indent : Int, newLines : Bool } -> Html Never -> String) -> BackendTask FatalError (List Head.Tag))
102
106
  , cmdToEffect : Cmd userMsg -> effect
103
107
  , perform :
104
108
  { fetchRouteData :
@@ -0,0 +1,109 @@
1
+ module Pages.Script exposing
2
+ ( Script
3
+ , withCliOptions, withoutCliOptions
4
+ , writeFile
5
+ , log
6
+ , Error(..)
7
+ )
8
+
9
+ {-|
10
+
11
+ @docs Script
12
+
13
+ @docs withCliOptions, withoutCliOptions
14
+
15
+
16
+ ## File System Utilities
17
+
18
+ @docs writeFile
19
+
20
+
21
+ ## Utilities
22
+
23
+ @docs log
24
+
25
+
26
+ ## Errors
27
+
28
+ @docs Error
29
+
30
+ -}
31
+
32
+ import BackendTask exposing (BackendTask)
33
+ import BackendTask.Http
34
+ import BackendTask.Internal.Request
35
+ import Cli.OptionsParser as OptionsParser
36
+ import Cli.Program as Program
37
+ import FatalError exposing (FatalError)
38
+ import Json.Decode as Decode
39
+ import Json.Encode as Encode
40
+ import Pages.Internal.Script
41
+
42
+
43
+ {-| -}
44
+ type alias Script =
45
+ Pages.Internal.Script.Script
46
+
47
+
48
+ {-| -}
49
+ type Error
50
+ = --TODO make more descriptive
51
+ FileWriteError
52
+
53
+
54
+ {-| -}
55
+ writeFile : { path : String, body : String } -> BackendTask { fatal : FatalError, recoverable : Error } ()
56
+ writeFile { path, body } =
57
+ BackendTask.Internal.Request.request
58
+ { name = "write-file"
59
+ , body =
60
+ BackendTask.Http.jsonBody
61
+ (Encode.object
62
+ [ ( "path", Encode.string path )
63
+ , ( "body", Encode.string body )
64
+ ]
65
+ )
66
+ , expect =
67
+ -- TODO decode possible error details here
68
+ BackendTask.Http.expectJson (Decode.succeed ())
69
+ }
70
+
71
+
72
+ {-| -}
73
+ log : String -> BackendTask error ()
74
+ log message =
75
+ BackendTask.Internal.Request.request
76
+ { name = "log"
77
+ , body =
78
+ BackendTask.Http.jsonBody
79
+ (Encode.object
80
+ [ ( "message", Encode.string message )
81
+ ]
82
+ )
83
+ , expect = BackendTask.Http.expectJson (Decode.succeed ())
84
+ }
85
+
86
+
87
+ {-| -}
88
+ withoutCliOptions : BackendTask FatalError () -> Script
89
+ withoutCliOptions execute =
90
+ Pages.Internal.Script.Script
91
+ (\_ ->
92
+ Program.config
93
+ |> Program.add
94
+ (OptionsParser.build ())
95
+ |> Program.mapConfig
96
+ (\() ->
97
+ execute
98
+ )
99
+ )
100
+
101
+
102
+ {-| -}
103
+ withCliOptions : Program.Config cliOptions -> (cliOptions -> BackendTask FatalError ()) -> Script
104
+ withCliOptions config execute =
105
+ Pages.Internal.Script.Script
106
+ (\_ ->
107
+ config
108
+ |> Program.mapConfig execute
109
+ )
@@ -1,10 +1,11 @@
1
1
  module Pages.SiteConfig exposing (SiteConfig)
2
2
 
3
- import DataSource exposing (DataSource)
3
+ import BackendTask exposing (BackendTask)
4
+ import FatalError exposing (FatalError)
4
5
  import Head
5
6
 
6
7
 
7
8
  type alias SiteConfig =
8
9
  { canonicalUrl : String
9
- , head : DataSource (List Head.Tag)
10
+ , head : BackendTask FatalError (List Head.Tag)
10
11
  }
@@ -11,7 +11,7 @@ type alias Request =
11
11
  , method : String
12
12
  , headers : List ( String, String )
13
13
  , body : Body
14
- , useCache : Bool
14
+ , cacheOptions : Maybe Encode.Value
15
15
  }
16
16
 
17
17
 
@@ -40,5 +40,5 @@ codec =
40
40
  |> Codec.field "method" .method Codec.string
41
41
  |> Codec.field "headers" .headers (Codec.list (Codec.tuple Codec.string Codec.string))
42
42
  |> Codec.field "body" .body StaticHttpBody.codec
43
- |> Codec.field "useCache" .useCache Codec.bool
43
+ |> Codec.nullableField "cacheOptions" .cacheOptions Codec.value
44
44
  |> Codec.buildObject