@atproto/lex-schema 0.0.4 → 0.0.5

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 (109) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/core/$type.d.ts +7 -0
  3. package/dist/core/$type.d.ts.map +1 -1
  4. package/dist/core/$type.js.map +1 -1
  5. package/dist/core/result.d.ts +7 -6
  6. package/dist/core/result.d.ts.map +1 -1
  7. package/dist/core/result.js +9 -8
  8. package/dist/core/result.js.map +1 -1
  9. package/dist/core/string-format.d.ts +37 -26
  10. package/dist/core/string-format.d.ts.map +1 -1
  11. package/dist/core/string-format.js +66 -59
  12. package/dist/core/string-format.js.map +1 -1
  13. package/dist/core/types.d.ts +3 -0
  14. package/dist/core/types.d.ts.map +1 -1
  15. package/dist/core/types.js.map +1 -1
  16. package/dist/external.d.ts +7 -6
  17. package/dist/external.d.ts.map +1 -1
  18. package/dist/external.js +1 -0
  19. package/dist/external.js.map +1 -1
  20. package/dist/helpers.d.ts +36 -0
  21. package/dist/helpers.d.ts.map +1 -0
  22. package/dist/helpers.js +3 -0
  23. package/dist/helpers.js.map +1 -0
  24. package/dist/schema/blob.d.ts +1 -0
  25. package/dist/schema/blob.d.ts.map +1 -1
  26. package/dist/schema/blob.js +32 -18
  27. package/dist/schema/blob.js.map +1 -1
  28. package/dist/schema/custom.js +1 -1
  29. package/dist/schema/custom.js.map +1 -1
  30. package/dist/schema/integer.js +1 -1
  31. package/dist/schema/integer.js.map +1 -1
  32. package/dist/schema/params.d.ts +0 -1
  33. package/dist/schema/params.d.ts.map +1 -1
  34. package/dist/schema/params.js.map +1 -1
  35. package/dist/schema/payload.d.ts +17 -15
  36. package/dist/schema/payload.d.ts.map +1 -1
  37. package/dist/schema/payload.js +28 -0
  38. package/dist/schema/payload.js.map +1 -1
  39. package/dist/schema/procedure.d.ts +3 -6
  40. package/dist/schema/procedure.d.ts.map +1 -1
  41. package/dist/schema/procedure.js +1 -0
  42. package/dist/schema/procedure.js.map +1 -1
  43. package/dist/schema/query.d.ts +3 -5
  44. package/dist/schema/query.d.ts.map +1 -1
  45. package/dist/schema/query.js +1 -0
  46. package/dist/schema/query.js.map +1 -1
  47. package/dist/schema/record.d.ts +13 -12
  48. package/dist/schema/record.d.ts.map +1 -1
  49. package/dist/schema/record.js.map +1 -1
  50. package/dist/schema/refine.js +1 -1
  51. package/dist/schema/refine.js.map +1 -1
  52. package/dist/schema/subscription.d.ts +4 -7
  53. package/dist/schema/subscription.d.ts.map +1 -1
  54. package/dist/schema/subscription.js.map +1 -1
  55. package/dist/schema/typed-object.d.ts +7 -6
  56. package/dist/schema/typed-object.d.ts.map +1 -1
  57. package/dist/schema/typed-object.js.map +1 -1
  58. package/dist/schema/union.d.ts.map +1 -1
  59. package/dist/schema/union.js +1 -4
  60. package/dist/schema/union.js.map +1 -1
  61. package/dist/util/assertion-util.d.ts +8 -0
  62. package/dist/util/assertion-util.d.ts.map +1 -0
  63. package/dist/util/assertion-util.js +31 -0
  64. package/dist/util/assertion-util.js.map +1 -0
  65. package/dist/validation/schema.d.ts +21 -2
  66. package/dist/validation/schema.d.ts.map +1 -1
  67. package/dist/validation/schema.js +25 -2
  68. package/dist/validation/schema.js.map +1 -1
  69. package/dist/validation/validation-error.d.ts.map +1 -1
  70. package/dist/validation/validation-error.js +3 -3
  71. package/dist/validation/validation-error.js.map +1 -1
  72. package/dist/validation/validation-issue.js +10 -2
  73. package/dist/validation/validation-issue.js.map +1 -1
  74. package/dist/validation/validator.d.ts +4 -3
  75. package/dist/validation/validator.d.ts.map +1 -1
  76. package/dist/validation/validator.js +13 -10
  77. package/dist/validation/validator.js.map +1 -1
  78. package/package.json +2 -2
  79. package/src/core/$type.ts +4 -0
  80. package/src/core/result.ts +9 -8
  81. package/src/core/string-format.ts +88 -68
  82. package/src/core/types.ts +4 -0
  83. package/src/external.ts +9 -8
  84. package/src/helpers.test.ts +486 -0
  85. package/src/helpers.ts +61 -0
  86. package/src/schema/blob.test.ts +2 -4
  87. package/src/schema/blob.ts +31 -23
  88. package/src/schema/custom.test.ts +5 -5
  89. package/src/schema/custom.ts +1 -1
  90. package/src/schema/integer.ts +1 -1
  91. package/src/schema/params.ts +0 -7
  92. package/src/schema/payload.ts +67 -34
  93. package/src/schema/permission-set.test.ts +36 -36
  94. package/src/schema/procedure.test.ts +1 -62
  95. package/src/schema/procedure.ts +8 -20
  96. package/src/schema/query.test.ts +22 -69
  97. package/src/schema/query.ts +7 -14
  98. package/src/schema/record.ts +8 -4
  99. package/src/schema/refine.ts +1 -1
  100. package/src/schema/subscription.test.ts +30 -93
  101. package/src/schema/subscription.ts +11 -24
  102. package/src/schema/typed-object.ts +7 -3
  103. package/src/schema/union.ts +1 -4
  104. package/src/util/assertion-util.ts +40 -0
  105. package/src/validation/schema.ts +29 -4
  106. package/src/validation/validation-error.ts +4 -4
  107. package/src/validation/validation-issue.ts +12 -2
  108. package/src/validation/validator.ts +16 -12
  109. package/tsconfig.tests.json +1 -1
