1 | # node-object-hash
|
2 |
|
3 | Tiny and fast node.js object hash library with properties/arrays sorting to provide constant hashes.
|
4 | It also provides a method that returns sorted object strings that can be used for object comparison without hashes.
|
5 | One of the fastest among other analogues (see [benchmarks](#Benchmarks)).
|
6 |
|
7 | Hashes are built on top of node's crypto module
|
8 | (so for using in browser use something like [browserify-crypto](https://github.com/crypto-browserify/crypto-browserify) or some kind of crypto functions polyfills). Or you can use only `objectSorter` ([source](https://github.com/SkeLLLa/node-object-hash/blob/master/objectSorter.js)) for getting your objects' string representation and compare or pass them to your own hash function.
|
9 |
|
10 | [![node](https://img.shields.io/node/v/node-object-hash.svg?maxAge=21600&style=flat-square)]()
|
11 | [![NPM](https://img.shields.io/npm/v/node-object-hash.svg?maxAge=21600&style=flat-square)](https://npmjs.org/packages/node-object-hash)
|
12 | [![NPM Downloads](https://img.shields.io/npm/dt/node-object-hash.svg?maxAge=21600&style=flat-square)](https://npmjs.org/packages/node-object-hash)
|
13 | [![Build Status](https://img.shields.io/travis/SkeLLLa/node-object-hash.svg?maxAge=21600&branch=master&style=flat-square)](https://travis-ci.org/SkeLLLa/node-object-hash)
|
14 | [![Known Vulnerabilities](https://snyk.io/test/github/SkeLLLa/node-object-hash/badge.svg?maxAge=21600&style=flat-square)](https://snyk.io/test/github/skellla/node-object-hash)
|
15 | [![Code Climate](https://img.shields.io/codeclimate/github/SkeLLLa/node-object-hash.svg?maxAge=21600&style=flat-square)](https://codeclimate.com/github/SkeLLLa/node-object-hash/code)
|
16 | [![Coverage](https://img.shields.io/codeclimate/coverage/github/SkeLLLa/node-object-hash.svg?maxAge=21600&style=flat-square)](https://codeclimate.com/github/SkeLLLa/node-object-hash/coverage)
|
17 | [![Analytics](https://ga-beacon.appspot.com/UA-90571586-1/node-object-hash/readme?pixel&useReferer)](https://github.com/igrigorik/ga-beacon)
|
18 |
|
19 | # Installation
|
20 |
|
21 | `npm i node-object-hash -S`
|
22 |
|
23 | # Features
|
24 | - Supports object property sorting for constant hashes for objects with same properties, but different order.
|
25 | - Supports ES6 (Weak)Maps and (Weak)Sets.
|
26 | - Supports type coercion (e.g. 1 and "1" will be the same)
|
27 | - rules:
|
28 | - numbers and strings represented without quotes;
|
29 | - boolean values converted to numbers;
|
30 | - Supports all hashes and encodings of crypto library
|
31 | - Supports large objects and arrays
|
32 | - Very fast comparing to other libs (see [Benchmarks](#Benchmarks) section)
|
33 |
|
34 | # Changes
|
35 |
|
36 | ## v0.x.x -> v1.0.0
|
37 |
|
38 | - Sorting mechanism rewritten form ES6 Maps to simple arrays
|
39 | (add <=node-4.0.0 support)
|
40 | - Performance optimization (~2 times faster than 0.x.x)
|
41 | - API changes:
|
42 | - Now module returns 'constructor' function, where you can set
|
43 | default parameters: ```var objectHash = require('node-object-hash')(options);```
|
44 |
|
45 | In case if you still need an old 0.x.x version it's available in `hash.js`
|
46 | file.
|
47 |
|
48 | ## v1.0.X -> v1.1.X
|
49 |
|
50 | Mainly all changes affected codestyle and documentation to provide better
|
51 | experience using this library. There are no changes that should affect
|
52 | functionality.
|
53 |
|
54 | - Renamed `sortObject` function to `sort` (old one is still present in code
|
55 | for backward compatibility).
|
56 | - Performed some refactoring for better codestyle and documentation.
|
57 | - Old version (`0.X.X`) moved to subfolder (`./v0`).
|
58 | - Advanced API reference added: [link](#Full API docs).
|
59 |
|
60 | # API overview
|
61 |
|
62 | ## Constructor `require('node-object-hash')([options])`
|
63 |
|
64 | Returns preconfigured object with API
|
65 |
|
66 | Parameters:
|
67 | * `options`:`object` - object with hasher config options
|
68 | * `options.coerce`:`boolean` - if true performs type coercion (default: `true`);
|
69 | e.g. `hash(true) == hash('1') == hash(1)`, `hash(false) == hash('0') == hash(0)`
|
70 | * `options.sort`:`boolean` - if true performs sorting on objects, arrays, etc. (default: `true`);
|
71 | * `options.alg`:`string` - sets default hash algorithm (default: `'sha256'`); can be overridden in `hash` method;
|
72 | * `options.enc`:`string` - sets default hash encoding (default: `'hex'`); can be overridden in `hash` method;
|
73 |
|
74 | ## API methods
|
75 |
|
76 | ### `hash(object[, options])`
|
77 |
|
78 | Returns hash string.
|
79 | * `object`:`*` object for calculating hash;
|
80 | * `options`:`object` object with options;
|
81 | * `options.alg`:`string` - hash algorithm (default: `'sha256'`);
|
82 | * `options.enc`:`string` - hash encoding (default: `'hex'`);
|
83 |
|
84 | ### `sort(object)`
|
85 |
|
86 | Returns sorted string generated from object (can be used for object comparison)
|
87 | * `object`:`*` - object for sorting;
|
88 |
|
89 | # Full API docs
|
90 |
|
91 | ## Modules
|
92 |
|
93 | <dl>
|
94 | <dt><a href="#module_node-object-hash/objectSorter">node-object-hash/objectSorter</a> : <code><a href="#module_node-object-hash/objectSorter..makeObjectSorter..objectToString">objectToString</a></code></dt>
|
95 | <dd><p>Object sorter module.
|
96 | It provides object sorter function constructor.</p>
|
97 | </dd>
|
98 | <dt><a href="#module_node-object-hash">node-object-hash</a> : <code><a href="#module_node-object-hash..apiConstructor">apiConstructor</a></code></dt>
|
99 | <dd><p>Node object hash module.
|
100 | It provides a methods that return object hash or sorted object string.</p>
|
101 | </dd>
|
102 | </dl>
|
103 |
|
104 | <a name="module_node-object-hash/objectSorter"></a>
|
105 |
|
106 | ## node-object-hash/objectSorter : <code>[objectToString](#module_node-object-hash/objectSorter..makeObjectSorter..objectToString)</code>
|
107 | Object sorter module.
|
108 | It provides object sorter function constructor.
|
109 |
|
110 |
|
111 | * [node-object-hash/objectSorter](#module_node-object-hash/objectSorter) : <code>[objectToString](#module_node-object-hash/objectSorter..makeObjectSorter..objectToString)</code>
|
112 | * [~_guessObjectType(obj)](#module_node-object-hash/objectSorter.._guessObjectType) ⇒ <code>string</code> ℗
|
113 | * [~_guessType(obj)](#module_node-object-hash/objectSorter.._guessType) ⇒ <code>string</code> ℗
|
114 | * [~makeObjectSorter([options])](#module_node-object-hash/objectSorter..makeObjectSorter) ⇒ <code>[objectToString](#module_node-object-hash/objectSorter..makeObjectSorter..objectToString)</code> ℗
|
115 | * [~objectToString(obj)](#module_node-object-hash/objectSorter..makeObjectSorter..objectToString) ⇒ <code>string</code> ℗
|
116 |
|
117 | <a name="module_node-object-hash/objectSorter.._guessObjectType"></a>
|
118 |
|
119 | ### node-object-hash/objectSorter~_guessObjectType(obj) ⇒ <code>string</code> ℗
|
120 | Guesses object's type
|
121 |
|
122 | **Kind**: inner method of <code>[node-object-hash/objectSorter](#module_node-object-hash/objectSorter)</code>
|
123 | **Returns**: <code>string</code> - Object type
|
124 | **Access:** private
|
125 |
|
126 | | Param | Type | Description |
|
127 | | --- | --- | --- |
|
128 | | obj | <code>Object</code> | Object to guess type |
|
129 |
|
130 | **Example**
|
131 | ```js
|
132 | var a = [];
|
133 | _guessObjectType(a) === 'array'; // true
|
134 | ```
|
135 | <a name="module_node-object-hash/objectSorter.._guessType"></a>
|
136 |
|
137 | ### node-object-hash/objectSorter~_guessType(obj) ⇒ <code>string</code> ℗
|
138 | Guesses variable type
|
139 |
|
140 | **Kind**: inner method of <code>[node-object-hash/objectSorter](#module_node-object-hash/objectSorter)</code>
|
141 | **Returns**: <code>string</code> - Variable type
|
142 | **Access:** private
|
143 |
|
144 | | Param | Type | Description |
|
145 | | --- | --- | --- |
|
146 | | obj | <code>\*</code> | Variable to guess type |
|
147 |
|
148 | **Example**
|
149 | ```js
|
150 | var a = '';
|
151 | _guessType(a) === 'string'; // true
|
152 | ```
|
153 | <a name="module_node-object-hash/objectSorter..makeObjectSorter"></a>
|
154 |
|
155 | ### node-object-hash/objectSorter~makeObjectSorter([options]) ⇒ <code>[objectToString](#module_node-object-hash/objectSorter..makeObjectSorter..objectToString)</code> ℗
|
156 | Creates object sorter function
|
157 |
|
158 | **Kind**: inner method of <code>[node-object-hash/objectSorter](#module_node-object-hash/objectSorter)</code>
|
159 | **Returns**: <code>[objectToString](#module_node-object-hash/objectSorter..makeObjectSorter..objectToString)</code> - Object sorting function
|
160 | **Access:** private
|
161 |
|
162 | | Param | Type | Default | Description |
|
163 | | --- | --- | --- | --- |
|
164 | | [options] | <code>Object</code> | | Sorter options |
|
165 | | [options.coerce] | <code>boolean</code> | <code>true</code> | Performs type coercion |
|
166 | | [options.sort] | <code>boolean</code> | <code>true</code> | Performs array, object, etc. sorting |
|
167 |
|
168 | **Example**
|
169 | ```js
|
170 | // with coercion
|
171 | var sorter = makeObjectSorter({coerce: true, sort: false});
|
172 | sorter(1) === "1"; // true
|
173 | // with sort
|
174 | var sorter = makeObjectSorter({coerce: false, sort: true});
|
175 | sorter([2, 3, 1]) === [1, 2, 3]; // true
|
176 | ```
|
177 | <a name="module_node-object-hash/objectSorter..makeObjectSorter..objectToString"></a>
|
178 |
|
179 | #### makeObjectSorter~objectToString(obj) ⇒ <code>string</code> ℗
|
180 | Object sorting function
|
181 |
|
182 | **Kind**: inner method of <code>[makeObjectSorter](#module_node-object-hash/objectSorter..makeObjectSorter)</code>
|
183 | **Returns**: <code>string</code> - Sorted string
|
184 | **Access:** private
|
185 |
|
186 | | Param | Type | Description |
|
187 | | --- | --- | --- |
|
188 | | obj | <code>Object</code> | Object to sort |
|
189 |
|
190 | <a name="module_node-object-hash"></a>
|
191 |
|
192 | ## node-object-hash : <code>[apiConstructor](#module_node-object-hash..apiConstructor)</code>
|
193 | Node object hash module.
|
194 | It provides a methods that return object hash or sorted object string.
|
195 |
|
196 |
|
197 | * [node-object-hash](#module_node-object-hash) : <code>[apiConstructor](#module_node-object-hash..apiConstructor)</code>
|
198 | * _instance_
|
199 | * [.sort(obj)](#module_node-object-hash+sort) ⇒ <code>string</code>
|
200 | * [.hash(obj, [opts])](#module_node-object-hash+hash) ⇒ <code>string</code>
|
201 | * _inner_
|
202 | * [~apiConstructor([options])](#module_node-object-hash..apiConstructor) ⇒ <code>[API](#module_node-object-hash..API)</code>
|
203 | * [~API](#module_node-object-hash..API) : <code>Object</code>
|
204 |
|
205 | <a name="module_node-object-hash+sort"></a>
|
206 |
|
207 | ### node-object-hash.sort(obj) ⇒ <code>string</code>
|
208 | Creates sorted string from given object
|
209 |
|
210 | **Kind**: instance method of <code>[node-object-hash](#module_node-object-hash)</code>
|
211 | **Returns**: <code>string</code> - Sorted object string
|
212 | **Access:** public
|
213 | **See**: [objectToString](#module_node-object-hash/objectSorter..makeObjectSorter..objectToString)
|
214 |
|
215 | | Param | Type | Description |
|
216 | | --- | --- | --- |
|
217 | | obj | <code>\*</code> | JS object to be sorted |
|
218 |
|
219 | **Example**
|
220 | ```js
|
221 | var apiConstructor = require('node-object-hash');
|
222 | var sorter = apiConstructor({sort:true, coerce:true}).sort;
|
223 |
|
224 | sort({b: {b: 1, d: 'x'}, c: 2, a: [3, 5, 1]});
|
225 | // "{a:[1,3,5],b:{b:1,d:x},c:2}"
|
226 | ```
|
227 | <a name="module_node-object-hash+hash"></a>
|
228 |
|
229 | ### node-object-hash.hash(obj, [opts]) ⇒ <code>string</code>
|
230 | Creates hash from given object
|
231 |
|
232 | **Kind**: instance method of <code>[node-object-hash](#module_node-object-hash)</code>
|
233 | **Returns**: <code>string</code> - Object hash value
|
234 | **Access:** public
|
235 |
|
236 | | Param | Type | Default | Description |
|
237 | | --- | --- | --- | --- |
|
238 | | obj | <code>\*</code> | | JS object to hash |
|
239 | | [opts] | <code>Object</code> | | Options |
|
240 | | [opts.alg] | <code>string</code> | <code>"sha256"</code> | Crypto algorithm to use |
|
241 | | [opts.enc] | <code>string</code> | <code>"hex"</code> | Hash string encoding |
|
242 |
|
243 | **Example**
|
244 | ```js
|
245 | var apiConstructor = require('node-object-hash');
|
246 | var hasher = apiConstructor({sort:true, coerce:true}).hash;
|
247 |
|
248 | hash({b: {b: 1, d: 'x'}, c: 2, a: [3, 5, 1]});
|
249 | // "4c18ce0dcb1696b329c8568d94a9830da810437d8c9e6cecf5d969780335a26b"
|
250 | ```
|
251 | <a name="module_node-object-hash..apiConstructor"></a>
|
252 |
|
253 | ### node-object-hash~apiConstructor([options]) ⇒ <code>[API](#module_node-object-hash..API)</code>
|
254 | Generates node-object-hash API object
|
255 |
|
256 | **Kind**: inner method of <code>[node-object-hash](#module_node-object-hash)</code>
|
257 | **Returns**: <code>[API](#module_node-object-hash..API)</code> - Node object hash API instance
|
258 |
|
259 | | Param | Type | Default | Description |
|
260 | | --- | --- | --- | --- |
|
261 | | [options] | <code>Object</code> | | Library options |
|
262 | | [options.coerce] | <code>boolean</code> | <code>true</code> | Performs type coercion |
|
263 | | [options.sort] | <code>boolean</code> | <code>true</code> | Performs array, object, etc. sorting |
|
264 | | [options.alg] | <code>string</code> | <code>"sha256"</code> | Default crypto algorithm to use (can be overridden) |
|
265 | | [options.enc] | <code>string</code> | <code>"hex"</code> | Hash string encoding (can be overridden) |
|
266 |
|
267 | **Example**
|
268 | ```js
|
269 | var apiConstructor = require('node-object-hash');
|
270 | var hashSortCoerce = apiConstructor({sort:true, coerce:true});
|
271 | // or
|
272 | var hashSort = apiConstructor({sort:true, coerce:false});
|
273 | // or
|
274 | var hashCoerce = apiConstructor({sort:false, coerce:true});
|
275 |
|
276 | var objects = {
|
277 | a: {
|
278 | a: [{c: 2, a: 1, b: {a: 3, c: 2, b: 0}}],
|
279 | b: [1, 'a', {}, null],
|
280 | },
|
281 | b: {
|
282 | b: ['a', 1, {}, undefined],
|
283 | a: [{c: '2', b: {b: false, c: 2, a: '3'}, a: true}]
|
284 | },
|
285 | c: ['4', true, 0, 2, 3]
|
286 | };
|
287 | hashSortCoerce.hash(objects.a) === hashSortCoerce.hash(objects.b);
|
288 | // returns true
|
289 |
|
290 | hashSortCoerce.sort(object.c);
|
291 | // returns '[0,1,2,3,4]'
|
292 | ```
|
293 | <a name="module_node-object-hash..API"></a>
|
294 |
|
295 | ### node-object-hash~API : <code>Object</code>
|
296 | Node object hash API object
|
297 |
|
298 | **Kind**: inner typedef of <code>[node-object-hash](#module_node-object-hash)</code>
|
299 | **Properties**
|
300 |
|
301 | | Name | Type | Description |
|
302 | | --- | --- | --- |
|
303 | | hash | <code>function</code> | Returns object hash string (see [hash](#module_node-object-hash+hash)) |
|
304 | | sort | <code>function</code> | Returns sorted object string (see [sort](#module_node-object-hash+sort)) |
|
305 |
|
306 |
|
307 | # Requirements
|
308 |
|
309 | ## version \>=1.0.0
|
310 | - `>=nodejs-0.10.0`
|
311 |
|
312 | ## version \>=0.1.0 && <1.0.0
|
313 | - `>=nodejs-6.0.0`
|
314 | - `>=nodejs-4.0.0` (requires to run node with `--harmony` flag)
|
315 |
|
316 | ## browsers
|
317 | - nodejs `crypto` module for browsers (e.g. [browserify-crypto](https://github.com/crypto-browserify/crypto-browserify)).
|
318 |
|
319 | # Example
|
320 | ```js
|
321 | var hasher = require('node-object-hash');
|
322 |
|
323 | var hashSortCoerce = hasher({sort:true, coerce:true});
|
324 | // or
|
325 | // var hashSortCoerce = hasher();
|
326 | // or
|
327 | // var hashSort = hasher({sort:true, coerce:false});
|
328 | // or
|
329 | // var hashCoerce = hasher({sort:false, coerce:true});
|
330 |
|
331 | var objects = {
|
332 | a: {
|
333 | a: [{c: 2, a: 1, b: {a: 3, c: 2, b: 0}}],
|
334 | b: [1, 'a', {}, null],
|
335 | },
|
336 | b: {
|
337 | b: ['a', 1, {}, undefined],
|
338 | a: [{c: '2', b: {b: false, c: 2, a: '3'}, a: true}]
|
339 | },
|
340 | c: ['4', true, 0, 2, 3]
|
341 | };
|
342 |
|
343 | hashSortCoerce.hash(objects.a) === hashSortCoerce.hash(objects.b);
|
344 | // returns true
|
345 |
|
346 | hashSortCoerce.sort(object.c);
|
347 | // returns '[0,1,2,3,4]'
|
348 | ```
|
349 |
|
350 | For more examples you can see [tests file](https://github.com/SkeLLLa/node-object-hash/blob/master/test/hash2.js)
|
351 | or try it out online at [runkit](https://runkit.com/skellla/node-object-hash-example)
|
352 |
|
353 | # Benchmarks
|
354 |
|
355 | Bench data - array of 100000 complex objects
|
356 |
|
357 | ## Usage
|
358 |
|
359 | * `npm run bench` to run custom benchmark
|
360 | * `npm run bench2` to run benchmark suite
|
361 |
|
362 | ## Results
|
363 |
|
364 | ### Custom benchmark ([code](bench/index.js))
|
365 |
|
366 | | Library | Time (ms) | Memory (Mb) |
|
367 | |---------------------------------------|------------|--------------------|
|
368 | | node-object-hash-0.2.1 | 5813.575 | 34 |
|
369 | | node-object-hash-1.0.X | 2805.581 | 27 |
|
370 | | node-object-hash-1.1.X (node v7) | 2555.583 | 27 |
|
371 | | object-hash-1.1.5 (node v7) | 28115.553 | 39 |
|
372 | | object-hash-1.1.4 | 534528.254 | 41 |
|
373 | | object-hash-1.1.3 | ERROR | Out of heap memory |
|
374 | | hash-object-0.1.7 | 9219.826 | 42 |
|
375 |
|
376 | ### Benchmark suite module ([code](bench/bench.js))
|
377 |
|
378 | ```
|
379 | node-object-hash x 844 ops/sec ±2.51% (82 runs sampled)
|
380 | node-object-hash-v0 x 540 ops/sec ±1.34% (82 runs sampled)
|
381 | hash-object x 310 ops/sec ±0.88% (81 runs sampled)
|
382 | object-hash x 107 ops/sec ±1.66% (72 runs sampled)
|
383 | ```
|
384 |
|
385 | ## Links
|
386 |
|
387 | * https://www.npmjs.com/package/object-hash (Slow, useful for browsers because it not uses node's crypto library)
|
388 | * https://www.npmjs.com/package/hash-object (no ES6 types support)
|
389 |
|
390 | # License
|
391 |
|
392 | ISC
|