justus 0.0.2 → 0.0.6
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/README.md +35 -0
- package/dist/dts-generator.js +14 -14
- package/dist/dts-generator.js.map +1 -1
- package/dist/dts-generator.mjs +2 -0
- package/dist/dts-generator.mjs.map +1 -1
- package/dist/index.js +136 -9
- package/dist/index.js.map +2 -2
- package/dist/index.mjs +112 -6
- package/dist/index.mjs.map +2 -2
- package/index.d.ts +122 -39
- package/package.json +15 -14
- package/src/dts-generator.ts +2 -0
- package/src/errors.ts +3 -3
- package/src/index.ts +44 -8
- package/src/schema.ts +6 -6
- package/src/types.ts +8 -6
- package/src/validators/array.ts +3 -3
- package/src/validators/date.ts +3 -3
- package/src/validators/number.ts +5 -5
- package/src/validators/object.ts +13 -6
- package/src/validators/string.ts +5 -5
- package/src/validators/tuple.ts +1 -1
- package/src/validators/union.ts +3 -3
- package/src/validators/url.ts +141 -0
package/src/index.ts
CHANGED
|
@@ -9,16 +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'
|
|
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'
|
|
22
23
|
|
|
23
24
|
/* ========================================================================== *
|
|
24
25
|
* VALIDATE FUNCTION (our main entry point) *
|
|
@@ -32,7 +33,12 @@ export type ValidateOptions = {
|
|
|
32
33
|
-readonly [ key in keyof ValidationOptions ]?: ValidationOptions[key] | undefined
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Validate a _value_ using the specified `Validation`.
|
|
38
|
+
*
|
|
39
|
+
* By default additional and forbidden properties will _not_ be stripped and
|
|
40
|
+
* reported as an error.
|
|
41
|
+
*/
|
|
36
42
|
export function validate<V extends Validation>(
|
|
37
43
|
validation: V,
|
|
38
44
|
value: any,
|
|
@@ -41,6 +47,36 @@ export function validate<V extends Validation>(
|
|
|
41
47
|
const opts: ValidationOptions = {
|
|
42
48
|
stripAdditionalProperties: false,
|
|
43
49
|
stripForbiddenProperties: false,
|
|
50
|
+
stripOptionalNulls: false,
|
|
51
|
+
...options,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return getValidator(validation).validate(value, opts)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Validate a _value_ using the specified `Validation`, automatically stripping
|
|
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
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function strip<V extends Validation>(
|
|
72
|
+
validation: V,
|
|
73
|
+
value: any,
|
|
74
|
+
options: ValidateOptions = {},
|
|
75
|
+
): InferValidation<V> {
|
|
76
|
+
const opts: ValidationOptions = {
|
|
77
|
+
stripAdditionalProperties: true,
|
|
78
|
+
stripForbiddenProperties: false,
|
|
79
|
+
stripOptionalNulls: true,
|
|
44
80
|
...options,
|
|
45
81
|
}
|
|
46
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
|
|
@@ -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 :
|
package/src/validators/array.ts
CHANGED
|
@@ -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)
|
package/src/validators/date.ts
CHANGED
|
@@ -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
|
|
package/src/validators/number.ts
CHANGED
|
@@ -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
|
|
package/src/validators/object.ts
CHANGED
|
@@ -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 (
|
|
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 (!
|
|
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)
|
package/src/validators/string.ts
CHANGED
|
@@ -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
|
|
package/src/validators/tuple.ts
CHANGED
|
@@ -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>> {
|
package/src/validators/union.ts
CHANGED
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
Validator,
|
|
8
8
|
} from '../types'
|
|
9
9
|
|
|
10
|
-
type UnionArguments = readonly [ Validation, ...Validation[] ]
|
|
10
|
+
export type UnionArguments = readonly [ Validation, ...Validation[] ]
|
|
11
11
|
|
|
12
12
|
/* -------------------------------------------------------------------------- */
|
|
13
13
|
|
|
14
|
-
type InferOneOfValidationType<A extends UnionArguments> =
|
|
14
|
+
export type InferOneOfValidationType<A extends UnionArguments> =
|
|
15
15
|
A extends readonly [ infer First, ...infer Rest ] ?
|
|
16
16
|
First extends Validation ?
|
|
17
17
|
Rest extends UnionArguments ?
|
|
@@ -49,7 +49,7 @@ export function oneOf<A extends UnionArguments>(...args: A): OneOfValidator<A> {
|
|
|
49
49
|
|
|
50
50
|
/* -------------------------------------------------------------------------- */
|
|
51
51
|
|
|
52
|
-
type InferAllOfValidationType<A extends UnionArguments> =
|
|
52
|
+
export type InferAllOfValidationType<A extends UnionArguments> =
|
|
53
53
|
A extends readonly [ infer First, ...infer Rest ] ?
|
|
54
54
|
First extends Validation ?
|
|
55
55
|
Rest extends UnionArguments ?
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { ConstantValidator } from './constant'
|
|
2
|
+
import { ValidationError, ValidationErrorBuilder } from '../errors'
|
|
3
|
+
import { Schema, Validator } from '../types'
|
|
4
|
+
import { makeTupleRestIterable } from './tuple'
|
|
5
|
+
import { ObjectValidator, ValidationOptions } from '..'
|
|
6
|
+
|
|
7
|
+
const KEYS: Exclude<keyof URLConstraints, 'searchParams'>[] = [
|
|
8
|
+
'href',
|
|
9
|
+
'origin',
|
|
10
|
+
'protocol',
|
|
11
|
+
'username',
|
|
12
|
+
'password',
|
|
13
|
+
'host',
|
|
14
|
+
'hostname',
|
|
15
|
+
'port',
|
|
16
|
+
'pathname',
|
|
17
|
+
'search',
|
|
18
|
+
'hash',
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
const OPTIONS: ValidationOptions = {
|
|
22
|
+
stripAdditionalProperties: false,
|
|
23
|
+
stripForbiddenProperties: false,
|
|
24
|
+
stripOptionalNulls: false,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Constraints to validate a `URL` with. */
|
|
28
|
+
export interface URLConstraints {
|
|
29
|
+
/** Constraint to validate the `href` component of the `URL`. */
|
|
30
|
+
href?: string | Validator<string>,
|
|
31
|
+
/** Constraint to validate the `origin` component of the `URL`. */
|
|
32
|
+
origin?: string | Validator<string>,
|
|
33
|
+
/** Constraint to validate the `protocol` component of the `URL`. */
|
|
34
|
+
protocol?: string | Validator<string>,
|
|
35
|
+
/** Constraint to validate the `username` component of the `URL`. */
|
|
36
|
+
username?: string | Validator<string>,
|
|
37
|
+
/** Constraint to validate the `password` component of the `URL`. */
|
|
38
|
+
password?: string | Validator<string>,
|
|
39
|
+
/** Constraint to validate the `host` (`hostname:port`) component of the `URL`. */
|
|
40
|
+
host?: string | Validator<string>,
|
|
41
|
+
/** Constraint to validate the `hostname` component of the `URL`. */
|
|
42
|
+
hostname?: string | Validator<string>,
|
|
43
|
+
/** Constraint to validate the `port` component of the `URL`. */
|
|
44
|
+
port?: string | Validator<string>,
|
|
45
|
+
/** Constraint to validate the `pathname` component of the `URL`. */
|
|
46
|
+
pathname?: string | Validator<string>,
|
|
47
|
+
/** Constraint to validate the `search` component of the `URL` as a string. */
|
|
48
|
+
search?: string | Validator<string>,
|
|
49
|
+
/** Constraint to validate the `hash` component of the `URL`. */
|
|
50
|
+
hash?: string | Validator<string>,
|
|
51
|
+
/**
|
|
52
|
+
* Schema used to validate the `searchParams` component of the `URL`.
|
|
53
|
+
*
|
|
54
|
+
* The `searchParams` will be normalized in a `Record<string, string>`, where
|
|
55
|
+
* only the _first_ value associated with a search parameter will be checked.
|
|
56
|
+
*/
|
|
57
|
+
searchParams?: Schema,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A `Validator` validating URLs and converting them to `URL` instances. */
|
|
61
|
+
export class URLValidator extends Validator<URL> {
|
|
62
|
+
readonly href?: Validator<string>
|
|
63
|
+
readonly origin?: Validator<string>
|
|
64
|
+
readonly protocol?: Validator<string>
|
|
65
|
+
readonly username?: Validator<string>
|
|
66
|
+
readonly password?: Validator<string>
|
|
67
|
+
readonly host?: Validator<string>
|
|
68
|
+
readonly hostname?: Validator<string>
|
|
69
|
+
readonly port?: Validator<string>
|
|
70
|
+
readonly pathname?: Validator<string>
|
|
71
|
+
readonly search?: Validator<string>
|
|
72
|
+
readonly hash?: Validator<string>
|
|
73
|
+
|
|
74
|
+
readonly searchParams?: ObjectValidator<Schema>
|
|
75
|
+
|
|
76
|
+
constructor(constraints: URLConstraints = {}) {
|
|
77
|
+
super()
|
|
78
|
+
|
|
79
|
+
for (const key of KEYS) {
|
|
80
|
+
const constraint = constraints[key]
|
|
81
|
+
if (typeof constraint === 'string') {
|
|
82
|
+
this[key] = new ConstantValidator(constraint)
|
|
83
|
+
} else if (constraint) {
|
|
84
|
+
this[key] = constraint
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (constraints.searchParams) {
|
|
89
|
+
this.searchParams = new ObjectValidator(constraints.searchParams)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
validate(value: unknown): URL {
|
|
94
|
+
let url: URL
|
|
95
|
+
try {
|
|
96
|
+
url = value instanceof URL ? value : new URL(value as any)
|
|
97
|
+
} catch (error) {
|
|
98
|
+
throw new ValidationError('Value could not be converted to a "URL"')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const builder = new ValidationErrorBuilder()
|
|
102
|
+
|
|
103
|
+
for (const key of KEYS) {
|
|
104
|
+
const validator = this[key]
|
|
105
|
+
if (validator) {
|
|
106
|
+
try {
|
|
107
|
+
validator.validate(url[key], OPTIONS)
|
|
108
|
+
} catch (error) {
|
|
109
|
+
builder.record(error, key)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (this.searchParams) {
|
|
115
|
+
const parameters: Record<string, string> = {}
|
|
116
|
+
for (const param of url.searchParams.keys()) {
|
|
117
|
+
parameters[param] = url.searchParams.get(param) as string
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
this.searchParams.validate(parameters, OPTIONS)
|
|
122
|
+
} catch (error) {
|
|
123
|
+
builder.record(error, 'searchParams')
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return builder.assert(url)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const anyURLValidator = new URLValidator()
|
|
132
|
+
|
|
133
|
+
export function _url(): URLValidator
|
|
134
|
+
export function _url(constraints: URLConstraints): URLValidator
|
|
135
|
+
|
|
136
|
+
export function _url(constraints?: URLConstraints): URLValidator {
|
|
137
|
+
return constraints ? new URLValidator(constraints) : anyURLValidator
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Validate URLs and convert them to `URL` instances. */
|
|
141
|
+
export const url = makeTupleRestIterable(_url)
|