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.
- package/dist/dts-generator.cjs +22 -7
- package/dist/dts-generator.cjs.map +1 -1
- package/dist/dts-generator.mjs +22 -7
- package/dist/dts-generator.mjs.map +1 -1
- package/dist/extra/arn.cjs +1 -1
- package/dist/extra/arn.cjs.map +1 -1
- package/dist/extra/arn.mjs +1 -1
- package/dist/extra/arn.mjs.map +1 -1
- package/dist/index.cjs +13 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.mjs +9 -2
- package/dist/index.mjs.map +1 -1
- package/dist/types.cjs +0 -7
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.ts +11 -13
- package/dist/types.mjs +0 -6
- package/dist/types.mjs.map +1 -1
- package/dist/utilities.cjs +1 -0
- package/dist/utilities.cjs.map +1 -1
- package/dist/utilities.mjs +1 -0
- package/dist/utilities.mjs.map +1 -1
- package/dist/validators/bigint.cjs +146 -0
- package/dist/validators/bigint.cjs.map +6 -0
- package/dist/validators/bigint.d.ts +46 -0
- package/dist/validators/bigint.mjs +118 -0
- package/dist/validators/bigint.mjs.map +6 -0
- package/dist/validators/boolean.cjs +1 -1
- package/dist/validators/boolean.cjs.map +1 -1
- package/dist/validators/boolean.mjs +1 -1
- package/dist/validators/boolean.mjs.map +1 -1
- package/dist/validators/constant.cjs +2 -1
- package/dist/validators/constant.cjs.map +1 -1
- package/dist/validators/constant.d.ts +2 -2
- package/dist/validators/constant.mjs +2 -1
- package/dist/validators/constant.mjs.map +1 -1
- package/dist/validators/never.cjs +1 -1
- package/dist/validators/never.cjs.map +1 -1
- package/dist/validators/never.mjs +2 -2
- package/dist/validators/never.mjs.map +1 -1
- package/dist/validators/number.cjs +5 -5
- package/dist/validators/number.cjs.map +1 -1
- package/dist/validators/number.mjs +5 -5
- package/dist/validators/number.mjs.map +1 -1
- package/dist/validators/object.cjs +7 -5
- package/dist/validators/object.cjs.map +1 -1
- package/dist/validators/object.mjs +8 -6
- package/dist/validators/object.mjs.map +1 -1
- package/dist/validators/optional.cjs +1 -1
- package/dist/validators/optional.cjs.map +1 -1
- package/dist/validators/optional.mjs +2 -2
- package/dist/validators/optional.mjs.map +1 -1
- package/dist/validators/string.cjs +2 -2
- package/dist/validators/string.cjs.map +1 -1
- package/dist/validators/string.mjs +2 -2
- package/dist/validators/string.mjs.map +1 -1
- package/package.json +3 -8
- package/src/dts-generator.ts +23 -6
- package/src/extra/arn.ts +1 -1
- package/src/index.ts +20 -2
- package/src/types.ts +11 -16
- package/src/utilities.ts +1 -0
- package/src/validators/bigint.ts +147 -0
- package/src/validators/boolean.ts +1 -1
- package/src/validators/constant.ts +4 -3
- package/src/validators/never.ts +2 -2
- package/src/validators/number.ts +5 -5
- package/src/validators/object.ts +8 -7
- package/src/validators/optional.ts +2 -2
- 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
|
|
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
|
-
|
|
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
|
|
package/src/validators/never.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ValidationError } from '../errors'
|
|
2
|
-
import { AbstractValidator
|
|
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 =
|
|
10
|
+
validate(value: unknown, options: ValidationOptions = {}): never {
|
|
11
11
|
const { stripForbiddenProperties } = options
|
|
12
12
|
|
|
13
13
|
// @ts-expect-error
|
package/src/validators/number.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
package/src/validators/object.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assertValidation, ValidationErrorBuilder } from '../errors'
|
|
2
2
|
import { registry } from '../registry'
|
|
3
|
-
import { AbstractValidator,
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
30
|
+
this.defaultValue = validator.validate(defaultValue, {})
|
|
31
31
|
} catch (cause) {
|
|
32
32
|
throw new TypeError('Default value does not match validator', { cause })
|
|
33
33
|
}
|
package/src/validators/string.ts
CHANGED
|
@@ -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
|
|
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
|
|
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}`)
|