index.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. module.exports = {
  2. diffApply: diffApply,
  3. jsonPatchPathConverter: jsonPatchPathConverter,
  4. };
  5. /*
  6. const obj1 = {a: 3, b: 5};
  7. diffApply(obj1,
  8. [
  9. { "op": "remove", "path": ['b'] },
  10. { "op": "replace", "path": ['a'], "value": 4 },
  11. { "op": "add", "path": ['c'], "value": 5 }
  12. ]
  13. );
  14. obj1; // {a: 4, c: 5}
  15. // using converter to apply jsPatch standard paths
  16. // see http://jsonpatch.com
  17. import {diff, jsonPatchPathConverter} from 'just-diff'
  18. const obj2 = {a: 3, b: 5};
  19. diffApply(obj2, [
  20. { "op": "remove", "path": '/b' },
  21. { "op": "replace", "path": '/a', "value": 4 }
  22. { "op": "add", "path": '/c', "value": 5 }
  23. ], jsonPatchPathConverter);
  24. obj2; // {a: 4, c: 5}
  25. // arrays
  26. const obj3 = {a: 4, b: [1, 2, 3]};
  27. diffApply(obj3, [
  28. { "op": "replace", "path": ['a'], "value": 3 }
  29. { "op": "replace", "path": ['b', 2], "value": 4 }
  30. { "op": "add", "path": ['b', 3], "value": 9 }
  31. ]);
  32. obj3; // {a: 3, b: [1, 2, 4, 9]}
  33. // nested paths
  34. const obj4 = {a: 4, b: {c: 3}};
  35. diffApply(obj4, [
  36. { "op": "replace", "path": ['a'], "value": 5 }
  37. { "op": "remove", "path": ['b', 'c']}
  38. { "op": "add", "path": ['b', 'd'], "value": 4 }
  39. ]);
  40. obj4; // {a: 5, b: {d: 4}}
  41. */
  42. var REMOVE = 'remove';
  43. var REPLACE = 'replace';
  44. var ADD = 'add';
  45. function diffApply(obj, diff, pathConverter) {
  46. if (!obj || typeof obj != 'object') {
  47. throw new Error('base object must be an object or an array');
  48. }
  49. if (!Array.isArray(diff)) {
  50. throw new Error('diff must be an array');
  51. }
  52. var diffLength = diff.length;
  53. for (var i = 0; i < diffLength; i++) {
  54. var thisDiff = diff[i];
  55. var subObject = obj;
  56. var thisOp = thisDiff.op;
  57. var thisPath = thisDiff.path;
  58. if (pathConverter) {
  59. thisPath = pathConverter(thisPath);
  60. if (!Array.isArray(thisPath)) {
  61. throw new Error('pathConverter must return an array');
  62. }
  63. } else {
  64. if (!Array.isArray(thisPath)) {
  65. throw new Error('diff path must be an array, consider supplying a path converter');
  66. }
  67. }
  68. var pathCopy = thisPath.slice();
  69. var lastProp = pathCopy.pop();
  70. if (lastProp == null) {
  71. return false;
  72. }
  73. var thisProp;
  74. while (((thisProp = pathCopy.shift())) != null) {
  75. if (!(thisProp in subObject)) {
  76. subObject[thisProp] = {};
  77. }
  78. subObject = subObject[thisProp];
  79. }
  80. if (thisOp === REMOVE || thisOp === REPLACE) {
  81. if (!subObject.hasOwnProperty(lastProp)) {
  82. throw new Error(['expected to find property', thisDiff.path, 'in object', obj].join(' '));
  83. }
  84. }
  85. if (thisOp === REMOVE) {
  86. Array.isArray(subObject) ? subObject.splice(lastProp, 1) : delete subObject[lastProp];
  87. }
  88. if (thisOp === REPLACE || thisOp === ADD) {
  89. subObject[lastProp] = thisDiff.value;
  90. }
  91. }
  92. return subObject;
  93. }
  94. function jsonPatchPathConverter(stringPath) {
  95. return stringPath.split('/').slice(1);
  96. }