@@ -1,33 +1,20 @@
1
1
  import { NsidString } from '../core.js'
2
- import { Infer } from '../validation.js'
3
- import { ObjectSchema } from './object.js'
2
+ import { Infer, Schema } from '../validation.js'
4
3
  import { ParamsSchema } from './params.js'
5
- import { RefSchema } from './ref.js'
6
- import { TypedUnionSchema } from './typed-union.js'
7
4
 
8
- export type InferSubscriptionParameters<S extends Subscription> =
9
- S extends Subscription<any, infer P extends ParamsSchema, any>
10
- ? Infer<P>
11
- : never
5
+ export type InferSubscriptionParameters<S extends Subscription> = Infer<
6
+ S['parameters']
7
+ >
12
8
 
13
- export type InferSubscriptionMessage<S extends Subscription> =
14
- S extends Subscription<
15
- any,
16
- any,
17
- infer M extends RefSchema | TypedUnionSchema | ObjectSchema
18
- >
19
- ? Infer<M>
20
- : unknown
9
+ export type InferSubscriptionMessage<S extends Subscription> = Infer<
10
+ S['message']
11
+ >
21
12
 
22
13
  export class Subscription<
23
- TNsid extends NsidString = any,
24
- TParameters extends ParamsSchema = any,
25
- TMessage extends
26
- | undefined
27
- | RefSchema
28
- | TypedUnionSchema
29
- | ObjectSchema = any,
30
- TErrors extends undefined | readonly string[] = any,
14
+ TNsid extends NsidString = NsidString,
15
+ TParameters extends ParamsSchema = ParamsSchema,
16
+ TMessage extends Schema = Schema,
17
+ TErrors extends undefined | readonly string[] = undefined | readonly string[],
31
18
  > {
32
19
  readonly type = 'subscription' as const
33
20
 
@@ -7,15 +7,16 @@ import {
7
7
  Validator,
8
8
  ValidatorContext,
9
9
  } from '../validation.js'
10
+ import { TypedObject } from './typed-union.js'
10
11
 
11
12
  export type TypedObjectSchemaOutput<
12
13
  T extends $Type,
13
- S extends Validator<{ [_ in string]?: unknown }>,
14
+ S extends Validator<{ [k: string]: unknown }>,
14
15
  > = Simplify<Infer<S> & { $type?: T }>
15
16
 
16
17
  export class TypedObjectSchema<
17
18
  const T extends $Type = any,
18
- const S extends Validator<{ [_ in string]?: unknown }> = any,
19
+ const S extends Validator<{ [k: string]: unknown }> = any,
19
20
  > extends Schema<TypedObjectSchemaOutput<T, S>> {
20
21
  constructor(
21
22
  readonly $type: T,
@@ -26,7 +27,10 @@ export class TypedObjectSchema<
26
27
 
27
28
  isTypeOf<X extends Record<string, unknown>>(
28
29
  value: X,
29
- ): value is X extends { $type?: T } ? X : X & { $type?: T } {
30
+ ): value is Exclude<
31
+ X extends { $type?: T } ? X : X & { $type?: T },
32
+ TypedObject
33
+ > {
30
34
  return value.$type === undefined || value.$type === this.$type
31
35
  }
32
36
 
@@ -33,9 +33,6 @@ export class UnionSchema<V extends UnionSchemaValidators = any> extends Schema<
33
33
  }
34
34
  }
35
35
 
36
- return {
37
- success: false,
38
- error: ValidationError.fromFailures(failures),
39
- }
36
+ return ctx.failure(ValidationError.fromFailures(failures))
40
37
  }
