@strictly/define 0.0.7 → 0.0.9
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/.out/index.d.ts +2 -0
- package/.out/index.js +2 -0
- package/.out/transformers/flatteners/flatten_type_to.d.ts +1 -1
- package/.out/transformers/flatteners/flatten_type_to.js +1 -1
- package/.out/tsconfig.tsbuildinfo +1 -1
- package/.out/types/builders.d.ts +3 -3
- package/.out/types/builders.js +4 -6
- package/.out/validation/validator.d.ts +11 -9
- package/.out/validation/validator.js +6 -1
- package/.out/validation/validators/defined_validator.d.ts +1 -1
- package/.out/validation/validators/minimum_string_length_validator.d.ts +1 -1
- package/.out/validation/validators/minimum_string_length_validator.js +1 -1
- package/.out/validation/validators/optional_validator_proxy.d.ts +13 -0
- package/.out/validation/validators/optional_validator_proxy.js +26 -0
- package/.out/validation/validators/regexp_validator.d.ts +29 -0
- package/.out/validation/validators/regexp_validator.js +37 -0
- package/.out/validation/validators/specs/minimum_string_length_validator.tests.d.ts +1 -0
- package/.out/validation/validators/specs/minimum_string_length_validator.tests.js +69 -0
- package/.out/validation/validators/specs/regexp_validator.tests.d.ts +1 -0
- package/.out/validation/validators/specs/regexp_validator.tests.js +98 -0
- package/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-check-types.log +1 -1
- package/dist/index.cjs +113 -33
- package/dist/index.d.cts +58 -15
- package/dist/index.d.ts +58 -15
- package/dist/index.js +109 -33
- package/index.ts +2 -0
- package/package.json +1 -1
- package/transformers/flatteners/flatten_type_to.ts +2 -2
- package/types/builders.ts +11 -14
- package/validation/validator.ts +26 -8
- package/validation/validators/defined_validator.ts +1 -3
- package/validation/validators/minimum_string_length_validator.ts +3 -3
- package/validation/validators/optional_validator_proxy.ts +52 -0
- package/validation/validators/regexp_validator.ts +61 -0
- package/validation/validators/specs/minimum_string_length_validator.tests.ts +76 -0
- package/validation/validators/specs/regexp_validator.tests.ts +108 -0
package/dist/index.d.cts
CHANGED
|
@@ -266,25 +266,27 @@ type InternalFlattenedTypeDefsOfUnionChildren<T extends ValidatingUnionTypeDef,
|
|
|
266
266
|
readonly [K in keyof Unions]: InternalFlattenedTypeDefsOfChildren<Unions[K], SegmentOverride, Path, `${Qualifier}${K}:`, Depth>;
|
|
267
267
|
}[keyof Unions]> : never : never;
|
|
268
268
|
|
|
269
|
+
type Annotations = {
|
|
270
|
+
readonly required: boolean;
|
|
271
|
+
readonly readonly: boolean;
|
|
272
|
+
};
|
|
269
273
|
type FunctionalValidator<V = any, E = any, ValuePath extends string = any, Context = any> = (v: V, valuePath: ValuePath, context: Context) => E | null;
|
|
270
274
|
type AnnotatedValidator<V = any, E = any, ValuePath extends string = any, Context = any> = {
|
|
271
275
|
readonly validate: (v: V, valuePath: ValuePath, context: Context) => E | null;
|
|
272
|
-
readonly annotations: (valuePath: ValuePath, context: Context) =>
|
|
273
|
-
readonly required: boolean;
|
|
274
|
-
readonly readonly: boolean;
|
|
275
|
-
};
|
|
276
|
+
readonly annotations: (valuePath: ValuePath, context: Context) => Annotations;
|
|
276
277
|
};
|
|
277
278
|
type Validator<V = any, E = any, ValuePath extends string = any, Context = any> = FunctionalValidator<V, E, ValuePath, Context> | AnnotatedValidator<V, E, ValuePath, Context>;
|
|
278
279
|
type ErrorOfValidator<V extends Validator> = V extends Validator<infer _V, infer E> ? E : never;
|
|
279
280
|
type ValidationError<Type extends string, Data = {}> = Simplify<{
|
|
280
281
|
type: Type;
|
|
281
282
|
} & Data>;
|
|
282
|
-
declare function isFunctionalValidator(v: Validator): v is FunctionalValidator
|
|
283
|
-
declare function isAnnotatedValidator(v: Validator): v is AnnotatedValidator
|
|
283
|
+
declare function isFunctionalValidator<V, E, ValuePath extends string, Context>(v: Validator<V, E, ValuePath, Context>): v is FunctionalValidator<V, E, ValuePath, Context>;
|
|
284
|
+
declare function isAnnotatedValidator<V, E, ValuePath extends string, Context>(v: Validator<V, E, ValuePath, Context>): v is AnnotatedValidator<V, E, ValuePath, Context>;
|
|
284
285
|
declare function validate<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, v: V, valuePath: ValuePath, context: Context): E | null;
|
|
285
|
-
declare function annotations<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, valuePath: ValuePath, context: Context):
|
|
286
|
-
|
|
287
|
-
readonly
|
|
286
|
+
declare function annotations<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, valuePath: ValuePath, context: Context): Annotations;
|
|
287
|
+
declare function mergeAnnotations(a1: Annotations, a2: Annotations): {
|
|
288
|
+
readonly: boolean;
|
|
289
|
+
required: boolean;
|
|
288
290
|
};
|
|
289
291
|
|
|
290
292
|
type ValidatorOfValidatingType<T extends ValidatingTypeDef, ValuePath extends string, Context> = T extends ValidatingTypeDef<infer E> ? Validator<ValueOfTypeDef<ReadonlyOfTypeDef<T>>, E, ValuePath, Context> : never;
|
|
@@ -402,9 +404,8 @@ type ValidatingUnionTypeDefWithError<T extends ValidatingUnionTypeDef, E2> = T e
|
|
|
402
404
|
declare class TypeDefBuilder<T extends ValidatingTypeDef> implements ValidatingType<T> {
|
|
403
405
|
readonly definition: T;
|
|
404
406
|
constructor(definition: T);
|
|
405
|
-
enforce<E2>(rule: Rule<E2, ValueOfType<Type<T>>>): TypeDefBuilder<ValidatingTypeDefWithError<T, E2>>;
|
|
406
|
-
required(): TypeDefBuilder<
|
|
407
|
-
required<RequiredError>(rule: Rule<RequiredError, ValueOfType<typeof this.narrow>>): TypeDefBuilder<ValidatingTypeDefWithError<T, RequiredError>>;
|
|
407
|
+
enforce<E2>(rule: Rule<E2, ValueOfType<Type<T>>> | Validator<ValueOfType<Type<T>>, E2, never, never>): TypeDefBuilder<ValidatingTypeDefWithError<T, E2>>;
|
|
408
|
+
required(): TypeDefBuilder<T>;
|
|
408
409
|
readonly(): TypeDefBuilder<T>;
|
|
409
410
|
get _type(): TypeOfType<Type<T>>;
|
|
410
411
|
get narrow(): ValidatingType<T>;
|
|
@@ -519,7 +520,7 @@ type ValueTypesOfDiscriminatedUnion<U extends UnionTypeDef> = U extends UnionTyp
|
|
|
519
520
|
};
|
|
520
521
|
} : never : never;
|
|
521
522
|
|
|
522
|
-
declare class DefinedValidator<V, E
|
|
523
|
+
declare class DefinedValidator<V, E> implements AnnotatedValidator<V | null | undefined, E, never, never> {
|
|
523
524
|
private readonly error;
|
|
524
525
|
constructor(error: E);
|
|
525
526
|
validate(v: V | null | undefined): E | null;
|
|
@@ -535,7 +536,7 @@ type MinimumStringLengthValidationError = {
|
|
|
535
536
|
receivedLength: number;
|
|
536
537
|
minimumLength: number;
|
|
537
538
|
};
|
|
538
|
-
declare class MinimumStringLengthValidator
|
|
539
|
+
declare class MinimumStringLengthValidator implements AnnotatedValidator<string, MinimumStringLengthValidationError, never, never> {
|
|
539
540
|
private readonly minimumLength;
|
|
540
541
|
constructor(minimumLength: number);
|
|
541
542
|
validate(value: string): MinimumStringLengthValidationError | null;
|
|
@@ -545,8 +546,50 @@ declare class MinimumStringLengthValidator<ValuePath extends string, Context> im
|
|
|
545
546
|
};
|
|
546
547
|
}
|
|
547
548
|
|
|
549
|
+
declare class OptionalValidatorProxy<V, V1 extends V, E, ValuePath extends string, Context> implements AnnotatedValidator<V, E, ValuePath, Context> {
|
|
550
|
+
private readonly proxied;
|
|
551
|
+
private readonly isRequired;
|
|
552
|
+
static createNullable<V, E, ValuePath extends string, Context>(proxied: AnnotatedValidator<NonNullable<V>, E, ValuePath, Context>): OptionalValidatorProxy<V, NonNullable<V>, E, ValuePath, Context>;
|
|
553
|
+
static createNullableOrEmptyString<V extends string | null | undefined, E, ValuePath extends string, Context>(proxied: AnnotatedValidator<NonNullable<V>, E, ValuePath, Context>): OptionalValidatorProxy<V, NonNullable<V>, E, ValuePath, Context>;
|
|
554
|
+
constructor(proxied: AnnotatedValidator<V1, E, ValuePath, Context>, isRequired: (v: V) => v is V1);
|
|
555
|
+
validate(v: V, valuePath: ValuePath, context: Context): E | null;
|
|
556
|
+
annotations(valuePath: ValuePath, context: Context): {
|
|
557
|
+
required: boolean;
|
|
558
|
+
readonly: boolean;
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
declare const RegexpValidationErrorType = "regexp";
|
|
563
|
+
type RegexpValidationError<Intent extends string> = {
|
|
564
|
+
type: typeof RegexpValidationErrorType;
|
|
565
|
+
intent: Intent;
|
|
566
|
+
};
|
|
567
|
+
declare class RegexpValidator<Intent extends string> implements AnnotatedValidator<string, RegexpValidationError<Intent>, never, never> {
|
|
568
|
+
private readonly regexp;
|
|
569
|
+
private readonly intent;
|
|
570
|
+
/**
|
|
571
|
+
* Extremely permissive email validator
|
|
572
|
+
*/
|
|
573
|
+
static readonly email: RegexpValidator<"email">;
|
|
574
|
+
/**
|
|
575
|
+
* Extremely permissive phone number validator
|
|
576
|
+
*/
|
|
577
|
+
static readonly phone: RegexpValidator<"phone">;
|
|
578
|
+
private readonly negate;
|
|
579
|
+
private readonly required;
|
|
580
|
+
constructor(regexp: RegExp, intent: Intent, { negate, required, }?: {
|
|
581
|
+
negate?: boolean;
|
|
582
|
+
required?: boolean;
|
|
583
|
+
});
|
|
584
|
+
validate(value: string): RegexpValidationError<Intent> | null;
|
|
585
|
+
annotations(): {
|
|
586
|
+
required: boolean;
|
|
587
|
+
readonly: boolean;
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
548
591
|
type ValidatorsOfValues<FlattenedValues extends Readonly<Record<string, any>>, TypePathsToValuePaths extends Readonly<Record<keyof FlattenedValues, string>> = Readonly<Record<keyof FlattenedValues, any>>, Context = any> = {
|
|
549
592
|
readonly [K in keyof FlattenedValues]: Validator<FlattenedValues[K], any, TypePathsToValuePaths[K], Context>;
|
|
550
593
|
};
|
|
551
594
|
|
|
552
|
-
export { type Accessor, type AnnotatedValidator, type AnyValueType, DefinedValidator, type ErrorOfValidator, type FlattenedAccessorsOfType, type FlattenedTypesOfType, type FlattenedValuesOfType, type FunctionalValidator, type InternalJsonPathsOf, type IsStrictUnion, type ListTypeDef, type LiteralTypeDef, type Mapper, type MinimumStringLengthValidationError, MinimumStringLengthValidationErrorType, MinimumStringLengthValidator, type MobxObservable, type MobxValueOfType, type NonMobxObservable, type ObjectFieldKey, type ObjectTypeDef, type ObjectTypeDefFields, type PathsOfType, type ReadonlyOfTypeDef, type ReadonlyTypeOfType, type RecordKeyType, type RecordTypeDef, type Setter, type StrictListTypeDef, type StrictLiteralTypeDef, type StrictObjectTypeDef, type StrictObjectTypeDefFields, type StrictRecordTypeDef, type StrictType, type StrictTypeDef, type StrictUnionTypeDef, type Type, type TypeDef, TypeDefType, type UnionKey, type UnionTypeDef, type ValidationError, type Validator, type ValidatorsOfValues, type ValueOfType, type ValueOfTypeDef, type ValueToTypePathsOfType, type ValueTypesOfDiscriminatedUnion, annotations, booleanType, copy, flattenAccessorsOfType, flattenJsonValueToTypePathsOf, flattenTypesOfType, flattenValidatorsOfValidatingType, flattenValueTo, flattenValuesOfType, getUnionTypeDef, isAnnotatedValidator, isFunctionalValidator, jsonPath, jsonPathPop, list, literal, mobxCopy, nullType, nullable, numberType, object, record, stringType, union, validate, valuePathToTypePath };
|
|
595
|
+
export { type Accessor, type AnnotatedValidator, type Annotations, type AnyValueType, DefinedValidator, type ErrorOfValidator, type FlattenedAccessorsOfType, type FlattenedTypesOfType, type FlattenedValuesOfType, type FunctionalValidator, type InternalJsonPathsOf, type IsStrictUnion, type ListTypeDef, type LiteralTypeDef, type Mapper, type MinimumStringLengthValidationError, MinimumStringLengthValidationErrorType, MinimumStringLengthValidator, type MobxObservable, type MobxValueOfType, type NonMobxObservable, type ObjectFieldKey, type ObjectTypeDef, type ObjectTypeDefFields, OptionalValidatorProxy, type PathsOfType, type ReadonlyOfTypeDef, type ReadonlyTypeOfType, type RecordKeyType, type RecordTypeDef, type RegexpValidationError, RegexpValidationErrorType, RegexpValidator, type Setter, type StrictListTypeDef, type StrictLiteralTypeDef, type StrictObjectTypeDef, type StrictObjectTypeDefFields, type StrictRecordTypeDef, type StrictType, type StrictTypeDef, type StrictUnionTypeDef, type Type, type TypeDef, TypeDefType, type UnionKey, type UnionTypeDef, type ValidationError, type Validator, type ValidatorsOfValues, type ValueOfType, type ValueOfTypeDef, type ValueToTypePathsOfType, type ValueTypesOfDiscriminatedUnion, annotations, booleanType, copy, flattenAccessorsOfType, flattenJsonValueToTypePathsOf, flattenTypesOfType, flattenValidatorsOfValidatingType, flattenValueTo, flattenValuesOfType, getUnionTypeDef, isAnnotatedValidator, isFunctionalValidator, jsonPath, jsonPathPop, list, literal, mergeAnnotations, mobxCopy, nullType, nullable, numberType, object, record, stringType, union, validate, valuePathToTypePath };
|
package/dist/index.d.ts
CHANGED
|
@@ -266,25 +266,27 @@ type InternalFlattenedTypeDefsOfUnionChildren<T extends ValidatingUnionTypeDef,
|
|
|
266
266
|
readonly [K in keyof Unions]: InternalFlattenedTypeDefsOfChildren<Unions[K], SegmentOverride, Path, `${Qualifier}${K}:`, Depth>;
|
|
267
267
|
}[keyof Unions]> : never : never;
|
|
268
268
|
|
|
269
|
+
type Annotations = {
|
|
270
|
+
readonly required: boolean;
|
|
271
|
+
readonly readonly: boolean;
|
|
272
|
+
};
|
|
269
273
|
type FunctionalValidator<V = any, E = any, ValuePath extends string = any, Context = any> = (v: V, valuePath: ValuePath, context: Context) => E | null;
|
|
270
274
|
type AnnotatedValidator<V = any, E = any, ValuePath extends string = any, Context = any> = {
|
|
271
275
|
readonly validate: (v: V, valuePath: ValuePath, context: Context) => E | null;
|
|
272
|
-
readonly annotations: (valuePath: ValuePath, context: Context) =>
|
|
273
|
-
readonly required: boolean;
|
|
274
|
-
readonly readonly: boolean;
|
|
275
|
-
};
|
|
276
|
+
readonly annotations: (valuePath: ValuePath, context: Context) => Annotations;
|
|
276
277
|
};
|
|
277
278
|
type Validator<V = any, E = any, ValuePath extends string = any, Context = any> = FunctionalValidator<V, E, ValuePath, Context> | AnnotatedValidator<V, E, ValuePath, Context>;
|
|
278
279
|
type ErrorOfValidator<V extends Validator> = V extends Validator<infer _V, infer E> ? E : never;
|
|
279
280
|
type ValidationError<Type extends string, Data = {}> = Simplify<{
|
|
280
281
|
type: Type;
|
|
281
282
|
} & Data>;
|
|
282
|
-
declare function isFunctionalValidator(v: Validator): v is FunctionalValidator
|
|
283
|
-
declare function isAnnotatedValidator(v: Validator): v is AnnotatedValidator
|
|
283
|
+
declare function isFunctionalValidator<V, E, ValuePath extends string, Context>(v: Validator<V, E, ValuePath, Context>): v is FunctionalValidator<V, E, ValuePath, Context>;
|
|
284
|
+
declare function isAnnotatedValidator<V, E, ValuePath extends string, Context>(v: Validator<V, E, ValuePath, Context>): v is AnnotatedValidator<V, E, ValuePath, Context>;
|
|
284
285
|
declare function validate<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, v: V, valuePath: ValuePath, context: Context): E | null;
|
|
285
|
-
declare function annotations<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, valuePath: ValuePath, context: Context):
|
|
286
|
-
|
|
287
|
-
readonly
|
|
286
|
+
declare function annotations<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, valuePath: ValuePath, context: Context): Annotations;
|
|
287
|
+
declare function mergeAnnotations(a1: Annotations, a2: Annotations): {
|
|
288
|
+
readonly: boolean;
|
|
289
|
+
required: boolean;
|
|
288
290
|
};
|
|
289
291
|
|
|
290
292
|
type ValidatorOfValidatingType<T extends ValidatingTypeDef, ValuePath extends string, Context> = T extends ValidatingTypeDef<infer E> ? Validator<ValueOfTypeDef<ReadonlyOfTypeDef<T>>, E, ValuePath, Context> : never;
|
|
@@ -402,9 +404,8 @@ type ValidatingUnionTypeDefWithError<T extends ValidatingUnionTypeDef, E2> = T e
|
|
|
402
404
|
declare class TypeDefBuilder<T extends ValidatingTypeDef> implements ValidatingType<T> {
|
|
403
405
|
readonly definition: T;
|
|
404
406
|
constructor(definition: T);
|
|
405
|
-
enforce<E2>(rule: Rule<E2, ValueOfType<Type<T>>>): TypeDefBuilder<ValidatingTypeDefWithError<T, E2>>;
|
|
406
|
-
required(): TypeDefBuilder<
|
|
407
|
-
required<RequiredError>(rule: Rule<RequiredError, ValueOfType<typeof this.narrow>>): TypeDefBuilder<ValidatingTypeDefWithError<T, RequiredError>>;
|
|
407
|
+
enforce<E2>(rule: Rule<E2, ValueOfType<Type<T>>> | Validator<ValueOfType<Type<T>>, E2, never, never>): TypeDefBuilder<ValidatingTypeDefWithError<T, E2>>;
|
|
408
|
+
required(): TypeDefBuilder<T>;
|
|
408
409
|
readonly(): TypeDefBuilder<T>;
|
|
409
410
|
get _type(): TypeOfType<Type<T>>;
|
|
410
411
|
get narrow(): ValidatingType<T>;
|
|
@@ -519,7 +520,7 @@ type ValueTypesOfDiscriminatedUnion<U extends UnionTypeDef> = U extends UnionTyp
|
|
|
519
520
|
};
|
|
520
521
|
} : never : never;
|
|
521
522
|
|
|
522
|
-
declare class DefinedValidator<V, E
|
|
523
|
+
declare class DefinedValidator<V, E> implements AnnotatedValidator<V | null | undefined, E, never, never> {
|
|
523
524
|
private readonly error;
|
|
524
525
|
constructor(error: E);
|
|
525
526
|
validate(v: V | null | undefined): E | null;
|
|
@@ -535,7 +536,7 @@ type MinimumStringLengthValidationError = {
|
|
|
535
536
|
receivedLength: number;
|
|
536
537
|
minimumLength: number;
|
|
537
538
|
};
|
|
538
|
-
declare class MinimumStringLengthValidator
|
|
539
|
+
declare class MinimumStringLengthValidator implements AnnotatedValidator<string, MinimumStringLengthValidationError, never, never> {
|
|
539
540
|
private readonly minimumLength;
|
|
540
541
|
constructor(minimumLength: number);
|
|
541
542
|
validate(value: string): MinimumStringLengthValidationError | null;
|
|
@@ -545,8 +546,50 @@ declare class MinimumStringLengthValidator<ValuePath extends string, Context> im
|
|
|
545
546
|
};
|
|
546
547
|
}
|
|
547
548
|
|
|
549
|
+
declare class OptionalValidatorProxy<V, V1 extends V, E, ValuePath extends string, Context> implements AnnotatedValidator<V, E, ValuePath, Context> {
|
|
550
|
+
private readonly proxied;
|
|
551
|
+
private readonly isRequired;
|
|
552
|
+
static createNullable<V, E, ValuePath extends string, Context>(proxied: AnnotatedValidator<NonNullable<V>, E, ValuePath, Context>): OptionalValidatorProxy<V, NonNullable<V>, E, ValuePath, Context>;
|
|
553
|
+
static createNullableOrEmptyString<V extends string | null | undefined, E, ValuePath extends string, Context>(proxied: AnnotatedValidator<NonNullable<V>, E, ValuePath, Context>): OptionalValidatorProxy<V, NonNullable<V>, E, ValuePath, Context>;
|
|
554
|
+
constructor(proxied: AnnotatedValidator<V1, E, ValuePath, Context>, isRequired: (v: V) => v is V1);
|
|
555
|
+
validate(v: V, valuePath: ValuePath, context: Context): E | null;
|
|
556
|
+
annotations(valuePath: ValuePath, context: Context): {
|
|
557
|
+
required: boolean;
|
|
558
|
+
readonly: boolean;
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
declare const RegexpValidationErrorType = "regexp";
|
|
563
|
+
type RegexpValidationError<Intent extends string> = {
|
|
564
|
+
type: typeof RegexpValidationErrorType;
|
|
565
|
+
intent: Intent;
|
|
566
|
+
};
|
|
567
|
+
declare class RegexpValidator<Intent extends string> implements AnnotatedValidator<string, RegexpValidationError<Intent>, never, never> {
|
|
568
|
+
private readonly regexp;
|
|
569
|
+
private readonly intent;
|
|
570
|
+
/**
|
|
571
|
+
* Extremely permissive email validator
|
|
572
|
+
*/
|
|
573
|
+
static readonly email: RegexpValidator<"email">;
|
|
574
|
+
/**
|
|
575
|
+
* Extremely permissive phone number validator
|
|
576
|
+
*/
|
|
577
|
+
static readonly phone: RegexpValidator<"phone">;
|
|
578
|
+
private readonly negate;
|
|
579
|
+
private readonly required;
|
|
580
|
+
constructor(regexp: RegExp, intent: Intent, { negate, required, }?: {
|
|
581
|
+
negate?: boolean;
|
|
582
|
+
required?: boolean;
|
|
583
|
+
});
|
|
584
|
+
validate(value: string): RegexpValidationError<Intent> | null;
|
|
585
|
+
annotations(): {
|
|
586
|
+
required: boolean;
|
|
587
|
+
readonly: boolean;
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
548
591
|
type ValidatorsOfValues<FlattenedValues extends Readonly<Record<string, any>>, TypePathsToValuePaths extends Readonly<Record<keyof FlattenedValues, string>> = Readonly<Record<keyof FlattenedValues, any>>, Context = any> = {
|
|
549
592
|
readonly [K in keyof FlattenedValues]: Validator<FlattenedValues[K], any, TypePathsToValuePaths[K], Context>;
|
|
550
593
|
};
|
|
551
594
|
|
|
552
|
-
export { type Accessor, type AnnotatedValidator, type AnyValueType, DefinedValidator, type ErrorOfValidator, type FlattenedAccessorsOfType, type FlattenedTypesOfType, type FlattenedValuesOfType, type FunctionalValidator, type InternalJsonPathsOf, type IsStrictUnion, type ListTypeDef, type LiteralTypeDef, type Mapper, type MinimumStringLengthValidationError, MinimumStringLengthValidationErrorType, MinimumStringLengthValidator, type MobxObservable, type MobxValueOfType, type NonMobxObservable, type ObjectFieldKey, type ObjectTypeDef, type ObjectTypeDefFields, type PathsOfType, type ReadonlyOfTypeDef, type ReadonlyTypeOfType, type RecordKeyType, type RecordTypeDef, type Setter, type StrictListTypeDef, type StrictLiteralTypeDef, type StrictObjectTypeDef, type StrictObjectTypeDefFields, type StrictRecordTypeDef, type StrictType, type StrictTypeDef, type StrictUnionTypeDef, type Type, type TypeDef, TypeDefType, type UnionKey, type UnionTypeDef, type ValidationError, type Validator, type ValidatorsOfValues, type ValueOfType, type ValueOfTypeDef, type ValueToTypePathsOfType, type ValueTypesOfDiscriminatedUnion, annotations, booleanType, copy, flattenAccessorsOfType, flattenJsonValueToTypePathsOf, flattenTypesOfType, flattenValidatorsOfValidatingType, flattenValueTo, flattenValuesOfType, getUnionTypeDef, isAnnotatedValidator, isFunctionalValidator, jsonPath, jsonPathPop, list, literal, mobxCopy, nullType, nullable, numberType, object, record, stringType, union, validate, valuePathToTypePath };
|
|
595
|
+
export { type Accessor, type AnnotatedValidator, type Annotations, type AnyValueType, DefinedValidator, type ErrorOfValidator, type FlattenedAccessorsOfType, type FlattenedTypesOfType, type FlattenedValuesOfType, type FunctionalValidator, type InternalJsonPathsOf, type IsStrictUnion, type ListTypeDef, type LiteralTypeDef, type Mapper, type MinimumStringLengthValidationError, MinimumStringLengthValidationErrorType, MinimumStringLengthValidator, type MobxObservable, type MobxValueOfType, type NonMobxObservable, type ObjectFieldKey, type ObjectTypeDef, type ObjectTypeDefFields, OptionalValidatorProxy, type PathsOfType, type ReadonlyOfTypeDef, type ReadonlyTypeOfType, type RecordKeyType, type RecordTypeDef, type RegexpValidationError, RegexpValidationErrorType, RegexpValidator, type Setter, type StrictListTypeDef, type StrictLiteralTypeDef, type StrictObjectTypeDef, type StrictObjectTypeDefFields, type StrictRecordTypeDef, type StrictType, type StrictTypeDef, type StrictUnionTypeDef, type Type, type TypeDef, TypeDefType, type UnionKey, type UnionTypeDef, type ValidationError, type Validator, type ValidatorsOfValues, type ValueOfType, type ValueOfTypeDef, type ValueToTypePathsOfType, type ValueTypesOfDiscriminatedUnion, annotations, booleanType, copy, flattenAccessorsOfType, flattenJsonValueToTypePathsOf, flattenTypesOfType, flattenValidatorsOfValidatingType, flattenValueTo, flattenValuesOfType, getUnionTypeDef, isAnnotatedValidator, isFunctionalValidator, jsonPath, jsonPathPop, list, literal, mergeAnnotations, mobxCopy, nullType, nullable, numberType, object, record, stringType, union, validate, valuePathToTypePath };
|
package/dist/index.js
CHANGED
|
@@ -392,7 +392,7 @@ function flattenTypeTo({ definition }, mapper2) {
|
|
|
392
392
|
return reduce4(
|
|
393
393
|
typeDefs,
|
|
394
394
|
function(acc, key, typeDef) {
|
|
395
|
-
acc[key] = mapper2(typeDef);
|
|
395
|
+
acc[key] = mapper2(typeDef, key);
|
|
396
396
|
return acc;
|
|
397
397
|
},
|
|
398
398
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
@@ -640,6 +640,37 @@ function internalJsonValuePathToTypePath(typeDef, valueSteps, allowMissingPaths,
|
|
|
640
640
|
}
|
|
641
641
|
}
|
|
642
642
|
|
|
643
|
+
// validation/validator.ts
|
|
644
|
+
function isFunctionalValidator(v) {
|
|
645
|
+
return typeof v === "function";
|
|
646
|
+
}
|
|
647
|
+
function isAnnotatedValidator(v) {
|
|
648
|
+
return typeof v !== "function";
|
|
649
|
+
}
|
|
650
|
+
function validate(validator, v, valuePath, context) {
|
|
651
|
+
if (isAnnotatedValidator(validator)) {
|
|
652
|
+
return validator.validate(v, valuePath, context);
|
|
653
|
+
} else {
|
|
654
|
+
return validator(v, valuePath, context);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
function annotations(validator, valuePath, context) {
|
|
658
|
+
if (isAnnotatedValidator(validator)) {
|
|
659
|
+
return validator.annotations(valuePath, context);
|
|
660
|
+
} else {
|
|
661
|
+
return {
|
|
662
|
+
required: false,
|
|
663
|
+
readonly: false
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
function mergeAnnotations(a1, a2) {
|
|
668
|
+
return {
|
|
669
|
+
readonly: a1.readonly || a2.readonly,
|
|
670
|
+
required: a1.required || a2.required
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
|
|
643
674
|
// types/type_of_type.ts
|
|
644
675
|
import {
|
|
645
676
|
map as map2,
|
|
@@ -733,23 +764,20 @@ var TypeDefBuilder = class _TypeDefBuilder {
|
|
|
733
764
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
734
765
|
{
|
|
735
766
|
...this.definition,
|
|
767
|
+
...isAnnotatedValidator(rule) ? mergeAnnotations(rule.annotations(null, null), this.definition) : {},
|
|
736
768
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
737
769
|
rule: (value) => {
|
|
738
|
-
return this.definition.rule(value)
|
|
770
|
+
return this.definition.rule(value) ?? validate(rule, value, null, null);
|
|
739
771
|
}
|
|
740
772
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
741
773
|
}
|
|
742
774
|
);
|
|
743
775
|
}
|
|
744
|
-
required(
|
|
776
|
+
required() {
|
|
745
777
|
return new _TypeDefBuilder(
|
|
746
778
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
747
779
|
{
|
|
748
780
|
...this.definition,
|
|
749
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
750
|
-
rule: (v) => {
|
|
751
|
-
return this.definition.rule(v) || rule?.(v);
|
|
752
|
-
},
|
|
753
781
|
required: true
|
|
754
782
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
755
783
|
}
|
|
@@ -954,31 +982,6 @@ function union(discriminator) {
|
|
|
954
982
|
);
|
|
955
983
|
}
|
|
956
984
|
|
|
957
|
-
// validation/validator.ts
|
|
958
|
-
function isFunctionalValidator(v) {
|
|
959
|
-
return typeof v === "function";
|
|
960
|
-
}
|
|
961
|
-
function isAnnotatedValidator(v) {
|
|
962
|
-
return typeof v !== "function";
|
|
963
|
-
}
|
|
964
|
-
function validate(validator, v, valuePath, context) {
|
|
965
|
-
if (isAnnotatedValidator(validator)) {
|
|
966
|
-
return validator.validate(v, valuePath, context);
|
|
967
|
-
} else {
|
|
968
|
-
return validator(v, valuePath, context);
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
function annotations(validator, valuePath, context) {
|
|
972
|
-
if (isAnnotatedValidator(validator)) {
|
|
973
|
-
return validator.annotations(valuePath, context);
|
|
974
|
-
} else {
|
|
975
|
-
return {
|
|
976
|
-
required: false,
|
|
977
|
-
readonly: false
|
|
978
|
-
};
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
985
|
// validation/validators/defined_validator.ts
|
|
983
986
|
var DefinedValidator = class {
|
|
984
987
|
constructor(error) {
|
|
@@ -1016,7 +1019,76 @@ var MinimumStringLengthValidator = class {
|
|
|
1016
1019
|
}
|
|
1017
1020
|
annotations() {
|
|
1018
1021
|
return {
|
|
1019
|
-
required:
|
|
1022
|
+
required: this.minimumLength > 0,
|
|
1023
|
+
readonly: false
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
|
|
1028
|
+
// validation/validators/optional_validator_proxy.ts
|
|
1029
|
+
var OptionalValidatorProxy = class _OptionalValidatorProxy {
|
|
1030
|
+
constructor(proxied, isRequired) {
|
|
1031
|
+
this.proxied = proxied;
|
|
1032
|
+
this.isRequired = isRequired;
|
|
1033
|
+
}
|
|
1034
|
+
static createNullable(proxied) {
|
|
1035
|
+
return new _OptionalValidatorProxy(proxied, (v) => v != null);
|
|
1036
|
+
}
|
|
1037
|
+
static createNullableOrEmptyString(proxied) {
|
|
1038
|
+
return new _OptionalValidatorProxy(proxied, (v) => v != null && v !== "");
|
|
1039
|
+
}
|
|
1040
|
+
validate(v, valuePath, context) {
|
|
1041
|
+
if (this.isRequired(v)) {
|
|
1042
|
+
return this.proxied.validate(v, valuePath, context);
|
|
1043
|
+
}
|
|
1044
|
+
return null;
|
|
1045
|
+
}
|
|
1046
|
+
annotations(valuePath, context) {
|
|
1047
|
+
return {
|
|
1048
|
+
...this.proxied.annotations(valuePath, context),
|
|
1049
|
+
required: false
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
|
|
1054
|
+
// validation/validators/regexp_validator.ts
|
|
1055
|
+
var RegexpValidationErrorType = "regexp";
|
|
1056
|
+
var RegexpValidator = class _RegexpValidator {
|
|
1057
|
+
constructor(regexp, intent, {
|
|
1058
|
+
negate = false,
|
|
1059
|
+
required = false
|
|
1060
|
+
} = {}) {
|
|
1061
|
+
this.regexp = regexp;
|
|
1062
|
+
this.intent = intent;
|
|
1063
|
+
this.negate = negate;
|
|
1064
|
+
this.required = required;
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Extremely permissive email validator
|
|
1068
|
+
*/
|
|
1069
|
+
static email = new _RegexpValidator(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, "email");
|
|
1070
|
+
/**
|
|
1071
|
+
* Extremely permissive phone number validator
|
|
1072
|
+
*/
|
|
1073
|
+
static phone = new _RegexpValidator(
|
|
1074
|
+
/^(\+\d{1,4}[\s]*)?(((\([\d\s-]{1,6}\))|\d)[\s-]*){3,14}(\d|(\(\d+\)))$/,
|
|
1075
|
+
"phone"
|
|
1076
|
+
);
|
|
1077
|
+
negate;
|
|
1078
|
+
required;
|
|
1079
|
+
validate(value) {
|
|
1080
|
+
const passes = this.regexp.test(value);
|
|
1081
|
+
if (!passes && !this.negate || passes && this.negate) {
|
|
1082
|
+
return {
|
|
1083
|
+
type: RegexpValidationErrorType,
|
|
1084
|
+
intent: this.intent
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
return null;
|
|
1088
|
+
}
|
|
1089
|
+
annotations() {
|
|
1090
|
+
return {
|
|
1091
|
+
required: this.required,
|
|
1020
1092
|
readonly: false
|
|
1021
1093
|
};
|
|
1022
1094
|
}
|
|
@@ -1025,6 +1097,9 @@ export {
|
|
|
1025
1097
|
DefinedValidator,
|
|
1026
1098
|
MinimumStringLengthValidationErrorType,
|
|
1027
1099
|
MinimumStringLengthValidator,
|
|
1100
|
+
OptionalValidatorProxy,
|
|
1101
|
+
RegexpValidationErrorType,
|
|
1102
|
+
RegexpValidator,
|
|
1028
1103
|
TypeDefType,
|
|
1029
1104
|
annotations,
|
|
1030
1105
|
booleanType,
|
|
@@ -1042,6 +1117,7 @@ export {
|
|
|
1042
1117
|
jsonPathPop,
|
|
1043
1118
|
list,
|
|
1044
1119
|
literal,
|
|
1120
|
+
mergeAnnotations,
|
|
1045
1121
|
mobxCopy,
|
|
1046
1122
|
nullType,
|
|
1047
1123
|
nullable,
|
package/index.ts
CHANGED
|
@@ -23,4 +23,6 @@ export * from './types/value_types_of_discriminated_union'
|
|
|
23
23
|
export * from './validation/validator'
|
|
24
24
|
export * from './validation/validators/defined_validator'
|
|
25
25
|
export * from './validation/validators/minimum_string_length_validator'
|
|
26
|
+
export * from './validation/validators/optional_validator_proxy'
|
|
27
|
+
export * from './validation/validators/regexp_validator'
|
|
26
28
|
export * from './validation/validators_of_values'
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@ import { jsonPath } from './json_path'
|
|
|
18
18
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
19
|
export type AnyValueType = any
|
|
20
20
|
|
|
21
|
-
export type Mapper<R> = (t: StrictTypeDef) => R
|
|
21
|
+
export type Mapper<R> = (t: StrictTypeDef, key: string) => R
|
|
22
22
|
|
|
23
23
|
export function flattenTypeTo<M, R extends Readonly<Record<string, M>>>(
|
|
24
24
|
{ definition }: StrictType,
|
|
@@ -29,7 +29,7 @@ export function flattenTypeTo<M, R extends Readonly<Record<string, M>>>(
|
|
|
29
29
|
return reduce(
|
|
30
30
|
typeDefs,
|
|
31
31
|
function (acc, key, typeDef) {
|
|
32
|
-
acc[key] = mapper(typeDef)
|
|
32
|
+
acc[key] = mapper(typeDef, key)
|
|
33
33
|
return acc
|
|
34
34
|
},
|
|
35
35
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
package/types/builders.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type IsFieldReadonly,
|
|
3
3
|
} from '@strictly/base'
|
|
4
|
+
import {
|
|
5
|
+
isAnnotatedValidator,
|
|
6
|
+
mergeAnnotations,
|
|
7
|
+
validate,
|
|
8
|
+
type Validator,
|
|
9
|
+
} from 'validation/validator'
|
|
4
10
|
import {
|
|
5
11
|
type ObjectFieldKey,
|
|
6
12
|
type RecordKeyType,
|
|
@@ -37,35 +43,26 @@ class TypeDefBuilder<T extends ValidatingTypeDef> implements ValidatingType<T> {
|
|
|
37
43
|
constructor(readonly definition: T) {
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
enforce<E2>(rule: Rule<E2, ValueOfType<Type<T>>>) {
|
|
46
|
+
enforce<E2>(rule: Rule<E2, ValueOfType<Type<T>>> | Validator<ValueOfType<Type<T>>, E2, never, never>) {
|
|
41
47
|
return new TypeDefBuilder<ValidatingTypeDefWithError<T, E2>>(
|
|
42
48
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
43
49
|
{
|
|
44
50
|
...this.definition,
|
|
51
|
+
...(isAnnotatedValidator(rule) ? mergeAnnotations(rule.annotations(null!, null!), this.definition) : {}),
|
|
45
52
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
53
|
rule: (value: any) => {
|
|
47
|
-
return this.definition.rule(value)
|
|
54
|
+
return this.definition.rule(value) ?? validate(rule, value, null!, null!)
|
|
48
55
|
},
|
|
49
56
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
57
|
} as any,
|
|
51
58
|
)
|
|
52
59
|
}
|
|
53
60
|
|
|
54
|
-
required(): TypeDefBuilder<
|
|
55
|
-
|
|
56
|
-
RequiredError,
|
|
57
|
-
>(rule: Rule<RequiredError, ValueOfType<typeof this.narrow>>): TypeDefBuilder<
|
|
58
|
-
ValidatingTypeDefWithError<T, RequiredError>
|
|
59
|
-
>
|
|
60
|
-
required<RequiredError = never>(rule?: Rule<RequiredError, ValueOfType<typeof this.narrow>>) {
|
|
61
|
-
return new TypeDefBuilder<ValidatingTypeDefWithError<T, RequiredError>>(
|
|
61
|
+
required(): TypeDefBuilder<T> {
|
|
62
|
+
return new TypeDefBuilder<T>(
|
|
62
63
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
63
64
|
{
|
|
64
65
|
...this.definition,
|
|
65
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
-
rule: (v: any) => {
|
|
67
|
-
return this.definition.rule(v) || rule?.(v)
|
|
68
|
-
},
|
|
69
66
|
required: true,
|
|
70
67
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
68
|
} as any,
|
package/validation/validator.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { type Simplify } from 'type-fest'
|
|
2
2
|
|
|
3
|
+
export type Annotations = {
|
|
4
|
+
readonly required: boolean,
|
|
5
|
+
readonly readonly: boolean,
|
|
6
|
+
}
|
|
7
|
+
|
|
3
8
|
export type FunctionalValidator<
|
|
4
9
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
10
|
V = any,
|
|
@@ -22,10 +27,7 @@ export type AnnotatedValidator<
|
|
|
22
27
|
Context = any,
|
|
23
28
|
> = {
|
|
24
29
|
readonly validate: (v: V, valuePath: ValuePath, context: Context) => E | null,
|
|
25
|
-
readonly annotations: (valuePath: ValuePath, context: Context) =>
|
|
26
|
-
readonly required: boolean,
|
|
27
|
-
readonly readonly: boolean,
|
|
28
|
-
},
|
|
30
|
+
readonly annotations: (valuePath: ValuePath, context: Context) => Annotations,
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export type Validator<
|
|
@@ -47,11 +49,21 @@ export type ValidationError<Type extends string, Data = {}> = Simplify<
|
|
|
47
49
|
} & Data
|
|
48
50
|
>
|
|
49
51
|
|
|
50
|
-
export function isFunctionalValidator
|
|
52
|
+
export function isFunctionalValidator<
|
|
53
|
+
V,
|
|
54
|
+
E,
|
|
55
|
+
ValuePath extends string,
|
|
56
|
+
Context,
|
|
57
|
+
>(v: Validator<V, E, ValuePath, Context>): v is FunctionalValidator<V, E, ValuePath, Context> {
|
|
51
58
|
return typeof v === 'function'
|
|
52
59
|
}
|
|
53
60
|
|
|
54
|
-
export function isAnnotatedValidator
|
|
61
|
+
export function isAnnotatedValidator<
|
|
62
|
+
V,
|
|
63
|
+
E,
|
|
64
|
+
ValuePath extends string,
|
|
65
|
+
Context,
|
|
66
|
+
>(v: Validator<V, E, ValuePath, Context>): v is AnnotatedValidator<V, E, ValuePath, Context> {
|
|
55
67
|
return typeof v !== 'function'
|
|
56
68
|
}
|
|
57
69
|
|
|
@@ -73,8 +85,7 @@ export function validate<
|
|
|
73
85
|
if (isAnnotatedValidator(validator)) {
|
|
74
86
|
return validator.validate(v, valuePath, context)
|
|
75
87
|
} else {
|
|
76
|
-
|
|
77
|
-
return (validator as FunctionalValidator<V, E, ValuePath, Context>)(v, valuePath, context)
|
|
88
|
+
return validator(v, valuePath, context)
|
|
78
89
|
}
|
|
79
90
|
}
|
|
80
91
|
|
|
@@ -101,3 +112,10 @@ export function annotations<
|
|
|
101
112
|
}
|
|
102
113
|
}
|
|
103
114
|
}
|
|
115
|
+
|
|
116
|
+
export function mergeAnnotations(a1: Annotations, a2: Annotations) {
|
|
117
|
+
return {
|
|
118
|
+
readonly: a1.readonly || a2.readonly,
|
|
119
|
+
required: a1.required || a2.required,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { type AnnotatedValidator } from 'validation/validator'
|
|
2
2
|
|
|
3
|
-
export class DefinedValidator<V, E
|
|
4
|
-
implements AnnotatedValidator<V | null | undefined, E, ValuePath, Context>
|
|
5
|
-
{
|
|
3
|
+
export class DefinedValidator<V, E> implements AnnotatedValidator<V | null | undefined, E, never, never> {
|
|
6
4
|
constructor(private readonly error: E) {
|
|
7
5
|
}
|
|
8
6
|
|
|
@@ -10,8 +10,8 @@ export type MinimumStringLengthValidationError = {
|
|
|
10
10
|
minimumLength: number,
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export class MinimumStringLengthValidator
|
|
14
|
-
implements AnnotatedValidator<string, MinimumStringLengthValidationError,
|
|
13
|
+
export class MinimumStringLengthValidator
|
|
14
|
+
implements AnnotatedValidator<string, MinimumStringLengthValidationError, never, never>
|
|
15
15
|
{
|
|
16
16
|
constructor(private readonly minimumLength: number) {
|
|
17
17
|
}
|
|
@@ -29,7 +29,7 @@ export class MinimumStringLengthValidator<ValuePath extends string, Context>
|
|
|
29
29
|
|
|
30
30
|
annotations() {
|
|
31
31
|
return {
|
|
32
|
-
required:
|
|
32
|
+
required: this.minimumLength > 0,
|
|
33
33
|
readonly: false,
|
|
34
34
|
}
|
|
35
35
|
}
|