@palmares/schemas 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/.turbo/turbo-build$colon$watch.log +12 -410
  2. package/CHANGELOG.md +17 -0
  3. package/__tests__/.drizzle/migrations/0000_skinny_harrier.sql +22 -0
  4. package/__tests__/.drizzle/migrations/meta/0000_snapshot.json +156 -0
  5. package/__tests__/.drizzle/migrations/meta/_journal.json +13 -0
  6. package/__tests__/.drizzle/schema.ts +35 -0
  7. package/__tests__/drizzle.config.ts +11 -0
  8. package/__tests__/eslint.config.js +10 -0
  9. package/__tests__/manage.ts +5 -0
  10. package/__tests__/node_modules/.bin/drizzle-kit +17 -0
  11. package/__tests__/node_modules/.bin/esbuild +14 -0
  12. package/__tests__/node_modules/.bin/tsc +17 -0
  13. package/__tests__/node_modules/.bin/tsserver +17 -0
  14. package/__tests__/node_modules/.bin/tsx +17 -0
  15. package/__tests__/package.json +36 -0
  16. package/__tests__/sqlite.db +0 -0
  17. package/__tests__/src/core/array.test.ts +130 -0
  18. package/__tests__/src/core/boolean.test.ts +66 -0
  19. package/__tests__/src/core/datetime.test.ts +102 -0
  20. package/__tests__/src/core/index.ts +35 -0
  21. package/__tests__/src/core/model.test.ts +260 -0
  22. package/__tests__/src/core/models.ts +50 -0
  23. package/__tests__/src/core/numbers.test.ts +177 -0
  24. package/__tests__/src/core/object.test.ts +198 -0
  25. package/__tests__/src/core/string.test.ts +222 -0
  26. package/__tests__/src/core/test.test.ts +59 -0
  27. package/__tests__/src/core/types.test.ts +97 -0
  28. package/__tests__/src/core/union.test.ts +99 -0
  29. package/__tests__/src/settings.ts +71 -0
  30. package/__tests__/tsconfig.json +11 -0
  31. package/dist/cjs/src/adapter/fields/index.js +2 -2
  32. package/dist/cjs/src/adapter/fields/object.js +9 -0
  33. package/dist/cjs/src/adapter/index.js +1 -0
  34. package/dist/cjs/src/constants.js +1 -7
  35. package/dist/cjs/src/domain.js +146 -1
  36. package/dist/cjs/src/index.js +69 -74
  37. package/dist/cjs/src/model.js +206 -206
  38. package/dist/cjs/src/schema/array.js +185 -58
  39. package/dist/cjs/src/schema/boolean.js +105 -44
  40. package/dist/cjs/src/schema/datetime.js +104 -38
  41. package/dist/cjs/src/schema/number.js +134 -114
  42. package/dist/cjs/src/schema/object.js +106 -43
  43. package/dist/cjs/src/schema/schema.js +123 -75
  44. package/dist/cjs/src/schema/string.js +152 -58
  45. package/dist/cjs/src/schema/union.js +412 -290
  46. package/dist/cjs/src/utils.js +42 -15
  47. package/dist/cjs/src/validators/array.js +6 -1
  48. package/dist/cjs/src/validators/boolean.js +2 -0
  49. package/dist/cjs/src/validators/datetime.js +4 -0
  50. package/dist/cjs/src/validators/number.js +12 -40
  51. package/dist/cjs/src/validators/object.js +1 -0
  52. package/dist/cjs/src/validators/schema.js +5 -1
  53. package/dist/cjs/src/validators/string.js +30 -2
  54. package/dist/cjs/src/validators/union.js +5 -4
  55. package/dist/cjs/src/validators/utils.js +99 -27
  56. package/dist/cjs/tsconfig.types.tsbuildinfo +1 -1
  57. package/dist/cjs/types/adapter/fields/array.d.ts +2 -2
  58. package/dist/cjs/types/adapter/fields/array.d.ts.map +1 -1
  59. package/dist/cjs/types/adapter/fields/boolean.d.ts.map +1 -1
  60. package/dist/cjs/types/adapter/fields/datetime.d.ts.map +1 -1
  61. package/dist/cjs/types/adapter/fields/index.d.ts +2 -2
  62. package/dist/cjs/types/adapter/fields/index.d.ts.map +1 -1
  63. package/dist/cjs/types/adapter/fields/number.d.ts.map +1 -1
  64. package/dist/cjs/types/adapter/fields/object.d.ts +2 -1
  65. package/dist/cjs/types/adapter/fields/object.d.ts.map +1 -1
  66. package/dist/cjs/types/adapter/fields/string.d.ts.map +1 -1
  67. package/dist/cjs/types/adapter/fields/union.d.ts.map +1 -1
  68. package/dist/cjs/types/adapter/index.d.ts +1 -0
  69. package/dist/cjs/types/adapter/index.d.ts.map +1 -1
  70. package/dist/cjs/types/adapter/types.d.ts +28 -18
  71. package/dist/cjs/types/adapter/types.d.ts.map +1 -1
  72. package/dist/cjs/types/constants.d.ts +0 -1
  73. package/dist/cjs/types/constants.d.ts.map +1 -1
  74. package/dist/cjs/types/domain.d.ts +5 -4
  75. package/dist/cjs/types/domain.d.ts.map +1 -1
  76. package/dist/cjs/types/index.d.ts +78 -55
  77. package/dist/cjs/types/index.d.ts.map +1 -1
  78. package/dist/cjs/types/model.d.ts +17 -17
  79. package/dist/cjs/types/model.d.ts.map +1 -1
  80. package/dist/cjs/types/schema/array.d.ts +168 -47
  81. package/dist/cjs/types/schema/array.d.ts.map +1 -1
  82. package/dist/cjs/types/schema/boolean.d.ts +103 -44
  83. package/dist/cjs/types/schema/boolean.d.ts.map +1 -1
  84. package/dist/cjs/types/schema/datetime.d.ts +90 -30
  85. package/dist/cjs/types/schema/datetime.d.ts.map +1 -1
  86. package/dist/cjs/types/schema/number.d.ts +133 -125
  87. package/dist/cjs/types/schema/number.d.ts.map +1 -1
  88. package/dist/cjs/types/schema/object.d.ts +104 -35
  89. package/dist/cjs/types/schema/object.d.ts.map +1 -1
  90. package/dist/cjs/types/schema/schema.d.ts +62 -44
  91. package/dist/cjs/types/schema/schema.d.ts.map +1 -1
  92. package/dist/cjs/types/schema/string.d.ts +152 -65
  93. package/dist/cjs/types/schema/string.d.ts.map +1 -1
  94. package/dist/cjs/types/schema/types.d.ts +11 -2
  95. package/dist/cjs/types/schema/types.d.ts.map +1 -1
  96. package/dist/cjs/types/schema/union.d.ts +133 -40
  97. package/dist/cjs/types/schema/union.d.ts.map +1 -1
  98. package/dist/cjs/types/types.d.ts +35 -0
  99. package/dist/cjs/types/types.d.ts.map +1 -1
  100. package/dist/cjs/types/utils.d.ts +41 -27
  101. package/dist/cjs/types/utils.d.ts.map +1 -1
  102. package/dist/cjs/types/validators/array.d.ts.map +1 -1
  103. package/dist/cjs/types/validators/boolean.d.ts.map +1 -1
  104. package/dist/cjs/types/validators/datetime.d.ts.map +1 -1
  105. package/dist/cjs/types/validators/number.d.ts +5 -6
  106. package/dist/cjs/types/validators/number.d.ts.map +1 -1
  107. package/dist/cjs/types/validators/object.d.ts.map +1 -1
  108. package/dist/cjs/types/validators/schema.d.ts +2 -2
  109. package/dist/cjs/types/validators/schema.d.ts.map +1 -1
  110. package/dist/cjs/types/validators/string.d.ts +9 -9
  111. package/dist/cjs/types/validators/string.d.ts.map +1 -1
  112. package/dist/cjs/types/validators/utils.d.ts +44 -27
  113. package/dist/cjs/types/validators/utils.d.ts.map +1 -1
  114. package/dist/esm/src/adapter/fields/index.js +2 -2
  115. package/dist/esm/src/adapter/fields/object.js +6 -0
  116. package/dist/esm/src/adapter/index.js +1 -0
  117. package/dist/esm/src/constants.js +1 -2
  118. package/dist/esm/src/domain.js +11 -1
  119. package/dist/esm/src/index.js +38 -73
  120. package/dist/esm/src/model.js +83 -78
  121. package/dist/esm/src/schema/array.js +136 -54
  122. package/dist/esm/src/schema/boolean.js +98 -44
  123. package/dist/esm/src/schema/datetime.js +91 -38
  124. package/dist/esm/src/schema/number.js +127 -110
  125. package/dist/esm/src/schema/object.js +98 -43
  126. package/dist/esm/src/schema/schema.js +102 -67
  127. package/dist/esm/src/schema/string.js +147 -59
  128. package/dist/esm/src/schema/union.js +119 -40
  129. package/dist/esm/src/types.js +14 -1
  130. package/dist/esm/src/utils.js +56 -27
  131. package/dist/esm/src/validators/array.js +6 -1
  132. package/dist/esm/src/validators/boolean.js +2 -0
  133. package/dist/esm/src/validators/datetime.js +4 -0
  134. package/dist/esm/src/validators/number.js +9 -23
  135. package/dist/esm/src/validators/object.js +1 -0
  136. package/dist/esm/src/validators/schema.js +5 -1
  137. package/dist/esm/src/validators/string.js +30 -2
  138. package/dist/esm/src/validators/union.js +5 -4
  139. package/dist/esm/src/validators/utils.js +62 -36
  140. package/package.json +3 -3
  141. package/src/adapter/fields/array.ts +2 -2
  142. package/src/adapter/fields/boolean.ts +3 -8
  143. package/src/adapter/fields/datetime.ts +3 -9
  144. package/src/adapter/fields/index.ts +11 -11
  145. package/src/adapter/fields/number.ts +3 -9
  146. package/src/adapter/fields/object.ts +13 -10
  147. package/src/adapter/fields/string.ts +3 -9
  148. package/src/adapter/fields/union.ts +3 -9
  149. package/src/adapter/index.ts +1 -0
  150. package/src/adapter/types.ts +60 -45
  151. package/src/constants.ts +1 -3
  152. package/src/domain.ts +15 -1
  153. package/src/index.ts +189 -211
  154. package/src/model.ts +119 -115
  155. package/src/schema/array.ts +274 -90
  156. package/src/schema/boolean.ts +145 -60
  157. package/src/schema/datetime.ts +133 -49
  158. package/src/schema/number.ts +210 -173
  159. package/src/schema/object.ts +167 -74
  160. package/src/schema/schema.ts +205 -126
  161. package/src/schema/string.ts +221 -94
  162. package/src/schema/types.ts +44 -16
  163. package/src/schema/union.ts +193 -68
  164. package/src/types.ts +53 -0
  165. package/src/utils.ts +115 -57
  166. package/src/validators/array.ts +46 -27
  167. package/src/validators/boolean.ts +13 -7
  168. package/src/validators/datetime.ts +24 -16
  169. package/src/validators/number.ts +53 -63
  170. package/src/validators/object.ts +6 -5
  171. package/src/validators/schema.ts +33 -25
  172. package/src/validators/string.ts +122 -59
  173. package/src/validators/union.ts +8 -8
  174. package/src/validators/utils.ts +67 -42
