effect-start 0.17.2 → 0.19.0
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/dist/Development.d.ts +7 -2
- package/dist/Development.js +12 -6
- package/dist/PlatformRuntime.d.ts +4 -0
- package/dist/PlatformRuntime.js +9 -0
- package/dist/Route.d.ts +6 -2
- package/dist/Route.js +22 -0
- package/dist/RouteHttp.d.ts +1 -1
- package/dist/RouteHttp.js +12 -19
- package/dist/RouteMount.d.ts +2 -1
- package/dist/Start.d.ts +1 -5
- package/dist/Start.js +1 -8
- package/dist/Unique.d.ts +50 -0
- package/dist/Unique.js +187 -0
- package/dist/bun/BunHttpServer.js +5 -6
- package/dist/bun/BunRoute.d.ts +1 -1
- package/dist/bun/BunRoute.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/node/Effectify.d.ts +209 -0
- package/dist/node/Effectify.js +19 -0
- package/dist/node/FileSystem.d.ts +3 -5
- package/dist/node/FileSystem.js +42 -62
- package/dist/node/PlatformError.d.ts +46 -0
- package/dist/node/PlatformError.js +43 -0
- package/dist/testing/TestLogger.js +1 -1
- package/package.json +10 -5
- package/src/Development.ts +13 -18
- package/src/PlatformRuntime.ts +11 -0
- package/src/Route.ts +31 -2
- package/src/RouteHttp.ts +15 -31
- package/src/RouteMount.ts +1 -1
- package/src/Start.ts +1 -15
- package/src/Unique.ts +232 -0
- package/src/bun/BunHttpServer.ts +6 -9
- package/src/bun/BunRoute.ts +3 -3
- package/src/index.ts +1 -0
- package/src/node/Effectify.ts +262 -0
- package/src/node/FileSystem.ts +59 -97
- package/src/node/PlatformError.ts +102 -0
- package/src/testing/TestLogger.ts +1 -1
- package/dist/Random.d.ts +0 -5
- package/dist/Random.js +0 -49
- package/src/Commander.test.ts +0 -1639
- package/src/ContentNegotiation.test.ts +0 -603
- package/src/Development.test.ts +0 -119
- package/src/Entity.test.ts +0 -592
- package/src/FileRouterPattern.test.ts +0 -147
- package/src/FileRouter_files.test.ts +0 -64
- package/src/FileRouter_path.test.ts +0 -145
- package/src/FileRouter_tree.test.ts +0 -132
- package/src/Http.test.ts +0 -319
- package/src/HttpAppExtra.test.ts +0 -103
- package/src/HttpUtils.test.ts +0 -85
- package/src/PathPattern.test.ts +0 -648
- package/src/Random.ts +0 -59
- package/src/RouteBody.test.ts +0 -232
- package/src/RouteHook.test.ts +0 -40
- package/src/RouteHttp.test.ts +0 -2909
- package/src/RouteMount.test.ts +0 -481
- package/src/RouteSchema.test.ts +0 -427
- package/src/RouteSse.test.ts +0 -249
- package/src/RouteTree.test.ts +0 -494
- package/src/RouteTrie.test.ts +0 -322
- package/src/RouterPattern.test.ts +0 -676
- package/src/Values.test.ts +0 -263
- package/src/bun/BunBundle.test.ts +0 -268
- package/src/bun/BunBundle_imports.test.ts +0 -48
- package/src/bun/BunHttpServer.test.ts +0 -251
- package/src/bun/BunImportTrackerPlugin.test.ts +0 -77
- package/src/bun/BunRoute.test.ts +0 -162
- package/src/bundler/BundleHttp.test.ts +0 -132
- package/src/effect/HttpRouter.test.ts +0 -548
- package/src/experimental/EncryptedCookies.test.ts +0 -488
- package/src/hyper/HyperHtml.test.ts +0 -209
- package/src/hyper/HyperRoute.test.tsx +0 -197
- package/src/middlewares/BasicAuthMiddleware.test.ts +0 -84
- package/src/testing/TestHttpClient.test.ts +0 -83
- package/src/testing/TestLogger.test.ts +0 -51
- package/src/x/datastar/Datastar.test.ts +0 -266
- package/src/x/tailwind/TailwindPlugin.test.ts +0 -333
package/src/PathPattern.test.ts
DELETED
|
@@ -1,648 +0,0 @@
|
|
|
1
|
-
import * as test from "bun:test"
|
|
2
|
-
import * as PathPattern from "./PathPattern.ts"
|
|
3
|
-
|
|
4
|
-
test.describe(PathPattern.validate, () => {
|
|
5
|
-
test.it("validates simple paths", () => {
|
|
6
|
-
test
|
|
7
|
-
.expect(PathPattern.validate("/users"))
|
|
8
|
-
.toEqual({ ok: true, segments: ["users"] })
|
|
9
|
-
test
|
|
10
|
-
.expect(PathPattern.validate("/users/posts"))
|
|
11
|
-
.toEqual({ ok: true, segments: ["users", "posts"] })
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
test.it("validates paths with params", () => {
|
|
15
|
-
test
|
|
16
|
-
.expect(PathPattern.validate("/users/:id"))
|
|
17
|
-
.toEqual({ ok: true, segments: ["users", ":id"] })
|
|
18
|
-
test
|
|
19
|
-
.expect(PathPattern.validate("/users/:userId/posts/:postId"))
|
|
20
|
-
.toEqual({ ok: true, segments: ["users", ":userId", "posts", ":postId"] })
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test.it("validates paths with optional params", () => {
|
|
24
|
-
test
|
|
25
|
-
.expect(PathPattern.validate("/users/:id?"))
|
|
26
|
-
.toEqual({ ok: true, segments: ["users", ":id?"] })
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test.it("validates paths with optional wildcard", () => {
|
|
30
|
-
test
|
|
31
|
-
.expect(PathPattern.validate("/files/:path*"))
|
|
32
|
-
.toEqual({ ok: true, segments: ["files", ":path*"] })
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test.it("validates paths with required wildcard", () => {
|
|
36
|
-
test
|
|
37
|
-
.expect(PathPattern.validate("/files/:path+"))
|
|
38
|
-
.toEqual({ ok: true, segments: ["files", ":path+"] })
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test.it("validates root path", () => {
|
|
42
|
-
test
|
|
43
|
-
.expect(PathPattern.validate("/"))
|
|
44
|
-
.toEqual({ ok: true, segments: [] })
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test.it("validates unicode segments", () => {
|
|
48
|
-
test
|
|
49
|
-
.expect(PathPattern.validate("/用户"))
|
|
50
|
-
.toEqual({ ok: true, segments: ["用户"] })
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
test.it("validates segments with dots and dashes", () => {
|
|
54
|
-
test
|
|
55
|
-
.expect(PathPattern.validate("/my-page"))
|
|
56
|
-
.toEqual({ ok: true, segments: ["my-page"] })
|
|
57
|
-
test
|
|
58
|
-
.expect(PathPattern.validate("/file.txt"))
|
|
59
|
-
.toEqual({ ok: true, segments: ["file.txt"] })
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
test.it("returns error for invalid segments", () => {
|
|
63
|
-
const result = PathPattern.validate("/foo bar")
|
|
64
|
-
test.expect(result.ok).toBe(false)
|
|
65
|
-
if (!result.ok) {
|
|
66
|
-
test.expect(result.error).toContain("foo bar")
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
test.it("returns error for empty param name", () => {
|
|
71
|
-
const result = PathPattern.validate("/:")
|
|
72
|
-
test.expect(result.ok).toBe(false)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test.it("returns error for param with only modifier", () => {
|
|
76
|
-
test.expect(PathPattern.validate("/:?").ok).toBe(false)
|
|
77
|
-
test.expect(PathPattern.validate("/:*").ok).toBe(false)
|
|
78
|
-
test.expect(PathPattern.validate("/:+").ok).toBe(false)
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test.describe("Segments", () => {
|
|
83
|
-
test.it("extracts literal segments", () => {
|
|
84
|
-
test
|
|
85
|
-
.expectTypeOf<PathPattern.Segments<"/users">>()
|
|
86
|
-
.toEqualTypeOf<["users"]>()
|
|
87
|
-
test
|
|
88
|
-
.expectTypeOf<PathPattern.Segments<"/users/posts">>()
|
|
89
|
-
.toEqualTypeOf<["users", "posts"]>()
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
test.it("extracts param segments", () => {
|
|
93
|
-
test
|
|
94
|
-
.expectTypeOf<PathPattern.Segments<"/users/:id">>()
|
|
95
|
-
.toEqualTypeOf<["users", ":id"]>()
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
test.it("extracts optional param segments", () => {
|
|
99
|
-
test
|
|
100
|
-
.expectTypeOf<PathPattern.Segments<"/users/:id?">>()
|
|
101
|
-
.toEqualTypeOf<["users", ":id?"]>()
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
test.it("extracts optional wildcard segments", () => {
|
|
105
|
-
test
|
|
106
|
-
.expectTypeOf<PathPattern.Segments<"/files/:path*">>()
|
|
107
|
-
.toEqualTypeOf<["files", ":path*"]>()
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
test.it("extracts required wildcard segments", () => {
|
|
111
|
-
test
|
|
112
|
-
.expectTypeOf<PathPattern.Segments<"/files/:path+">>()
|
|
113
|
-
.toEqualTypeOf<["files", ":path+"]>()
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test.it("extracts complex paths", () => {
|
|
117
|
-
test
|
|
118
|
-
.expectTypeOf<PathPattern.Segments<"/users/:userId/posts/:postId">>()
|
|
119
|
-
.toEqualTypeOf<["users", ":userId", "posts", ":postId"]>()
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
test.it("handles root path", () => {
|
|
123
|
-
test
|
|
124
|
-
.expectTypeOf<PathPattern.Segments<"/">>()
|
|
125
|
-
.toEqualTypeOf<[]>()
|
|
126
|
-
})
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
test.describe("Params", () => {
|
|
130
|
-
test.it("extracts required params", () => {
|
|
131
|
-
test
|
|
132
|
-
.expectTypeOf<PathPattern.Params<"/users/:id">>()
|
|
133
|
-
.toEqualTypeOf<{ id: string }>()
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
test.it("extracts optional params", () => {
|
|
137
|
-
test
|
|
138
|
-
.expectTypeOf<PathPattern.Params<"/users/:id?">>()
|
|
139
|
-
.toEqualTypeOf<{ id?: string }>()
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
test.it("extracts optional wildcard params as optional", () => {
|
|
143
|
-
test
|
|
144
|
-
.expectTypeOf<PathPattern.Params<"/files/:path*">>()
|
|
145
|
-
.toEqualTypeOf<{ path?: string }>()
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
test.it("extracts required wildcard params as required", () => {
|
|
149
|
-
test
|
|
150
|
-
.expectTypeOf<PathPattern.Params<"/files/:path+">>()
|
|
151
|
-
.toEqualTypeOf<{ path: string }>()
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
test.it("extracts multiple params", () => {
|
|
155
|
-
test
|
|
156
|
-
.expectTypeOf<PathPattern.Params<"/users/:userId/posts/:postId">>()
|
|
157
|
-
.toEqualTypeOf<{ userId: string } & { postId: string }>()
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
test.it("returns empty for literal-only paths", () => {
|
|
161
|
-
test
|
|
162
|
-
.expectTypeOf<PathPattern.Params<"/users">>()
|
|
163
|
-
.toEqualTypeOf<{}>()
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
test.it("handles mixed params with optional wildcard", () => {
|
|
167
|
-
test
|
|
168
|
-
.expectTypeOf<PathPattern.Params<"/users/:id/files/:path*">>()
|
|
169
|
-
.toEqualTypeOf<{ id: string } & { path?: string }>()
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
test.it("handles mixed params with required wildcard", () => {
|
|
173
|
-
test
|
|
174
|
-
.expectTypeOf<PathPattern.Params<"/users/:id/files/:path+">>()
|
|
175
|
-
.toEqualTypeOf<{ id: string } & { path: string }>()
|
|
176
|
-
})
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
test.describe(PathPattern.match, () => {
|
|
180
|
-
test.it("matches static path", () => {
|
|
181
|
-
const result = PathPattern.match("/users", "/users")
|
|
182
|
-
test.expect(result).toEqual({})
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
test.it("returns null for non-matching static path", () => {
|
|
186
|
-
const result = PathPattern.match("/users", "/posts")
|
|
187
|
-
test.expect(result).toBeNull()
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
test.it("extracts required param", () => {
|
|
191
|
-
const result = PathPattern.match("/users/:id", "/users/123")
|
|
192
|
-
test.expect(result).toEqual({ id: "123" })
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
test.it("extracts optional param when present", () => {
|
|
196
|
-
const result = PathPattern.match("/users/:id?", "/users/123")
|
|
197
|
-
test.expect(result).toEqual({ id: "123" })
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
test.it("omits optional param when absent", () => {
|
|
201
|
-
const result = PathPattern.match("/users/:id?", "/users")
|
|
202
|
-
test.expect(result).toEqual({})
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
test.it("extracts optional wildcard when present", () => {
|
|
206
|
-
const result = PathPattern.match("/docs/:path*", "/docs/api/users")
|
|
207
|
-
test.expect(result).toEqual({ path: "api/users" })
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
test.it("omits optional wildcard when absent", () => {
|
|
211
|
-
const result = PathPattern.match("/docs/:path*", "/docs")
|
|
212
|
-
test.expect(result).toEqual({})
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
test.it("extracts required wildcard when present", () => {
|
|
216
|
-
const result = PathPattern.match("/docs/:path+", "/docs/api/users")
|
|
217
|
-
test.expect(result).toEqual({ path: "api/users" })
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
test.it("returns null for required wildcard when absent", () => {
|
|
221
|
-
const result = PathPattern.match("/docs/:path+", "/docs")
|
|
222
|
-
test.expect(result).toBeNull()
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
test.it("distinguishes optional from required wildcard", () => {
|
|
226
|
-
const optionalMatch = PathPattern.match("/files/:path*", "/files")
|
|
227
|
-
const requiredMatch = PathPattern.match("/files/:path+", "/files")
|
|
228
|
-
|
|
229
|
-
test.expect(optionalMatch).toEqual({})
|
|
230
|
-
test.expect(requiredMatch).toBeNull()
|
|
231
|
-
})
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
test.describe(PathPattern.toRegex, () => {
|
|
235
|
-
test.it("strips double slashes", () => {
|
|
236
|
-
const regex = PathPattern.toRegex("//users//")
|
|
237
|
-
test.expect(regex.test("/users")).toBe(true)
|
|
238
|
-
test.expect(regex.test("/users/")).toBe(true)
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
test.it("strips trailing slashes in pattern", () => {
|
|
242
|
-
const regex = PathPattern.toRegex("/users/")
|
|
243
|
-
test.expect(regex.test("/users")).toBe(true)
|
|
244
|
-
test.expect(regex.test("/users/")).toBe(true)
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
test.it("converts greedy params with +", () => {
|
|
248
|
-
const regex = PathPattern.toRegex("/files/:path+")
|
|
249
|
-
test.expect(regex.test("/files/a/b/c")).toBe(true)
|
|
250
|
-
test.expect(regex.test("/files/")).toBe(true)
|
|
251
|
-
test.expect(regex.test("/files")).toBe(false)
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
test.it("converts named params", () => {
|
|
255
|
-
const regex = PathPattern.toRegex("/users/:id")
|
|
256
|
-
test.expect(regex.test("/users/123")).toBe(true)
|
|
257
|
-
const match = "/users/123".match(regex)
|
|
258
|
-
test.expect(match?.groups).toEqual({ id: "123" })
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
test.it("escapes dots", () => {
|
|
262
|
-
const regex = PathPattern.toRegex("/file.json")
|
|
263
|
-
test.expect(regex.test("/file.json")).toBe(true)
|
|
264
|
-
test.expect(regex.test("/filexjson")).toBe(false)
|
|
265
|
-
})
|
|
266
|
-
|
|
267
|
-
test.it("converts wildcards", () => {
|
|
268
|
-
const regex = PathPattern.toRegex("/api/*")
|
|
269
|
-
test.expect(regex.test("/api")).toBe(true)
|
|
270
|
-
test.expect(regex.test("/api/")).toBe(true)
|
|
271
|
-
test.expect(regex.test("/api/users")).toBe(true)
|
|
272
|
-
test.expect(regex.test("/api/users/123")).toBe(true)
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
test.it("matches static paths", () => {
|
|
276
|
-
const regex = PathPattern.toRegex("/users")
|
|
277
|
-
test.expect(regex.test("/users")).toBe(true)
|
|
278
|
-
test.expect(regex.test("/users/")).toBe(true)
|
|
279
|
-
test.expect(regex.test("/posts")).toBe(false)
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
test.it("matches named params", () => {
|
|
283
|
-
const regex = PathPattern.toRegex("/users/:id")
|
|
284
|
-
test.expect(regex.test("/users/123")).toBe(true)
|
|
285
|
-
test.expect(regex.test("/users/abc")).toBe(true)
|
|
286
|
-
test.expect(regex.test("/users")).toBe(false)
|
|
287
|
-
test.expect(regex.test("/users/123/posts")).toBe(false)
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
test.it("extracts named params", () => {
|
|
291
|
-
const regex = PathPattern.toRegex("/users/:id")
|
|
292
|
-
const match = "/users/123".match(regex)
|
|
293
|
-
test.expect(match?.groups).toEqual({ id: "123" })
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
test.it("matches greedy params", () => {
|
|
297
|
-
const regex = PathPattern.toRegex("/docs/:path+")
|
|
298
|
-
test.expect(regex.test("/docs/api/users")).toBe(true)
|
|
299
|
-
test.expect(regex.test("/docs/")).toBe(true)
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
test.it("matches wildcards", () => {
|
|
303
|
-
const regex = PathPattern.toRegex("/api/*")
|
|
304
|
-
test.expect(regex.test("/api")).toBe(true)
|
|
305
|
-
test.expect(regex.test("/api/")).toBe(true)
|
|
306
|
-
test.expect(regex.test("/api/users")).toBe(true)
|
|
307
|
-
test.expect(regex.test("/api/users/123")).toBe(true)
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
test.it("matches complex patterns", () => {
|
|
311
|
-
const regex = PathPattern.toRegex("/users/:userId/posts/:postId")
|
|
312
|
-
test.expect(regex.test("/users/42/posts/7")).toBe(true)
|
|
313
|
-
const match = "/users/42/posts/7".match(regex)
|
|
314
|
-
test.expect(match?.groups).toEqual({ userId: "42", postId: "7" })
|
|
315
|
-
})
|
|
316
|
-
|
|
317
|
-
test.it("handles dots in file extensions", () => {
|
|
318
|
-
const regex = PathPattern.toRegex("/files/:name.json")
|
|
319
|
-
test.expect(regex.test("/files/data.json")).toBe(true)
|
|
320
|
-
test.expect(regex.test("/files/dataxjson")).toBe(false)
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
test.it("allows trailing slashes in matched path", () => {
|
|
324
|
-
const regex = PathPattern.toRegex("/users/:id")
|
|
325
|
-
test.expect(regex.test("/users/123/")).toBe(true)
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
test.it("matches optional wildcard params with :param*", () => {
|
|
329
|
-
const regex = PathPattern.toRegex("/docs/:path*")
|
|
330
|
-
test.expect(regex.test("/docs")).toBe(true)
|
|
331
|
-
test.expect(regex.test("/docs/")).toBe(true)
|
|
332
|
-
test.expect(regex.test("/docs/api")).toBe(true)
|
|
333
|
-
test.expect(regex.test("/docs/api/users")).toBe(true)
|
|
334
|
-
test.expect(regex.test("/docs/api/users/create")).toBe(true)
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
test.it("extracts optional wildcard params with :param*", () => {
|
|
338
|
-
const regex = PathPattern.toRegex("/docs/:path*")
|
|
339
|
-
const emptyMatch = "/docs".match(regex)
|
|
340
|
-
|
|
341
|
-
test
|
|
342
|
-
.expect(emptyMatch?.groups)
|
|
343
|
-
.toHaveProperty("path")
|
|
344
|
-
test
|
|
345
|
-
.expect(emptyMatch?.groups?.path)
|
|
346
|
-
.toBeUndefined()
|
|
347
|
-
test
|
|
348
|
-
.expect("/docs/api".match(regex)?.groups)
|
|
349
|
-
.toEqual({ path: "api" })
|
|
350
|
-
test
|
|
351
|
-
.expect("/docs/api/users/create".match(regex)?.groups)
|
|
352
|
-
.toEqual({ path: "api/users/create" })
|
|
353
|
-
})
|
|
354
|
-
|
|
355
|
-
test.it("distinguishes :param* from :param+", () => {
|
|
356
|
-
const optionalRegex = PathPattern.toRegex("/files/:path*")
|
|
357
|
-
const greedyRegex = PathPattern.toRegex("/files/:path+")
|
|
358
|
-
|
|
359
|
-
test.expect(optionalRegex.test("/files")).toBe(true)
|
|
360
|
-
test.expect(greedyRegex.test("/files")).toBe(false)
|
|
361
|
-
|
|
362
|
-
test.expect(optionalRegex.test("/files/a/b")).toBe(true)
|
|
363
|
-
test.expect(greedyRegex.test("/files/a/b")).toBe(true)
|
|
364
|
-
})
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
test.describe(PathPattern.toExpress, () => {
|
|
368
|
-
test.it("converts literal paths", () => {
|
|
369
|
-
test
|
|
370
|
-
.expect(PathPattern.toExpress("/users"))
|
|
371
|
-
.toEqual(["/users"])
|
|
372
|
-
test
|
|
373
|
-
.expect(PathPattern.toExpress("/users/posts"))
|
|
374
|
-
.toEqual(["/users/posts"])
|
|
375
|
-
})
|
|
376
|
-
|
|
377
|
-
test.it("converts required params", () => {
|
|
378
|
-
test
|
|
379
|
-
.expect(PathPattern.toExpress("/users/:id"))
|
|
380
|
-
.toEqual(["/users/:id"])
|
|
381
|
-
})
|
|
382
|
-
|
|
383
|
-
test.it("converts optional params to brace syntax", () => {
|
|
384
|
-
test
|
|
385
|
-
.expect(PathPattern.toExpress("/users/:id?"))
|
|
386
|
-
.toEqual(["/users{/:id}"])
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
test.it("converts required wildcard", () => {
|
|
390
|
-
test
|
|
391
|
-
.expect(PathPattern.toExpress("/docs/:path+"))
|
|
392
|
-
.toEqual(["/docs/*path"])
|
|
393
|
-
})
|
|
394
|
-
|
|
395
|
-
test.it("converts optional wildcard to two routes", () => {
|
|
396
|
-
test
|
|
397
|
-
.expect(PathPattern.toExpress("/docs/:path*"))
|
|
398
|
-
.toEqual(["/docs", "/docs/*path"])
|
|
399
|
-
})
|
|
400
|
-
|
|
401
|
-
test.it("converts root path", () => {
|
|
402
|
-
test
|
|
403
|
-
.expect(PathPattern.toExpress("/"))
|
|
404
|
-
.toEqual(["/"])
|
|
405
|
-
})
|
|
406
|
-
})
|
|
407
|
-
|
|
408
|
-
test.describe(PathPattern.toURLPattern, () => {
|
|
409
|
-
test.it("converts literal paths", () => {
|
|
410
|
-
test
|
|
411
|
-
.expect(PathPattern.toURLPattern("/users"))
|
|
412
|
-
.toEqual(["/users"])
|
|
413
|
-
})
|
|
414
|
-
|
|
415
|
-
test.it("preserves param modifiers", () => {
|
|
416
|
-
test
|
|
417
|
-
.expect(PathPattern.toURLPattern("/users/:id"))
|
|
418
|
-
.toEqual(["/users/:id"])
|
|
419
|
-
test
|
|
420
|
-
.expect(PathPattern.toURLPattern("/users/:id?"))
|
|
421
|
-
.toEqual(["/users/:id?"])
|
|
422
|
-
test
|
|
423
|
-
.expect(PathPattern.toURLPattern("/docs/:path+"))
|
|
424
|
-
.toEqual(["/docs/:path+"])
|
|
425
|
-
test
|
|
426
|
-
.expect(PathPattern.toURLPattern("/docs/:path*"))
|
|
427
|
-
.toEqual(["/docs/:path*"])
|
|
428
|
-
})
|
|
429
|
-
|
|
430
|
-
test.it("converts root path", () => {
|
|
431
|
-
test
|
|
432
|
-
.expect(PathPattern.toURLPattern("/"))
|
|
433
|
-
.toEqual(["/"])
|
|
434
|
-
})
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
test.describe(PathPattern.toReactRouter, () => {
|
|
438
|
-
test.it("converts literal paths", () => {
|
|
439
|
-
test
|
|
440
|
-
.expect(PathPattern.toReactRouter("/users"))
|
|
441
|
-
.toEqual(["/users"])
|
|
442
|
-
})
|
|
443
|
-
|
|
444
|
-
test.it("converts required params", () => {
|
|
445
|
-
test
|
|
446
|
-
.expect(PathPattern.toReactRouter("/users/:id"))
|
|
447
|
-
.toEqual(["/users/:id"])
|
|
448
|
-
})
|
|
449
|
-
|
|
450
|
-
test.it("converts optional params", () => {
|
|
451
|
-
test
|
|
452
|
-
.expect(PathPattern.toReactRouter("/users/:id?"))
|
|
453
|
-
.toEqual(["/users/:id?"])
|
|
454
|
-
})
|
|
455
|
-
|
|
456
|
-
test.it("converts required wildcard to splat", () => {
|
|
457
|
-
test
|
|
458
|
-
.expect(PathPattern.toReactRouter("/docs/:path+"))
|
|
459
|
-
.toEqual(["/docs/*"])
|
|
460
|
-
})
|
|
461
|
-
|
|
462
|
-
test.it("converts optional wildcard to two routes", () => {
|
|
463
|
-
test
|
|
464
|
-
.expect(PathPattern.toReactRouter("/docs/:path*"))
|
|
465
|
-
.toEqual(["/docs", "/docs/*"])
|
|
466
|
-
})
|
|
467
|
-
|
|
468
|
-
test.it("converts root path", () => {
|
|
469
|
-
test
|
|
470
|
-
.expect(PathPattern.toReactRouter("/"))
|
|
471
|
-
.toEqual(["/"])
|
|
472
|
-
})
|
|
473
|
-
})
|
|
474
|
-
|
|
475
|
-
test.describe(PathPattern.toRemixFile, () => {
|
|
476
|
-
test.it("converts literal paths with dot separator", () => {
|
|
477
|
-
test
|
|
478
|
-
.expect(PathPattern.toRemixFile("/users"))
|
|
479
|
-
.toBe("users")
|
|
480
|
-
test
|
|
481
|
-
.expect(PathPattern.toRemixFile("/users/posts"))
|
|
482
|
-
.toBe("users.posts")
|
|
483
|
-
})
|
|
484
|
-
|
|
485
|
-
test.it("converts required params to $param", () => {
|
|
486
|
-
test
|
|
487
|
-
.expect(PathPattern.toRemixFile("/users/:id"))
|
|
488
|
-
.toBe("users.$id")
|
|
489
|
-
})
|
|
490
|
-
|
|
491
|
-
test.it("converts optional params to ($param)", () => {
|
|
492
|
-
test
|
|
493
|
-
.expect(PathPattern.toRemixFile("/users/:id?"))
|
|
494
|
-
.toBe("users.($id)")
|
|
495
|
-
})
|
|
496
|
-
|
|
497
|
-
test.it("converts required wildcard to $", () => {
|
|
498
|
-
test
|
|
499
|
-
.expect(PathPattern.toRemixFile("/docs/:path+"))
|
|
500
|
-
.toBe("docs.$")
|
|
501
|
-
})
|
|
502
|
-
|
|
503
|
-
test.it("converts optional wildcard to ($)", () => {
|
|
504
|
-
test
|
|
505
|
-
.expect(PathPattern.toRemixFile("/docs/:path*"))
|
|
506
|
-
.toBe("docs.($)")
|
|
507
|
-
})
|
|
508
|
-
|
|
509
|
-
test.it("converts root path", () => {
|
|
510
|
-
test
|
|
511
|
-
.expect(PathPattern.toRemixFile("/"))
|
|
512
|
-
.toBe("")
|
|
513
|
-
})
|
|
514
|
-
})
|
|
515
|
-
|
|
516
|
-
test.describe(PathPattern.toTanStack, () => {
|
|
517
|
-
test.it("converts literal paths with dot separator", () => {
|
|
518
|
-
test
|
|
519
|
-
.expect(PathPattern.toTanStack("/users"))
|
|
520
|
-
.toBe("users")
|
|
521
|
-
test
|
|
522
|
-
.expect(PathPattern.toTanStack("/users/posts"))
|
|
523
|
-
.toBe("users.posts")
|
|
524
|
-
})
|
|
525
|
-
|
|
526
|
-
test.it("converts required params to $param", () => {
|
|
527
|
-
test
|
|
528
|
-
.expect(PathPattern.toTanStack("/users/:id"))
|
|
529
|
-
.toBe("users.$id")
|
|
530
|
-
})
|
|
531
|
-
|
|
532
|
-
test.it("converts optional params to {-$param}", () => {
|
|
533
|
-
test
|
|
534
|
-
.expect(PathPattern.toTanStack("/users/:id?"))
|
|
535
|
-
.toBe("users.{-$id}")
|
|
536
|
-
})
|
|
537
|
-
|
|
538
|
-
test.it("converts required wildcard to $", () => {
|
|
539
|
-
test
|
|
540
|
-
.expect(PathPattern.toTanStack("/docs/:path+"))
|
|
541
|
-
.toBe("docs.$")
|
|
542
|
-
})
|
|
543
|
-
|
|
544
|
-
test.it("converts optional wildcard to $ (treated as required)", () => {
|
|
545
|
-
test
|
|
546
|
-
.expect(PathPattern.toTanStack("/docs/:path*"))
|
|
547
|
-
.toBe("docs.$")
|
|
548
|
-
})
|
|
549
|
-
|
|
550
|
-
test.it("converts root path", () => {
|
|
551
|
-
test
|
|
552
|
-
.expect(PathPattern.toTanStack("/"))
|
|
553
|
-
.toBe("")
|
|
554
|
-
})
|
|
555
|
-
})
|
|
556
|
-
|
|
557
|
-
test.describe(PathPattern.toHono, () => {
|
|
558
|
-
test.it("converts literal paths", () => {
|
|
559
|
-
test
|
|
560
|
-
.expect(PathPattern.toHono("/users"))
|
|
561
|
-
.toEqual(["/users"])
|
|
562
|
-
})
|
|
563
|
-
|
|
564
|
-
test.it("converts required params", () => {
|
|
565
|
-
test
|
|
566
|
-
.expect(PathPattern.toHono("/users/:id"))
|
|
567
|
-
.toEqual(["/users/:id"])
|
|
568
|
-
})
|
|
569
|
-
|
|
570
|
-
test.it("converts optional params", () => {
|
|
571
|
-
test
|
|
572
|
-
.expect(PathPattern.toHono("/users/:id?"))
|
|
573
|
-
.toEqual(["/users/:id?"])
|
|
574
|
-
})
|
|
575
|
-
|
|
576
|
-
test.it("converts required wildcard to unnamed *", () => {
|
|
577
|
-
test
|
|
578
|
-
.expect(PathPattern.toHono("/docs/:path+"))
|
|
579
|
-
.toEqual(["/docs/*"])
|
|
580
|
-
})
|
|
581
|
-
|
|
582
|
-
test.it("converts optional wildcard to two routes with unnamed *", () => {
|
|
583
|
-
test
|
|
584
|
-
.expect(PathPattern.toHono("/docs/:path*"))
|
|
585
|
-
.toEqual(["/docs", "/docs/*"])
|
|
586
|
-
})
|
|
587
|
-
|
|
588
|
-
test.it("converts root path", () => {
|
|
589
|
-
test
|
|
590
|
-
.expect(PathPattern.toHono("/"))
|
|
591
|
-
.toEqual(["/"])
|
|
592
|
-
})
|
|
593
|
-
})
|
|
594
|
-
|
|
595
|
-
test.describe(PathPattern.toEffect, () => {
|
|
596
|
-
test.it("is alias for toHono", () => {
|
|
597
|
-
test
|
|
598
|
-
.expect(PathPattern.toEffect("/users/:id"))
|
|
599
|
-
.toEqual(PathPattern.toHono("/users/:id"))
|
|
600
|
-
test
|
|
601
|
-
.expect(PathPattern.toEffect("/docs/:path*"))
|
|
602
|
-
.toEqual(PathPattern.toHono("/docs/:path*"))
|
|
603
|
-
})
|
|
604
|
-
})
|
|
605
|
-
|
|
606
|
-
test.describe(PathPattern.toBun, () => {
|
|
607
|
-
test.it("converts literal paths", () => {
|
|
608
|
-
test
|
|
609
|
-
.expect(PathPattern.toBun("/users"))
|
|
610
|
-
.toEqual(["/users"])
|
|
611
|
-
})
|
|
612
|
-
|
|
613
|
-
test.it("converts required params", () => {
|
|
614
|
-
test
|
|
615
|
-
.expect(PathPattern.toBun("/users/:id"))
|
|
616
|
-
.toEqual(["/users/:id"])
|
|
617
|
-
})
|
|
618
|
-
|
|
619
|
-
test.it("expands optional params to two routes", () => {
|
|
620
|
-
test
|
|
621
|
-
.expect(PathPattern.toBun("/users/:id?"))
|
|
622
|
-
.toEqual(["/users", "/users/:id"])
|
|
623
|
-
})
|
|
624
|
-
|
|
625
|
-
test.it("converts required wildcard to /*", () => {
|
|
626
|
-
test
|
|
627
|
-
.expect(PathPattern.toBun("/docs/:path+"))
|
|
628
|
-
.toEqual(["/docs/*"])
|
|
629
|
-
})
|
|
630
|
-
|
|
631
|
-
test.it("expands optional wildcard to two routes", () => {
|
|
632
|
-
test
|
|
633
|
-
.expect(PathPattern.toBun("/docs/:path*"))
|
|
634
|
-
.toEqual(["/docs", "/docs/*"])
|
|
635
|
-
})
|
|
636
|
-
|
|
637
|
-
test.it("converts root path", () => {
|
|
638
|
-
test
|
|
639
|
-
.expect(PathPattern.toBun("/"))
|
|
640
|
-
.toEqual(["/"])
|
|
641
|
-
})
|
|
642
|
-
|
|
643
|
-
test.it("expands multiple optional params", () => {
|
|
644
|
-
test
|
|
645
|
-
.expect(PathPattern.toBun("/users/:id?/posts/:postId?"))
|
|
646
|
-
.toEqual(["/users", "/users/:id/posts/:postId"])
|
|
647
|
-
})
|
|
648
|
-
})
|
package/src/Random.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
export function uuid(): string {
|
|
2
|
-
return base36(uuid4bytes())
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export function uuidSorted(): string {
|
|
6
|
-
return base36(uuid7bytes())
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function token(length: number): string {
|
|
10
|
-
return base36(bytes(length))
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function base36(bytes: Uint8Array): string {
|
|
14
|
-
if (bytes.length === 0) return ""
|
|
15
|
-
let zeros = 0
|
|
16
|
-
while (zeros < bytes.length && bytes[zeros] === 0) zeros++
|
|
17
|
-
|
|
18
|
-
let n = 0n
|
|
19
|
-
for (let i = zeros; i < bytes.length; i++) n = (n << 8n) + BigInt(bytes[i])
|
|
20
|
-
|
|
21
|
-
return "0".repeat(zeros) + (n === 0n ? "" : n.toString(36))
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function bytes(length: number): Uint8Array {
|
|
25
|
-
const buf = new Uint8Array(length)
|
|
26
|
-
crypto.getRandomValues(buf)
|
|
27
|
-
return buf
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function uuid4bytes(): Uint8Array {
|
|
31
|
-
const buf = bytes(16)
|
|
32
|
-
buf[6] = (buf[6] & 0x0f) | 0x40 // version 4
|
|
33
|
-
buf[8] = (buf[8] & 0x3f) | 0x80 // variant
|
|
34
|
-
|
|
35
|
-
return buf
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function uuid7bytes(): Uint8Array {
|
|
39
|
-
const buf = new Uint8Array(16)
|
|
40
|
-
const timestamp = BigInt(Date.now())
|
|
41
|
-
|
|
42
|
-
// 48-bit timestamp (6 bytes)
|
|
43
|
-
buf[0] = Number((timestamp >> 40n) & 0xffn)
|
|
44
|
-
buf[1] = Number((timestamp >> 32n) & 0xffn)
|
|
45
|
-
buf[2] = Number((timestamp >> 24n) & 0xffn)
|
|
46
|
-
buf[3] = Number((timestamp >> 16n) & 0xffn)
|
|
47
|
-
buf[4] = Number((timestamp >> 8n) & 0xffn)
|
|
48
|
-
buf[5] = Number(timestamp & 0xffn)
|
|
49
|
-
|
|
50
|
-
// 12-bit random A (1.5 bytes)
|
|
51
|
-
crypto.getRandomValues(buf.subarray(6, 8))
|
|
52
|
-
buf[6] = (buf[6] & 0x0f) | 0x70 // version 7
|
|
53
|
-
|
|
54
|
-
// 2-bit variant + 62-bit random B (8 bytes)
|
|
55
|
-
crypto.getRandomValues(buf.subarray(8, 16))
|
|
56
|
-
buf[8] = (buf[8] & 0x3f) | 0x80 // variant
|
|
57
|
-
|
|
58
|
-
return buf
|
|
59
|
-
}
|