Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

deeply

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

deeply - npm Package Compare versions

Comparing version 1.0.0 to 2.0.0

adapters.js

14

immutable.js

@@ -7,14 +7,14 @@ var mutable = require('./mutable.js');

/**
* Creates untangled copy (deep clone) of the provided object,
* and deeply merges properties of the rest of the provided objects.
* Creates untangled copy (deep clone) of the provided value,
* and deeply merges rest of the provided values.
*
* @param {...object} object - objects to merge/clone
* @param {function} [reduceArrays] - reduce function for custom array merging
* @returns {object} deep merged copy of all the provided objects
* @param {...mixed} value - value(s) to merge/clone
* @returns {mixed} - deep merged copy of all the provided values
*/
function immutable(/* a[, b[, ...[, reduceArrays]]] */)
function immutable(/* a[, b[, ...]] */)
{
// invoke mutable with new object as first argument
var args = Array.prototype.slice.call(arguments, 0);
return mutable.apply(this, [{}].concat(args));
// use `undefined` as always-override value
return mutable.apply(this, [undefined].concat(args));
}

@@ -1,2 +0,4 @@

var mutable = require('./mutable.js')
var behaviors = require('./flags.js')
, adapters = require('./adapters.js')
, mutable = require('./mutable.js')
, immutable = require('./immutable.js')

@@ -8,4 +10,8 @@ ;

module.exports = immutable;
// expose both options
// expose both variants
module.exports.mutable = mutable;
module.exports.immutable = immutable;
// expose behavior flags
module.exports.behaviors = behaviors;
// expose available adapters
module.exports.adapters = adapters;

@@ -0,42 +1,22 @@

