@palmares/schemas 0.0.1
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/.turbo/turbo-build$colon$watch.log +424 -0
- package/.turbo/turbo-build.log +13 -0
- package/.turbo/turbo-build:watch.log +26 -0
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/dist/cjs/src/adapter/fields/array.js +157 -0
- package/dist/cjs/src/adapter/fields/boolean.js +167 -0
- package/dist/cjs/src/adapter/fields/datetime.js +167 -0
- package/dist/cjs/src/adapter/fields/index.js +311 -0
- package/dist/cjs/src/adapter/fields/number.js +167 -0
- package/dist/cjs/src/adapter/fields/object.js +167 -0
- package/dist/cjs/src/adapter/fields/string.js +167 -0
- package/dist/cjs/src/adapter/fields/union.js +167 -0
- package/dist/cjs/src/adapter/index.js +198 -0
- package/dist/cjs/src/adapter/types.js +4 -0
- package/dist/cjs/src/compile.js +262 -0
- package/dist/cjs/src/conf.js +27 -0
- package/dist/cjs/src/constants.js +42 -0
- package/dist/cjs/src/domain.js +12 -0
- package/dist/cjs/src/exceptions.js +168 -0
- package/dist/cjs/src/index.js +365 -0
- package/dist/cjs/src/model.js +628 -0
- package/dist/cjs/src/parsers/convert-from-number.js +20 -0
- package/dist/cjs/src/parsers/convert-from-string.js +24 -0
- package/dist/cjs/src/parsers/index.js +25 -0
- package/dist/cjs/src/schema/array.js +890 -0
- package/dist/cjs/src/schema/boolean.js +826 -0
- package/dist/cjs/src/schema/datetime.js +778 -0
- package/dist/cjs/src/schema/index.js +17 -0
- package/dist/cjs/src/schema/number.js +960 -0
- package/dist/cjs/src/schema/object.js +999 -0
- package/dist/cjs/src/schema/schema.js +1788 -0
- package/dist/cjs/src/schema/string.js +948 -0
- package/dist/cjs/src/schema/types.js +4 -0
- package/dist/cjs/src/schema/union.js +952 -0
- package/dist/cjs/src/types.js +4 -0
- package/dist/cjs/src/utils.js +627 -0
- package/dist/cjs/src/validators/array.js +457 -0
- package/dist/cjs/src/validators/boolean.js +199 -0
- package/dist/cjs/src/validators/datetime.js +287 -0
- package/dist/cjs/src/validators/number.js +403 -0
- package/dist/cjs/src/validators/object.js +290 -0
- package/dist/cjs/src/validators/schema.js +318 -0
- package/dist/cjs/src/validators/string.js +439 -0
- package/dist/cjs/src/validators/types.js +4 -0
- package/dist/cjs/src/validators/union.js +232 -0
- package/dist/cjs/src/validators/utils.js +426 -0
- package/dist/cjs/tsconfig.types.tsbuildinfo +1 -0
- package/dist/cjs/types/adapter/fields/array.d.ts +20 -0
- package/dist/cjs/types/adapter/fields/array.d.ts.map +1 -0
- package/dist/cjs/types/adapter/fields/boolean.d.ts +25 -0
- package/dist/cjs/types/adapter/fields/boolean.d.ts.map +1 -0
- package/dist/cjs/types/adapter/fields/datetime.d.ts +25 -0
- package/dist/cjs/types/adapter/fields/datetime.d.ts.map +1 -0
- package/dist/cjs/types/adapter/fields/index.d.ts +31 -0
- package/dist/cjs/types/adapter/fields/index.d.ts.map +1 -0
- package/dist/cjs/types/adapter/fields/number.d.ts +25 -0
- package/dist/cjs/types/adapter/fields/number.d.ts.map +1 -0
- package/dist/cjs/types/adapter/fields/object.d.ts +25 -0
- package/dist/cjs/types/adapter/fields/object.d.ts.map +1 -0
- package/dist/cjs/types/adapter/fields/string.d.ts +25 -0
- package/dist/cjs/types/adapter/fields/string.d.ts.map +1 -0
- package/dist/cjs/types/adapter/fields/union.d.ts +25 -0
- package/dist/cjs/types/adapter/fields/union.d.ts.map +1 -0
- package/dist/cjs/types/adapter/index.d.ts +25 -0
- package/dist/cjs/types/adapter/index.d.ts.map +1 -0
- package/dist/cjs/types/adapter/types.d.ts +144 -0
- package/dist/cjs/types/adapter/types.d.ts.map +1 -0
- package/dist/cjs/types/compile.d.ts +3 -0
- package/dist/cjs/types/compile.d.ts.map +1 -0
- package/dist/cjs/types/conf.d.ts +16 -0
- package/dist/cjs/types/conf.d.ts.map +1 -0
- package/dist/cjs/types/constants.d.ts +6 -0
- package/dist/cjs/types/constants.d.ts.map +1 -0
- package/dist/cjs/types/domain.d.ts +21 -0
- package/dist/cjs/types/domain.d.ts.map +1 -0
- package/dist/cjs/types/exceptions.d.ts +13 -0
- package/dist/cjs/types/exceptions.d.ts.map +1 -0
- package/dist/cjs/types/index.d.ts +240 -0
- package/dist/cjs/types/index.d.ts.map +1 -0
- package/dist/cjs/types/model.d.ts +136 -0
- package/dist/cjs/types/model.d.ts.map +1 -0
- package/dist/cjs/types/parsers/convert-from-number.d.ts +15 -0
- package/dist/cjs/types/parsers/convert-from-number.d.ts.map +1 -0
- package/dist/cjs/types/parsers/convert-from-string.d.ts +9 -0
- package/dist/cjs/types/parsers/convert-from-string.d.ts.map +1 -0
- package/dist/cjs/types/parsers/index.d.ts +3 -0
- package/dist/cjs/types/parsers/index.d.ts.map +1 -0
- package/dist/cjs/types/schema/array.d.ts +429 -0
- package/dist/cjs/types/schema/array.d.ts.map +1 -0
- package/dist/cjs/types/schema/boolean.d.ts +501 -0
- package/dist/cjs/types/schema/boolean.d.ts.map +1 -0
- package/dist/cjs/types/schema/datetime.d.ts +474 -0
- package/dist/cjs/types/schema/datetime.d.ts.map +1 -0
- package/dist/cjs/types/schema/index.d.ts +4 -0
- package/dist/cjs/types/schema/index.d.ts.map +1 -0
- package/dist/cjs/types/schema/number.d.ts +667 -0
- package/dist/cjs/types/schema/number.d.ts.map +1 -0
- package/dist/cjs/types/schema/object.d.ts +450 -0
- package/dist/cjs/types/schema/object.d.ts.map +1 -0
- package/dist/cjs/types/schema/schema.d.ts +646 -0
- package/dist/cjs/types/schema/schema.d.ts.map +1 -0
- package/dist/cjs/types/schema/string.d.ts +606 -0
- package/dist/cjs/types/schema/string.d.ts.map +1 -0
- package/dist/cjs/types/schema/types.d.ts +70 -0
- package/dist/cjs/types/schema/types.d.ts.map +1 -0
- package/dist/cjs/types/schema/union.d.ts +388 -0
- package/dist/cjs/types/schema/union.d.ts.map +1 -0
- package/dist/cjs/types/types.d.ts +11 -0
- package/dist/cjs/types/types.d.ts.map +1 -0
- package/dist/cjs/types/utils.d.ts +79 -0
- package/dist/cjs/types/utils.d.ts.map +1 -0
- package/dist/cjs/types/validators/array.d.ts +8 -0
- package/dist/cjs/types/validators/array.d.ts.map +1 -0
- package/dist/cjs/types/validators/boolean.d.ts +4 -0
- package/dist/cjs/types/validators/boolean.d.ts.map +1 -0
- package/dist/cjs/types/validators/datetime.d.ts +7 -0
- package/dist/cjs/types/validators/datetime.d.ts.map +1 -0
- package/dist/cjs/types/validators/number.d.ts +10 -0
- package/dist/cjs/types/validators/number.d.ts.map +1 -0
- package/dist/cjs/types/validators/object.d.ts +6 -0
- package/dist/cjs/types/validators/object.d.ts.map +1 -0
- package/dist/cjs/types/validators/schema.d.ts +10 -0
- package/dist/cjs/types/validators/schema.d.ts.map +1 -0
- package/dist/cjs/types/validators/string.d.ts +12 -0
- package/dist/cjs/types/validators/string.d.ts.map +1 -0
- package/dist/cjs/types/validators/types.d.ts +2 -0
- package/dist/cjs/types/validators/types.d.ts.map +1 -0
- package/dist/cjs/types/validators/union.d.ts +4 -0
- package/dist/cjs/types/validators/union.d.ts.map +1 -0
- package/dist/cjs/types/validators/utils.d.ts +83 -0
- package/dist/cjs/types/validators/utils.d.ts.map +1 -0
- package/dist/esm/src/adapter/fields/array.js +13 -0
- package/dist/esm/src/adapter/fields/boolean.js +20 -0
- package/dist/esm/src/adapter/fields/datetime.js +20 -0
- package/dist/esm/src/adapter/fields/index.js +37 -0
- package/dist/esm/src/adapter/fields/number.js +20 -0
- package/dist/esm/src/adapter/fields/object.js +20 -0
- package/dist/esm/src/adapter/fields/string.js +20 -0
- package/dist/esm/src/adapter/fields/union.js +20 -0
- package/dist/esm/src/adapter/index.js +18 -0
- package/dist/esm/src/adapter/types.js +1 -0
- package/dist/esm/src/compile.js +10 -0
- package/dist/esm/src/conf.js +19 -0
- package/dist/esm/src/constants.js +5 -0
- package/dist/esm/src/domain.js +2 -0
- package/dist/esm/src/exceptions.js +15 -0
- package/dist/esm/src/index.js +160 -0
- package/dist/esm/src/model.js +255 -0
- package/dist/esm/src/parsers/convert-from-number.js +8 -0
- package/dist/esm/src/parsers/convert-from-string.js +14 -0
- package/dist/esm/src/parsers/index.js +2 -0
- package/dist/esm/src/schema/array.js +403 -0
- package/dist/esm/src/schema/boolean.js +465 -0
- package/dist/esm/src/schema/datetime.js +423 -0
- package/dist/esm/src/schema/index.js +3 -0
- package/dist/esm/src/schema/number.js +592 -0
- package/dist/esm/src/schema/object.js +464 -0
- package/dist/esm/src/schema/schema.js +728 -0
- package/dist/esm/src/schema/string.js +579 -0
- package/dist/esm/src/schema/types.js +1 -0
- package/dist/esm/src/schema/union.js +388 -0
- package/dist/esm/src/types.js +1 -0
- package/dist/esm/src/utils.js +175 -0
- package/dist/esm/src/validators/array.js +135 -0
- package/dist/esm/src/validators/boolean.js +35 -0
- package/dist/esm/src/validators/datetime.js +85 -0
- package/dist/esm/src/validators/number.js +162 -0
- package/dist/esm/src/validators/object.js +38 -0
- package/dist/esm/src/validators/schema.js +114 -0
- package/dist/esm/src/validators/string.js +174 -0
- package/dist/esm/src/validators/types.js +1 -0
- package/dist/esm/src/validators/union.js +38 -0
- package/dist/esm/src/validators/utils.js +120 -0
- package/package.json +48 -0
- package/src/adapter/fields/array.ts +31 -0
- package/src/adapter/fields/boolean.ts +48 -0
- package/src/adapter/fields/datetime.ts +49 -0
- package/src/adapter/fields/index.ts +72 -0
- package/src/adapter/fields/number.ts +49 -0
- package/src/adapter/fields/object.ts +49 -0
- package/src/adapter/fields/string.ts +49 -0
- package/src/adapter/fields/union.ts +49 -0
- package/src/adapter/index.ts +34 -0
- package/src/adapter/types.ts +261 -0
- package/src/compile.ts +14 -0
- package/src/conf.ts +27 -0
- package/src/constants.ts +9 -0
- package/src/domain.ts +3 -0
- package/src/exceptions.ts +17 -0
- package/src/index.ts +338 -0
- package/src/model.ts +501 -0
- package/src/parsers/convert-from-number.ts +13 -0
- package/src/parsers/convert-from-string.ts +19 -0
- package/src/parsers/index.ts +2 -0
- package/src/schema/array.ts +633 -0
- package/src/schema/boolean.ts +700 -0
- package/src/schema/datetime.ts +613 -0
- package/src/schema/index.ts +5 -0
- package/src/schema/number.ts +885 -0
- package/src/schema/object.ts +699 -0
- package/src/schema/schema.ts +1093 -0
- package/src/schema/string.ts +807 -0
- package/src/schema/types.ts +126 -0
- package/src/schema/union.ts +596 -0
- package/src/types.ts +13 -0
- package/src/utils.ts +322 -0
- package/src/validators/array.ts +164 -0
- package/src/validators/boolean.ts +46 -0
- package/src/validators/datetime.ts +113 -0
- package/src/validators/number.ts +188 -0
- package/src/validators/object.ts +55 -0
- package/src/validators/schema.ts +134 -0
- package/src/validators/string.ts +215 -0
- package/src/validators/types.ts +1 -0
- package/src/validators/union.ts +52 -0
- package/src/validators/utils.ts +200 -0
- package/tsconfig.json +9 -0
- package/tsconfig.types.json +10 -0
package/src/utils.ts
ADDED
@@ -0,0 +1,322 @@
|
|
1
|
+
import { checkType, nullable, optional } from './validators/schema';
|
2
|
+
import Validator from './validators/utils';
|
3
|
+
|
4
|
+
import type SchemaAdapter from './adapter';
|
5
|
+
import type FieldAdapter from './adapter/fields';
|
6
|
+
import type { ValidationDataBasedOnType } from './adapter/types';
|
7
|
+
import type Schema from './schema/schema';
|
8
|
+
import type { ValidationFallbackCallbackReturnType, ValidationFallbackReturnType } from './schema/types';
|
9
|
+
import type { FallbackFunctionsType, SupportedSchemas } from './types';
|
10
|
+
|
11
|
+
/**
|
12
|
+
* The usage of this is that imagine that the library doesn't support a specific feature that we support on our schema definition, it can return an instance
|
13
|
+
* of this class and with this instance we are able to fallback to our default implementation of the schema validation.
|
14
|
+
*/
|
15
|
+
export default class WithFallback<TType extends SupportedSchemas> {
|
16
|
+
fallbackFor: Set<
|
17
|
+
| keyof Omit<ValidationDataBasedOnType<TType>, 'withFallback' | 'parsers'>
|
18
|
+
| keyof ValidationDataBasedOnType<TType>['parsers']
|
19
|
+
>;
|
20
|
+
transformedSchema: any;
|
21
|
+
adapterType: TType;
|
22
|
+
|
23
|
+
constructor(
|
24
|
+
adapterType: TType,
|
25
|
+
fallbackFor: (
|
26
|
+
| keyof Omit<ValidationDataBasedOnType<TType>, 'withFallback' | 'parsers'>
|
27
|
+
| keyof ValidationDataBasedOnType<TType>['parsers']
|
28
|
+
)[],
|
29
|
+
transformedSchema: any
|
30
|
+
) {
|
31
|
+
this.adapterType = adapterType;
|
32
|
+
this.fallbackFor = new Set<
|
33
|
+
| keyof Omit<ValidationDataBasedOnType<TType>, 'withFallback' | 'parsers'>
|
34
|
+
| keyof ValidationDataBasedOnType<TType>['parsers']
|
35
|
+
>(fallbackFor as any);
|
36
|
+
this.transformedSchema = transformedSchema;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
/**
|
41
|
+
* Factory function for creating a new instance of WithFallback. We call that function when parsing the schema adapter, and then, inside of the adapter the user will can the inner function
|
42
|
+
* to create a new instance of WithFallback.
|
43
|
+
*
|
44
|
+
* @param adapterType - The type of the adapter that we are using.
|
45
|
+
*
|
46
|
+
* @returns - A currying function that will create a new instance of WithFallback.
|
47
|
+
*/
|
48
|
+
export function withFallbackFactory<TType extends SupportedSchemas>(adapterType: TType) {
|
49
|
+
return (
|
50
|
+
fallbackFor: (
|
51
|
+
| keyof Omit<ValidationDataBasedOnType<TType>, 'withFallback' | 'parsers'>
|
52
|
+
| keyof ValidationDataBasedOnType<TType>['parsers']
|
53
|
+
)[],
|
54
|
+
transformedSchema: WithFallback<SupportedSchemas>['transformedSchema']
|
55
|
+
) => new WithFallback<TType>(adapterType, fallbackFor, transformedSchema);
|
56
|
+
}
|
57
|
+
|
58
|
+
export function parseErrorsFactory(schemaAdapter: SchemaAdapter) {
|
59
|
+
return async (
|
60
|
+
errorOrErrors: any | any[],
|
61
|
+
metadata?: any
|
62
|
+
): Promise<Awaited<ReturnType<SchemaAdapter['formatError']>>[]> => {
|
63
|
+
const errorsIsAnArray = Array.isArray(errorOrErrors);
|
64
|
+
if (errorsIsAnArray)
|
65
|
+
return Promise.all(errorOrErrors.map((error) => schemaAdapter.formatError.bind(schemaAdapter)(error, metadata)));
|
66
|
+
return [await schemaAdapter.formatError.bind(schemaAdapter)(errorOrErrors, metadata)];
|
67
|
+
};
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* The default transform function that we use for the schema adapters. This function tries to abstract away the complexity of translating the schema to the adapter.
|
72
|
+
*
|
73
|
+
* So first things first, WHAT IS a fallback? A fallback is a function that we call when the user defines a validation that is not supported by the adapter. For example, imagine that
|
74
|
+
* for some reason the adapter doesn't support the `max` validation, we can define a fallback for that validation and then, when the user defines that validation, we call the fallback
|
75
|
+
* function. So, even if the adapter doesn't support that validation our schema will still be able to validate that.
|
76
|
+
*
|
77
|
+
* @param type - The type of the adapter that we are using, can be a number, an object, all of the possible schema adapters.
|
78
|
+
* @param schema - The schema that we are translating.
|
79
|
+
* @param validationData - The data that we are using to validate the schema. This means for example, the `max` validation, the `min` validation, etc. The message of the validation when
|
80
|
+
* it is not valid, etc.
|
81
|
+
* @param fallbackFunctions - The fallback functions that we are using to validate the schema. Those are the functions we fallback to when the user defines a validation that is not
|
82
|
+
* supported by the adapter.
|
83
|
+
*
|
84
|
+
* @returns - The translated schema for something that the adapter is able to understand.
|
85
|
+
*/
|
86
|
+
export async function defaultTransform<TType extends SupportedSchemas>(
|
87
|
+
type: TType,
|
88
|
+
schema: Schema<any, any>,
|
89
|
+
adapter: SchemaAdapter,
|
90
|
+
fieldAdapter: FieldAdapter | undefined,
|
91
|
+
getValidationData: (isStringVersion: boolean) => ValidationDataBasedOnType<TType>,
|
92
|
+
fallbackFunctions: FallbackFunctionsType<Omit<Awaited<ReturnType<typeof getValidationData>>, 'parsers'>>,
|
93
|
+
options: {
|
94
|
+
validatorsIfFallbackOrNotSupported?: ValidationFallbackReturnType | ValidationFallbackReturnType[];
|
95
|
+
/**
|
96
|
+
* If the schema is not supported by the adapter, this means, that the adapter hasn't defined an adapter for that field type, we can fallback to a custom implementation.
|
97
|
+
* The problem is that, for example: Unions,
|
98
|
+
*
|
99
|
+
* Let's say we have a schema like this: ObjectSchema.new({ age: UnionSchema.new([NumberSchema.new(), StringSchema.new()] )});
|
100
|
+
*
|
101
|
+
* The root object will be validated by the adapter so what we need to do is create two schemas on the root object, one where the
|
102
|
+
* value of `age` key is a number and another where the value of `age` key is a string. Now the root object has two schemas memoized on __transformedSchemas, nice,
|
103
|
+
* what's the logic on that case? The ObjectSchema shouldn't take care of that logic. So the Union schema takes control of validating through the adapter. Is adapter 1 without errors?
|
104
|
+
* If yes, return the result, if not, try the second adapter. If the second adapter is without errors, return the result, if not, return the errors.
|
105
|
+
*
|
106
|
+
* In other words, the `fallbackIfNotSupported` function on Unions should return the two schemas saved on it on that case, that way the root ObjectSchema will
|
107
|
+
* create those two schemas on the array.
|
108
|
+
*/
|
109
|
+
fallbackIfNotSupported?: () => ReturnType<Schema['__transformToAdapter']>;
|
110
|
+
} & Pick<Parameters<Schema['__transformToAdapter']>[0], 'shouldAddStringVersion'>
|
111
|
+
): Promise<any[]> {
|
112
|
+
const validationData = await Promise.resolve(getValidationData(false));
|
113
|
+
|
114
|
+
const validationDataForStringVersion = (
|
115
|
+
options.shouldAddStringVersion ? await Promise.resolve(getValidationData(true)) : undefined
|
116
|
+
) as ValidationDataBasedOnType<TType>;
|
117
|
+
const schemaWithPrivateFields = schema as unknown as {
|
118
|
+
__transformedSchemas: Schema['__transformedSchemas'];
|
119
|
+
__rootFallbacksValidator: Schema['__rootFallbacksValidator'];
|
120
|
+
__optional: Schema['__optional'];
|
121
|
+
__nullable: Schema['__nullable'];
|
122
|
+
__type: Schema['__type'];
|
123
|
+
__parsers: Schema['__parsers'];
|
124
|
+
__extends: Schema['__extends'];
|
125
|
+
};
|
126
|
+
|
127
|
+
const checkIfShouldUseParserAndAppend = (parser: Parameters<WithFallback<SupportedSchemas>['fallbackFor']['add']>[0]) => {
|
128
|
+
const isValidationDataAParser = (validationData as any).parsers?.[parser] !== undefined;
|
129
|
+
if (isValidationDataAParser) (schema as unknown as {
|
130
|
+
__parsers: Schema['__parsers'];
|
131
|
+
}).__parsers._fallbacks.add(parser);
|
132
|
+
}
|
133
|
+
|
134
|
+
const getExtendedOrNotSchemaAndString = (schema: any, toStringVersion: string) => {
|
135
|
+
const extendedOrNotSchema = typeof schemaWithPrivateFields.__extends?.callback === 'function' ?
|
136
|
+
schemaWithPrivateFields.__extends.callback(schema) :
|
137
|
+
schema;
|
138
|
+
const extendedOrNotSchemaString = typeof schemaWithPrivateFields.__extends?.toStringCallback === 'function' ?
|
139
|
+
schemaWithPrivateFields.__extends.toStringCallback(toStringVersion) :
|
140
|
+
toStringVersion;
|
141
|
+
return [extendedOrNotSchema, extendedOrNotSchemaString];
|
142
|
+
}
|
143
|
+
|
144
|
+
const checkIfShouldAppendFallbackAndAppend = (
|
145
|
+
fallback: Parameters<WithFallback<SupportedSchemas>['fallbackFor']['add']>[0]
|
146
|
+
) => {
|
147
|
+
const wereArgumentsForThatFallbackDefinedAndFallbackFunctionDefined =
|
148
|
+
(validationData as any)[fallback] !== undefined && (fallbackFunctions as any)[fallback] !== undefined;
|
149
|
+
|
150
|
+
if (wereArgumentsForThatFallbackDefinedAndFallbackFunctionDefined) {
|
151
|
+
const fallbackReturnType = (fallbackFunctions as any)[fallback](
|
152
|
+
(validationData as any)[fallback]
|
153
|
+
) as ValidationFallbackReturnType;
|
154
|
+
Validator.createAndAppendFallback(schema, fallbackReturnType);
|
155
|
+
}
|
156
|
+
};
|
157
|
+
|
158
|
+
const appendRootFallback = () => {
|
159
|
+
if (options.validatorsIfFallbackOrNotSupported) {
|
160
|
+
const validatorsIfFallbackOrNotSupported = Array.isArray(options.validatorsIfFallbackOrNotSupported)
|
161
|
+
? options.validatorsIfFallbackOrNotSupported
|
162
|
+
: [options.validatorsIfFallbackOrNotSupported];
|
163
|
+
for (const fallback of validatorsIfFallbackOrNotSupported) Validator.createAndAppendFallback(schema, fallback);
|
164
|
+
}
|
165
|
+
};
|
166
|
+
|
167
|
+
const hasFallbacks = schemaWithPrivateFields.__rootFallbacksValidator instanceof Validator;
|
168
|
+
const isFieldAdapterNotSupportedForThatFieldType = fieldAdapter === undefined;
|
169
|
+
|
170
|
+
if (hasFallbacks) {
|
171
|
+
Validator.createAndAppendFallback(schema, optional(schemaWithPrivateFields.__optional));
|
172
|
+
Validator.createAndAppendFallback(schema, nullable(schemaWithPrivateFields.__nullable));
|
173
|
+
Validator.createAndAppendFallback(schema, checkType(schemaWithPrivateFields.__type));
|
174
|
+
}
|
175
|
+
|
176
|
+
if (options.fallbackIfNotSupported !== undefined && isFieldAdapterNotSupportedForThatFieldType) {
|
177
|
+
const existingFallbacks = Object.keys(fallbackFunctions) as Parameters<
|
178
|
+
WithFallback<SupportedSchemas>['fallbackFor']['add']
|
179
|
+
>[0][];
|
180
|
+
const allParsers = Object.keys(validationData['parsers']) as Parameters<WithFallback<SupportedSchemas>['fallbackFor']['add']>[0][];
|
181
|
+
|
182
|
+
appendRootFallback();
|
183
|
+
|
184
|
+
for (const fallback of existingFallbacks) checkIfShouldAppendFallbackAndAppend(fallback);
|
185
|
+
for (const parser of allParsers) checkIfShouldUseParserAndAppend(parser);
|
186
|
+
return options.fallbackIfNotSupported();
|
187
|
+
}
|
188
|
+
if (!fieldAdapter) throw new Error('The field adapter is not supported and no fallback was provided.');
|
189
|
+
|
190
|
+
const translatedSchemaOrWithFallback = (await Promise.resolve(
|
191
|
+
fieldAdapter.translate(adapter.field, {
|
192
|
+
withFallback: withFallbackFactory<SupportedSchemas>(type),
|
193
|
+
...validationData,
|
194
|
+
})
|
195
|
+
));
|
196
|
+
|
197
|
+
let stringVersion = '';
|
198
|
+
if (options.shouldAddStringVersion)
|
199
|
+
stringVersion = await fieldAdapter.toString(adapter, adapter.field, validationDataForStringVersion);
|
200
|
+
|
201
|
+
if (translatedSchemaOrWithFallback instanceof WithFallback) {
|
202
|
+
appendRootFallback();
|
203
|
+
for (const fallback of translatedSchemaOrWithFallback.fallbackFor) {
|
204
|
+
checkIfShouldAppendFallbackAndAppend(fallback);
|
205
|
+
checkIfShouldUseParserAndAppend(fallback);
|
206
|
+
}
|
207
|
+
|
208
|
+
const [extendedOrNotSchema, extendedOrNotSchemaString] = getExtendedOrNotSchemaAndString(
|
209
|
+
translatedSchemaOrWithFallback.transformedSchema,
|
210
|
+
stringVersion
|
211
|
+
);
|
212
|
+
|
213
|
+
return [
|
214
|
+
{
|
215
|
+
transformed: extendedOrNotSchema,
|
216
|
+
asString: extendedOrNotSchemaString,
|
217
|
+
},
|
218
|
+
];
|
219
|
+
}
|
220
|
+
|
221
|
+
const [extendedOrNotSchema, extendedOrNotSchemaString] = getExtendedOrNotSchemaAndString(
|
222
|
+
translatedSchemaOrWithFallback,
|
223
|
+
stringVersion
|
224
|
+
);
|
225
|
+
|
226
|
+
return [
|
227
|
+
{
|
228
|
+
transformed: extendedOrNotSchema,
|
229
|
+
asString: extendedOrNotSchemaString,
|
230
|
+
},
|
231
|
+
];
|
232
|
+
}
|
233
|
+
|
234
|
+
/**
|
235
|
+
* This function is used to transform the schema to the adapter. By default it caches the transformed schemas on the schema instance. So on subsequent validations we don't need
|
236
|
+
* to transform to the schema again.
|
237
|
+
*/
|
238
|
+
export async function defaultTransformToAdapter(
|
239
|
+
callback: (adapter: SchemaAdapter) => ReturnType<FieldAdapter['translate']>,
|
240
|
+
transformedSchemas: Schema['__transformedSchemas'],
|
241
|
+
options: Parameters<Schema['__transformToAdapter']>[0],
|
242
|
+
type: string
|
243
|
+
) {
|
244
|
+
const schemaAdapterNameToUse = options.schemaAdapter?.constructor.name || Object.keys(transformedSchemas)[0];
|
245
|
+
const isACustomSchemaAdapterAndNotYetDefined =
|
246
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
247
|
+
transformedSchemas[schemaAdapterNameToUse] === undefined && options.schemaAdapter !== undefined;
|
248
|
+
|
249
|
+
if (isACustomSchemaAdapterAndNotYetDefined)
|
250
|
+
transformedSchemas[schemaAdapterNameToUse] = {
|
251
|
+
transformed: false,
|
252
|
+
adapter: options.schemaAdapter as SchemaAdapter,
|
253
|
+
schemas: [],
|
254
|
+
};
|
255
|
+
|
256
|
+
const shouldTranslate = transformedSchemas[schemaAdapterNameToUse].transformed === false || options.force === true;
|
257
|
+
|
258
|
+
if (shouldTranslate) {
|
259
|
+
const translatedSchemas = await callback(transformedSchemas[schemaAdapterNameToUse].adapter);
|
260
|
+
transformedSchemas[schemaAdapterNameToUse].schemas = translatedSchemas;
|
261
|
+
transformedSchemas[schemaAdapterNameToUse].transformed = true;
|
262
|
+
}
|
263
|
+
transformedSchemas[schemaAdapterNameToUse].transformed = true;
|
264
|
+
|
265
|
+
return transformedSchemas[schemaAdapterNameToUse].schemas;
|
266
|
+
}
|
267
|
+
|
268
|
+
export async function formatErrorFromParseMethod(
|
269
|
+
adapter: SchemaAdapter,
|
270
|
+
fieldAdapter: FieldAdapter,
|
271
|
+
error: any,
|
272
|
+
path: ValidationFallbackCallbackReturnType['errors'][number]['path'],
|
273
|
+
errorsAsHashedSet: Set<string>
|
274
|
+
) {
|
275
|
+
const formattedError = await fieldAdapter.formatError(adapter, fieldAdapter, error);
|
276
|
+
formattedError.path = Array.isArray(formattedError.path) ? [...path, ...formattedError.path] : path;
|
277
|
+
const formattedErrorAsParseResultError =
|
278
|
+
formattedError as unknown as ValidationFallbackCallbackReturnType['errors'][number];
|
279
|
+
formattedErrorAsParseResultError.isValid = false;
|
280
|
+
errorsAsHashedSet.add(JSON.stringify(formattedErrorAsParseResultError));
|
281
|
+
return formattedErrorAsParseResultError;
|
282
|
+
}
|
283
|
+
|
284
|
+
/**
|
285
|
+
* Transform the schema and check if we should add a fallback validation for that schema. This is used for complex schemas like Objects, arrays, unions, etc.
|
286
|
+
*/
|
287
|
+
export async function transformSchemaAndCheckIfShouldBeHandledByFallbackOnComplexSchemas(
|
288
|
+
schema: Schema,
|
289
|
+
options: Parameters<Schema['__transformToAdapter']>[0]
|
290
|
+
) {
|
291
|
+
const schemaWithProtected = schema as Schema & {
|
292
|
+
__runBeforeParseAndData: Schema['__runBeforeParseAndData']
|
293
|
+
__toInternal: Schema['__toInternal'];
|
294
|
+
__toValidate: Schema['__toValidate'];
|
295
|
+
__toRepresentation: Schema['__toRepresentation'];
|
296
|
+
__defaultFunction: Schema['__defaultFunction'];
|
297
|
+
__rootFallbacksValidator: Schema['__rootFallbacksValidator'];
|
298
|
+
__transformToAdapter: Schema['__transformToAdapter'];
|
299
|
+
__parsers: Schema['__parsers'];
|
300
|
+
};
|
301
|
+
|
302
|
+
const transformedData = await schemaWithProtected.__transformToAdapter(options); // This should come first because we will get the fallbacks of the field here.
|
303
|
+
|
304
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
305
|
+
const doesKeyHaveFallback = schemaWithProtected.__rootFallbacksValidator !== undefined;
|
306
|
+
const doesKeyHaveToInternal = typeof schemaWithProtected.__toInternal === 'function';
|
307
|
+
const doesKeyHaveToValidate = typeof schemaWithProtected.__toValidate === 'function';
|
308
|
+
const doesKeyHaveToDefault = typeof schemaWithProtected.__defaultFunction === 'function';
|
309
|
+
const doesKeyHaveRunBeforeParseAndData = typeof schemaWithProtected.__runBeforeParseAndData === 'function';
|
310
|
+
const doesKeyHaveParserFallback = schemaWithProtected.__parsers._fallbacks.size > 0;
|
311
|
+
const shouldAddFallbackValidation =
|
312
|
+
doesKeyHaveFallback ||
|
313
|
+
doesKeyHaveToInternal ||
|
314
|
+
doesKeyHaveToValidate ||
|
315
|
+
doesKeyHaveToDefault ||
|
316
|
+
doesKeyHaveParserFallback ||
|
317
|
+
doesKeyHaveRunBeforeParseAndData ||
|
318
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
319
|
+
transformedData === undefined;
|
320
|
+
|
321
|
+
return [transformedData, shouldAddFallbackValidation] as const;
|
322
|
+
}
|
@@ -0,0 +1,164 @@
|
|
1
|
+
import type ArraySchema from '../schema/array';
|
2
|
+
import type Schema from '../schema/schema';
|
3
|
+
import type { ValidationFallbackCallbackReturnType, ValidationFallbackReturnType } from '../schema/types';
|
4
|
+
|
5
|
+
export function arrayValidation(isTuple: boolean, schemas: Schema<any, any>[]): ValidationFallbackReturnType {
|
6
|
+
return {
|
7
|
+
type: 'medium',
|
8
|
+
callback: async (value: any, path: (string | number)[], options: Parameters<Schema['__transformToAdapter']>[0]) => {
|
9
|
+
const isNotAnArray = Array.isArray(value) === false;
|
10
|
+
if (isNotAnArray)
|
11
|
+
return {
|
12
|
+
parsed: value,
|
13
|
+
preventChildValidation: true,
|
14
|
+
errors: [
|
15
|
+
{
|
16
|
+
isValid: false,
|
17
|
+
code: 'array',
|
18
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
19
|
+
path: path || [],
|
20
|
+
message: 'The value must be an array. Received: ' + typeof value,
|
21
|
+
},
|
22
|
+
],
|
23
|
+
};
|
24
|
+
if (isTuple && value.length !== schemas.length)
|
25
|
+
return {
|
26
|
+
parsed: value,
|
27
|
+
preventChildValidation: true,
|
28
|
+
errors: [
|
29
|
+
{
|
30
|
+
isValid: false,
|
31
|
+
code: 'tuple',
|
32
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
33
|
+
path: path || [],
|
34
|
+
message: 'The tuple must have exactly ' + schemas.length + ' elements. Received: ' + value.length,
|
35
|
+
},
|
36
|
+
],
|
37
|
+
};
|
38
|
+
|
39
|
+
const errorsOfArray: ValidationFallbackCallbackReturnType['errors'] = [];
|
40
|
+
|
41
|
+
// To speed things up, we can do a simple type check, if the value is of type number and number is on index 1, and on index 0 is a string,
|
42
|
+
// if the value is a number we can skip checking at index 0.
|
43
|
+
const schemaIndexByTypeof = new Map<string, number>();
|
44
|
+
let parsedValues: any[] = [];
|
45
|
+
parsedValues = await Promise.all(
|
46
|
+
value.map(async (element, index) => {
|
47
|
+
let errorsToAppendAfterLoopIfNoSchemaMatched: ValidationFallbackCallbackReturnType['errors'] = [];
|
48
|
+
const typeofElement = typeof element;
|
49
|
+
const schemaIndex = schemaIndexByTypeof.get(typeofElement);
|
50
|
+
const existsASchemaIndex = typeof schemaIndex === 'number';
|
51
|
+
|
52
|
+
const schemasToValidateAgainst = isTuple
|
53
|
+
? [schemas[index]]
|
54
|
+
: existsASchemaIndex
|
55
|
+
? [schemas[schemaIndex]]
|
56
|
+
: schemas;
|
57
|
+
|
58
|
+
for (let indexOfSchema = 0; indexOfSchema < schemasToValidateAgainst.length; indexOfSchema++) {
|
59
|
+
const schemaToValidate = schemasToValidateAgainst[indexOfSchema];
|
60
|
+
const schemaWithProtected = schemaToValidate as Schema & {
|
61
|
+
__parse: Schema['__parse'];
|
62
|
+
__toInternal: Schema['__toInternal'];
|
63
|
+
};
|
64
|
+
const { parsed, errors } = await schemaWithProtected.__parse(element, [...path, index], options);
|
65
|
+
|
66
|
+
if (schemaWithProtected.__toInternal && options.toInternalToBubbleUp)
|
67
|
+
options.toInternalToBubbleUp.push(async () => (parsedValues[indexOfSchema] = await schemaWithProtected.__toInternal?.(parsed)));
|
68
|
+
|
69
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
70
|
+
if ((errors || []).length <= 0) {
|
71
|
+
errorsToAppendAfterLoopIfNoSchemaMatched = [];
|
72
|
+
schemaIndexByTypeof.set(typeofElement, indexOfSchema);
|
73
|
+
return parsed;
|
74
|
+
}
|
75
|
+
errorsToAppendAfterLoopIfNoSchemaMatched.push(...errors);
|
76
|
+
}
|
77
|
+
|
78
|
+
errorsOfArray.push(...errorsToAppendAfterLoopIfNoSchemaMatched);
|
79
|
+
return element;
|
80
|
+
})
|
81
|
+
);
|
82
|
+
|
83
|
+
return {
|
84
|
+
parsed: parsedValues,
|
85
|
+
errors: errorsOfArray,
|
86
|
+
};
|
87
|
+
},
|
88
|
+
};
|
89
|
+
}
|
90
|
+
|
91
|
+
export function minLength(args: ArraySchema['__minLength']): ValidationFallbackReturnType {
|
92
|
+
return {
|
93
|
+
type: 'low',
|
94
|
+
// eslint-disable-next-line ts/require-await
|
95
|
+
callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
|
96
|
+
const isValid = args.inclusive ? value.length >= args.value : value.length > args.value;
|
97
|
+
|
98
|
+
return {
|
99
|
+
parsed: value,
|
100
|
+
errors: isValid
|
101
|
+
? []
|
102
|
+
: [
|
103
|
+
{
|
104
|
+
isValid: false,
|
105
|
+
code: 'minLength',
|
106
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
107
|
+
path: path || [],
|
108
|
+
message: args.message,
|
109
|
+
},
|
110
|
+
],
|
111
|
+
};
|
112
|
+
},
|
113
|
+
};
|
114
|
+
}
|
115
|
+
|
116
|
+
export function maxLength(args: ArraySchema['__maxLength']): ValidationFallbackReturnType {
|
117
|
+
return {
|
118
|
+
type: 'low',
|
119
|
+
// eslint-disable-next-line ts/require-await
|
120
|
+
callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
|
121
|
+
const isValid = args.inclusive ? value.length <= args.value : value.length < args.value;
|
122
|
+
|
123
|
+
return {
|
124
|
+
parsed: value,
|
125
|
+
errors: isValid
|
126
|
+
? []
|
127
|
+
: [
|
128
|
+
{
|
129
|
+
isValid: false,
|
130
|
+
code: 'maxLength',
|
131
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
132
|
+
path: path || [],
|
133
|
+
message: args.message,
|
134
|
+
},
|
135
|
+
],
|
136
|
+
};
|
137
|
+
},
|
138
|
+
};
|
139
|
+
}
|
140
|
+
|
141
|
+
export function nonEmpty(args: ArraySchema['__nonEmpty']): ValidationFallbackReturnType {
|
142
|
+
return {
|
143
|
+
type: 'low',
|
144
|
+
// eslint-disable-next-line ts/require-await
|
145
|
+
callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
|
146
|
+
const isValid = value.length > 0;
|
147
|
+
|
148
|
+
return {
|
149
|
+
parsed: value,
|
150
|
+
errors: isValid
|
151
|
+
? []
|
152
|
+
: [
|
153
|
+
{
|
154
|
+
isValid: false,
|
155
|
+
code: 'nonEmpty',
|
156
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
157
|
+
path: path || [],
|
158
|
+
message: args.message,
|
159
|
+
},
|
160
|
+
],
|
161
|
+
};
|
162
|
+
},
|
163
|
+
};
|
164
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import type Schema from '../schema/schema';
|
2
|
+
import type { ValidationFallbackReturnType } from '../schema/types';
|
3
|
+
|
4
|
+
export function booleanValidation(): ValidationFallbackReturnType {
|
5
|
+
return {
|
6
|
+
type: 'medium',
|
7
|
+
// eslint-disable-next-line ts/require-await
|
8
|
+
callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
|
9
|
+
const isValid = typeof value === 'boolean';
|
10
|
+
|
11
|
+
return {
|
12
|
+
parsed: value,
|
13
|
+
errors: isValid
|
14
|
+
? []
|
15
|
+
: [
|
16
|
+
{
|
17
|
+
isValid: false,
|
18
|
+
code: 'boolean',
|
19
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
20
|
+
path: path || [],
|
21
|
+
message: 'Value is not a boolean',
|
22
|
+
},
|
23
|
+
],
|
24
|
+
preventChildValidation: true,
|
25
|
+
};
|
26
|
+
},
|
27
|
+
};
|
28
|
+
}
|
29
|
+
|
30
|
+
export function allowStringParser(): ValidationFallbackReturnType {
|
31
|
+
return {
|
32
|
+
type: 'high',
|
33
|
+
// eslint-disable-next-line ts/require-await
|
34
|
+
callback: async (
|
35
|
+
value: any,
|
36
|
+
_path: (string | number)[],
|
37
|
+
_options: Parameters<Schema['__transformToAdapter']>[0]
|
38
|
+
) => {
|
39
|
+
const parsed = Boolean(value);
|
40
|
+
return {
|
41
|
+
parsed: parsed,
|
42
|
+
errors: [],
|
43
|
+
};
|
44
|
+
},
|
45
|
+
};
|
46
|
+
}
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import type DatetimeSchema from '../schema/datetime';
|
2
|
+
import type Schema from '../schema/schema';
|
3
|
+
import type { ValidationFallbackReturnType } from '../schema/types';
|
4
|
+
|
5
|
+
export function datetimeValidation(): ValidationFallbackReturnType {
|
6
|
+
return {
|
7
|
+
type: 'medium',
|
8
|
+
// eslint-disable-next-line ts/require-await
|
9
|
+
callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
|
10
|
+
const isValid = value instanceof Date && !isNaN(value.getTime());
|
11
|
+
|
12
|
+
return {
|
13
|
+
parsed: value,
|
14
|
+
errors: isValid
|
15
|
+
? []
|
16
|
+
: [
|
17
|
+
{
|
18
|
+
isValid: false,
|
19
|
+
code: 'datetime',
|
20
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
21
|
+
path: path || [],
|
22
|
+
message: 'Value is not a date',
|
23
|
+
},
|
24
|
+
],
|
25
|
+
preventChildValidation: true,
|
26
|
+
};
|
27
|
+
},
|
28
|
+
};
|
29
|
+
}
|
30
|
+
|
31
|
+
export function allowStringParser(): ValidationFallbackReturnType {
|
32
|
+
return {
|
33
|
+
type: 'high',
|
34
|
+
// eslint-disable-next-line ts/require-await
|
35
|
+
callback: async (
|
36
|
+
value: any,
|
37
|
+
_path: (string | number)[],
|
38
|
+
_options: Parameters<Schema['__transformToAdapter']>[0]
|
39
|
+
) => {
|
40
|
+
if (typeof value === 'string') {
|
41
|
+
const parsed = new Date(value);
|
42
|
+
if (parsed instanceof Date && !isNaN(parsed.getTime())) {
|
43
|
+
return {
|
44
|
+
parsed: parsed,
|
45
|
+
errors: [],
|
46
|
+
};
|
47
|
+
}
|
48
|
+
}
|
49
|
+
return {
|
50
|
+
parsed: value,
|
51
|
+
errors: [],
|
52
|
+
};
|
53
|
+
},
|
54
|
+
};
|
55
|
+
}
|
56
|
+
|
57
|
+
export function below(args: DatetimeSchema['__below']): ValidationFallbackReturnType {
|
58
|
+
return {
|
59
|
+
type: 'low',
|
60
|
+
// eslint-disable-next-line ts/require-await
|
61
|
+
callback: async (
|
62
|
+
value: any,
|
63
|
+
path: (string | number)[],
|
64
|
+
_options: Parameters<Schema['__transformToAdapter']>[0]
|
65
|
+
) => {
|
66
|
+
const isValid = args.inclusive ? value <= args.value : value < args.value;
|
67
|
+
|
68
|
+
return {
|
69
|
+
parsed: value,
|
70
|
+
errors: isValid
|
71
|
+
? []
|
72
|
+
: [
|
73
|
+
{
|
74
|
+
isValid: false,
|
75
|
+
code: 'below',
|
76
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
77
|
+
path: path || [],
|
78
|
+
message: args.message,
|
79
|
+
},
|
80
|
+
],
|
81
|
+
};
|
82
|
+
},
|
83
|
+
};
|
84
|
+
}
|
85
|
+
|
86
|
+
export function above(args: DatetimeSchema['__above']): ValidationFallbackReturnType {
|
87
|
+
return {
|
88
|
+
type: 'low',
|
89
|
+
// eslint-disable-next-line ts/require-await
|
90
|
+
callback: async (
|
91
|
+
value: any,
|
92
|
+
path: (string | number)[],
|
93
|
+
_options: Parameters<Schema['__transformToAdapter']>[0]
|
94
|
+
) => {
|
95
|
+
const isValid = args.inclusive ? value <= args.value : value < args.value;
|
96
|
+
|
97
|
+
return {
|
98
|
+
parsed: value,
|
99
|
+
errors: isValid
|
100
|
+
? []
|
101
|
+
: [
|
102
|
+
{
|
103
|
+
isValid: false,
|
104
|
+
code: 'above',
|
105
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
106
|
+
path: path || [],
|
107
|
+
message: args.message,
|
108
|
+
},
|
109
|
+
],
|
110
|
+
};
|
111
|
+
},
|
112
|
+
};
|
113
|
+
}
|