Merge objects/arrays declaratively.
- Objects: deeply, shallowly, or both
- Arrays: items can be updated, merged, added, inserted, appended, prepended, deleted or set
This is intended for cases where objects/arrays manipulation in JavaScript is not available.
For example, a library where shared configuration files can be extended.
extend: my-shared-config
# Deep merge
log:
verbosity: silent
# Shallow merge
provider:
_merge: shallow
name: redis
type: local
# Delete properties
output:
_merge: delete
rules:
# Update arrays deeply
1:
level: silent
# Append arrays
'-0':
name: appendedRuleOr a server receiving network patch requests.
PATCH /pets/0{
// Deep merge
"capabilities": { "play": true },
// Shallow merge
"title": { "name": "felix", "_merge": "shallow" },
// Append arrays
"toys": { "-0": "newToy" }
}import declarativeMerge from 'declarative-merge'
declarativeMerge({ a: 1, b: { c: 2 }, d: 3 }, { a: 10, b: { e: 20 } })
// { a: 10, b: { c: 2, e: 20 }, d: 3 }declarativeMerge(
{ a: 1, b: { c: 2 }, d: 3 },
{ a: 10, b: { e: 20 }, _merge: 'shallow' },
)
// { a: 10, b: { e: 20 }, d: 3 }declarativeMerge(
{ a: 1, b: { c: 2 }, d: 3 },
{ a: 10, b: { e: 20 }, _merge: 'set' },
)
// { a: 10, b: { e: 20 } }// `_merge` can be specified in nested objects
declarativeMerge(
{ a: 1, b: { c: 2 }, d: 3 },
{ a: 10, b: { e: 20, _merge: 'set' } },
)
// { a: 10, b: { e: 20 }, d: 3 }
declarativeMerge(
{ a: 1, b: { c: 2 }, d: 3 },
{ a: 10, b: { e: 20, _merge: 'deep' }, _merge: 'set' },
)
// { a: 10, b: { c: 2, e: 20 } }declarativeMerge(
{ a: 1, b: { c: 2 }, d: 3 },
{ a: 10, b: { e: 20, _merge: 'delete' } },
)
// { a: 10, d: 3 }// By default, arrays override each other
declarativeMerge({ one: ['a', 'b', 'c'] }, { one: ['X', 'Y'] }) // { one: ['X', 'Y'] }
// They can be updated instead using an object where the keys are the array
// indices (before any updates).
declarativeMerge(
{ one: ['a', 'b', 'c'], two: 2 },
{ one: { 1: 'X' }, three: 3 },
)
// { one: ['a', 'X', 'c'], two: 2, three: 3 }
// This works on top-level arrays too
declarativeMerge(['a', 'b', 'c'], { 1: 'X', 2: 'Y' }) // ['a', 'X', 'Y']// If the new array items are objects, they are merged
declarativeMerge(
[{ id: 'a' }, { id: 'b', value: { name: 'Ann' } }, { id: 'c' }],
{ 1: { value: { color: 'red' } } },
)
// [{ id: 'a' }, { id: 'b', value: { name: 'Ann', color: 'red' } }, { id: 'c' }]
declarativeMerge(
[{ id: 'a' }, { id: 'b', value: { name: 'Ann' } }, { id: 'c' }],
{ 1: { value: { color: 'red' }, _merge: 'shallow' } },
)
// [{ id: 'a' }, { id: 'b', value: { color: 'red' } }, { id: 'c' }]declarativeMerge(['a', 'b', 'c'], { '*': 'X' }) // ['X', 'X', 'X']
declarativeMerge(['a', 'b', 'c'], { '-1': 'X' }) // ['a', 'b', 'X']
declarativeMerge(['a', 'b', 'c'], { 4: 'X' }) // ['a', 'b', 'c', undefined, 'X']// Array of items can be used
declarativeMerge(['a', 'b', 'c'], { 1: ['X', 'Y'] }) // ['a', 'X', 'Y', 'c']
declarativeMerge(['a', 'b', 'c'], { 1: ['X'] }) // ['a', 'X', 'c']
declarativeMerge(['a', 'b', 'c'], { 1: [['X']] }) // ['a', ['X'], 'c']// If the key ends with +, items are prepended, not replaced
declarativeMerge(['a', 'b', 'c'], { '1+': 'X' }) // ['a', 'X', 'b', 'c']declarativeMerge(['a', 'b', 'c'], { '-0': 'X' }) // ['a', 'b', 'c', 'X']
declarativeMerge(['a', 'b', 'c'], { '-0': ['X', 'Y'] }) // ['a', 'b', 'c', 'X', 'Y']declarativeMerge(['a', 'b', 'c'], { '0+': ['X', 'Y'] }) // ['X', 'Y', 'a', 'b', 'c']declarativeMerge(['a', 'b', 'c'], { 1: [] }) // ['a', 'c']declarativeMerge({}, { one: { 0: 'X', 2: 'Z' } }) // { one: ['X', undefined, 'Z'] }
declarativeMerge({ one: true }, { one: { 0: 'X', 2: 'Z' } }) // { one: ['X', undefined, 'Z'] }npm install declarative-mergeThis package works in both Node.js >=18.18.0 and browsers.
This is an ES module. It must be loaded using
an import or import() statement,
not require(). If TypeScript is used, it must be configured to
output ES modules,
not CommonJS.
firstValue any
secondValue any
options Options
Return value: any
Merge firstValue and secondValue.
Any object can change the merge mode using a _merge property with
value "deep" (default), "shallow",
"set" or "delete".
Arrays can be merged using objects where the keys are the array indices. Items can be updated, merged, added, inserted, appended, prepended, deleted or set.
The _merge property and array updates objects can only be used in
secondValue. They are left as is in firstValue.
firstValue and secondValue are not modified. Plain objects and arrays are
deeply cloned.
Inherited and non-enumerable properties are ignored.
Options are an optional object.
Type: string | symbol
Default: "_merge"
Name of the property used to specify the merge mode.
declarativeMerge({ a: 1 }, { b: 2, _mergeMode: 'set' }, { key: '_mergeMode' }) // { b: 2 }Symbols can be useful to prevent injections when the input is user-provided.
const mergeMode = Symbol('mergeMode')
declarativeMerge({ a: 1 }, { b: 2, [mergeMode]: 'set' }, { key: mergeMode }) // { b: 2 }set-array: underlying module to merge arrayswild-wild-utils: applydeclarative-mergeon multiple properties at once using this module'smerge()method
For any question, don't hesitate to submit an issue on GitHub.
Everyone is welcome regardless of personal background. We enforce a Code of conduct in order to promote a positive and inclusive environment.
This project was made with ❤️. The simplest way to give back is by starring and sharing it online.
If the documentation is unclear or has a typo, please click on the page's Edit
button (pencil icon) and suggest a correction.
If you would like to help us fix a bug or add a new feature, please check our guidelines. Pull requests are welcome!