var merge = require('./merge.js');
// Public API
module.exports = deeply;
module.exports = mutable;
/**
* Deeply merges properties of the provided objects,
* into the first object.
* Deeply merges properties of the provided objects, into the first object.
*
* @param {...object} object - objects to merge
* @param {function} [reduceArrays] - reduce function for custom array merging
* @returns {object} first object with merged in properties from other objects
* @param {...mixed} value - values to merge
* @returns {mixed} first value with merged in properties from other values
*/
function deeply(/* a[, b[, ...[, reduceArrays]]] */)
function mutable(/* a[, b[, ...]] */)
{
var o
, prop
, args = Array.prototype.slice.call(arguments)
, result = args.shift()
, reduceArrays = typeof args[args.length-1] == 'function' ? args.pop() : undefined
var source
, args = Array.prototype.slice.call(arguments)
, result = args.shift()
;
while ((o = args.shift()))
while ((source = args.shift()))
{
for (prop in o)
{
if (!o.hasOwnProperty(prop)) continue;
if (typeof o[prop] == 'object' && preciseTypeOf(o[prop]) == 'object')
{
result[prop] = deeply(result[prop] || {}, o[prop], reduceArrays);
}
// check if there is custom reduce function for array merging
else if (reduceArrays && Array.isArray(o[prop]))
{
// make sure it's all untangled
result[prop] = reduceArrays(result[prop] || [], Array.prototype.slice.call(o[prop]));
}
else
{
result[prop] = o[prop];
}
}
result = merge.call(this, result, source);
}

@@ -46,12 +26,1 @@

}
/**
* Detects real type of the objects like `new Number(1)` and `new Boolean(true)``
*
* @param {mixed} obj - object to get type of
* @returns {string} precise type
*/
function preciseTypeOf(obj)
{
return Object.prototype.toString.call(obj).match(/\[object\s*([^\]]+)\]/)[1].toLowerCase();
}
{
"name": "deeply",
"version": "1.0.0",
"description": "Universal (nodejs + browser) library that deeply merges properties of the provided objects, returns untangled copy (clone). Mutable operations also available.",
"version": "2.0.0",
"description": "A toolkit for deep structure manipulations, provides deep merge/clone functionality out of the box, and exposes hooks and custom adapters for more control and greater flexibility.",
"main": "index.js",
"scripts": {
"lint": "eslint *.js test/*.js",
"test": "nyc --reporter=lcov --reporter=text tape ./test/*.js",
"posttest": "nyc check-coverage --lines 98 --functions 100 --branches 98",
"browser": "browserify test/compatability.js | ghostface | tap-set-exit"
"clean": "rimraf coverage",
"lint": "eslint *.js adapters/*.js test/*.js",
"test": "nyc --reporter=json tape test/*.js | tap-spec",
"browser": "browserify -t browserify-istanbul test/compatability.js | obake --coverage | tap-spec",
"report": "istanbul report",
"size": "browserify index.js | size-table deeply",
"toc": "toc-md README.md",
"files": "pkgfiles --sort=name",
"debug": "tape test/*.js | tap-spec"
},
"pre-commit": [
"clean",
"lint",
"test"
"test",
"browser",
"report",
"size",
"toc",
"files"
],

@@ -27,3 +38,10 @@ "engines": {

"clone",
"mutable",
"immutable",
"object",
"array",
"function",
"prototype",
"util",
"hook",
"browser",

@@ -39,15 +57,22 @@ "client",

"devDependencies": {
"browserify": "^12.0.1",
"codacy-coverage": "^1.1.3",
"coveralls": "^2.11.6",
"eslint": "^1.10.3",
"ghostface": "^1.5.0",
"lodash.partialright": "^3.1.1",
"nyc": "^5.3.0",
"phantomjs": "^1.9.19",
"browserify": "^13.0.0",
"browserify-istanbul": "^2.0.0",
"coveralls": "^2.11.8",
"eslint": "^2.4.0",
"istanbul": "^0.4.2",
"lodash.partialright": "^4.1.2",
"nyc": "^6.1.1",
"obake": "^0.1.2",
"phantomjs-prebuilt": "^2.1.5",
"pre-commit": "^1.1.2",
"reamde": "^1.1.0",
"tap-set-exit": "^1.1.1",
"tape": "^4.4.0"
"rimraf": "^2.5.2",
"size-table": "^0.2.0",
"tap-spec": "^4.1.1",
"tape": "^4.5.1",
"toc-md": "^0.1.0"
},
"dependencies": {
"precise-typeof": "^1.0.2"
}
}
# Deeply [![NPM Module](https://img.shields.io/npm/v/deeply.svg?style=flat)](https://www.npmjs.com/package/deeply)
Universal (nodejs + browser) library that deeply merges properties of the provided objects, returns untangled copy (clone). Mutable operations also available.
A toolkit for deep structure manipulations, provides deep merge/clone functionality out of the box,
and exposes hooks and custom adapters for more control and greater flexibility.

@@ -11,11 +12,40 @@ [![PhantomJS Build](https://img.shields.io/travis/alexindigo/deeply/master.svg?label=browser&style=flat)](https://travis-ci.org/alexindigo/deeply)

[![Dependency Status](https://img.shields.io/david/alexindigo/deeply.svg?style=flat)](https://david-dm.org/alexindigo/deeply)
![Readme](https://img.shields.io/badge/readme-tested-brightgreen.svg?style=flat)
<!-- No flat badge yet [![bitHound Overall Score](https://www.bithound.io/github/alexindigo/deeply/badges/score.svg)](https://www.bithound.io/github/alexindigo/deeply)
Too many false positives [![Codacy Badge](https://img.shields.io/codacy/5f1289b78b7346498797f9f3cd674408.svg)](https://www.codacy.com/app/alexindigo/deeply) -->
[![bitHound Overall Score](https://www.bithound.io/github/alexindigo/deeply/badges/score.svg)](https://www.bithound.io/github/alexindigo/deeply)
[![Readme](https://img.shields.io/badge/readme-tested-brightgreen.svg?style=flat)](https://www.npmjs.com/package/reamde)
| compression | size |
| :--------------- | ------: |
| deeply.js | 15.2 kB |
| deeply.min.js | 5.06 kB |
| deeply.min.js.gz | 1.52 kB |
## Table of Contents
<!-- TOC -->
- [Install](#install)
- [Examples](#examples)
- [Merging](#merging)
- [Cloning](#cloning)
- [Arrays Custom Merging](#arrays-custom-merging)
- [Default Behavior](#default-behavior)
- [Combining Arrays](#combining-arrays)
- [Appending Arrays](#appending-arrays)
- [Appending Arrays and Keeping Unique Elements Only](#appending-arrays-and-keeping-unique-elements-only)
- [Custom Merge Function](#custom-merge-function)
- [Cloning Functions](#cloning-functions)
- [Cloning Prototype Chain](#cloning-prototype-chain)
- [Extend Original Function Prototype](#extend-original-function-prototype)
- [Custom hooks](#custom-hooks)
- [Mutable Operations](#mutable-operations)
- [Ludicrous Mode](#ludicrous-mode)
- [Want to Know More?](#want-to-know-more)
- [License](#license)
<!-- TOC END -->
## Install
> Version `1.0.0` backwards compatible with `0.1.0` version.
```
```sh
$ npm install deeply --save

@@ -26,16 +56,22 @@ ```

### merge
– Deeply merges two or more objects.
By default it provides interface for immutable operations,
also available via explicit require `require('deeply/immutable')`
or `require('deeply').immutable` property.
### Merging
Deeply merges two or more objects.
```javascript
var merge = require('deeply');
var clone = merge({a: {a1: 1}}, {a: {a2: 2}});
var result = merge({a: {a1: 1}}, {a: {a2: 2}}, {b: {b3: 3}});
assert.deepEqual(clone, {a: {a1: 1, a2: 2}});
assert.equal(result, {a: {a1: 1, a2: 2}, b: {b3: 3}});
```
### clone
– As degenerated case of merging one object on itself, it's possible to use deeply as deep clone function.
### Cloning
As degenerated case of merging one object on itself, it's possible to use deeply as deep clone function.
```javascript

@@ -50,35 +86,315 @@ var merge = require('deeply');

assert.deepEqual(x.a.b.c, 1);
assert.equal(x.a.b.c, 1);
```
### arrays custom merging
– By default array treated as primitive values and being replaced upon conflict, for more meaningful array merge strategy, provide custom reduce function as last argument.
### Arrays Custom Merging
#### default behavior
By default array treated as primitive values and being replaced upon conflict,
for more meaningful array merge strategy, provide one of the pre-built array merge helpers
or a custom reduce function within invocation context.
#### Default Behavior
```javascript
var merge = require('deeply');
var clone = merge({ a: { b: [0, 2, 4] }}, { a: {b: [1, 3, 5] }});
var result = merge({ a: { b: [0, 2, 4, {a: 'A'}], c: 'first' }}, { a: {b: [1, 3, 5, {b: 'B'}], d: 'second' }});
assert.deepEqual(clone, { a: { b: [1, 3, 5] }});
assert.equal(result, { a: { b: [1, 3, 5, {b: 'B'}], c: 'first', d: 'second' }});
```
#### custom merge function
#### Combining Arrays
```javascript
var merge = require('deeply');
var result;
function customMerge(a, b)
var context =
{
return (a||[]).concat(b);
useCustomAdapters: merge.behaviors.useCustomAdapters,
'array' : merge.adapters.arraysCombine
};
// it might be useful when you have array of objects
result = merge.call(context, { a: { b: [0, {a: 'A1', b: 'B1'}, 4] }}, { a: {b: [1, {a: 'A2', c: 'C2'}, 5] }});
assert.equal(result, { a: { b: [1, {a: 'A2', b: 'B1', c: 'C2'}, 5] }});
```
#### Appending Arrays
```javascript
var merge = require('deeply');
var context =
{
useCustomAdapters: merge.behaviors.useCustomAdapters,
'array' : merge.adapters.arraysAppend
};
var result = merge.call(context, { a: { b: [0, 2, 4, 4, 2, 0] }}, { a: {b: [1, 3, 5, 5, 3, 1] }});
assert.equal(result, { a: { b: [0, 2, 4, 4, 2, 0, 1, 3, 5, 5, 3, 1] }});
```
#### Appending Arrays and Keeping Unique Elements Only
```javascript
var merge = require('deeply');
var context =
{
useCustomAdapters: merge.behaviors.useCustomAdapters,
'array' : merge.adapters.arraysAppendUnique
};
var result = merge.call(context, { a: { b: [0, 2, 4, 4, 2, 0] }}, { a: {b: [1, 3, 5, 5, 3, 1] }});
assert.equal(result, { a: { b: [0, 2, 4, 1, 3, 5] }});
```
#### Custom Merge Function
For example we need to have merging arrays to be appended,
with only unique elements and sort the result array.
```javascript
var merge = require('deeply');
var context =
{
useCustomAdapters: merge.behaviors.useCustomAdapters,
'array' : appendUniqueAndSort
};
var result = merge.call(context, { a: { b: [0, 2, 4, 4, 2, 0] }}, { a: {b: [1, 3, 5, 5, 3, 1] }});
assert.equal(result, { a: { b: [0, 1, 2, 3, 4, 5] }});
// Custom array adapter
function appendUniqueAndSort(to, from, merge)
{
// append only if new element isn't present yet
from.forEach(function(v) { to.indexOf(v) == -1 && to.push(merge(undefined, v)); });
// and sort
return to.sort();
}
```
var clone = merge({ a: { b: [0, 2, 4] }}, { a: {b: [1, 3, 5] }}, customMerge);
### Cloning Functions
assert.deepEqual(clone, { a: { b: [0, 2, 4, 1, 3, 5] }});
By default, functions copied as is to the result object,
basically being treated as primitive values.
You can use `functionsClone` adapter to clone functions,
creating new function object with the same signature as original.
```javascript
var clone = require('deeply');
function subj(a, b)
{
return a + b + 10;
}
subj.customProp = 13;
subj.prototype.A = 1;
subj.prototype.B = {isB: 'true'};
var context =
{
useCustomAdapters: clone.behaviors.useCustomAdapters,
'function' : clone.adapters.functionsClone
};
var result = clone.call(context, { a: { b: subj}});
// cloned object function named subj
assert.equal(result, { a: { b: subj}});
// same signature
assert.equal(subj.name, result.a.b.name);
assert.equal(subj.length, result.a.b.length);
assert.equal(subj.customProp, result.a.b.customProp);
// separate objects
subj.isOriginal = true;
result.a.b.isCopy = true;
assert.equal(subj.isOriginal, true);
assert.equal(subj.isCopy, undefined);
assert.equal(result.a.b.isOriginal, undefined);
assert.equal(result.a.b.isCopy, true);
// same output
assert.equal(subj(3, 4), result.a.b(3, 4));
```
### mutable operations
#### Cloning Prototype Chain
It will also clone prototype objects,
so use this option with caution.
```javascript
var clone = require('deeply');
function Subj()
{
this.boom = 'Zap!';
}
Subj.prototype.A = 1;
Subj.prototype.B = {isB: 'true'};
var context =
{
useCustomAdapters: clone.behaviors.useCustomAdapters,
'function' : clone.adapters.functionsClone
};
var result = clone.call(context, { class: Subj });
// cloned object function named Subj
assert.equal(result, { class: Subj });
// has prototype properties
assert.equal(result.class.prototype.A, 1);
assert.equal(result.class.prototype.B.isB, 'true');
// prototypes are decoupled
Subj.prototype.C = 2;
assert.equal(Subj.prototype.C, 2);
assert.equal(result.class.prototype.C, undefined);
// instances
var s1 = new Subj();
var s2 = new result.class();
assert.equal(s1.A, s2.A);
assert.equal(s1.B, s2.B);
assert.equal(s1.C, 2);
assert.equal(s2.C, undefined);
assert.equal(s1.boom, s2.boom);
// but reported instanceof isn't the same
assert.equal(s1 instanceof Subj, true);
assert.equal(s2 instanceof Subj, false);
```
#### Extend Original Function Prototype
When having proper `instanceof` results matters,
you can use `functionsExtend` helper instead.
```javascript
var clone = require('deeply');
function Subj()
{
this.boom = 'Zap!';
return this.boom;
}
Subj.customProp = 13;
Subj.prototype.A = 1;
Subj.prototype.B = {isB: 'true'};
var context =
{
useCustomAdapters: clone.behaviors.useCustomAdapters,
'function' : clone.adapters.functionsExtend
};
var result = clone.call(context, { class: Subj });
// cloned object function named Subj
assert.equal(result, { class: Subj });
// same signature
assert.equal(Subj.name, result.class.name);
assert.equal(Subj.length, result.class.length);
assert.equal(Subj.customProp, result.class.customProp);
// separate objects
Subj.isOriginal = true;
result.class.isCopy = true;
assert.equal(Subj.isOriginal, true);
assert.equal(Subj.isCopy, undefined);
assert.equal(result.class.isOriginal, undefined);
assert.equal(result.class.isCopy, true);
// same output
assert.equal(Subj(), result.class());
// has prototype properties
assert.equal(result.class.prototype.A, 1);
assert.equal(result.class.prototype.B.isB, 'true');
// prototypes are extended
Subj.prototype.X = 67;
assert.equal(Subj.prototype.X, 67);
assert.equal(result.class.prototype.X, 67);
// instances
var s1 = new Subj();
var s2 = new result.class();
assert.equal(s1.A, s2.A);
assert.equal(s1.B, s2.B);
assert.equal(s1.boom, s2.boom);
// but reported instanceof isn't the same
assert.equal(s1 instanceof Subj, true);
assert.equal(s2 instanceof Subj, true);
```
### Custom hooks
As shown in [Custom Merge Function](#custom-merge-function) example,
you can add custom adapters for any data type
that supported by [precise-typeof](https://www.npmjs.com/precise-typeof).
For this example we will combine arrays of number,
by performing addition operation on array elements.
```javascript
var merge = require('deeply');
var context =
{
useCustomAdapters: merge.behaviors.useCustomAdapters,
'array' : merge.adapters.arraysCombine,
'number' : addNumbers
};
var result = merge.call(context, { a: { b: [0, 2, 4, 4, 2, 0] }}, { a: {b: [1, 3, 5, 5, 3, 1] }}, { a: {b: [7, 8, 9, 10, 11, 12] }});
assert.equal(result, { a: { b: [8, 13, 18, 19, 16, 13] }});
// Custom number adapter
function addNumbers(to, from)
{
return (to || 0) + from;
}
```
### Mutable Operations
Mutable interface supports all the described operations,
and available via explicit require `require('deeply/mutable')`
or `require('deeply').mutable` property.
```javascript
var merge = require('deeply/mutable');

@@ -89,9 +405,55 @@ var myObj = {a: {a1: 1, a2: 2}, b: {b1: 11, b2: 12}};

assert.deepEqual(myObj, {a: {a1: 1, a2: 2}, b: {b1: 11, b2: 12}, c: 'c', d: 'd', x: {y: {z: -Infinity}}});
assert.equal(myObj, {a: {a1: 1, a2: 2}, b: {b1: 11, b2: 12}, c: 'c', d: 'd', x: {y: {z: -Infinity}}});
```
More examples can be found in ```test/index.js```.
### Ludicrous Mode
Also as shortcut and a homage to Tesla, ludicrous mode is available,
that will clone functions and it's prototype objects by default. :)
Details could be found in [Cloning Functions](#cloning-functions) examples.
```javascript
var ludicrous = require('deeply/ludicrous');
var scopeVar = 6;
function original(a, b)
{
return a + b + scopeVar;
}
var cloned = ludicrous({ func: original });
// cloned object function named subj
assert.equal(cloned, { func: original });
// same signature
assert.equal(original.name, cloned.func.name);
assert.equal(original.length, cloned.func.length);
// separate objects
original.isOriginal = true;
cloned.func.isCopy = true;
assert.equal(original.isOriginal, true);
assert.equal(original.isCopy, undefined);
assert.equal(cloned.func.isOriginal, undefined);
assert.equal(cloned.func.isCopy, true);
// same output
assert.equal(original(1, 2), cloned.func(1, 2));
```
_Note: `ludicrous` isn't included into the main `deeply` package, so it won't be automatically pulled in,
if you're bundling using `browserify deeply/index.js`, to use ludicrous in the browser you'd need to explicitly
require it in your modules or specify direct path in your bundler config._
## Want to Know More?
More examples can be found in [test/compatability.js](test/compatability.js).
Or open an [issue](https://github.com/alexindigo/deeply/issues) with questions and/or suggestions.
## License
Deeply is licensed under the MIT license.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc