Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

node-object-hash

Package Overview
Dependencies
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-object-hash - npm Package Compare versions

Comparing version
0.2.1
to
1.0.0
+127
bench/index.js
/**
* Created on 8/23/16.
*/
'use strict';
const faker = require('faker');
const data = [];
const datacount = 100000;
const objectHash = require('object-hash');
const nodeObjectHash = require('../hash');
const nodeObjectHash2 = require('../hash2')();
console.log('Creating fake data...');
for (let i = 0; i < datacount; i++){
data.push({
name: faker.name.firstName(),
date: new Date(),
address: {
city: faker.address.city(),
streetAddress: faker.address.streetAddress(),
country: faker.address.country()
},
email: [
faker.internet.email(),
faker.internet.email(),
faker.internet.email(),
faker.internet.email()
],
randoms: [
faker.random.number(),
faker.random.alphaNumeric(),
faker.random.number(),
faker.random.alphaNumeric(),
faker.random.words(),
faker.random.word()
],
avatars: [
{
number: faker.random.number(),
avatar: faker.internet.avatar()
},{
number: faker.random.number(),
avatar: faker.internet.avatar()
},{
number: faker.random.number(),
avatar: faker.internet.avatar()
},{
number: faker.random.number(),
avatar: faker.internet.avatar()
}
]
});
}
var memStats;
var memMaxHeap = 0;
var memHeapStart;
var data1 = data.slice(0);
var data2 = data.slice(0);
var data3 = data.slice(0);
console.log('Starting benchmark...');
memStats = process.memoryUsage();
memHeapStart = memStats.heapUsed;
console.time('node-object-hash-2');
data1.forEach((it, idx) => {
it.hash = nodeObjectHash2.hash(it);
if (idx % 10000 === 0) {
memStats = process.memoryUsage();
if (memMaxHeap < memStats.heapUsed) {
memMaxHeap = memStats.heapUsed;
}
console.log(`${idx} items processed: RSS:${Math.round(memStats.rss / (1024*1024))}Mb / HEAP: ${Math.round(memStats.heapUsed / (1024*1024))}Mb`)
}
});
console.timeEnd('node-object-hash-2');
memStats = process.memoryUsage();
memMaxHeap = memMaxHeap < memStats.heapUsed ? memStats.heapUsed : memMaxHeap;
console.log(`Memory footprint:\n MAX HEAP DIFF:${Math.round((memMaxHeap-memHeapStart) / (1024*1024))}Mb`);
console.log('Collecting garbage...');
gc();
memMaxHeap = 0;
memStats = process.memoryUsage();
memHeapStart = memStats.heapUsed;
console.time('node-object-hash-1');
data2.forEach((it, idx) => {
it.hash = nodeObjectHash.hash(it);
if (idx % 10000 === 0) {
memStats = process.memoryUsage();
if (memMaxHeap < memStats.heapUsed) {
memMaxHeap = memStats.heapUsed;
}
console.log(`${idx} items processed: RSS:${Math.round(memStats.rss / (1024*1024))}Mb / HEAP: ${Math.round(memStats.heapUsed / (1024*1024))}Mb`)
}
});
console.timeEnd('node-object-hash-1');
memStats = process.memoryUsage();
memMaxHeap = memMaxHeap < memStats.heapUsed ? memStats.heapUsed : memMaxHeap;
console.log(`Memory footprint:\n MAX HEAP DIFF:${Math.round((memMaxHeap-memHeapStart) / (1024*1024))}Mb`);
console.log('Collecting garbage...');
gc();
memMaxHeap = 0;
memStats = process.memoryUsage();
memHeapStart = memStats.heapUsed;
console.time('object-hash');
data3.forEach((it, idx) => {
it.hash = objectHash(it, {algorithm: 'sha256', encoding: 'hex', unorderedArrays: true});
if (idx % 10000 === 0) {
memStats = process.memoryUsage();
if (memMaxHeap < memStats.heapUsed) {
memMaxHeap = memStats.heapUsed;
}
console.log(`${idx} items processed: RSS:${Math.round(memStats.rss / (1024*1024))}Mb / HEAP: ${Math.round(memStats.heapUsed / (1024*1024))}Mb`)
}
});
console.timeEnd('object-hash');
memStats = process.memoryUsage();
memMaxHeap = memMaxHeap < memStats.heapUsed ? memStats.heapUsed : memMaxHeap;
console.log(`Memory footprint:\n MAX HEAP DIFF:${Math.round((memMaxHeap-memHeapStart) / (1024*1024))}Mb`);
/**
* Node.js constant object hash module.
* @exports node-object-hash
* @type {Function}
*/
'use strict';
const crypto = require('crypto');
/**
* Sorts object fields
* @param {Object|Array|string|function} obj Initial object
* @param {Object} options Options
* @param {boolean} [options.coerce=true] Perform coercion
* @param {boolean} [options.sort=true] Perform Array, Set, Object sorting
* @returns {string}
*/
exports.sortedObjectString = (obj, options) => {
const coerce = typeof options.coerce == 'undefined' ? true : options.coerce;
const sort = typeof options.sort == 'undefined' ? true : options.sort;
if (typeof obj == 'object') {
if (Array.isArray(obj)) {
let tmp = [...obj];
tmp.forEach((it, idx) => {
tmp[idx] = exports.sortedObjectString(it, {coerce, sort})
});
return sort ? `[${tmp.sort().toString()}]` : `[${tmp.toString()}]`;
}
if (obj === null) {
return `null`;
}
if (obj instanceof Map) {
return `Map[${[...obj].toString()}]`;
}
if (obj instanceof Set) {
return sort ? `Set[${[...obj].sort().toString()}]` : `Set[${[...obj].toString()}]`;
}
const sortedObj = new Map();
const keys = sort ? Object.keys(obj).sort() : Object.keys(obj);
keys.forEach((key) => {
sortedObj.set(key, exports.sortedObjectString(obj[key], {coerce, sort}));
});
return `{${[...sortedObj].toString()}}`;
}
if (typeof obj == 'function') {
return `${obj.name}=>${obj.toString()}`;
}
if (coerce) {
if (typeof obj == 'boolean') {
return `${Number(obj)}`;
}
} else {
if (typeof obj == 'string') {
return `"${obj}"`
}
}
if (coerce && typeof obj == 'boolean') {
return `${Number(obj)}`;
}
return obj;
};
/**
* Calculates object hash
* @param {Object} obj Object to hash
* @param {Object} [options] Options
* @param {string} [options.alg="sha256"] Crypto algorithm to use
* @param {string} [options.enc="hex"] Hash string encoding
* @param {boolean} [options.coerce=true] Perform coercion
* @param {boolean} [options.sort=true] Perform Array, Set, Object sorting
* @returns {string} Hash string
*/
exports.hash = (obj, options) => {
options = options || {};
const alg = options.alg || 'sha256';
const enc = options.enc || 'hex';
const coerce = typeof options.coerce == 'undefined' ? true : options.coerce;
const sort = typeof options.sort == 'undefined' ? true : options.sort;
if (~crypto.getHashes().indexOf(alg)) {
const sorted = exports.sortedObjectString(obj, {coerce, sort});
return crypto.createHash(alg)
.update(sorted)
.digest(enc);
} else {
throw new Error(`Algorithm ${alg} not supported by "ctypto" module`);
}
};
/**
* Created on 8/23/16.
*/
'use strict';
var crypto = require('crypto');
var objectSorter = require('./objectSorter');
/**
* @typedef {Object} API
* @property {Function} hash Returns object hash
* @property {Function} sortObject Returns sorted object string
*/
/**
* API constructor
* @param {Object} [options] Library options
* @param {boolean} [options.coerce="true"] Performs type coercion
* @param {boolean} [options.sort="true"] Performs array, object, etc. sorting
* @param {string} [options.alg="sha256"] Default crypto algorithm to use (can be overridden)
* @param {string} [options.enc="hex"] Hash string encoding (can be overridden)
* @returns {API} API object
*/
module.exports = function Hash(options) {
var api = {};
var defaults = options || {};
defaults.coerce = typeof defaults.coerce === 'undefined' ? true : defaults.coerce;
defaults.sort = typeof defaults.sort === 'undefined' ? true : defaults.sort;
defaults.alg = defaults.alg || 'sha256';
defaults.enc = defaults.enc || 'hex';
var sortObjectToString = objectSorter(defaults);
/**
* Creates hash from given object
* @param {*} obj JS object to hash
* @param {Object} [opts] Options
* @param {string} [opts.alg="sha256"] Crypto algorithm to use
* @param {string} [opts.enc="hex"] Hash string encoding
* @returns {string} Object hash value
*/
api.hash = function hash(obj, opts) {
opts = opts || {};
var alg = opts.alg || defaults.alg;
var enc = opts.enc || defaults.enc;
var sorted = sortObjectToString(obj);
return crypto.createHash(alg)
.update(sorted)
.digest(enc);
};
/**
* Creates sorted string from object
* @param {*} obj JS object to be sorted
* @returns {string} Sorted object string
*/
api.sortObject = function sortObject(obj) {
return sortObjectToString(obj);
};
return api;
};
/**
* Created on 8/22/16.
*/
'use strict';
/**
* Guesses object's type
* @param {Object} obj Object
* @returns {string}
*/
function guessObjectType(obj) {
var hasMapSet = typeof Map !== 'undefined';
if (obj === null) {
return 'null';
}
if (Array.isArray(obj)) {
return 'array';
}
if (hasMapSet && (obj instanceof Map || obj instanceof WeakMap)) {
return 'map';
}
if (hasMapSet && (obj instanceof Set || obj instanceof WeakSet)) {
return 'set';
}
if (obj instanceof Date) {
return 'date';
}
return 'object';
}
/**
* Guesses variable type
* @param {*} obj
* @returns {string}
*/
function guessType(obj) {
var type = typeof obj;
return type !== 'object' ? type : guessObjectType(obj);
}
/**
* Creates object sorter function
* @param {Object} [options] Sorter options
* @param {string} [options.coerce="true"] Performs type coercion (e.g sorter(true) === ("1"); sorter(1) === ("1"))
* @param {string} [options.sort="true"] Performs array, object, etc. sorting
* @returns {string} Sorted object string
*/
var objectSorter = function (options) {
options = options || {};
var coerce = typeof options.coerce === 'undefined' ? true : options.coerce;
var sort = typeof options.sort === 'undefined' ? true : options.sort;
var self = {};
self.string = function sortString(obj) {
if (coerce) {
return obj;
}
return '<:s>:' + obj;
};
self.number = function sortNumber(obj) {
if (coerce) {
return obj.toString();
}
return '<:n>:' + obj;
};
self.boolean = function sortBoolean(obj) {
if (coerce) {
return obj ? '1' : '0';
}
return obj ? '<:b>:true' : '<:b>:false';
};
self.symbol = function sortSymbol() {
return '<:smbl>';
};
self.undefined = function sortUndefined() {
if (coerce) {
return '';
}
return '<:undf>';
};
self.null = function sortNull() {
if (coerce) {
return '';
}
return '<:null>';
};
self.function = function sortFunction(obj) {
if (coerce){
return obj.name + '=>' + obj.toString();
}
return '<:func>:' + obj.name + '=>' + obj.toString();
};
self.array = function sortArray(obj) {
var item, itemType;
var result = [];
for (var i = 0; i < obj.length; i++) {
item = obj[i];
itemType = guessType(item);
result.push(self[itemType](item));
}
return sort ? '[' + result.sort().toString() + ']' : '[' + result.toString() + ']';
};
self.set = function sortSet(obj) {
return self.array(Array.from(obj));
};
self.date = function sortDate(obj) {
var dateStr = obj.toISOString();
if (coerce) {
return dateStr;
}
return '<:date>:' + dateStr;
};
self.object = function sortObject(obj) {
var keys = sort ? Object.keys(obj).sort() : Object.keys(obj);
var objArray = [];
var key, value, valueType;
for (var i = 0; i < keys.length; i++) {
key = keys[i];
value = obj[key];
valueType = guessType(value);
objArray.push(key + ':' + self[valueType](value))
}
return '{' + objArray.toString() + '}';
};
self.map = function sortMap(obj) {
var arr = Array.from(obj);
var key, value, item;
for (var i = 0; i < arr.length; i++) {
item = arr[i];
key = item[0];
value = item[1];
item = [
self[guessType(key)](key),
self[guessType(value)](value),
];
arr[i] = item;
}
return sort ? '[' + arr.sort().join(';') + ']' : '[' + arr.join(';') + ']';
};
function obj2string(obj) {
return self[guessType(obj)](obj);
}
return obj2string;
};
module.exports = objectSorter;
/**
* Created on 8/23/16.
*/
'use strict';
const hash = require('../hash2');
const assert = require('chai').assert;
const hashSC = hash();
const hashS = hash({coerce: false});
const hashC = hash({sort: false});
const libName = 'node-object-hash-v2';
const objects = {
a: {
b: 1,
c: 3,
a: 4,
f: 0
},
b: {
c: 3,
b: 1,
f: 0,
a: 4
},
c: {
c: '3',
b: 1,
f: '0',
a: 4
},
d: [4, 3, 0, 2, 1],
e: [2, '4', '3', false, true],
f: {
a: [{c: 2, a: 1, b: {a: 3, c: 2, b: 0}}],
b: [1, 'a', {}, null],
},
g: {
b: ['a', 1, {}, undefined],
a: [{c: '2', b: {b: false, c: 2, a: '3'}, a: true}]
}
};
describe(`${libName}`, () => {
describe(`#hash() on objects: [sort=true, coerce=true]`, () => {
it(`should return equal hashes`, () => {
assert.equal(hashSC.hash(objects.a), hashSC.hash(objects.c));
});
});
describe(`#hash() on objects: [sort=true, coerce=false]`, () => {
it(`should return equal hashes`, () => {
assert.equal(hashS.hash(objects.a), hashS.hash(objects.b));
});
});
describe(`#hash() on objects: [sort=false, coerce=true]`, () => {
it(`should return equal hashes`, () => {
assert.equal(hashC.hash(objects.c), hashC.hash(objects.b));
});
});
describe(`#hash() on arrays: [sort=true, coerce=true]`, () => {
it(`should return equal hashes`, () => {
assert.equal(hashSC.hash(objects.d), hashSC.hash(objects.e));
});
});
describe(`#hash() on complex objects: [sort=true, coerce=true]`, () => {
it(`should return equal hashes`, () => {
assert.equal(hashSC.hash(objects.f), hashSC.hash(objects.g));
});
});
describe(`#sortObject() on multitype array: [sort=true, coerce=true]`, () => {
it(`should return sorted array`, () => {
assert.equal(hashSC.sortObject(objects.e), '[0,1,2,3,4]');
});
});
});
+7
-4
{
"name": "node-object-hash",
"version": "0.2.1",
"version": "1.0.0",
"description": "Node.js object hash library with properties/arrays sorting to provide constant hashes",
"main": "index.js",
"main": "hash2.js",
"directories": {

@@ -12,6 +12,9 @@ "test": "test"

"chai": "^3.5.0",
"mocha": "^2.5.3"
"faker": "^3.1.0",
"mocha": "^2.5.3",
"object-hash": "^1.1.4"
},
"scripts": {
"test": "mocha --harmony"
"test": "mocha --harmony",
"bench": "node --expose-gc ./bench/index.js"
},

@@ -18,0 +21,0 @@ "repository": {

+71
-33
# node-object-hash
Node object hash library. Built on top of node's crypto module.
Node.js object hash library with properties/arrays sorting to provide constant hashes.
Built on top of node's crypto module (so for using in browser use something
like browserify or use crypto functions polyfills).
### Installation

@@ -10,3 +13,2 @@ `npm i node-object-hash`

- Supports object property sorting for constant hashes for objects with same properties, but different order.
- NOTE: object arrays should be sorted manually if needed
- Supports ES6 Maps and Sets.

@@ -20,53 +22,89 @@ - Supports type coercion (e.g. 1 and "1" will be the same)

### Changes
#### v0.x.x -> v1.0.0
- Sorting mechanism rewritten form ES6 Maps to simple arrays
(add <=node-4.0.0 support)
- Performance optimization (~2 times faster than 0.x.x)
- API changes:
- Now module returns 'constructor' function, where you can set
default parameters: ```var objectHash = require('node-object-hash')(options);```
### API
#### Constructor `require('node-object-hash')([options])`
Returns preconfigured object with API
Parameters:
* `options`:`<object>` - object with hasher config options
* `options.coerce`:`<boolean>` - if true performs type coercion (default: `true`);
e.g. `hash(true) == hash('1') == hash(1)`, `hash(false) == hash('0') == hash(0)`
* `options.sort`:`<boolean>` - if true performs sorting on objects, arrays, etc. (default: `true`);
* `options.alg`:`<string>` - sets default hash algorithm (default: `'sha256'`); can be overridden in `hash` method;
* `options.enc`:`<string>` - sets default hash encoding (default: `'hex'`); can be overridden in `hash` method;
#### `hash(object[, options])`
Returns hash string.
* `object` object for calculating hash;
* `options` object with options;
* `options.alg` hash algorithm (default: `'sha256'`);
* `options.enc` hash encoding (default: `'hex'`);
* `options.coerce` if true performs type coercion (default: `true`);
* `options.sort` if true performs sorting on objects, arrays and Sets (default: `true`);
* `object`:`<*>` object for calculating hash;
* `options`:`<object>` object with options;
* `options.alg`:`<string>` - hash algorithm (default: `'sha256'`);
* `options.enc`:`<string>` - hash encoding (default: `'hex'`);
#### `sortedObjectString(object[, options])`
#### `sortObject(object)`
Returns sorted string generated from object
* `object` object for calculating hash;
* `options` object with options;
* `options.coerce` if true performs type coercion (default: `true`);
* `options.sort` if true performs sorting on objects, arrays and Sets (default: `true`);
* `object`:`<*>` - object for sorting;
### Requirements
- `>=nodejs-0.10.0` (starting from version 1.0.0)
- `>=nodejs-6.0.0`
- `>=nodejs-4.0.0` (requires to run node with `--harmony` flag)
- nodejs `crypto` module
### Example
```js
const {hash} = require('node-object-hash');
var hasher = require('node-object-hash');
const object = {
x: new Map([['a', 1], ['c', 3], ['b', 2]]),
z: new Set([4,3,2,1]),
f: 2,
e: [{a:2}, 3, {g:2, e:{d:1}}, "rt", "1", "2abc", "3d"],
d: [3,5,6,1,2,3],
c: "3ab",
b: "2",
a: 1
var hashSortCoerce = hasher({sort:true, coerce:true});
// or
// var hashSortCoerce = hasher();
// or
// var hashSort = hasher({sort:true, coerce:false});
// or
// var hashCoerce = hasher({sort:false, coerce:true});
var objects = {
a: {
a: [{c: 2, a: 1, b: {a: 3, c: 2, b: 0}}],
b: [1, 'a', {}, null],
},
b: {
b: ['a', 1, {}, undefined],
a: [{c: '2', b: {b: false, c: 2, a: '3'}, a: true}]
},
c: ['4', true, 0, 2, 3]
};
const hashString = hash(object);
const hashStringSha512 = hash(object, {alg:'sha512'});
hashSortCoerce.hash(objects.a) === hashSortCoerce.hash(objects.b);
// returns true
hashSortCoerce.sortObject(object.c)
// returns '[0,1,2,3,4]'
```
### Compared to same libraries
### Benchmark results
Bench data - array of 100000 complex objects
#### Usage
`npm run bench`
#### Results
| | node-object-hash-0.2.1 | node-object-hash-1.0.0 | object-hash-1.1.4 |
|---|---|---|---|
| Time | 5773.869ms | 2961.812ms | 534528.254ms |
| Memory | ~35Mb | ~33Mb | ~41Mb |
### Similar libraries
* https://www.npmjs.com/package/object-hash
* Pros:
* node-object-hash has twice smaller memory footprint
* five times faster
* ~~no memory leak when using in sync flow~~ (fixed in last version of `object-hash`)
* Cons:
* Only `>=node-4.0.0` supported
### License
ISC
/**
* Node.js constant object hash module.
* @exports node-object-hash
* @type {Function}
*/
'use strict';
const crypto = require('crypto');
/**
* Sorts object fields
* @param {Object|Array|string|function} obj Initial object
* @param {Object} options Options
* @param {boolean} [options.coerce=true] Perform coercion
* @param {boolean} [options.sort=true] Perform Array, Set, Object sorting
* @returns {string}
*/
exports.sortedObjectString = (obj, options) => {
const coerce = typeof options.coerce == 'undefined' ? true : options.coerce;
const sort = typeof options.sort == 'undefined' ? true : options.sort;
if (typeof obj == 'object') {
if (Array.isArray(obj)) {
let tmp = [...obj];
tmp.forEach((it, idx) => {
tmp[idx] = exports.sortedObjectString(it, {coerce, sort})
});
return sort ? `[${tmp.sort().toString()}]` : `[${tmp.toString()}]`;
}
if (obj === null) {
return `null`;
}
if (obj instanceof Map) {
return `Map[${[...obj].toString()}]`;
}
if (obj instanceof Set) {
return sort ? `Set[${[...obj].sort().toString()}]` : `Set[${[...obj].toString()}]`;
}
const sortedObj = new Map();
const keys = sort ? Object.keys(obj).sort() : Object.keys(obj);
keys.forEach((key) => {
sortedObj.set(key, exports.sortedObjectString(obj[key], {coerce, sort}));
});
return `{${[...sortedObj].toString()}}`;
}
if (typeof obj == 'function') {
return `${obj.name}=>${obj.toString()}`;
}
if (coerce) {
if (typeof obj == 'boolean') {
return `${Number(obj)}`;
}
} else {
if (typeof obj == 'string') {
return `"${obj}"`
}
}
if (coerce && typeof obj == 'boolean') {
return `${Number(obj)}`;
}
return obj;
};
/**
* Calculates object hash
* @param {Object} obj Object to hash
* @param {Object} [options] Options
* @param {string} [options.alg="sha256"] Crypto algorithm to use
* @param {string} [options.enc="hex"] Hash string encoding
* @param {boolean} [options.coerce=true] Perform coercion
* @param {boolean} [options.sort=true] Perform Array, Set, Object sorting
* @returns {string} Hash string
*/
exports.hash = (obj, options) => {
options = options || {};
const alg = options.alg || 'sha256';
const enc = options.enc || 'hex';
const coerce = typeof options.coerce == 'undefined' ? true : options.coerce;
const sort = typeof options.sort == 'undefined' ? true : options.sort;
if (~crypto.getHashes().indexOf(alg)) {
const sorted = exports.sortedObjectString(obj, {coerce, sort});
return crypto.createHash(alg)
.update(sorted)
.digest(enc);
} else {
throw new Error(`Algorithm ${alg} not supported by "ctypto" module`);
}
};
/**
* Created on 8/17/16.
*/
'use strict';
const hash = require('../index').hash;
const assert = require('chai').assert;
const obj1 = {
a: 1,
c: 2,
b: "3"
};
const obj2 = {
c: 2,
b: "3",
a: 1
};
describe(`node-object-hash`, () => {
describe(`#hash(obj, {coerce: true, sort: true})`, () => {
it(`should return equal hashes`, () => {
assert.equal(hash(obj1), hash(obj2));
});
});
});
/**
* Created on 7/5/16.
*/
'use strict';
const sortedObjectString = require('../index').sortedObjectString;
const assert = require('chai').assert;
const object = {
x: new Map([['a', 1], ['c', 3], ['b', 2]]),
z: new Set([4,3,2,1]),
f: 2,
e: [{a:2}, 3, {g:2, e:{d:1}}, "rt", "1", "2abc", "3d"],
d: [3,5,6,1,2,3],
c: "3ab",
b: "2",
a: 1
};
describe(`node-object-hash`, () => {
describe(`#sortedObjectString(obj, {coerce: true, sort: true})`, () => {
it(`should return properly sorted object string`, () => {
let options = {coerce: true, sort: true};
assert.equal(sortedObjectString(object, options), `{a,1,b,2,c,3ab,d,[1,2,3,3,5,6],e,[1,2abc,3,3d,rt,{a,2},{e,{d,1},g,2}],f,2,x,Map[a,1,c,3,b,2],z,Set[1,2,3,4]}`);
});
});
});
describe(`node-object-hash`, () => {
describe(`#sortedObjectString(obj, {coerce: true, sort: false})`, () => {
it(`should return properly sorted object string`, () => {
let options = {coerce: true, sort: false};
assert.equal(sortedObjectString(object, options), `{x,Map[a,1,c,3,b,2],z,Set[4,3,2,1],f,2,e,[{a,2},3,{g,2,e,{d,1}},rt,1,2abc,3d],d,[3,5,6,1,2,3],c,3ab,b,2,a,1}`);
});
});
});
describe(`node-object-hash`, () => {
describe(`#sortedObjectString(obj, {coerce: false, sort: true})`, () => {
it(`should return properly sorted object string`, () => {
let options = {coerce: false, sort: true};
assert.equal(sortedObjectString(object, options), `{a,1,b,"2",c,"3ab",d,[1,2,3,3,5,6],e,["1","2abc","3d","rt",3,{a,2},{e,{d,1},g,2}],f,2,x,Map[a,1,c,3,b,2],z,Set[1,2,3,4]}`);
});
});
});
describe(`node-object-hash`, () => {
describe(`#sortedObjectString(obj, {coerce: false, sort: false})`, () => {
it(`should return properly sorted object string`, () => {
let options = {coerce: false, sort: false};
assert.equal(sortedObjectString(object, options), `{x,Map[a,1,c,3,b,2],z,Set[4,3,2,1],f,2,e,[{a,2},3,{g,2,e,{d,1}},"rt","1","2abc","3d"],d,[3,5,6,1,2,3],c,"3ab",b,"2",a,1}`);
});
});
});
describe(`node-object-hash`, () => {
describe(`#sortedObjectString(obj, {coerce: false, sort: false}) Array`, () => {
it(`should return properly sorted object string`, () => {
const src = [5,'4',3,'1',2];
let options = {coerce: true, sort: true};
assert.equal(sortedObjectString(src, options), `[1,2,3,4,5]`);
});
});
});
describe(`node-object-hash`, () => {
describe(`#sortedObjectString(obj, {coerce: false, sort: false}) Object`, () => {
it(`should return properly sorted object string`, () => {
const src = {'b': 1, a:2, c:'5', d:1};
let options = {coerce: true, sort: true};
assert.equal(sortedObjectString(src, options), `{a,2,b,1,c,5,d,1}`);
});
});
});