mirror: A fast canonicalisation utility for stable object equality
0

Configure Feed

Select the types of activity you want to include in your feed.

chore: adds swr/_internal/stableHash as a candidate

Marais Rossouw (Jun 30, 2026, 4:27 PM +1000) fbb5c5c2 68418246

+91 -78
+13 -5
lib/mod.bench.ts
··· 114 114 lib: () => import('npm:@tufjs/canonical-json@^2.0'), 115 115 run: (m, o) => m.canonicalize(o), 116 116 }, 117 + 'swr/_internal/stableHash': { 118 + lib: () => import('npm:swr@^2.4/_internal'), 119 + run: (m, o) => m.stableHash(o), 120 + }, 117 121 }; 118 122 119 123 const mods: Record<string, any> = {}; 120 124 for (const [name, c] of Object.entries(candidates)) mods[name] = await c.lib(); 121 125 122 - const fixtures = Object.entries(scenarios).map(([name, make]) => [name, make()] as const); 123 - 124 - for (const [scenario, value] of fixtures) { 126 + for (const [scenario, value] of Object.entries(scenarios)) { 125 127 for (const [name, c] of Object.entries(candidates)) { 126 128 // Validate up front: a throw (can't handle the shape) or non-deterministic 127 129 // output marks the bench ignored, so it's skipped instead of measured. 128 130 let valid = false; 129 131 try { 130 - valid = c.run(mods[name], value) === c.run(mods[name], value); 132 + let o = value(); 133 + valid = c.run(mods[name], o) === c.run(mods[name], o); 131 134 } catch { 132 135 /* leaves valid false -> ignored */ 133 136 } ··· 137 140 group: scenario, 138 141 baseline: name === 'object-identity', 139 142 ignore: !valid, 140 - fn: () => void c.run(mods[name], value), 143 + fn: (ctx) => { 144 + let o = value(); 145 + ctx.start(); 146 + let _ = c.run(mods[name], o) 147 + ctx.end(); 148 + } 141 149 }); 142 150 } 143 151 }
+78 -73
readme.md
··· 62 62 <!-- BEGIN BENCHMARK --> 63 63 64 64 ``` 65 - ✔ simple ~ 1.1µs @ 932,332 ops/sec ± 0.76% 66 - ✔ deep ~ 8.0µs @ 124,505 ops/sec ± 2.85% 67 - ✔ deep circular ~ 5.5µs @ 183,042 ops/sec ± 0.16% 68 - ✔ big ~ 80.2µs @ 12,467 ops/sec ± 0.42% 69 - ✔ leafy ~ 23.7µs @ 42,223 ops/sec ± 0.63% 65 + ✔ simple ~ 1.1µs @ 870,271 ops/sec ± 0.22% 66 + ✔ deep ~ 8.4µs @ 118,807 ops/sec ± 0.01% 67 + ✔ deep circular ~ 6.0µs @ 166,470 ops/sec ± 0.51% 68 + ✔ big ~ 82.1µs @ 12,175 ops/sec ± 1.06% 69 + ✔ leafy ~ 23.8µs @ 41,957 ops/sec ± 0.70% 70 70 ``` 71 71 72 72 <details><summary>All candidates</summary> 73 73 74 74 ``` 75 75 simple 76 - ✔ object-identity ~ 1.1µs @ 932,332 ops/sec ± 0.76% 77 - ✔ safe-stable-stringify ~ 1.7µs @ 588,871 ops/sec ± 0.67% 78 - ✔ ohash ~ 3.5µs @ 285,750 ops/sec ± 0.28% 79 - ✔ object-hash ~ 9.7µs @ 102,617 ops/sec ± 2.08% 80 - ✔ hash-it † ~ 2.8µs @ 361,547 ops/sec ± 2.62% 81 - ✔ json-stable-stringify ~ 3.1µs @ 325,737 ops/sec ± 0.08% 82 - ✔ fast-json-stable-stringify ~ 2.1µs @ 480,206 ops/sec ± 0.44% 83 - ✔ tiny-stable-stringify ~ 2.4µs @ 409,949 ops/sec ± 1.60% 84 - ✔ json-stringify-deterministic ~ 3.1µs @ 326,067 ops/sec ± 2.55% 85 - ✔ json-stable-stringify-without-jsonify ~ 3.0µs @ 329,660 ops/sec ± 0.25% 86 - ✔ json-sorted-stringify ~ 2.3µs @ 429,194 ops/sec ± 0.54% 87 - ✔ canonicalize ~ 3.5µs @ 284,416 ops/sec ± 1.62% 76 + ✔ object-identity ~ 1.1µs @ 870,271 ops/sec ± 0.22% 77 + ✔ safe-stable-stringify ~ 1.8µs @ 563,781 ops/sec ± 0.46% 78 + ✔ ohash ~ 3.8µs @ 262,901 ops/sec ± 0.25% 79 + ✔ object-hash ~ 10.2µs @ 98,164 ops/sec ± 1.84% 80 + ✔ hash-it † ~ 3.0µs @ 335,235 ops/sec ± 2.05% 81 + ✔ json-stable-stringify ~ 3.1µs @ 317,679 ops/sec ± 0.30% 82 + ✔ fast-json-stable-stringify ~ 2.1µs @ 471,606 ops/sec ± 0.22% 83 + ✔ tiny-stable-stringify ~ 2.5µs @ 403,418 ops/sec ± 1.49% 84 + ✔ json-stringify-deterministic ~ 3.2µs @ 313,455 ops/sec ± 0.63% 85 + ✔ json-stable-stringify-without-jsonify ~ 3.2µs @ 312,450 ops/sec ± 0.59% 86 + ✔ json-sorted-stringify ~ 2.4µs @ 411,299 ops/sec ± 0.86% 87 + ✔ canonicalize ~ 3.7µs @ 271,025 ops/sec ± 0.17% 88 + ✔ swr/_internal/stableHash ~ 3.9µs @ 255,223 ops/sec ± 0.60% 88 89 ✘ @tufjs/canonical-json 89 - ───────────────────────────────────────────────────────────────────────── 90 - ⭐︎ object-identity (1.58x faster than safe-stable-stringify) 90 + ────────────────────────────────────────────────────────────────────────── 91 + ⭐︎ object-identity (1.54x faster than safe-stable-stringify) 91 92 92 93 deep 93 - ✔ object-identity ~ 8.0µs @ 124,505 ops/sec ± 2.85% 94 - ✔ safe-stable-stringify ~ 13.6µs @ 73,292 ops/sec ± 0.45% 95 - ✔ ohash ~ 25.6µs @ 39,078 ops/sec ± 0.79% 96 - ✔ object-hash ~ 53.3µs @ 18,748 ops/sec ± 1.73% 97 - ✔ hash-it † ~ 21.1µs @ 47,506 ops/sec ± 1.23% 98 - ✔ json-stable-stringify ~ 22.9µs @ 43,649 ops/sec ± 1.24% 99 - ✔ fast-json-stable-stringify ~ 14.4µs @ 69,262 ops/sec ± 0.14% 100 - ✔ tiny-stable-stringify ~ 16.4µs @ 60,994 ops/sec ± 0.38% 101 - ✔ json-stringify-deterministic ~ 22.5µs @ 44,468 ops/sec ± 1.25% 102 - ✔ json-stable-stringify-without-jsonify ~ 22.7µs @ 43,964 ops/sec ± 0.53% 103 - ✔ json-sorted-stringify ~ 16.1µs @ 61,935 ops/sec ± 0.64% 104 - ✔ canonicalize ~ 26.7µs @ 37,508 ops/sec ± 0.76% 105 - ✔ @tufjs/canonical-json ~ 34.5µs @ 29,020 ops/sec ± 1.45% 106 - ────────────────────────────────────────────────────────────────────────── 107 - ⭐︎ object-identity (1.70x faster than safe-stable-stringify) 94 + ✔ object-identity ~ 8.4µs @ 118,807 ops/sec ± 0.01% 95 + ✔ safe-stable-stringify ~ 13.3µs @ 75,024 ops/sec ± 0.66% 96 + ✔ ohash ~ 26.0µs @ 38,497 ops/sec ± 0.57% 97 + ✔ object-hash ~ 56.2µs @ 17,807 ops/sec ± 0.95% 98 + ✔ hash-it † ~ 22.8µs @ 43,812 ops/sec ± 0.14% 99 + ✔ json-stable-stringify ~ 24.1µs @ 41,487 ops/sec ± 0.95% 100 + ✔ fast-json-stable-stringify ~ 14.2µs @ 70,522 ops/sec ± 0.39% 101 + ✔ tiny-stable-stringify ~ 16.1µs @ 62,039 ops/sec ± 0.56% 102 + ✔ json-stringify-deterministic ~ 23.2µs @ 43,102 ops/sec ± 0.15% 103 + ✔ json-stable-stringify-without-jsonify ~ 23.3µs @ 42,858 ops/sec ± 0.18% 104 + ✔ json-sorted-stringify ~ 15.8µs @ 63,287 ops/sec ± 0.73% 105 + ✔ canonicalize ~ 26.8µs @ 37,383 ops/sec ± 0.16% 106 + ✔ swr/_internal/stableHash ~ 29.0µs @ 34,460 ops/sec ± 22.90% 107 + ✔ @tufjs/canonical-json ~ 34.9µs @ 28,625 ops/sec ± 0.17% 108 + ─────────────────────────────────────────────────────────────────────────── 109 + ⭐︎ object-identity (1.58x faster than safe-stable-stringify) 108 110 109 111 deep circular 110 - ✔ object-identity ~ 5.5µs @ 183,042 ops/sec ± 0.16% 111 - ✔ safe-stable-stringify ~ 7.2µs @ 139,264 ops/sec ± 0.32% 112 - ✔ ohash ~ 16.6µs @ 60,357 ops/sec ± 0.66% 113 - ✔ object-hash ~ 44.1µs @ 22,688 ops/sec ± 1.50% 114 - ✔ hash-it † ~ 15.1µs @ 66,295 ops/sec ± 1.39% 112 + ✔ object-identity ~ 6.0µs @ 166,470 ops/sec ± 0.51% 113 + ✔ safe-stable-stringify ~ 7.5µs @ 132,624 ops/sec ± 0.27% 114 + ✔ ohash ~ 17.2µs @ 58,116 ops/sec ± 0.49% 115 + ✔ object-hash ~ 45.7µs @ 21,863 ops/sec ± 0.07% 116 + ✔ hash-it † ~ 16.1µs @ 61,985 ops/sec ± 0.31% 115 117 ✘ json-stable-stringify 116 - ✔ fast-json-stable-stringify ~ 10.0µs @ 100,160 ops/sec ± 0.67% 118 + ✔ fast-json-stable-stringify ~ 10.2µs @ 97,666 ops/sec ± 0.51% 117 119 ✘ tiny-stable-stringify 118 - ✔ json-stringify-deterministic ~ 14.8µs @ 67,354 ops/sec ± 1.50% 120 + ✔ json-stringify-deterministic ~ 15.5µs @ 64,604 ops/sec ± 0.41% 119 121 ✘ json-stable-stringify-without-jsonify 120 122 ✘ json-sorted-stringify 121 123 ✘ canonicalize 124 + ✔ swr/_internal/stableHash ~ 15.4µs @ 65,066 ops/sec ± 21.11% 122 125 ✘ @tufjs/canonical-json 123 - ────────────────────────────────────────────────────────────────────────── 124 - ⭐︎ object-identity (1.31x faster than safe-stable-stringify) 126 + ─────────────────────────────────────────────────────────────────────────── 127 + ⭐︎ object-identity (1.26x faster than safe-stable-stringify) 125 128 126 129 big 127 - ✔ object-identity ~ 80.2µs @ 12,467 ops/sec ± 0.42% 128 - ✔ safe-stable-stringify ~ 135.1µs @ 7,404 ops/sec ± 0.88% 129 - ✔ ohash ~ 289.9µs @ 3,449 ops/sec ± 0.63% 130 - ✔ object-hash ~ 490.0µs @ 2,041 ops/sec ± 1.51% 131 - ✔ hash-it † ~ 258.9µs @ 3,862 ops/sec ± 0.48% 132 - ✔ json-stable-stringify ~ 214.5µs @ 4,662 ops/sec ± 0.69% 133 - ✔ fast-json-stable-stringify ~ 156.8µs @ 6,379 ops/sec ± 0.69% 134 - ✔ tiny-stable-stringify ~ 174.3µs @ 5,736 ops/sec ± 0.24% 135 - ✔ json-stringify-deterministic ~ 223.6µs @ 4,471 ops/sec ± 0.38% 136 - ✔ json-stable-stringify-without-jsonify ~ 215.6µs @ 4,639 ops/sec ± 0.21% 137 - ✔ json-sorted-stringify ~ 165.3µs @ 6,049 ops/sec ± 0.13% 138 - ✔ canonicalize ~ 245.5µs @ 4,073 ops/sec ± 0.44% 139 - ✔ @tufjs/canonical-json ~ 369.7µs @ 2,705 ops/sec ± 0.11% 140 - ────────────────────────────────────────────────────────────────────────── 141 - ⭐︎ object-identity (1.68x faster than safe-stable-stringify) 130 + ✔ object-identity ~ 82.1µs @ 12,175 ops/sec ± 1.06% 131 + ✔ safe-stable-stringify ~ 140.5µs @ 7,118 ops/sec ± 0.04% 132 + ✔ ohash ~ 304.4µs @ 3,285 ops/sec ± 0.53% 133 + ✔ object-hash ~ 513.2µs @ 1,949 ops/sec ± 1.23% 134 + ✔ hash-it † ~ 276.5µs @ 3,617 ops/sec ± 0.61% 135 + ✔ json-stable-stringify ~ 228.2µs @ 4,382 ops/sec ± 1.06% 136 + ✔ fast-json-stable-stringify ~ 164.2µs @ 6,091 ops/sec ± 0.56% 137 + ✔ tiny-stable-stringify ~ 180.0µs @ 5,556 ops/sec ± 1.08% 138 + ✔ json-stringify-deterministic ~ 224.9µs @ 4,447 ops/sec ± 1.01% 139 + ✔ json-stable-stringify-without-jsonify ~ 224.1µs @ 4,463 ops/sec ± 0.66% 140 + ✔ json-sorted-stringify ~ 172.5µs @ 5,797 ops/sec ± 0.21% 141 + ✔ canonicalize ~ 262.7µs @ 3,807 ops/sec ± 1.01% 142 + ✔ swr/_internal/stableHash ~ 287.7µs @ 3,476 ops/sec ± 16.90% 143 + ✔ @tufjs/canonical-json ~ 387.7µs @ 2,580 ops/sec ± 0.32% 144 + ─────────────────────────────────────────────────────────────────────────── 145 + ⭐︎ object-identity (1.71x faster than safe-stable-stringify) 142 146 143 147 leafy 144 - ✔ object-identity ~ 23.7µs @ 42,223 ops/sec ± 0.63% 145 - ✔ safe-stable-stringify ~ 51.0µs @ 19,622 ops/sec ± 0.66% 146 - ✔ ohash ~ 30.6µs @ 32,645 ops/sec ± 0.38% 147 - ✔ object-hash ~ 82.1µs @ 12,183 ops/sec ± 0.10% 148 - ✔ hash-it † ~ 83.0µs @ 12,050 ops/sec ± 0.42% 149 - ✔ json-stable-stringify ~ 113.6µs @ 8,800 ops/sec ± 0.02% 150 - ✔ fast-json-stable-stringify ~ 59.2µs @ 16,901 ops/sec ± 1.06% 151 - ✔ tiny-stable-stringify ~ 103.5µs @ 9,661 ops/sec ± 0.11% 152 - ✔ json-stringify-deterministic ~ 111.5µs @ 8,965 ops/sec ± 0.00% 153 - ✔ json-stable-stringify-without-jsonify ~ 113.7µs @ 8,796 ops/sec ± 2.00% 154 - ✔ json-sorted-stringify ~ 107.3µs @ 9,324 ops/sec ± 0.97% 155 - ✔ canonicalize ~ 92.4µs @ 10,821 ops/sec ± 1.36% 156 - ✔ @tufjs/canonical-json ~ 207.2µs @ 4,826 ops/sec ± 0.72% 157 - ────────────────────────────────────────────────────────────────────────── 158 - ⭐︎ object-identity (1.29x faster than ohash) 148 + ✔ object-identity ~ 23.8µs @ 41,957 ops/sec ± 0.70% 149 + ✔ safe-stable-stringify ~ 50.3µs @ 19,896 ops/sec ± 0.47% 150 + ✔ ohash ~ 30.9µs @ 32,336 ops/sec ± 0.38% 151 + ✔ object-hash ~ 87.7µs @ 11,397 ops/sec ± 1.27% 152 + ✔ hash-it † ~ 84.3µs @ 11,860 ops/sec ± 0.97% 153 + ✔ json-stable-stringify ~ 115.1µs @ 8,686 ops/sec ± 0.87% 154 + ✔ fast-json-stable-stringify ~ 59.6µs @ 16,765 ops/sec ± 0.11% 155 + ✔ tiny-stable-stringify ~ 107.8µs @ 9,277 ops/sec ± 0.23% 156 + ✔ json-stringify-deterministic ~ 116.5µs @ 8,583 ops/sec ± 0.29% 157 + ✔ json-stable-stringify-without-jsonify ~ 117.2µs @ 8,532 ops/sec ± 0.35% 158 + ✔ json-sorted-stringify ~ 107.9µs @ 9,266 ops/sec ± 0.15% 159 + ✔ canonicalize ~ 93.3µs @ 10,720 ops/sec ± 0.50% 160 + ✔ swr/_internal/stableHash ~ 134.1µs @ 7,459 ops/sec ± 31.44% 161 + ✔ @tufjs/canonical-json ~ 217.2µs @ 4,605 ops/sec ± 1.07% 162 + ─────────────────────────────────────────────────────────────────────────── 163 + ⭐︎ object-identity (1.30x faster than ohash) 159 164 ``` 160 165 161 166 </details>