Security News
The Risks of Misguided Research in Supply Chain Security
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
@clevercanyon/js-object-mc
Advanced tools
Simple library for deep merge of objects and other types (also for patch and immutable updates). Declarative operations to merge, for example to remove specific properties. Customize merging between specific types. Calculate diffs.
Install this fork with NPM as follows:
$ npm install --save @clevercanyon/js-object-mc;
As noted, this is a fork of VladimirShestakov/merge-change that has been patched to resolve this prototype pollution security issue. The original, but slightly modified README file continues below.
Simple library for deep merge of objects and other types, also for patches and immutable updates.
By default, merge works for "plain objects".
Values of other types are replaced, but you can customize merging between specific types.
Also, you can use declarative operations to specific merge like unset
, leave
, push
and other.
For example to remove some properties of object, to replace "plain objects", to concat arrays.
Calculating diffs between two values.
Install with NPM:
$ npm install --save @clevercanyon/js-object-mc;
Merge with deep cloning without changing the source objects. Great for creating or extending objects from the example (source).
mc.merge(source, ...values);
Example
const mc = require('@clevercanyon/js-object-mc');
// Create new object with adding "a.three" and deleting "a.one"
let first = {
a: {
one: true,
two: 2
}
};
let second = {
a: {
three: 3,
$unset: ['one'] // $unset is a declarative operations
}
};
const result = mc.merge(first, second);
console.log(result);
{ a: { two: 2, three: 3} }
Merge with mutation of the source objects. Nice for patching. New instances will not be created.
mc.patch(source, ...patches);
let first = {
a: {
one: true,
two: 2
}
};
let second = {
a: {
three: 3,
$unset: ['one'] // $unset is a declarative operations
}
};
const result = mc.patch(first, second); // => { a: { two: 2, three: 3} }
// result is a mutated first argument
console.log(result === first); // => true
console.log(result !== second); // => true
Immutable merge - create new instances only if there are diffs (also in inner properties). Nice for state management.
mc.update(source, ...changes);
let first = {
a: {
one: true,
two: 2,
sub: {
value: 3
}
}
};
let second = {
a: {
three: 3,
$unset: ['one'] // $unset is a declarative operations
}
};
const result = mc.update(first, second); // => { a: { two: 2, three: 3, sub: { value: 3 }} }
// result is a new object
console.log(result !== first); // => true
console.log(result !== second); // => true
// object "a.sub" is unchanged
console.log(result.a.sub === first.a.sub); // => true
When merging objects, you can perform delete and replace properties at the same time. Use declarative operations in second or next arguments. Supported in all merge methods. The syntax is similar to mongodb.
$set
To set (or replace) property without deep merge.
const result = mc.merge(
{
a: {
one: 1,
two: 2
}
},
{
$set: {
a: {
three: 3
},
'a.two': 20 // Fields keys can be path.
}
}
);
console.log(result);
Result
{
"a": {
"one": 1,
"two": 20,
"three": 3
}
}
$unset
To unset properties by name (or path)
const result = mc.merge(
{
a: {
one: 1,
two: 2
}
},
{
$unset: ['a.two']
}
);
console.log(result);
Result
{
"a": {
"one": 1
}
}
*
const result = mc.merge(
{
a: {
one: 1,
two: 2
}
},
{
$unset: ['a.*']
}
);
console.log(result);
Result
{
"a": {}
}
$leave
To leave properties by name (or path). All other properties will be removed.
const result = mc(
{
a: {
one: 1,
two: 2,
tree: 3
}
},
{
a: {
$leave: ['two']
}
}
);
console.log(result);
Result
{
"a": {
"two": 2
}
}
$push
To push one value to the array property. The source property must be an array.
const result = mc(
// First object
{
prop1: ['a', 'b'],
prop2: ['a', 'b'],
},
// Merge
{
$push: {
prop1: ['c', 'd'],
prop2: {x: 'c'}
},
}
);
console.log(result);
Result
{
"prop1": ["a", "b", ["c", "d"]],
"prop2": ["a", "b", {"x": "c"}]
}
$concat
To concatenate arrays. The source property must be an array. The property in secondary arguments may not be an array.
const result = mc(
// First object
{
prop1: ['a', 'b'],
prop2: ['a', 'b'],
},
// Merge
{
$concat: {
prop1: ['c', 'd'],
prop2: {x: 'c'}
},
}
);
console.log(result);
Result
{
"prop1": ["a", "b", "c", "d"],
"prop2": ["a", "b", {"x": "c"}]
}
You can declare function for merge custom types (or override default logic). Returns previous merge method.
mc.addMerge(type1, type2, callback)
type1, type2
- constructor name of the first and second values: Number, String, Boolean, Object, Array, Date, RegExp, Function, Undefined, Null, Symbol, Set, Map
and other system and custom constructor namescallback
- merge function with argument: (first, second, kind)
first
- first value for mergesecond
- second value for mergekind
- name of merging method, such as "merge", "patch", "update".For example, if you always need to union arrays, you can declare method to merge array with array.
const previous = mc.addMerge('Array', 'Array', function(first, second, kind){
// merge - creaete new array with deep clone
if (kind === 'merge'){
return first.concat(second).map(item => mc.merge(undefined, item));
}
// patch - mutate first array
if (kind === 'patch'){
first.splice(first.length, 0, ...second);
return first;
}
// update - return first array if second is empty, or create new without clone
if (second.length === 0){
return first;
} else {
return first.concat(second);
}
});
// reset custom method
mc.addMerge('Array', 'Array', previous);
You can declare function for declarative operation (or override default logic). Returns previous operation method.
mc.addOperation(name, callback)
name
- operation name, for example "$concat"callback
- operation function with argument: (source, params). Return new value or source.
source
- the value in which the operation is defined (source: {$concat: params}
)params
- value of operator ($concat: params
)For example, if sometimes need to union arrays, you can declare declarative operation $concat (it exists in the library).
const previous = mc.addOperation('$concat', function(source, params){
const paths = Object.keys(params);
for (const path of paths) {
let value = params[path];
let array = utils.get(source, path, []);
if (Array.isArray(array)) {
array = array.concat(value);
utils.set(source, path, array);
} else {
throw new Error('Cannot concat on not array');
}
}
return paths.length > 0;
});
// reset custom operation
mc.addOperation('$concat', previous);
Useful functions - utilities
const utils = require('@clevercanyon/js-object-mc').utils;
utils.diff(source, compare, {ignore = [], separator = '.'})
To calculate the difference between source
and compare
value.
The return value is an object with $set
and $unset
operators. Return value can be used in merge functions.
The ignore
parameter - is a list of properties that are not included in the comparison.
const first = {
name: 'value',
profile: {
surname: 'Surname',
birthday: new Date(),
avatar: {
url: 'pic.png'
}
},
access: [100, 350, 200],
secret: 'x'
}
const second = {
login: 'value',
profile: {
surname: 'Surname2',
avatar: {
url: 'new/pic.png'
}
},
access: [700]
}
const diff = utils.diff(first, second, {ignore: ['secret'], separator: '/'});
Result (diff)
{
$set: {
'login': 'value',
'profile.surname': 'Surname2',
'profile.avatar.url': 'new/pic.png',
'access': [ 700 ]
},
$unset: [
'profile.birthday',
'name'
]
}
utils.type(value)
Get real type of any value. The return value is a string - the name of the constructor.
utils.type(null); // => 'Null'
utils.type(true); // => 'Boolean'
utils.type(new ObjectId()); // => 'ObjectID'
utils.instanceof(value, className)
Checking instance of class. className
is string (not constructor). The return value is a boolean.
utils.instanceof(100, 'Number'); // => true
utils.instanceof(new MyClass(), 'MyClass'); // => true
utils.instanceof(new MyClass(), 'Object'); // => true
utils.plain(value)
Converting deep value to plain types if value has plain representation. For example, all dates are converted to a string, but RegEx not.
To customize conversion, you can define the [methods.toPlain]()
method in your object.
Nice for unit tests.
The method is similar to converting to JSON, only objects (arrays, functions...) are not converted to string representation.
const plain = utils.plain({
date: new Date('2021-01-07T19:10:21.759Z'),
prop: {
_id: new ObjectId('6010a8c75b9b393070e42e68')
}
});
Result (plain)
{
date: '2021-01-07T19:10:21.759Z',
prop: {
_id: '6010a8c75b9b393070e42e68'
}
}
utils.flat(value, path = '', separator = '.', clearUndefined = false)
Converting a nested structure to a flat object.
Property names become path with separator
.
To customize conversion, you can define the [methods.toFlat]()
method in your object.
const value = {
a: {
b: {
c: 100
}
}
};
const flat = utils.flat(value, 'parent', '.');
Result (flat)
{
'parent.a.b.c': 100
}
FAQs
Simple library for deep merge of objects and other types (also for patch and immutable updates). Declarative operations to merge, for example to remove specific properties. Customize merging between specific types. Calculate diffs.
The npm package @clevercanyon/js-object-mc receives a total of 0 weekly downloads. As such, @clevercanyon/js-object-mc popularity was classified as not popular.
We found that @clevercanyon/js-object-mc demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
Research
Security News
Socket researchers found several malicious npm packages typosquatting Chalk and Chokidar, targeting Node.js developers with kill switches and data theft.
Security News
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.