justus 0.0.6 → 0.1.0
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/NOTICE.md +1 -1
- package/README.md +13 -6
- package/dist/dts-generator.js +67 -14
- package/dist/dts-generator.js.map +2 -2
- package/dist/dts-generator.mjs +69 -15
- package/dist/dts-generator.mjs.map +2 -2
- package/dist/index.js +169 -151
- package/dist/index.js.map +3 -3
- package/dist/index.mjs +163 -150
- package/dist/index.mjs.map +3 -3
- package/dts-generator.d.ts +3 -3
- package/index.d.ts +75 -134
- package/package.json +14 -14
- package/src/dts-generator.ts +44 -18
- package/src/index.ts +3 -1
- package/src/schema.ts +1 -72
- package/src/types.ts +53 -140
- package/src/utilities.ts +5 -11
- package/src/validators/any.ts +2 -2
- package/src/validators/array.ts +7 -15
- package/src/validators/boolean.ts +2 -2
- package/src/validators/constant.ts +2 -2
- package/src/validators/date.ts +5 -11
- package/src/validators/never.ts +18 -0
- package/src/validators/number.ts +8 -12
- package/src/validators/object.ts +15 -48
- package/src/validators/optional.ts +30 -0
- package/src/validators/string.ts +8 -13
- package/src/validators/tuple.ts +2 -12
- package/src/validators/union.ts +3 -2
- package/src/validators/url.ts +5 -9
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ValidationError } from '../errors'
|
|
2
|
+
import { ValidationOptions, AbstractValidator } from '../types'
|
|
3
|
+
|
|
4
|
+
/** A `Validator` validating _nothing_. */
|
|
5
|
+
export class NeverValidator extends AbstractValidator<never> {
|
|
6
|
+
optional: true = true
|
|
7
|
+
|
|
8
|
+
validate(value: unknown, options: ValidationOptions): never {
|
|
9
|
+
const { stripForbiddenProperties } = options
|
|
10
|
+
|
|
11
|
+
// @ts-expect-error
|
|
12
|
+
if (stripForbiddenProperties || (value === undefined)) return
|
|
13
|
+
throw new ValidationError('Forbidden property')
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The `Validator` validating _nothing_. */
|
|
18
|
+
export const never = new NeverValidator()
|
package/src/validators/number.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Branding, Validator } from '../types'
|
|
1
|
+
import { Branding, Validator, AbstractValidator, makeValidatorFactory } from '../types'
|
|
2
2
|
import { assertSchema, assertValidation } from '../errors'
|
|
3
|
-
import { makeTupleRestIterable } from './tuple'
|
|
4
3
|
import { ValidationError } from '..'
|
|
5
4
|
|
|
6
5
|
/* ========================================================================== */
|
|
@@ -42,7 +41,7 @@ export interface BrandedNumberConstraints<B extends string> extends NumberConstr
|
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
/** A `Validator` validating any `number`. */
|
|
45
|
-
export class AnyNumberValidator extends
|
|
44
|
+
export class AnyNumberValidator extends AbstractValidator<number> {
|
|
46
45
|
validate(value: unknown): number {
|
|
47
46
|
assertValidation(typeof value == 'number', 'Value is not a "number"')
|
|
48
47
|
assertValidation(! isNaN(value), 'Number is "NaN"')
|
|
@@ -51,7 +50,7 @@ export class AnyNumberValidator extends Validator<number> {
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
/** A `Validator` validating `number`s with constaints. */
|
|
54
|
-
export class NumberValidator<N extends number = number> extends
|
|
53
|
+
export class NumberValidator<N extends number = number> extends AbstractValidator<N> {
|
|
55
54
|
#isMultipleOf?: ((value: number) => boolean)
|
|
56
55
|
|
|
57
56
|
readonly allowNaN: boolean
|
|
@@ -148,16 +147,13 @@ export class NumberValidator<N extends number = number> extends Validator<N> {
|
|
|
148
147
|
}
|
|
149
148
|
}
|
|
150
149
|
|
|
151
|
-
const anyNumberValidator = new AnyNumberValidator()
|
|
152
150
|
|
|
153
|
-
export function _number():
|
|
154
|
-
export function _number(constraints
|
|
155
|
-
export function _number<N extends number>(constraints?: NumberConstraints): NumberValidator<N>
|
|
151
|
+
export function _number(constraints: NumberConstraints): NumberValidator<number>
|
|
152
|
+
export function _number<N extends number>(constraints: NumberConstraints): NumberValidator<N>
|
|
156
153
|
export function _number<B extends string>(constraints: BrandedNumberConstraints<B>): NumberValidator<number & Branding<B>>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return constraints ? new NumberValidator(constraints) : anyNumberValidator
|
|
154
|
+
export function _number(constraints: NumberConstraints): Validator<number> {
|
|
155
|
+
return new NumberValidator(constraints)
|
|
160
156
|
}
|
|
161
157
|
|
|
162
158
|
/** Validate `number`s. */
|
|
163
|
-
export const number =
|
|
159
|
+
export const number = makeValidatorFactory(new AnyNumberValidator(), _number)
|
package/src/validators/object.ts
CHANGED
|
@@ -4,29 +4,21 @@ import {
|
|
|
4
4
|
TupleRestParameter,
|
|
5
5
|
ValidationOptions,
|
|
6
6
|
Validator,
|
|
7
|
+
AbstractValidator,
|
|
7
8
|
additionalValidator,
|
|
8
|
-
modifierValidator,
|
|
9
|
-
never,
|
|
10
9
|
restValidator,
|
|
11
10
|
schemaValidator,
|
|
11
|
+
makeValidatorFactory,
|
|
12
12
|
} from '../types'
|
|
13
13
|
import { assertValidation, ValidationErrorBuilder } from '../errors'
|
|
14
14
|
import { getValidator } from '../utilities'
|
|
15
|
-
import { isModifier } from '../schema'
|
|
16
|
-
import { makeTupleRestIterable } from './tuple'
|
|
17
15
|
|
|
18
16
|
/* ========================================================================== *
|
|
19
17
|
* OBJECT VALIDATOR *
|
|
20
18
|
* ========================================================================== */
|
|
21
19
|
|
|
22
|
-
export type ObjectProperty = {
|
|
23
|
-
validator: Validator,
|
|
24
|
-
readonly?: true,
|
|
25
|
-
optional?: true,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
20
|
/** A `Validator` validating any `object`. */
|
|
29
|
-
export class AnyObjectValidator extends
|
|
21
|
+
export class AnyObjectValidator extends AbstractValidator<Record<string, any>> {
|
|
30
22
|
validate(value: unknown): Record<string, any> {
|
|
31
23
|
assertValidation(typeof value == 'object', 'Value is not an "object"')
|
|
32
24
|
assertValidation(value !== null, 'Value is "null"')
|
|
@@ -35,10 +27,10 @@ export class AnyObjectValidator extends Validator<Record<string, any>> {
|
|
|
35
27
|
}
|
|
36
28
|
|
|
37
29
|
/** A `Validator` validating `object`s according to a `Schema`. */
|
|
38
|
-
export class ObjectValidator<S extends Schema> extends
|
|
30
|
+
export class ObjectValidator<S extends Schema> extends AbstractValidator<InferSchema<S>> {
|
|
39
31
|
readonly schema: Readonly<S>
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
validators = new Map<string, Validator>()
|
|
42
34
|
additionalProperties?: Validator
|
|
43
35
|
|
|
44
36
|
constructor(schema: S) {
|
|
@@ -48,19 +40,7 @@ export class ObjectValidator<S extends Schema> extends Validator<InferSchema<S>>
|
|
|
48
40
|
if (additional) this.additionalProperties = getValidator(additional)
|
|
49
41
|
|
|
50
42
|
for (const key of Object.keys(properties)) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (definition === never) {
|
|
54
|
-
this.properties.set(key, undefined)
|
|
55
|
-
} else if (isModifier(definition)) {
|
|
56
|
-
this.properties.set(key, {
|
|
57
|
-
validator: definition[modifierValidator],
|
|
58
|
-
readonly: definition.readonly,
|
|
59
|
-
optional: definition.optional,
|
|
60
|
-
})
|
|
61
|
-
} else {
|
|
62
|
-
this.properties.set(key, { validator: getValidator(definition) })
|
|
63
|
-
}
|
|
43
|
+
this.validators.set(key, getValidator(properties[key]))
|
|
64
44
|
}
|
|
65
45
|
|
|
66
46
|
this.schema = schema
|
|
@@ -70,22 +50,14 @@ export class ObjectValidator<S extends Schema> extends Validator<InferSchema<S>>
|
|
|
70
50
|
assertValidation(typeof value === 'object', 'Value is not an "object"')
|
|
71
51
|
assertValidation(value !== null, 'Value is "null"')
|
|
72
52
|
|
|
73
|
-
const { stripAdditionalProperties,
|
|
53
|
+
const { stripAdditionalProperties, stripOptionalNulls } = options
|
|
74
54
|
|
|
75
55
|
const record: { [ k in string | number | symbol ]?: unknown } = value
|
|
76
56
|
const builder = new ValidationErrorBuilder()
|
|
77
57
|
const clone: Record<string, any> = {}
|
|
78
58
|
|
|
79
|
-
for (const [ key,
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
// no validator? this is "never" (forbidden)
|
|
83
|
-
if (! validator) {
|
|
84
|
-
if (record[key] === undefined) continue
|
|
85
|
-
if (stripForbiddenProperties) continue
|
|
86
|
-
builder.record('Forbidden property', key)
|
|
87
|
-
continue
|
|
88
|
-
}
|
|
59
|
+
for (const [ key, validator ] of this.validators.entries()) {
|
|
60
|
+
const optional = !! validator.optional
|
|
89
61
|
|
|
90
62
|
// no value? might be optional, but definitely not validated
|
|
91
63
|
if (record[key] === undefined) {
|
|
@@ -100,13 +72,14 @@ export class ObjectValidator<S extends Schema> extends Validator<InferSchema<S>>
|
|
|
100
72
|
|
|
101
73
|
// all the rest gets validated normally
|
|
102
74
|
try {
|
|
103
|
-
|
|
75
|
+
const value = validator.validate(record[key], options)
|
|
76
|
+
if (! (optional && (value == undefined))) clone[key] = value
|
|
104
77
|
} catch (error) {
|
|
105
78
|
builder.record(error, key)
|
|
106
79
|
}
|
|
107
80
|
}
|
|
108
81
|
|
|
109
|
-
const additionalKeys = Object.keys(record).filter((k) => !this.
|
|
82
|
+
const additionalKeys = Object.keys(record).filter((k) => !this.validators.has(k))
|
|
110
83
|
const additional = this.additionalProperties
|
|
111
84
|
|
|
112
85
|
if (additional) {
|
|
@@ -128,15 +101,9 @@ export class ObjectValidator<S extends Schema> extends Validator<InferSchema<S>>
|
|
|
128
101
|
}
|
|
129
102
|
}
|
|
130
103
|
|
|
131
|
-
const anyObjectValidator = new AnyObjectValidator()
|
|
132
|
-
|
|
133
|
-
export function _object(): Validator<Record<string, any>>
|
|
134
104
|
export function _object<S extends Schema>(schema: S): S & {
|
|
135
105
|
[Symbol.iterator](): Generator<TupleRestParameter<InferSchema<S>>>
|
|
136
|
-
}
|
|
137
|
-
export function _object(schema?: Schema): Validator<Record<string, any>> | Schema {
|
|
138
|
-
if (! schema) return anyObjectValidator
|
|
139
|
-
|
|
106
|
+
} {
|
|
140
107
|
const validator = new ObjectValidator(schema)
|
|
141
108
|
function* iterator(): Generator<TupleRestParameter> {
|
|
142
109
|
yield { [restValidator]: validator }
|
|
@@ -145,8 +112,8 @@ export function _object(schema?: Schema): Validator<Record<string, any>> | Schem
|
|
|
145
112
|
return Object.defineProperties(schema, {
|
|
146
113
|
[schemaValidator]: { value: validator, enumerable: false },
|
|
147
114
|
[Symbol.iterator]: { value: iterator, enumerable: false },
|
|
148
|
-
})
|
|
115
|
+
}) as any
|
|
149
116
|
}
|
|
150
117
|
|
|
151
118
|
/** Validate `object`s. */
|
|
152
|
-
export const object =
|
|
119
|
+
export const object = makeValidatorFactory(new AnyObjectValidator(), _object)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AbstractValidator, Validator, ValidationOptions, Validation, InferValidation } from '../types'
|
|
2
|
+
import { getValidator } from '../utilities'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A `Validator` for _optional_ properties (that is `type | undefined`).
|
|
6
|
+
*/
|
|
7
|
+
export class OptionalValidator<T = any> extends AbstractValidator<T | undefined> {
|
|
8
|
+
validator: Validator<T>
|
|
9
|
+
optional: true = true
|
|
10
|
+
|
|
11
|
+
constructor(validator: Validator<T>) {
|
|
12
|
+
super()
|
|
13
|
+
this.validator = validator
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
validate(value: unknown, options: ValidationOptions): T | undefined {
|
|
17
|
+
if (value === undefined) return value
|
|
18
|
+
return this.validator.validate(value, options)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Ensure that the property is marked as _optional_ in the `Schema`.
|
|
24
|
+
*
|
|
25
|
+
* @param validation - A `Validation` to be marked as _optional_.
|
|
26
|
+
*/
|
|
27
|
+
export function optional<V extends Validation>(validation: V): OptionalValidator<InferValidation<V>> {
|
|
28
|
+
const validator = getValidator(validation)
|
|
29
|
+
return new OptionalValidator(validator)
|
|
30
|
+
}
|
package/src/validators/string.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Branding, Validator } from '../types'
|
|
1
|
+
import { Branding, Validator, AbstractValidator, makeValidatorFactory } from '../types'
|
|
2
2
|
import { assertValidation, assertSchema } from '../errors'
|
|
3
|
-
import { makeTupleRestIterable } from './tuple'
|
|
4
3
|
|
|
5
4
|
/** Constraints to validate a `string` with. */
|
|
6
5
|
export interface StringConstraints {
|
|
@@ -19,7 +18,7 @@ export interface BrandedStringConstraints<B extends string> extends StringConstr
|
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
/** A `Validator` validating any `string`. */
|
|
22
|
-
export class AnyStringValidator extends
|
|
21
|
+
export class AnyStringValidator extends AbstractValidator<string> {
|
|
23
22
|
validate(value: unknown): string {
|
|
24
23
|
assertValidation(typeof value == 'string', 'Value is not a "string"')
|
|
25
24
|
return value
|
|
@@ -27,7 +26,7 @@ export class AnyStringValidator extends Validator<string> {
|
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
/** A `Validator` validating `string`s with constraints. */
|
|
30
|
-
export class StringValidator<S extends string = string> extends
|
|
29
|
+
export class StringValidator<S extends string = string> extends AbstractValidator<S> {
|
|
31
30
|
readonly maxLength: number
|
|
32
31
|
readonly minLength: number
|
|
33
32
|
readonly pattern?: RegExp
|
|
@@ -69,16 +68,12 @@ export class StringValidator<S extends string = string> extends Validator<S> {
|
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
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>
|
|
71
|
+
export function _string(constraints: StringConstraints): StringValidator<string>
|
|
72
|
+
export function _string<S extends string>(constraints: StringConstraints): StringValidator<S>
|
|
77
73
|
export function _string<B extends string>(constraints: BrandedStringConstraints<B>): StringValidator<string & Branding<B>>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return constraints ? new StringValidator(constraints) : anyStringValidator
|
|
74
|
+
export function _string(constraints: StringConstraints): Validator<string> {
|
|
75
|
+
return new StringValidator(constraints)
|
|
81
76
|
}
|
|
82
77
|
|
|
83
78
|
/** Validate `string`s. */
|
|
84
|
-
export const string =
|
|
79
|
+
export const string = makeValidatorFactory(new AnyStringValidator(), _string)
|
package/src/validators/tuple.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Tuple, InferTuple, Validator,
|
|
1
|
+
import { Tuple, InferTuple, Validator, AbstractValidator, restValidator } from '../types'
|
|
2
2
|
import { ValidationOptions } from '../types'
|
|
3
3
|
import { assertValidation, ValidationError } from '../errors'
|
|
4
4
|
import { getValidator } from '../utilities'
|
|
@@ -7,7 +7,7 @@ import { nullValidator } from './constant'
|
|
|
7
7
|
export interface TupleMember { single: boolean, validator: Validator }
|
|
8
8
|
|
|
9
9
|
/** A `Validator` for _tuples_. */
|
|
10
|
-
export class TupleValidator<T extends Tuple> extends
|
|
10
|
+
export class TupleValidator<T extends Tuple> extends AbstractValidator<InferTuple<T>> {
|
|
11
11
|
readonly members: readonly TupleMember[]
|
|
12
12
|
readonly tuple: T
|
|
13
13
|
|
|
@@ -78,13 +78,3 @@ export class TupleValidator<T extends Tuple> extends Validator<InferTuple<T>> {
|
|
|
78
78
|
export function tuple<T extends Tuple>(tuple: T): Validator<InferTuple<T>> {
|
|
79
79
|
return new TupleValidator(tuple)
|
|
80
80
|
}
|
|
81
|
-
|
|
82
|
-
export function makeTupleRestIterable<
|
|
83
|
-
F extends () => Validator,
|
|
84
|
-
>(create: F): F & Iterable<TupleRestParameter<InferValidation<F>>> {
|
|
85
|
-
const validator = create()
|
|
86
|
-
;(<any>create)[Symbol.iterator] = function* (): Generator<TupleRestParameter<InferValidation<F>>> {
|
|
87
|
-
yield { [restValidator]: validator }
|
|
88
|
-
}
|
|
89
|
-
return create as any
|
|
90
|
-
}
|
package/src/validators/union.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
Validation,
|
|
6
6
|
ValidationOptions,
|
|
7
7
|
Validator,
|
|
8
|
+
AbstractValidator,
|
|
8
9
|
} from '../types'
|
|
9
10
|
|
|
10
11
|
export type UnionArguments = readonly [ Validation, ...Validation[] ]
|
|
@@ -21,7 +22,7 @@ export type InferOneOfValidationType<A extends UnionArguments> =
|
|
|
21
22
|
never
|
|
22
23
|
|
|
23
24
|
/** A `Validator` validating a value as _one of_ the specified arguments. */
|
|
24
|
-
export class OneOfValidator<A extends UnionArguments> extends
|
|
25
|
+
export class OneOfValidator<A extends UnionArguments> extends AbstractValidator<InferOneOfValidationType<A>> {
|
|
25
26
|
readonly validators: readonly Validator[]
|
|
26
27
|
|
|
27
28
|
constructor(args: A) {
|
|
@@ -59,7 +60,7 @@ export type InferAllOfValidationType<A extends UnionArguments> =
|
|
|
59
60
|
never
|
|
60
61
|
|
|
61
62
|
/** A `Validator` validating a value as _all of_ the specified arguments. */
|
|
62
|
-
export class AllOfValidator<A extends UnionArguments> extends
|
|
63
|
+
export class AllOfValidator<A extends UnionArguments> extends AbstractValidator<InferAllOfValidationType<A>> {
|
|
63
64
|
readonly validators: readonly Validator[]
|
|
64
65
|
|
|
65
66
|
constructor(args: A) {
|
package/src/validators/url.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ConstantValidator } from './constant'
|
|
2
2
|
import { ValidationError, ValidationErrorBuilder } from '../errors'
|
|
3
|
-
import { Schema, Validator } from '../types'
|
|
4
|
-
import { makeTupleRestIterable } from './tuple'
|
|
3
|
+
import { Schema, Validator, AbstractValidator, makeValidatorFactory } from '../types'
|
|
5
4
|
import { ObjectValidator, ValidationOptions } from '..'
|
|
6
5
|
|
|
7
6
|
const KEYS: Exclude<keyof URLConstraints, 'searchParams'>[] = [
|
|
@@ -58,7 +57,7 @@ export interface URLConstraints {
|
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
/** A `Validator` validating URLs and converting them to `URL` instances. */
|
|
61
|
-
export class URLValidator extends
|
|
60
|
+
export class URLValidator extends AbstractValidator<URL> {
|
|
62
61
|
readonly href?: Validator<string>
|
|
63
62
|
readonly origin?: Validator<string>
|
|
64
63
|
readonly protocol?: Validator<string>
|
|
@@ -130,12 +129,9 @@ export class URLValidator extends Validator<URL> {
|
|
|
130
129
|
|
|
131
130
|
const anyURLValidator = new URLValidator()
|
|
132
131
|
|
|
133
|
-
export function _url(): URLValidator
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
export function _url(constraints?: URLConstraints): URLValidator {
|
|
137
|
-
return constraints ? new URLValidator(constraints) : anyURLValidator
|
|
132
|
+
export function _url(constraints: URLConstraints): URLValidator {
|
|
133
|
+
return new URLValidator(constraints)
|
|
138
134
|
}
|
|
139
135
|
|
|
140
136
|
/** Validate URLs and convert them to `URL` instances. */
|
|
141
|
-
export const url =
|
|
137
|
+
export const url = makeValidatorFactory(anyURLValidator, _url)
|