package/src/utils.ts CHANGED
@@ -1,7 +1,8 @@
1
+ import SchemaAdapter from './adapter';
2
+ import { getDefaultAdapter } from './conf';
1
3
  import { checkType, nullable, optional } from './validators/schema';
2
4
  import Validator from './validators/utils';
3
5
 
4
- import type SchemaAdapter from './adapter';
5
6
  import type FieldAdapter from './adapter/fields';
6
7
  import type { ValidationDataBasedOnType } from './adapter/types';
7
8
  import type Schema from './schema/schema';
@@ -9,8 +10,9 @@ import type { ValidationFallbackCallbackReturnType, ValidationFallbackReturnType
9
10
  import type { FallbackFunctionsType, SupportedSchemas } from './types';
10
11
 
11
12
  /**
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.
13
+ * The usage of this is that imagine that the library doesn't support a specific feature that we support on
14
+ * our schema definition, it can return an instance of this class and with this instance we are able to
15
+ * fallback to our default implementation of the schema validation.
14
16
  */
15
17
  export default class WithFallback<TType extends SupportedSchemas> {
16
18
  fallbackFor: Set<
@@ -38,8 +40,9 @@ export default class WithFallback<TType extends SupportedSchemas> {
38
40
  }
39
41
 
40
42
  /**
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
+ * Factory function for creating a new instance of WithFallback. We call that function when parsing the
44
+ * schema adapter, and then, inside of the adapter the user will can the inner function to create a new
45
+ * instance of WithFallback.
43
46
  *
44
47
  * @param adapterType - The type of the adapter that we are using.
45
48
  *
@@ -68,18 +71,22 @@ export function parseErrorsFactory(schemaAdapter: SchemaAdapter) {
68
71
  }
69
72
 
70
73
  /**
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.
74
+ * The default transform function that we use for the schema adapters. This function tries to abstract away
75
+ * the complexity of translating the schema to the adapter.
72
76
  *
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.
77
+ * So first things first, WHAT IS a fallback? A fallback is a function that we call when the user defines a
78
+ * validation that is not supported by the adapter. For example, imagine that for some reason the adapter
79
+ * doesn't support the `max` validation, we can define a fallback for that validation and then, when the
80
+ * user defines that validation, we call the fallback function. So, even if the adapter doesn't support that
81
+ * validation our schema will still be able to validate that.
76
82
  *
77
- * @param type - The type of the adapter that we are using, can be a number, an object, all of the possible schema adapters.
83
+ * @param type - The type of the adapter that we are using, can be a number, an object, all of the possible
84
+ * schema adapters.
78
85
  * @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.
86
+ * @param validationData - The data that we are using to validate the schema. This means for example, the
87
+ * `max` validation, the `min` validation, etc. The message of the validation when it is not valid, etc.
88
+ * @param fallbackFunctions - The fallback functions that we are using to validate the schema. Those are
89
+ * the functions we fallback to when the user defines a validation that is not supported by the adapter.
83
90
  *
84
91
  * @returns - The translated schema for something that the adapter is able to understand.
85
92
  */
@@ -93,18 +100,23 @@ export async function defaultTransform<TType extends SupportedSchemas>(
93
100
  options: {
94
101
  validatorsIfFallbackOrNotSupported?: ValidationFallbackReturnType | ValidationFallbackReturnType[];
95
102
  /**
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.
103
+ * If the schema is not supported by the adapter, this means, that the adapter hasn't defined an adapter
104
+ * for that field type, we can fallback to a custom implementation.
97
105
  * The problem is that, for example: Unions,
98
106
  *
99
- * Let's say we have a schema like this: ObjectSchema.new({ age: UnionSchema.new([NumberSchema.new(), StringSchema.new()] )});
107
+ * Let's say we have a schema like this:
108
+ * ObjectSchema.new({ age: UnionSchema.new([NumberSchema.new(), StringSchema.new()] )});
100
109
  *
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.
110
+ * The root object will be validated by the adapter so what we need to do is create two schemas on the
111
+ * root object, one where the value of `age` key is a number and another where the value of `age` key is
112
+ * a string. Now the root object has two schemas memoized on __transformedSchemas, nice, what's the logic
113
+ * on that case? The ObjectSchema shouldn't take care of that logic. So the Union schema takes control of
114
+ * validating through the adapter. Is adapter 1 without errors? If yes, return the result, if not, try
115
+ * the second adapter. If the second adapter is without errors, return the result, if not, return the
116
+ * errors.
105
117
  *
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.
118
+ * In other words, the `fallbackIfNotSupported` function on Unions should return the two schemas saved on
119
+ * it on that case, that way the root ObjectSchema will create those two schemas on the array.
108
120
  */
109
121
  fallbackIfNotSupported?: () => ReturnType<Schema['__transformToAdapter']>;
110
122
  } & Pick<Parameters<Schema['__transformToAdapter']>[0], 'shouldAddStringVersion'>
@@ -124,22 +136,29 @@ export async function defaultTransform<TType extends SupportedSchemas>(
124
136
  __extends: Schema['__extends'];
125
137
  };
126
138
 
127
- const checkIfShouldUseParserAndAppend = (parser: Parameters<WithFallback<SupportedSchemas>['fallbackFor']['add']>[0]) => {
139
+ const checkIfShouldUseParserAndAppend = (
140
+ parser: Parameters<WithFallback<SupportedSchemas>['fallbackFor']['add']>[0]
141
+ ) => {
128
142
  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
- }
143
+ if (isValidationDataAParser)
144
+ (
145
+ schema as unknown as {
146
+ __parsers: Schema['__parsers'];
147
+ }
148
+ ).__parsers._fallbacks.add(parser);
149
+ };
133
150
 
134
151
  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;
152
+ const extendedOrNotSchema =
153
+ typeof schemaWithPrivateFields.__extends?.callback === 'function'
154
+ ? schemaWithPrivateFields.__extends.callback(schema)
155
+ : schema;
156
+ const extendedOrNotSchemaString =
157
+ typeof schemaWithPrivateFields.__extends?.toStringCallback === 'function'
158
+ ? schemaWithPrivateFields.__extends.toStringCallback(toStringVersion)
159
+ : toStringVersion;
141
160
  return [extendedOrNotSchema, extendedOrNotSchemaString];
142
- }
161
+ };
143
162
 
144
163
  const checkIfShouldAppendFallbackAndAppend = (
145
164
  fallback: Parameters<WithFallback<SupportedSchemas>['fallbackFor']['add']>[0]
@@ -160,39 +179,46 @@ export async function defaultTransform<TType extends SupportedSchemas>(
160
179
  const validatorsIfFallbackOrNotSupported = Array.isArray(options.validatorsIfFallbackOrNotSupported)
161
180
  ? options.validatorsIfFallbackOrNotSupported
162
181
  : [options.validatorsIfFallbackOrNotSupported];
182
+
163
183
  for (const fallback of validatorsIfFallbackOrNotSupported) Validator.createAndAppendFallback(schema, fallback);
164
184
  }
165
185
  };
166
186
 
167
- const hasFallbacks = schemaWithPrivateFields.__rootFallbacksValidator instanceof Validator;
168
- const isFieldAdapterNotSupportedForThatFieldType = fieldAdapter === undefined;
187
+ const appendRequiredFallbacks = () => {
188
+ const hasFallbacks = schemaWithPrivateFields.__rootFallbacksValidator instanceof Validator;
189
+ if (hasFallbacks) {
190
+ Validator.createAndAppendFallback(schema, optional(schemaWithPrivateFields.__optional));
191
+ Validator.createAndAppendFallback(schema, nullable(schemaWithPrivateFields.__nullable));
192
+ Validator.createAndAppendFallback(schema, checkType(schemaWithPrivateFields.__type));
193
+ }
194
+ };
169
195
 
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
- }
196
+ const isFieldAdapterNotSupportedForThatFieldType = fieldAdapter === undefined;
175
197
 
