Skip to content

Commit

Permalink
add support for toJSON() js objects
Browse files Browse the repository at this point in the history
  • Loading branch information
pierreinglebert committed May 9, 2020
1 parent 0449de7 commit 783c897
Show file tree
Hide file tree
Showing 8 changed files with 332 additions and 251 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
env:
node: true
mocha: true

rules:
# Possible Errors
Expand Down Expand Up @@ -45,7 +46,7 @@ rules:
## require parens for Constructor
new-parens: 2
## max 80 length
max-len: [2, 80, 2]
max-len: [2, 120, 2]
## max 2 consecutive empty lines
no-multiple-empty-lines: [2, {max: 2}]
## require newline at end of files
Expand Down
42 changes: 39 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ $ npm install json-merge-patch --save

## Usage

Applying patches:
### Applying patches:
```js
var source = {
"title": "Goodbye!",
Expand All @@ -53,7 +53,7 @@ var target = jsonmergepatch.apply(source, patch);
// }
```

Generating patches:
### Generating patches:
```js
var source = {
"title": "Goodbye!",
Expand All @@ -72,6 +72,41 @@ var patch = jsonmergepatch.generate(source, target);
// }
```


### Usage with Javascript objects

This library is primarily designed to work with JSON.
Nonetheless, it is possible to use Javascript objects if the method `toJSON()` is implemented, the library will then serialize your object using it.
```js
var patch = jsonmergepatch.generate(
{
"title": "Goodbye!"
},
{
toJSON: () {
return {
"title": "I am serialized"
}
},
}
);
// patch = {
// "title": "I am serialized",
// }
```

```js
var patch = jsonmergepatch.generate(
{},
{
date: new Date("2020-05-09T00:00:00.000")
}
);
// patch = {
// date: "2020-05-09T00:00:00.000"
// }
```

## API

#### jsonmergepatch.apply (`obj` Object, `patch` Object) : Object
Expand All @@ -87,10 +122,11 @@ Generates a `patch` Object from source and target Object.

Generates a `patch` Object by merging patch1 and patch2.


## Running tests

```sh
make test
npm test
```

# License
Expand Down
5 changes: 5 additions & 0 deletions lib/apply.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
'use strict';

var serialize = require('./utils').serialize;

