justus 0.0.4 → 0.0.7

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.
package/index.d.ts CHANGED
@@ -33,13 +33,13 @@ export declare class AllOfValidator<A extends UnionArguments> extends Validator<
33
33
  export declare const allowAdditionalProperties: typeof _allowAdditionalProperties & AdditionalProperties<Validator<any>>;
34
34
 
35
35
  /** Internal definition of `allowAdditionalProperties(...)` */
36
- declare function _allowAdditionalProperties(): AdditionalProperties<Validator<any>>;
36
+ export declare function _allowAdditionalProperties(): AdditionalProperties<Validator<any>>;
37
37
 
38
- declare function _allowAdditionalProperties(allow: true): AdditionalProperties<Validator<any>>;
38
+ export declare function _allowAdditionalProperties(allow: true): AdditionalProperties<Validator<any>>;
39
39
 
40
- declare function _allowAdditionalProperties(allow: false): AdditionalProperties<false>;
40
+ export declare function _allowAdditionalProperties(allow: false): AdditionalProperties<false>;
41
41
 
42
- declare function _allowAdditionalProperties<V extends Validation>(validation: V): AdditionalProperties<Validator<InferValidation<V>>>;
42
+ export declare function _allowAdditionalProperties<V extends Validation>(validation: V): AdditionalProperties<Validator<InferValidation<V>>>;
43
43
 
44
44
  /** The `Validator` validating _anything_. */
45
45
  export declare const any: AnyValidator;