176
198
  if (options.fallbackIfNotSupported !== undefined && isFieldAdapterNotSupportedForThatFieldType) {
177
199
  const existingFallbacks = Object.keys(fallbackFunctions) as Parameters<
178
200
  WithFallback<SupportedSchemas>['fallbackFor']['add']
179
201
  >[0][];
180
- const allParsers = Object.keys(validationData['parsers']) as Parameters<WithFallback<SupportedSchemas>['fallbackFor']['add']>[0][];
202
+ const allParsers = Object.keys(validationData['parsers']) as Parameters<
203
+ WithFallback<SupportedSchemas>['fallbackFor']['add']
204
+ >[0][];
181
205
 
182
206
  appendRootFallback();
183
207
 
184
208
  for (const fallback of existingFallbacks) checkIfShouldAppendFallbackAndAppend(fallback);
185
209
  for (const parser of allParsers) checkIfShouldUseParserAndAppend(parser);
210
+ appendRequiredFallbacks();
211
+
186
212
  return options.fallbackIfNotSupported();
187
213
  }
188
214
  if (!fieldAdapter) throw new Error('The field adapter is not supported and no fallback was provided.');
189
215
 
190
- const translatedSchemaOrWithFallback = (await Promise.resolve(
216
+ const translatedSchemaOrWithFallback = await Promise.resolve(
191
217
  fieldAdapter.translate(adapter.field, {
192
218
  withFallback: withFallbackFactory<SupportedSchemas>(type),
193
- ...validationData,
219
+ ...validationData
194
220
  })
195
- ));
221
+ );
196
222
 
