packages/jsondiffpatch/src/filters/nested.ts
import DiffContext from '../contexts/diff.js';
import PatchContext from '../contexts/patch.js';
import ReverseContext from '../contexts/reverse.js';
import type { ArrayDelta, Delta, Filter, ObjectDelta } from '../types.js';
export const collectChildrenDiffFilter: Filter<DiffContext> = (context) => {
if (!context || !context.children) {
return;
}
const length = context.children.length;
let child;
let result = context.result as ObjectDelta | ArrayDelta;
for (let index = 0; index < length; index++) {
child = context.children[index];
if (typeof child.result === 'undefined') {
continue;
}
result = result || {};
(result as Record<string | number, Delta>)[child.childName!] = child.result;
}
if (result && context.leftIsArray) {
result._t = 'a';
}
context.setResult(result).exit();
};
collectChildrenDiffFilter.filterName = 'collectChildren';
export const objectsDiffFilter: Filter<DiffContext> = (context) => {
if (context.leftIsArray || context.leftType !== 'object') {
return;
}
const left = context.left as Record<string, unknown>;
const right = context.right as Record<string, unknown>;
let name;
let child;
const propertyFilter = context.options!.propertyFilter;
for (name in left) {
if (!Object.prototype.hasOwnProperty.call(left, name)) {
continue;
}
if (propertyFilter && !propertyFilter(name, context)) {
continue;
}
child = new DiffContext(left[name], right[name]);
context.push(child, name);
}
for (name in right) {
if (!Object.prototype.hasOwnProperty.call(right, name)) {
continue;
}
if (propertyFilter && !propertyFilter(name, context)) {
continue;
}
if (typeof left[name] === 'undefined') {
child = new DiffContext(undefined, right[name]);
context.push(child, name);
}
}
if (!context.children || context.children.length === 0) {
context.setResult(undefined).exit();
return;
}
context.exit();
};
objectsDiffFilter.filterName = 'objects';
export const patchFilter: Filter<PatchContext> = function nestedPatchFilter(
context,
) {
if (!context.nested) {
return;
}
const nestedDelta = context.delta as ObjectDelta | ArrayDelta;
if (nestedDelta._t) {
return;
}
const objectDelta = nestedDelta as ObjectDelta;
let name;
let child;
for (name in objectDelta) {
child = new PatchContext(
(context.left as Record<string, unknown>)[name],
objectDelta[name],
);
context.push(child, name);
}
context.exit();
};
patchFilter.filterName = 'objects';
export const collectChildrenPatchFilter: Filter<PatchContext> =
function collectChildrenPatchFilter(context) {
if (!context || !context.children) {
return;
}
const deltaWithChildren = context.delta as ObjectDelta | ArrayDelta;
if (deltaWithChildren._t) {
return;
}
const object = context.left as Record<string, unknown>;
const length = context.children.length;
let child;
for (let index = 0; index < length; index++) {
child = context.children[index];
const property = child.childName as string;
if (
Object.prototype.hasOwnProperty.call(context.left, property) &&
child.result === undefined
) {
delete object[property];
} else if (object[property] !== child.result) {
object[property] = child.result;
}
}
context.setResult(object).exit();
};
collectChildrenPatchFilter.filterName = 'collectChildren';
export const reverseFilter: Filter<ReverseContext> =
function nestedReverseFilter(context) {
if (!context.nested) {
return;
}
const nestedDelta = context.delta as ObjectDelta | ArrayDelta;
if (nestedDelta._t) {
return;
}
const objectDelta = context.delta as ObjectDelta;
let name;
let child;
for (name in objectDelta) {
child = new ReverseContext(objectDelta[name]);
context.push(child, name);
}
context.exit();
};
reverseFilter.filterName = 'objects';
export const collectChildrenReverseFilter: Filter<ReverseContext> = (
context,
) => {
if (!context || !context.children) {
return;
}
const deltaWithChildren = context.delta as ObjectDelta | ArrayDelta;
if (deltaWithChildren._t) {
return;
}
const length = context.children.length;
let child;
const delta: ObjectDelta = {};
for (let index = 0; index < length; index++) {
child = context.children[index];
const property = child.childName as string;
if (delta[property] !== child.result) {
delta[property] = child.result;
}
}
context.setResult(delta).exit();
};
collectChildrenReverseFilter.filterName = 'collectChildren';