@atproto/lex-schema 0.0.11 → 0.0.13

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 (261) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/core/$type.d.ts +149 -0
  3. package/dist/core/$type.d.ts.map +1 -1
  4. package/dist/core/$type.js +44 -0
  5. package/dist/core/$type.js.map +1 -1
  6. package/dist/core/record-key.d.ts +44 -0
  7. package/dist/core/record-key.d.ts.map +1 -1
  8. package/dist/core/record-key.js +30 -0
  9. package/dist/core/record-key.js.map +1 -1
  10. package/dist/core/result.d.ts +85 -4
  11. package/dist/core/result.d.ts.map +1 -1
  12. package/dist/core/result.js +60 -4
  13. package/dist/core/result.js.map +1 -1
  14. package/dist/core/schema.d.ts +232 -5
  15. package/dist/core/schema.d.ts.map +1 -1
  16. package/dist/core/schema.js +197 -4
  17. package/dist/core/schema.js.map +1 -1
  18. package/dist/core/string-format.d.ts +244 -11
  19. package/dist/core/string-format.d.ts.map +1 -1
  20. package/dist/core/string-format.js +150 -0
  21. package/dist/core/string-format.js.map +1 -1
  22. package/dist/core/types.d.ts +90 -3
  23. package/dist/core/types.d.ts.map +1 -1
  24. package/dist/core/types.js.map +1 -1
  25. package/dist/core/validation-error.d.ts +60 -0
  26. package/dist/core/validation-error.d.ts.map +1 -1
  27. package/dist/core/validation-error.js +60 -0
  28. package/dist/core/validation-error.js.map +1 -1
  29. package/dist/core/validation-issue.d.ts +61 -0
  30. package/dist/core/validation-issue.d.ts.map +1 -1
  31. package/dist/core/validation-issue.js +54 -1
  32. package/dist/core/validation-issue.js.map +1 -1
  33. package/dist/core/validator.d.ts +356 -11
  34. package/dist/core/validator.d.ts.map +1 -1
  35. package/dist/core/validator.js +203 -4
  36. package/dist/core/validator.js.map +1 -1
  37. package/dist/helpers.d.ts +12 -28
  38. package/dist/helpers.d.ts.map +1 -1
  39. package/dist/helpers.js.map +1 -1
  40. package/dist/schema/array.d.ts +46 -0
  41. package/dist/schema/array.d.ts.map +1 -1
  42. package/dist/schema/array.js +16 -1
  43. package/dist/schema/array.js.map +1 -1
  44. package/dist/schema/blob.d.ts +50 -2
  45. package/dist/schema/blob.d.ts.map +1 -1
  46. package/dist/schema/blob.js +44 -2
  47. package/dist/schema/blob.js.map +1 -1
  48. package/dist/schema/boolean.d.ts +29 -0
  49. package/dist/schema/boolean.d.ts.map +1 -1
  50. package/dist/schema/boolean.js +30 -1
  51. package/dist/schema/boolean.js.map +1 -1
  52. package/dist/schema/bytes.d.ts +39 -0
  53. package/dist/schema/bytes.d.ts.map +1 -1
  54. package/dist/schema/bytes.js +34 -1
  55. package/dist/schema/bytes.js.map +1 -1
  56. package/dist/schema/cid.d.ts +39 -0
  57. package/dist/schema/cid.d.ts.map +1 -1
  58. package/dist/schema/cid.js +35 -1
  59. package/dist/schema/cid.js.map +1 -1
  60. package/dist/schema/custom.d.ts +67 -1
  61. package/dist/schema/custom.d.ts.map +1 -1
  62. package/dist/schema/custom.js +55 -0
  63. package/dist/schema/custom.js.map +1 -1
  64. package/dist/schema/dict.d.ts +45 -0
  65. package/dist/schema/dict.d.ts.map +1 -1
  66. package/dist/schema/dict.js +46 -1
  67. package/dist/schema/dict.js.map +1 -1
  68. package/dist/schema/discriminated-union.d.ts +59 -0
  69. package/dist/schema/discriminated-union.d.ts.map +1 -1
  70. package/dist/schema/discriminated-union.js +47 -1
  71. package/dist/schema/discriminated-union.js.map +1 -1
  72. package/dist/schema/enum.d.ts +49 -0
  73. package/dist/schema/enum.d.ts.map +1 -1
  74. package/dist/schema/enum.js +49 -0
  75. package/dist/schema/enum.js.map +1 -1
  76. package/dist/schema/integer.d.ts +43 -0
  77. package/dist/schema/integer.d.ts.map +1 -1
  78. package/dist/schema/integer.js +38 -1
  79. package/dist/schema/integer.js.map +1 -1
  80. package/dist/schema/intersection.d.ts +55 -0
  81. package/dist/schema/intersection.d.ts.map +1 -1
  82. package/dist/schema/intersection.js +50 -0
  83. package/dist/schema/intersection.js.map +1 -1
  84. package/dist/schema/lex-map.d.ts +37 -0
  85. package/dist/schema/lex-map.d.ts.map +1 -0
  86. package/dist/schema/lex-map.js +60 -0
  87. package/dist/schema/lex-map.js.map +1 -0
  88. package/dist/schema/lex-value.d.ts +35 -0
  89. package/dist/schema/lex-value.d.ts.map +1 -0
  90. package/dist/schema/lex-value.js +87 -0
  91. package/dist/schema/lex-value.js.map +1 -0
  92. package/dist/schema/literal.d.ts +45 -0
  93. package/dist/schema/literal.d.ts.map +1 -1
  94. package/dist/schema/literal.js +45 -0
  95. package/dist/schema/literal.js.map +1 -1
  96. package/dist/schema/never.d.ts +43 -0
  97. package/dist/schema/never.d.ts.map +1 -1
  98. package/dist/schema/never.js +44 -1
  99. package/dist/schema/never.js.map +1 -1
  100. package/dist/schema/null.d.ts +30 -0
  101. package/dist/schema/null.d.ts.map +1 -1
  102. package/dist/schema/null.js +31 -1
  103. package/dist/schema/null.js.map +1 -1
  104. package/dist/schema/nullable.d.ts +42 -0
  105. package/dist/schema/nullable.d.ts.map +1 -1
  106. package/dist/schema/nullable.js +42 -0
  107. package/dist/schema/nullable.js.map +1 -1
  108. package/dist/schema/object.d.ts +57 -0
  109. package/dist/schema/object.d.ts.map +1 -1
  110. package/dist/schema/object.js +53 -1
  111. package/dist/schema/object.js.map +1 -1
  112. package/dist/schema/optional.d.ts +43 -0
  113. package/dist/schema/optional.d.ts.map +1 -1
  114. package/dist/schema/optional.js +43 -0
  115. package/dist/schema/optional.js.map +1 -1
  116. package/dist/schema/params.d.ts +96 -12
  117. package/dist/schema/params.d.ts.map +1 -1
  118. package/dist/schema/params.js +155 -21
  119. package/dist/schema/params.js.map +1 -1
  120. package/dist/schema/payload.d.ts +111 -15
  121. package/dist/schema/payload.d.ts.map +1 -1
  122. package/dist/schema/payload.js +73 -3
  123. package/dist/schema/payload.js.map +1 -1
  124. package/dist/schema/permission-set.d.ts +58 -0
  125. package/dist/schema/permission-set.d.ts.map +1 -1
  126. package/dist/schema/permission-set.js +50 -0
  127. package/dist/schema/permission-set.js.map +1 -1
  128. package/dist/schema/permission.d.ts +42 -0
  129. package/dist/schema/permission.d.ts.map +1 -1
  130. package/dist/schema/permission.js +39 -0
  131. package/dist/schema/permission.js.map +1 -1
  132. package/dist/schema/procedure.d.ts +64 -0
  133. package/dist/schema/procedure.d.ts.map +1 -1
  134. package/dist/schema/procedure.js +64 -0
  135. package/dist/schema/procedure.js.map +1 -1
  136. package/dist/schema/query.d.ts +55 -0
  137. package/dist/schema/query.d.ts.map +1 -1
  138. package/dist/schema/query.js +55 -0
  139. package/dist/schema/query.js.map +1 -1
  140. package/dist/schema/record.d.ts +76 -25
  141. package/dist/schema/record.d.ts.map +1 -1
  142. package/dist/schema/record.js +21 -0
  143. package/dist/schema/record.js.map +1 -1
  144. package/dist/schema/ref.d.ts +51 -0
  145. package/dist/schema/ref.d.ts.map +1 -1
  146. package/dist/schema/ref.js +18 -0
  147. package/dist/schema/ref.js.map +1 -1
  148. package/dist/schema/refine.d.ts +58 -9
  149. package/dist/schema/refine.d.ts.map +1 -1
  150. package/dist/schema/refine.js.map +1 -1
  151. package/dist/schema/regexp.d.ts +45 -0
  152. package/dist/schema/regexp.d.ts.map +1 -1
  153. package/dist/schema/regexp.js +46 -1
  154. package/dist/schema/regexp.js.map +1 -1
  155. package/dist/schema/string.d.ts +72 -6
  156. package/dist/schema/string.d.ts.map +1 -1
  157. package/dist/schema/string.js +56 -8
  158. package/dist/schema/string.js.map +1 -1
  159. package/dist/schema/subscription.d.ts +72 -2
  160. package/dist/schema/subscription.d.ts.map +1 -1
  161. package/dist/schema/subscription.js +59 -0
  162. package/dist/schema/subscription.js.map +1 -1
  163. package/dist/schema/token.d.ts +48 -0
  164. package/dist/schema/token.d.ts.map +1 -1
  165. package/dist/schema/token.js +49 -1
  166. package/dist/schema/token.js.map +1 -1
  167. package/dist/schema/typed-object.d.ts +73 -23
  168. package/dist/schema/typed-object.d.ts.map +1 -1
  169. package/dist/schema/typed-object.js +20 -1
  170. package/dist/schema/typed-object.js.map +1 -1
  171. package/dist/schema/typed-ref.d.ts +54 -0
  172. package/dist/schema/typed-ref.d.ts.map +1 -1
  173. package/dist/schema/typed-ref.js +16 -0
  174. package/dist/schema/typed-ref.js.map +1 -1
  175. package/dist/schema/typed-union.d.ts +51 -1
  176. package/dist/schema/typed-union.d.ts.map +1 -1
  177. package/dist/schema/typed-union.js +52 -2
  178. package/dist/schema/typed-union.js.map +1 -1
  179. package/dist/schema/union.d.ts +46 -0
  180. package/dist/schema/union.d.ts.map +1 -1
  181. package/dist/schema/union.js +41 -0
  182. package/dist/schema/union.js.map +1 -1
  183. package/dist/schema/unknown.d.ts +34 -0
  184. package/dist/schema/unknown.d.ts.map +1 -1
  185. package/dist/schema/unknown.js +34 -0
  186. package/dist/schema/unknown.js.map +1 -1
  187. package/dist/schema/with-default.d.ts +45 -0
  188. package/dist/schema/with-default.d.ts.map +1 -1
  189. package/dist/schema/with-default.js +45 -0
  190. package/dist/schema/with-default.js.map +1 -1
  191. package/dist/schema.d.ts +2 -1
  192. package/dist/schema.d.ts.map +1 -1
  193. package/dist/schema.js +2 -1
  194. package/dist/schema.js.map +1 -1
  195. package/dist/util/if-any.d.ts +2 -0
  196. package/dist/util/if-any.d.ts.map +1 -0
  197. package/dist/util/if-any.js +3 -0
  198. package/dist/util/if-any.js.map +1 -0
  199. package/package.json +3 -3
  200. package/src/core/$type.ts +150 -18
  201. package/src/core/record-key.ts +44 -0
  202. package/src/core/result.ts +86 -4
  203. package/src/core/schema.ts +244 -9
  204. package/src/core/string-format.ts +259 -13
  205. package/src/core/types.ts +91 -3
  206. package/src/core/validation-error.ts +60 -0
  207. package/src/core/validation-issue.ts +68 -2
  208. package/src/core/validator.ts +373 -12
  209. package/src/helpers.test.ts +110 -29
  210. package/src/helpers.ts +54 -25
  211. package/src/schema/array.test.ts +94 -79
  212. package/src/schema/array.ts +48 -1
  213. package/src/schema/blob.ts +50 -1
  214. package/src/schema/boolean.ts +31 -1
  215. package/src/schema/bytes.ts +41 -1
  216. package/src/schema/cid.ts +41 -1
  217. package/src/schema/custom.ts +68 -1
  218. package/src/schema/dict.ts +47 -1
  219. package/src/schema/discriminated-union.ts +61 -1
  220. package/src/schema/enum.ts +50 -0
  221. package/src/schema/integer.ts +45 -1
  222. package/src/schema/intersection.ts +56 -0
  223. package/src/schema/{unknown-object.test.ts → lex-map.test.ts} +9 -9
  224. package/src/schema/lex-map.ts +63 -0
  225. package/src/schema/lex-value.test.ts +81 -0
  226. package/src/schema/lex-value.ts +86 -0
  227. package/src/schema/literal.ts +46 -0
  228. package/src/schema/never.ts +45 -1
  229. package/src/schema/null.ts +32 -1
  230. package/src/schema/nullable.ts +43 -0
  231. package/src/schema/object.ts +59 -1
  232. package/src/schema/optional.ts +44 -0
  233. package/src/schema/params.test.ts +133 -38
  234. package/src/schema/params.ts +237 -37
  235. package/src/schema/payload.test.ts +3 -3
  236. package/src/schema/payload.ts +145 -42
  237. package/src/schema/permission-set.ts +58 -0
  238. package/src/schema/permission.ts +42 -0
  239. package/src/schema/procedure.ts +64 -0
  240. package/src/schema/query.ts +55 -0
  241. package/src/schema/record.ts +82 -16
  242. package/src/schema/ref.ts +52 -0
  243. package/src/schema/refine.ts +58 -9
  244. package/src/schema/regexp.ts +47 -1
  245. package/src/schema/string.test.ts +99 -2
  246. package/src/schema/string.ts +108 -15
  247. package/src/schema/subscription.ts +72 -2
  248. package/src/schema/token.ts +50 -1
  249. package/src/schema/typed-object.ts +81 -16
  250. package/src/schema/typed-ref.ts +55 -0
  251. package/src/schema/typed-union.ts +58 -3
  252. package/src/schema/union.ts +47 -0
  253. package/src/schema/unknown.ts +35 -0
  254. package/src/schema/with-default.ts +46 -0
  255. package/src/schema.ts +2 -1
  256. package/src/util/if-any.ts +3 -0
  257. package/dist/schema/unknown-object.d.ts +0 -8
  258. package/dist/schema/unknown-object.d.ts.map +0 -1
  259. package/dist/schema/unknown-object.js +0 -19
  260. package/dist/schema/unknown-object.js.map +0 -1
  261. package/src/schema/unknown-object.ts +0 -19
