diffUtils.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. const _ = require('lodash');
  2. function getObjDiff(oldObj, newObj, opts = {}) {
  3. const {
  4. exclude = [],
  5. excludeAdd = [],
  6. excludeDel = [],
  7. } = opts;
  8. const ex = new Set(exclude);
  9. const exAdd = new Set(excludeAdd);
  10. const exDel = new Set(excludeDel);
  11. const makeObjDiff = (oldObj, newObj, keyPath) => {
  12. const result = {__isDiff: true, change: {}, add: {}, del: []};
  13. keyPath = `${keyPath}${keyPath ? '/' : ''}`;
  14. for (const key of Object.keys(oldObj)) {
  15. const kp = `${keyPath}${key}`;
  16. if (newObj.hasOwnProperty(key)) {
  17. if (ex.has(kp))
  18. continue;
  19. if (!_.isEqual(oldObj[key], newObj[key])) {
  20. if (_.isObject(oldObj[key]) && _.isObject(newObj[key])) {
  21. result.change[key] = makeObjDiff(oldObj[key], newObj[key], kp);
  22. } else {
  23. result.change[key] = _.cloneDeep(newObj[key]);
  24. }
  25. }
  26. } else {
  27. if (exDel.has(kp))
  28. continue;
  29. result.del.push(key);
  30. }
  31. }
  32. for (const key of Object.keys(newObj)) {
  33. const kp = `${keyPath}${key}`;
  34. if (exAdd.has(kp))
  35. continue;
  36. if (!oldObj.hasOwnProperty(key)) {
  37. result.add[key] = _.cloneDeep(newObj[key]);
  38. }
  39. }
  40. return result;
  41. }
  42. return makeObjDiff(oldObj, newObj, '');
  43. }
  44. function isObjDiff(diff) {
  45. return (_.isObject(diff) && diff.__isDiff && diff.change && diff.add && diff.del);
  46. }
  47. function isEmptyObjDiff(diff) {
  48. return (!isObjDiff(diff) ||
  49. !(Object.keys(diff.change).length ||
  50. Object.keys(diff.add).length ||
  51. diff.del.length
  52. )
  53. );
  54. }
  55. function isEmptyObjDiffDeep(diff, opts = {}) {
  56. if (!isObjDiff(diff))
  57. return true;
  58. const {
  59. isApplyChange = true,
  60. isApplyAdd = true,
  61. isApplyDel = true,
  62. } = opts;
  63. let notEmptyDeep = false;
  64. const change = diff.change;
  65. for (const key of Object.keys(change)) {
  66. if (_.isObject(change[key]))
  67. notEmptyDeep |= !isEmptyObjDiffDeep(change[key], opts);
  68. else if (isApplyChange)
  69. notEmptyDeep = true;
  70. }
  71. return !(
  72. notEmptyDeep ||
  73. (isApplyAdd && Object.keys(diff.add).length) ||
  74. (isApplyDel && diff.del.length)
  75. );
  76. }
  77. function applyObjDiff(obj, diff, opts = {}) {
  78. const {
  79. isAddChanged = false,
  80. isApplyChange = true,
  81. isApplyAdd = true,
  82. isApplyDel = true,
  83. } = opts;
  84. let result = _.cloneDeep(obj);
  85. if (!diff.__isDiff)
  86. return result;
  87. const change = diff.change;
  88. for (const key of Object.keys(change)) {
  89. if (result.hasOwnProperty(key)) {
  90. if (_.isObject(change[key])) {
  91. result[key] = applyObjDiff(result[key], change[key], opts);
  92. } else {
  93. if (isApplyChange)
  94. result[key] = _.cloneDeep(change[key]);
  95. }
  96. } else if (isAddChanged) {
  97. result[key] = _.cloneDeep(change[key]);
  98. }
  99. }
  100. if (isApplyAdd) {
  101. for (const key of Object.keys(diff.add)) {
  102. result[key] = _.cloneDeep(diff.add[key]);
  103. }
  104. }
  105. if (isApplyDel && diff.del.length) {
  106. for (const key of diff.del) {
  107. delete result[key];
  108. }
  109. if (_.isArray(result))
  110. result = result.filter(v => v);
  111. }
  112. return result;
  113. }
  114. module.exports = {
  115. getObjDiff,
  116. isObjDiff,
  117. isEmptyObjDiff,
  118. applyObjDiff,
  119. }