197
223
  let stringVersion = '';
198
224
  if (options.shouldAddStringVersion)
@@ -209,12 +235,13 @@ export async function defaultTransform<TType extends SupportedSchemas>(
209
235
  translatedSchemaOrWithFallback.transformedSchema,
210
236
  stringVersion
211
237
  );
238
+ appendRequiredFallbacks();
212
239
 
213
240
  return [
214
241
  {
215
242
  transformed: extendedOrNotSchema,
216
- asString: extendedOrNotSchemaString,
217
- },
243
+ asString: extendedOrNotSchemaString
244
+ }
218
245
  ];
219
246
  }
220
247
 
@@ -226,21 +253,33 @@ export async function defaultTransform<TType extends SupportedSchemas>(
226
253
  return [
227
254
  {
228
255
  transformed: extendedOrNotSchema,
229
- asString: extendedOrNotSchemaString,
230
- },
256
+ asString: extendedOrNotSchemaString
257
+ }
231
258
  ];
232
259
  }
233
260
 
234
261
  /**
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.
262
+ * This function is used to transform the schema to the adapter. By default it caches the transformed schemas on
263
+ * the schema instance. So on subsequent validations we don't need to transform to the schema again.
237
264
  */
238
265
  export async function defaultTransformToAdapter(
239
266
  callback: (adapter: SchemaAdapter) => ReturnType<FieldAdapter['translate']>,
267
+ schema: Schema<any, any>,
240
268
  transformedSchemas: Schema['__transformedSchemas'],
241
269
  options: Parameters<Schema['__transformToAdapter']>[0],
242
270
  type: string
243
271
  ) {
272
+ const isTransformedSchemasEmpty = Object.keys(transformedSchemas).length <= 0;
273
+ if (isTransformedSchemasEmpty) {
274
+ const adapterInstanceToUse =
275
+ options.schemaAdapter instanceof SchemaAdapter ? options.schemaAdapter : getDefaultAdapter();
276
+ schema['__transformedSchemas'][adapterInstanceToUse.constructor.name] = {
277
+ transformed: false,
278
+ adapter: adapterInstanceToUse,
279
+ schemas: []
280
+ };
281
+ }
282
+
244
283
  const schemaAdapterNameToUse = options.schemaAdapter?.constructor.name || Object.keys(transformedSchemas)[0];
245
284
  const isACustomSchemaAdapterAndNotYetDefined =
246
285
  // eslint-disable-next-line ts/no-unnecessary-condition
@@ -250,7 +289,7 @@ export async function defaultTransformToAdapter(
250
289
  transformedSchemas[schemaAdapterNameToUse] = {
251
290
  transformed: false,
252
291
  adapter: options.schemaAdapter as SchemaAdapter,
253
- schemas: [],
292
+ schemas: []
254
293
  };
255
294
 
256
295
  const shouldTranslate = transformedSchemas[schemaAdapterNameToUse].transformed === false || options.force === true;
@@ -269,27 +308,36 @@ export async function formatErrorFromParseMethod(
269
308
  adapter: SchemaAdapter,
270
309
  fieldAdapter: FieldAdapter,
271
310
  error: any,
311
+ received: any,
312
+ schema: any,
272
313
  path: ValidationFallbackCallbackReturnType['errors'][number]['path'],
273
314
  errorsAsHashedSet: Set<string>
274
315
  ) {
275
- const formattedError = await fieldAdapter.formatError(adapter, fieldAdapter, error);
316
+ const formattedError = await fieldAdapter.formatError(adapter, adapter.field, schema, error);
276
317
  formattedError.path = Array.isArray(formattedError.path) ? [...path, ...formattedError.path] : path;
318
+
277
319
  const formattedErrorAsParseResultError =
278
320
  formattedError as unknown as ValidationFallbackCallbackReturnType['errors'][number];
279
321
  formattedErrorAsParseResultError.isValid = false;
280
- errorsAsHashedSet.add(JSON.stringify(formattedErrorAsParseResultError));
322
+ const sortedError = Object.fromEntries(
323
+ Object.entries(formattedErrorAsParseResultError).sort(([a], [b]) => a.localeCompare(b))
324
+ );
325
+ const hashedError = JSON.stringify(sortedError);
326
+ errorsAsHashedSet.add(JSON.stringify(sortedError));
327
+ formattedErrorAsParseResultError.received = received;
281
328
  return formattedErrorAsParseResultError;
282
329
  }
283
330
 
284
331
  /**
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.
332
+ * Transform the schema and check if we should add a fallback validation for that schema. This is used for complex
333
+ * schemas like Objects, arrays, unions, etc.
286
334
  */
287
335
  export async function transformSchemaAndCheckIfShouldBeHandledByFallbackOnComplexSchemas(
288
336
  schema: Schema,
289
337
  options: Parameters<Schema['__transformToAdapter']>[0]
290
338
  ) {
291
339
  const schemaWithProtected = schema as Schema & {
292
- __runBeforeParseAndData: Schema['__runBeforeParseAndData']
340
+ __runBeforeParseAndData: Schema['__runBeforeParseAndData'];
293
341
  __toInternal: Schema['__toInternal'];
294
342
  __toValidate: Schema['__toValidate'];
295
343
  __toRepresentation: Schema['__toRepresentation'];
@@ -299,7 +347,8 @@ export async function transformSchemaAndCheckIfShouldBeHandledByFallbackOnComple
299
347
  __parsers: Schema['__parsers'];
300
348
  };
301
349
 
302
- const transformedData = await schemaWithProtected.__transformToAdapter(options); // This should come first because we will get the fallbacks of the field here.
350
+ // This should come first because we will get the fallbacks of the field here.
351
+ const transformedData = await schemaWithProtected.__transformToAdapter(options);
303
352
 
304
353
  // eslint-disable-next-line ts/no-unnecessary-condition
305
354
  const doesKeyHaveFallback = schemaWithProtected.__rootFallbacksValidator !== undefined;
@@ -320,3 +369,12 @@ export async function transformSchemaAndCheckIfShouldBeHandledByFallbackOnComple
320
369
 
321
370
  return [transformedData, shouldAddFallbackValidation] as const;
322
371
  }
372
+
373
+ export function shouldRunDataOnComplexSchemas(schema: Schema<any, any>) {
374
+ return (
375
+ typeof schema['__parsersToTransformValue'] === 'function' ||
376
+ typeof schema['__runBeforeParseAndData'] === 'function' ||
377
+ typeof schema['__toRepresentation'] === 'function' ||
378
+ typeof schema['__defaultFunction'] === 'function'
379
+ );
380
+ }
@@ -4,6 +4,7 @@ import type { ValidationFallbackCallbackReturnType, ValidationFallbackReturnType
4
4
 
5
5
  export function arrayValidation(isTuple: boolean, schemas: Schema<any, any>[]): ValidationFallbackReturnType {
6
6
  return {
7
+ name: 'array',
7
8
  type: 'medium',
8
9
  callback: async (value: any, path: (string | number)[], options: Parameters<Schema['__transformToAdapter']>[0]) => {
9
10
  const isNotAnArray = Array.isArray(value) === false;
@@ -17,9 +18,9 @@ export function arrayValidation(isTuple: boolean, schemas: Schema<any, any>[]):
17
18
  code: 'array',
18
19
  // eslint-disable-next-line ts/no-unnecessary-condition
19
20
  path: path || [],
20
- message: 'The value must be an array. Received: ' + typeof value,
21
- },
22
- ],
21
+ message: 'The value must be an array. Received: ' + typeof value
22
+ }
23
+ ]
23
24
  };
24
25
  if (isTuple && value.length !== schemas.length)
25
26
  return {
@@ -31,14 +32,15 @@ export function arrayValidation(isTuple: boolean, schemas: Schema<any, any>[]):
31
32
  code: 'tuple',
32
33
  // eslint-disable-next-line ts/no-unnecessary-condition
33
34
  path: path || [],
34
- message: 'The tuple must have exactly ' + schemas.length + ' elements. Received: ' + value.length,
35
- },
36
- ],
35
+ message: 'The tuple must have exactly ' + schemas.length + ' elements. Received: ' + value.length
36
+ }
37
+ ]
37
38
  };