@@ -12,15 +12,79 @@ import {
12
12
  MeasurableType,
13
13
  } from './validation-issue.js'
14
14
 
15
+ /**
16
+ * Represents a successful validation result.
17
+ *
18
+ * @typeParam Value - The type of the validated value
19
+ */
15
20
  export type ValidationSuccess<Value = unknown> = ResultSuccess<Value>
21
+
22
+ /**
23
+ * Represents a failed validation result containing a {@link ValidationError}.
24
+ */
16
25
  export type ValidationFailure = ResultFailure<ValidationError>
26
+
27
+ /**
28
+ * Discriminated union representing the outcome of a validation operation.
29
+ *
30
+ * Check the `success` property to determine if validation passed or failed:
31
+ * - If `success` is `true`, the `value` property contains the validated data
32
+ * - If `success` is `false`, the `reason` property contains the {@link ValidationError}
33
+ *
34
+ * @typeParam Value - The type of the validated value on success
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * const result: ValidationResult<string> = schema.safeParse(data)
39
+ * if (result.success) {
40
+ * // result.value is string
41
+ * } else {
42
+ * // result.reason is ValidationError
43
+ * }
44
+ * ```
45
+ */
17
46
  export type ValidationResult<Value = unknown> =
18
47
  | ValidationSuccess<Value>
