elm-pages 2.1.7 → 2.1.11
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/generator/review/elm.json +34 -0
- package/generator/review/src/ReviewConfig.elm +10 -0
- package/generator/src/basepath-middleware.js +15 -9
- package/generator/src/build.js +77 -4
- package/generator/src/cli.js +13 -9
- package/generator/src/compile-elm.js +43 -0
- package/generator/src/dev-server.js +63 -11
- package/generator/src/error-formatter.js +62 -9
- package/generator/src/generate-template-module-connector.js +17 -4
- package/generator/src/init.js +4 -0
- package/generator/src/pre-render-html.js +19 -12
- package/generator/src/render-worker.js +0 -1
- package/generator/src/render.js +1 -2
- package/generator/src/seo-renderer.js +21 -2
- package/generator/static-code/hmr.js +43 -6
- package/generator/template/elm.json +13 -5
- package/generator/template/package.json +3 -2
- package/package.json +14 -8
- package/src/ApiRoute.elm +178 -0
- package/src/AriaLiveAnnouncer.elm +36 -0
- package/src/BuildError.elm +60 -0
- package/src/DataSource/File.elm +288 -0
- package/src/DataSource/Glob.elm +1050 -0
- package/src/DataSource/Http.elm +467 -0
- package/src/DataSource/Internal/Glob.elm +74 -0
- package/src/DataSource/Port.elm +87 -0
- package/src/DataSource/ServerRequest.elm +60 -0
- package/src/DataSource.elm +801 -0
- package/src/Head/Seo.elm +516 -0
- package/src/Head/Twitter.elm +109 -0
- package/src/Head.elm +452 -0
- package/src/HtmlPrinter.elm +27 -0
- package/src/Internal/ApiRoute.elm +89 -0
- package/src/Internal/OptimizedDecoder.elm +18 -0
- package/src/KeepOrDiscard.elm +6 -0
- package/src/OptimizedDecoder/Pipeline.elm +335 -0
- package/src/OptimizedDecoder.elm +818 -0
- package/src/Pages/ContentCache.elm +248 -0
- package/src/Pages/Flags.elm +26 -0
- package/src/Pages/Http.elm +10 -0
- package/src/Pages/Internal/ApplicationType.elm +6 -0
- package/src/Pages/Internal/NotFoundReason.elm +256 -0
- package/src/Pages/Internal/Platform/Cli.elm +1015 -0
- package/src/Pages/Internal/Platform/Effect.elm +14 -0
- package/src/Pages/Internal/Platform/StaticResponses.elm +540 -0
- package/src/Pages/Internal/Platform/ToJsPayload.elm +138 -0
- package/src/Pages/Internal/Platform.elm +745 -0
- package/src/Pages/Internal/RoutePattern.elm +122 -0
- package/src/Pages/Internal/Router.elm +116 -0
- package/src/Pages/Internal/StaticHttpBody.elm +54 -0
- package/src/Pages/Internal/String.elm +39 -0
- package/src/Pages/Manifest/Category.elm +240 -0
- package/src/Pages/Manifest.elm +412 -0
- package/src/Pages/PageUrl.elm +38 -0
- package/src/Pages/ProgramConfig.elm +73 -0
- package/src/Pages/Review/NoContractViolations.elm +397 -0
- package/src/Pages/Secrets.elm +83 -0
- package/src/Pages/SiteConfig.elm +13 -0
- package/src/Pages/StaticHttp/Request.elm +42 -0
- package/src/Pages/StaticHttpRequest.elm +320 -0
- package/src/Pages/Url.elm +60 -0
- package/src/Path.elm +96 -0
- package/src/QueryParams.elm +216 -0
- package/src/RenderRequest.elm +163 -0
- package/src/RequestsAndPending.elm +20 -0
- package/src/Secrets.elm +111 -0
- package/src/SecretsDict.elm +45 -0
- package/src/StructuredData.elm +236 -0
- package/src/TerminalText.elm +242 -0
- package/src/Test/Html/Internal/ElmHtml/Constants.elm +53 -0
- package/src/Test/Html/Internal/ElmHtml/Helpers.elm +17 -0
- package/src/Test/Html/Internal/ElmHtml/InternalTypes.elm +529 -0
- package/src/Test/Html/Internal/ElmHtml/Markdown.elm +56 -0
- package/src/Test/Html/Internal/ElmHtml/ToString.elm +197 -0
- 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
|