deepmerge-json
Advanced tools
Comparing version 1.2.0 to 1.3.0
# Changelog | ||
## [1.3.0] - 2022-12-04 | ||
### Added: | ||
- Support to multiple operations at once | ||
- Clone functionality with an empty second parameter. | ||
- Proper `clone` method which is a more meaninful named alias to the functionality | ||
- `merge.multi` an utility method to merge multiple objects at once, respecting their order | ||
### Fixed: | ||
- Result was being replaced by an empty `pos` parameter. This fix can be a breaking change if your code rely on this behavior. This was wrongly assuming that if you pass any _falsey_ `pos` parameter it meant you wanted to replace the entire `pre` parameter with it. Now it works like this: if you pass nothing (`undefined`) to the `pos` parameter, the `pre` parameter will be cloned as is. If you pass anything else, it will be used in the merge process as expected. | ||
- README titles | ||
--- | ||
## [1.2.0] - 2021-08-06 | ||
### Changed | ||
* Added support to negative indexes to `$insert` operation | ||
- Added support to negative indexes to `$insert` operation | ||
--- | ||
@@ -13,7 +30,9 @@ | ||
### Added | ||
* New array operation: `$insert` | ||
- New array operation: `$insert` | ||
### Changed | ||
* Now `$replace` accept string numeric keys | ||
- Now `$replace` accept string numeric keys | ||
--- | ||
@@ -24,7 +43,8 @@ | ||
### Changed | ||
* Changed the name of the generated artifacts for better integration with other libraries | ||
* from "index.js" to "deepmerge-json.js" | ||
* from "index.d.js" to "deepmerge-json.d.js" | ||
* Source code mode to src folder to keep thing organized | ||
- Changed the name of the generated artifacts for better integration with other libraries | ||
- from "index.js" to "deepmerge-json.js" | ||
- from "index.d.js" to "deepmerge-json.d.js" | ||
- Source code mode to src folder to keep thing organized | ||
--- | ||
@@ -35,7 +55,9 @@ | ||
### Added | ||
* New array operation: `$replace` | ||
- New array operation: `$replace` | ||
### Fixed | ||
* Fixed security issues with some dependencies | ||
- Fixed security issues with some dependencies | ||
--- | ||
@@ -46,7 +68,9 @@ | ||
### Fixed | ||
* Arrays of objects were not being merged | ||
- Arrays of objects were not being merged | ||
### Added | ||
* `$push` tests | ||
- `$push` tests | ||
--- | ||
@@ -58,3 +82,4 @@ | ||
[unreleased]: https://github.com/kleber-swf/deepmerge-json/tree/develop | ||
[1.3.0]: https://github.com/kleber-swf/deepmerge-json/tree/v1.3.0 | ||
[1.2.0]: https://github.com/kleber-swf/deepmerge-json/tree/v1.2.0 | ||
@@ -65,2 +90,2 @@ [1.1.3]: https://github.com/kleber-swf/deepmerge-json/tree/v1.1.3 | ||
[1.0.2]: https://github.com/kleber-swf/deepmerge-json/tree/v1.0.2 | ||
[1.0.0]: https://github.com/kleber-swf/deepmerge-json/tree/v1.0.0 | ||
[1.0.0]: https://github.com/kleber-swf/deepmerge-json/tree/v1.0.0 |
@@ -5,3 +5,3 @@ (function (global, factory) { | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.merge = factory()); | ||
}(this, (function () { 'use strict'; | ||
})(this, (function () { 'use strict'; | ||
@@ -25,6 +25,10 @@ const directReplace = (_, pos) => pos; | ||
const mergeArrayWithParams = function (pre, pos) { | ||
const key = Object.keys(pos)[0]; // (x_x) This is ugly | ||
return key in arrayMergeFn | ||
? arrayMergeFn[key](pre.slice(), pos[key]) | ||
: pos; | ||
pre = pre.slice(); | ||
Object.keys(pos).forEach(key => { | ||
pre = key in arrayMergeFn | ||
? arrayMergeFn[key](pre, pos[key]) | ||
: pos; | ||
}); | ||
return pre; | ||
}; | ||
@@ -78,3 +82,10 @@ | ||
function merge(pre, pos) { | ||
if (!pos) return pos; | ||
if (pos === undefined) { | ||
if (pre == null) return pre; | ||
if (Array.isArray(pre)) pos = []; | ||
else if (typeof pre === 'object') pos = {}; | ||
else pos = pre; | ||
} else if (pos === null) { | ||
return null; | ||
} | ||
const tt = Array.isArray(pre) ? 'a' : typeof pre === 'object' ? 'o' : 'b'; | ||
@@ -85,5 +96,16 @@ const st = Array.isArray(pos) ? 'a' : typeof pos === 'object' ? 'o' : 'b'; | ||
merge.clone = obj => merge(obj); | ||
merge.multi = (pre, ...args) => { | ||
if (!args) return merge(pre); | ||
for (let i = 0; i < args.length; i++) { | ||
pre = merge(pre, args[i]); | ||
} | ||
return pre; | ||
}; | ||
return merge; | ||
}))); | ||
})); | ||
//# sourceMappingURL=deepmerge-json.js.map |
@@ -1,2 +0,2 @@ | ||
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(e="undefined"!=typeof globalThis?globalThis:e||self).merge=r()}(this,(function(){"use strict";const e=(e,r)=>r,r=(e,r)=>Object.assign({},r),n=(e,r)=>r.slice(),t={$push:(e,r)=>e.concat(r),$append:(e,r)=>e.concat(r),$prepend:(e,r)=>r.concat(e),$replace:function(e,r){let n;return e=e.slice(),Object.keys(r).forEach((t=>{if(n=Number.parseInt(t),n<0||Number.isNaN(n))throw Error(`Invalid index for $replace: ${t}`);e[n]=c(e[n],r[t])})),e},$insert:function(e,r){let n;return e=e.slice(),Object.keys(r).forEach((t=>{if(n=Number.parseInt(t),Number.isNaN(n))throw Error(`Invalid index for $insert: ${t}`);e.splice(n,0,r[t])})),e},$set:n},o={oo:function(e,r){return e=Object.assign({},e),Object.keys(r).forEach((n=>e[n]=c(e[n],r[n]))),e},oa:r,ob:e,aa:function(e,r){return e=e.slice(),r.forEach(((r,n)=>e[n]=c(e[n],r))),e},ao:function(e,r){const n=Object.keys(r)[0];return n in t?t[n](e.slice(),r[n]):r},ab:e,bb:e,bo:r,ba:n};function c(e,r){if(!r)return r;const n=Array.isArray(e)?"a":"object"==typeof e?"o":"b",t=Array.isArray(r)?"a":"object"==typeof r?"o":"b";return o[n+t](e,r)}return c})); | ||
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(e="undefined"!=typeof globalThis?globalThis:e||self).merge=r()}(this,(function(){"use strict";const e=(e,r)=>r,r=(e,r)=>Object.assign({},r),n=(e,r)=>r.slice(),t={$push:(e,r)=>e.concat(r),$append:(e,r)=>e.concat(r),$prepend:(e,r)=>r.concat(e),$replace:function(e,r){let n;return e=e.slice(),Object.keys(r).forEach((t=>{if(n=Number.parseInt(t),n<0||Number.isNaN(n))throw Error(`Invalid index for $replace: ${t}`);e[n]=i(e[n],r[t])})),e},$insert:function(e,r){let n;return e=e.slice(),Object.keys(r).forEach((t=>{if(n=Number.parseInt(t),Number.isNaN(n))throw Error(`Invalid index for $insert: ${t}`);e.splice(n,0,r[t])})),e},$set:n},o={oo:function(e,r){return e=Object.assign({},e),Object.keys(r).forEach((n=>e[n]=i(e[n],r[n]))),e},oa:r,ob:e,aa:function(e,r){return e=e.slice(),r.forEach(((r,n)=>e[n]=i(e[n],r))),e},ao:function(e,r){return e=e.slice(),Object.keys(r).forEach((n=>{e=n in t?t[n](e,r[n]):r})),e},ab:e,bb:e,bo:r,ba:n};function i(e,r){if(void 0===r){if(null==e)return e;r=Array.isArray(e)?[]:"object"==typeof e?{}:e}else if(null===r)return null;const n=Array.isArray(e)?"a":"object"==typeof e?"o":"b",t=Array.isArray(r)?"a":"object"==typeof r?"o":"b";return o[n+t](e,r)}return i.clone=e=>i(e),i.multi=(e,...r)=>{if(!r)return i(e);for(let n=0;n<r.length;n++)e=i(e,r[n]);return e},i})); | ||
//# sourceMappingURL=deepmerge-json.min.js.map |
{ | ||
"name": "deepmerge-json", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "A library to deep merge json files with array operations", | ||
@@ -37,6 +37,6 @@ "keywords": [ | ||
"devDependencies": { | ||
"mocha": "^9.0.3", | ||
"rollup": "^2.55.1", | ||
"mocha": "^9.2.2", | ||
"rollup": "^2.70.1", | ||
"rollup-plugin-terser": "^7.0.2" | ||
} | ||
} |
155
README.md
@@ -44,6 +44,6 @@ # Deepmerge Json | ||
## Installation | ||
# Installation | ||
## With NPM | ||
### With NPM | ||
```sh | ||
@@ -54,6 +54,9 @@ npm install deepmerge-json | ||
After that you can import it: | ||
```js | ||
import merge from 'deepmerge-json'; | ||
``` | ||
or | ||
```js | ||
@@ -65,5 +68,4 @@ const merge = require('deepmerge-json'); | ||
## With a CDN | ||
### With a CDN | ||
Just add this line to your HTML file: | ||
@@ -75,10 +77,8 @@ | ||
# Usage | ||
## Usage | ||
The main reason this library was created was to mimic and extend some array merging functions from mongodb when merging two sets of properties json files. | ||
## Simple Merge | ||
### Simple merge | ||
It is possible to merge recursively all types of properties. | ||
@@ -116,3 +116,3 @@ | ||
// result | ||
{ | ||
{ | ||
boolValue: true, | ||
@@ -131,8 +131,14 @@ numberValue: 222, | ||
} | ||
``` | ||
## Clone | ||
### Array merge | ||
You can clone an object omitting the second parameter. This will execute the `merge` function with an empty second parameter, which results in a deep clone of the first one. | ||
Notice that if you pass anything other than `undefined` to the second parameter (even `null`), it will be actively used in the merge process. | ||
You can also use the `merge.clone()` method which is an alias to the `merge` method with a single parameter. It's also more semantically meaningful. | ||
## Array Merge | ||
Merging arrays are special because sometimes you want to append elements, sometimes prepend and sometimes you want to merge them. | ||
@@ -142,7 +148,6 @@ | ||
Inspired on that this library has the following merging methods (note that to be merged, the arrays can have any depth as long as they have the same path): | ||
Inspired on that, this library has some merging methods (here called **operations**) to help you merge or improve the arrays from the original object. Just keep in mind that no matter the depth of the array, you just need to have the same path to the objects you want to merge. | ||
### Merging Elements | ||
#### Merge elements | ||
This is the default behavior. It merges the arrays elements one by one. It will add elements to the end if there more on the right than on the left element. | ||
@@ -161,3 +166,3 @@ | ||
const result = merge(left, right) | ||
const result = merge(left, right) | ||
@@ -171,7 +176,6 @@ // Result | ||
### $push / $append | ||
#### #push / #append | ||
You can use the `$push` or `$append` operation to add elements to the end of the "left" array. | ||
You can use the special property `$push` or `$append` to add elements to the end of the "left" array. | ||
```js | ||
@@ -183,11 +187,9 @@ const left = [0, 1, 2]; | ||
// Result | ||
[0, 1, 2, 3, 4, 5] | ||
[0, 1, 2, 3, 4, 5]; | ||
``` | ||
### $prepend | ||
#### #prepend | ||
Similarly, you can use `$prepend` operation to add elements to the beginning of the "left" array. | ||
Similarly, you can use the property `$prepend` to add elements to the beginning of the "left" array. | ||
```js | ||
@@ -199,11 +201,9 @@ const left = [0, 1, 2]; | ||
// Result | ||
[-2, -1, 0, 1, 2] | ||
[-2, -1, 0, 1, 2]; | ||
``` | ||
### $set | ||
#### #set | ||
Use `$set` when you want to completely replace "left" array by the "right" one. | ||
Use `#set` when you want to completely replace "left" array by the "right" one. | ||
```js | ||
@@ -215,25 +215,25 @@ const left = [0, 1, 2, 3, 4, 5, 6]; | ||
// Result | ||
[10, 20] | ||
[10, 20]; | ||
``` | ||
### $replace | ||
#### $replace | ||
Use `$replace` to replace or add indexed elements by their indexes. Indexes can be numbers or strings and cannot be less than 0 or `NaN` values. | ||
With valid indexes: | ||
```js | ||
const left = [10, 20, 30]; | ||
const right = { $replace: { 0: 100, '2': 300, 4: 400 } }; | ||
const right = { $replace: { 0: 100, 2: 300, 4: 400 } }; | ||
const result = merge(left, right); | ||
// Result (note that the element with index 3 was never given) | ||
[100, 20, 300, , 400] | ||
[100, 20, 300, , 400]; | ||
``` | ||
With invalid indexes: | ||
```js | ||
const left = [10, 20, 30]; | ||
const right = { $replace: { null: 0, 'foo': 0, true: 0, '-1': 0 } }; | ||
const right = { $replace: { null: 0, foo: 0, true: 0, '-1': 0 } }; | ||
const result = merge(left, right); | ||
@@ -244,8 +244,8 @@ | ||
### $insert | ||
#### $insert | ||
Use `$insert` to insert indexed elements at their indexes. Indexes can be numbers or strings and cannot `NaN` values. Notice that elements change places as you insert them. Negative numbers insert them to the end of the array. See [Array.splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice). | ||
With positive indexes: | ||
```js | ||
@@ -257,6 +257,7 @@ const left = [10, 20, 30]; | ||
// Result (notice that the elements moved and the 400 was added to the last index) | ||
[ 100, 10, 200, 20, 30, 400 ] | ||
[100, 10, 200, 20, 30, 400]; | ||
``` | ||
With negative indexes: | ||
```js | ||
@@ -268,9 +269,10 @@ const left = [10, 20, 30]; | ||
// Result | ||
[ 0, 10, 20, 200, 100, 30 ] | ||
[0, 10, 20, 200, 100, 30]; | ||
``` | ||
With invalid indexes: | ||
```js | ||
const left = [10, 20, 30]; | ||
const right = { $insert: { null: 100, 'foo': 300, true: 400 } }; | ||
const right = { $insert: { null: 100, foo: 300, true: 400 } }; | ||
const result = merge(left, right); | ||
@@ -281,5 +283,4 @@ | ||
### Skipping Elements | ||
#### Skipping elements | ||
If you skip some elements in the "right" array, the respective "left" elements will be kept in the result. This is not very useful for json merging since it's ot possible to create a sparse array _per se_, but it's a nice consequence of the `merge` method. | ||
@@ -293,13 +294,56 @@ | ||
// Result | ||
[10, 20, 30, 40, 50, 60] | ||
[10, 20, 30, 40, 50, 60]; | ||
``` | ||
### Multiple Operations | ||
Starting from version `1.3.0` it's possible to use multiple operations at once. They are executed in place and in order. | ||
```js | ||
const left = [2, 3, 4]; | ||
const right: { | ||
$prepend: [0, 1], | ||
$append: [5, 6], | ||
$replace: { 0: 100 }; | ||
} | ||
const result = merge(left, right); | ||
// Result | ||
[100, 1, 2, 3, 4, 5, 6] | ||
``` | ||
### Options | ||
```js | ||
const left = [2, 3, 4]; | ||
const right: { | ||
$replace: { 0: 100 }; | ||
$prepend: [0, 1], | ||
$append: [5, 6], | ||
} | ||
const result = merge(left, right); | ||
For now, no options yet. | ||
// Result | ||
[0, 1, 100, 3, 4, 5, 6] | ||
``` | ||
## Merging Multiple Objects | ||
## Contributing | ||
You can also merge multiple objects with the help of the utility method `merge.multi()`. It respects the order of the parameters and the operations just like expected if you call `merge` multiple times passing the last result as the first parameter to the next call. | ||
```js | ||
const obj1 = { a: 0, b: [true, { c: 'ok' }] }; | ||
const obj2 = { a: 10, d: false }; | ||
const obj3 = { a: 20, b: { $push: [42] } }; | ||
const result = merge.multi(obj1, obj2, obj3); | ||
// Result | ||
{ a: 20, b: [true, { c: 'ok' }, 42], d: false } | ||
``` | ||
## Options | ||
For now, no options yet :chipmunk:. | ||
# Contributing | ||
If you are nice enough you can submit bugs and features to the issue board and make this lib great and useful for you and the community. | ||
@@ -309,1 +353,20 @@ | ||
# Rough Performance Test | ||
Just a fun performance test with a 1 million runs. I'm not a performance expert so they might not be very precise. | ||
Testing machine: | ||
- CPU: Intel Core i5-9300H @ 2.4GHz x8 | ||
- Memory: 32GB | ||
- SO: Ubuntu 20.04.4 LTS | ||
| Measures | Node 17.7.2 | Chrome 100.0.4896.75 | Firefox 99.0 <sup>2</sup> :thinking: | | ||
| ------------------- | ----------- | -------------------- | ------------------------------------ | | ||
| Max. Value | 279763.93 | 295386.07 | 852514.92 | | ||
| Min. Value | 277344.35 | 287802.91 | 827814.57 | | ||
| Average<sup>1</sup> | 279574.05 | 293929.66 | 840884.13 | | ||
- Operations per second | ||
- <sup>1</sup> The average is calculated removing the maximum and the minimum values | ||
- <sup>2</sup> For some reason Firefox returned a really good but suspicious performance |
@@ -5,13 +5,14 @@ /** | ||
* | ||
* Arrays can be merged or changed with `$push` (or `$append`), | ||
* `$prepend` or `$set` methods. | ||
* Arrays can be merged or changed with `$push`, `$prepend`, `$set`, `$replace` or `$insert` | ||
* operations. Multiple operations can be passed. | ||
* | ||
* @see {@link https://github.com/kleber-swf/deepmerge-json#readme} | ||
* @param first Base object | ||
* @param second Object that will overrite base properties | ||
* @param pre Base object | ||
* @param pos Object that will overrite base properties. If none is given, the first object is | ||
* deeply cloned | ||
* @returns A deep clone object containing a combination of all | ||
* properties from first and second arguments. | ||
* properties from pre and pos arguments. | ||
*/ | ||
declare function merge<T1, T2>(first: Partial<T1>, second: Partial<T2>): T1 & T2; | ||
declare function merge<T1, T2>(pre: Partial<T1>, pos?: Partial<T2>): T1 & T2; | ||
export default merge; |
@@ -18,6 +18,10 @@ const directReplace = (_, pos) => pos; | ||
const mergeArrayWithParams = function (pre, pos) { | ||
const key = Object.keys(pos)[0]; // (x_x) This is ugly | ||
return key in arrayMergeFn | ||
? arrayMergeFn[key](pre.slice(), pos[key]) | ||
: pos; | ||
pre = pre.slice(); | ||
Object.keys(pos).forEach(key => { | ||
pre = key in arrayMergeFn | ||
? arrayMergeFn[key](pre, pos[key]) | ||
: pos; | ||
}); | ||
return pre; | ||
}; | ||
@@ -71,3 +75,10 @@ | ||
function merge(pre, pos) { | ||
if (!pos) return pos; | ||
if (pos === undefined) { | ||
if (pre == null) return pre; | ||
if (Array.isArray(pre)) pos = []; | ||
else if (typeof pre === 'object') pos = {}; | ||
else pos = pre; | ||
} else if (pos === null) { | ||
return null; | ||
} | ||
const tt = Array.isArray(pre) ? 'a' : typeof pre === 'object' ? 'o' : 'b'; | ||
@@ -78,2 +89,13 @@ const st = Array.isArray(pos) ? 'a' : typeof pos === 'object' ? 'o' : 'b'; | ||
merge.clone = obj => merge(obj); | ||
merge.multi = (pre, ...args) => { | ||
if (!args) return merge(pre); | ||
for (let i = 0; i < args.length; i++) { | ||
pre = merge(pre, args[i]); | ||
} | ||
return pre; | ||
} | ||
export default merge; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
32569
13
237
355