Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(deepMerge): bring up #141

Merged
merged 7 commits into from Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Expand Up @@ -16,6 +16,7 @@ Utilities for [Hexo].
- [camelCaseKeys](#camelcasekeysobj-options)
- [createSha1Hash](#createsha1hash)
- [decodeURL](#decodeurlstr)
- [deepMerge](#deepmergetarget-source)
- [encodeURL](#encodeurlstr)
- [escapeDiacritic](#escapediacriticstr)
- [escapeHTML](#escapehtmlstr)
Expand Down Expand Up @@ -111,6 +112,28 @@ decodeURI(format(new URL('http://xn--br-mia.com.com/b%C3%A1r'), {unicode: true})
// http://bár.com/báz
```

### deepMerge(target, source)

Merges the enumerable properties of two objects deeply while neither `target` or `source` is modified.
curbengh marked this conversation as resolved.
Show resolved Hide resolved

``` js
// Merge deeply
const obj1 = {a: {b: 1, c: 1, d: {e: 1, f: 1}}};
const obj2 = {a: {b: 2, d: {f: 'f'} }};

deepMerge(obj1, obj2);
// {a: {b: 2, c: 1, d: {e: 1, f: 'f'} }}
```

``` js
// Objects will be combined at the same index in the two arrays, just as lodash.merge
curbengh marked this conversation as resolved.
Show resolved Hide resolved
const obj1 = { 'a': [{ 'b': 2 }, { 'd': 4 }] };
const obj2 = { 'a': [{ 'c': 3 }, { 'e': 5 }] };

deepMerge(obj1, obj2);
// { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] };
```

### encodeURL(str)

Encode URL or path into a [safe format](https://en.wikipedia.org/wiki/Percent-encoding).
Expand Down
25 changes: 25 additions & 0 deletions lib/deep_merge.js
@@ -0,0 +1,25 @@
'use strict';

const deepmerge = require('deepmerge');

const arrayMerge = (target, source, options) => {
const destination = target.slice();

source.forEach((item, index) => {
if (typeof destination[index] === 'undefined') {
destination[index] = options.cloneUnlessOtherwiseSpecified(item, options);
} else if (options.isMergeableObject(item)) {
destination[index] = deepmerge(target[index], item, options);
} else if (!target.includes(item)) {
destination.push(item);
}
});
return destination;
};


function deepMerge(target, source) {
return deepmerge(target, source, { arrayMerge });
}

module.exports = deepMerge;
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -7,6 +7,7 @@ exports.camelCaseKeys = require('./camel_case_keys');
exports.Color = require('./color');
exports.createSha1Hash = hash.createSha1Hash;
exports.decodeURL = require('./decode_url');
exports.deepMerge = require('./deep_merge');
exports.encodeURL = require('./encode_url');
exports.escapeDiacritic = require('./escape_diacritic');
exports.escapeHTML = require('./escape_html');
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -46,6 +46,7 @@
"bluebird": "^3.5.2",
"camel-case": "^3.0.0",
"cross-spawn": "^7.0.0",
"deepmerge": "^4.2.2",
"highlight.js": "^9.13.1",
"striptags": "^3.1.1"
},
Expand Down
80 changes: 80 additions & 0 deletions test/deep_merge.spec.js
@@ -0,0 +1,80 @@
'use strict';

require('chai').should();

// The test is modified based on https://github.com/jonschlinkert/merge-deep/blob/master/test.js

describe('deepMerge()', () => {
const deepMerge = require('../lib/deep_merge');

it('should act as lodash.merge', () => {
const obj1 = { 'a': [{ 'b': 2 }, { 'd': 4 }] };
const obj2 = { 'a': [{ 'c': 3 }, { 'e': 5 }] };

const expected = { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] };

deepMerge(obj1, obj2).should.eql(expected);
});

it('should do a deep merge', () => {
const obj1 = {a: {b: 1, c: 1, d: {e: 1, f: 1}}};
const obj2 = {a: {b: 2, d: {f: 'f'} }};

const expected = {a: {b: 2, c: 1, d: {e: 1, f: 'f'} }};

deepMerge(obj1, obj2).should.eql(expected);
});

it('should not merge strings', () => {
const obj1 = {a: 'fooo'};
const obj2 = {a: {b: 2, d: {f: 'f'} }};
const obj3 = {a: 'bar'};

const result = deepMerge(deepMerge(obj1, obj2), obj3);
result.a.should.eql('bar');
});

it('should merge simple array', () => {
const obj1 = {a: [1, [2, 3], 4]};
const obj2 = {a: [1, [3, 4], [5, 6], 6]};

const result = deepMerge(obj1, obj2);
const expected = {a: [1, [2, 3, 4], [5, 6], 6]};

result.should.eql(expected);
});

it('should not merge an objects into an array', () => {
const obj1 = {a: {b: 1}};
const obj2 = {a: ['foo', 'bar']};

deepMerge(obj1, obj2).should.eql({a: ['foo', 'bar']});
});

it('should not affect target & source', () => {
const obj1 = {a: 0, b: 1, c: {d: 1}, e: 4};
const obj2 = {b: 3, c: {d: 2}};

const result = deepMerge(obj1, obj2);
const expected = {a: 0, b: 3, c: {d: 2}, e: 4};

result.should.eql(expected);

result.should.not.eql(obj1);
obj1.should.eql({a: 0, b: 1, c: {d: 1}, e: 4});

result.should.not.eql(obj2);
obj2.should.eql({b: 3, c: {d: 2}});
});

it('should deep clone arrays during merge', () => {
const obj1 = {a: [1, 2, [3, 4]]};
const obj2 = {b: [5, 6]};

const result = deepMerge(obj1, obj2);

result.a.should.eql([1, 2, [3, 4]]);
result.a[2].should.eql([3, 4]);
result.b.should.eql(obj2.b);
});
});