19
48
  | ValidationFailure
20
49
 
50
+ /**
51
+ * Extracts the input type that a validator accepts.
52
+ *
53
+ * Use this utility type to infer what type a schema will accept during validation.
54
+ *
55
+ * @typeParam V - A validator type
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const userSchema = new ObjectSchema({ name: stringSchema, age: numberSchema })
60
+ * type UserInput = InferInput<typeof userSchema>
61
+ * // { name: string; age: number }
62
+ * ```
63
+ */
21
64
  export type InferInput<V extends Validator> = V['__lex']['input']
65
+
66
+ /**
67
+ * Extracts the output type that a validator produces after parsing.
68
+ *
69
+ * The output type may differ from the input type when the schema applies
70
+ * transformations such as default values or type coercion during parsing.
71
+ *
72
+ * @typeParam V - A validator type
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const schema = new StringSchema().default('hello')
77
+ * type Input = InferInput<typeof schema> // string | undefined
78
+ * type Output = InferOutput<typeof schema> // string
79
+ * ```
80
+ */
22
81
  export type InferOutput<V extends Validator> = V['__lex']['output']
23
82
 
83
+ /**
84
+ * Alias for {@link InferInput} for convenient type inference.
85
+ *
86
+ * @typeParam V - A validator type
87
+ */
24
88
  export type { InferInput as Infer }