38
39
 
39
40
  const errorsOfArray: ValidationFallbackCallbackReturnType['errors'] = [];
40
41
 
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
+ // To speed things up, we can do a simple type check, if the value is of type number and
43
+ // number is on index 1, and on index 0 is a string,
42
44
  // if the value is a number we can skip checking at index 0.
43
45
  const schemaIndexByTypeof = new Map<string, number>();
44
46
  let parsedValues: any[] = [];
@@ -52,8 +54,8 @@ export function arrayValidation(isTuple: boolean, schemas: Schema<any, any>[]):
52
54
  const schemasToValidateAgainst = isTuple
53
55
  ? [schemas[index]]
54
56
  : existsASchemaIndex
55
- ? [schemas[schemaIndex]]
56
- : schemas;
57
+ ? [schemas[schemaIndex]]
58
+ : schemas;
57
59
 
58
60
  for (let indexOfSchema = 0; indexOfSchema < schemasToValidateAgainst.length; indexOfSchema++) {
59
61
  const schemaToValidate = schemasToValidateAgainst[indexOfSchema];
@@ -64,7 +66,9 @@ export function arrayValidation(isTuple: boolean, schemas: Schema<any, any>[]):
64
66
  const { parsed, errors } = await schemaWithProtected.__parse(element, [...path, index], options);
65
67
 
66
68
  if (schemaWithProtected.__toInternal && options.toInternalToBubbleUp)
67
- options.toInternalToBubbleUp.push(async () => (parsedValues[indexOfSchema] = await schemaWithProtected.__toInternal?.(parsed)));
69
+ options.toInternalToBubbleUp.push(
70
+ async () => (parsedValues[indexOfSchema] = await schemaWithProtected.__toInternal?.(parsed))
71
+ );
68
72
 
69
73
  // eslint-disable-next-line ts/no-unnecessary-condition
70
74
  if ((errors || []).length <= 0) {
@@ -82,17 +86,22 @@ export function arrayValidation(isTuple: boolean, schemas: Schema<any, any>[]):
82
86
 
83
87
  return {
84
88
  parsed: parsedValues,
85
- errors: errorsOfArray,
89
+ errors: errorsOfArray
86
90
  };
87
- },
91
+ }
88
92
  };
