elm-pages 3.0.0-beta.40 → 3.0.0-beta.42

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 (40) hide show
  1. package/README.md +1 -1
  2. package/codegen/elm-pages-codegen.cjs +251 -285
  3. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  6. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  7. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  8. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
  9. package/generator/src/RouteBuilder.elm +19 -60
  10. package/generator/src/SharedTemplate.elm +5 -5
  11. package/generator/src/compatibility-key.js +2 -2
  12. package/package.json +2 -2
  13. package/src/ApiRoute.elm +3 -31
  14. package/src/BackendTask.elm +18 -24
  15. package/src/FormData.elm +21 -1
  16. package/src/Head/Seo.elm +4 -4
  17. package/src/Internal/Request.elm +84 -4
  18. package/src/Pages/ConcurrentSubmission.elm +127 -0
  19. package/src/Pages/Form.elm +151 -40
  20. package/src/Pages/FormData.elm +19 -0
  21. package/src/Pages/Internal/NotFoundReason.elm +4 -4
  22. package/src/Pages/Internal/Platform/Cli.elm +30 -17
  23. package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
  24. package/src/Pages/Internal/Platform.elm +39 -38
  25. package/src/Pages/Internal/ResponseSketch.elm +2 -2
  26. package/src/Pages/Manifest.elm +23 -7
  27. package/src/Pages/Navigation.elm +85 -0
  28. package/src/Pages/PageUrl.elm +3 -3
  29. package/src/Pages/ProgramConfig.elm +13 -11
  30. package/src/Pages/Script.elm +64 -7
  31. package/src/Pages/Url.elm +3 -3
  32. package/src/PagesMsg.elm +9 -3
  33. package/src/RenderRequest.elm +7 -7
  34. package/src/Scaffold/Form.elm +28 -5
  35. package/src/Scaffold/Route.elm +82 -53
  36. package/src/Server/Request.elm +446 -952
  37. package/src/Server/Session.elm +141 -91
  38. package/src/Server/SetCookie.elm +71 -31
  39. package/src/{Path.elm → UrlPath.elm} +21 -21
  40. package/src/Pages/Transition.elm +0 -79
@@ -4,43 +4,48 @@ module Server.Session exposing
4
4
  , Session, empty, get, insert, remove, update, withFlash
5
5
  )
6
6
 
7
- {-| You can manage server state with HTTP cookies using this Server.Session API. Server-rendered pages define a `Server.Request.Parser`
8
- to choose which requests to respond to and how to extract structured data from the incoming request.
7
+ {-| You can manage server state with HTTP cookies using this Server.Session API. Server-rendered routes have a `Server.Request.Request`
8
+ argument that lets you inspect the incoming HTTP request, and return a response using the `Server.Response.Response` type.
9
9
 
10
+ This API provides a higher-level abstraction for extracting data from the HTTP request, and setting data in the HTTP response.
11
+ It manages the session through key-value data stored in cookies, and lets you [`insert`](#insert), [`update`](#update), and [`remove`](#remove)
12
+ values from the Session. It also provides an abstraction for flash session values through [`withFlash`](#withFlash).
10
13
 
11
- ## Using Sessions in a Request.Parser
14
+
15
+ ## Using Sessions
12
16
 
13
17
  Using these functions, you can store and read session data in cookies to maintain state between requests.
14
- For example, TODO:
15
-
16
- action : RouteParams -> Request.Parser (BackendTask (Response ActionData ErrorPage))
17
- action routeParams =
18
- MySession.withSession
19
- (Request.formDataWithServerValidation (form |> Form.initCombinedServer identity))
20
- (\nameResultData session ->
21
- nameResultData
22
- |> BackendTask.map
23
- (\nameResult ->
24
- case nameResult of
25
- Err errors ->
26
- ( session
27
- |> Result.withDefault Nothing
28
- |> Maybe.withDefault Session.empty
29
- , Response.render
30
- { errors = errors
31
- }
32
- )
33
18
 
34
- Ok ( _, name ) ->
35
- ( session
36
- |> Result.withDefault Nothing
37
- |> Maybe.withDefault Session.empty
38
- |> Session.insert "name" name
39
- |> Session.withFlash "message" ("Welcome " ++ name ++ "!")
40
- , Route.redirectTo Route.Greet
41
- )
42
- )
43
- )
19
+ import Server.Session as Session
20
+
21
+ secrets : BackendTask FatalError (List String)
22
+ secrets =
23
+ Env.expect "SESSION_SECRET"
24
+ |> BackendTask.allowFatal
25
+ |> BackendTask.map List.singleton
26
+
27
+ type alias Data =
28
+ { darkMode : Bool }
29
+
30
+ data : RouteParams -> Request -> BackendTask (Response Data ErrorPage)
31
+ data routeParams request =
32
+ request
33
+ |> Session.withSession
34
+ { name = "mysession"
35
+ , secrets = secrets
36
+ , options = Nothing
37
+ }
38
+ (\session ->
39
+ let
40
+ darkMode : Bool
41
+ darkMode =
42
+ (session |> Session.get "mode" |> Maybe.withDefault "light")
43
+ == "dark"
44
+ in
45
+ ( session
46
+ , { darkMode = darkMode }
47
+ )
48
+ )
44
49
 
45
50
  The elm-pages framework will manage signing these cookies using the `secrets : BackendTask (List String)` you pass in.
46
51
  That means that the values you set in your session will be directly visible to anyone who has access to the cookie
@@ -113,12 +118,17 @@ import BackendTask.Internal.Request
113
118
  import Dict exposing (Dict)
114
119
  import Json.Decode
115
120
  import Json.Encode
116
- import Server.Request
121
+ import Server.Request exposing (Request)
117
122
  import Server.Response exposing (Response)
118
123
  import Server.SetCookie as SetCookie
119
124
 
120
125
 
121
- {-| -}
126
+ {-| Represents a Session with key-value Strings.
127
+
128
+ Use with `withSession` to read in the `Session`, and encode any changes you make to the `Session` back through cookie storage
129
+ via the outgoing HTTP response.
130
+
131
+ -}
122
132
  type Session
123
133
  = Session (Dict String Value)
124
134
 
@@ -130,7 +140,12 @@ type Value
130
140
  | NewFlash String
131
141
 
132
142
 
133
- {-| -}
143
+ {-| Flash session values are values that are only available for the next request.
144
+
145
+ session
146
+ |> Session.withFlash "message" "Your payment was successful!"
147
+
148
+ -}
134
149
  withFlash : String -> String -> Session -> Session
135
150
  withFlash key value (Session session) =
136
151
  session
@@ -138,7 +153,12 @@ withFlash key value (Session session) =
138
153
  |> Session
139
154
 
140
155
 
141
- {-| -}
156
+ {-| Insert a value under the given key in the `Session`.
157
+
158
+ session
159
+ |> Session.insert "mode" "dark"
160
+
161
+ -}
142
162
  insert : String -> String -> Session -> Session
143
163
  insert key value (Session session) =
144
164
  session
@@ -146,7 +166,15 @@ insert key value (Session session) =
146
166
  |> Session
147
167
 
148
168
 
149
- {-| -}
169
+ {-| Retrieve a String value from the session for the given key (or `Nothing` if the key is not present).
170
+
171
+ (session
172
+ |> Session.get "mode"
173
+ |> Maybe.withDefault "light"
174
+ )
175
+ == "dark"
176
+
177
+ -}
150
178
  get : String -> Session -> Maybe String
151
179
  get key (Session session) =
152
180
  session
@@ -168,7 +196,25 @@ unwrap value =
168
196
  string
169
197
 
170
198
 
171
- {-| -}
199
+ {-| Update the `Session`, given a `Maybe String` of the current value for the given key, and returning a `Maybe String`.
200
+
201
+ If you return `Nothing`, the key-value pair will be removed from the `Session` (or left out if it didn't exist in the first place).
202
+
203
+ session
204
+ |> Session.update "mode"
205
+ (\mode ->
206
+ case mode of
207
+ Just "dark" ->
208
+ Just "light"
209
+
210
+ Just "light" ->
211
+ Just "dark"
212
+
213
+ Nothing ->
214
+ Just "dark"
215
+ )
216
+
217
+ -}
172
218
  update : String -> (Maybe String -> Maybe String) -> Session -> Session
173
219
  update key updateFn (Session session) =
174
220
  session
@@ -192,7 +238,8 @@ update key updateFn (Session session) =
192
238
  |> Session
193
239
 
194
240
 
195
- {-| -}
241
+ {-| Remove a key from the `Session`.
242
+ -}
196
243
  remove : String -> Session -> Session
197
244
  remove key (Session session) =
198
245
  session
@@ -200,13 +247,15 @@ remove key (Session session) =
200
247
  |> Session
201
248
 
202
249
 
203
- {-| -}
250
+ {-| An empty `Session` with no key-value pairs.
251
+ -}
204
252
  empty : Session
205
253
  empty =
206
254
  Session Dict.empty
207
255
 
208
256
 
209
- {-| -}
257
+ {-| [`withSessionResult`](#withSessionResult) will return a `Result` with this type if it can't load a session.
258
+ -}
210
259
  type NotLoadedReason
211
260
  = NoSessionCookie
212
261
  | InvalidSessionCookie
@@ -239,65 +288,67 @@ flashPrefix =
239
288
  "__flash__"
240
289
 
241
290
 
242
- {-| -}
291
+ {-| The main function for using sessions. If you need more fine-grained control over cases where a session can't be loaded, see
292
+ [`withSessionResult`](#withSessionResult).
293
+ -}
243
294
  withSession :
244
295
  { name : String
245
296
  , secrets : BackendTask error (List String)
246
297
  , options : Maybe SetCookie.Options
247
298
  }
248
- -> (request -> Session -> BackendTask error ( Session, Response data errorPage ))
249
- -> Server.Request.Parser request
250
- -> Server.Request.Parser (BackendTask error (Response data errorPage))
251
- withSession config toRequest userRequest =
252
- withSessionResult config
253
- (\request session ->
254
- toRequest request
255
- (session
299
+ -> (Session -> BackendTask error ( Session, Response data errorPage ))
300
+ -> Request
301
+ -> BackendTask error (Response data errorPage)
302
+ withSession config toRequest request_ =
303
+ request_
304
+ |> withSessionResult config
305
+ (\session ->
306
+ session
256
307
  |> Result.withDefault empty
257
- )
258
- )
259
- userRequest
308
+ |> toRequest
309
+ )
260
310
 
261
311
 
262
- {-| -}
312
+ {-| Same as `withSession`, but gives you an `Err` with the reason why the Session couldn't be loaded instead of
313
+ using `Session.empty` as a default in the cases where there is an error loading the session.
314
+
315
+ A session won't load if there is no session, or if it cannot be unsigned with your secrets. This could be because the cookie was tampered with
316
+ or otherwise corrupted, or because the cookie was signed with a secret that is no longer in the rotation.
317
+
318
+ -}
263
319
  withSessionResult :
264
320
  { name : String
265
321
  , secrets : BackendTask error (List String)
266
322
  , options : Maybe SetCookie.Options
267
323
  }
268
- -> (request -> Result NotLoadedReason Session -> BackendTask error ( Session, Response data errorPage ))
269
- -> Server.Request.Parser request
270
- -> Server.Request.Parser (BackendTask error (Response data errorPage))
271
- withSessionResult config toRequest userRequest =
272
- Server.Request.map2
273
- (\maybeSessionCookie userRequestData ->
274
- let
275
- unsigned : BackendTask error (Result NotLoadedReason Session)
276
- unsigned =
277
- case maybeSessionCookie of
278
- Just sessionCookie ->
279
- sessionCookie
280
- |> unsignCookie config
281
- |> BackendTask.map
282
- (\unsignResult ->
283
- case unsignResult of
284
- Ok decoded ->
285
- Ok decoded
286
-
287
- Err () ->
288
- Err InvalidSessionCookie
289
- )
324
+ -> (Result NotLoadedReason Session -> BackendTask error ( Session, Response data errorPage ))
325
+ -> Request
326
+ -> BackendTask error (Response data errorPage)
327
+ withSessionResult config toTask request =
328
+ let
329
+ unsigned : BackendTask error (Result NotLoadedReason Session)
330
+ unsigned =
331
+ case Server.Request.cookie config.name request of
332
+ Just sessionCookie ->
333
+ sessionCookie
334
+ |> unsignCookie config
335
+ |> BackendTask.map
336
+ (\unsignResult ->
337
+ case unsignResult of
338
+ Ok decoded ->
339
+ Ok decoded
340
+
341
+ Err () ->
342
+ Err InvalidSessionCookie
343
+ )
290
344
 
291
- Nothing ->
292
- Err NoSessionCookie
293
- |> BackendTask.succeed
294
- in
295
- unsigned
296
- |> BackendTask.andThen
297
- (encodeSessionUpdate config toRequest userRequestData)
298
- )
299
- (Server.Request.cookie config.name)
300
- userRequest
345
+ Nothing ->
346
+ Err NoSessionCookie
347
+ |> BackendTask.succeed
348
+ in
349
+ unsigned
350
+ |> BackendTask.andThen
351
+ (encodeSessionUpdate config toTask)
301
352
 
302
353
 
303
354
  encodeSessionUpdate :
@@ -305,20 +356,19 @@ encodeSessionUpdate :
305
356
  , secrets : BackendTask error (List String)
306
357
  , options : Maybe SetCookie.Options
307
358
  }
308
- -> (c -> d -> BackendTask error ( Session, Response data errorPage ))
309
- -> c
359
+ -> (d -> BackendTask error ( Session, Response data errorPage ))
310
360
  -> d
311
361
  -> BackendTask error (Response data errorPage)
312
- encodeSessionUpdate config toRequest userRequestData sessionResult =
362
+ encodeSessionUpdate config toRequest sessionResult =
313
363
  sessionResult
314
- |> toRequest userRequestData
364
+ |> toRequest
315
365
  |> BackendTask.andThen
316
366
  (\( sessionUpdate, response ) ->
317
367
  BackendTask.map
318
368
  (\encoded ->
319
369
  response
320
370
  |> Server.Response.withSetCookieHeader
321
- (SetCookie.setCookie config.name encoded (config.options |> Maybe.withDefault SetCookie.initOptions))
371
+ (SetCookie.setCookie config.name encoded (config.options |> Maybe.withDefault SetCookie.options))
322
372
  )
323
373
  (sign config.secrets
324
374
  (encodeNonExpiringPairs sessionUpdate)
@@ -1,8 +1,8 @@
1
1
  module Server.SetCookie exposing
2
- ( SetCookie
3
- , SameSite(..)
4
- , Options, initOptions
5
- , withImmediateExpiration, makeVisibleToJavaScript, nonSecure, setCookie, withDomain, withExpiration, withMaxAge, withPath, withoutPath, withSameSite
2
+ ( SetCookie, setCookie
3
+ , Options, options
4
+ , SameSite(..), withSameSite
5
+ , withImmediateExpiration, makeVisibleToJavaScript, nonSecure, withDomain, withExpiration, withMaxAge, withPath, withoutPath
6
6
  , toString
7
7
  )
8
8
 
@@ -20,16 +20,29 @@ You can learn more about the basics of cookies in the Web Platform in these help
20
20
  - <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie>
21
21
  - <https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies>
22
22
 
23
- @docs SetCookie
23
+ @docs SetCookie, setCookie
24
24
 
25
- @docs SameSite
26
25
 
26
+ ## Building Options
27
27
 
28
- ## Options
28
+ Usually you'll want to start by creating default `Options` with `options` and then overriding defaults using the `with...` helpers.
29
29
 
30
- @docs Options, initOptions
30
+ import Server.SetCookie as SetCookie
31
31
 
32
- @docs withImmediateExpiration, makeVisibleToJavaScript, nonSecure, setCookie, withDomain, withExpiration, withMaxAge, withPath, withoutPath, withSameSite
32
+ options : SetCookie.Options
33
+ options =
34
+ SetCookie.options
35
+ |> SetCookie.nonSecure
36
+ |> SetCookie.withMaxAge 123
37
+ |> SetCookie.makeVisibleToJavaScript
38
+ |> SetCookie.withoutPath
39
+ |> SetCookie.setCookie "id" "a3fWa"
40
+
41
+ @docs Options, options
42
+
43
+ @docs SameSite, withSameSite
44
+
45
+ @docs withImmediateExpiration, makeVisibleToJavaScript, nonSecure, withDomain, withExpiration, withMaxAge, withPath, withoutPath
33
46
 
34
47
 
35
48
  ## Internal
@@ -51,7 +64,8 @@ type alias SetCookie =
51
64
  }
52
65
 
53
66
 
54
- {-| -}
67
+ {-| The set of possible configuration options. You can configure this record directly, or use the `with...` helpers.
68
+ -}
55
69
  type alias Options =
56
70
  { expiration : Maybe Time.Posix
57
71
  , visibleToJavaScript : Bool
@@ -63,7 +77,15 @@ type alias Options =
63
77
  }
64
78
 
65
79
 
66
- {-| -}
80
+ {-| Possible values for [the cookie's same-site value](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value).
81
+
82
+ The default option is [`Lax`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#lax) (Lax does not send
83
+ cookies in cross-origin requests so it is a good default for most cases, but [`Strict`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#strict)
84
+ is even more restrictive).
85
+
86
+ Override the default option using [`withSameSite`](#withSameSite).
87
+
88
+ -}
67
89
  type SameSite
68
90
  = Strict
69
91
  | Lax
@@ -95,24 +117,24 @@ toString builder =
95
117
  else
96
118
  ""
97
119
 
98
- options : Options
99
- options =
120
+ options_ : Options
121
+ options_ =
100
122
  builder.options
101
123
 
102
124
  httpOnly : Bool
103
125
  httpOnly =
104
- not options.visibleToJavaScript
126
+ not options_.visibleToJavaScript
105
127
  in
106
128
  builder.name
107
129
  ++ "="
108
130
  ++ Url.percentEncode builder.value
109
- ++ option "Expires" (options.expiration |> Maybe.map Utc.fromTime)
110
- ++ option "Max-Age" (options.maxAge |> Maybe.map String.fromInt)
111
- ++ option "Path" options.path
112
- ++ option "Domain" options.domain
113
- ++ option "SameSite" (options.sameSite |> Maybe.map sameSiteToString)
131
+ ++ option "Expires" (options_.expiration |> Maybe.map Utc.fromTime)
132
+ ++ option "Max-Age" (options_.maxAge |> Maybe.map String.fromInt)
133
+ ++ option "Path" options_.path
134
+ ++ option "Domain" options_.domain
135
+ ++ option "SameSite" (options_.sameSite |> Maybe.map sameSiteToString)
114
136
  ++ boolOption "HttpOnly" httpOnly
115
- ++ boolOption "Secure" options.secure
137
+ ++ boolOption "Secure" options_.secure
116
138
 
117
139
 
118
140
  sameSiteToString : SameSite -> String
@@ -128,18 +150,22 @@ sameSiteToString sameSite =
128
150
  "None"
129
151
 
130
152
 
131
- {-| -}
153
+ {-| Create a `SetCookie` record with the given name, value, and [`Options`](Options]. To add a `Set-Cookie` header, you can
154
+ pass this value with [`Server.Response.withSetCookieHeader`](Server-Response#withSetCookieHeader). Or for more low-level
155
+ uses you can stringify the value manually with [`toString`](#toString).
156
+ -}
132
157
  setCookie : String -> String -> Options -> SetCookie
133
- setCookie name value options =
158
+ setCookie name value options_ =
134
159
  { name = name
135
160
  , value = value
136
- , options = options
161
+ , options = options_
137
162
  }
138
163
 
139
164
 
140
- {-| -}
141
- initOptions : Options
142
- initOptions =
165
+ {-| Initialize the default `SetCookie` `Options`. Can be configured directly through a record update, or with `withExpiration`, etc.
166
+ -}
167
+ options : Options
168
+ options =
143
169
  { expiration = Nothing
144
170
  , visibleToJavaScript = False
145
171
  , maxAge = Nothing
@@ -158,7 +184,9 @@ withExpiration time builder =
158
184
  }
159
185
 
160
186
 
161
- {-| -}
187
+ {-| Sets [`Expires`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#expiresdate) to `Time.millisToPosix 0`,
188
+ which effectively tells the browser to delete the cookie immediately (by giving it an expiration date in the past).
189
+ -}
162
190
  withImmediateExpiration : Options -> Options
163
191
  withImmediateExpiration builder =
164
192
  { builder
@@ -184,7 +212,8 @@ makeVisibleToJavaScript builder =
184
212
  }
185
213
 
186
214
 
187
- {-| -}
215
+ {-| Sets the `Set-Cookie`'s [`Max-Age`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#max-agenumber).
216
+ -}
188
217
  withMaxAge : Int -> Options -> Options
189
218
  withMaxAge maxAge builder =
190
219
  { builder
@@ -192,7 +221,11 @@ withMaxAge maxAge builder =
192
221
  }
193
222
 
194
223
 
195
- {-| -}
224
+ {-| Sets the `Set-Cookie`'s [`Path`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value).
225
+
226
+ The default value is `/`, which will match any sub-directories or the root directory. See also [\`withoutPath](#withoutPath)
227
+
228
+ -}
196
229
  withPath : String -> Options -> Options
197
230
  withPath path builder =
198
231
  { builder
@@ -200,7 +233,13 @@ withPath path builder =
200
233
  }
201
234
 
202
235
 
203
- {-| -}
236
+ {-|
237
+
238
+ > If the server omits the Path attribute, the user agent will use the "directory" of the request-uri's path component as the default value.
239
+
240
+ Source: <https://www.rfc-editor.org/rfc/rfc6265>. See <https://stackoverflow.com/a/43336097>.
241
+
242
+ -}
204
243
  withoutPath : Options -> Options
205
244
  withoutPath builder =
206
245
  { builder
@@ -208,7 +247,8 @@ withoutPath builder =
208
247
  }
209
248
 
210
249
 
211
- {-| -}
250
+ {-| Sets the `Set-Cookie`'s [`Domain`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#domaindomain-value).
251
+ -}
212
252
  withDomain : String -> Options -> Options
213
253
  withDomain domain builder =
214
254
  { builder
@@ -1,5 +1,5 @@
1
- module Path exposing
2
- ( Path, join, fromString
1
+ module UrlPath exposing
2
+ ( UrlPath, join, fromString
3
3
  , toAbsolute, toRelative, toSegments
4
4
  )
5
5
 
@@ -9,27 +9,27 @@ This helper lets you combine together path parts without worrying about having t
9
9
  These two examples will result in the same URL, even though the first example has trailing and leading slashes, and the
10
10
  second does not.
11
11
 
12
- Path.join [ "/blog/", "/post-1/" ]
13
- |> Path.toAbsolute
12
+ UrlPath.join [ "/blog/", "/post-1/" ]
13
+ |> UrlPath.toAbsolute
14
14
  --> "/blog/post-1"
15
15
 
16
- Path.join [ "blog", "post-1" ]
17
- |> Path.toAbsolute
16
+ UrlPath.join [ "blog", "post-1" ]
17
+ |> UrlPath.toAbsolute
18
18
  --> "/blog/post-1"
19
19
 
20
20
  We can also safely join Strings that include multiple path parts, a single path part per string, or a mix of the two:
21
21
 
22
- Path.join [ "/articles/archive/", "1977", "06", "10", "post-1" ]
23
- |> Path.toAbsolute
22
+ UrlPath.join [ "/articles/archive/", "1977", "06", "10", "post-1" ]
23
+ |> UrlPath.toAbsolute
24
24
  --> "/articles/archive/1977/06/10/post-1"
25
25
 
26
26
 
27
- ## Creating Paths
27
+ ## Creating UrlPaths
28
28
 
29
- @docs Path, join, fromString
29
+ @docs UrlPath, join, fromString
30
30
 
31
31
 
32
- ## Turning Paths to String
32
+ ## Turning UrlPaths to String
33
33
 
34
34
  @docs toAbsolute, toRelative, toSegments
35
35
 
@@ -40,35 +40,35 @@ import Pages.Internal.String exposing (chopEnd, chopStart)
40
40
 
41
41
  {-| The path portion of the URL, normalized to ensure that path segments are joined with `/`s in the right places (no doubled up or missing slashes).
42
42
  -}
43
- type alias Path =
43
+ type alias UrlPath =
44
44
  List String
45
45
 
46
46
 
47
47
  {-| Turn a Path to a relative URL.
48
48
  -}
49
- join : Path -> Path
49
+ join : UrlPath -> UrlPath
50
50
  join parts =
51
51
  parts
52
52
  |> List.filter (\segment -> segment /= "/")
53
53
  |> List.map normalize
54
54
 
55
55
 
56
- {-| Turn a Path to a relative URL.
56
+ {-| Turn a UrlPath to a relative URL.
57
57
  -}
58
- toRelative : Path -> String
58
+ toRelative : UrlPath -> String
59
59
  toRelative parts =
60
60
  join parts
61
61
  |> String.join "/"
62
62
 
63
63
 
64
- {-| Create a Path from a path String.
64
+ {-| Create a UrlPath from a path String.
65
65
 
66
- Path.fromString "blog/post-1/"
67
- |> Path.toAbsolute
66
+ UrlPath.fromString "blog/post-1/"
67
+ |> UrlPath.toAbsolute
68
68
  |> Expect.equal "/blog/post-1"
69
69
 
70
70
  -}
71
- fromString : String -> Path
71
+ fromString : String -> UrlPath
72
72
  fromString path =
73
73
  path
74
74
  |> toSegments
@@ -80,9 +80,9 @@ toSegments path =
80
80
  path |> String.split "/" |> List.filter ((/=) "")
81
81
 
82
82
 
83
- {-| Turn a Path to an absolute URL (with no trailing slash).
83
+ {-| Turn a UrlPath to an absolute URL (with no trailing slash).
84
84
  -}
85
- toAbsolute : Path -> String
85
+ toAbsolute : UrlPath -> String
86
86
  toAbsolute path =
87
87
  "/" ++ toRelative path
88
88