@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
@@ -7,17 +7,70 @@ import {
7
7
  Validator,
8
8
  } from './validator.js'
9
9
 
10
- type ParseOptions = Omit<ValidationOptions, 'mode'>
11
- type ValidateOptions = Omit<ValidationOptions, 'mode'>
10
+ /**
11
+ * Options for parsing operations.
12
+ * Excludes the `mode` option as it is implicitly set to `"parse"`.
13
+ */
14
+ export type ParseOptions = Omit<ValidationOptions, 'mode'>
12
15
 
16
+ /**
17
+ * Options for validation operations.
18
+ * Excludes the `mode` option as it is implicitly set to `"validate"`.
19
+ */
20
+ export type ValidateOptions = Omit<ValidationOptions, 'mode'>
21
+
22
+ /**
23
+ * Internal type structure for schema type inference.
24
+ *
25
+ * This interface defines the phantom types used for compile-time type inference
26
+ * without affecting runtime behavior. The `input` and `output` properties
27
+ * represent the expected input type during validation and the resulting output
28
+ * type after parsing, respectively.
29
+ *
30
+ * @typeParam TInput - The type accepted as input during validation
31
+ * @typeParam TOutput - The type returned after parsing (may differ from input due to coercion)
32
+ */
13
33
  export interface SchemaInternals<out TInput = unknown, out TOutput = TInput> {
14
- /** @internal The inferred validation type */
15
34
  input: TInput
16
-
17
- /** @internal The inferred parse type */
18
35
  output: TOutput
19
36
  }
20
37
 
38
+ /**
39
+ * Abstract base class for all schema validators in the lexicon system.
40
+ *
41
+ * This class provides the standard validation interface that all schema types
42
+ * implement. It offers multiple methods for validating and parsing data:
43
+ *
44
+ * - **Assertion methods**: `assert()`, `check()` - throw on invalid input
45
+ * - **Type guard methods**: `matches()`, `ifMatches()` - return boolean or optional value
46
+ * - **Parse methods**: `parse()`, `safeParse()` - allow value transformation/coercion
47
+ * - **Validate methods**: `validate()`, `safeValidate()` - strict validation without coercion
48
+ *
49
+ * All methods are also available with a `$` prefix (e.g., `$parse()`, `$validate()`)
50
+ * for consistent access in generated lexicon namespaces.
51
+ *
52
+ * @typeParam TInput - The type accepted as valid input during validation
53
+ * @typeParam TOutput - The type returned after parsing (may include transformations)
54
+ * @typeParam TInternals - Internal type structure for type inference
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * class MySchema extends Schema<string> {
59
+ * validateInContext(input: unknown, ctx: ValidationContext): ValidationResult {
60
+ * if (typeof input !== 'string') {
61
+ * return ctx.issueUnexpectedType(input, 'string')
62
+ * }
63
+ * return ctx.success(input)
64
+ * }
65
+ * }
66
+ *
67
+ * const schema = new MySchema()
68
+ * schema.assert('hello') // OK
69
+ * schema.assert(123) // Throws ValidationError
70
+ * schema.matches('hello') // true
71
+ * schema.matches(123) // false
72
+ * ```
73
+ */
21
74
  export abstract class Schema<
22
75
  out TInput = unknown,
23
76
  out TOutput = TInput,
@@ -27,8 +80,33 @@ export abstract class Schema<
27
80
  >,
28
81
  > implements Validator<TInternals['input'], TInternals['output']>