89
93
  }
90
94
 
91
95
  export function minLength(args: ArraySchema['__minLength']): ValidationFallbackReturnType {
92
96
  return {
97
+ name: 'minLength',
93
98
  type: 'low',
94
99
  // eslint-disable-next-line ts/require-await
95
- callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
100
+ callback: async (
101
+ value: any,
102
+ path: (string | number)[],
103
+ _options: Parameters<Schema['__transformToAdapter']>[0]
104
+ ) => {
96
105
  const isValid = args.inclusive ? value.length >= args.value : value.length > args.value;
97
106
 
98
107
  return {
@@ -105,19 +114,24 @@ export function minLength(args: ArraySchema['__minLength']): ValidationFallbackR
105
114
  code: 'minLength',
106
115
  // eslint-disable-next-line ts/no-unnecessary-condition
107
116
  path: path || [],
108
- message: args.message,
109
- },
110
- ],
117
+ message: args.message
118
+ }
119
+ ]
111
120
  };
112
- },
121
+ }
113
122
  };
114
123
  }
115
124
 
116
125
  export function maxLength(args: ArraySchema['__maxLength']): ValidationFallbackReturnType {
117
126
  return {
127
+ name: 'maxLength',
118
128
  type: 'low',
119
129
  // eslint-disable-next-line ts/require-await
120
- callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
130
+ callback: async (
131
+ value: any,
132
+ path: (string | number)[],
133
+ _options: Parameters<Schema['__transformToAdapter']>[0]
134
+ ) => {
121
135
  const isValid = args.inclusive ? value.length <= args.value : value.length < args.value;
122
136
 
123
137
  return {
@@ -130,19 +144,24 @@ export function maxLength(args: ArraySchema['__maxLength']): ValidationFallbackR
130
144
  code: 'maxLength',
131
145
  // eslint-disable-next-line ts/no-unnecessary-condition
132
146
  path: path || [],
133
- message: args.message,
134
- },
135
- ],
147
+ message: args.message
148
+ }
149
+ ]
136
150
  };
