merge-change
Version:
Advanced library for deep merging, patching, and immutable updates of data structures. Features declarative operations for specific merging behaviors, property management, custom type merging rules, and difference tracking. Supports complex data transform
110 lines • 4.12 kB
JavaScript
import { MergeChangeKind, } from './types';
import { type } from '../type';
import { defaultOperations, extractOperations, isOperation } from './operations';
// Default methods for handling different type combinations
const defaultMethods = {
unknown_unknown(first, second, kind, mc) {
return mc(undefined, second);
},
unknown_undefined(first, second, kind, mc) {
return mc(undefined, first);
},
undefined_unknown(first, second) {
return second;
},
undefined_Date(first, second, kind) {
return kind === MergeChangeKind.MERGE ? new Date(second) : second;
},
undefined_Set(first, second, kind) {
return kind === MergeChangeKind.MERGE ? new Set(second) : second;
},
undefined_Map(first, second, kind) {
return kind === MergeChangeKind.MERGE ? new Map(second) : second;
},
undefined_Array(first, second, kind, mc) {
return kind === MergeChangeKind.MERGE
? defaultMethods.Array_Array([], second, kind, mc)
: second;
},
undefined_object(first, second, kind, mc) {
const operations = extractOperations(second);
return defaultMethods.object_object(second, operations, kind, mc);
},
object_object(first, second, kind, mc) {
const result = kind === MergeChangeKind.PATCH ? first : {};
let resultField;
let isChange = kind === MergeChangeKind.MERGE;
const operations = [];
const keysFirst = Object.keys(first);
const keysSecond = new Set(Object.keys(second));
for (const key of keysFirst) {
if (key in second) {
resultField = mc(first[key], second[key]);
keysSecond.delete(key);
}
else {
resultField = mc(first[key], undefined);
}
isChange = isChange || resultField !== first[key];
result[key] = resultField;
}
for (const key of keysSecond) {
if (isOperation(key)) {
operations.push([key, second[key]]);
}
else {
resultField = mc(undefined, second[key]);
isChange = isChange || resultField !== first[key];
result[key] = resultField;
}
}
// execute declarative operations
for (const [operation, params] of operations) {
isChange = defaultOperations[operation](result, params) || isChange;
}
return isChange ? result : first;
},
Array_Array(first, second, kind, mc) {
if (kind === MergeChangeKind.MERGE) {
return second.map((item) => mc(undefined, item));
}
return second;
},
};
function createMergeChange(kind, customMethods = {}) {
const methods = Object.assign(Object.assign({}, defaultMethods), customMethods);
const mergeChange = (...values) => {
return values.reduce((first, second) => {
const firstType = type(first);
const secondType = type(second);
const actions = [
`${firstType}_${secondType}`,
`${firstType}_unknown`,
`unknown_${secondType}`,
`unknown_unknown`,
];
for (const action of actions) {
if (methods[action]) {
return methods[action](first, second, kind, mergeChange);
}
}
return first;
});
};
return mergeChange;
}
// Factory functions for the three merge types
export function createMerge(customMethods = {}) {
return createMergeChange(MergeChangeKind.MERGE, customMethods);
}
export function createUpdate(customMethods = {}) {
return createMergeChange(MergeChangeKind.UPDATE, customMethods);
}
export function createPatch(customMethods = {}) {
return createMergeChange(MergeChangeKind.PATCH, customMethods);
}
export const merge = createMerge();
export const update = createUpdate();
export const patch = createPatch();
export default { merge, update, patch };
//# sourceMappingURL=index.js.map