elm-pages 2.1.6 → 2.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/generator/review/elm.json +34 -0
  2. package/generator/review/src/ReviewConfig.elm +10 -0
  3. package/generator/src/basepath-middleware.js +15 -9
  4. package/generator/src/build.js +100 -6
  5. package/generator/src/cli.js +13 -9
  6. package/generator/src/compile-elm.js +43 -0
  7. package/generator/src/dev-server.js +63 -11
  8. package/generator/src/error-formatter.js +62 -9
  9. package/generator/src/generate-template-module-connector.js +17 -4
  10. package/generator/src/init.js +4 -0
  11. package/generator/src/pre-render-html.js +19 -12
  12. package/generator/src/render-worker.js +0 -1
  13. package/generator/src/render.js +1 -2
  14. package/generator/src/seo-renderer.js +21 -2
  15. package/generator/static-code/hmr.js +43 -6
  16. package/generator/template/elm-tooling.json +9 -0
  17. package/generator/template/package.json +5 -1
  18. package/package.json +16 -9
  19. package/src/ApiRoute.elm +178 -0
  20. package/src/AriaLiveAnnouncer.elm +36 -0
  21. package/src/BuildError.elm +60 -0
  22. package/src/DataSource/File.elm +288 -0
  23. package/src/DataSource/Glob.elm +1050 -0
  24. package/src/DataSource/Http.elm +467 -0
  25. package/src/DataSource/Internal/Glob.elm +74 -0
  26. package/src/DataSource/Port.elm +87 -0
  27. package/src/DataSource/ServerRequest.elm +60 -0
  28. package/src/DataSource.elm +801 -0
  29. package/src/Head/Seo.elm +516 -0
  30. package/src/Head/Twitter.elm +109 -0
  31. package/src/Head.elm +452 -0
  32. package/src/HtmlPrinter.elm +27 -0
  33. package/src/Internal/ApiRoute.elm +89 -0
  34. package/src/Internal/OptimizedDecoder.elm +18 -0
  35. package/src/KeepOrDiscard.elm +6 -0
  36. package/src/OptimizedDecoder/Pipeline.elm +335 -0
  37. package/src/OptimizedDecoder.elm +818 -0
  38. package/src/Pages/ContentCache.elm +248 -0
  39. package/src/Pages/Flags.elm +26 -0
  40. package/src/Pages/Http.elm +10 -0
  41. package/src/Pages/Internal/ApplicationType.elm +6 -0
  42. package/src/Pages/Internal/NotFoundReason.elm +256 -0
  43. package/src/Pages/Internal/Platform/Cli.elm +1015 -0
  44. package/src/Pages/Internal/Platform/Effect.elm +14 -0
  45. package/src/Pages/Internal/Platform/StaticResponses.elm +540 -0
  46. package/src/Pages/Internal/Platform/ToJsPayload.elm +138 -0
  47. package/src/Pages/Internal/Platform.elm +745 -0
  48. package/src/Pages/Internal/RoutePattern.elm +122 -0
  49. package/src/Pages/Internal/Router.elm +116 -0
  50. package/src/Pages/Internal/StaticHttpBody.elm +54 -0
  51. package/src/Pages/Internal/String.elm +39 -0
  52. package/src/Pages/Manifest/Category.elm +240 -0
  53. package/src/Pages/Manifest.elm +412 -0
  54. package/src/Pages/PageUrl.elm +38 -0
  55. package/src/Pages/ProgramConfig.elm +73 -0
  56. package/src/Pages/Review/NoContractViolations.elm +397 -0
  57. package/src/Pages/Secrets.elm +83 -0
  58. package/src/Pages/SiteConfig.elm +13 -0
  59. package/src/Pages/StaticHttp/Request.elm +42 -0
  60. package/src/Pages/StaticHttpRequest.elm +320 -0
  61. package/src/Pages/Url.elm +60 -0
  62. package/src/Path.elm +96 -0
  63. package/src/QueryParams.elm +216 -0
  64. package/src/RenderRequest.elm +163 -0
  65. package/src/RequestsAndPending.elm +20 -0
  66. package/src/Secrets.elm +111 -0
  67. package/src/SecretsDict.elm +45 -0
  68. package/src/StructuredData.elm +236 -0
  69. package/src/TerminalText.elm +242 -0
  70. package/src/Test/Html/Internal/ElmHtml/Constants.elm +53 -0
  71. package/src/Test/Html/Internal/ElmHtml/Helpers.elm +17 -0
  72. package/src/Test/Html/Internal/ElmHtml/InternalTypes.elm +529 -0
  73. package/src/Test/Html/Internal/ElmHtml/Markdown.elm +56 -0
  74. package/src/Test/Html/Internal/ElmHtml/ToString.elm +197 -0
  75. package/src/Test/Internal/KernelConstants.elm +34 -0