137
- },
151
+ }
138
152
  };
139
153
  }
140
154
 
141
155
  export function nonEmpty(args: ArraySchema['__nonEmpty']): ValidationFallbackReturnType {
142
156
  return {
157
+ name: 'nonEmpty',
143
158
  type: 'low',
144
159
  // eslint-disable-next-line ts/require-await
145
- callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
160
+ callback: async (
161
+ value: any,
162
+ path: (string | number)[],
163
+ _options: Parameters<Schema['__transformToAdapter']>[0]
164
+ ) => {
146
165
  const isValid = value.length > 0;
147
166
 
148
167
  return {
@@ -155,10 +174,10 @@ export function nonEmpty(args: ArraySchema['__nonEmpty']): ValidationFallbackRet
155
174
  code: 'nonEmpty',
156
175
  // eslint-disable-next-line ts/no-unnecessary-condition
157
176
  path: path || [],
158
- message: args.message,
159
- },
160
- ],
177
+ message: args.message
178
+ }
179
+ ]
161
180
  };
162
- },
181
+ }
163
182
  };
164
183
  }
@@ -3,9 +3,14 @@ import type { ValidationFallbackReturnType } from '../schema/types';
3
3
 
4
4
  export function booleanValidation(): ValidationFallbackReturnType {
5
5
  return {
6
+ name: 'boolean',
6
7
  type: 'medium',
7
8
  // eslint-disable-next-line ts/require-await
8
- callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
9
+ callback: async (
10
+ value: any,
11
+ path: (string | number)[],
12
+ _options: Parameters<Schema['__transformToAdapter']>[0]
13
+ ) => {
9
14
  const isValid = typeof value === 'boolean';
10
15
 
11
16
  return {
@@ -18,17 +23,18 @@ export function booleanValidation(): ValidationFallbackReturnType {
18
23
  code: 'boolean',
19
24
  // eslint-disable-next-line ts/no-unnecessary-condition
20
25
  path: path || [],
21
- message: 'Value is not a boolean',
22
- },
26
+ message: 'Value is not a boolean'
27
+ }
23
28
  ],
24
- preventChildValidation: true,
29
+ preventChildValidation: true
25
30
  };
26
- },
31
+ }
27
32
  };
