@atproto/lex-schema 0.1.0 → 0.1.2

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 (54) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/core/result.d.ts +1 -125
  3. package/dist/core/result.d.ts.map +1 -1
  4. package/dist/core/result.js +1 -128
  5. package/dist/core/result.js.map +1 -1
  6. package/dist/core/string-format.d.ts +1 -7
  7. package/dist/core/string-format.d.ts.map +1 -1
  8. package/dist/core/string-format.js +2 -23
  9. package/dist/core/string-format.js.map +1 -1
  10. package/dist/core/validation-error.d.ts +0 -18
  11. package/dist/core/validation-error.d.ts.map +1 -1
  12. package/dist/core/validation-error.js +0 -30
  13. package/dist/core/validation-error.js.map +1 -1
  14. package/dist/core/validator.d.ts +8 -15
  15. package/dist/core/validator.d.ts.map +1 -1
  16. package/dist/core/validator.js +3 -14
  17. package/dist/core/validator.js.map +1 -1
  18. package/dist/schema/array.d.ts +1 -1
  19. package/dist/schema/blob.d.ts +1 -1
  20. package/dist/schema/boolean.d.ts +1 -1
  21. package/dist/schema/bytes.d.ts +1 -1
  22. package/dist/schema/cid.d.ts +1 -1
  23. package/dist/schema/custom.d.ts +1 -1
  24. package/dist/schema/dict.d.ts +1 -1
  25. package/dist/schema/enum.d.ts +1 -1
  26. package/dist/schema/integer.d.ts +1 -1
  27. package/dist/schema/intersection.d.ts +1 -1
  28. package/dist/schema/lex-map.d.ts +1 -1
  29. package/dist/schema/lex-value.d.ts +1 -1
  30. package/dist/schema/literal.d.ts +1 -1
  31. package/dist/schema/null.d.ts +1 -1
  32. package/dist/schema/nullable.d.ts +1 -1
  33. package/dist/schema/object.d.ts +1 -1
  34. package/dist/schema/optional.d.ts +1 -1
  35. package/dist/schema/params.d.ts +2 -2
  36. package/dist/schema/params.d.ts.map +1 -1
  37. package/dist/schema/regexp.d.ts +1 -1
  38. package/dist/schema/string.d.ts +1 -1
  39. package/dist/schema/token.d.ts +2 -1
  40. package/dist/schema/token.d.ts.map +1 -1
  41. package/dist/schema/token.js +6 -1
  42. package/dist/schema/token.js.map +1 -1
  43. package/dist/schema/typed-union.d.ts +1 -1
  44. package/dist/schema/union.d.ts.map +1 -1
  45. package/dist/schema/union.js +3 -3
  46. package/dist/schema/union.js.map +1 -1
  47. package/dist/schema/unknown.d.ts +1 -1
  48. package/package.json +3 -4
  49. package/src/core/result.ts +8 -155
  50. package/src/core/string-format.ts +2 -22
  51. package/src/core/validation-error.ts +1 -33
  52. package/src/core/validator.ts +10 -21
  53. package/src/schema/token.ts +9 -1
  54. package/src/schema/union.ts +4 -4