module.exports = function apply(target, patch) {
patch = serialize(patch);
if (patch === null || typeof patch !== 'object' || Array.isArray(patch)) {
return patch;
}

target = serialize(target);
if (target === null || typeof target !== 'object' || Array.isArray(target)) {
target = {};
}
Expand Down
8 changes: 6 additions & 2 deletions lib/generate.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var equal = require('deep-equal');
var serialize = require('./utils').serialize;

function arrayEquals(before, after) {
if (before.length !== after.length) {
Expand All @@ -15,6 +16,9 @@ function arrayEquals(before, after) {
}

module.exports = function generate(before, after) {
before = serialize(before);
after = serialize(after);

if (before === null || after === null ||
typeof before !== 'object' || typeof after !== 'object' ||
Array.isArray(before) !== Array.isArray(after)) {
Expand All @@ -40,7 +44,7 @@ module.exports = function generate(before, after) {
key = afterKeys[i];
if (beforeKeys.indexOf(key) === -1) {
newKeys[key] = true;
patch[key] = after[key];
patch[key] = serialize(after[key]);
}
}

Expand All @@ -58,7 +62,7 @@ module.exports = function generate(before, after) {
patch[key] = subPatch;
}
} else if (before[key] !== after[key]) {
patch[key] = after[key];
patch[key] = serialize(after[key]);
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports.serialize = function(value) {
return (value && typeof value.toJSON === 'function') ? value.toJSON() : value;
};
143 changes: 75 additions & 68 deletions test/lib/apply.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,108 +5,115 @@ var assert = require('chai').assert;
var apply = require('../../lib/apply');

describe('apply', function() {
it('should replace an attribute', function() {
assert.deepEqual(
apply({a: 'b'}, {a: 'c'}),
it('should replace an attribute', function() {
assert.deepEqual(
apply({a: 'b'}, {a: 'c'}),
{a: 'c'}
);
});
});

it('should add an attribute', function() {
assert.deepEqual(
apply({a: 'b'}, {b: 'c'}),
it('should add an attribute', function() {
assert.deepEqual(
apply({a: 'b'}, {b: 'c'}),
{a: 'b', b: 'c'}
);
});
});

it('should delete attribute', function() {
assert.deepEqual(
apply({a: 'b'}, {a: null}),
it('should delete attribute', function() {
assert.deepEqual(
apply({a: 'b'}, {a: null}),
{}
);
});
});

it('should delete attribute without affecting others', function() {
assert.deepEqual(
apply({a: 'b', b: 'c'}, {a: null}),
it('should delete attribute without affecting others', function() {
assert.deepEqual(
apply({a: 'b', b: 'c'}, {a: null}),
{b: 'c'}
);
});
});

it('should replace array with a string', function() {
assert.deepEqual(
apply({a: ['b']}, {a: 'c'}),
it('should replace array with a string', function() {
assert.deepEqual(
apply({a: ['b']}, {a: 'c'}),
{a: 'c'}
);
});
});

it('should replace an string with an array', function() {
assert.deepEqual(
apply({a: 'c'}, {a: ['b']}),
it('should replace an string with an array', function() {
assert.deepEqual(
apply({a: 'c'}, {a: ['b']}),
{a: ['b']}
);
});
});

it('should apply recursively', function() {
assert.deepEqual(
apply({a: {b: 'c'}}, {a: {b: 'd', c: null}}),
it('should apply recursively', function() {
assert.deepEqual(
apply({a: {b: 'c'}}, {a: {b: 'd', c: null}}),
{a: {b: 'd'}}
);
});
});

it('should replace an object array with a number array', function() {
assert.deepEqual(
apply({a: [{b: 'c'}]}, {a: [1]}),
it('should replace an object array with a number array', function() {
assert.deepEqual(
apply({a: [{b: 'c'}]}, {a: [1]}),
{a: [1]}
);
});
});

it('should replace an array', function() {
assert.deepEqual(
apply(['a', 'b'], ['c', 'd']),
['c', 'd']
it('should replace an array', function() {
assert.deepEqual(
apply(['a', 'b'], ['c', 'd']),
['c', 'd']
);
});
});

it('should replace an object with an array', function() {
assert.deepEqual(
apply({a: 'b'}, ['c']),
['c']
it('should replace an object with an array', function() {
assert.deepEqual(
apply({a: 'b'}, ['c']),
['c']
);
});
});

it('should replace an object with null', function() {
assert.deepEqual(
apply({a: 'foo'}, null),
null
it('should replace an object with null', function() {
assert.deepEqual(
apply({a: 'foo'}, null),
null
);
});
});

it('should replace an object with a string', function() {
assert.deepEqual(
apply({a: 'foo'}, 'bar'),
'bar'
it('should replace with an object implementing toJSON() method', function() {
assert.deepEqual(
apply({a: 'foo'}, {a: new Date('2020-05-09T00:00:00.000Z')}),
{a: '2020-05-09T00:00:00.000Z'}
);
});
});

it('should not change null attributes', function() {
assert.deepEqual(
apply({e: null}, {a: 1}),
{e: null, a: 1}
it('should replace an object with a string', function() {
assert.deepEqual(
apply({a: 'foo'}, 'bar'),
'bar'
);
});
});

it('should not set an attribute to null', function() {
assert.deepEqual(
apply([1, 2], {a: 'b', c: null}),
{a: 'b'}
it('should not change null attributes', function() {
assert.deepEqual(
apply({e: null}, {a: 1}),
{e: null, a: 1}
);
});
});

it('should not set an attribute to null in a sub object', function() {
assert.deepEqual(
apply({}, {a: {bb: {ccc: null}}}),
{a: {bb: {}}}
);
});
it('should not set an attribute to null', function() {
assert.deepEqual(
apply([1, 2], {a: 'b', c: null}),
{a: 'b'}
);
});

it('should not set an attribute to null in a sub object', function() {
assert.deepEqual(
apply({}, {a: {bb: {ccc: null}}}),
{a: {bb: {}}}
);
});
});
Loading

0 comments on commit 783c897

Please sign in to comment.