28
33
  }
29
34
 
30
35
  export function allowStringParser(): ValidationFallbackReturnType {
31
36
  return {
37
+ name: 'allowString',
32
38
  type: 'high',
33
39
  // eslint-disable-next-line ts/require-await
34
40
  callback: async (
@@ -39,8 +45,8 @@ export function allowStringParser(): ValidationFallbackReturnType {
39
45
  const parsed = Boolean(value);
40
46
  return {
41
47
  parsed: parsed,
42
- errors: [],
48
+ errors: []
43
49
  };
44
- },
50
+ }
45
51
  };
46
52
  }
@@ -4,9 +4,14 @@ import type { ValidationFallbackReturnType } from '../schema/types';
4
4
 
5
5
  export function datetimeValidation(): ValidationFallbackReturnType {
6
6
  return {
7
+ name: 'datetime',
7
8
  type: 'medium',
8
9
  // eslint-disable-next-line ts/require-await
9
- callback: async (value: any, path: (string | number)[], _options: Parameters<Schema['__transformToAdapter']>[0]) => {
10
+ callback: async (
11
+ value: any,
12
+ path: (string | number)[],
13
+ _options: Parameters<Schema['__transformToAdapter']>[0]
14
+ ) => {
10
15
  const isValid = value instanceof Date && !isNaN(value.getTime());
11
16
 
12
17
  return {
@@ -19,17 +24,18 @@ export function datetimeValidation(): ValidationFallbackReturnType {
19
24
  code: 'datetime',
20
25
  // eslint-disable-next-line ts/no-unnecessary-condition
21
26
  path: path || [],
22
- message: 'Value is not a date',
23
- },
27
+ message: 'Value is not a date'
28
+ }
24
29
  ],
25
- preventChildValidation: true,
30
+ preventChildValidation: true
26
31
  };
27
- },
32
+ }
28
33
  };
29
34
  }
30
35
 
31
36
  export function allowStringParser(): ValidationFallbackReturnType {
32
37
  return {
38
+ name: 'allowString',
33
39
  type: 'high',
34
40
  // eslint-disable-next-line ts/require-await
35
41
  callback: async (
@@ -42,20 +48,21 @@ export function allowStringParser(): ValidationFallbackReturnType {
42
48
  if (parsed instanceof Date && !isNaN(parsed.getTime())) {
43
49
  return {
44
50
  parsed: parsed,
45
- errors: [],
51
+ errors: []
46
52
  };
47
53
  }
48
54
  }
49
55
  return {
50
56
  parsed: value,
51
- errors: [],
57
+ errors: []
52
58
  };
53
- },
59
+ }
54
60
  };
55
61
  }
56
62
 
57
63
  export function below(args: DatetimeSchema['__below']): ValidationFallbackReturnType {
58
64
  return {
65
+ name: 'below',
59
66
  type: 'low',
60
67
  // eslint-disable-next-line ts/require-await
61
68
  callback: async (
@@ -75,16 +82,17 @@ export function below(args: DatetimeSchema['__below']): ValidationFallbackReturn
75
82
  code: 'below',
76
83
  // eslint-disable-next-line ts/no-unnecessary-condition
77
84
  path: path || [],
78
- message: args.message,
79
- },
80
- ],
85
+ message: args.message
86
+ }
87
+ ]
81
88
  };
82
- },
89
+ }
83
90
  };
84
91
  }
85
92
 
86
93
  export function above(args: DatetimeSchema['__above']): ValidationFallbackReturnType {
87
94
  return {
95
+ name: 'above',
88
96
  type: 'low',
89
97
  // eslint-disable-next-line ts/require-await
90
98
  callback: async (
@@ -104,10 +112,10 @@ export function above(args: DatetimeSchema['__above']): ValidationFallbackReturn
104
112
  code: 'above',
105
113
  // eslint-disable-next-line ts/no-unnecessary-condition
106
114
  path: path || [],
107
- message: args.message,
108
- },
109
- ],
115
+ message: args.message
116
+ }
117
+ ]
110
118
  };
111
- },
119
+ }
112
120
  };
113
121
  }