29
82
  {
83
+ /**
84
+ * Internal phantom property for type inference.
85
+ * This property does not exist at runtime.
86
+ *
87
+ * @internal
88
+ */
30
89
  declare readonly ['__lex']: TInternals
31
90
 
91
+ // Needed to discriminate multiple schema types when used in unions. Without
92
+ // this, Typescript could allow an EnumSchema<"foo" | "bar"> to be used where
93
+ // a StringSchema is expected, since they would both be structurally
94
+ // compatible.
95
+ abstract readonly type: string
96
+
97
+ /**
98
+ * Performs validation of the input value within a validation context.
99
+ *
100
+ * This method must be implemented by subclasses to define the actual
101
+ * validation logic. It should not be called directly; use
102
+ * {@link ValidationContext.validate} instead to ensure proper mode enforcement.
103
+ *
104
+ * @param input - The value to validate
105
+ * @param ctx - The validation context providing path tracking and issue reporting
106
+ * @returns A validation result indicating success with the validated value or failure with issues
107
+ *
108
+ * @internal
109
+ */
32
110
  abstract validateInContext(
33
111
  input: unknown,
34
112
  ctx: ValidationContext,
@@ -66,21 +144,91 @@ export abstract class Schema<
66
144
  throw result.reason
67
145
  }
68
146
 
147
+ /**
148
+ * Type guard that checks if the input matches this schema.
149
+ *
150
+ * @param input - The value to check
151
+ * @returns `true` if the input is valid according to this schema
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * if (schema.matches(data)) {
156
+ * // data is narrowed to the schema's input type
157
+ * console.log(data)
158
+ * }
159
+ * ```
160
+ */
69
161
  matches<I>(input: I): input is I & InferInput<this> {
70
162
  const result = ValidationContext.validate(input, this)
71
163
  return result.success
72
164
  }
73
165
 
166
+ /**
167
+ * Returns the input if it matches this schema, otherwise returns `undefined`.
168
+ *
169
+ * This is useful for optional filtering operations where you want to
170
+ * conditionally extract values that match a schema.
171
+ *
172
+ * @param input - The value to check
173
+ * @returns The input value with narrowed type if valid, otherwise `undefined`
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * const validData = schema.ifMatches(data)
178
+ * if (validData !== undefined) {
179
+ * // validData is the schema's input type
180
+ * console.log(validData)
181
+ * }
182
+ * ```
183
+ */
74
184
  ifMatches<I>(input: I): (I & InferInput<this>) | undefined {
75
185
  return this.matches(input) ? input : undefined
76
186
  }
77
187
 
188
+ /**
189
+ * Parses the input, allowing value transformations and coercion.
190
+ *
191
+ * Unlike {@link validate}, this method allows the schema to transform
192
+ * the input value (e.g., applying default values, type coercion).
193
+ * Throws a {@link ValidationError} if the input is invalid.
194
+ *
195
+ * @param input - The value to parse
196
+ * @param options - Optional parsing configuration
197
+ * @returns The parsed and potentially transformed value
198
+ * @throws {ValidationError} If the input fails validation
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * const result = schema.parse(rawData)
203
+ * // result has defaults applied and is fully typed
204
+ * ```
205
+ */
78
206
  parse(input: unknown, options?: ParseOptions): InferOutput<this> {
79
207
  const result = this.safeParse(input, options)
80
208
  if (result.success) return result.value
81
209
  throw result.reason
82
210
  }
83
211
 
212
+ /**
213
+ * Safely parses the input without throwing, returning a result object.
214
+ *
215
+ * This method allows value transformations like {@link parse}, but
216
+ * returns a discriminated union result instead of throwing on error.
217
+ *
218
+ * @param input - The value to parse
219
+ * @param options - Optional parsing configuration
220
+ * @returns A {@link ValidationResult} with either the parsed value or validation errors
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * const result = schema.safeParse(data)
225
+ * if (result.success) {
226
+ * console.log(result.value)
227
+ * } else {
228
+ * console.error(result.reason.issues)
229
+ * }
230
+ * ```
231
+ */
84
232
  safeParse(
85
233
  input: unknown,
86
234
  options?: ParseOptions,
@@ -91,12 +239,52 @@ export abstract class Schema<
91
239
  })
92
240
  }
93
241
 
242
+ /**
243
+ * Validates the input strictly without allowing transformations.
244
+ *
245
+ * Unlike {@link parse}, this method requires the input to exactly match
246
+ * the schema without any transformations (no defaults applied, no coercion).
247
+ * Throws a {@link ValidationError} if the input is invalid or would require transformation.
248
+ *
249
+ * @typeParam I - The input type (preserved in the return type)
250
+ * @param input - The value to validate
251
+ * @param options - Optional validation configuration
252
+ * @returns The validated input with narrowed type
253
+ * @throws {ValidationError} If the input fails validation or requires transformation
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * const validated = schema.validate(data)
258
+ * // validated is typed as the intersection of input type and schema type
259
+ * ```
260
+ */
94
261
  validate<I>(input: I, options?: ValidateOptions): I & InferInput<this> {
95
262
  const result = this.safeValidate(input, options)
96
263
  if (result.success) return result.value
97
264
  throw result.reason
98
265
  }
99
266
 