@@ -1,162 +1,15 @@
1
- export type ResultSuccess<V = any> = { success: true; value: V }
2
-
3
- /**
4
- * Represents a failed result containing an error reason.
5
- *
6
- * @typeParam E - The type of the error reason
7
- */
8
- export type ResultFailure<E = Error> = { success: false; reason: E }
9
-
10
- /**
11
- * A discriminated union type representing either a success or failure outcome.
12
- *
13
- * Check the `success` property to determine the outcome and access the
14
- * appropriate property (`value` for success, `reason` for failure).
15
- *
16
- * @typeParam V - The type of the success value
17
- * @typeParam E - The type of the error reason
18
- *
19
- * @example
20
- * ```typescript
21
- * function parseJson(text: string): Result<unknown, SyntaxError> {
22
- * try {
23
- * return success(JSON.parse(text))
24
- * } catch (e) {
25
- * return failure(e as SyntaxError)
26
- * }
27
- * }
28
- * ```
29
- */
30
- export type Result<V = any, E = Error> = ResultSuccess<V> | ResultFailure<E>
31
-
32
- /**
33
- * Creates a successful result wrapping the given value.
34
- *
35
- * @typeParam V - The type of the value
36
- * @param value - The success value to wrap
37
- * @returns {ResultSuccess} A success result containing the value
38
- *
39
- * @example
40
- * ```typescript
41
- * const result = success(42)
42
- * console.log(result.success) // true
43
- * console.log(result.value) // 42
44
- * ```
45
- */
46
- /*@__NO_SIDE_EFFECTS__*/
47
- export function success<V>(value: V): ResultSuccess<V> {
48
- return { success: true, value }
1
+ export type ResultSuccess<V = any> = {
2
+ success: true
3
+ value: V
4
+ reason?: undefined
49
5
  }
50
6
 
51
7
  /**
52
- * Creates a failed result wrapping the given error reason.
8
+ * Represents a failed result containing an error reason.
53
9
  *
54
10
  * @typeParam E - The type of the error reason
55
- * @param reason - The error reason to wrap
56
- * @returns {ResultFailure} A failure result containing the error
57
- *
58
- * @example
59
- * ```typescript
60
- * const result = failure(new Error('Something went wrong'))
61
- * console.log(result.success) // false
62
- * console.log(result.reason.message) // "Something went wrong"
63
- * ```
64
- */
65
- /*@__NO_SIDE_EFFECTS__*/
66
- export function failure<E>(reason: E): ResultFailure<E> {
67
- return { success: false, reason }
68
- }
69
-
70
- /**
71
- * Extracts the error reason from a failure result.
72
- *
73
- * @typeParam T - The type of the error reason
74
- * @param result - A failure result
75
- * @returns {T} The error reason
76
- *
77
- * @example
78
- * ```typescript
79
- * const result = failure(new Error('oops'))
80
- * const error = failureReason(result)
81
- * console.log(error.message) // "oops"
82
- * ```
83
- */
84
- /*@__NO_SIDE_EFFECTS__*/
85
- export function failureReason<T>(result: ResultFailure<T>): T {
86
- return result.reason
87
- }
88
-
89
- /**
90
- * Extracts the value from a success result.
91
- *
92
- * @typeParam T - The type of the success value
93
- * @param result - A success result
94
- * @returns {T} The success value
95
- *
96
- * @example
97
- * ```typescript
98
- * const result = success(42)
99
- * const value = successValue(result)
100
- * console.log(value) // 42
101
- * ```
102
- */
103
- /*@__NO_SIDE_EFFECTS__*/
104
- export function successValue<T>(result: ResultSuccess<T>): T {
105
- return result.value
106
- }
107
-
108
- /**
109
- * Catches any error and wraps it in a {@link ResultFailure<Error>}.
110
- *
111
- * @param err - The error to catch.
112
- * @returns {ResultFailure} A failure result containing the error.
113
- * @example
114
- *
115
- * ```ts
116
- * declare function someFunction(): Promise<string>
117
- *
118
- * const result = await someFunction().then(success, catchall)
119
- * if (result.success) {
120
- * console.log(result.value) // string
121
- * } else {
122
- * console.error(result.reason instanceof Error) // true
123
- * console.error(result.reason.message) // string
124
- * }
125
- * ```
126
- */
127
- /*@__NO_SIDE_EFFECTS__*/
128
- export function catchall(err: unknown): ResultFailure<Error> {
129
- if (err instanceof Error) return failure(err)
130
- return failure(new Error('Unknown error', { cause: err }))
131
- }
132
-
133
- /**
134
- * Creates a catcher function for the given constructor that wraps caught errors
135
- * in a {@link ResultFailure}.
136
- *
137
- * @example
138
- *
139
- * ```ts
140
- * class FooError extends Error {}
141
- * class BarError extends Error {}
142
- *
143
- * declare function someFunction(): Promise<string>
144
- *
145
- * const result = await someFunction()
146
- * .then(success)
147
- * .catch(createCatcher(FooError))
148
- * .catch(createCatcher(BarError))
149
- *
150
- * if (result.success) {
151
- * console.log(result.value) // string
152
- * } else {
153
- * console.error(result.reason) // FooError | BarError
154
- * }
155
11
  */
156
- /*@__NO_SIDE_EFFECTS__*/
157
- export function createCatcher<T>(Ctor: new (...args: any[]) => T) {
158
- return (err: unknown): ResultFailure<T> => {
159
- if (err instanceof Ctor) return failure(err)
160
- throw err
161
- }
12
+ export type ResultFailure<E = Error> = {
13
+ success: false
14
+ reason: E
162
15
  }
@@ -1,5 +1,3 @@
1
- import isoDatestringValidator from 'iso-datestring-validator'
2
- const { isValidISODateString } = isoDatestringValidator
3
1
  import { validateCidString } from '@atproto/lex-data'
4
2
  import {
5
3
  AtIdentifierString,
@@ -14,6 +12,7 @@ import {
14
12
  isAtIdentifierString,
15
13
  isAtUriString,
16
14
  isDatetimeString,
15
+ isDatetimeStringLenient,
17
16
  isValidDid,
18
17
  isValidHandle,
19
18
  isValidLanguage,
@@ -50,28 +49,9 @@ export {
50
49
  assertDatetimeString,
51
50
  ifDatetimeString,
52
51
  isDatetimeString,
52
+ isDatetimeStringLenient,
53
53
  } from '@atproto/syntax'
54
54
 
55
- /**
56
- * Matches any ISO-ish datetime string. This is a more lenient check than
57
- * the strict {@link isDatetimeString} guard, which only allows datetimes that
58
- * fully conform to the AT Protocol specification (e.g. must include timezone).
59
- */
60
- export function isDatetimeStringLenient<I>(
61
- input: I,
62
- ): input is I & DatetimeString {
63
- // @NOTE the returned type assertion is inaccurate wrt. the DatetimeString
64
- // type definition. A more accurate solution would be to use a branded type
65
- // instead of a template literal for the "datetime" format
66
- if (typeof input !== 'string') return false
67
- try {
68
- return isValidISODateString(input)
69
- } catch {
70
- // @NOTE isValidISODateString throws on some inputs
71
- return false
72
- }
73
- }
74
-
75
55
  // DatetimeString utilities
76
56
  export { currentDatetimeString, toDatetimeString } from '@atproto/syntax'
77
57
 
@@ -1,6 +1,6 @@
1
1
  import { LexError } from '@atproto/lex-data'
2
2
  import { arrayAgg } from '../util/array-agg.js'
3
- import { ResultFailure, failureReason } from './result.js'
3
+ import { ResultFailure } from './result.js'
4
4
  import {
5
5
  Issue,
6
6
  IssueInvalidType,
@@ -82,38 +82,6 @@ export class LexValidationError
82
82
  issues: this.issues.map((issue) => issue.toJSON()),
83
83
  }
84
84
  }
85
-
86
- /**
87
- * Creates a validation error by combining multiple validation failures.
88
- *
89
- * This is useful when validating against multiple possible schemas (e.g., unions)
90
- * and all branches fail. The resulting error contains issues from all failures.
91
- *
92
- * @param failures - The validation failures to combine
93
- * @returns A single validation error containing all issues from the failures
94
- *
95
- * @example
96
- * ```typescript
97
- * const failures = schemas.map(s => s.safeValidate(data)).filter(r => !r.success)
98
- * if (failures.length === schemas.length) {
99
- * throw LexValidationError.fromFailures(failures)
100
- * }
101
- * ```
102
- */
103
- static fromFailures(
104
- failures: readonly ResultFailure<LexValidationError>[],
105
- ): LexValidationError {
106
- if (failures.length === 1) return failureReason(failures[0])
107
- const issues = failures.flatMap(extractFailureIssues)
108
- return new LexValidationError(issues, {
109
- // Keep the original errors as the cause chain
110
- cause: failures.map(failureReason),
111
- })
112
- }
113
- }
114
-
115
- function extractFailureIssues(result: ResultFailure<LexValidationError>) {
116
- return result.reason.issues
117
85
  }
118
86
 
119
87
  function aggregateIssues(issues: Issue[]): Issue[] {
@@ -1,5 +1,4 @@
1
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2
- import { ResultFailure, ResultSuccess, success } from './result.js'
1
+ import type * as Result from './result.js'
3
2
  import { LexValidationError } from './validation-error.js'
4
3
  import {
5
4
  Issue,
@@ -15,16 +14,16 @@ import {
15
14
  /**
16
15
  * Represents a successful validation result.
17
16
  *
18
- * @typeParam Value - The type of the validated value
17
+ * @typeParam TValue - The type of the validated value
18
+ * @extends Result.ResultSuccess<TValue>
19
19
  */
20
- export type ValidationSuccess<Value = unknown> = ResultSuccess<Value>
20
+ export type ValidationSuccess<TValue = unknown> = Result.ResultSuccess<TValue>
21
21
 
22
22
  /**
23
23
  * Represents a failed validation result containing a {@link LexValidationError}.
24
24
  *
25
- * @extends ResultFailure<LexValidationError>
26
- * @see {@link ResultFailure}
27
25
  * @see {@link LexValidationError}
26
+ * @extends Result.ResultFailure<LexValidationError>
28
27
  */
29
28
  export type ValidationFailure = LexValidationError
30
29
 
@@ -429,24 +428,14 @@ export class ValidationContext {
429
428
  }
430
429
 
431
430
  /**
432
- * Creates a successful validation result with the given value.
431
+ * Helper method to create a successful validation result.
433
432
  *
434
433
  * @typeParam V - The value type
435
434
  * @param value - The validated value
436
435
  * @returns A successful validation result
437
436
  */
438
- success<V>(value: V): ValidationResult<V> {
439
- return success(value)
440
- }
441
-
442
- /**
443
- * Creates a failed validation result with the given error.
444
- *
445
- * @param reason - The validation error
446
- * @returns A failed validation result
447
- */
448
- failure(reason: LexValidationError): ValidationFailure {
449
- return reason
437
+ success<V>(value: V): ValidationSuccess<V> {
438
+ return { success: true, value }
450
439
  }
451
440
 
452
441
  /**
@@ -457,8 +446,8 @@ export class ValidationContext {
457
446
  * @param issue - The validation issue that caused the failure
458
447
  * @returns A failed validation result
459
448
  */
460
- issue(issue: Issue) {
461
- return this.failure(new LexValidationError([...this.issues, issue]))
449
+ issue(issue: Issue): ValidationFailure {
450
+ return new LexValidationError([...this.issues, issue])
462
451
  }
463
452
 
464
453
  /**
@@ -24,6 +24,10 @@ export class TokenSchema<
24
24
  super()
25
25
  }
26
26
 
27
+ get $token(): TValue {
28
+ return this.value
29
+ }
30
+
27
31
  validateInContext(input: unknown, ctx: ValidationContext) {
28
32
  if (input === this.value) {
29
33
  return ctx.success(this.value)
@@ -31,7 +35,11 @@ export class TokenSchema<
31
35
 
32
36
  // @NOTE: allow using the token instance itself (but convert to the actual
33
37
  // token value)
34
- if (input instanceof TokenSchema && input.value === this.value) {
38
+ if (
39
+ ctx.options.mode === 'parse' &&
40
+ input instanceof TokenSchema &&
41
+ input.value === this.value
42
+ ) {
35
43
  return ctx.success(this.value)
36
44
  }
37
45
 
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  InferInput,
3
3
  InferOutput,
4
+ Issue,
4
5
  LexValidationError,
5
6
  Schema,
6
7
  ValidationContext,
7
- ValidationFailure,
8
8
  Validator,
9
9
  } from '../core.js'
10
10
 
@@ -44,16 +44,16 @@ export class UnionSchema<
44
44
  }
45
45
 
46
46
  validateInContext(input: unknown, ctx: ValidationContext) {
47
- const failures: ValidationFailure[] = []
47
+ const issues: Issue[] = []
48
48
 
49
49
  for (const validator of this.validators) {
50
50
  const result = ctx.validate(input, validator)
51
51
  if (result.success) return result
52
52
 
53
- failures.push(result)
53
+ issues.push(...result.issues)
54
54
  }
55
55
 
56
- return ctx.failure(LexValidationError.fromFailures(failures))
56
+ return new LexValidationError(issues)
57
57
  }
58
58
  }
59
59