41
38
  }
@@ -0,0 +1,40 @@
1
+ export type AssertFn<T> = <I extends string>(input: I) => asserts input is I & T
2
+ export type CastFn<T> = <I extends string>(input: I) => I & T
3
+ export type CheckFn<T> = <I extends string>(input: I) => input is I & T
4
+
5
+ export function createAssertFunction<T extends string>(
6
+ checkFn: (input: string) => input is T,
7
+ errorMessage?: string,
8
+ ): AssertFn<T>
9
+ export function createAssertFunction<T extends string>(
10
+ checkFn: (input: string) => boolean,
11
+ errorMessage?: string,
12
+ ): AssertFn<T>
13
+ export function createAssertFunction<T extends string>(
14
+ checkFn: (input: string) => boolean,
15
+ errorMessage = 'Invalid format',
16
+ ): AssertFn<T> {
17
+ return (input: string) => {
18
+ if (!checkFn(input)) throw new Error(errorMessage)
19
+ }
20
+ }
21
+
22
+ /*@__NO_SIDE_EFFECTS__*/
23
+ export function createCastFunction<T>(assertFn: AssertFn<T>): CastFn<T> {
24
+ return <I extends string>(input: I) => {
25
+ assertFn(input)
26
+ return input as I & T
27
+ }
28
+ }
29
+
30
+ /*@__NO_SIDE_EFFECTS__ */
31
+ export function createCheckFunction<T>(assertFn: AssertFn<T>): CheckFn<T> {
32
+ return <I extends string>(input: I): input is I & T => {
33
+ try {
34
+ assertFn(input)
35
+ return true
36
+ } catch {
37
+ return false
38
+ }
39
+ }
40
+ }
@@ -5,17 +5,42 @@ import {
5
5
  ValidatorContext,
6
6
  } from './validator.js'
7
7
 