267
+ /**
268
+ * Safely validates the input without throwing, returning a result object.
269
+ *
270
+ * This method performs strict validation like {@link validate}, but
271
+ * returns a discriminated union result instead of throwing on error.
272
+ *
273
+ * @typeParam I - The input type (preserved in the result value type)
274
+ * @param input - The value to validate
275
+ * @param options - Optional validation configuration
276
+ * @returns A {@link ValidationResult} with either the validated value or validation errors
277
+ *
278
+ * @example
279
+ * ```typescript
280
+ * const result = schema.safeValidate(data)
281
+ * if (result.success) {
282
+ * console.log(result.value)
283
+ * } else {
284
+ * console.error(result.reason.issues)
285
+ * }
286
+ * ```
287
+ */
100
288
  safeValidate<I>(
101
289
  input: I,
102
290
  options?: ValidateOptions,
@@ -107,10 +295,12 @@ export abstract class Schema<
107
295
  })
108
296
  }
109
297
 
110
- // @NOTE The built lexicons namespaces will export utility functions that
111
- // allow accessing the schema's methods without the need to specify ".main."
112
- // as part of the namespace. This way, a utility for a particular record type
113
- // can be called like "app.bsky.feed.post.<utility>()" instead of
298
+ // @NOTE Dollar-prefixed aliases
299
+ //
300
+ // The built lexicons namespaces export utility functions that allow accessing
301
+ // the schema's methods without the need to specify ".main." as part of the
302
+ // namespace. This way, a utility for a particular record type can be called
303
+ // like "app.bsky.feed.post.<utility>()" instead of
114
304
  // "app.bsky.feed.post.main.<utility>()". Because those utilities could
115
305
  // conflict with other schemas (e.g. if there is a lexicon definition at
116
306
  // "#<utility>"), those exported utilities will be prefixed with "$". In order
@@ -121,30 +311,65 @@ export abstract class Schema<
121
311
  // - "app.bsky.feed.post.$parse(...)" // calls a utility function created by "lex build"
122
312
  // - "app.bsky.feed.defs.postView.$parse(...)" // uses the alias defined below on the schema instance
123
313
 
314
+ /**
315
+ * Alias for {@link assert} with `$` prefix for namespace compatibility.
316
+ *
317
+ * @see {@link assert}
318
+ */
124
319
  $assert(input: unknown): asserts input is InferInput<this> {
125
320
  return this.assert(input)
126
321
  }
127
322
 
323
+ /**
324
+ * Alias for {@link check} with `$` prefix for namespace compatibility.
325
+ *
326
+ * @see {@link check}
327
+ */
128
328
  $check(input: unknown): void {
129
329
  return this.check(input)
130
330
  }
131
331
 
332
+ /**
333
+ * Alias for {@link cast} with `$` prefix for namespace compatibility.
334
+ *
335
+ * @see {@link cast}
336
+ */
132
337
  $cast<I>(input: I): I & InferInput<this> {
133
338
  return this.cast(input)
134
339
  }
135
340
 
341
+ /**
342
+ * Alias for {@link matches} with `$` prefix for namespace compatibility.
343
+ *
344
+ * @see {@link matches}
345
+ */
136
346
  $matches(input: unknown): input is InferInput<this> {
137
347
  return this.matches(input)
138
348
  }
139
349
 
350
+ /**
351
+ * Alias for {@link ifMatches} with `$` prefix for namespace compatibility.
352
+ *
353
+ * @see {@link ifMatches}
354
+ */
140
355
  $ifMatches<I>(input: I): (I & InferInput<this>) | undefined {
141
356
  return this.ifMatches(input)
142
357
  }
143
358
 
359
+ /**
360
+ * Alias for {@link parse} with `$` prefix for namespace compatibility.
361
+ *
362
+ * @see {@link parse}
363
+ */
144
364
  $parse(input: unknown, options?: ValidateOptions): InferOutput<this> {
145
365
  return this.parse(input, options)
146
366
  }
147
367
 
368
+ /**
369
+ * Alias for {@link safeParse} with `$` prefix for namespace compatibility.
370
+ *
371
+ * @see {@link safeParse}
372
+ */
148
373
  $safeParse(
149
374
  input: unknown,
150
375
  options?: ValidateOptions,
@@ -152,10 +377,20 @@ export abstract class Schema<
152
377
  return this.safeParse(input, options)
153
378
  }
