@atproto/lex-schema 0.1.4 → 0.1.6

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 (263) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/core/$type.d.ts +2 -2
  3. package/dist/core/$type.d.ts.map +1 -1
  4. package/dist/core/$type.js.map +1 -1
  5. package/dist/core/record-key.d.ts +1 -1
  6. package/dist/core/record-key.d.ts.map +1 -1
  7. package/dist/core/record-key.js.map +1 -1
  8. package/dist/core/schema.d.ts +3 -2
  9. package/dist/core/schema.d.ts.map +1 -1
  10. package/dist/core/schema.js +1 -1
  11. package/dist/core/schema.js.map +1 -1
  12. package/dist/core/standard-schema.d.ts +2 -2
  13. package/dist/core/standard-schema.d.ts.map +1 -1
  14. package/dist/core/standard-schema.js.map +1 -1
  15. package/dist/core/string-format.d.ts +2 -2
  16. package/dist/core/string-format.d.ts.map +1 -1
  17. package/dist/core/string-format.js.map +1 -1
  18. package/dist/core/validation-error.d.ts +1 -1
  19. package/dist/core/validation-error.d.ts.map +1 -1
  20. package/dist/core/validation-error.js +1 -1
  21. package/dist/core/validation-error.js.map +1 -1
  22. package/dist/core/validator.d.ts +1 -1
  23. package/dist/core/validator.d.ts.map +1 -1
  24. package/dist/core/validator.js +1 -1
  25. package/dist/core/validator.js.map +1 -1
  26. package/dist/helpers.d.ts +2 -2
  27. package/dist/helpers.d.ts.map +1 -1
  28. package/dist/helpers.js +2 -2
  29. package/dist/helpers.js.map +1 -1
  30. package/dist/schema/array.d.ts +1 -1
  31. package/dist/schema/array.d.ts.map +1 -1
  32. package/dist/schema/array.js +1 -1
  33. package/dist/schema/array.js.map +1 -1
  34. package/dist/schema/blob.d.ts +1 -1
  35. package/dist/schema/blob.d.ts.map +1 -1
  36. package/dist/schema/blob.js +2 -2
  37. package/dist/schema/blob.js.map +1 -1
  38. package/dist/schema/boolean.js +1 -1
  39. package/dist/schema/boolean.js.map +1 -1
  40. package/dist/schema/bytes.js +1 -1
  41. package/dist/schema/bytes.js.map +1 -1
  42. package/dist/schema/cid.d.ts +1 -1
  43. package/dist/schema/cid.d.ts.map +1 -1
  44. package/dist/schema/cid.js +3 -3
  45. package/dist/schema/cid.js.map +1 -1
  46. package/dist/schema/custom.js +1 -1
  47. package/dist/schema/custom.js.map +1 -1
  48. package/dist/schema/dict.d.ts +1 -1
  49. package/dist/schema/dict.d.ts.map +1 -1
  50. package/dist/schema/dict.js +1 -1
  51. package/dist/schema/dict.js.map +1 -1
  52. package/dist/schema/discriminated-union.d.ts +1 -1
  53. package/dist/schema/discriminated-union.d.ts.map +1 -1
  54. package/dist/schema/discriminated-union.js +2 -1
  55. package/dist/schema/discriminated-union.js.map +1 -1
  56. package/dist/schema/enum.js +1 -1
  57. package/dist/schema/enum.js.map +1 -1
  58. package/dist/schema/integer.js +1 -1
  59. package/dist/schema/integer.js.map +1 -1
  60. package/dist/schema/intersection.d.ts +1 -1
  61. package/dist/schema/intersection.d.ts.map +1 -1
  62. package/dist/schema/intersection.js +3 -1
  63. package/dist/schema/intersection.js.map +1 -1
  64. package/dist/schema/lex-map.d.ts +1 -1
  65. package/dist/schema/lex-map.d.ts.map +1 -1
  66. package/dist/schema/lex-map.js +1 -1
  67. package/dist/schema/lex-map.js.map +1 -1
  68. package/dist/schema/lex-value.d.ts +1 -1
  69. package/dist/schema/lex-value.d.ts.map +1 -1
  70. package/dist/schema/lex-value.js +1 -1
  71. package/dist/schema/lex-value.js.map +1 -1
  72. package/dist/schema/literal.js +1 -1
  73. package/dist/schema/literal.js.map +1 -1
  74. package/dist/schema/never.js +1 -1
  75. package/dist/schema/never.js.map +1 -1
  76. package/dist/schema/null.js +1 -1
  77. package/dist/schema/null.js.map +1 -1
  78. package/dist/schema/nullable.d.ts +1 -1
  79. package/dist/schema/nullable.d.ts.map +1 -1
  80. package/dist/schema/nullable.js +1 -1
  81. package/dist/schema/nullable.js.map +1 -1
  82. package/dist/schema/object.d.ts +2 -1
  83. package/dist/schema/object.d.ts.map +1 -1
  84. package/dist/schema/object.js +1 -1
  85. package/dist/schema/object.js.map +1 -1
  86. package/dist/schema/optional.d.ts +2 -1
  87. package/dist/schema/optional.d.ts.map +1 -1
  88. package/dist/schema/optional.js +2 -1
  89. package/dist/schema/optional.js.map +1 -1
  90. package/dist/schema/params.d.ts +1 -1
  91. package/dist/schema/params.d.ts.map +1 -1
  92. package/dist/schema/params.js +1 -1
  93. package/dist/schema/params.js.map +1 -1
  94. package/dist/schema/payload.d.ts +3 -2
  95. package/dist/schema/payload.d.ts.map +1 -1
  96. package/dist/schema/payload.js +2 -1
  97. package/dist/schema/payload.js.map +1 -1
  98. package/dist/schema/permission-set.d.ts +1 -1
  99. package/dist/schema/permission-set.d.ts.map +1 -1
  100. package/dist/schema/permission-set.js +1 -0
  101. package/dist/schema/permission-set.js.map +1 -1
  102. package/dist/schema/permission.d.ts +1 -1
  103. package/dist/schema/permission.d.ts.map +1 -1
  104. package/dist/schema/permission.js.map +1 -1
  105. package/dist/schema/procedure.d.ts +1 -1
  106. package/dist/schema/procedure.d.ts.map +1 -1
  107. package/dist/schema/procedure.js +2 -0
  108. package/dist/schema/procedure.js.map +1 -1
  109. package/dist/schema/query.d.ts +1 -1
  110. package/dist/schema/query.d.ts.map +1 -1
  111. package/dist/schema/query.js +2 -0
  112. package/dist/schema/query.js.map +1 -1
  113. package/dist/schema/record.d.ts +2 -2
  114. package/dist/schema/record.d.ts.map +1 -1
  115. package/dist/schema/record.js +1 -1
  116. package/dist/schema/record.js.map +1 -1
  117. package/dist/schema/ref.d.ts +1 -1
  118. package/dist/schema/ref.d.ts.map +1 -1
  119. package/dist/schema/ref.js +1 -1
  120. package/dist/schema/ref.js.map +1 -1
  121. package/dist/schema/refine.d.ts +2 -2
  122. package/dist/schema/refine.d.ts.map +1 -1
  123. package/dist/schema/refine.js +1 -1
  124. package/dist/schema/refine.js.map +1 -1
  125. package/dist/schema/regexp.js +1 -1
  126. package/dist/schema/regexp.js.map +1 -1
  127. package/dist/schema/string.d.ts +2 -2
  128. package/dist/schema/string.d.ts.map +1 -1
  129. package/dist/schema/string.js +1 -1
  130. package/dist/schema/string.js.map +1 -1
  131. package/dist/schema/subscription.d.ts +3 -2
  132. package/dist/schema/subscription.d.ts.map +1 -1
  133. package/dist/schema/subscription.js +2 -0
  134. package/dist/schema/subscription.js.map +1 -1
  135. package/dist/schema/token.d.ts +1 -1
  136. package/dist/schema/token.d.ts.map +1 -1
  137. package/dist/schema/token.js +1 -1
  138. package/dist/schema/token.js.map +1 -1
  139. package/dist/schema/typed-object.d.ts +2 -2
  140. package/dist/schema/typed-object.d.ts.map +1 -1
  141. package/dist/schema/typed-object.js +1 -1
  142. package/dist/schema/typed-object.js.map +1 -1
  143. package/dist/schema/typed-ref.d.ts +1 -1
  144. package/dist/schema/typed-ref.d.ts.map +1 -1
  145. package/dist/schema/typed-ref.js +1 -1
  146. package/dist/schema/typed-ref.js.map +1 -1
  147. package/dist/schema/typed-union.d.ts +1 -1
  148. package/dist/schema/typed-union.d.ts.map +1 -1
  149. package/dist/schema/typed-union.js +3 -1
  150. package/dist/schema/typed-union.js.map +1 -1
  151. package/dist/schema/union.d.ts +1 -1
  152. package/dist/schema/union.d.ts.map +1 -1
  153. package/dist/schema/union.js +1 -1
  154. package/dist/schema/union.js.map +1 -1
  155. package/dist/schema/unknown.js +1 -1
  156. package/dist/schema/unknown.js.map +1 -1
  157. package/dist/schema/with-default.d.ts +1 -1
  158. package/dist/schema/with-default.d.ts.map +1 -1
  159. package/dist/schema/with-default.js +1 -1
  160. package/dist/schema/with-default.js.map +1 -1
  161. package/package.json +6 -10
  162. package/src/core/$type.test.ts +0 -24
  163. package/src/core/$type.ts +0 -199
  164. package/src/core/record-key.ts +0 -85
  165. package/src/core/result.ts +0 -15
  166. package/src/core/schema.ts +0 -412
  167. package/src/core/standard-schema.test.ts +0 -124
  168. package/src/core/standard-schema.ts +0 -31
  169. package/src/core/string-format.ts +0 -411
  170. package/src/core/types.ts +0 -120
  171. package/src/core/validation-error.ts +0 -134
  172. package/src/core/validation-issue.ts +0 -340
  173. package/src/core/validator.ts +0 -636
  174. package/src/core.ts +0 -9
  175. package/src/external.ts +0 -3
  176. package/src/helpers.test.ts +0 -694
  177. package/src/helpers.ts +0 -222
  178. package/src/index.ts +0 -3
  179. package/src/schema/array.test.ts +0 -251
  180. package/src/schema/array.ts +0 -126
  181. package/src/schema/blob.test.ts +0 -733
  182. package/src/schema/blob.ts +0 -150
  183. package/src/schema/boolean.test.ts +0 -118
  184. package/src/schema/boolean.ts +0 -46
  185. package/src/schema/bytes.test.ts +0 -227
  186. package/src/schema/bytes.ts +0 -81
  187. package/src/schema/cid.test.ts +0 -125
  188. package/src/schema/cid.ts +0 -69
  189. package/src/schema/custom.test.ts +0 -414
  190. package/src/schema/custom.ts +0 -106
  191. package/src/schema/dict.test.ts +0 -181
  192. package/src/schema/dict.ts +0 -122
  193. package/src/schema/discriminated-union.test.ts +0 -676
  194. package/src/schema/discriminated-union.ts +0 -196
  195. package/src/schema/enum.test.ts +0 -398
  196. package/src/schema/enum.ts +0 -77
  197. package/src/schema/integer.test.ts +0 -314
  198. package/src/schema/integer.ts +0 -86
  199. package/src/schema/intersection.test.ts +0 -33
  200. package/src/schema/intersection.ts +0 -113
  201. package/src/schema/lex-map.test.ts +0 -593
  202. package/src/schema/lex-map.ts +0 -63
  203. package/src/schema/lex-value.test.ts +0 -81
  204. package/src/schema/lex-value.ts +0 -86
  205. package/src/schema/literal.test.ts +0 -533
  206. package/src/schema/literal.ts +0 -70
  207. package/src/schema/never.test.ts +0 -175
  208. package/src/schema/never.ts +0 -56
  209. package/src/schema/null.test.ts +0 -80
  210. package/src/schema/null.ts +0 -49
  211. package/src/schema/nullable.test.ts +0 -470
  212. package/src/schema/nullable.ts +0 -74
  213. package/src/schema/object.test.ts +0 -69
  214. package/src/schema/object.ts +0 -136
  215. package/src/schema/optional.test.ts +0 -479
  216. package/src/schema/optional.ts +0 -92
  217. package/src/schema/params.test.ts +0 -1118
  218. package/src/schema/params.ts +0 -371
  219. package/src/schema/payload.test.ts +0 -340
  220. package/src/schema/payload.ts +0 -204
  221. package/src/schema/permission-set.test.ts +0 -613
  222. package/src/schema/permission-set.ts +0 -86
  223. package/src/schema/permission.test.ts +0 -537
  224. package/src/schema/permission.ts +0 -63
  225. package/src/schema/procedure.test.ts +0 -324
  226. package/src/schema/procedure.ts +0 -98
  227. package/src/schema/query.test.ts +0 -348
  228. package/src/schema/query.ts +0 -86
  229. package/src/schema/record.test.ts +0 -812
  230. package/src/schema/record.ts +0 -217
  231. package/src/schema/ref.test.ts +0 -349
  232. package/src/schema/ref.ts +0 -103
  233. package/src/schema/refine.test.ts +0 -579
  234. package/src/schema/refine.ts +0 -153
  235. package/src/schema/regexp.test.ts +0 -577
  236. package/src/schema/regexp.ts +0 -82
  237. package/src/schema/string.test.ts +0 -773
  238. package/src/schema/string.ts +0 -229
  239. package/src/schema/subscription.test.ts +0 -499
  240. package/src/schema/subscription.ts +0 -108
  241. package/src/schema/token.test.ts +0 -152
  242. package/src/schema/token.ts +0 -103
  243. package/src/schema/typed-object.test.ts +0 -745
  244. package/src/schema/typed-object.ts +0 -181
  245. package/src/schema/typed-ref.test.ts +0 -796
  246. package/src/schema/typed-ref.ts +0 -126
  247. package/src/schema/typed-union.test.ts +0 -355
  248. package/src/schema/typed-union.ts +0 -130
  249. package/src/schema/union.test.ts +0 -191
  250. package/src/schema/union.ts +0 -89
  251. package/src/schema/unknown.test.ts +0 -313
  252. package/src/schema/unknown.ts +0 -47
  253. package/src/schema/with-default.ts +0 -81
  254. package/src/schema.ts +0 -43
  255. package/src/util/array-agg.test.ts +0 -42
  256. package/src/util/array-agg.ts +0 -44
  257. package/src/util/assertion-util.ts +0 -1
  258. package/src/util/if-any.ts +0 -3
  259. package/src/util/lazy-property.ts +0 -14
  260. package/src/util/memoize.ts +0 -37
  261. package/tsconfig.build.json +0 -12
  262. package/tsconfig.json +0 -7
  263. package/tsconfig.tests.json +0 -8
