@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
package/src/helpers.ts DELETED
@@ -1,222 +0,0 @@
1
- import { LexErrorData } from '@atproto/lex-data'
2
- import {
3
- AtIdentifierString,
4
- InferOutput,
5
- NsidString,
6
- RecordKeyValue,
7
- Restricted,
8
- Schema,
9
- assertAtIdentifierString,
10
- assertStringFormat,
11
- } from './core.js'
12
- import {
13
- InferPayload,
14
- InferPayloadBody,
15
- InferPayloadEncoding,
16
- InferRecordKey,
17
- Procedure,
18
- Query,
19
- RecordSchema,
20
- Subscription,
21
- object,
22
- optional,
23
- regexp,
24
- string,
25
- } from './schema.js'
26
-
27
- export type Main<T> = T | { main: T }
28
-
29
- export function getMain<T extends object>(ns: Main<T>): T {
30
- return 'main' in ns ? ns.main : ns
31
- }
32
-
33
- /**
34
- * Every XRPC implementation should translate `application/json` and `text/*`
35
- * payloads into their native equivalent ({@link LexValue} or string). Binary
36
- * data payloads, however, can be represented differently depending on the
37
- * environment and use case (e.g. `Uint8Array`, `Blob`, `Buffer`,
38
- * `ReadableStream`, etc.). This type is a placeholder to represent binary data
39
- * when not explicitly provided.
40
- */
41
- export type BinaryData = Restricted<'Binary data'>
42
-
43
- export type InferMethodParams<
44
- M extends Procedure | Query | Subscription = Procedure | Query | Subscription,
45
- > =
46
- M extends Procedure<any, infer TParams, any, any, any>
47
- ? InferOutput<TParams>
48
- : M extends Query<any, infer TParams, any, any>
49
- ? InferOutput<TParams>
50
- : M extends Subscription<any, infer TParams, any, any>
51
- ? InferOutput<TParams>
52
- : never
53
-
54
- export type InferMethodInput<
55
- M extends Procedure | Query | Subscription = Procedure | Query | Subscription,
56
- B = BinaryData,
57
- > =
58
- M extends Procedure<any, any, infer TInput, any, any>
59
- ? InferPayload<TInput, B>
60
- : undefined
61
-
62
- export type InferMethodInputBody<
63
- M extends Procedure | Query | Subscription = Procedure | Query | Subscription,
64
- B = BinaryData,
65
- > =
66
- M extends Procedure<any, any, infer TInput, any, any>
67
- ? InferPayloadBody<TInput, B>
68
- : undefined
69
-
70
- export type InferMethodInputEncoding<
71
- M extends Procedure | Query | Subscription = Procedure | Query | Subscription,
72
- > =
73
- M extends Procedure<any, any, infer TInput, any, any>
74
- ? InferPayloadEncoding<TInput>
75
- : undefined
76
-
77
- export type InferMethodOutput<
78
- M extends Procedure | Query | Subscription = Procedure | Query | Subscription,
79
- B = BinaryData,
80
- > =
81
- M extends Procedure<any, any, any, infer TOutput, any>
82
- ? InferPayload<TOutput, B>
83
- : M extends Query<any, any, infer TOutput, any>
84
- ? InferPayload<TOutput, B>
85
- : undefined
86
-
87
- export type InferMethodOutputBody<
88
- M extends Procedure | Query | Subscription = Procedure | Query | Subscription,
89
- B = BinaryData,
90
- > =
91
- M extends Procedure<any, any, any, infer TOutput, any>
92
- ? InferPayloadBody<TOutput, B>
93
- : M extends Query<any, any, infer TOutput, any>
94
- ? InferPayloadBody<TOutput, B>
95
- : undefined
96
-
97
- export type InferMethodOutputEncoding<
98
- M extends Procedure | Query | Subscription = Procedure | Query | Subscription,
99
- > =
100
- M extends Procedure<any, any, any, infer TOutput, any>
101
- ? InferPayloadEncoding<TOutput>
102
- : M extends Query<any, any, infer TOutput, any>
103
- ? InferPayloadEncoding<TOutput>
104
- : undefined
105
-
106
- export type InferMethodMessage<
107
- M extends Procedure | Query | Subscription = Procedure | Query | Subscription,
108
- > =
109
- M extends Subscription<any, any, infer TMessage, any>
110
- ? InferOutput<TMessage>
111
- : undefined
112
-
113
- export type InferMethodError<
114
- //
115
- M extends Procedure | Query | Subscription = Procedure | Query | Subscription,
116
- > = M extends { errors: readonly (infer E extends string)[] } ? E : never
117
-
118
- /**
119
- * @see {@link https://atproto.com/specs/xrpc#error-responses}
120
- */
121
- export const lexErrorDataSchema = object({
122
- // type name of the error (generic ASCII constant, no whitespace)
123
- error: regexp(/^[\w_-]+$/, 'Expected ASCII constant with no whitespace'),
124
- // description of the error, appropriate for display to humans
125
- message: optional(string()),
126
- }) satisfies Schema<LexErrorData>
127
-
128
- /**
129
- * Helper function to construct AT Protocol URIs with compile-time & runtime
130
- * validation of their components. This function supports different use cases,
131
- * including constructing URIs from raw strings or from RecordSchema instances,
132
- * ensuring that the resulting URI adheres to the expected format.
133
- *
134
- * @throws {TypeError} If the arguments do not match the interface
135
- * @throws {Error} If AT-URI components are invalid
136
- *
137
- * @example
138
- * ```typescript
139
- * import { atUri } from '@atproto/lex'
140
- * import { app } from '#/lexicons/index.js'
141
- *
142
- * // Constructing a URI from raw components
143
- * const uri1 = atUri('did:example:123', 'app.bsky.feed.post', 'my-post')
144
- *
145
- * // Constructing a URI from a RecordSchema instance
146
- * const uri2 = atUri('did:example:123', app.bsky.feed.post, 'my-post')
147
- *
148
- * // Literal rkey can be omitted
149
- * const uri3 = atUri('did:example:123', app.bsky.actor.profile) // rkey 'self' is implied
150
- *
151
- * // Invalid URIs will throw errors
152
- * atUri('invalid authority', 'app.bsky.feed.post', 'my-post') // throws
153
- * atUri('did:example:123', 'invalid collection', 'my-post') // throws
154
- * atUri('did:example:123', 'app.bsky.feed.post', '..') // throws
155
- * ```
156
- */
157
- export function atUri<const TAuthority extends AtIdentifierString>(
158
- authority: TAuthority,
159
- ): `at://${TAuthority}`
160
- export function atUri<
161
- const TAuthority extends AtIdentifierString,
162
- const TCollection extends NsidString,
163
- const TRecordKey extends RecordKeyValue,
164
- >(
165
- authority: TAuthority,
166
- nsid: TCollection,
167
- rkey: TRecordKey extends '..' | '.' ? never : TRecordKey,
168
- ): `at://${TAuthority}/${TCollection}/${TRecordKey}`
169
- export function atUri<
170
- const TAuthority extends AtIdentifierString,
171
- const TRecord extends RecordSchema,
172
- >(
173
- authority: TAuthority,
174
- record: TRecord['key'] extends `literal:${string}` ? Main<TRecord> : never,
175
- ): `at://${TAuthority}/${TRecord['$type']}/${InferRecordKey<TRecord>}`
176
- export function atUri<
177
- const TAuthority extends AtIdentifierString,
178
- const TRecord extends RecordSchema,
179
- const TRecordKey extends InferRecordKey<TRecord>,
180
- >(
181
- authority: TAuthority,
182
- record: Main<TRecord>,
183
- rkey: TRecordKey extends '..' | '.' ? never : TRecordKey,
184
- ): `at://${TAuthority}/${TRecord['$type']}/${TRecordKey}`
185
- export function atUri(
186
- authority: AtIdentifierString,
187
- record?: string | Main<RecordSchema>,
188
- rkey?: string,
189
- ) {
190
- /**
191
- * @NOTE because we are encoding potentially untrusted input into a URI, we
192
- * validate the input against the AT Protocol constraints, ensuring that no
193
- * invalid URIs can be generated.
194
- */
195
- switch (typeof record) {
196
- case 'undefined': {
197
- assertAtIdentifierString(authority)
198
- return `at://${authority}`
199
- }
200
-
201
- case 'string': {
202
- if (!rkey) {
203
- throw new TypeError('Record key is required when record is a string')
204
- }
205
- assertAtIdentifierString(authority)
206
- assertStringFormat(record, 'nsid')
207
- assertStringFormat(rkey, 'record-key')
208
- return `at://${authority}/${record}/${rkey}`
209
- }
210
-
211
- default: {
212
- // @NOTE The use of a schema assumes that the collection ($type) is a
213
- // valid NSID that can safely be included in the URI without additional
214
- // checks.
215
- assertAtIdentifierString(authority)
216
- const schema = getMain(record)
217
- // @NOTE parsing will apply defaults, so that literal keys will be
218
- // properly validated and included in the URI.
219
- return `at://${authority}/${schema.$type}/${schema.keySchema.parse(rkey)}`
220
- }
221
- }
222
- }
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- import * as l from './external.js'
2
- export * from './external.js'
3
- export { l }
@@ -1,251 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { array } from './array.js'
3
- import { integer } from './integer.js'
4
- import { object } from './object.js'
5
- import { string } from './string.js'
6
-
7
- describe('ArraySchema', () => {
8
- describe('validation', () => {
9
- it('validates arrays with string items', () => {
10
- const schema = array(string())
11
- const result = schema.safeValidate(['hello', 'world'])
12
- expect(result).toMatchObject({ success: true })
13
- })
14
-
15
- it('validates arrays with integer items', () => {
16
- const schema = array(integer())
17
- const result = schema.safeValidate([1, 2, 3])
18
- expect(result).toMatchObject({ success: true })
19
- })
20
-
21
- it('validates arrays with object items', () => {
22
- const schema = array(
23
- object({
24
- name: string(),
25
- age: integer(),
26
- }),
27
- )
28
- const result = schema.safeValidate([
29
- { name: 'Alice', age: 30 },
30
- { name: 'Bob', age: 25 },
31
- ])
32
- expect(result).toMatchObject({ success: true })
33
- })
34
-
35
- it('validates empty arrays', () => {
36
- const schema = array(string())
37
- const result = schema.safeValidate([])
38
- expect(result).toMatchObject({ success: true })
39
- })
40
-
41
- it('rejects non-array values', () => {
42
- const schema = array(string())
43
- const result = schema.safeValidate('not an array')
44
- expect(result).toMatchObject({ success: false })
45
- })
46
-
47
- it('rejects null values', () => {
48
- const schema = array(string())
49
- const result = schema.safeValidate(null)
50
- expect(result).toMatchObject({ success: false })
51
- })
52
-
53
- it('rejects undefined values', () => {
54
- const schema = array(string())
55
- const result = schema.safeValidate(undefined)
56
- expect(result).toMatchObject({ success: false })
57
- })
58
-
59
- it('rejects objects that look like arrays', () => {
60
- const schema = array(string())
61
- const result = schema.safeValidate({ 0: 'a', 1: 'b', length: 2 })
62
- expect(result).toMatchObject({ success: false })
63
- })
64
-
65
- it('rejects arrays with invalid items', () => {
66
- const schema = array(integer())
67
- const result = schema.safeValidate([1, 2, 'three'])
68
- expect(result).toMatchObject({ success: false })
69
- })
70
-
71
- it('rejects arrays with some invalid items', () => {
72
- const schema = array(string())
73
- const result = schema.safeValidate(['valid', null, 'also valid'])
74
- expect(result).toMatchObject({ success: false })
75
- })
76
-
77
- it('rejects single values', () => {
78
- const schema = array(string())
79
- const result = schema.safeValidate(3)
80
- expect(result).toMatchObject({
81
- success: false,
82
- reason: expect.objectContaining({
83
- message: expect.stringContaining(
84
- 'Expected array value type (got 3) at $',
85
- ),
86
- }),
87
- })
88
- })
89
- })
90
-
91
- describe('minLength constraint', () => {
92
- it('validates arrays meeting minLength', () => {
93
- const schema = array(string(), { minLength: 2 })
94
- const result = schema.safeParse(['a', 'b'])
95
- expect(result).toMatchObject({ success: true })
96
- })
97
-
98
- it('validates arrays exceeding minLength', () => {
99
- const schema = array(string(), { minLength: 2 })
100
- const result = schema.safeParse(['a', 'b', 'c'])
101
- expect(result).toMatchObject({ success: true })
102
- })
103
-
104
- it('rejects arrays below minLength', () => {
105
- const schema = array(string(), { minLength: 3 })
106
- const result = schema.safeParse(['a', 'b'])
107
- expect(result).toMatchObject({ success: false })
108
- })
109
-
110
- it('rejects empty arrays when minLength is set', () => {
111
- const schema = array(string(), { minLength: 1 })
112
- const result = schema.safeParse([])
113
- expect(result).toMatchObject({ success: false })
114
- })
115
-
116
- it('validates empty arrays when minLength is 0', () => {
117
- const schema = array(string(), { minLength: 0 })
118
- const result = schema.safeParse([])
119
- expect(result).toMatchObject({ success: true })
120
- })
121
- })
122
-
123
- describe('maxLength constraint', () => {
124
- it('validates arrays meeting maxLength', () => {
125
- const schema = array(string(), { maxLength: 3 })
126
- const result = schema.safeParse(['a', 'b', 'c'])
127
- expect(result).toMatchObject({ success: true })
128
- })
129
-
130
- it('validates arrays below maxLength', () => {
131
- const schema = array(string(), { maxLength: 3 })
132
- const result = schema.safeParse(['a', 'b'])
133
- expect(result).toMatchObject({ success: true })
134
- })
135
-
136
- it('rejects arrays exceeding maxLength', () => {
137
- const schema = array(string(), { maxLength: 2 })
138
- const result = schema.safeParse(['a', 'b', 'c'])
139
- expect(result).toMatchObject({ success: false })
140
- })
141
-
142
- it('validates empty arrays with maxLength', () => {
143
- const schema = array(string(), { maxLength: 5 })
144
- const result = schema.safeParse([])
145
- expect(result).toMatchObject({ success: true })
146
- })
147
-
148
- it('rejects empty arrays when maxLength is 0', () => {
149
- const schema = array(string(), { maxLength: 0 })
150
- const result = schema.safeParse(['a'])
151
- expect(result).toMatchObject({ success: false })
152
- })
153
-
154
- it('validates empty arrays when maxLength is 0', () => {
155
- const schema = array(string(), { maxLength: 0 })
156
- const result = schema.safeParse([])
157
- expect(result).toMatchObject({ success: true })
158
- })
159
- })
160
-
161
- describe('minLength and maxLength together', () => {
162
- it('validates arrays within range', () => {
163
- const schema = array(string(), {
164
- minLength: 2,
165
- maxLength: 4,
166
- })
167
- const result = schema.safeParse(['a', 'b', 'c'])
168
- expect(result).toMatchObject({ success: true })
169
- })
170
-
171
- it('validates arrays at min boundary', () => {
172
- const schema = array(string(), {
173
- minLength: 2,
174
- maxLength: 4,
175
- })
176
- const result = schema.safeParse(['a', 'b'])
177
- expect(result).toMatchObject({ success: true })
178
- })
179
-
180
- it('validates arrays at max boundary', () => {
181
- const schema = array(string(), {
182
- minLength: 2,
183
- maxLength: 4,
184
- })
185
- const result = schema.safeParse(['a', 'b', 'c', 'd'])
186
- expect(result).toMatchObject({ success: true })
187
- })
188
-
189
- it('rejects arrays below minLength', () => {
190
- const schema = array(string(), {
191
- minLength: 2,
192
- maxLength: 4,
193
- })
194
- const result = schema.safeParse(['a'])
195
- expect(result).toMatchObject({ success: false })
196
- })
197
-
198
- it('rejects arrays above maxLength', () => {
199
- const schema = array(string(), {
200
- minLength: 2,
201
- maxLength: 4,
202
- })
203
- const result = schema.safeParse(['a', 'b', 'c', 'd', 'e'])
204
- expect(result).toMatchObject({ success: false })
205
- })
206
-
207
- it('validates single-length range', () => {
208
- const schema = array(string(), {
209
- minLength: 3,
210
- maxLength: 3,
211
- })
212
- const result = schema.safeParse(['a', 'b', 'c'])
213
- expect(result).toMatchObject({ success: true })
214
- })
215
-
216
- it('rejects arrays not matching exact length', () => {
217
- const schema = array(string(), {
218
- minLength: 3,
219
- maxLength: 3,
220
- })
221
- const result = schema.safeParse(['a', 'b'])
222
- expect(result).toMatchObject({ success: false })
223
- })
224
- })
225
-
226
- describe('nested arrays', () => {
227
- it('validates arrays of arrays', () => {
228
- const schema = array(array(string()))
229
- const result = schema.safeParse([
230
- ['a', 'b'],
231
- ['c', 'd'],
232
- ])
233
- expect(result).toMatchObject({ success: true })
234
- })
235
-
236
- it('rejects invalid nested arrays', () => {
237
- const schema = array(array(integer()))
238
- const result = schema.safeParse([
239
- [1, 2],
240
- [3, 'four'],
241
- ])
242
- expect(result).toMatchObject({ success: false })
243
- })
244
-
245
- it('validates deeply nested arrays', () => {
246
- const schema = array(array(array(integer())))
247
- const result = schema.safeParse([[[1, 2], [3]], [[4, 5, 6]]])
248
- expect(result).toMatchObject({ success: true })
249
- })
250
- })
251
- })
@@ -1,126 +0,0 @@
1
- import {
2
- InferInput,
3
- InferOutput,
4
- Schema,
5
- ValidationContext,
6
- Validator,
7
- } from '../core.js'
8
- import { memoizedTransformer } from '../util/memoize.js'
9
-
10
- /**
11
- * Configuration options for array schema validation.
12
- *
13
- * @property minLength - Minimum number of items in the array
14
- * @property maxLength - Maximum number of items in the array
15
- */
16
- export type ArraySchemaOptions = {
17
- minLength?: number
18
- maxLength?: number
19
- }
20
-
21
- /**
22
- * Schema for validating arrays where all items match a given schema.
23
- *
24
- * Validates that the input is an array, checks length constraints, and
25
- * validates each item against the provided item schema.
26
- *
27
- * @template TItem - The validator type for array items
28
- *
29
- * @example
30
- * ```ts
31
- * const schema = new ArraySchema(l.string(), { maxLength: 10 })
32
- * const result = schema.validate(['a', 'b', 'c'])
33
- * ```
34
- */
35
- export class ArraySchema<const TItem extends Validator> extends Schema<
36
- Array<InferInput<TItem>>,
37
- Array<InferOutput<TItem>>
38
- > {
39
- readonly type = 'array' as const
40
-
41
- constructor(
42
- readonly validator: TItem,
43
- readonly options: ArraySchemaOptions = {},
44
- ) {
45
- super()
46
- }
47
-
48
- validateInContext(input: unknown, ctx: ValidationContext) {
49
- if (!Array.isArray(input)) {
50
- return ctx.issueUnexpectedType(input, 'array')
51
- }
52
-
53
- const { minLength, maxLength } = this.options
54
-
55
- if (minLength != null && input.length < minLength) {
56
- return ctx.issueTooSmall(input, 'array', minLength, input.length)
57
- }
58
-
59
- if (maxLength != null && input.length > maxLength) {
60
- return ctx.issueTooBig(input, 'array', maxLength, input.length)
61
- }
62
-
63
- let copy: undefined | unknown[]
64
-
65
- for (let i = 0; i < input.length; i++) {
66
- const result = ctx.validateChild(input, i, this.validator)
67
- if (!result.success) return result
68
-
69
- if (result.value !== input[i]) {
70
- if (ctx.options.mode === 'validate') {
71
- // In "validate" mode, we can't modify the input, so we issue an error
72
- return ctx.issueInvalidPropertyValue(input, i, [result.value])
73
- }
74
-
75
- // Copy on write (but only if we did not already make a copy)
76
- copy ??= Array.from(input)
77
- copy[i] = result.value
78
- }
79
- }
80
-
81
- return ctx.success(copy ?? input)
82
- }
83
- }
84
-
85
- /**
86
- * Creates an array schema that validates each item against the provided schema.
87
- *
88
- * @param items - Schema to validate each array item against
89
- * @param options - Optional length constraints
90
- * @returns A new {@link ArraySchema} instance
91
- *
92
- * @example
93
- * ```ts
94
- * // Array of strings
95
- * const tagsSchema = l.array(l.string())
96
- *
97
- * // Array with length constraints
98
- * const limitedSchema = l.array(l.integer(), { maxLength: 100 })
99
- *
100
- * // Array of objects
101
- * const usersSchema = l.array(l.object({
102
- * name: l.string(),
103
- * age: l.integer(),
104
- * }))
105
- *
106
- * // Non-empty array
107
- * const nonEmptySchema = l.array(l.string(), { minLength: 1 })
108
- * ```
109
- */
110
- /*@__NO_SIDE_EFFECTS__*/
111
- function arraySchema<const TValidator extends Validator>(
112
- items: TValidator,
113
- options?: ArraySchemaOptions,
114
- ): ArraySchema<TValidator>
115
- function arraySchema<
116
- const TValue,
117
- const TValidator extends Validator<TValue> = Validator<TValue>,
118
- >(items: TValidator, options?: ArraySchemaOptions): ArraySchema<TValidator>
119
- function arraySchema<const TValidator extends Validator>(
120
- items: TValidator,
121
- options?: ArraySchemaOptions,
122
- ) {
123
- return new ArraySchema<TValidator>(items, options)
124
- }
125
-
126
- export const array = /*#__PURE__*/ memoizedTransformer(arraySchema)