154
379
 
380
+ /**
381
+ * Alias for {@link validate} with `$` prefix for namespace compatibility.
382
+ *
383
+ * @see {@link validate}
384
+ */
155
385
  $validate<I>(input: I, options?: ValidateOptions): I & InferInput<this> {
156
386
  return this.validate(input, options)
157
387
  }
158
388
 
389
+ /**
390
+ * Alias for {@link safeValidate} with `$` prefix for namespace compatibility.
391
+ *
392
+ * @see {@link safeValidate}
393
+ */
159
394
  $safeValidate<I>(
160
395
  input: I,
161
396
  options?: ValidateOptions,
@@ -22,42 +22,193 @@ import {
22
22
  } from '@atproto/syntax'
23
23
  import { CheckFn } from '../util/assertion-util.js'
24
24
 
25
- // Expose all individual string format types and type guards
25
+ // -----------------------------------------------------------------------------
26
+ // Individual string format types and type guards
27
+ // -----------------------------------------------------------------------------
26
28
 
27
- export type { AtIdentifierString }
29
+ /**
30
+ * Type guard that checks if a value is a valid AT identifier (DID or handle).
31
+ *
32
+ * @param value - The value to check
33
+ * @returns `true` if the value is a valid AT identifier
34
+ */
28
35
  export const isAtIdentifierString: CheckFn<AtIdentifierString> = isValidAtId
36
+ export type {
37
+ /**
38
+ * An AT identifier string - either a DID or a handle.
39
+ *
40
+ * @example `"did:plc:1234..."` or `"alice.bsky.social"`
41
+ */
42
+ AtIdentifierString,
43
+ }
29
44
 
30
- export type { AtUriString }
45
+ /**
46
+ * Type guard that checks if a value is a valid AT URI.
47
+ *
48
+ * @param value - The value to check
49
+ * @returns `true` if the value is a valid AT URI
50
+ */
31
51
  export const isAtUriString: CheckFn<AtUriString> = isValidAtUri
52
+ export type {
53
+ /**
54
+ * An AT URI string pointing to a resource in the AT Protocol network.
55
+ *
56
+ * @example `"at://did:plc:1234.../app.bsky.feed.post/3k2..."`
57
+ */
58
+ AtUriString,
59
+ }
32
60
 
33
- export type CidString = string
61
+ /**
62
+ * Type guard that checks if a value is a valid CID string.
63
+ *
64
+ * @param value - The value to check
65
+ * @returns `true` if the value is a valid CID string
66
+ */
34
67
  export const isCidString = ((v) => validateCidString(v)) as CheckFn<CidString>
68
+ /**
69
+ * A Content Identifier (CID) string.
70
+ *
71
+ * CIDs are self-describing content addresses used to identify data by its hash.
72
+ *
73
+ * @example `"bafyreig..."`
74
+ */
75
+ export type CidString = string
35
76
 
36
- export type { DatetimeString }
77
+ /**
78
+ * Type guard that checks if a value is a valid datetime string.
79
+ *
80
+ * @param value - The value to check
81
+ * @returns `true` if the value is a valid datetime string
82
+ */
37
83
  export const isDatetimeString: CheckFn<DatetimeString> = isValidDatetime
84
+ export type {
85
+ /**
86
+ * An ISO 8601 datetime string.
87
+ *
88
+ * @example `"2024-01-15T12:30:00.000Z"`
89
+ */
90
+ DatetimeString,
91
+ }
38
92
 
39
- export type { DidString }
93
+ /**
94
+ * Type guard that checks if a value is a valid DID string.
95
+ *
96
+ * @param value - The value to check
97
+ * @returns `true` if the value is a valid DID string
98
+ */
40
99
  export const isDidString: CheckFn<DidString> = isValidDid
100
+ export type {
101
+ /**
102
+ * A Decentralized Identifier (DID) string.
103
+ *
104
+ * DIDs are globally unique identifiers that don't require a central authority.
105
+ *
106
+ * @example `"did:plc:1234abcd..."` or `"did:web:example.com"`
107
+ */
108
+ DidString,
109
+ }
41
110
 
42
- export type { HandleString }
111
+ /**
112
+ * Type guard that checks if a value is a valid handle string.
113
+ *
114
+ * @param value - The value to check
115
+ * @returns `true` if the value is a valid handle string
116
+ */
43
117
  export const isHandleString: CheckFn<HandleString> = isValidHandle
118
+ export type {
119
+ /**
120
+ * A handle string - a human-readable identifier for users.
121
+ *
122
+ * @example `"alice.bsky.social"` or `"bob.example.com"`
123
+ */
124
+ HandleString,
125
+ }
44
126
 
45
- export type LanguageString = string
127
+ /**
128
+ * Type guard that checks if a value is a valid BCP-47 language tag.
129
+ *
130
+ * @param value - The value to check
131
+ * @returns `true` if the value is a valid language string
132
+ */
46
133
  export const isLanguageString = isValidLanguage as CheckFn<LanguageString>
134
+ /**
135
+ * A BCP-47 language tag string.
136
+ *
137
+ * @example `"en"`, `"en-US"`, `"zh-Hans"`
138
+ */
139
+ export type LanguageString = string
47
140
 
48
- export type { NsidString }
141
+ /**
142
+ * Type guard that checks if a value is a valid NSID string.
143
+ *
144
+ * @param value - The value to check
145
+ * @returns `true` if the value is a valid NSID string
146
+ */
49
147
  export const isNsidString: CheckFn<NsidString> = isValidNsid
148
+ export type {
149
+ /**
150
+ * A Namespaced Identifier (NSID) string identifying a lexicon.
151
+ *
152
+ * NSIDs use reverse-domain notation to identify schemas.
153
+ *
154
+ * @example `"app.bsky.feed.post"`, `"com.atproto.repo.createRecord"`
155
+ */
156
+ NsidString,
157
+ }
50
158
 
51
- export type { RecordKeyString }
159
+ /**
160
+ * Type guard that checks if a value is a valid record key string.
161
+ *
162
+ * @param value - The value to check
163
+ * @returns `true` if the value is a valid record key string
164
+ */
52
165
  export const isRecordKeyString: CheckFn<RecordKeyString> = isValidRecordKey
166
+ export type {
167
+ /**
168
+ * A record key string identifying a record within a collection.
169
+ *
170
+ * @example `"3k2..."` (TID format) or `"self"` (literal key)
171
+ */
172
+ RecordKeyString,
173
+ }
53
174
 
54
- export type { TidString }
175
+ /**
176
+ * Type guard that checks if a value is a valid TID string.
177
+ *
178
+ * @param value - The value to check
179
+ * @returns `true` if the value is a valid TID string
180
+ */
55
181
  export const isTidString: CheckFn<TidString> = isValidTid
182
+ export type {
183
+ /**
184
+ * A Timestamp Identifier (TID) string.
185
+ *
186
+ * TIDs are time-based identifiers used for record keys.
187
+ *
188
+ * @example `"3k2..."`
189
+ */
190
+ TidString,
191
+ }
56
192
 
57
- export type { UriString }
193
+ /**
194
+ * Type guard that checks if a value is a valid URI string.
195
+ *
196
+ * @param value - The value to check
197
+ * @returns `true` if the value is a valid URI string
198
+ */
58
199
  export const isUriString: CheckFn<UriString> = isValidUri
200
+ export type {
201
+ /**
202
+ * A standard URI string.
203
+ *
204
+ * @example `"https://example.com/path"`
205
+ */
206
+ UriString,
207
+ }
59
208
 
60
- // String format registry (maps format names to their types and type guards)
209
+ // -----------------------------------------------------------------------------
210
+ // String format registry
211
+ // -----------------------------------------------------------------------------
61
212
 
62
213
  type StringFormats = {
63
214
  'at-identifier': AtIdentifierString
@@ -73,6 +224,9 @@ type StringFormats = {
73
224
  uri: UriString
74
225
  }
75
226
 
227
+ /**
228
+ * Union type of all valid string format names.
229
+ */
76
230
  export type StringFormat = Extract<keyof StringFormats, string>
77
231
 
78
232
  const stringFormatVerifiers: {
@@ -93,10 +247,39 @@ const stringFormatVerifiers: {
93
247
  uri: isUriString,
94
248
  })
95
249
 
250
+ /**
251
+ * Infers the string type for a given format name.
252
+ *
253
+ * @typeParam F - The format name
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * type Did = InferStringFormat<'did'>
258
+ * // Result: DidString
259
+ * ```
260
+ */
96
261
  export type InferStringFormat<F extends StringFormat> = F extends StringFormat
97
262
  ? StringFormats[F]
98
263
  : never
99
264
 
265
+ /**
266
+ * Type guard that checks if a string matches a specific format.
267
+ *
268
+ * @typeParam I - The input string type
269
+ * @typeParam F - The format to check
270
+ * @param input - The string to validate
271
+ * @param format - The format name to validate against
272
+ * @returns `true` if the string matches the format
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * const value: string = 'did:plc:1234...'
277
+ * if (isStringFormat(value, 'did')) {
278
+ * // value is typed as DidString
279
+ * console.log('Valid DID:', value)
280
+ * }
281
+ * ```
282
+ */
100
283
  /*@__NO_SIDE_EFFECTS__*/
101
284
  export function isStringFormat<I extends string, F extends StringFormat>(
102
285
  input: I,
@@ -109,6 +292,21 @@ export function isStringFormat<I extends string, F extends StringFormat>(
109
292
  return formatVerifier(input)
110
293
  }
111
294
 
295
+ /**
296
+ * Asserts that a string matches a specific format, throwing if invalid.
297
+ *
298
+ * @typeParam I - The input string type
299
+ * @typeParam F - The format to check
300
+ * @param input - The string to validate
301
+ * @param format - The format name to validate against
302
+ * @throws {TypeError} If the string doesn't match the format
303
+ *
304
+ * @example
305
+ * ```typescript
306
+ * assertStringFormat(value, 'handle')
307
+ * // value is now typed as HandleString
308
+ * ```
309
+ */
112
310
  /*@__NO_SIDE_EFFECTS__*/
113
311
  export function assertStringFormat<I extends string, F extends StringFormat>(
114
312
  input: I,
@@ -119,6 +317,24 @@ export function assertStringFormat<I extends string, F extends StringFormat>(
119
317
  }
120
318
  }
121
319
 
320
+ /**
321
+ * Validates and returns a string as the specified format type, throwing if invalid.
322
+ *
323
+ * This is useful when you need to convert a string to a format type in an expression.
324
+ *
325
+ * @typeParam I - The input string type
326
+ * @typeParam F - The format to validate against
327
+ * @param input - The string to validate
328
+ * @param format - The format name to validate against
329
+ * @returns The input typed as the format type
330
+ * @throws {TypeError} If the string doesn't match the format
331
+ *
332
+ * @example
333
+ * ```typescript
334
+ * const did = asStringFormat(userInput, 'did')
335
+ * // did is typed as DidString
336
+ * ```
337
+ */
122
338
  /*@__NO_SIDE_EFFECTS__*/
123
339
  export function asStringFormat<I extends string, F extends StringFormat>(
124
340
  input: I,
@@ -128,6 +344,26 @@ export function asStringFormat<I extends string, F extends StringFormat>(
128
344
  return input
129
345
  }
130
346
 
347
+ /**
348
+ * Returns the string as the format type if valid, otherwise returns `undefined`.
349
+ *
350
+ * This is useful for optional validation where you want to handle invalid values
351
+ * without throwing.
352
+ *
353
+ * @typeParam I - The input string type
354
+ * @typeParam F - The format to validate against
355
+ * @param input - The string to validate
356
+ * @param format - The format name to validate against
357
+ * @returns The typed string if valid, otherwise `undefined`
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * const did = ifStringFormat(maybeInvalid, 'did')
362
+ * if (did) {
363
+ * // did is typed as DidString
364
+ * }
365
+ * ```
366
+ */
131
367
  /*@__NO_SIDE_EFFECTS__*/
132
368
  export function ifStringFormat<I extends string, F extends StringFormat>(
133
369
  input: I,
@@ -136,6 +372,16 @@ export function ifStringFormat<I extends string, F extends StringFormat>(
136
372
  return isStringFormat(input, format) ? input : undefined
137
373
  }
138
374
 
375
+ /**
376
+ * Array of all valid string format names.
377
+ *
378
+ * @example
379
+ * ```typescript
380
+ * for (const format of STRING_FORMATS) {
381
+ * console.log(format) // 'at-identifier', 'at-uri', 'cid', ...
382
+ * }
383
+ * ```
384
+ */
139
385
  export const STRING_FORMATS = /*#__PURE__*/ Object.freeze(
140
386
  /*#__PURE__*/ Object.keys(stringFormatVerifiers),
141
387
  ) as readonly StringFormat[]