justus 0.5.2 → 0.5.4

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 (70) hide show
  1. package/dist/dts-generator.cjs +22 -7
  2. package/dist/dts-generator.cjs.map +1 -1
  3. package/dist/dts-generator.mjs +22 -7
  4. package/dist/dts-generator.mjs.map +1 -1
  5. package/dist/extra/arn.cjs +1 -1
  6. package/dist/extra/arn.cjs.map +1 -1
  7. package/dist/extra/arn.mjs +1 -1
  8. package/dist/extra/arn.mjs.map +1 -1
  9. package/dist/index.cjs +13 -2
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.ts +12 -0
  12. package/dist/index.mjs +9 -2
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/types.cjs +0 -7
  15. package/dist/types.cjs.map +1 -1
  16. package/dist/types.d.ts +11 -13
  17. package/dist/types.mjs +0 -6
  18. package/dist/types.mjs.map +1 -1
  19. package/dist/utilities.cjs +1 -0
  20. package/dist/utilities.cjs.map +1 -1
  21. package/dist/utilities.mjs +1 -0
  22. package/dist/utilities.mjs.map +1 -1
  23. package/dist/validators/bigint.cjs +146 -0
  24. package/dist/validators/bigint.cjs.map +6 -0
  25. package/dist/validators/bigint.d.ts +46 -0
  26. package/dist/validators/bigint.mjs +118 -0
  27. package/dist/validators/bigint.mjs.map +6 -0
  28. package/dist/validators/boolean.cjs +1 -1
  29. package/dist/validators/boolean.cjs.map +1 -1
  30. package/dist/validators/boolean.mjs +1 -1
  31. package/dist/validators/boolean.mjs.map +1 -1
  32. package/dist/validators/constant.cjs +2 -1
  33. package/dist/validators/constant.cjs.map +1 -1
  34. package/dist/validators/constant.d.ts +2 -2
  35. package/dist/validators/constant.mjs +2 -1
  36. package/dist/validators/constant.mjs.map +1 -1
  37. package/dist/validators/never.cjs +1 -1
  38. package/dist/validators/never.cjs.map +1 -1
  39. package/dist/validators/never.mjs +2 -2
  40. package/dist/validators/never.mjs.map +1 -1
  41. package/dist/validators/number.cjs +5 -5
  42. package/dist/validators/number.cjs.map +1 -1
  43. package/dist/validators/number.mjs +5 -5
  44. package/dist/validators/number.mjs.map +1 -1
  45. package/dist/validators/object.cjs +7 -5
  46. package/dist/validators/object.cjs.map +1 -1
  47. package/dist/validators/object.mjs +8 -6
  48. package/dist/validators/object.mjs.map +1 -1
  49. package/dist/validators/optional.cjs +1 -1
  50. package/dist/validators/optional.cjs.map +1 -1
  51. package/dist/validators/optional.mjs +2 -2
  52. package/dist/validators/optional.mjs.map +1 -1
  53. package/dist/validators/string.cjs +2 -2
  54. package/dist/validators/string.cjs.map +1 -1
  55. package/dist/validators/string.mjs +2 -2
  56. package/dist/validators/string.mjs.map +1 -1
  57. package/package.json +3 -8
  58. package/src/dts-generator.ts +23 -6
  59. package/src/extra/arn.ts +1 -1
  60. package/src/index.ts +20 -2
  61. package/src/types.ts +11 -16
  62. package/src/utilities.ts +1 -0
  63. package/src/validators/bigint.ts +147 -0
  64. package/src/validators/boolean.ts +1 -1
  65. package/src/validators/constant.ts +4 -3
  66. package/src/validators/never.ts +2 -2
  67. package/src/validators/number.ts +5 -5
  68. package/src/validators/object.ts +8 -7
  69. package/src/validators/optional.ts +2 -2
  70. package/src/validators/string.ts +2 -2
