@broofa/jsondiff
Advanced tools
Comparing version 1.1.2 to 1.2.0
13
index.js
@@ -55,3 +55,3 @@ // Reserved values | ||
function _patch(before, _diff, diffOnly = false) { | ||
function patch(before, _diff) { | ||
if (_diff === DROP) return undefined; | ||
@@ -86,3 +86,3 @@ if (_diff === KEEP) _diff = before; | ||
let isEqual = true; | ||
const values = diffOnly ? {} : {...before}; | ||
const values = {...before}; | ||
for (const k in _diff) { | ||
@@ -95,3 +95,3 @@ if (_diff[k] === undefined || _diff[k] === DROP) { | ||
} else { | ||
const val = _patch(before[k], _diff[k], diffOnly); | ||
const val = patch(before[k], _diff[k]); | ||
if (val !== before[k]) { | ||
@@ -112,3 +112,3 @@ values[k] = val; | ||
for (let i = 0, l = _diff.length; i < l; i++) { | ||
const val = _patch(before[i], _diff[i], diffOnly); | ||
const val = patch(before[i], _diff[i]); | ||
@@ -132,5 +132,4 @@ if (val !== before[i]) isEqual = false; | ||
diff, | ||
patch(before, _diff) {return _patch(before, _diff);}, | ||
mask(before, _diff) {return _patch(before, _diff, true);}, | ||
merge(before, after) {return _patch(before, diff(before, after));} | ||
patch, | ||
merge(before, after) {return patch(before, diff(before, after));} | ||
}; |
{ | ||
"name": "@broofa/jsondiff", | ||
"version": "1.1.2", | ||
"version": "1.2.0", | ||
"description": "Pragmatic, intuitive diffing and patching of JSON objects", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -25,13 +25,18 @@ <!-- | ||
target object. In contrast, the patches in this module act as an "overlay" | ||
that is copied onto the target object. This has the following tradeoffs: | ||
that is copied onto the target object. There are tradeoffs to this, some | ||
good, some bad: | ||
1. **Readability** - A structured patch is easier to read because it looks | ||
1. **Readability** - A structured patch is easier to read because it "looks" | ||
like the object it's modifying. | ||
2. **Size** - Operation-based patches have a lot of redundant keys and values that, again, | ||
making reading (and debugging) more difficult. This can also affect network | ||
performance in contexts where data is not compressed (e.g. websockets) | ||
3. **Fault tolerance** - Operation-based patches can fail if operations are applied out of order or if the target object does not have the expected structure. | ||
4. **Wonky hack** - Full disclosure: This module does require a small(?) hack to handle | ||
the cases where a value is deleted or an array changes. This may be | ||
off-putting to some readers. See comments about `DROP` and `KEEP`, below | ||
2. **Reordering** - Data is not "moved" in a structured patch. It is simply | ||
deleted from the old location and inserted at the new location. | ||
2. **Size** - Operation-based patches are more verbose (lots of duplicate keys | ||
and values), except in the case where values move locations. This may have a | ||
significant impact on network bandwidth, especially for uncompressed data | ||
streams. | ||
3. **Fault tolerance** - Operation-based patches may fail if operations are | ||
applied out of order or if the target object does not have the expected | ||
structure. | ||
4. **DROP/KEEP hack** - See comments about `DROP` and `KEEP` values in "Patch | ||
Objects", below. This may be off-putting to some readers. | ||
@@ -47,10 +52,11 @@ ## Installation | ||
const before = {a: 'Hello', b: 'you', c: ['dark', 'crazy'], d: 'bastard'}; | ||
const after = {a: 'Hello', c: ['dark', 'mysterious'], d: 'world'}; | ||
const before = {a: 'Hello', b: 'you', c: ['big', 'bad'], d: 'beast'}; | ||
const after = {a: 'Hi', c: ['big', 'bad', 'bold'], d: 'beast'}; | ||
// Create a patch | ||
const patch = jsondiff.diff(before, after); // ⇨ { b: '-', c: [ '+', 'mysterious' ], d: 'world' } | ||
// Note the use of DROP (-) and KEEP(+) values | ||
const patch = jsondiff.diff(before, after); // ⇨ { a: 'Hi', b: '-', c: [ '+', '+', 'bold' ] } | ||
// Apply it to the original | ||
const patched = jsondiff.patch(before, patch); // ⇨ { a: 'Hello', c: [ 'dark', 'mysterious' ], d: 'world' } | ||
const patched = jsondiff.patch(before, patch); // ⇨ { a: 'Hi', c: [ 'big', 'bad', 'bold' ], d: 'beast' } | ||
@@ -64,2 +70,6 @@ // Get the expected result | ||
### jsondiff.DROP & jsondiff.KEEP | ||
const DROP | ||
### jsondiff.diff(before, after) | ||
@@ -70,19 +80,14 @@ | ||
### jsondiff.patch(before, patchObject) | ||
### jsondiff.patch(before, patch) | ||
Applies `patchObject` to `before` and returns the result. | ||
Applies a `patch` object to `before` and returns the result. | ||
Note: Any result value that is deep-equal to it's `before` counterpart will | ||
reference simply reference the 'before' value. Thus, `===` can be used to test | ||
reference the 'before' value directly, allowing `===` to be used as a test | ||
for deep equality. | ||
### jsondiff.mask(before, patchObject) | ||
Similar to patch(), but omits values not defined in `patchObject`. I.e. Creates | ||
a version of `before` as "masked" by the patchObject. | ||
### jsondiff.merge(before, after) | ||
Shorthand for `patch(before, diff(before, after))`. Useful for | ||
updating an mutating an object only where values have actually changed. | ||
Shorthand for `jsondiff.patch(before, jsondiff.diff(before, after))`. Useful | ||
for mutating an object only where values have actually changed. | ||
@@ -93,14 +98,16 @@ ## Patch Objects | ||
they apply to. Applying a patch is (almost) as simple as doing a deep copy of | ||
the patch onto the target object. There are two minor caveats: | ||
the patch onto the target object. There are two special cases: | ||
1. The special `jsondiff.DROP` ("`-`") string is used to indicate deleted | ||
values | ||
2. A changed array is always fully-specified but, for brevity, unchanged items | ||
are indicated by the special `jsondiff.KEEP` ("`+`") string | ||
1. `jsondiff.DROP` ("`-`") values are "dropped" (deleted or set | ||
to `undefined`) | ||
2. `jsondiff.KEEP` ("`+`") values are "kept" (resolve to the corresponding | ||
value in the target) | ||
Note: The use of `DROP` and `KEEP` is, admittedly, a hack. If these | ||
exact string values appear in data outside of patch objects, `diff()` and `patch()` may not function correctly. That said, this is not expected to be an issue in real-world conditions. (Both strings include a "private use" Unicode character that should make them fairly unique.) | ||
Note: `DROP` and `KEEP` are, admittedly, a hack. If these exact string values | ||
appear in data outside of patch objects, `diff()` and `patch()` may not function | ||
correctly. That said, this is not expected to be an issue in real-world | ||
conditions. (Both strings include a "private use" Unicode character that should | ||
make them fairly unique.) | ||
---- | ||
Markdown generated from [src/README_js.md](src/README_js.md) by [![RunMD Logo](http://i.imgur.com/h0FVyzU.png)](https://github.com/broofa/runmd) |
@@ -26,13 +26,18 @@ ```javascript --hide --run usage | ||
target object. In contrast, the patches in this module act as an "overlay" | ||
that is copied onto the target object. This has the following tradeoffs: | ||
that is copied onto the target object. There are tradeoffs to this, some | ||
good, some bad: | ||
1. **Readability** - A structured patch is easier to read because it looks | ||
1. **Readability** - A structured patch is easier to read because it "looks" | ||
like the object it's modifying. | ||
2. **Size** - Operation-based patches have a lot of redundant keys and values that, again, | ||
making reading (and debugging) more difficult. This can also affect network | ||
performance in contexts where data is not compressed (e.g. websockets) | ||
3. **Fault tolerance** - Operation-based patches can fail if operations are applied out of order or if the target object does not have the expected structure. | ||
4. **Wonky hack** - Full disclosure: This module does require a small(?) hack to handle | ||
the cases where a value is deleted or an array changes. This may be | ||
off-putting to some readers. See comments about `DROP` and `KEEP`, below | ||
2. **Reordering** - Data is not "moved" in a structured patch. It is simply | ||
deleted from the old location and inserted at the new location. | ||
2. **Size** - Operation-based patches are more verbose (lots of duplicate keys | ||
and values), except in the case where values move locations. This may have a | ||
significant impact on network bandwidth, especially for uncompressed data | ||
streams. | ||
3. **Fault tolerance** - Operation-based patches may fail if operations are | ||
applied out of order or if the target object does not have the expected | ||
structure. | ||
4. **DROP/KEEP hack** - See comments about `DROP` and `KEEP` values in "Patch | ||
Objects", below. This may be off-putting to some readers. | ||
@@ -48,6 +53,7 @@ ## Installation | ||
const before = {a: 'Hello', b: 'you', c: ['dark', 'crazy'], d: 'bastard'}; | ||
const after = {a: 'Hello', c: ['dark', 'mysterious'], d: 'world'}; | ||
const before = {a: 'Hello', b: 'you', c: ['big', 'bad'], d: 'beast'}; | ||
const after = {a: 'Hi', c: ['big', 'bad', 'bold'], d: 'beast'}; | ||
// Create a patch | ||
// Note the use of DROP (-) and KEEP(+) values | ||
const patch = jsondiff.diff(before, after); // RESULT | ||
@@ -64,2 +70,6 @@ | ||
### jsondiff.DROP & jsondiff.KEEP | ||
const DROP | ||
### jsondiff.diff(before, after) | ||
@@ -70,19 +80,14 @@ | ||
### jsondiff.patch(before, patchObject) | ||
### jsondiff.patch(before, patch) | ||
Applies `patchObject` to `before` and returns the result. | ||
Applies a `patch` object to `before` and returns the result. | ||
Note: Any result value that is deep-equal to it's `before` counterpart will | ||
reference simply reference the 'before' value. Thus, `===` can be used to test | ||
reference the 'before' value directly, allowing `===` to be used as a test | ||
for deep equality. | ||
### jsondiff.mask(before, patchObject) | ||
Similar to patch(), but omits values not defined in `patchObject`. I.e. Creates | ||
a version of `before` as "masked" by the patchObject. | ||
### jsondiff.merge(before, after) | ||
Shorthand for `patch(before, diff(before, after))`. Useful for | ||
updating an mutating an object only where values have actually changed. | ||
Shorthand for `jsondiff.patch(before, jsondiff.diff(before, after))`. Useful | ||
for mutating an object only where values have actually changed. | ||
@@ -93,11 +98,13 @@ ## Patch Objects | ||
they apply to. Applying a patch is (almost) as simple as doing a deep copy of | ||
the patch onto the target object. There are two minor caveats: | ||
the patch onto the target object. There are two special cases: | ||
1. The special `jsondiff.DROP` ("`-`") string is used to indicate deleted | ||
values | ||
2. A changed array is always fully-specified but, for brevity, unchanged items | ||
are indicated by the special `jsondiff.KEEP` ("`+`") string | ||
1. `jsondiff.DROP` ("`-`") values are "dropped" (deleted or set | ||
to `undefined`) | ||
2. `jsondiff.KEEP` ("`+`") values are "kept" (resolve to the corresponding | ||
value in the target) | ||
Note: The use of `DROP` and `KEEP` is, admittedly, a hack. If these | ||
exact string values appear in data outside of patch objects, `diff()` and `patch()` may not function correctly. That said, this is not expected to be an issue in real-world conditions. (Both strings include a "private use" Unicode character that should make them fairly unique.) | ||
Note: `DROP` and `KEEP` are, admittedly, a hack. If these exact string values | ||
appear in data outside of patch objects, `diff()` and `patch()` may not function | ||
correctly. That said, this is not expected to be an issue in real-world | ||
conditions. (Both strings include a "private use" Unicode character that should | ||
make them fairly unique.) |
var assert = require('assert'); | ||
var {diff, patch, mask, DROP, KEEP} = require('..'); | ||
var {diff, patch, DROP, KEEP} = require('..'); | ||
@@ -86,35 +86,2 @@ describe(__filename, async () => { | ||
}); | ||
it('mask', async () => { | ||
const a = { | ||
bar: 111, | ||
// a: {x: 111}, | ||
b: [1, {x:222}, {x: 222}], | ||
// c: 333, | ||
// f: [1,2,5,6], | ||
ff: [1,2,6], | ||
}; | ||
const b = { | ||
bar: DROP, | ||
b: [DROP, KEEP], | ||
ff: [1], | ||
}; | ||
assert.deepEqual( | ||
mask(null, b), | ||
{ | ||
b: [undefined, undefined], | ||
ff: [1] | ||
} | ||
); | ||
assert.deepEqual( | ||
mask(a, b), | ||
{ | ||
b: [undefined, {x:222}], | ||
ff: [1] | ||
} | ||
); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
108
18081
303