effect-start 0.18.0 → 0.20.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.
Files changed (203) hide show
  1. package/README.md +3 -3
  2. package/dist/Development.d.ts +8 -3
  3. package/dist/Development.js +14 -7
  4. package/dist/Effectify.d.ts +212 -0
  5. package/dist/Effectify.js +19 -0
  6. package/dist/FilePathPattern.d.ts +29 -0
  7. package/dist/FilePathPattern.js +86 -0
  8. package/dist/FileRouter.d.ts +39 -41
  9. package/dist/FileRouter.js +104 -158
  10. package/dist/FileRouterCodegen.d.ts +7 -8
  11. package/dist/FileRouterCodegen.js +97 -66
  12. package/dist/PlatformError.d.ts +46 -0
  13. package/dist/PlatformError.js +43 -0
  14. package/dist/PlatformRuntime.d.ts +27 -0
  15. package/dist/PlatformRuntime.js +51 -0
  16. package/dist/Route.d.ts +6 -2
  17. package/dist/Route.js +22 -0
  18. package/dist/RouteBody.d.ts +1 -1
  19. package/dist/RouteHttp.d.ts +1 -1
  20. package/dist/RouteHttp.js +12 -19
  21. package/dist/RouteMount.d.ts +2 -1
  22. package/dist/Start.d.ts +33 -6
  23. package/dist/Start.js +31 -13
  24. package/dist/Unique.d.ts +50 -0
  25. package/dist/Unique.js +187 -0
  26. package/dist/bun/BunHttpServer.js +5 -6
  27. package/dist/bun/BunPlatformHttpServer.d.ts +10 -0
  28. package/dist/bun/BunPlatformHttpServer.js +53 -0
  29. package/dist/bun/BunRoute.d.ts +4 -6
  30. package/dist/bun/BunRoute.js +10 -18
  31. package/dist/bun/BunRuntime.d.ts +2 -1
  32. package/dist/bun/BunRuntime.js +10 -5
  33. package/dist/bun/BunServer.d.ts +33 -0
  34. package/dist/bun/BunServer.js +133 -0
  35. package/dist/bun/BunServerRequest.d.ts +60 -0
  36. package/dist/bun/BunServerRequest.js +252 -0
  37. package/dist/bun/index.d.ts +1 -1
  38. package/dist/bun/index.js +1 -1
  39. package/dist/datastar/actions/fetch.d.ts +30 -0
  40. package/dist/datastar/actions/fetch.js +411 -0
  41. package/dist/datastar/actions/peek.d.ts +1 -0
  42. package/dist/datastar/actions/peek.js +14 -0
  43. package/dist/datastar/actions/setAll.d.ts +1 -0
  44. package/dist/datastar/actions/setAll.js +13 -0
  45. package/dist/datastar/actions/toggleAll.d.ts +1 -0
  46. package/dist/datastar/actions/toggleAll.js +13 -0
  47. package/dist/datastar/attributes/attr.d.ts +1 -0
  48. package/dist/datastar/attributes/attr.js +49 -0
  49. package/dist/datastar/attributes/bind.d.ts +1 -0
  50. package/dist/datastar/attributes/bind.js +183 -0
  51. package/dist/datastar/attributes/class.d.ts +1 -0
  52. package/dist/datastar/attributes/class.js +50 -0
  53. package/dist/datastar/attributes/computed.d.ts +1 -0
  54. package/dist/datastar/attributes/computed.js +27 -0
  55. package/dist/datastar/attributes/effect.d.ts +1 -0
  56. package/dist/datastar/attributes/effect.js +10 -0
  57. package/dist/datastar/attributes/indicator.d.ts +1 -0
  58. package/dist/datastar/attributes/indicator.js +32 -0
  59. package/dist/datastar/attributes/init.d.ts +1 -0
  60. package/dist/datastar/attributes/init.js +27 -0
  61. package/dist/datastar/attributes/jsonSignals.d.ts +1 -0
  62. package/dist/datastar/attributes/jsonSignals.js +31 -0
  63. package/dist/datastar/attributes/on.d.ts +1 -0
  64. package/dist/datastar/attributes/on.js +59 -0
  65. package/dist/datastar/attributes/onIntersect.d.ts +1 -0
  66. package/dist/datastar/attributes/onIntersect.js +54 -0
  67. package/dist/datastar/attributes/onInterval.d.ts +1 -0
  68. package/dist/datastar/attributes/onInterval.js +31 -0
  69. package/dist/datastar/attributes/onSignalPatch.d.ts +1 -0
  70. package/dist/datastar/attributes/onSignalPatch.js +44 -0
  71. package/dist/datastar/attributes/ref.d.ts +1 -0
  72. package/dist/datastar/attributes/ref.js +11 -0
  73. package/dist/datastar/attributes/show.d.ts +1 -0
  74. package/dist/datastar/attributes/show.js +32 -0
  75. package/dist/datastar/attributes/signals.d.ts +1 -0
  76. package/dist/datastar/attributes/signals.js +18 -0
  77. package/dist/datastar/attributes/style.d.ts +1 -0
  78. package/dist/datastar/attributes/style.js +56 -0
  79. package/dist/datastar/attributes/text.d.ts +1 -0
  80. package/dist/datastar/attributes/text.js +27 -0
  81. package/dist/datastar/engine.d.ts +156 -0
  82. package/dist/datastar/engine.js +971 -0
  83. package/dist/datastar/index.d.ts +24 -0
  84. package/dist/datastar/index.js +24 -0
  85. package/dist/datastar/load.d.ts +24 -0
  86. package/dist/datastar/load.js +24 -0
  87. package/dist/datastar/utils.d.ts +51 -0
  88. package/dist/datastar/utils.js +205 -0
  89. package/dist/datastar/watchers/patchElements.d.ts +1 -0
  90. package/dist/datastar/watchers/patchElements.js +420 -0
  91. package/dist/datastar/watchers/patchSignals.d.ts +1 -0
  92. package/dist/datastar/watchers/patchSignals.js +15 -0
  93. package/dist/index.d.ts +1 -0
  94. package/dist/index.js +1 -0
  95. package/dist/node/Effectify.d.ts +209 -0
  96. package/dist/node/Effectify.js +19 -0
  97. package/dist/node/FileSystem.d.ts +3 -5
  98. package/dist/node/FileSystem.js +42 -62
  99. package/dist/node/NodeFileSystem.d.ts +7 -0
  100. package/dist/node/NodeFileSystem.js +420 -0
  101. package/dist/node/NodeUtils.d.ts +2 -0
  102. package/dist/node/NodeUtils.js +20 -0
  103. package/dist/node/PlatformError.d.ts +46 -0
  104. package/dist/node/PlatformError.js +43 -0
  105. package/dist/testing/TestLogger.js +1 -1
  106. package/dist/x/tailwind/plugin.js +1 -1
  107. package/package.json +18 -7
  108. package/src/Development.ts +36 -40
  109. package/src/Effectify.ts +269 -0
  110. package/src/FilePathPattern.ts +115 -0
  111. package/src/FileRouter.ts +178 -255
  112. package/src/FileRouterCodegen.ts +135 -92
  113. package/src/PlatformError.ts +117 -0
  114. package/src/PlatformRuntime.ts +108 -0
  115. package/src/Route.ts +31 -2
  116. package/src/RouteBody.ts +1 -1
  117. package/src/RouteHttp.ts +15 -29
  118. package/src/RouteMount.ts +1 -1
  119. package/src/Start.ts +61 -27
  120. package/src/Unique.ts +232 -0
  121. package/src/bun/BunPlatformHttpServer.ts +88 -0
  122. package/src/bun/BunRoute.ts +14 -24
  123. package/src/bun/BunRuntime.ts +21 -5
  124. package/src/bun/BunServer.ts +228 -0
  125. package/src/bun/index.ts +1 -1
  126. package/src/datastar/README.md +18 -0
  127. package/src/datastar/actions/fetch.ts +609 -0
  128. package/src/datastar/actions/peek.ts +17 -0
  129. package/src/datastar/actions/setAll.ts +20 -0
  130. package/src/datastar/actions/toggleAll.ts +20 -0
  131. package/src/datastar/attributes/attr.ts +50 -0
  132. package/src/datastar/attributes/bind.ts +220 -0
  133. package/src/datastar/attributes/class.ts +57 -0
  134. package/src/datastar/attributes/computed.ts +33 -0
  135. package/src/datastar/attributes/effect.ts +11 -0
  136. package/src/datastar/attributes/indicator.ts +39 -0
  137. package/src/datastar/attributes/init.ts +35 -0
  138. package/src/datastar/attributes/jsonSignals.ts +38 -0
  139. package/src/datastar/attributes/on.ts +71 -0
  140. package/src/datastar/attributes/onIntersect.ts +65 -0
  141. package/src/datastar/attributes/onInterval.ts +39 -0
  142. package/src/datastar/attributes/onSignalPatch.ts +63 -0
  143. package/src/datastar/attributes/ref.ts +12 -0
  144. package/src/datastar/attributes/show.ts +33 -0
  145. package/src/datastar/attributes/signals.ts +22 -0
  146. package/src/datastar/attributes/style.ts +63 -0
  147. package/src/datastar/attributes/text.ts +30 -0
  148. package/src/datastar/engine.ts +1341 -0
  149. package/src/datastar/index.ts +25 -0
  150. package/src/datastar/utils.ts +286 -0
  151. package/src/datastar/watchers/patchElements.ts +554 -0
  152. package/src/datastar/watchers/patchSignals.ts +15 -0
  153. package/src/index.ts +1 -0
  154. package/src/node/{FileSystem.ts → NodeFileSystem.ts} +59 -97
  155. package/src/node/{Utils.ts → NodeUtils.ts} +2 -0
  156. package/src/testing/TestLogger.ts +1 -1
  157. package/src/x/tailwind/plugin.ts +1 -1
  158. package/dist/Random.d.ts +0 -5
  159. package/dist/Random.js +0 -49
  160. package/src/Commander.test.ts +0 -1639
  161. package/src/ContentNegotiation.test.ts +0 -603
  162. package/src/Development.test.ts +0 -119
  163. package/src/Entity.test.ts +0 -592
  164. package/src/FileRouterCodegen.todo.ts +0 -1133
  165. package/src/FileRouterPattern.test.ts +0 -147
  166. package/src/FileRouterPattern.ts +0 -59
  167. package/src/FileRouter_files.test.ts +0 -64
  168. package/src/FileRouter_path.test.ts +0 -145
  169. package/src/FileRouter_tree.test.ts +0 -132
  170. package/src/Http.test.ts +0 -319
  171. package/src/HttpAppExtra.test.ts +0 -103
  172. package/src/HttpUtils.test.ts +0 -85
  173. package/src/PathPattern.test.ts +0 -648
  174. package/src/Random.ts +0 -59
  175. package/src/RouteBody.test.ts +0 -232
  176. package/src/RouteHook.test.ts +0 -40
  177. package/src/RouteHttp.test.ts +0 -2909
  178. package/src/RouteMount.test.ts +0 -481
  179. package/src/RouteSchema.test.ts +0 -427
  180. package/src/RouteSse.test.ts +0 -249
  181. package/src/RouteTree.test.ts +0 -494
  182. package/src/RouteTrie.test.ts +0 -322
  183. package/src/RouterPattern.test.ts +0 -676
  184. package/src/RouterPattern.ts +0 -416
  185. package/src/StartApp.ts +0 -47
  186. package/src/Values.test.ts +0 -263
  187. package/src/bun/BunBundle.test.ts +0 -268
  188. package/src/bun/BunBundle_imports.test.ts +0 -48
  189. package/src/bun/BunHttpServer.test.ts +0 -251
  190. package/src/bun/BunHttpServer.ts +0 -306
  191. package/src/bun/BunImportTrackerPlugin.test.ts +0 -77
  192. package/src/bun/BunRoute.test.ts +0 -162
  193. package/src/bundler/BundleHttp.test.ts +0 -132
  194. package/src/effect/HttpRouter.test.ts +0 -548
  195. package/src/experimental/EncryptedCookies.test.ts +0 -488
  196. package/src/hyper/HyperHtml.test.ts +0 -209
  197. package/src/hyper/HyperRoute.test.tsx +0 -197
  198. package/src/middlewares/BasicAuthMiddleware.test.ts +0 -84
  199. package/src/testing/TestHttpClient.test.ts +0 -83
  200. package/src/testing/TestLogger.test.ts +0 -51
  201. package/src/x/datastar/Datastar.test.ts +0 -266
  202. package/src/x/tailwind/TailwindPlugin.test.ts +0 -333
  203. /package/src/bun/{BunHttpServer_web.ts → BunServerRequest.ts} +0 -0
@@ -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
- }