# Introduction
- FlatFieldMetadataType validators hashmap
- Do not fail fast on validation but aggregate errors
- Implemented `enum` validation
- Plugged the new v2 dynamic call in the field metadata service v2
## What's next:
- Implem integration tests to make things run 🙃
- migrate existing settings valdiation
- Finish the create object metadata service
- Handle update input transpilation and validation
## Open question
Should we implement, not covered validation ?, adding strictness now or
never.
This will be required by the import anw
## Discovered issue with cache
Currently the cache is not accurately typed, `fieldsById` map are not
storing any relations.
Which means the current transpilation tools are hitting undefined at
runtime
In the best of the world we will refactor the cache to be storing
`FlatObjectMetadata` and `FlatFieldMetadata` so we don't even have to
transpile them for validation and so on
But it would require to refactor the loaders that returns the cache to
the front on hit as FieldMetadataEntity, so we might land on a lighter
solution to rather add a new `getExistingFlatCache` that handles the
transpilation itself
About to do that in an other PR to be discussed with Coco
80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
/**
|
|
* Deep merges two objects or arrays recursively
|
|
* - Objects are merged by combining their properties
|
|
* - Arrays are merged by concatenating them
|
|
* - Primitive values from target override source
|
|
* - Null values from target are preserved
|
|
* - Undefined values from target are ignored
|
|
* - Date and RegExp objects are treated as primitives (replaced, not merged)
|
|
*
|
|
* @param source The source object to merge from
|
|
* @param target The target object to merge into
|
|
* @returns A new merged object
|
|
*/
|
|
export const deepMerge = <T extends object>(
|
|
source: Required<T>,
|
|
target: Required<T>,
|
|
): T => {
|
|
// Handle null/undefined cases
|
|
if (!source) return target as T;
|
|
if (!target) return source;
|
|
|
|
// Create a new object to avoid mutations
|
|
const output = { ...source };
|
|
|
|
// Iterate through all keys in target
|
|
Object.keys(target).forEach((key) => {
|
|
const sourceValue = source[key as keyof T];
|
|
const targetValue = target[key as keyof T];
|
|
|
|
// Skip undefined values in target
|
|
if (targetValue === undefined) {
|
|
return;
|
|
}
|
|
|
|
// Handle null values - explicitly assign them
|
|
if (targetValue === null) {
|
|
output[key as keyof T] = null as T[keyof T];
|
|
return;
|
|
}
|
|
|
|
// Handle arrays - concatenate them
|
|
if (Array.isArray(sourceValue) && Array.isArray(targetValue)) {
|
|
output[key as keyof T] = [...sourceValue, ...targetValue] as T[keyof T];
|
|
return;
|
|
}
|
|
|
|
// Handle Date and RegExp objects - treat them as primitives
|
|
if (
|
|
targetValue instanceof Date ||
|
|
targetValue instanceof RegExp ||
|
|
sourceValue instanceof Date ||
|
|
sourceValue instanceof RegExp
|
|
) {
|
|
output[key as keyof T] = targetValue as T[keyof T];
|
|
return;
|
|
}
|
|
|
|
// Handle nested objects - recurse
|
|
if (
|
|
sourceValue &&
|
|
targetValue &&
|
|
typeof sourceValue === 'object' &&
|
|
typeof targetValue === 'object' &&
|
|
!Array.isArray(sourceValue) &&
|
|
!Array.isArray(targetValue)
|
|
) {
|
|
output[key as keyof T] = deepMerge(
|
|
sourceValue as object,
|
|
targetValue as object,
|
|
) as T[keyof T];
|
|
return;
|
|
}
|
|
|
|
// For primitives
|
|
output[key as keyof T] = targetValue as T[keyof T];
|
|
});
|
|
|
|
return output;
|
|
};
|