143 lines
3.6 KiB
JavaScript
143 lines
3.6 KiB
JavaScript
const _ = require('lodash');
|
|
|
|
function getObjDiff(oldObj, newObj, opts = {}) {
|
|
const {
|
|
exclude = [],
|
|
excludeAdd = [],
|
|
excludeDel = [],
|
|
} = opts;
|
|
|
|
const ex = new Set(exclude);
|
|
const exAdd = new Set(excludeAdd);
|
|
const exDel = new Set(excludeDel);
|
|
|
|
const makeObjDiff = (oldObj, newObj, keyPath) => {
|
|
const result = {__isDiff: true, change: {}, add: {}, del: []};
|
|
|
|
keyPath = `${keyPath}${keyPath ? '/' : ''}`;
|
|
|
|
for (const key of Object.keys(oldObj)) {
|
|
const kp = `${keyPath}${key}`;
|
|
|
|
if (newObj.hasOwnProperty(key)) {
|
|
if (ex.has(kp))
|
|
continue;
|
|
|
|
if (!_.isEqual(oldObj[key], newObj[key])) {
|
|
if (_.isObject(oldObj[key]) && _.isObject(newObj[key])) {
|
|
result.change[key] = makeObjDiff(oldObj[key], newObj[key], kp);
|
|
} else {
|
|
result.change[key] = _.cloneDeep(newObj[key]);
|
|
}
|
|
}
|
|
} else {
|
|
if (exDel.has(kp))
|
|
continue;
|
|
result.del.push(key);
|
|
}
|
|
}
|
|
|
|
for (const key of Object.keys(newObj)) {
|
|
const kp = `${keyPath}${key}`;
|
|
if (exAdd.has(kp))
|
|
continue;
|
|
|
|
if (!oldObj.hasOwnProperty(key)) {
|
|
result.add[key] = _.cloneDeep(newObj[key]);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
return makeObjDiff(oldObj, newObj, '');
|
|
}
|
|
|
|
function isObjDiff(diff) {
|
|
return (_.isObject(diff) && diff.__isDiff && diff.change && diff.add && diff.del);
|
|
}
|
|
|
|
function isEmptyObjDiff(diff) {
|
|
return (!isObjDiff(diff) ||
|
|
!(Object.keys(diff.change).length ||
|
|
Object.keys(diff.add).length ||
|
|
diff.del.length
|
|
)
|
|
);
|
|
}
|
|
|
|
function isEmptyObjDiffDeep(diff, opts = {}) {
|
|
if (!isObjDiff(diff))
|
|
return true;
|
|
|
|
const {
|
|
isApplyChange = true,
|
|
isApplyAdd = true,
|
|
isApplyDel = true,
|
|
} = opts;
|
|
|
|
let notEmptyDeep = false;
|
|
const change = diff.change;
|
|
for (const key of Object.keys(change)) {
|
|
if (_.isObject(change[key]))
|
|
notEmptyDeep |= !isEmptyObjDiffDeep(change[key], opts);
|
|
else if (isApplyChange)
|
|
notEmptyDeep = true;
|
|
}
|
|
|
|
return !(
|
|
notEmptyDeep ||
|
|
(isApplyAdd && Object.keys(diff.add).length) ||
|
|
(isApplyDel && diff.del.length)
|
|
);
|
|
}
|
|
|
|
function applyObjDiff(obj, diff, opts = {}) {
|
|
const {
|
|
isAddChanged = false,
|
|
isApplyChange = true,
|
|
isApplyAdd = true,
|
|
isApplyDel = true,
|
|
} = opts;
|
|
|
|
let result = _.cloneDeep(obj);
|
|
if (!diff.__isDiff)
|
|
return result;
|
|
|
|
const change = diff.change;
|
|
for (const key of Object.keys(change)) {
|
|
if (result.hasOwnProperty(key)) {
|
|
if (_.isObject(change[key])) {
|
|
result[key] = applyObjDiff(result[key], change[key], opts);
|
|
} else {
|
|
if (isApplyChange)
|
|
result[key] = _.cloneDeep(change[key]);
|
|
}
|
|
} else if (isAddChanged) {
|
|
result[key] = _.cloneDeep(change[key]);
|
|
}
|
|
}
|
|
|
|
if (isApplyAdd) {
|
|
for (const key of Object.keys(diff.add)) {
|
|
result[key] = _.cloneDeep(diff.add[key]);
|
|
}
|
|
}
|
|
|
|
if (isApplyDel && diff.del.length) {
|
|
for (const key of diff.del) {
|
|
delete result[key];
|
|
}
|
|
if (_.isArray(result))
|
|
result = result.filter(v => v);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
module.exports = {
|
|
getObjDiff,
|
|
isObjDiff,
|
|
isEmptyObjDiff,
|
|
applyObjDiff,
|
|
} |