@@ -0,0 +1,397 @@
1
+ module Pages.Review.NoContractViolations exposing (rule)
2
+
3
+ {-|
4
+
5
+ @docs rule
6
+
7
+ -}
8
+
9
+ import Dict exposing (Dict)
10
+ import Elm.Syntax.Declaration as Declaration exposing (Declaration)
11
+ import Elm.Syntax.Exposing as Exposing exposing (Exposing)
12
+ import Elm.Syntax.Module as Module exposing (Module)
13
+ import Elm.Syntax.Node as Node exposing (Node)
14
+ import Elm.Syntax.TypeAnnotation as TypeAnnotation exposing (TypeAnnotation)
15
+ import Review.Rule as Rule exposing (Direction, Error, Rule)
16
+ import Set exposing (Set)
17
+
18
+
19
+ {-| Reports... REPLACEME
20
+
21
+ config =
22
+ [ Pages.Review.NoContractViolations.rule
23
+ ]
24
+
25
+
26
+ ## Fail
27
+
28
+ a =
29
+ "REPLACEME example to replace"
30
+
31
+
32
+ ## Success
33
+
34
+ a =
35
+ "REPLACEME example to replace"
36
+
37
+
38
+ ## When (not) to enable this rule
39
+
40
+ This rule is useful when REPLACEME.
41
+ This rule is not useful when REPLACEME.
42
+
43
+
44
+ ## Try it out
45
+
46
+ You can try this rule out by running the following command:
47
+
48
+ ```bash
49
+ elm-review --template dillonkearns/elm-review-elm-pages/example --rules Pages.Review.NoContractViolations
50
+ ```
51
+
52
+ -}
53
+ rule : Rule
54
+ rule =
55
+ Rule.newModuleRuleSchema "Pages.Review.NoContractViolations"
56
+ { moduleName = []
57
+ , isPageModule = False
58
+ }
59
+ |> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor
60
+ |> Rule.withDeclarationVisitor declarationVisitor
61
+ |> Rule.fromModuleRuleSchema
62
+
63
+
64
+ type alias Context =
65
+ { moduleName : List String
66
+ , isPageModule : Bool
67
+ }
68
+
69
+
70
+ moduleDefinitionVisitor : Node Module -> Context -> ( List (Error {}), Context )
71
+ moduleDefinitionVisitor node _ =
72
+ let
73
+ isPageModule : Bool
74
+ isPageModule =
75
+ (Node.value node |> Module.moduleName |> List.take 1)
76
+ == [ "Page" ]
77
+ && ((Node.value node |> Module.moduleName |> List.length) > 1)
78
+ in
79
+ case Node.value node |> Module.exposingList of
80
+ Exposing.All _ ->
81
+ ( []
82
+ , { moduleName = Node.value node |> Module.moduleName
83
+ , isPageModule = isPageModule
84
+ }
85
+ )
86
+
87
+ Exposing.Explicit exposedValues ->
88
+ if isPageModule then
89
+ case Set.diff (Set.fromList [ "Data", "Msg", "Model", "page" ]) (exposedNames exposedValues) |> Set.toList of
90
+ [] ->
91
+ ( []
92
+ , { moduleName = Node.value node |> Module.moduleName
93
+ , isPageModule = isPageModule
94
+ }
95
+ )
96
+
97
+ nonEmpty ->
98
+ ( [ Rule.error
99
+ { message = "Unexposed Declaration in Page Module"
100
+ , details =
101
+ [ """Page Modules need to expose the following values:
102
+
103
+ - page
104
+ - Data
105
+ - Model
106
+ - Msg
107
+
108
+ But it is not exposing: """
109
+ ++ (nonEmpty |> String.join ", ")
110
+ ]
111
+ }
112
+ (Node.range (exposingListNode (Node.value node)))
113
+ ]
114
+ , { moduleName = Node.value node |> Module.moduleName
115
+ , isPageModule = isPageModule
116
+ }
117
+ )
118
+
119
+ else
120
+ ( []
121
+ , { moduleName = Node.value node |> Module.moduleName
122
+ , isPageModule = isPageModule
123
+ }
124
+ )
125
+
126
+
127
+ routeParamsMatchesNameOrError : Node TypeAnnotation -> List String -> List (Error {})
128
+ routeParamsMatchesNameOrError annotation moduleName =
129
+ case stringFields annotation of
130
+ Err error ->
131
+ [ error ]
132
+
133
+ Ok actualStringFields ->
134
+ let
135
+ expectedFields : Dict String Param
136
+ expectedFields =
137
+ expectedRouteParamsFromModuleName moduleName
138
+ in
139
+ if actualStringFields == (expectedFields |> Dict.map (\_ value -> Ok value)) then
140
+ []
141
+
142
+ else
143
+ [ Rule.error
144
+ { message = "RouteParams don't match Page Module name"
145
+ , details =
146
+ [ """Expected
147
+
148
+ """
149
+ ++ expectedFieldsToRecordString expectedFields
150
+ ++ "\n"
151
+ ]
152
+ }
153
+ (Node.range annotation)
154
+ ]
155
+
156
+
157
+ expectedFieldsToRecordString : Dict String Param -> String
158
+ expectedFieldsToRecordString expectedFields =
159
+ "type alias RouteParams = { "
160
+ ++ (expectedFields
161
+ |> Dict.toList
162
+ |> List.map (\( name, param ) -> name ++ " : " ++ paramToTypeString param)
163
+ |> String.join ", "
164
+ )
165
+ ++ " }"
166
+
167
+
168
+ paramToTypeString : Param -> String
169
+ paramToTypeString param =
170
+ case param of
171
+ Required ->
172
+ "String"
173
+
174
+ Optional ->
175
+ "Maybe String"
176
+
177
+ RequiredSplat ->
178
+ "( String, List String )"
179
+
180
+ OptionalSplat ->
181
+ "List String"
182
+
183
+
184
+ expectedRouteParamsFromModuleName : List String -> Dict String Param
185
+ expectedRouteParamsFromModuleName moduleSegments =
186
+ case moduleSegments of
187
+ "Page" :: segments ->
188
+ segments
189
+ |> List.filterMap segmentToParam
190
+ |> Dict.fromList
191
+
192
+ _ ->
193
+ Dict.empty
194
+
195
+
196
+ type Param
197
+ = Required
198
+ | Optional
199
+ | RequiredSplat
200
+ | OptionalSplat
201
+
202
+
203
+ segmentToParam : String -> Maybe ( String, Param )
204
+ segmentToParam segment =
205
+ if segment == "SPLAT__" then
206
+ ( "splat"
207
+ , OptionalSplat
208
+ )
209
+ |> Just
210
+
211
+ else if segment == "SPLAT_" then
212
+ ( "splat"
213
+ , RequiredSplat
214
+ )
215
+ |> Just
216
+
217
+ else if segment |> String.endsWith "__" then
218
+ ( segment
219
+ |> String.dropRight 2
220
+ |> decapitalize
221
+ , Optional
222
+ )
223
+ |> Just
224
+
225
+ else if segment |> String.endsWith "_" then
226
+ ( segment
227
+ |> String.dropRight 1
228
+ |> decapitalize
229
+ , Required
230
+ )
231
+ |> Just
232
+
233
+ else
234
+ Nothing
235
+
236
+
237
+ {-| Decapitalize the first letter of a string.
238
+ decapitalize "This is a phrase" == "this is a phrase"
239
+ decapitalize "Hello, World" == "hello, World"
240
+ -}
241
+ decapitalize : String -> String
242
+ decapitalize word =
243
+ -- Source: https://github.com/elm-community/string-extra/blob/4.0.1/src/String/Extra.elm
244
+ changeCase Char.toLower word
245
+
246
+
247
+ {-| Change the case of the first letter of a string to either uppercase or
248
+ lowercase, depending of the value of `wantedCase`. This is an internal
249
+ function for use in `toSentenceCase` and `decapitalize`.
250
+ -}
251
+ changeCase : (Char -> Char) -> String -> String
252
+ changeCase mutator word =
253
+ -- Source: https://github.com/elm-community/string-extra/blob/4.0.1/src/String/Extra.elm
254
+ String.uncons word
255
+ |> Maybe.map (\( head, tail ) -> String.cons (mutator head) tail)
256
+ |> Maybe.withDefault ""
257
+
258
+
259
+ stringFields :
260
+ Node TypeAnnotation
261
+ -> Result (Error {}) (Dict String (Result (Node TypeAnnotation) Param))
262
+ stringFields typeAnnotation =
263
+ case Node.value typeAnnotation of
264
+ TypeAnnotation.Record recordDefinition ->
265
+ let
266
+ fields : Dict String (Result (Node TypeAnnotation) Param)
267
+ fields =
268
+ recordDefinition
269
+ |> List.map Node.value
270
+ |> List.map
271
+ (\( name, annotation ) ->
272
+ ( Node.value name, paramType annotation )
273
+ )
274
+ |> Dict.fromList
275
+ in
276
+ Ok fields
277
+
278
+ _ ->
279
+ Err
280
+ (Rule.error
281
+ { message = "RouteParams must be a record type alias."
282
+ , details =
283
+ [ """Expected a record type alias."""
284
+ ]
285
+ }
286
+ (Node.range typeAnnotation)
287
+ )
288
+
289
+
290
+ paramType : Node TypeAnnotation -> Result (Node TypeAnnotation) Param
291
+ paramType typeAnnotation =
292
+ case Node.value typeAnnotation of
293
+ TypeAnnotation.Tupled [ first, second ] ->
294
+ case ( Node.value first, Node.value second ) of
295
+ ( TypeAnnotation.Typed firstType [], TypeAnnotation.Typed secondType [ listType ] ) ->
296
+ if
297
+ (Node.value firstType == ( [], "String" ))
298
+ && (Node.value secondType == ( [], "List" ))
299
+ && (Node.value listType |> isString)
300
+ then
301
+ Ok RequiredSplat
302
+
303
+ else
304
+ Err typeAnnotation
305
+
306
+ _ ->
307
+ Err typeAnnotation
308
+
309
+ TypeAnnotation.Typed moduleContext innerType ->
310
+ -- TODO need to use module lookup table to handle Basics or aliases?
311
+ case ( Node.value moduleContext, innerType ) of
312
+ ( ( [], "String" ), [] ) ->
313
+ Ok Required
314
+
315
+ ( ( [], "Maybe" ), [ maybeOf ] ) ->
316
+ if isString (Node.value maybeOf) then
317
+ Ok Optional
318
+
319
+ else
320
+ Err typeAnnotation
321
+
322
+ ( ( [], "List" ), [ listOf ] ) ->
323
+ if isString (Node.value listOf) then
324
+ Ok OptionalSplat
325
+
326
+ else
327
+ Err typeAnnotation
328
+
329
+ _ ->
330
+ Ok Optional
331
+
332
+ _ ->
333
+ Err typeAnnotation
334
+
335
+
336
+ isString : TypeAnnotation -> Bool
337
+ isString typeAnnotation =
338
+ case typeAnnotation of
339
+ TypeAnnotation.Typed moduleContext [] ->
340
+ -- TODO need to use module lookup table to handle Basics or aliases?
341
+ Node.value moduleContext == ( [], "String" )
342
+
343
+ _ ->
344
+ False
345
+
346
+
347
+ declarationVisitor : Node Declaration -> Direction -> Context -> ( List (Error {}), Context )
348
+ declarationVisitor node direction context =
349
+ case ( direction, Node.value node ) of
350
+ ( Rule.OnEnter, Declaration.AliasDeclaration { name, typeAnnotation } ) ->
351
+ -- TODO check that generics is empty
352
+ if context.isPageModule && Node.value name == "RouteParams" then
353
+ ( routeParamsMatchesNameOrError typeAnnotation context.moduleName
354
+ , context
355
+ )
356
+
357
+ else
358
+ ( [], context )
359
+
360
+ _ ->
361
+ ( [], context )
362
+
363
+
364
+ exposedNames : List (Node Exposing.TopLevelExpose) -> Set String
365
+ exposedNames exposedValues =
366
+ exposedValues
367
+ |> List.filterMap (Node.value >> getExposedName)
368
+ |> Set.fromList
369
+
370
+
371
+ getExposedName : Exposing.TopLevelExpose -> Maybe String
372
+ getExposedName exposedValue =
373
+ case exposedValue of
374
+ Exposing.FunctionExpose name ->
375
+ Just name
376
+
377
+ Exposing.InfixExpose _ ->
378
+ Nothing
379
+
380
+ Exposing.TypeOrAliasExpose name ->
381
+ Just name
382
+
383
+ Exposing.TypeExpose exposedType ->
384
+ Just exposedType.name
385
+
386
+
387
+ exposingListNode : Module -> Node Exposing
388
+ exposingListNode m =
389
+ case m of
390
+ Module.NormalModule x ->
391
+ x.exposingList
392
+
393
+ Module.PortModule x ->
394
+ x.exposingList
395
+
396
+ Module.EffectModule x ->
397
+ x.exposingList
@@ -0,0 +1,83 @@
1
+ module Pages.Secrets exposing (Value, map, succeed, with)
2
+
3
+ {-| Secrets are a secure way to use environment variables in your DataSource.Http requests. The actual environment
4
+ variable value is used to perform DataSource.Http requests, while the masked value is the only thing that ends up in your
5
+ built site. Let's go through what happens in a concrete example:
6
+
7
+
8
+ ## Example
9
+
10
+ Let's say you execute this from the shell:
11
+
12
+ ```shell
13
+ GITHUB_TOKEN=abcd1234 API_KEY=xyz789 elm-pages build
14
+ ```
15
+
16
+ And your DataSource.Http request in your Elm code looks like this:
17
+
18
+ import Pages.Secrets as Secrets
19
+ import DataSource.Http
20
+
21
+ DataSource.Http.request
22
+ (Secrets.succeed
23
+ (\apiKey githubToken ->
24
+ { url = "https://api.github.com/repos/dillonkearns/elm-pages?apiKey=" ++ apiKey
25
+ , method = "GET"
26
+ , headers = [ ( "Authorization", "Bearer " ++ githubToken ) ]
27
+ , body = DataSource.Http.emptyBody
28
+ }
29
+ )
30
+ |> Secrets.with "API_KEY"
31
+ |> Secrets.with "BEARER"
32
+ )
33
+ (Decode.succeed ())
34
+ )
35
+
36
+ The following masked values are what will be visible in your production bundle if you inspect the code or the Network tab:
37
+
38
+ [GET]https://api.github.com/repos/dillonkearns/elm-pages?apiKey=<API_KEY>Authorization : Bearer <BEARER>
39
+
40
+ So the actual Secrets only exist for the duration of the build in order to perform the DataSource.Http requests, but they
41
+ are replaced with `<SECRET_NAME>` once that step is done and your assets are bundled.
42
+
43
+ @docs Value, map, succeed, with
44
+
45
+ -}
46
+
47
+ import Secrets
48
+
49
+
50
+ {-| Represents a Secure value from your environment variables. `Pages.Secrets.Value`s are much like `Json.Decode.Value`s
51
+ in that you can take raw values, map them, and combine them with other values into any data structure.
52
+ -}
53
+ type alias Value value =
54
+ Secrets.Value value
55
+
56
+
57
+ {-| Hardcode a secret value. Or, this can be used to start a pipeline-style value with several different secrets (see
58
+ the example at the top of this page).
59
+
60
+ Warning: a hardcoded value is not protected by masking! Make sure to to use `Secrets.with` to fetch sentitive values from environment variables.
61
+
62
+ import Pages.Secrets as Secrets
63
+
64
+ Secrets.succeed "hardcoded-secret"
65
+
66
+ -}
67
+ succeed : value -> Value value
68
+ succeed =
69
+ Secrets.succeed
70
+
71
+
72
+ {-| Map a Secret's raw value into an arbitrary type or value.
73
+ -}
74
+ map : (valueA -> valueB) -> Value valueA -> Value valueB
75
+ map =
76
+ Secrets.map
77
+
78
+
79
+ {-| Allows you to chain together multiple secrets. See the top of this page for a full example.
80
+ -}
81
+ with : String -> Value (String -> value) -> Value value
82
+ with =
83
+ Secrets.with
@@ -0,0 +1,13 @@
1
+ module Pages.SiteConfig exposing (SiteConfig)
2
+
3
+ import DataSource exposing (DataSource)
4
+ import Head
5
+ import Pages.Manifest
6
+
7
+
8
+ type alias SiteConfig data =
9
+ { data : DataSource data
10
+ , canonicalUrl : String
11
+ , manifest : data -> Pages.Manifest.Config
12
+ , head : data -> List Head.Tag
13
+ }
@@ -0,0 +1,42 @@
1
+ module Pages.StaticHttp.Request exposing (Request, codec, hash)
2
+
3
+ import Codec exposing (Codec)
4
+ import Json.Encode as Encode
5
+ import Murmur3
6
+ import Pages.Internal.StaticHttpBody as StaticHttpBody exposing (Body)
7
+
8
+
9
+ type alias Request =
10
+ { url : String
11
+ , method : String
12
+ , headers : List ( String, String )
13
+ , body : Body
14
+ }
15
+
16
+
17
+ hash : Request -> String
18
+ hash requestDetails =
19
+ Encode.object
20
+ [ ( "method", Encode.string requestDetails.method )
21
+ , ( "url", Encode.string requestDetails.url )
22
+ , ( "headers", Encode.list hashHeader requestDetails.headers )
23
+ , ( "body", StaticHttpBody.encode requestDetails.body )
24
+ ]
25
+ |> Encode.encode 0
26
+ |> Murmur3.hashString 0
27
+ |> String.fromInt
28
+
29
+
30
+ hashHeader : ( String, String ) -> Encode.Value
31
+ hashHeader ( name, value ) =
32
+ Encode.string <| name ++ ": " ++ value
33
+
34
+
35
+ codec : Codec Request
36
+ codec =
37
+ Codec.object Request
38
+ |> Codec.field "url" .url Codec.string
39
+ |> Codec.field "method" .method Codec.string
40
+ |> Codec.field "headers" .headers (Codec.list (Codec.tuple Codec.string Codec.string))
41
+ |> Codec.field "body" .body StaticHttpBody.codec
42
+ |> Codec.buildObject