├── .editorconfig ├── .gitignore ├── .jshintignore ├── .jshintrc ├── changelog.markdown ├── hash-sum.js ├── license ├── package-lock.json ├── package.json ├── readme.md └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "newcap": true, 5 | "noarg": true, 6 | "noempty": true, 7 | "nonew": true, 8 | "sub": true, 9 | "validthis": true, 10 | "undef": true, 11 | "trailing": true, 12 | "boss": true, 13 | "eqnull": true, 14 | "strict": true, 15 | "immed": true, 16 | "expr": true, 17 | "latedef": "nofunc", 18 | "quotmark": "single", 19 | "indent": 2, 20 | "node": true 21 | } 22 | -------------------------------------------------------------------------------- /changelog.markdown: -------------------------------------------------------------------------------- 1 | # 2.0.0 2 | 3 | - Now takes into account result of calling `valueOf` functions when they exist 4 | 5 | # 1.0.2 Quick Sort 6 | 7 | - Sorts object keys so that property order doesn't affect outcome 8 | 9 | # 1.0.1 Perfect Circle 10 | 11 | - Guard against circular references 12 | 13 | # 1.0.0 IPO 14 | 15 | - Initial Public Release 16 | -------------------------------------------------------------------------------- /hash-sum.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function pad (hash, len) { 4 | while (hash.length < len) { 5 | hash = '0' + hash; 6 | } 7 | return hash; 8 | } 9 | 10 | function fold (hash, text) { 11 | var i; 12 | var chr; 13 | var len; 14 | if (text.length === 0) { 15 | return hash; 16 | } 17 | for (i = 0, len = text.length; i < len; i++) { 18 | chr = text.charCodeAt(i); 19 | hash = ((hash << 5) - hash) + chr; 20 | hash |= 0; 21 | } 22 | return hash < 0 ? hash * -2 : hash; 23 | } 24 | 25 | function foldObject (hash, o, seen) { 26 | return Object.keys(o).sort().reduce(foldKey, hash); 27 | function foldKey (hash, key) { 28 | return foldValue(hash, o[key], key, seen); 29 | } 30 | } 31 | 32 | function foldValue (input, value, key, seen) { 33 | var hash = fold(fold(fold(input, key), toString(value)), typeof value); 34 | if (value === null) { 35 | return fold(hash, 'null'); 36 | } 37 | if (value === undefined) { 38 | return fold(hash, 'undefined'); 39 | } 40 | if (typeof value === 'object' || typeof value === 'function') { 41 | if (seen.indexOf(value) !== -1) { 42 | return fold(hash, '[Circular]' + key); 43 | } 44 | seen.push(value); 45 | 46 | var objHash = foldObject(hash, value, seen) 47 | 48 | if (!('valueOf' in value) || typeof value.valueOf !== 'function') { 49 | return objHash; 50 | } 51 | 52 | try { 53 | return fold(objHash, String(value.valueOf())) 54 | } catch (err) { 55 | return fold(objHash, '[valueOf exception]' + (err.stack || err.message)) 56 | } 57 | } 58 | return fold(hash, value.toString()); 59 | } 60 | 61 | function toString (o) { 62 | return Object.prototype.toString.call(o); 63 | } 64 | 65 | function sum (o) { 66 | return pad(foldValue(0, o, '', []).toString(16), 8); 67 | } 68 | 69 | module.exports = sum; 70 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2014 Nicolas Bevacqua 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hash-sum", 3 | "version": "2.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ansi-styles": { 8 | "version": "1.0.0", 9 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", 10 | "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", 11 | "dev": true 12 | }, 13 | "balanced-match": { 14 | "version": "1.0.0", 15 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 16 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 17 | "dev": true 18 | }, 19 | "brace-expansion": { 20 | "version": "1.1.11", 21 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 22 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 23 | "dev": true, 24 | "requires": { 25 | "balanced-match": "^1.0.0", 26 | "concat-map": "0.0.1" 27 | } 28 | }, 29 | "chalk": { 30 | "version": "0.4.0", 31 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", 32 | "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", 33 | "dev": true, 34 | "requires": { 35 | "ansi-styles": "~1.0.0", 36 | "has-color": "~0.1.0", 37 | "strip-ansi": "~0.1.0" 38 | } 39 | }, 40 | "cli": { 41 | "version": "0.4.5", 42 | "resolved": "https://registry.npmjs.org/cli/-/cli-0.4.5.tgz", 43 | "integrity": "sha1-ePlIXNFhtWbppsctcXDEJw6B22E=", 44 | "dev": true, 45 | "requires": { 46 | "glob": ">= 3.1.4" 47 | } 48 | }, 49 | "concat-map": { 50 | "version": "0.0.1", 51 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 52 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 53 | "dev": true 54 | }, 55 | "console-browserify": { 56 | "version": "0.1.6", 57 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-0.1.6.tgz", 58 | "integrity": "sha1-0SijwLuINQ61YmxufHGm8P1ImDw=", 59 | "dev": true 60 | }, 61 | "core-util-is": { 62 | "version": "1.0.2", 63 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 64 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 65 | "dev": true 66 | }, 67 | "deep-equal": { 68 | "version": "0.2.2", 69 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", 70 | "integrity": "sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0=", 71 | "dev": true 72 | }, 73 | "defined": { 74 | "version": "0.0.0", 75 | "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", 76 | "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=", 77 | "dev": true 78 | }, 79 | "domelementtype": { 80 | "version": "1.3.1", 81 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", 82 | "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", 83 | "dev": true 84 | }, 85 | "domhandler": { 86 | "version": "2.1.0", 87 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", 88 | "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", 89 | "dev": true, 90 | "requires": { 91 | "domelementtype": "1" 92 | } 93 | }, 94 | "domutils": { 95 | "version": "1.1.6", 96 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", 97 | "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", 98 | "dev": true, 99 | "requires": { 100 | "domelementtype": "1" 101 | } 102 | }, 103 | "exit": { 104 | "version": "0.1.2", 105 | "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", 106 | "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", 107 | "dev": true 108 | }, 109 | "fs.realpath": { 110 | "version": "1.0.0", 111 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 112 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 113 | "dev": true 114 | }, 115 | "glob": { 116 | "version": "7.1.4", 117 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", 118 | "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", 119 | "dev": true, 120 | "requires": { 121 | "fs.realpath": "^1.0.0", 122 | "inflight": "^1.0.4", 123 | "inherits": "2", 124 | "minimatch": "^3.0.4", 125 | "once": "^1.3.0", 126 | "path-is-absolute": "^1.0.0" 127 | }, 128 | "dependencies": { 129 | "minimatch": { 130 | "version": "3.0.4", 131 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 132 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 133 | "dev": true, 134 | "requires": { 135 | "brace-expansion": "^1.1.7" 136 | } 137 | } 138 | } 139 | }, 140 | "has-color": { 141 | "version": "0.1.7", 142 | "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", 143 | "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", 144 | "dev": true 145 | }, 146 | "htmlparser2": { 147 | "version": "3.3.0", 148 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", 149 | "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", 150 | "dev": true, 151 | "requires": { 152 | "domelementtype": "1", 153 | "domhandler": "2.1", 154 | "domutils": "1.1", 155 | "readable-stream": "1.0" 156 | } 157 | }, 158 | "inflight": { 159 | "version": "1.0.6", 160 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 161 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 162 | "dev": true, 163 | "requires": { 164 | "once": "^1.3.0", 165 | "wrappy": "1" 166 | } 167 | }, 168 | "inherits": { 169 | "version": "2.0.4", 170 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 171 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 172 | "dev": true 173 | }, 174 | "isarray": { 175 | "version": "0.0.1", 176 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 177 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 178 | "dev": true 179 | }, 180 | "jshint": { 181 | "version": "2.5.0", 182 | "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.5.0.tgz", 183 | "integrity": "sha1-gv0aI1/851+tG0Cyo4vvR76sjFQ=", 184 | "dev": true, 185 | "requires": { 186 | "cli": "0.4.x", 187 | "console-browserify": "0.1.x", 188 | "exit": "0.1.x", 189 | "htmlparser2": "3.3.x", 190 | "minimatch": "0.x.x", 191 | "shelljs": "0.1.x", 192 | "strip-json-comments": "0.1.x", 193 | "underscore": "1.4.x" 194 | } 195 | }, 196 | "jshint-stylish": { 197 | "version": "0.2.0", 198 | "resolved": "https://registry.npmjs.org/jshint-stylish/-/jshint-stylish-0.2.0.tgz", 199 | "integrity": "sha1-newAJQrISXlgvk7tb1Bn+x1twH0=", 200 | "dev": true, 201 | "requires": { 202 | "chalk": "~0.4.0", 203 | "text-table": "~0.2.0" 204 | } 205 | }, 206 | "lodash": { 207 | "version": "4.17.11", 208 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 209 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", 210 | "dev": true 211 | }, 212 | "lru-cache": { 213 | "version": "2.7.3", 214 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 215 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", 216 | "dev": true 217 | }, 218 | "minimatch": { 219 | "version": "0.4.0", 220 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.4.0.tgz", 221 | "integrity": "sha1-vSx9Bg0sjI/Xzefx8u0tWycP2xs=", 222 | "dev": true, 223 | "requires": { 224 | "lru-cache": "2", 225 | "sigmund": "~1.0.0" 226 | } 227 | }, 228 | "object-inspect": { 229 | "version": "0.4.0", 230 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-0.4.0.tgz", 231 | "integrity": "sha1-9RV8EWwUVbJDsG7pdwM5LFrYn+w=", 232 | "dev": true 233 | }, 234 | "once": { 235 | "version": "1.4.0", 236 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 237 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 238 | "dev": true, 239 | "requires": { 240 | "wrappy": "1" 241 | } 242 | }, 243 | "path-is-absolute": { 244 | "version": "1.0.1", 245 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 246 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 247 | "dev": true 248 | }, 249 | "readable-stream": { 250 | "version": "1.0.34", 251 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", 252 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", 253 | "dev": true, 254 | "requires": { 255 | "core-util-is": "~1.0.0", 256 | "inherits": "~2.0.1", 257 | "isarray": "0.0.1", 258 | "string_decoder": "~0.10.x" 259 | } 260 | }, 261 | "resumer": { 262 | "version": "0.0.0", 263 | "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", 264 | "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", 265 | "dev": true, 266 | "requires": { 267 | "through": "~2.3.4" 268 | } 269 | }, 270 | "shelljs": { 271 | "version": "0.1.4", 272 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.1.4.tgz", 273 | "integrity": "sha1-37vnjVbDwBaNL7eeEOzR28sH7A4=", 274 | "dev": true 275 | }, 276 | "sigmund": { 277 | "version": "1.0.1", 278 | "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", 279 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 280 | "dev": true 281 | }, 282 | "string_decoder": { 283 | "version": "0.10.31", 284 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 285 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 286 | "dev": true 287 | }, 288 | "strip-ansi": { 289 | "version": "0.1.1", 290 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", 291 | "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", 292 | "dev": true 293 | }, 294 | "strip-json-comments": { 295 | "version": "0.1.3", 296 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz", 297 | "integrity": "sha1-Fkxk43Coo8wAyeAbU55WmCPw7lQ=", 298 | "dev": true 299 | }, 300 | "tape": { 301 | "version": "3.0.3", 302 | "resolved": "https://registry.npmjs.org/tape/-/tape-3.0.3.tgz", 303 | "integrity": "sha1-3E0oqPPBHlRrAZiAzgPnjVCTtVQ=", 304 | "dev": true, 305 | "requires": { 306 | "deep-equal": "~0.2.0", 307 | "defined": "~0.0.0", 308 | "glob": "~3.2.9", 309 | "inherits": "~2.0.1", 310 | "object-inspect": "~0.4.0", 311 | "resumer": "~0.0.0", 312 | "through": "~2.3.4" 313 | }, 314 | "dependencies": { 315 | "glob": { 316 | "version": "3.2.11", 317 | "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", 318 | "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", 319 | "dev": true, 320 | "requires": { 321 | "inherits": "2", 322 | "minimatch": "0.3" 323 | } 324 | }, 325 | "minimatch": { 326 | "version": "0.3.0", 327 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", 328 | "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", 329 | "dev": true, 330 | "requires": { 331 | "lru-cache": "2", 332 | "sigmund": "~1.0.0" 333 | } 334 | } 335 | } 336 | }, 337 | "text-table": { 338 | "version": "0.2.0", 339 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 340 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 341 | "dev": true 342 | }, 343 | "through": { 344 | "version": "2.3.8", 345 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 346 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 347 | "dev": true 348 | }, 349 | "underscore": { 350 | "version": "1.4.4", 351 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", 352 | "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", 353 | "dev": true 354 | }, 355 | "wrappy": { 356 | "version": "1.0.2", 357 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 358 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 359 | "dev": true 360 | } 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hash-sum", 3 | "description": "Blazing fast unique hash generator", 4 | "version": "2.0.0", 5 | "homepage": "https://github.com/bevacqua/hash-sum", 6 | "authors": [ 7 | "Nicolas Bevacqua " 8 | ], 9 | "license": "MIT", 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/bevacqua/hash-sum.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/bevacqua/hash-sum/issues" 16 | }, 17 | "main": "hash-sum.js", 18 | "scripts": { 19 | "test": "jshint . && tape test.js" 20 | }, 21 | "dependencies": {}, 22 | "devDependencies": { 23 | "jshint": "2.5.0", 24 | "jshint-stylish": "0.2.0", 25 | "lodash": "4.17.11", 26 | "tape": "3.0.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # hash-sum 2 | 3 | > blazing fast unique hash generator 4 | 5 | # install 6 | 7 | ```shell 8 | npm i hash-sum -S 9 | ``` 10 | 11 | # features 12 | 13 | - no dependencies 14 | - minimal footprint 15 | - works in all of node.js, io.js, and the browser 16 | - hashes functions based on their source code 17 | - produces different hashes for different object types 18 | - support for circular references in objects 19 | - ignores property assignment order 20 | 21 | # `sum(value)` 22 | 23 | yields a four-byte hexadecimal hash based off of `value`. 24 | 25 | ``` 26 | # creates unique hashes 27 | 00a34759 from: [ 0, 1, 2, 3 ] 28 | a8996f0c from: { '0': 0, '1': 1, '2': 2, '3': 3 } 29 | 5b4c2116 from: { '0': 0, '1': 1, '2': 2, '3': 3, length: 4 } 30 | 2c937c45 from: { url: 12 } 31 | 31d55010 from: { headers: 12 } 32 | 2d2e11bc from: { headers: 122 } 33 | ec99d958 from: { headers: '122' } 34 | 18c00eee from: { headers: { accept: 'text/plain' } } 35 | 6cb332c8 from: { payload: [ 0, 1, 2, 3 ], headers: [ { a: 'b' } ] } 36 | 12ff55db from: { a: [Function: a] } 37 | 46f806d2 from: { b: [Function: b] } 38 | 0660d9c4 from: { b: [Function: b] } 39 | 6c95fc65 from: function () {} 40 | 2941766e from: function (a) {} 41 | 294f8def from: function (b) {} 42 | 2d9c0cb8 from: function (a) { return a;} 43 | ed5c63fc from: function (a) {return a;} 44 | bba68bf6 from: '' 45 | 2d27667d from: 'null' 46 | 774b96ed from: 'false' 47 | 2d2a1684 from: 'true' 48 | 8daa1a0c from: '0' 49 | 8daa1a0a from: '1' 50 | e38f07cc from: 'void 0' 51 | 6037ea1a from: 'undefined' 52 | 9b7df12e from: null 53 | 3c206f76 from: false 54 | 01e34ba8 from: true 55 | 8a8f9624 from: Infinity 56 | 0315bf8f from: -Infinity 57 | 64a48b16 from: NaN 58 | 1a96284a from: 0 59 | 1a96284b from: 1 60 | 29172c1a from: undefined 61 | 59322f29 from: {} 62 | 095b3a22 from: { a: {}, b: {} } 63 | 63be56dd from: { valueOf: [Function: valueOf] } 64 | 63be4f5c from: { valueOf: [Function: valueOf] } 65 | 5d844489 from: [] 66 | ba0bfa14 from: 2019-06-28T21:24:31.215Z 67 | 49324d16 from: 2019-06-28T03:00:00.000Z 68 | 434c9188 from: 1988-06-09T03:00:00.000Z 69 | ce1b5e44 from: global 70 | ``` 71 | 72 | # license 73 | 74 | MIT 75 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var test = require('tape'); 5 | var sum = require('./'); 6 | 7 | test('creates unique hashes', function (t) { 8 | var cases = []; 9 | 10 | test_case([0,1,2,3]); 11 | test_case({0:0,1:1,2:2,3:3}); 12 | test_case({0:0,1:1,2:2,3:3,length:4}); 13 | test_case({url:12}); 14 | test_case({headers:12}); 15 | test_case({headers:122}); 16 | test_case({headers:'122'}); 17 | test_case({headers:{accept:'text/plain'}}); 18 | test_case({payload:[0,1,2,3],headers:[{a:'b'}]}); 19 | test_case({a:function () {}}); 20 | test_case({b:function () {}}); 21 | test_case({b:function (a) {}}); 22 | test_case(function () {}); 23 | test_case(function (a) {}); 24 | test_case(function (b) {}); 25 | test_case(function (a) { return a;}); 26 | test_case(function (a) {return a;}); 27 | test_case('', '\'\''); 28 | test_case('null', '\'null\''); 29 | test_case('false', '\'false\''); 30 | test_case('true', '\'true\''); 31 | test_case('0', '\'0\''); 32 | test_case('1', '\'1\''); 33 | test_case('void 0', '\'void 0\''); 34 | test_case('undefined', '\'undefined\''); 35 | test_case(null); 36 | test_case(false); 37 | test_case(true); 38 | test_case(Infinity); 39 | test_case(-Infinity); 40 | test_case(NaN); 41 | test_case(0); 42 | test_case(1); 43 | test_case(void 0); 44 | test_case({}); 45 | test_case({a:{},b:{}}); 46 | test_case({valueOf(){return 1}}); 47 | test_case({valueOf(){return 2}}); 48 | test_case([]); 49 | test_case(new Date()); 50 | test_case(new Date(2019, 5, 28)); 51 | test_case(new Date(1988, 5, 9)); 52 | test_case(global, 'global'); 53 | 54 | const uniqCases = _.uniqBy(cases, 'hash') 55 | _.uniqBy(cases, 'hash').forEach(function (expected) { 56 | var matches = _.filter(cases, { hash: expected.hash }) 57 | t.equal(matches.length, 1, expected.hash + ': ' + _.map(matches, 'value').join(' ')) 58 | }) 59 | 60 | t.end(); 61 | 62 | function test_case(value, name) { 63 | var hash = sum(value); 64 | cases.push({ value, hash }); 65 | console.log('%s from:', hash, name || value); 66 | } 67 | }); 68 | 69 | test('hashes clash if same properties', function (t) { 70 | equals(function () {}, function () {}); 71 | equals(function (a) {}, function (a) {}); 72 | equals({a:'1'},{a:'1'}); 73 | equals({a:'1',b:1},{b:1,a:'1'}); 74 | equals({valueOf(){return 1}},{valueOf(){return 1}}); 75 | t.end(); 76 | 77 | function equals (a, b) { 78 | t.equal(sum(a), sum(b)); 79 | } 80 | }); 81 | --------------------------------------------------------------------------------