https://github.com/kleber-swf/deepmerge-json
A library to deep merge json files with array operations
https://github.com/kleber-swf/deepmerge-json
clone copy deepmerge extend javascript json merge recursive typescript
Last synced: about 1 year ago
JSON representation
A library to deep merge json files with array operations
- Host: GitHub
- URL: https://github.com/kleber-swf/deepmerge-json
- Owner: kleber-swf
- License: mit
- Created: 2019-07-01T14:36:45.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2024-06-17T02:15:18.000Z (almost 2 years ago)
- Last Synced: 2025-03-19T03:37:17.939Z (about 1 year ago)
- Topics: clone, copy, deepmerge, extend, javascript, json, merge, recursive, typescript
- Language: JavaScript
- Size: 324 KB
- Stars: 10
- Watchers: 0
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Deepmerge Json
[](https://travis-ci.org/kleber-swf/deepmerge-json)



# What
A simple library to deep merge json files with array operations. Hugely inspired by the awesome [deepmerge](https://github.com/TehShrike/deepmerge) project.
> Note that you can use to merge javascript objects, but the main reason this library was created was to merge json files with optional special operations for array merging.
# Why
Sometimes you need a deeply copied objects. Sometimes you need to alter these objects to make them more extensible and generic, specially when you are using [convention over configuration](https://en.wikipedia.org/wiki/Convention_over_configuration) or [convention over code](https://en.wikipedia.org/wiki/Convention_over_Code) patterns.
The objective of this library is to help you with these situations being really simple, performatic and small (~1.5kb).
# How
```js
let left = {
keep: 'keep',
simple: 10,
obj: { a: { multi: { level: 'property' } }, is: 'ok' },
merge: [0, 1, 2, 3],
append: [0, 1, 2],
prepend: [0, 1, 2]
};
let right = {
simple: 20,
obj: { a: { multi: { level: 'and' }, deep: 'property' } },
merge: [10, 20],
append: { $append: [3, 4, 5] },
prepend: { $prepend: [-2, -1] }
};
let result = merge(left, right);
console.log(result);
// Result
{
keep: 'keep',
simple: 20,
obj: { a: { multi: { level: 'and' }, deep: 'property' }, is: 'ok' },
merge: [10, 20, 2, 3],
append: [0, 1, 2, 3, 4, 5],
prepend: [-2, -1, 0, 1, 2]
}
```
**Explanation:** it deeply merges `right` object into `left` without altering them and their properties. Everything is cloned. Arrays elements are merged based on `right` parameters (operators) passed as objects.
# Installation
## With NPM
```sh
npm install deepmerge-json
```
After that you can import it:
```js
import merge from 'deepmerge-json';
```
or
```js
const merge = require('deepmerge-json');
```
There is even a Typescript `d.ts` definition file to support auto complete.
## With a CDN
Just add this line to your HTML file:
```html
**Note for users of version `< 1.4.0`**: if you want the old operation functionality, replace `$replace` for [`$merge`](#merge).
```js
const left = [{ a: 1, b: 1 }, { c: 1 }];
const right = { $merge: [{ a: 2 }] };
const result = merge(left, right);
// Result
[{ a: 2 }, { c: 1 }];
```
### $merge
Use `$merge` to merge or add indexed elements by their indexes. Indexes can be numbers or strings and cannot be less than 0 or `NaN` values. It's similar to [`$replace`](#replace) but instead of replacing the values when found, it merges them with the new values.
#### With valid indexes:
```js
const left = [10, 20, 30];
const right = { $merge: { 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];
```
#### With invalid indexes:
```js
const left = [10, 20, 30];
const right = { $merge: { null: 0, foo: 0, true: 0, '-1': 0 } };
const result = merge(left, right);
// throws an Error
```
#### With objects
```js
const left = [{ a: 1, b: 1 }, { c: 1 }];
const right = { $merge: [{ a: 2 }] };
const result = merge(left, right);
// Result
[{ a: 2, b: 1 }, { c: 1 }];
```
### $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
const left = [10, 20, 30];
const right = { $insert: { 0: 100, 2: 200, 10: 400 } };
const result = merge(left, right);
// Result (notice that the elements moved and the 400 was added to the last index)
[100, 10, 200, 20, 30, 400];
```
#### With negative indexes:
```js
const left = [10, 20, 30];
const right = { $insert: { '-1': 100, '-2': 200, '-10': 0 } };
const result = merge(left, right);
// Result
[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 result = merge(left, right);
// throws an Error
```
### 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.
```js
const left = [1, 20, 3, 40, 5, 60];
const right = [10, , 30, , 50];
const result = merge(left, right);
// Result
[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]
```
```js
const left = [2, 3, 4];
const right: {
$replace: { 0: 100 };
$prepend: [0, 1],
$append: [5, 6],
}
const result = merge(left, right);
// Result
[0, 1, 100, 3, 4, 5, 6]
```
## Merging Multiple Objects
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.
But if you are really nice you can submit a PR and make this lib awesome!
# 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 | 279,763.93 | 295,386.07 | 852,514.92 |
| Min. Value | 277,344.35 | 287,802.91 | 827,814.57 |
| Average<sup>1</sup> | 279,574.05 | 293,929.66 | 840,884.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