@@ -0,0 +1,147 @@
1
+ import { assertSchema, assertValidation, ValidationError } from '../errors'
2
+ import { AbstractValidator, makeValidatorFactory } from '../types'
3
+
4
+ import type { Branding, Validator } from '../types'
5
+
6
+ /* ========================================================================== */
7
+
8
+ /** Constraints to validate a `bigint` with. */
9
+ export interface BigIntConstraints {
10
+ /** The value for which a `bigint` must be multiple of for it to be valid */
11
+ multipleOf?: bigint | number,
12
+ /** The _inclusive_ maximum value for a valid `bigint`: `value <= maximum` */
13
+ maximum?: bigint | number,
14
+ /** The _inclusive_ minimum value for a valid `bigint`: `value >= minimum` */
15
+ minimum?: bigint | number,
16
+ /** The _exclusive_ maximum value for a valid `bigint`: `value < exclusiveMaximum` */
17
+ exclusiveMaximum?: bigint | number,
18
+ /** The _exclusive_ minimum value for a valid `bigint`: `value > exclusiveMaximum` */
19
+ exclusiveMinimum?: bigint | number,
20
+ /** Allow bigints to be parsed from strings (e.g. `123.456` or `0x0CAFE`, default: `false`) */
21
+ fromString?: boolean,
22
+ /** Allow bigints to be parsed from numbers (default: `true`) */
23
+ fromNumber?: boolean,
24
+ }
25
+
26
+ /** Constraints to validate a `bigint` with extra branding information. */
27
+ export interface BrandedBigIntConstraints<B extends string> extends BigIntConstraints {
28
+ /** The _brand_ of the string (will generate a `__brand_${B}` type property */
29
+ brand: B
30
+ }
31
+
32
+ /** A `Validator` validating any `bigint`. */
33
+ export class AnyBigIntValidator extends AbstractValidator<bigint> {
34
+ validate(value: unknown): bigint {
35
+ if (typeof value === 'number') {
36
+ try {
37
+ value = BigInt(value)
38
+ } catch (error) {
39
+ throw new ValidationError('BigInt can not be parsed from number')
40
+ }
41
+ }
42
+ assertValidation(typeof value === 'bigint', 'Value is not a "bigint"')
43
+ return value
44
+ }
45
+ }
46
+
47
+ /** A `Validator` validating `bigint`s with constaints. */
48
+ export class BigIntValidator<N extends bigint = bigint> extends AbstractValidator<N, bigint> {
49
+ readonly fromString: boolean
50
+ readonly fromNumber: boolean
51
+ readonly exclusiveMaximum?: bigint
52
+ readonly exclusiveMinimum?: bigint
53
+ readonly maximum?: bigint
54
+ readonly minimum?: bigint
55
+ readonly multipleOf?: bigint
56
+ readonly brand?: string
57
+
58
+ constructor(constraints: BigIntConstraints = {}) {
59
+ super()
60
+
61
+ const {
62
+ exclusiveMaximum,
63
+ exclusiveMinimum,
64
+ maximum,
65
+ minimum,
66
+ multipleOf,
67
+ fromString = false,
68
+ fromNumber = true,
69
+ } = constraints
70
+
71
+ if ('brand' in constraints) this.brand = (<any> constraints).brand
72
+ this.fromString = fromString
73
+ this.fromNumber = fromNumber
74
+
75
+ const _exclusiveMaximum = exclusiveMaximum === undefined ? undefined : BigInt(exclusiveMaximum)
76
+ const _exclusiveMinimum = exclusiveMinimum === undefined ? undefined : BigInt(exclusiveMinimum)
77
+ const _maximum = maximum === undefined ? undefined : BigInt(maximum)
78
+ const _minimum = minimum === undefined ? undefined : BigInt(minimum)
79
+ const _multipleOf = multipleOf === undefined ? undefined : BigInt(multipleOf)
80
+
81
+ if ((_maximum !== undefined) && (_minimum !== undefined)) {
82
+ assertSchema(_maximum >= _minimum, `Constraint "minimum" (${_minimum}) is greater than "maximum" (${_maximum})`)
83
+ }
84
+
85
+ if ((_exclusiveMaximum !== undefined) && (_minimum !== undefined)) {
86
+ assertSchema(_exclusiveMaximum > _minimum,
87
+ `Constraint "exclusiveMaximum" (${_exclusiveMaximum}) must be greater than "minimum" (${_minimum})`)
88
+ }
89
+
90
+ if ((_exclusiveMinimum !== undefined) && (_maximum != undefined)) {
91
+ assertSchema(_maximum > _exclusiveMinimum,
92
+ `Constraint "maximum" (${_maximum}) must be greater than "exclusiveMinimum" (${_exclusiveMinimum})`)
93
+ }
94
+
95
+ if ((_exclusiveMinimum != undefined) && (_exclusiveMaximum !== undefined)) {
96
+ assertSchema(_exclusiveMaximum > _exclusiveMinimum,
97
+ `Constraint "exclusiveMaximum" (${_exclusiveMaximum}) must be greater than "exclusiveMinimum" (${_exclusiveMinimum})`)
98
+ }
99
+
100
+ if (_multipleOf !== undefined) {
101
+ assertSchema(_multipleOf > 0, `Constraint "multipleOf" (${_multipleOf}) must be greater than zero`)
102
+ }
103
+
104
+ this.exclusiveMaximum = _exclusiveMaximum
105
+ this.exclusiveMinimum = _exclusiveMinimum
106
+ this.maximum = _maximum
107
+ this.minimum = _minimum
108
+ this.multipleOf = _multipleOf
109
+ }
110
+
111
+ validate(value: unknown): N {
112
+ // Allow parsing from strings or numbers
113
+ if (((typeof value === 'string') && (this.fromString)) ||
114
+ ((typeof value === 'number') && (this.fromNumber))) {
115
+ try {
116
+ value = BigInt(value)
117
+ } catch (error) {
118
+ throw new ValidationError('BigInt can not be parsed from ' + typeof value)
119
+ }
120
+ }
121
+
122
+ assertValidation(typeof value === 'bigint', 'Value is not a "bigint"')
123
+
124
+ assertValidation(((this.minimum === undefined) || (value >= this.minimum)),
125
+ `BigInt is less than ${this.minimum}`)
126
+ assertValidation(((this.maximum === undefined) || (value <= this.maximum)),
127
+ `BigInt is greater than ${this.maximum}`)
128
+ assertValidation((this.exclusiveMinimum === undefined) || (value > this.exclusiveMinimum),
129
+ `BigInt is less than or equal to ${this.exclusiveMinimum}`)
130
+ assertValidation((this.exclusiveMaximum === undefined) || (value < this.exclusiveMaximum),
131
+ `BigInt is greater than or equal to ${this.exclusiveMaximum}`)
132
+ assertValidation((this.multipleOf === undefined) || (!(value % this.multipleOf)),
133
+ `BigInt is not a multiple of ${this.multipleOf}`)
134
+
135
+ return value as N
136
+ }
137
+ }
138
+
139
+ export function bigintFactory(constraints: BigIntConstraints): BigIntValidator<bigint>
140
+ export function bigintFactory<N extends bigint>(constraints: BigIntConstraints): BigIntValidator<N>
141
+ export function bigintFactory<B extends string>(constraints: BrandedBigIntConstraints<B>): BigIntValidator<bigint & Branding<B>>
142
+ export function bigintFactory(constraints: BigIntConstraints): Validator<bigint> {
143
+ return new BigIntValidator(constraints)
144
+ }
145
+
146
+ /** Validate `bigint`s. */
147
+ export const bigint = makeValidatorFactory(new AnyBigIntValidator(), bigintFactory)
@@ -25,7 +25,7 @@ export class BooleanValidator extends AbstractValidator<boolean> {
25
25
 
26
26
  validate(value: unknown): boolean {
27
27
  // Allow parsing from strings
28
- if ((typeof value == 'string') && (this.fromString)) {
28
+ if ((typeof value === 'string') && (this.fromString)) {
29
29
  const string = value.toLowerCase()
30
30
  const parsed = string === 'true' ? true : string === 'false' ? false : undefined
31
31
  assertValidation(parsed !== undefined, 'Boolean can not be parsed from string')
@@ -5,7 +5,7 @@ import { AbstractValidator } from '../types'
5
5
  import type { Validator } from '../types'
6
6
 
7
7
  /** A `Validator` for _constants_. */
8
- export class ConstantValidator<T extends string | number | boolean | null> extends AbstractValidator<T> {
8
+ export class ConstantValidator<T extends string | number | boolean | bigint | null> extends AbstractValidator<T> {
9
9
  readonly constant: T
10
10
 
11
11
  constructor(constant: T) {
@@ -14,13 +14,14 @@ export class ConstantValidator<T extends string | number | boolean | null> exten
14
14
  }
15
15
 
16
16
  validate(value: unknown): T {
17
- assertValidation(value === this.constant, `Value does not match constant "${this.constant}"`)
17
+ const extra = this.constant === null ? '' : ` (${typeof this.constant})`
18
+ assertValidation(value === this.constant, `Value does not match constant "${this.constant}"${extra}`)
18
19
  return value as T
19
20
  }
20
21
  }
21
22
 
22
23
  /** Validate _constants_. */
23
- export function constant<T extends string | number | boolean | null>(constant: T): Validator<T> {
24
+ export function constant<T extends string | number | boolean | bigint | null>(constant: T): Validator<T> {
24
25
  return new ConstantValidator(constant)
25
26
  }
26
27
 
@@ -1,5 +1,5 @@
1
1
  import { ValidationError } from '../errors'
2
- import { AbstractValidator, defaultValidationOptions } from '../types'
2
+ import { AbstractValidator } from '../types'
3
3
 
4
4
  import type { ValidationOptions } from '../types'
5
5
 
@@ -7,7 +7,7 @@ import type { ValidationOptions } from '../types'
7
7
  export class NeverValidator extends AbstractValidator<never> {
8
8
  optional: true = true
9
9
 
10
- validate(value: unknown, options: ValidationOptions = defaultValidationOptions): never {
10
+ validate(value: unknown, options: ValidationOptions = {}): never {
11
11
  const { stripForbiddenProperties } = options
12
12
 
13
13
  // @ts-expect-error
@@ -46,7 +46,7 @@ export interface BrandedNumberConstraints<B extends string> extends NumberConstr
46
46
  /** A `Validator` validating any `number`. */
47
47
  export class AnyNumberValidator extends AbstractValidator<number> {
48
48
  validate(value: unknown): number {
49
- assertValidation(typeof value == 'number', 'Value is not a "number"')
49
+ assertValidation(typeof value === 'number', 'Value is not a "number"')
50
50
  assertValidation(! isNaN(value), 'Number is "NaN"')
51
51
  return value
52
52
  }
@@ -131,13 +131,13 @@ export class NumberValidator<N extends number = number> extends AbstractValidato
131
131
 
132
132
  validate(value: unknown): N {
133
133
  // Allow parsing from strings
134
- if ((typeof value == 'string') && (this.fromString)) {
134
+ if ((typeof value === 'string') && (this.fromString)) {
135
135
  const parsed = +`${value}`
136
136
  assertValidation(! isNaN(parsed), 'Number can not be parsed from string')
137
137
  value = parsed
138
138
  }
139
139
 
140
- assertValidation(typeof value == 'number', 'Value is not a "number"')
140
+ assertValidation(typeof value === 'number', 'Value is not a "number"')
141
141
 
142
142
  if (isNaN(value)) {
143
143
  assertValidation(this.allowNaN, 'Number is "NaN"')
@@ -147,10 +147,10 @@ export class NumberValidator<N extends number = number> extends AbstractValidato
147
147
  assertValidation(value >= this.minimum, `Number is less than ${this.minimum}`)
148
148
  assertValidation(value <= this.maximum, `Number is greater than ${this.maximum}`)
149
149
 
150
- assertValidation((this.exclusiveMinimum == undefined) || (value > this.exclusiveMinimum),
150
+ assertValidation((this.exclusiveMinimum === undefined) || (value > this.exclusiveMinimum),
151
151
  `Number is less than or equal to ${this.exclusiveMinimum}`)
152
152
 
153
- assertValidation((this.exclusiveMaximum == undefined) || (value < this.exclusiveMaximum),
153
+ assertValidation((this.exclusiveMaximum === undefined) || (value < this.exclusiveMaximum),
154
154
  `Number is greater than or equal to ${this.exclusiveMaximum}`)
155
155
 
156
156
  assertValidation(this.#isMultipleOf ? this.#isMultipleOf(value) : true,
@@ -1,6 +1,6 @@
1
1
  import { assertValidation, ValidationErrorBuilder } from '../errors'
2
2
  import { registry } from '../registry'
3
- import { AbstractValidator, defaultValidationOptions, makeValidatorFactory } from '../types'
3
+ import { AbstractValidator, makeValidatorFactory } from '../types'
4
4
  import { getValidator } from '../utilities'
5
5
 
6
6
  import type {
@@ -17,7 +17,7 @@ import type {
17
17
  /** A `Validator` validating any `object`. */
18
18
  export class AnyObjectValidator extends AbstractValidator<Record<string, any>> {
19
19
  validate(value: unknown): Record<string, any> {
20
- assertValidation(typeof value == 'object', 'Value is not an "object"')
20
+ assertValidation(typeof value === 'object', 'Value is not an "object"')
21
21
  assertValidation(value !== null, 'Value is "null"')
22
22
  return value
23
23
  }
@@ -43,11 +43,11 @@ export class ObjectValidator<S extends Schema> extends AbstractValidator<InferSc
43
43
  this.schema = schema
44
44
  }
45
45
 
46
- validate(value: unknown, options: ValidationOptions = defaultValidationOptions): InferSchema<S> {
46
+ validate(value: unknown, options: ValidationOptions = {}): InferSchema<S> {
47
47
  assertValidation(typeof value === 'object', 'Value is not an "object"')
48
48
  assertValidation(value !== null, 'Value is "null"')
49
49
 
50
- const { stripAdditionalProperties, stripOptionalNulls } = options
50
+ const { stripAdditionalProperties, stripOptionalNulls, partialValidation } = options
51
51
 
52
52
  const record: { [ k in string | number | symbol ]?: unknown } = value
53
53
  const builder = new ValidationErrorBuilder()
@@ -63,19 +63,20 @@ export class ObjectValidator<S extends Schema> extends AbstractValidator<InferSc
63
63
  }
64
64
 
65
65
  // if we have no value, then we have few possibilities:
66
+ // - we are performing a partial validation, so we ignore
66
67
  // - the (optional) validator provides a valid value
67
68
  // - the validator is optional, so we can simply ignore
68
69
  // - the validator is not optional, so the property is missing
69
70
  if (original === undefined) {
71
+ if (partialValidation) continue
70
72
  try {
71
73
  // try to validate, the validator _might_ be giving us a value
72
74
  const validated = validator.validate(original, options)
73
75
  // put the validated value in the clone, unless optional and undefined
74
- if (! (optional && (validated == undefined))) clone[key] = validated
76
+ if (! (optional && (validated === undefined))) clone[key] = validated
75
77
  } catch (error) {
76
78
  if (optional) continue // original was undefined, so we can skip!
77
79
  builder.record('Required property missing', key)
78
- // builder.record(error, key) // double error!
79
80
  }
80
81
 
81
82
  continue
@@ -85,7 +86,7 @@ export class ObjectValidator<S extends Schema> extends AbstractValidator<InferSc
85
86
  try {
86
87
  const validated = validator.validate(original, options)
87
88
  // put the validated value in the clone, unless optional and undefined
88
- if (! (optional && (validated == undefined))) clone[key] = validated
89
+ if (! (optional && (validated === undefined))) clone[key] = validated
89
90
  } catch (error) {
90
91
  builder.record(error, key)
91
92
  }
@@ -1,4 +1,4 @@
1
- import { AbstractValidator, defaultValidationOptions } from '../types'
1
+ import { AbstractValidator } from '../types'
2
2
  import { getValidator } from '../utilities'
3
3
 
4
4
  import type { InferInput, InferValidation, Validation, ValidationOptions, Validator } from '../types'
@@ -27,7 +27,7 @@ export class OptionalValidator<
27
27
  }
28
28
 
29
29
  try {
30
- this.defaultValue = validator.validate(defaultValue, defaultValidationOptions)
30
+ this.defaultValue = validator.validate(defaultValue, {})
31
31
  } catch (cause) {
32
32
  throw new TypeError('Default value does not match validator', { cause })
33
33
  }
@@ -22,7 +22,7 @@ export interface BrandedStringConstraints<B extends string> extends StringConstr
22
22
  /** A `Validator` validating any `string`. */
23
23
  export class AnyStringValidator extends AbstractValidator<string> {
24
24
  validate(value: unknown): string {
25
- assertValidation(typeof value == 'string', 'Value is not a "string"')
25
+ assertValidation(typeof value === 'string', 'Value is not a "string"')
26
26
  return value
27
27
  }
28
28
  }
@@ -55,7 +55,7 @@ export class StringValidator<S extends string = string, I = string> extends Abst
55
55
  }
56
56
 
57
57
  validate(value: unknown): S {
58
- assertValidation(typeof value == 'string', 'Value is not a "string"')
58
+ assertValidation(typeof value === 'string', 'Value is not a "string"')
59
59
 
60
60
  assertValidation(value.length >= this.minLength,
61
61
  `String must have a minimum length of ${this.minLength}`)