8
- export abstract class Schema<Output> implements Validator<Output> {
9
- declare readonly ['_lex']: { output: Output }
8
+ export abstract class Schema<Output = any> implements Validator<Output> {
9
+ declare readonly ['__lex']: { output: Output }
10
10
 
11
11
  abstract validateInContext(
12
12
  input: unknown,
13
13
  ctx: ValidatorContext,
14
14
  ): ValidationResult<Output>
15
15
 
16
+ /**
17
+ * @note use {@link check}() instead of {@link assert}() if you encounter a
18
+ * `ts(2775)` error and you are not able to fully type the validator. This
19
+ * will typically arise in generic contexts, where the narrowed type is not
20
+ * needed.
21
+ */
16
22
  assert(input: unknown): asserts input is Output {
17
23
  const result = this.safeParse(input, { allowTransform: false })
18
- if (!result.success) throw result.error
24
+ if (!result.success) throw result.reason
25
+ }
26
+
27
+ /**
28
+ * Alias for {@link assert}(). Most useful in generic contexts where the
29
+ * validator is not exactly typed, allowing to avoid "_Assertions require
30
+ * every name in the call target to be declared with an explicit type
31
+ * annotation. ts(2775)_" errors.
32
+ */
33
+ check(input: unknown): void {
34
+ this.assert(input)
35
+ }
36
+
37
+ /**
38
+ * Casts the input (by validating it) to the output type if it matches the
39
+ * schema, otherwise throws. This is the same as calling {@link parse}() with
40
+ * `allowTransform: false`.
41
+ */
42
+ cast<I>(input: I): I & Output {
43
+ return this.parse(input, { allowTransform: false })
19
44
  }
20
45
 
21
46
  matches(input: unknown): input is Output {
@@ -34,7 +59,7 @@ export abstract class Schema<Output> implements Validator<Output> {
34
59
  parse(input: unknown, options?: ValidationOptions): Output
35
60
  parse(input: unknown, options?: ValidationOptions): Output {
36
61
  const result = this.safeParse(input, options)
37
- if (!result.success) throw result.error
62
+ if (!result.success) throw result.reason
38
63
  return result.value
39
64
  }
40
65
 
@@ -1,4 +1,4 @@
1
- import { ResultFailure, failureError } from '../core.js'
1
+ import { ResultFailure, failureReason } from '../core.js'
2
2
  import { arrayAgg } from '../util/array-agg.js'
3
3
  import {
4
4
  Issue,
@@ -20,17 +20,17 @@ export class ValidationError extends Error {
20
20
  static fromFailures(
21
21
  failures: ResultFailure<ValidationError>[],
22
22
  ): ValidationError {
23
- if (failures.length === 1) return failures[0].error
23
+ if (failures.length === 1) return failureReason(failures[0])
24
24
  const issues = failures.flatMap(extractFailureIssues)
25
25
  return new ValidationError(issues, {
26
26
  // Keep the original errors as the cause chain
27
- cause: failures.map(failureError),
27
+ cause: failures.map(failureReason),
28
28
  })
29
29
  }
30
30
  }
31
31
 
32
32
  function extractFailureIssues(result: ResultFailure<ValidationError>) {
33
- return result.error.issues
33
+ return result.reason.issues
34
34
  }
35
35
 
36
36
  function aggregateIssues(issues: Issue[]): Issue[] {
@@ -184,8 +184,18 @@ function stringifyType(value: unknown): string {
184
184
  if (value instanceof Set) return 'set'
185
185
  return 'object'
186
186
  case 'number':
187
- if (Number.isInteger(value)) return 'integer'
188
- if (Number.isNaN(value)) return 'NaN'
187
+ if (Number.isInteger(value) && Number.isSafeInteger(value)) {
188
+ return 'integer'
189
+ }
190
+ if (Number.isNaN(value)) {
191
+ return 'NaN'
192
+ }
193
+ if (value === Infinity) {
194
+ return 'Infinity'
195
+ }
196
+ if (value === -Infinity) {
197
+ return '-Infinity'
198
+ }
189
199
  return 'float'
190
200
  default:
191
201
  return typeof value
@@ -25,7 +25,7 @@ export type ValidationOptions = {
25
25
  allowTransform?: boolean
26
26
  }
27
27
 
28
- export type Infer<T extends Validator> = T['_lex']['output']
28
+ export type Infer<T extends Validator> = T['__lex']['output']
29
29
 
30
30
  export interface Validator<Output = any> {
31
31
  /**
@@ -34,7 +34,7 @@ export interface Validator<Output = any> {
34
34
  *
35
35
  * @deprecated **INTERNAL API, DO NOT USE**.
36
36
  */
37
- readonly ['_lex']: { output: Output }
37
+ readonly ['__lex']: { output: Output }
38
38
 
39
39
  /**
40
40
  * @internal **INTERNAL API**: use {@link ValidatorContext.validate} instead
@@ -162,24 +162,28 @@ export class ValidatorContext {
162
162
  return success(value)
163
163
  }
164
164
 
165
- failure(issue: Issue): ValidationFailure {
166
- return failure(new ValidationError([...this.issues, issue]))
165
+ failure(reason: ValidationError): ValidationFailure {
166
+ return failure(reason)
167
+ }
168
+
169
+ issue(issue: Issue) {
170
+ return this.failure(new ValidationError([...this.issues, issue]))
167
171
  }
168
172
 
169
173
  issueInvalidValue(input: unknown, values: readonly unknown[]) {
170
- return this.failure(new IssueInvalidValue(this.path, input, values))
174
+ return this.issue(new IssueInvalidValue(this.path, input, values))
171
175
  }
172
176
 
173
177
  issueInvalidType(input: unknown, expected: string) {
174
- return this.failure(new IssueInvalidType(this.path, input, [expected]))
178
+ return this.issue(new IssueInvalidType(this.path, input, [expected]))
175
179
  }
176
180
 
177
181
  issueRequiredKey(input: object, key: PropertyKey) {
178
- return this.failure(new IssueRequiredKey(this.path, input, key))
182
+ return this.issue(new IssueRequiredKey(this.path, input, key))
179
183
  }
180
184
 
181
185
  issueInvalidFormat(input: unknown, format: string, msg?: string) {
182
- return this.failure(new IssueInvalidFormat(this.path, input, format, msg))
186
+ return this.issue(new IssueInvalidFormat(this.path, input, format, msg))
183
187
  }
184
188
 
185
189
  issueTooBig(
@@ -188,7 +192,7 @@ export class ValidatorContext {
188
192
  max: number,
189
193
  actual: number,
190
194
  ) {
191
- return this.failure(new IssueTooBig(this.path, input, max, type, actual))
195
+ return this.issue(new IssueTooBig(this.path, input, max, type, actual))
192
196
  }
193
197
 
194
198
  issueTooSmall(
@@ -197,7 +201,7 @@ export class ValidatorContext {
197
201
  min: number,
198
202
  actual: number,
199
203
  ) {
200
- return this.failure(new IssueTooSmall(this.path, input, min, type, actual))
204
+ return this.issue(new IssueTooSmall(this.path, input, min, type, actual))
201
205
  }
202
206
 
203
207
  issueInvalidPropertyValue<I>(
@@ -207,7 +211,7 @@ export class ValidatorContext {
207
211
  ) {
208
212
  const value = input[property]
209
213
  const path = this.concatPath(property)
210
- return this.failure(new IssueInvalidValue(path, value, values))
214
+ return this.issue(new IssueInvalidValue(path, value, values))
211
215
  }
212
216
 
213
217
  issueInvalidPropertyType<I>(
@@ -217,6 +221,6 @@ export class ValidatorContext {
217
221
  ) {
218
222
  const value = input[property]
219
223
  const path = this.concatPath(property)
220
- return this.failure(new IssueInvalidType(path, value, [expected]))
224
+ return this.issue(new IssueInvalidType(path, value, [expected]))
221
225
  }
222
226
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "extends": "../../../tsconfig/tests.json",
3
- "include": ["./tests", "./src/**.test.ts"],
3
+ "include": ["./tests", "./src/**/*.test.ts"],
4
4
  "compilerOptions": {
5
5
  "noImplicitAny": true,
6
6
  "rootDir": "./",