@@ -72,12 +72,12 @@ export declare class AnyValidator extends Validator<any> {
72
72
  /** Validate `Array`s. */
73
73
  export declare const array: typeof _array & Iterable<TupleRestParameter<any[]>>;
74
74
 
75
- declare function _array(): Validator<any[]>;
75
+ export declare function _array(): Validator<any[]>;
76
76
 
77
- declare function _array<V extends Validation>(constraints: ArrayConstraints<V>): ArrayValidator<InferValidation<V>>;
77
+ export declare function _array<V extends Validation>(constraints: ArrayConstraints<V>): ArrayValidator<InferValidation<V>>;
78
78
 
79
79
  /** Constraints to validate an `Array` with. */
80
- declare interface ArrayConstraints<V extends Validation> {
80
+ export declare interface ArrayConstraints<V extends Validation> {
81
81
  /** The _maximum_ number of elements a valid `Array`: `value.length <= maxItems` */
82
82
  maxItems?: number;
83
83
  /** The _minimum_ number of elements a valid `Array`: `value.length >= minItems` */
@@ -121,13 +121,13 @@ export declare class BooleanValidator extends Validator<boolean> {
121
121
  }
122
122
 
123
123
  /** Constraints to validate a `number` with extra branding information. */
124
- declare interface BrandedNumberConstraints<B extends string> extends NumberConstraints {
124
+ export declare interface BrandedNumberConstraints<B extends string> extends NumberConstraints {
125
125
  /** The _brand_ of the string (will generate a `__brand_${B}` type property */
126
126
  brand: B;
127
127
  }
128
128
 
129
129
  /** Constraints to validate a `string` with extra branding information. */
130
- declare interface BrandedStringConstraints<B extends string> extends StringConstraints {
130
+ export declare interface BrandedStringConstraints<B extends string> extends StringConstraints {
131
131
  /** The _brand_ of the string (will generate a `__brand_${B}` type property */
132
132
  brand: B;
133
133
  }
@@ -147,7 +147,7 @@ export declare interface CombinedModifier<V extends Validator = Validator> exten
147
147
  readonly: true;
148
148
  }
149
149
 
150
- declare type CombineModifiers<M1 extends Modifier, M2 extends Modifier> = M1 extends ReadonlyModifier ? M2 extends ReadonlyModifier<infer V> ? ReadonlyModifier<V> : M2 extends OptionalModifier<infer V> ? CombinedModifier<V> : never : M1 extends OptionalModifier ? M2 extends ReadonlyModifier<infer V> ? CombinedModifier<V> : M2 extends OptionalModifier<infer V> ? OptionalModifier<V> : never : never;
150
+ export declare type CombineModifiers<M1 extends Modifier, M2 extends Modifier> = M1 extends ReadonlyModifier ? M2 extends ReadonlyModifier<infer V> ? ReadonlyModifier<V> : M2 extends OptionalModifier<infer V> ? CombinedModifier<V> : never : M1 extends OptionalModifier ? M2 extends ReadonlyModifier<infer V> ? CombinedModifier<V> : M2 extends OptionalModifier<infer V> ? OptionalModifier<V> : never : never;
151
151
 
152
152
  /** Validate _constants_. */
153
153
  export declare function constant<T extends string | number | boolean | null>(constant: T): Validator<T>;
@@ -162,12 +162,12 @@ export declare class ConstantValidator<T extends string | number | boolean | nul
162
162
  /** Validate dates and convert them to `Date` instances. */
163
163
  export declare const date: typeof _date & Iterable<TupleRestParameter<Date>>;
164
164
 
165
- declare function _date(): DateValidator;
165
+ export declare function _date(): DateValidator;
166
166
 
167
- declare function _date(constraints: DateConstraints): DateValidator;
167
+ export declare function _date(constraints: DateConstraints): DateValidator;
168
168
 
169
169
  /** Constraints to validate a `Date` with. */
170
- declare interface DateConstraints {
170
+ export declare interface DateConstraints {
171
171
  /** The format for dates, an _ISO date_ (RFC 3339) or a numeric timestamp */
172
172
  format?: 'iso' | 'timestamp';
173
173
  /** The earliest value a date can have */
@@ -192,37 +192,37 @@ export declare class DateValidator extends Validator<Date> {
192
192
  */
193
193
  export declare function getValidator(validation?: Validation): Validator;
194
194
 
195
- declare type InferAllOfValidationType<A extends UnionArguments> = A extends readonly [infer First, ...infer Rest] ? First extends Validation ? Rest extends UnionArguments ? InferValidation<First> & InferOneOfValidationType<Rest> : InferValidation<First> : never : never;
195
+ export declare type InferAllOfValidationType<A extends UnionArguments> = A extends readonly [infer First, ...infer Rest] ? First extends Validation ? Rest extends UnionArguments ? InferValidation<First> & InferOneOfValidationType<Rest> : InferValidation<First> : never : never;
196
196
 
197
197
  /** Infer the type of _read only_ **and** _optional_ `Schema` properties */
198
- declare type InferCombinedModifiers<S extends Schema> = {
198
+ export declare type InferCombinedModifiers<S extends Schema> = {
199
199
  readonly [key in keyof S as key extends string ? S[key] extends CombinedModifier ? key : never : never]?: S[key] extends CombinedModifier<infer V> ? InferValidation<V> : never;
200
200
  };
201
201
 
202
202
  /** Ensure that we properly type `never` properties */
203
- declare type InferNever<S extends Schema> = {
203
+ export declare type InferNever<S extends Schema> = {
204
204
  [key in keyof S as key extends string ? S[key] extends typeof never ? key : never : never]: never;
205
205
  };
206
206
 
207
- declare type InferOneOfValidationType<A extends UnionArguments> = A extends readonly [infer First, ...infer Rest] ? First extends Validation ? Rest extends UnionArguments ? InferValidation<First> | InferOneOfValidationType<Rest> : InferValidation<First> : never : never;
207
+ export declare type InferOneOfValidationType<A extends UnionArguments> = A extends readonly [infer First, ...infer Rest] ? First extends Validation ? Rest extends UnionArguments ? InferValidation<First> | InferOneOfValidationType<Rest> : InferValidation<First> : never : never;
208
208
 
209
209
  /** Infer the type of _optional_ `Schema` properties */
210
- declare type InferOptionalModifiers<S extends Schema> = {
210
+ export declare type InferOptionalModifiers<S extends Schema> = {
211
211
  [key in keyof S as key extends string ? S[key] extends ReadonlyModifier<Validator> ? never : S[key] extends OptionalModifier<Validator> ? key : never : never]?: S[key] extends OptionalModifier<infer V> ? InferValidation<V> : never;
212
212
  };
213
213
 
214
214
  /** Infer the type of _read only_ `Schema` properties */
215
- declare type InferReadonlyModifiers<S extends Schema> = {
215
+ export declare type InferReadonlyModifiers<S extends Schema> = {
216
216
  readonly [key in keyof S as key extends string ? S[key] extends OptionalModifier<Validator> ? never : S[key] extends ReadonlyModifier<Validator> ? key : never : never]: S[key] extends ReadonlyModifier<infer V> ? InferValidation<V> : never;
217
217
  };
218
218
 
219
219
  /** Infer the type of keys associated with `Validation`s */
220
- declare type InferRequired<S extends Schema> = {
220
+ export declare type InferRequired<S extends Schema> = {
221
221
  [key in keyof S as key extends string ? S[key] extends Validation ? key : never : never]: S[key] extends Validation ? InferValidation<S[key]> : never;
222
222
  };
223
223
 
224
224
  /** Infer the type validated by a `Schema` */
225
- export declare type InferSchema<S extends Schema> = InferReadonlyModifiers<S> & InferOptionalModifiers<S> & InferCombinedModifiers<S> & (S extends AdditionalProperties<Validator<infer V>> ? Record<string, V> & InferNever<S> & InferRequired<S> : InferRequired<S>);
225
+ export declare type InferSchema<S extends Schema> = InferReadonlyModifiers<S> & InferOptionalModifiers<S> & InferCombinedModifiers<S> & (S extends AdditionalProperties<Validator<infer V>> ? Record<string, V | undefined> & InferNever<S> & InferRequired<S> : InferRequired<S>);
226
226
 
227
227
  /**
228
228
  * Infer the type returned by a `TupleValidator` when validating an array.
@@ -254,7 +254,7 @@ export declare type InferValidation<V> = V extends Validation ? V extends {
254
254
  } ? A0 extends [] ? R0 : A1 extends [] ? R1 : A2 extends [] ? R2 : A3 extends [] ? R3 : A4 extends [] ? R4 : A5 extends [] ? R5 : A6 extends [] ? R6 : A7 extends [] ? R7 : A8 extends [] ? R8 : A9 extends [] ? R9 : never : V extends Validator<infer T> ? T : V extends Tuple ? InferTuple<V> : V extends Schema ? InferSchema<V> : V extends boolean ? V : V extends number ? V : V extends string ? V : V extends null ? V : never : never;
255
255
 
256
256
  /** Infer the type validated by a `Validation` or `TupleRestParameter` */
257
- declare type InferValidationOrTupleRest<T> = T extends TupleRestParameter<infer X> ? X : T extends Validation ? InferValidation<T> : never;
257
+ export declare type InferValidationOrTupleRest<T> = T extends TupleRestParameter<infer X> ? X : T extends Validation ? InferValidation<T> : never;
258
258
 
259
259
  /** Type guard for `Modifier` instances */
260
260
  export declare function isModifier(what: any): what is Modifier<any>;
@@ -277,16 +277,16 @@ export declare const never: unique symbol;
277
277
  /** Validate `number`s. */
278
278
  export declare const number: typeof _number & Iterable<TupleRestParameter<number>>;
279
279
 
280
- declare function _number(): Validator<number>;
280
+ export declare function _number(): Validator<number>;
281
281
 
282
- declare function _number(constraints?: NumberConstraints): NumberValidator<number>;
282
+ export declare function _number(constraints?: NumberConstraints): NumberValidator<number>;
283
283
 
284
- declare function _number<N extends number>(constraints?: NumberConstraints): NumberValidator<N>;
284
+ export declare function _number<N extends number>(constraints?: NumberConstraints): NumberValidator<N>;
285
285
 
286
- declare function _number<B extends string>(constraints: BrandedNumberConstraints<B>): NumberValidator<number & Branding<B>>;
286
+ export declare function _number<B extends string>(constraints: BrandedNumberConstraints<B>): NumberValidator<number & Branding<B>>;
287
287
 
288
288
  /** Constraints to validate a `number` with. */
289
- declare interface NumberConstraints {
289
+ export declare interface NumberConstraints {
290
290
  /** The value for which a `number` must be multiple of for it to be valid */
291
291
  multipleOf?: number;
292
292
  /** The _inclusive_ maximum value for a valid `number`: `value <= maximum` */
@@ -318,13 +318,13 @@ export declare class NumberValidator<N extends number = number> extends Validato
318
318
  /** Validate `object`s. */
319
319
  export declare const object: typeof _object & Iterable<TupleRestParameter<Record<string, any>>>;
320
320
 
321
- declare function _object(): Validator<Record<string, any>>;
321
+ export declare function _object(): Validator<Record<string, any>>;
322
322
 
323
- declare function _object<S extends Schema>(schema: S): S & {
323
+ export declare function _object<S extends Schema>(schema: S): S & {
324
324
  [Symbol.iterator](): Generator<TupleRestParameter<InferSchema<S>>>;
325
325
  };
326
326
 
327
- declare type ObjectProperty = {
327
+ export declare type ObjectProperty = {
328
328
  validator: Validator;
329
329
  readonly?: true;
330
330
  optional?: true;
@@ -403,16 +403,16 @@ export declare const schemaValidator: unique symbol;
403
403
  /** Validate `string`s. */
404
404
  export declare const string: typeof _string & Iterable<TupleRestParameter<string>>;
405
405
 
406
- declare function _string(): Validator<string>;
406
+ export declare function _string(): Validator<string>;
407
407
 
408
- declare function _string(constraints?: StringConstraints): StringValidator<string>;
408
+ export declare function _string(constraints?: StringConstraints): StringValidator<string>;
409
409
 
410
- declare function _string<S extends string>(constraints?: StringConstraints): StringValidator<S>;
410
+ export declare function _string<S extends string>(constraints?: StringConstraints): StringValidator<S>;
411
411
 
412
- declare function _string<B extends string>(constraints: BrandedStringConstraints<B>): StringValidator<string & Branding<B>>;
412
+ export declare function _string<B extends string>(constraints: BrandedStringConstraints<B>): StringValidator<string & Branding<B>>;
413
413
 
414
414
  /** Constraints to validate a `string` with. */
415
- declare interface StringConstraints {
415
+ export declare interface StringConstraints {
416
416
  /** The _maximum_ length of a valid `string`: `value.length <= maxLength` */
417
417
  maxLength?: number;
418
418
  /** The _minimum_ length of a valid `string`: `value.length >= minLength` */
@@ -433,7 +433,17 @@ export declare class StringValidator<S extends string = string> extends Validato
433
433
 
434
434
  /**
435
435
  * Validate a _value_ using the specified `Validation`, automatically stripping
436
- * additional properties (but not forbidden ones).
436
+ * additional properties and optional `null`s (but not forbidden ones).
437
+ *
438
+ * This is equivalent to:
439
+ *
440
+ * ```
441
+ * validate(validation, value, {
442
+ * stripAdditionalProperties: true,
443
+ * stripForbiddenProperties: false,
444
+ * stripOptionalNulls: true,
445
+ * })
446
+ * ```
437
447
  */
438
448
  export declare function strip<V extends Validation>(validation: V, value: any, options?: ValidateOptions): InferValidation<V>;
439
449
 
@@ -445,7 +455,7 @@ export declare type Tuple = readonly (Validation | TupleRestParameter)[];
445
455
  /** Validate _tuples_. */
446
456
  export declare function tuple<T extends Tuple>(tuple: T): Validator<InferTuple<T>>;
447
457
 
448
- declare interface TupleMember {
458
+ export declare interface TupleMember {
449
459
  single: boolean;
450
460
  validator: Validator;
451
461
  }
@@ -475,17 +485,17 @@ export declare class TupleValidator<T extends Tuple> extends Validator<InferTupl
475
485
  validate(value: unknown, options: ValidationOptions): InferTuple<T>;
476
486
  }
477
487
 
478
- declare type UnionArguments = readonly [Validation, ...Validation[]];
488
+ export declare type UnionArguments = readonly [Validation, ...Validation[]];
479
489
 
480
490
  /** Validate URLs and convert them to `URL` instances. */
481
491
  export declare const url: typeof _url & Iterable<TupleRestParameter<URL>>;
482
492
 
483
- declare function _url(): URLValidator;
493
+ export declare function _url(): URLValidator;
484
494
 
485
- declare function _url(constraints: URLConstraints): URLValidator;
495
+ export declare function _url(constraints: URLConstraints): URLValidator;
486
496
 
487
497
  /** Constraints to validate a `URL` with. */
488
- declare interface URLConstraints {
498
+ export declare interface URLConstraints {
489
499
  /** Constraint to validate the `href` component of the `URL`. */
490
500
  href?: string | Validator<string>;
491
501
  /** Constraint to validate the `origin` component of the `URL`. */
@@ -606,7 +616,7 @@ export declare class ValidationErrorBuilder {
606
616
  assert<T>(value: T): T;
607
617
  }
608
618
 
609
- declare type ValidationErrors = {
619
+ export declare type ValidationErrors = {
610
620
  path: (string | number)[];
611
621
  message: string;
612
622
  }[];
@@ -617,6 +627,8 @@ declare type ValidationErrors = {
617
627
  export declare interface ValidationOptions {
618
628
  /** Strip additional, undeclared properties from objects */
619
629
  readonly stripAdditionalProperties: boolean;
630
+ /** Strip `null`s from an object when associated with an optional key */
631
+ readonly stripOptionalNulls: boolean;
620
632
  /** Ignore and strip forbidden (`never`) properties from objects */
621
633
  readonly stripForbiddenProperties: boolean;
622
634
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "justus",
3
- "version": "0.0.4",
3
+ "version": "0.0.7",
4
4
  "description": "A JavaScript validation library, with types!",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -17,28 +17,28 @@
17
17
  "types": "./index.d.ts",
18
18
  "scripts": {
19
19
  "build": "./build.sh",
20
- "dev": "nodemon -e ts -x build.sh -w src -w test -w test-d",
20
+ "dev": "nodemon -e ts -x ./build.sh -w src -w test -w test-d",
21
21
  "lint": "eslint src test test-d",
22
22
  "prepare": "patch -N -p0 -i .nyc.patch || true"
23
23
  },
24
24
  "author": "Juit Developers <developers@juit.com>",
25
25
  "license": "MIT",
26
26
  "devDependencies": {
27
- "@microsoft/api-extractor": "^7.19.4",
27
+ "@microsoft/api-extractor": "^7.20.0",
28
28
  "@types/chai": "^4.3.0",
29
29
  "@types/mocha": "^9.1.0",
30
- "@types/node": "~16.11.24",
31
- "@typescript-eslint/eslint-plugin": "^5.11.0",
32
- "@typescript-eslint/parser": "^5.11.0",
30
+ "@types/node": "~16.11.26",
31
+ "@typescript-eslint/eslint-plugin": "^5.17.0",
32
+ "@typescript-eslint/parser": "^5.17.0",
33
33
  "chai": "^4.3.6",
34
- "esbuild": "^0.14.21",
35
- "eslint": "^8.9.0",
34
+ "esbuild": "^0.14.29",
35
+ "eslint": "^8.12.0",
36
36
  "eslint-config-google": "^0.14.0",
37
- "mocha": "^9.2.0",
37
+ "mocha": "^9.2.2",
38
38
  "nodemon": "^2.0.15",
39
39
  "nyc": "^15.1.0",
40
40
  "tsd": "^0.19.1",
41
- "typescript": "^4.5.5"
41
+ "typescript": "^4.6.3"
42
42
  },
43
43
  "directories": {
44
44
  "test": "test"
@@ -122,6 +122,7 @@ const booleanType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeywor
122
122
  const numberType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
123
123
  const neverType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)
124
124
  const stringType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
125
+ const undefinedType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)
125
126
  const recordType = ts.factory.createMappedTypeNode(
126
127
  undefined, // readonly
127
128
  ts.factory.createTypeParameterDeclaration('key', stringType),
@@ -258,12 +259,15 @@ registerTypeGenerator(ObjectValidator, (validator, references) => {
258
259
  }
259
260
 
260
261
  if (validator.additionalProperties) {
262
+ const propertyType = generateTypeNode(validator.additionalProperties, references)
263
+ const optionalPropertyType = ts.factory.createUnionTypeNode([ propertyType, undefinedType ])
264
+
261
265
  const extra = ts.factory.createMappedTypeNode(
262
266
  undefined, // readonly
263
267
  ts.factory.createTypeParameterDeclaration('key', stringType),
264
268
  undefined, // name type
265
269
  undefined, // question token
266
- generateTypeNode(validator.additionalProperties, references),
270
+ optionalPropertyType, // (type | undefined)
267
271
  undefined) // members
268
272
 
269
273
  if (properties.length == 0) return extra
package/src/errors.ts CHANGED
@@ -1,4 +1,4 @@
1
- type ValidationErrors = { path: (string | number)[], message: string }[]
1
+ export type ValidationErrors = { path: (string | number)[], message: string }[]
2
2
 
3
3
  /** Combine the components of a _path_ into a human readable string */
4
4
  function pathToString(path: (string | number)[]): string {
package/src/index.ts CHANGED
@@ -9,17 +9,17 @@ export * from './types'
9
9
  export * from './utilities'
10
10
 
11
11
  // Validators
12
- export { allOf, oneOf, AllOfValidator, OneOfValidator } from './validators/union'
12
+ export { allOf, oneOf, AllOfValidator, InferAllOfValidationType, InferOneOfValidationType, OneOfValidator, UnionArguments } from './validators/union'
13
13
  export { any, AnyValidator } from './validators/any'
14
- export { array, arrayOf, AnyArrayValidator, ArrayValidator } from './validators/array'
14
+ export { _array, array, arrayOf, AnyArrayValidator, ArrayConstraints, ArrayValidator } from './validators/array'
15
15
  export { boolean, BooleanValidator } from './validators/boolean'
16
16
  export { constant, ConstantValidator } from './validators/constant'
17
- export { date, DateValidator } from './validators/date'
18
- export { number, AnyNumberValidator, NumberValidator } from './validators/number'
19
- export { object, AnyObjectValidator, ObjectValidator } from './validators/object'
20
- export { string, AnyStringValidator, StringValidator } from './validators/string'
21
- export { tuple, TupleValidator } from './validators/tuple'
22
- export { url, URLValidator } from './validators/url'
17
+ export { _date, date, DateConstraints, DateValidator } from './validators/date'
18
+ export { _number, number, AnyNumberValidator, BrandedNumberConstraints, NumberConstraints, NumberValidator } from './validators/number'
19
+ export { _object, object, AnyObjectValidator, ObjectProperty, ObjectValidator } from './validators/object'
20
+ export { _string, string, AnyStringValidator, BrandedStringConstraints, StringConstraints, StringValidator } from './validators/string'
21
+ export { tuple, TupleMember, TupleValidator } from './validators/tuple'
22
+ export { _url, url, URLConstraints, URLValidator } from './validators/url'
23
23
 
24
24
  /* ========================================================================== *
25
25
  * VALIDATE FUNCTION (our main entry point) *
@@ -47,6 +47,7 @@ export function validate<V extends Validation>(
47
47
  const opts: ValidationOptions = {
48
48
  stripAdditionalProperties: false,
49
49
  stripForbiddenProperties: false,
50
+ stripOptionalNulls: false,
50
51
  ...options,
51
52
  }
52
53
 
@@ -55,7 +56,17 @@ export function validate<V extends Validation>(
55
56
 
56
57
  /**
57
58
  * Validate a _value_ using the specified `Validation`, automatically stripping
58
- * additional properties (but not forbidden ones).
59
+ * additional properties and optional `null`s (but not forbidden ones).
60
+ *
61
+ * This is equivalent to:
62
+ *
63
+ * ```
64
+ * validate(validation, value, {
65
+ * stripAdditionalProperties: true,
66
+ * stripForbiddenProperties: false,
67
+ * stripOptionalNulls: true,
68
+ * })
69
+ * ```
59
70
  */
60
71
  export function strip<V extends Validation>(
61
72
  validation: V,
@@ -65,6 +76,7 @@ export function strip<V extends Validation>(
65
76
  const opts: ValidationOptions = {
66
77
  stripAdditionalProperties: true,
67
78
  stripForbiddenProperties: false,
79
+ stripOptionalNulls: true,
68
80
  ...options,
69
81
  }
70
82
 
package/src/schema.ts CHANGED
@@ -19,12 +19,12 @@ import {
19
19
  * ========================================================================== */
20
20
 
21
21
  /** Internal definition of `allowAdditionalProperties(...)` */
22
- function _allowAdditionalProperties(): AdditionalProperties<Validator<any>>
23
- function _allowAdditionalProperties(allow: true): AdditionalProperties<Validator<any>>
24
- function _allowAdditionalProperties(allow: false): AdditionalProperties<false>
25
- function _allowAdditionalProperties<V extends Validation>(validation: V): AdditionalProperties<Validator<InferValidation<V>>>
22
+ export function _allowAdditionalProperties(): AdditionalProperties<Validator<any>>
23
+ export function _allowAdditionalProperties(allow: true): AdditionalProperties<Validator<any>>
24
+ export function _allowAdditionalProperties(allow: false): AdditionalProperties<false>
25
+ export function _allowAdditionalProperties<V extends Validation>(validation: V): AdditionalProperties<Validator<InferValidation<V>>>
26
26
 
27
- function _allowAdditionalProperties(options?: Validation | boolean): AdditionalProperties<Validator | false> {
27
+ export function _allowAdditionalProperties(options?: Validation | boolean): AdditionalProperties<Validator | false> {
28
28
  if (options === false) return { [additionalValidator]: false }
29
29
  if (options === true) return { [additionalValidator]: any }
30
30
 
@@ -49,7 +49,7 @@ allowAdditionalProperties[additionalValidator] = any
49
49
  * SCHEMA KEYS MODIFIERS *
50
50
  * ========================================================================== */
51
51
 
52
- type CombineModifiers<M1 extends Modifier, M2 extends Modifier> =
52
+ export type CombineModifiers<M1 extends Modifier, M2 extends Modifier> =
53
53
  M1 extends ReadonlyModifier ?
54
54
  M2 extends ReadonlyModifier<infer V> ? ReadonlyModifier<V> :
55
55
  M2 extends OptionalModifier<infer V> ? CombinedModifier<V> :
package/src/types.ts CHANGED
@@ -27,6 +27,8 @@ export const never = Symbol.for('justus.never')
27
27
  export interface ValidationOptions {
28
28
  /** Strip additional, undeclared properties from objects */
29
29
  readonly stripAdditionalProperties: boolean,
30
+ /** Strip `null`s from an object when associated with an optional key */
31
+ readonly stripOptionalNulls: boolean,
30
32
  /** Ignore and strip forbidden (`never`) properties from objects */
31
33
  readonly stripForbiddenProperties: boolean,
32
34
  }
@@ -115,7 +117,7 @@ export type InferValidation<V> =
115
117
  * ========================================================================== */
116
118
 
117
119
  /** Infer the type validated by a `Validation` or `TupleRestParameter` */
118
- type InferValidationOrTupleRest<T> =
120
+ export type InferValidationOrTupleRest<T> =
119
121
  T extends TupleRestParameter<infer X> ? X :
120
122
  T extends Validation ? InferValidation<T> :
121
123
  never
@@ -229,7 +231,7 @@ export type InferSchema<S extends Schema> =
229
231
  InferOptionalModifiers<S> &
230
232
  InferCombinedModifiers<S> &
231
233
  ( S extends AdditionalProperties<Validator<infer V>> ?
232
- Record<string, V> &
234
+ Record<string, V | undefined> &
233
235
  InferNever<S> &
234
236
  InferRequired<S> :
235
237
  InferRequired<S> )
@@ -237,7 +239,7 @@ export type InferSchema<S extends Schema> =
237
239
  /* -------------------------------------------------------------------------- */
238
240
 
239
241
  /** Infer the type of keys associated with `Validation`s */
240
- type InferRequired<S extends Schema> = {
242
+ export type InferRequired<S extends Schema> = {
241
243
  [ key in keyof S as
242
244
  key extends string ?
243
245
  S[key] extends Validation ? key :
@@ -251,7 +253,7 @@ type InferRequired<S extends Schema> = {
251
253
  /* -------------------------------------------------------------------------- */
252
254
 
253
255
  /** Infer the type of _read only_ `Schema` properties */
254
- type InferReadonlyModifiers<S extends Schema> = {
256
+ export type InferReadonlyModifiers<S extends Schema> = {
255
257
  readonly [ key in keyof S as
256
258
  key extends string ?
257
259
  S[key] extends OptionalModifier<Validator> ? never :
@@ -263,7 +265,7 @@ type InferReadonlyModifiers<S extends Schema> = {
263
265
  }
264
266
 
265
267
  /** Infer the type of _optional_ `Schema` properties */
266
- type InferOptionalModifiers<S extends Schema> = {
268
+ export type InferOptionalModifiers<S extends Schema> = {
267
269
  [ key in keyof S as
268
270
  key extends string ?
269
271
  S[key] extends ReadonlyModifier<Validator> ? never :
@@ -275,7 +277,7 @@ type InferOptionalModifiers<S extends Schema> = {
275
277
  }
276
278
 
277
279
  /** Infer the type of _read only_ **and** _optional_ `Schema` properties */
278
- type InferCombinedModifiers<S extends Schema> = {
280
+ export type InferCombinedModifiers<S extends Schema> = {
279
281
  readonly [ key in keyof S as
280
282
  key extends string ?
281
283
  S[key] extends CombinedModifier ? key :
@@ -288,7 +290,7 @@ type InferCombinedModifiers<S extends Schema> = {
288
290
  /* -------------------------------------------------------------------------- */
289
291
 
290
292
  /** Ensure that we properly type `never` properties */
291
- type InferNever<S extends Schema> =
293
+ export type InferNever<S extends Schema> =
292
294
  { [ key in keyof S as
293
295
  key extends string ?
294
296
  S[key] extends typeof never ? key :
@@ -91,10 +91,10 @@ const anyArrayValidator = new AnyArrayValidator()
91
91
 
92
92
  /* -------------------------------------------------------------------------- */
93
93
 
94
- function _array(): Validator<any[]>
95
- function _array<V extends Validation>(constraints: ArrayConstraints<V>): ArrayValidator<InferValidation<V>>
94
+ export function _array(): Validator<any[]>
95
+ export function _array<V extends Validation>(constraints: ArrayConstraints<V>): ArrayValidator<InferValidation<V>>
96
96
 
97
- function _array(options?: ArrayConstraints<Validation>): Validator<any[]> {
97
+ export function _array(options?: ArrayConstraints<Validation>): Validator<any[]> {
98
98
  if (! options) return anyArrayValidator
99
99
 
100
100
  const items = getValidator(options.items)
@@ -67,10 +67,10 @@ export class DateValidator extends Validator<Date> {
67
67
 
68
68
  const anyDateValidator = new DateValidator()
69
69
 
70
- function _date(): DateValidator
71
- function _date(constraints: DateConstraints): DateValidator
70
+ export function _date(): DateValidator
71
+ export function _date(constraints: DateConstraints): DateValidator
72
72
 
73
- function _date(constraints?: DateConstraints): DateValidator {
73
+ export function _date(constraints?: DateConstraints): DateValidator {
74
74
  return constraints ? new DateValidator(constraints) : anyDateValidator
75
75
  }
76
76
 
@@ -150,12 +150,12 @@ export class NumberValidator<N extends number = number> extends Validator<N> {
150
150
 
151
151
  const anyNumberValidator = new AnyNumberValidator()
152
152
 
153
- function _number(): Validator<number>
154
- function _number(constraints?: NumberConstraints): NumberValidator<number>
155
- function _number<N extends number>(constraints?: NumberConstraints): NumberValidator<N>
156
- function _number<B extends string>(constraints: BrandedNumberConstraints<B>): NumberValidator<number & Branding<B>>
153
+ export function _number(): Validator<number>
154
+ export function _number(constraints?: NumberConstraints): NumberValidator<number>
155
+ export function _number<N extends number>(constraints?: NumberConstraints): NumberValidator<N>
156
+ export function _number<B extends string>(constraints: BrandedNumberConstraints<B>): NumberValidator<number & Branding<B>>
157
157
 
158
- function _number(constraints?: NumberConstraints): Validator<number> {
158
+ export function _number(constraints?: NumberConstraints): Validator<number> {
159
159
  return constraints ? new NumberValidator(constraints) : anyNumberValidator
160
160
  }
161
161
 
@@ -19,7 +19,7 @@ import { makeTupleRestIterable } from './tuple'
19
19
  * OBJECT VALIDATOR *
20
20
  * ========================================================================== */
21
21
 
22
- type ObjectProperty = {
22
+ export type ObjectProperty = {
23
23
  validator: Validator,
24
24
  readonly?: true,
25
25
  optional?: true,
@@ -70,6 +70,8 @@ export class ObjectValidator<S extends Schema> extends Validator<InferSchema<S>>
70
70
  assertValidation(typeof value === 'object', 'Value is not an "object"')
71
71
  assertValidation(value !== null, 'Value is "null"')
72
72
 
73
+ const { stripAdditionalProperties, stripForbiddenProperties, stripOptionalNulls } = options
74
+
73
75
  const record: { [ k in string | number | symbol ]?: unknown } = value
74
76
  const builder = new ValidationErrorBuilder()
75
77
  const clone: Record<string, any> = {}
@@ -80,7 +82,7 @@ export class ObjectValidator<S extends Schema> extends Validator<InferSchema<S>>
80
82
  // no validator? this is "never" (forbidden)
81
83
  if (! validator) {
82
84
  if (record[key] === undefined) continue
83
- if (options.stripForbiddenProperties) continue
85
+ if (stripForbiddenProperties) continue
84
86
  builder.record('Forbidden property', key)
85
87
  continue
86
88
  }
@@ -91,6 +93,11 @@ export class ObjectValidator<S extends Schema> extends Validator<InferSchema<S>>
91
93
  continue
92
94
  }
93
95
 
96
+ // strip any optional "null" value if told to do so
97
+ if (stripOptionalNulls && optional && (record[key] === null)) {
98
+ continue
99
+ }
100
+
94
101
  // all the rest gets validated normally
95
102
  try {
96
103
  clone[key] = validator.validate(record[key], options)
@@ -111,7 +118,7 @@ export class ObjectValidator<S extends Schema> extends Validator<InferSchema<S>>
111
118
  builder.record(error, key)
112
119
  }
113
120
  })
114
- } else if (! options.stripAdditionalProperties) {
121
+ } else if (! stripAdditionalProperties) {
115
122
  additionalKeys.forEach((key) => {
116
123
  if (record[key] !== undefined) builder.record('Unknown property', key)
117
124
  })
@@ -123,11 +130,11 @@ export class ObjectValidator<S extends Schema> extends Validator<InferSchema<S>>
123
130
 
124
131
  const anyObjectValidator = new AnyObjectValidator()
125
132
 
126
- function _object(): Validator<Record<string, any>>
127
- function _object<S extends Schema>(schema: S): S & {
133
+ export function _object(): Validator<Record<string, any>>
134
+ export function _object<S extends Schema>(schema: S): S & {
128
135
  [Symbol.iterator](): Generator<TupleRestParameter<InferSchema<S>>>
129
136
  }
130
- function _object(schema?: Schema): Validator<Record<string, any>> | Schema {
137
+ export function _object(schema?: Schema): Validator<Record<string, any>> | Schema {
131
138
  if (! schema) return anyObjectValidator
132
139
 
133
140
  const validator = new ObjectValidator(schema)
@@ -71,12 +71,12 @@ export class StringValidator<S extends string = string> extends Validator<S> {
71
71
 
72
72
  const anyStringValidator = new AnyStringValidator()
73
73
 
74
- function _string(): Validator<string>
75
- function _string(constraints?: StringConstraints): StringValidator<string>
76
- function _string<S extends string>(constraints?: StringConstraints): StringValidator<S>
77
- function _string<B extends string>(constraints: BrandedStringConstraints<B>): StringValidator<string & Branding<B>>
74
+ export function _string(): Validator<string>
75
+ export function _string(constraints?: StringConstraints): StringValidator<string>
76
+ export function _string<S extends string>(constraints?: StringConstraints): StringValidator<S>
77
+ export function _string<B extends string>(constraints: BrandedStringConstraints<B>): StringValidator<string & Branding<B>>
78
78
 
79
- function _string(constraints?: StringConstraints): Validator<string> {
79
+ export function _string(constraints?: StringConstraints): Validator<string> {
80
80
  return constraints ? new StringValidator(constraints) : anyStringValidator
81
81
  }
82
82
 
@@ -4,7 +4,7 @@ import { assertValidation, ValidationError } from '../errors'
4
4
  import { getValidator } from '../utilities'
5
5
  import { nullValidator } from './constant'
6
6
 
7
- interface TupleMember { single: boolean, validator: Validator }
7
+ export interface TupleMember { single: boolean, validator: Validator }
8
8
 
9
9
  /** A `Validator` for _tuples_. */
10
10
  export class TupleValidator<T extends Tuple> extends Validator<InferTuple<T>> {