@@ -1,1118 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { array } from './array.js'
3
- import { boolean } from './boolean.js'
4
- import { enumSchema } from './enum.js'
5
- import { integer } from './integer.js'
6
- import { literal } from './literal.js'
7
- import { optional } from './optional.js'
8
- import { paramSchema, params, paramsSchema } from './params.js'
9
- import { string } from './string.js'
10
-
11
- describe('ParamsSchema', () => {
12
- describe('basic validation', () => {
13
- const schema = params({
14
- name: string(),
15
- age: integer(),
16
- })
17
-
18
- it('validates plain objects with required params', () => {
19
- const result = schema.safeParse({
20
- name: 'Alice',
21
- age: 30,
22
- })
23
- expect(result.success).toBe(true)
24
- })
25
-
26
- it('rejects non-objects', () => {
27
- const result = schema.safeParse('not an object')
28
- expect(result.success).toBe(false)
29
- })
30
-
31
- it('rejects null values', () => {
32
- const result = schema.safeParse(null)
33
- expect(result.success).toBe(false)
34
- })
35
-
36
- it('rejects undefined values', () => {
37
- const result = schema.safeParse(undefined)
38
- expect(result.success).toBe(false)
39
- })
40
-
41
- it('rejects arrays', () => {
42
- const result = schema.safeParse(['Alice', 30])
43
- expect(result.success).toBe(false)
44
- })
45
-
46
- it('rejects missing required properties', () => {
47
- const result = schema.safeParse({
48
- name: 'Alice',
49
- })
50
- expect(result.success).toBe(false)
51
- })
52
-
53
- it('rejects invalid property types', () => {
54
- const result = schema.safeParse({
55
- name: 'Alice',
56
- age: 'thirty',
57
- })
58
- expect(result.success).toBe(false)
59
- })
60
- })
61
-
62
- describe('optional parameters', () => {
63
- const schema = params({
64
- name: string(),
65
- age: optional(integer()),
66
- active: optional(boolean()),
67
- })
68
-
69
- it('validates with all parameters present', () => {
70
- const result = schema.safeParse({
71
- name: 'Alice',
72
- age: 30,
73
- active: true,
74
- })
75
- expect(result.success).toBe(true)
76
- })
77
-
78
- it('validates with only required parameters', () => {
79
- const result = schema.safeParse({
80
- name: 'Alice',
81
- })
82
- expect(result.success).toBe(true)
83
- })
84
-
85
- it('validates with some optional parameters', () => {
86
- const result = schema.safeParse({
87
- name: 'Alice',
88
- age: 30,
89
- })
90
- expect(result.success).toBe(true)
91
- })
92
-
93
- it('rejects when required parameter is missing', () => {
94
- const result = schema.safeParse({
95
- age: 30,
96
- active: true,
97
- })
98
- expect(result.success).toBe(false)
99
- })
100
- })
101
-
102
- describe('additional unspecified parameters', () => {
103
- const schema = params({
104
- name: string(),
105
- })
106
-
107
- it('accepts string values in additional params', () => {
108
- const result = schema.safeParse({
109
- name: 'Alice',
110
- extra: 'value',
111
- })
112
- expect(result.success).toBe(true)
113
- })
114
-
115
- it('accepts boolean values in additional params', () => {
116
- const result = schema.safeParse({
117
- name: 'Alice',
118
- flag: true,
119
- })
120
- expect(result.success).toBe(true)
121
- })
122
-
123
- it('accepts integer values in additional params', () => {
124
- const result = schema.safeParse({
125
- name: 'Alice',
126
- count: 42,
127
- })
128
- expect(result.success).toBe(true)
129
- })
130
-
131
- it('accepts array values in additional params', () => {
132
- const result = schema.safeParse({
133
- name: 'Alice',
134
- tags: ['tag1', 'tag2'],
135
- })
136
- expect(result.success).toBe(true)
137
- })
138
-
139
- it('accepts multiple additional params', () => {
140
- const result = schema.safeParse({
141
- name: 'Alice',
142
- extra1: 'value',
143
- extra2: 42,
144
- extra3: true,
145
- })
146
- expect(result.success).toBe(true)
147
- })
148
-
149
- it('rejects null values in additional params', () => {
150
- const result = schema.safeParse({
151
- name: 'Alice',
152
- extra: null,
153
- })
154
- expect(result.success).toBe(false)
155
- })
156
-
157
- it('rejects object values in additional params', () => {
158
- const result = schema.safeParse({
159
- name: 'Alice',
160
- extra: { nested: 'object' },
161
- })
162
- expect(result.success).toBe(false)
163
- })
164
-
165
- it('rejects undefined values in additional params', () => {
166
- const result = schema.safeParse({
167
- name: 'Alice',
168
- extra: undefined,
169
- })
170
- expect(result.success).toBe(false)
171
- })
172
- })
173
-
174
- describe('parameter types', () => {
175
- describe('string parameters', () => {
176
- const schema = params({
177
- text: string(),
178
- })
179
-
180
- it('validates string values', () => {
181
- const result = schema.safeParse({ text: 'hello' })
182
- expect(result.success).toBe(true)
183
- })
184
-
185
- it('validates empty strings', () => {
186
- const result = schema.safeParse({ text: '' })
187
- expect(result.success).toBe(true)
188
- })
189
-
190
- it('rejects non-string values', () => {
191
- const result = schema.safeParse({ text: 123 })
192
- expect(result.success).toBe(false)
193
- })
194
- })
195
-
196
- describe('integer parameters', () => {
197
- const schema = params({
198
- count: integer(),
199
- })
200
-
201
- it('validates integer values', () => {
202
- const result = schema.safeParse({ count: 42 })
203
- expect(result.success).toBe(true)
204
- })
205
-
206
- it('validates zero', () => {
207
- const result = schema.safeParse({ count: 0 })
208
- expect(result.success).toBe(true)
209
- })
210
-
211
- it('validates negative integers', () => {
212
- const result = schema.safeParse({ count: -10 })
213
- expect(result.success).toBe(true)
214
- })
215
-
216
- it('rejects non-integer values', () => {
217
- const result = schema.safeParse({ count: 'not a number' })
218
- expect(result.success).toBe(false)
219
- })
220
- })
221
-
222
- describe('boolean parameters', () => {
223
- const schema = params({
224
- flag: boolean(),
225
- })
226
-
227
- it('validates true', () => {
228
- const result = schema.safeParse({ flag: true })
229
- expect(result.success).toBe(true)
230
- })
231
-
232
- it('validates false', () => {
233
- const result = schema.safeParse({ flag: false })
234
- expect(result.success).toBe(true)
235
- })
236
-
237
- it('rejects non-boolean values', () => {
238
- const result = schema.safeParse({ flag: 'true' })
239
- expect(result.success).toBe(false)
240
- })
241
- })
242
-
243
- describe('array parameters', () => {
244
- const schema = params({
245
- tags: array(string()),
246
- })
247
-
248
- it('validates string arrays', () => {
249
- const result = schema.safeParse({ tags: ['tag1', 'tag2'] })
250
- expect(result.success).toBe(true)
251
- })
252
-
253
- it('validates empty arrays', () => {
254
- const result = schema.safeParse({ tags: [] })
255
- expect(result.success).toBe(true)
256
- })
257
-
258
- it('rejects arrays with invalid items', () => {
259
- const result = schema.safeParse({ tags: ['tag1', 123] })
260
- expect(result.success).toBe(false)
261
- })
262
- })
263
- })
264
-
265
- describe('coercion', () => {
266
- it('throws for invalid enum values', () => {
267
- const schema = params({
268
- status: enumSchema(['active', 'inactive']),
269
- })
270
- expect(() => schema.fromURLSearchParams('status=unknown')).toThrow(
271
- 'Expected one of "active" or "inactive"',
272
- )
273
- })
274
-
275
- it('throws for invalid const values', () => {
276
- const schema = params({
277
- version: literal(42),
278
- })
279
- expect(() => schema.fromURLSearchParams('version=99')).toThrow(
280
- 'Expected 42',
281
- )
282
- })
283
-
284
- it('handles negative integer enum values', () => {
285
- const schema = params({
286
- offset: enumSchema([-10, 0, 10]),
287
- })
288
- const result = schema.fromURLSearchParams('offset=-10')
289
- expect(result).toEqual({ offset: -10 })
290
- })
291
-
292
- it('handles boolean const false', () => {
293
- const schema = params({
294
- disabled: literal(false),
295
- })
296
- const result = schema.fromURLSearchParams('disabled=false')
297
- expect(result).toEqual({ disabled: false })
298
- })
299
- })
300
-
301
- describe('fromURLSearchParams', () => {
302
- const schema = params({
303
- name: string(),
304
- age: optional(integer()),
305
- active: optional(boolean()),
306
- tags: optional(array(string())),
307
- ids: optional(array(integer())),
308
- bools: optional(array(boolean())),
309
- })
310
-
311
- it('parses string parameters', () => {
312
- const result = schema.fromURLSearchParams('name=Alice')
313
- expect(result).toEqual({ name: 'Alice' })
314
- })
315
-
316
- it('parses and coerces boolean true', () => {
317
- const result = schema.fromURLSearchParams('name=Alice&active=true')
318
- expect(result).toEqual({ name: 'Alice', active: true })
319
- })
320
-
321
- it('parses and coerces boolean false', () => {
322
- const result = schema.fromURLSearchParams('name=Alice&active=false')
323
- expect(result).toEqual({ name: 'Alice', active: false })
324
- })
325
-
326
- it('parses and coerces integer values', () => {
327
- const result = schema.fromURLSearchParams('name=Alice&age=30')
328
- expect(result).toEqual({ name: 'Alice', age: 30 })
329
- })
330
-
331
- it('parses and coerces negative integers', () => {
332
- const result = schema.fromURLSearchParams('name=Alice&age=-5')
333
- expect(result).toEqual({ name: 'Alice', age: -5 })
334
- })
335
-
336
- it('does not coerce non-integer numbers', () => {
337
- const result = schema.fromURLSearchParams('name=Alice&extra=3.14')
338
- expect(result).toEqual({ name: 'Alice', extra: '3.14' })
339
- })
340
-
341
- it('keeps string values for string schema even if they look like numbers', () => {
342
- const result = schema.fromURLSearchParams('name=123')
343
- expect(result).toEqual({ name: '123' })
344
- })
345
-
346
- it('parses multiple values as array', () => {
347
- const result = schema.fromURLSearchParams('name=Alice&tags=one&tags=two')
348
- expect(result).toEqual({ name: 'Alice', tags: ['one', 'two'] })
349
- })
350
-
351
- it('does not coerce numeric values of unknown params', () => {
352
- expect(
353
- schema.fromURLSearchParams('name=Alice&num=1&num=2&num=3&foo=3'),
354
- ).toEqual({ name: 'Alice', num: ['1', '2', '3'], foo: '3' })
355
-
356
- expect(
357
- schema.fromURLSearchParams('name=Alice&val=true&val=123&val=text'),
358
- ).toEqual({ name: 'Alice', val: ['true', '123', 'text'] })
359
- })
360
-
361
- it('handles empty URLSearchParams', () => {
362
- expect(() => schema.fromURLSearchParams(new URLSearchParams())).toThrow()
363
- expect(() => schema.fromURLSearchParams('')).toThrow()
364
- })
365
-
366
- it('handles multiple parameters', () => {
367
- const urlParams = new URLSearchParams(
368
- 'name=Alice&age=30&active=true&extra=value',
369
- )
370
- const result = schema.fromURLSearchParams(urlParams)
371
- expect(result).toEqual({
372
- name: 'Alice',
373
- age: 30,
374
- active: true,
375
- extra: 'value',
376
- })
377
- })
378
-
379
- it('coerces single values into arrays in parse mode', () => {
380
- expect(
381
- schema.fromURLSearchParams([
382
- ['name', 'Alice'],
383
- ['tags', 'tag1'],
384
- ]),
385
- ).toEqual({ name: 'Alice', tags: ['tag1'] })
386
-
387
- expect(
388
- schema.fromURLSearchParams([
389
- ['name', 'Alice'],
390
- ['tags', 'true'],
391
- ]),
392
- ).toEqual({ name: 'Alice', tags: ['true'] })
393
-
394
- expect(
395
- schema.fromURLSearchParams([
396
- ['name', 'Alice'],
397
- ['tags', '1'],
398
- ]),
399
- ).toEqual({ name: 'Alice', tags: ['1'] })
400
- })
401
-
402
- it('coerces single boolean values into arrays in parse mode', () => {
403
- expect(
404
- schema.fromURLSearchParams([
405
- ['name', 'Alice'],
406
- ['bools', 'true'],
407
- ]),
408
- ).toEqual({ name: 'Alice', bools: [true] })
409
-
410
- expect(
411
- schema.fromURLSearchParams([
412
- ['name', 'Alice'],
413
- ['bools', 'false'],
414
- ]),
415
- ).toEqual({ name: 'Alice', bools: [false] })
416
-
417
- expect(() =>
418
- schema.fromURLSearchParams([
419
- ['name', 'Alice'],
420
- ['bools', 'notabool'],
421
- ]),
422
- ).toThrow('Expected boolean value type (got "notabool") at $.bools')
423
-
424
- expect(() =>
425
- schema.fromURLSearchParams(
426
- [
427
- ['name', 'Alice'],
428
- ['bools', '2'],
429
- ],
430
- {
431
- path: ['foo', 'bar'],
432
- },
433
- ),
434
- ).toThrow('Expected boolean value type (got "2") at $.foo.bar.bools')
435
- })
436
-
437
- it('ignores empty string values', () => {
438
- const result = schema.fromURLSearchParams([
439
- ['name', 'Alice'],
440
- ['extra', ''],
441
- ])
442
- expect(result).toEqual({ name: 'Alice' })
443
- })
444
-
445
- it('ignores empty string values for known parameters', () => {
446
- const result = schema.fromURLSearchParams([
447
- ['name', 'Alice'],
448
- ['age', ''],
449
- ])
450
- expect(result).toEqual({ name: 'Alice' })
451
- })
452
- })
453
-
454
- describe('toURLSearchParams', () => {
455
- const schema = params({
456
- name: string(),
457
- age: optional(integer()),
458
- active: optional(boolean()),
459
- })
460
-
461
- it('converts string parameters', () => {
462
- const result = schema.toURLSearchParams({ name: 'Alice' })
463
- expect(result.toString()).toBe('name=Alice')
464
- })
465
-
466
- it('converts integer parameters', () => {
467
- const result = schema.toURLSearchParams({ name: 'Alice', age: 30 })
468
- expect(result.toString()).toBe('name=Alice&age=30')
469
- })
470
-
471
- it('converts boolean parameters', () => {
472
- const result = schema.toURLSearchParams({ name: 'Alice', active: true })
473
- expect(result.toString()).toBe('name=Alice&active=true')
474
- })
475
-
476
- it('converts multiple parameters', () => {
477
- const result = schema.toURLSearchParams({
478
- name: 'Alice',
479
- age: 30,
480
- active: true,
481
- })
482
- expect(result.toString()).toBe('name=Alice&age=30&active=true')
483
- })
484
-
485
- it('handles array values', () => {
486
- const result = schema.toURLSearchParams({
487
- name: 'Alice',
488
- // @ts-expect-error
489
- tags: ['tag1', 'tag2'],
490
- })
491
- expect(result.toString()).toBe('name=Alice&tags=tag1&tags=tag2')
492
- })
493
-
494
- it('skips undefined values', () => {
495
- const result = schema.toURLSearchParams({
496
- name: 'Alice',
497
- age: undefined,
498
- })
499
- expect(result.toString()).toBe('name=Alice')
500
- })
501
-
502
- it('handles empty arrays', () => {
503
- const result = schema.toURLSearchParams({
504
- name: 'Alice',
505
- // @ts-expect-error
506
- tags: [],
507
- })
508
- expect(result.toString()).toBe('name=Alice')
509
- })
510
-
511
- it('rejects arrays with multiple types', () => {
512
- expect(() => {
513
- schema.toURLSearchParams({
514
- name: 'Alice',
515
- // @ts-expect-error
516
- values: [1, true, 'text'],
517
- })
518
- }).toThrow()
519
- })
520
-
521
- it('handles arrays with multiple types', () => {
522
- const result = schema.toURLSearchParams({
523
- name: 'Alice',
524
- // @ts-expect-error
525
- values: ['foo', 'bar'],
526
- })
527
- expect(result.toString()).toBe('name=Alice&values=foo&values=bar')
528
- })
529
-
530
- it('handles undefined input', () => {
531
- // @ts-expect-error
532
- expect(() => schema.toURLSearchParams(undefined)).toThrow()
533
- })
534
-
535
- it('converts negative integers', () => {
536
- const result = schema.toURLSearchParams({ name: 'Alice', age: -5 })
537
- expect(result.toString()).toBe('name=Alice&age=-5')
538
- })
539
-
540
- it('converts zero', () => {
541
- const result = schema.toURLSearchParams({ name: 'Alice', age: 0 })
542
- expect(result.toString()).toBe('name=Alice&age=0')
543
- })
544
-
545
- it('converts false boolean', () => {
546
- const result = schema.toURLSearchParams({ name: 'Alice', active: false })
547
- expect(result.toString()).toBe('name=Alice&active=false')
548
- })
549
- })
550
-
551
- describe('roundtrip conversion', () => {
552
- const schema = params({
553
- name: string(),
554
- age: optional(integer()),
555
- active: optional(boolean()),
556
- })
557
-
558
- it('roundtrips simple params correctly', () => {
559
- const original = { name: 'Alice', age: 30, active: true }
560
- const urlParams = schema.toURLSearchParams(original)
561
- const result = schema.fromURLSearchParams(urlParams)
562
- expect(result).toEqual(original)
563
- })
564
-
565
- it('roundtrips params with arrays', () => {
566
- const original = { name: 'Alice', tags: ['tag1', 'tag2'] }
567
- const urlParams = schema.toURLSearchParams(original)
568
- const result = schema.fromURLSearchParams(urlParams)
569
- expect(result).toEqual(original)
570
- })
571
-
572
- it('roundtrips params with boolean false', () => {
573
- const original = { name: 'Alice', active: false }
574
- const urlParams = schema.toURLSearchParams(original)
575
- const result = schema.fromURLSearchParams(urlParams)
576
- expect(result).toEqual(original)
577
- })
578
-
579
- it('roundtrips params with zero', () => {
580
- const original = { name: 'Alice', age: 0 }
581
- const urlParams = schema.toURLSearchParams(original)
582
- const result = schema.fromURLSearchParams(urlParams)
583
- expect(result).toEqual(original)
584
- })
585
- })
586
-
587
- describe('empty schema', () => {
588
- const schema = params()
589
-
590
- it('validates empty object', () => {
591
- const result = schema.safeParse({})
592
- expect(result.success).toBe(true)
593
- })
594
-
595
- it('accepts additional params', () => {
596
- const result = schema.safeParse({ extra: 'value' })
597
- expect(result.success).toBe(true)
598
- })
599
-
600
- it('rejects non-objects', () => {
601
- const result = schema.safeParse('not an object')
602
- expect(result.success).toBe(false)
603
- })
604
- })
605
-
606
- describe('complex scenarios', () => {
607
- const schema = params({
608
- query: string({ minLength: 1 }),
609
- limit: optional(integer({ minimum: 1, maximum: 100 })),
610
- offset: optional(integer({ minimum: 0 })),
611
- filters: optional(array(string())),
612
- })
613
-
614
- it('validates typical query parameters', () => {
615
- const result = schema.safeParse({
616
- query: 'search term',
617
- limit: 10,
618
- offset: 0,
619
- filters: ['filter1', 'filter2'],
620
- })
621
- expect(result.success).toBe(true)
622
- })
623
-
624
- it('validates minimal query', () => {
625
- const result = schema.safeParse({
626
- query: 'search',
627
- })
628
- expect(result.success).toBe(true)
629
- })
630
-
631
- it('rejects empty query string', () => {
632
- const result = schema.safeParse({
633
- query: '',
634
- })
635
- expect(result.success).toBe(false)
636
- })
637
-
638
- it('rejects limit out of range', () => {
639
- const result = schema.safeParse({
640
- query: 'search',
641
- limit: 200,
642
- })
643
- expect(result.success).toBe(false)
644
- })
645
-
646
- it('rejects negative offset', () => {
647
- const result = schema.safeParse({
648
- query: 'search',
649
- offset: -1,
650
- })
651
- expect(result.success).toBe(false)
652
- })
653
-
654
- it('accepts additional unspecified params', () => {
655
- const result = schema.safeParse({
656
- query: 'search',
657
- extra: 'value',
658
- })
659
- expect(result.success).toBe(true)
660
- })
661
- })
662
-
663
- describe('edge cases', () => {
664
- const schema = params({
665
- name: string(),
666
- })
667
-
668
- it('rejects objects with custom prototypes', () => {
669
- const obj = Object.create({ inherited: 'value' })
670
- obj.name = 'Alice'
671
- const result = schema.safeParse(obj)
672
- expect(result.success).toBe(false)
673
- })
674
-
675
- it('validates with numeric string keys', () => {
676
- const result = schema.safeParse({
677
- name: 'Alice',
678
- '123': 'numeric key',
679
- })
680
- expect(result.success).toBe(true)
681
- })
682
-
683
- it('handles empty string keys in additional params', () => {
684
- const result = schema.safeParse({
685
- name: 'Alice',
686
- '': 'empty key',
687
- })
688
- expect(result.success).toBe(true)
689
- })
690
- })
691
-
692
- describe('memoized params schema', () => {
693
- it('returns the same instance when no shape is provided', () => {
694
- expect(params()).toBe(params())
695
- })
696
-
697
- it('returns different instances when (identical) shapes are provided', () => {
698
- const schemaA = params({ a: string() })
699
- const schemaB = params({ a: string() })
700
- expect(schemaA).not.toBe(schemaB)
701
- })
702
- })
703
- })
704
-
705
- describe('paramSchema', () => {
706
- describe('scalar values', () => {
707
- it('validates boolean values', () => {
708
- const result = paramSchema.safeParse(true)
709
- expect(result.success).toBe(true)
710
- })
711
-
712
- it('validates integer values', () => {
713
- const result = paramSchema.safeParse(42)
714
- expect(result.success).toBe(true)
715
- })
716
-
717
- it('validates string values', () => {
718
- const result = paramSchema.safeParse('hello')
719
- expect(result.success).toBe(true)
720
- })
721
-
722
- it('validates empty strings', () => {
723
- const result = paramSchema.safeParse('')
724
- expect(result.success).toBe(true)
725
- })
726
-
727
- it('validates zero', () => {
728
- const result = paramSchema.safeParse(0)
729
- expect(result.success).toBe(true)
730
- })
731
-
732
- it('validates negative integers', () => {
733
- const result = paramSchema.safeParse(-50)
734
- expect(result.success).toBe(true)
735
- })
736
-
737
- it('validates false boolean', () => {
738
- const result = paramSchema.safeParse(false)
739
- expect(result.success).toBe(true)
740
- })
741
- })
742
-
743
- describe('array values', () => {
744
- it('validates arrays of booleans', () => {
745
- const result = paramSchema.safeParse([true, false, true])
746
- expect(result.success).toBe(true)
747
- })
748
-
749
- it('validates arrays of integers', () => {
750
- const result = paramSchema.safeParse([1, 2, 3, 4])
751
- expect(result.success).toBe(true)
752
- })
753
-
754
- it('validates arrays of strings', () => {
755
- const result = paramSchema.safeParse(['foo', 'bar', 'baz'])
756
- expect(result.success).toBe(true)
757
- })
758
-
759
- it('validates empty arrays', () => {
760
- const result = paramSchema.safeParse([])
761
- expect(result.success).toBe(true)
762
- })
763
-
764
- it('validates arrays with single element', () => {
765
- const result = paramSchema.safeParse(['single'])
766
- expect(result.success).toBe(true)
767
- })
768
-
769
- it('rejects arrays with mixed scalar types', () => {
770
- const result = paramSchema.safeParse([true, 42, 'text'])
771
- expect(result.success).toBe(false)
772
- })
773
-
774
- it('validates arrays with negative integers', () => {
775
- const result = paramSchema.safeParse([-1, -2, -3])
776
- expect(result.success).toBe(true)
777
- })
778
-
779
- it('validates arrays with empty strings', () => {
780
- const result = paramSchema.safeParse(['', 'non-empty', ''])
781
- expect(result.success).toBe(true)
782
- })
783
-
784
- it('validates arrays with zero', () => {
785
- const result = paramSchema.safeParse([0, 1, 2])
786
- expect(result.success).toBe(true)
787
- })
788
-
789
- it('rejects nested arrays', () => {
790
- const result = paramSchema.safeParse([
791
- [1, 2],
792
- [3, 4],
793
- ])
794
- expect(result.success).toBe(false)
795
- })
796
-
797
- it('rejects arrays with null values', () => {
798
- const result = paramSchema.safeParse([1, null, 3])
799
- expect(result.success).toBe(false)
800
- })
801
-
802
- it('rejects arrays with undefined values', () => {
803
- const result = paramSchema.safeParse([1, undefined, 3])
804
- expect(result.success).toBe(false)
805
- })
806
-
807
- it('rejects arrays with object values', () => {
808
- const result = paramSchema.safeParse([1, { key: 'value' }, 3])
809
- expect(result.success).toBe(false)
810
- })
811
-
812
- it('rejects arrays with floating point numbers', () => {
813
- const result = paramSchema.safeParse([1, 2.5, 3])
814
- expect(result.success).toBe(false)
815
- })
816
-
817
- it('rejects arrays with NaN', () => {
818
- const result = paramSchema.safeParse([1, NaN, 3])
819
- expect(result.success).toBe(false)
820
- })
821
-
822
- it('rejects arrays with Infinity', () => {
823
- const result = paramSchema.safeParse([1, Infinity, 3])
824
- expect(result.success).toBe(false)
825
- })
826
- })
827
-
828
- describe('invalid values', () => {
829
- it('rejects null values', () => {
830
- const result = paramSchema.safeParse(null)
831
- expect(result.success).toBe(false)
832
- })
833
-
834
- it('rejects undefined values', () => {
835
- const result = paramSchema.safeParse(undefined)
836
- expect(result.success).toBe(false)
837
- })
838
-
839
- it('rejects object values', () => {
840
- const result = paramSchema.safeParse({ key: 'value' })
841
- expect(result.success).toBe(false)
842
- })
843
-
844
- it('rejects floating point numbers', () => {
845
- const result = paramSchema.safeParse(3.14)
846
- expect(result.success).toBe(false)
847
- })
848
-
849
- it('rejects NaN', () => {
850
- const result = paramSchema.safeParse(NaN)
851
- expect(result.success).toBe(false)
852
- })
853
-
854
- it('rejects Infinity', () => {
855
- const result = paramSchema.safeParse(Infinity)
856
- expect(result.success).toBe(false)
857
- })
858
-
859
- it('rejects -Infinity', () => {
860
- const result = paramSchema.safeParse(-Infinity)
861
- expect(result.success).toBe(false)
862
- })
863
- })
864
- })
865
-
866
- describe('paramsSchema', () => {
867
- it('validates empty object', () => {
868
- const result = paramsSchema.safeParse({})
869
- expect(result.success).toBe(true)
870
- })
871
-
872
- it('validates object with boolean parameters', () => {
873
- const result = paramsSchema.safeParse({
874
- enabled: true,
875
- disabled: false,
876
- })
877
- expect(result.success).toBe(true)
878
- })
879
-
880
- it('validates object with integer parameters', () => {
881
- const result = paramsSchema.safeParse({
882
- limit: 10,
883
- offset: 0,
884
- count: 100,
885
- })
886
- expect(result.success).toBe(true)
887
- })
888
-
889
- it('validates object with string parameters', () => {
890
- const result = paramsSchema.safeParse({
891
- name: 'Alice',
892
- query: 'search term',
893
- cursor: 'abc123',
894
- })
895
- expect(result.success).toBe(true)
896
- })
897
-
898
- it('validates object with array parameters', () => {
899
- const result = paramsSchema.safeParse({
900
- tags: ['tag1', 'tag2', 'tag3'],
901
- ids: [1, 2, 3, 4],
902
- flags: [true, false, true],
903
- })
904
- expect(result.success).toBe(true)
905
- })
906
-
907
- it('validates object with mixed parameter types', () => {
908
- const result = paramsSchema.safeParse({
909
- name: 'Alice',
910
- age: 30,
911
- active: true,
912
- tags: ['user', 'admin'],
913
- limit: 50,
914
- })
915
- expect(result.success).toBe(true)
916
- })
917
-
918
- it('validates object with empty string parameters', () => {
919
- const result = paramsSchema.safeParse({
920
- query: '',
921
- cursor: '',
922
- })
923
- expect(result.success).toBe(true)
924
- })
925
-
926
- it('validates object with negative integer parameters', () => {
927
- const result = paramsSchema.safeParse({
928
- offset: -10,
929
- delta: -5,
930
- })
931
- expect(result.success).toBe(true)
932
- })
933
-
934
- it('validates object with empty array parameters', () => {
935
- const result = paramsSchema.safeParse({
936
- tags: [],
937
- ids: [],
938
- })
939
- expect(result.success).toBe(true)
940
- })
941
-
942
- it('rejects object with arrays of mixed scalar types', () => {
943
- const result = paramsSchema.safeParse({
944
- values: [true, 42, 'text'],
945
- })
946
- expect(result.success).toBe(false)
947
- })
948
-
949
- it('validates object with numeric string keys', () => {
950
- const result = paramsSchema.safeParse({
951
- '0': 'value0',
952
- '1': 'value1',
953
- '2': 'value2',
954
- })
955
- expect(result.success).toBe(true)
956
- })
957
-
958
- it('rejects non-object values', () => {
959
- const result = paramsSchema.safeParse('not an object')
960
- expect(result.success).toBe(false)
961
- })
962
-
963
- it('rejects null values', () => {
964
- const result = paramsSchema.safeParse(null)
965
- expect(result.success).toBe(false)
966
- })
967
-
968
- it('rejects undefined values', () => {
969
- const result = paramsSchema.safeParse(undefined)
970
- expect(result.success).toBe(false)
971
- })
972
-
973
- it('rejects arrays', () => {
974
- const result = paramsSchema.safeParse([1, 2, 3])
975
- expect(result.success).toBe(false)
976
- })
977
-
978
- it('rejects object with null parameter values', () => {
979
- const result = paramsSchema.safeParse({
980
- name: 'Alice',
981
- invalid: null,
982
- })
983
- expect(result.success).toBe(false)
984
- })
985
-
986
- it('rejects object with floating point parameter values', () => {
987
- const result = paramsSchema.safeParse({
988
- value: 3.14,
989
- })
990
- expect(result.success).toBe(false)
991
- })
992
-
993
- it('rejects object with NaN parameter values', () => {
994
- const result = paramsSchema.safeParse({
995
- value: NaN,
996
- })
997
- expect(result.success).toBe(false)
998
- })
999
-
1000
- it('rejects object with Infinity parameter values', () => {
1001
- const result = paramsSchema.safeParse({
1002
- value: Infinity,
1003
- })
1004
- expect(result.success).toBe(false)
1005
- })
1006
-
1007
- it('rejects object with object parameter values', () => {
1008
- const result = paramsSchema.safeParse({
1009
- nested: { key: 'value' },
1010
- })
1011
- expect(result.success).toBe(false)
1012
- })
1013
-
1014
- it('rejects object with nested array parameter values', () => {
1015
- const result = paramsSchema.safeParse({
1016
- nested: [
1017
- [1, 2],
1018
- [3, 4],
1019
- ],
1020
- })
1021
- expect(result.success).toBe(false)
1022
- })
1023
-
1024
- it('rejects object with arrays containing invalid values', () => {
1025
- const result = paramsSchema.safeParse({
1026
- tags: ['valid', null, 'also valid'],
1027
- })
1028
- expect(result.success).toBe(false)
1029
- })
1030
-
1031
- it('rejects object with arrays containing objects', () => {
1032
- const result = paramsSchema.safeParse({
1033
- items: [1, { key: 'value' }, 3],
1034
- })
1035
- expect(result.success).toBe(false)
1036
- })
1037
-
1038
- it('rejects object with arrays containing floating point numbers', () => {
1039
- const result = paramsSchema.safeParse({
1040
- values: [1, 2.5, 3],
1041
- })
1042
- expect(result.success).toBe(false)
1043
- })
1044
-
1045
- it('rejects when one parameter is invalid', () => {
1046
- const result = paramsSchema.safeParse({
1047
- valid1: 'string',
1048
- valid2: 42,
1049
- invalid: null,
1050
- valid3: true,
1051
- })
1052
- expect(result.success).toBe(false)
1053
- })
1054
-
1055
- describe('edge cases', () => {
1056
- it('validates single parameter', () => {
1057
- const result = paramsSchema.safeParse({
1058
- single: 'value',
1059
- })
1060
- expect(result.success).toBe(true)
1061
- })
1062
-
1063
- it('validates many parameters', () => {
1064
- const manyParams: Record<string, string> = {}
1065
- for (let i = 0; i < 100; i++) {
1066
- manyParams[`param${i}`] = `value${i}`
1067
- }
1068
- const result = paramsSchema.safeParse(manyParams)
1069
- expect(result.success).toBe(true)
1070
- })
1071
-
1072
- it('validates parameters with long string values', () => {
1073
- const result = paramsSchema.safeParse({
1074
- longString: 'a'.repeat(1000),
1075
- })
1076
- expect(result.success).toBe(true)
1077
- })
1078
-
1079
- it('validates parameters with large integer values', () => {
1080
- const result = paramsSchema.safeParse({
1081
- largeInt: 2147483647,
1082
- negativeInt: -2147483648,
1083
- })
1084
- expect(result.success).toBe(true)
1085
- })
1086
-
1087
- it('validates parameters with long arrays', () => {
1088
- const result = paramsSchema.safeParse({
1089
- longArray: Array.from({ length: 100 }, (_, i) => i),
1090
- })
1091
- expect(result.success).toBe(true)
1092
- })
1093
-
1094
- it('validates parameters with special characters in keys', () => {
1095
- const result = paramsSchema.safeParse({
1096
- 'key-with-dashes': 'value',
1097
- key_with_underscores: 'value',
1098
- 'key.with.dots': 'value',
1099
- })
1100
- expect(result.success).toBe(true)
1101
- })
1102
-
1103
- it('preserves original object when no transformations occur', () => {
1104
- const input = {
1105
- name: 'Alice',
1106
- age: 30,
1107
- tags: ['user'],
1108
- }
1109
- const result = paramsSchema.safeParse(input)
1110
-
1111
- if (result.success) {
1112
- expect(result.value).toBe(input)
1113
- } else {
1114
- throw new Error('Expected validation to succeed')
1115
- }
1116
- })
1117
- })
1118
- })