25
89
 
26
90
  export interface Validator<TInput = unknown, TOutput = TInput> {
@@ -28,12 +92,11 @@ export interface Validator<TInput = unknown, TOutput = TInput> {
28
92
  * This property is used for type inference purposes and does not actually
29
93
  * exist at runtime.
30
94
  *
95
+ * @internal
31
96
  * @deprecated **INTERNAL API, DO NOT USE**.
32
97
  */
33
98
  readonly ['__lex']: {
34
- /** @internal The inferred validation type */
35
99
  input: TInput
36
- /** @internal The inferred parse type */
37
100
  output: TOutput
38
101
  }
39
102
 
@@ -66,22 +129,87 @@ export interface Validator<TInput = unknown, TOutput = TInput> {
66
129
  validateInContext(input: unknown, ctx: ValidationContext): ValidationResult
67
130
  }
68
131
 
132
+ /**
133
+ * Configuration options for validation and parsing operations.
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * // Validate mode (strict, no transformations)
138
+ * ValidationContext.validate(data, schema, { mode: 'validate' })
139
+ *
140
+ * // Parse mode (allows transformations like defaults)
141
+ * ValidationContext.validate(data, schema, { mode: 'parse' })
142
+ *
143
+ * // With initial path for nested validation
144
+ * ValidationContext.validate(data, schema, { path: ['user', 'profile'] })
145
+ * ```
146
+ */
69
147
  export type ValidationOptions = {
70
148
  /**
71
- * When set to `"validate"` (default), the result of validation must be
72
- * strictly equal to the input value (i.e. no transformation, such as applying
73
- * default values, is allowed).
149
+ * The validation mode determining how transformations are handled.
150
+ *
151
+ * - `"validate"` (default): Strict validation where the result must be
152
+ * strictly equal to the input value. No transformations such as applying
153
+ * default values are allowed.
154
+ * - `"parse"`: Allows the schema to transform the input value, such as
155
+ * applying default values or performing type coercion.
74
156
  */
75
157
  mode?: 'validate' | 'parse'
76
158
 
77
159
  /**
78
- * The path to the value being validated. This is used to provide more
79
- * context in validation issues.
160
+ * The initial path to the value being validated.
161
+ *
162
+ * This is used to provide context in validation issues when validating
163
+ * nested structures. The path is prepended to all issue paths.
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * // Issues will be reported at paths like "user.name" instead of just "name"
168
+ * ValidationContext.validate(data, schema, { path: ['user'] })
169
+ * ```
80
170
  */
81
171
  path?: readonly PropertyKey[]
82
172
  }
83
173
 
174
+ /**
175
+ * Manages the state and context for validation operations.
176
+ *
177
+ * The `ValidationContext` class is responsible for:
178
+ * - Tracking the current path in nested structures for error reporting
179
+ * - Collecting validation issues during traversal
180
+ * - Enforcing validation mode (validate vs parse)
181
+ * - Providing factory methods for creating validation results
182
+ *
183
+ * Use the static {@link ValidationContext.validate} method as the primary entry point
184
+ * for validation. This ensures proper mode enforcement and issue aggregation.
185
+ *
186
+ * @example
187
+ * ```typescript
188
+ * // Primary usage via static method
189
+ * const result = ValidationContext.validate(data, schema, { mode: 'parse' })
190
+ *
191
+ * // Within a custom validator implementation
192
+ * class MyValidator implements Validator {
193
+ * validateInContext(input: unknown, ctx: ValidationContext): ValidationResult {
194
+ * if (typeof input !== 'string') {
195
+ * return ctx.issueUnexpectedType(input, 'string')
196
+ * }
197
+ * return ctx.success(input)
198
+ * }
199
+ * }
200
+ * ```
201
+ */
84
202
  export class ValidationContext {
203
+ /**
204
+ * Validates input against a validator in parse mode.
205
+ *
206
+ * In parse mode, the schema may transform the input (e.g., apply defaults).
207
+ *
208
+ * @param input - The value to validate
209
+ * @param validator - The validator to use
210
+ * @param options - Validation options with mode set to 'parse'
211
+ * @returns A validation result with the parsed output type
212
+ */
85
213
  static validate<V extends Validator>(
86
214
  input: unknown,
87
215
  validator: V,
@@ -89,6 +217,19 @@ export class ValidationContext {
89
217
  mode: 'parse'
90
218
  },
91
219
  ): ValidationResult<InferOutput<V>>
220
+ /**
221
+ * Validates input against a validator in validate mode (default).
222
+ *
223
+ * In validate mode, the result must be strictly equal to the input.
224
+ * No transformations are allowed.
225
+ *
226
+ * @typeParam V - The validator type
227
+ * @typeParam I - The input type
228
+ * @param input - The value to validate
229
+ * @param validator - The validator to use
230
+ * @param options - Optional validation options (defaults to validate mode)
231
+ * @returns A validation result preserving the input type intersected with the schema type
232
+ */
92
233
  static validate<V extends Validator, I = unknown>(
93
234
  input: I,
94
235
  validator: V,
@@ -96,6 +237,14 @@ export class ValidationContext {
96
237
  mode?: 'validate'
97
238
  },
98
239
  ): ValidationResult<I & InferInput<V>>
240
+ /**
241
+ * Validates input against a validator with configurable options.
242
+ *
243
+ * @param input - The value to validate
244
+ * @param validator - The validator to use
245
+ * @param options - Optional validation options
246
+ * @returns A validation result with either the input or output type
247
+ */
99
248
  static validate<V extends Validator>(
100
249
  input: unknown,
101
250
  validator: V,
@@ -113,27 +262,58 @@ export class ValidationContext {
113
262
  return context.validate(input, validator)
114
263
  }
115
264
 
265
+ /**
266
+ * The current path being validated, used for error reporting.
267
+ */
116
268
  protected readonly currentPath: PropertyKey[]
269
+
270
+ /**
271
+ * Accumulated validation issues collected during traversal.
272
+ */
117
273
  protected readonly issues: Issue[] = []
118
274
 
275
+ /**
276
+ * Creates a new validation context with the specified options.
277
+ *
278
+ * @param options - The validation options (path and mode are required)
279
+ */
119
280
  constructor(readonly options: Required<ValidationOptions>) {
120
281
  // Create a copy because we will be mutating the array during validation.
121
282
  this.currentPath = Array.from(options.path)
122
283
  }
123
284
 
285
+ /**
286
+ * Returns a copy of the current validation path.
287
+ *
288
+ * The path represents the location in the data structure being validated,
289
+ * used for constructing meaningful error messages.
290
+ */
124
291
  get path() {
125
292
  return Array.from(this.currentPath)
126
293
  }
127
294
 
295
+ /**
296
+ * Creates a new path by appending segments to the current path.
297
+ *
298
+ * @param path - Optional path segment(s) to append
299
+ * @returns A new path array with the segment(s) appended
300
+ */
128
301
  concatPath(path?: PropertyKey | readonly PropertyKey[]) {
129
302
  if (path == null) return this.path
130
303
  return this.currentPath.concat(path)
131
304
  }
132
305
 
133
306
  /**
134
- * This is basically the entry point for validation within a context. Use this
135
- * method instead of using {@link Validator.validateInContext} directly,
136
- * because this method ensures the proper use of {@link ValidationOptions}.
307
+ * Validates input against a validator within this context.
308
+ *
309
+ * This is the primary entry point for validation within a context. Always use
310
+ * this method instead of calling {@link Validator.validateInContext} directly,
311
+ * as this method enforces validation mode rules and handles transformation detection.
312
+ *
313
+ * @typeParam V - The validator type
314
+ * @param input - The value to validate
315
+ * @param validator - The validator to use
316
+ * @returns A validation result with the validated value or error
137
317
  */
138
318
  validate<V extends Validator>(
139
319
  input: unknown,
@@ -170,11 +350,42 @@ export class ValidationContext {
170
350
  return result as ValidationResult<InferInput<V>>
171
351
  }
172
352
 
353
+ /**
354
+ * Validates a child property of an object within this context.
355
+ *
356
+ * This method automatically manages the path stack, pushing the property key
357
+ * before validation and popping it afterward. Use this for validating object
358
+ * properties to ensure proper path tracking in error messages.
359
+ *
360
+ * @typeParam I - The input object type
361
+ * @typeParam K - The property key type
362
+ * @typeParam V - The validator type
363
+ * @param input - The parent object containing the property
364
+ * @param key - The property key to validate
365
+ * @param validator - The validator to use for the property value
366
+ * @returns A validation result for the property value
367
+ *
368
+ * @example
369
+ * ```typescript
370
+ * // In a custom object validator
371
+ * const result = ctx.validateChild(input, 'name', stringSchema)
372
+ * // If validation fails, error path will include 'name'
373
+ * ```
374
+ */
173
375
  validateChild<
174
376
  I extends object,
175
377
  K extends PropertyKey & keyof I,
176
378
  V extends Validator,
177
379
  >(input: I, key: K, validator: V): ValidationResult<InferInput<V>> {
380
+ // @NOTE we could add support for recursive schemas by keeping track of
381
+ // "parent" objects in the context and checking for circular references
382
+ // here. This would allow us to validate recursive structures without
383
+ // hitting maximum call stack errors, and would also allow us to provide
384
+ // better error messages for circular reference issues. However, this is not
385
+ // a priority at the moment as recursive structures are not supported in
386
+ // the context of AT Protocol lexicons, and we can always add this in the
387
+ // future if needed.
388
+
178
389
  // Instead of creating a new context, we just push/pop the path segment.
179
390
  this.currentPath.push(key)
180
391
  try {
@@ -184,38 +395,117 @@ export class ValidationContext {
184
395
  }
185
396
  }
186
397
 
398
+ /**
399
+ * Adds a validation issue to the context without immediately failing.
400
+ *
401
+ * Use this method to collect multiple issues during validation before
402
+ * determining the final result. Issues added this way will be included
403
+ * in the final error if validation fails.
404
+ *
405
+ * @param issue - The validation issue to add
406
+ */
187
407
  addIssue(issue: Issue): void {
188
408
  this.issues.push(issue)
189
409
  }
190
410
 
411
+ /**
412
+ * Creates a successful validation result with the given value.
413
+ *
414
+ * @typeParam V - The value type
415
+ * @param value - The validated value
416
+ * @returns A successful validation result
417
+ */
191
418
  success<V>(value: V): ValidationResult<V> {
192
419
  return success(value)
193
420
  }
194
421
 
422
+ /**
423
+ * Creates a failed validation result with the given error.
424
+ *
425
+ * @param reason - The validation error
426
+ * @returns A failed validation result
427
+ */
195
428
  failure(reason: ValidationError): ValidationFailure {
196
429
  return failure(reason)
197
430
  }
198
431
 
432
+ /**
433
+ * Creates a failed validation result from a single issue.
434
+ *
435
+ * Any previously accumulated issues in the context are included in the error.
436
+ *
437
+ * @param issue - The validation issue that caused the failure
438
+ * @returns A failed validation result
439
+ */
199
440
  issue(issue: Issue) {
200
441
  return this.failure(new ValidationError([...this.issues, issue]))
201
442
  }
202
443
 
444
+ /**
445
+ * Creates a failure for an invalid value that doesn't match expected values.
446
+ *
447
+ * @param input - The actual value that was received
448
+ * @param values - The expected valid values
449
+ * @returns A failed validation result with an invalid value issue
450
+ */
203
451
  issueInvalidValue(input: unknown, values: readonly unknown[]) {
204
452
  return this.issue(new IssueInvalidValue(this.path, input, values))
205
453
  }
206
454
 
207
- issueInvalidType(input: unknown, expected: string) {
208
- return this.issue(new IssueInvalidType(this.path, input, [expected]))
455
+ /**
456
+ * Creates a failure for an invalid type.
457
+ *
458
+ * @param input - The actual value that was received
459
+ * @param expected - An array of expected type names
460
+ * @returns A failed validation result with an invalid type issue
461
+ */
462
+ issueInvalidType(input: unknown, expected: readonly string[]) {
463
+ return this.issue(new IssueInvalidType(this.path, input, expected))
209
464
  }
210
465
 
466
+ /**
467
+ * Creates a failure for an invalid type.
468
+ *
469
+ * @param input - The actual value that was received
470
+ * @param expected - The expected type name
471
+ * @returns A failed validation result with an invalid type issue
472
+ */
473
+ issueUnexpectedType(input: unknown, expected: string) {
474
+ return this.issueInvalidType(input, [expected])
475
+ }
476
+
477
+ /**
478
+ * Creates a failure for a missing required key in an object.
479
+ *
480
+ * @param input - The object missing the required key
481
+ * @param key - The name of the required key
482
+ * @returns A failed validation result with a required key issue
483
+ */
211
484
  issueRequiredKey(input: object, key: PropertyKey) {
212
485
  return this.issue(new IssueRequiredKey(this.path, input, key))
213
486
  }
214
487
 
488
+ /**
489
+ * Creates a failure for an invalid string format.
490
+ *
491
+ * @param input - The actual value that was received
492
+ * @param format - The expected format name (e.g., 'did', 'handle', 'uri')
493
+ * @param msg - Optional additional message describing the format error
494
+ * @returns A failed validation result with an invalid format issue
495
+ */
215
496
  issueInvalidFormat(input: unknown, format: string, msg?: string) {
216
497
  return this.issue(new IssueInvalidFormat(this.path, input, format, msg))
217
498
  }
218
499
 
500
+ /**
501
+ * Creates a failure for a value that exceeds a maximum constraint.
502
+ *
503
+ * @param input - The actual value that was received
504
+ * @param type - The type of measurement (e.g., 'string', 'array', 'bytes')
505
+ * @param max - The maximum allowed value
506
+ * @param actual - The actual measured value
507
+ * @returns A failed validation result with a too big issue
508
+ */
219
509
  issueTooBig(
220
510
  input: unknown,
221
511
  type: MeasurableType,
@@ -225,6 +515,15 @@ export class ValidationContext {
225
515
  return this.issue(new IssueTooBig(this.path, input, max, type, actual))
226
516
  }
227
517
 
518
+ /**
519
+ * Creates a failure for a value that is below a minimum constraint.
520
+ *
521
+ * @param input - The actual value that was received
522
+ * @param type - The type of measurement (e.g., 'string', 'array', 'bytes')
523
+ * @param min - The minimum required value
524
+ * @param actual - The actual measured value
525
+ * @returns A failed validation result with a too small issue
526
+ */
228
527
  issueTooSmall(
229
528
  input: unknown,
230
529
  type: MeasurableType,
@@ -234,6 +533,18 @@ export class ValidationContext {
234
533
  return this.issue(new IssueTooSmall(this.path, input, min, type, actual))
235
534
  }
236
535
 
536
+ /**
537
+ * Creates a failure for an invalid property value within an object.
538
+ *
539
+ * This is a convenience method that automatically extracts the property value
540
+ * and constructs the appropriate path.
541
+ *
542
+ * @typeParam I - The input object type
543
+ * @param input - The object containing the invalid property
544
+ * @param property - The property key with the invalid value
545
+ * @param values - The expected valid values
546
+ * @returns A failed validation result with an invalid value issue at the property path
547
+ */
237
548
  issueInvalidPropertyValue<I>(
238
549
  input: I,
239
550
  property: keyof I & PropertyKey,
@@ -244,6 +555,18 @@ export class ValidationContext {
244
555
  return this.issue(new IssueInvalidValue(path, value, values))
245
556
  }
246
557
 
558
+ /**
559
+ * Creates a failure for an invalid property type within an object.
560
+ *
561
+ * This is a convenience method that automatically extracts the property value
562
+ * and constructs the appropriate path.
563
+ *
564
+ * @typeParam I - The input object type
565
+ * @param input - The object containing the invalid property
566
+ * @param property - The property key with the invalid type
567
+ * @param expected - The expected type name
568
+ * @returns A failed validation result with an invalid type issue at the property path
569
+ */
247
570
  issueInvalidPropertyType<I>(
248
571
  input: I,
249
572
  property: keyof I & PropertyKey,
@@ -255,12 +578,50 @@ export class ValidationContext {
255
578
  }
256
579
  }
257
580
 
581
+ /**
582
+ * Recursively unwraps a wrapped validator to its innermost validator type.
583
+ *
584
+ * Some validators wrap other validators (e.g., optional, nullable). This type
585
+ * utility recursively unwraps such wrappers to reveal the core validator.
586
+ *
587
+ * @typeParam T - A validator type, possibly wrapped
588
+ *
589
+ * @example
590
+ * ```typescript
591
+ * type Inner = UnwrapValidator<OptionalValidator<NullableValidator<StringSchema>>>
592
+ * // Result: StringSchema
593
+ * ```
594
+ */
258
595
  export type UnwrapValidator<T extends Validator> = T extends {
259
596
  unwrap(): infer U extends Validator
260
597
  }
261
598
  ? UnwrapValidator<U>
262
599
  : T
263
600
 
601
+ /**
602
+ * Interface for validators that wrap another validator.
603
+ *
604
+ * Implement this interface when creating validators that wrap or modify
605
+ * the behavior of another validator (e.g., optional, nullable, transform).
606
+ *
607
+ * @typeParam Validator - The type of the wrapped validator
608
+ *
609
+ * @example
610
+ * ```typescript
611
+ * class OptionalSchema<V extends Validator> implements WrappedValidator<V> {
612
+ * constructor(private inner: V) {}
613
+ *
614
+ * unwrap(): V {
615
+ * return this.inner
616
+ * }
617
+ * }
618
+ * ```
619
+ */
264
620
  export interface WrappedValidator<out Validator> {
621
+ /**
622
+ * Returns the inner wrapped validator.
623
+ *
624
+ * @returns The wrapped validator
625
+ */
265
626
  unwrap(): Validator
266
627
  }