···11function walk(input: any, seen: any[]): string | undefined {
22 if (input === null) return 'L';
3344- let type = typeof input;
55- if (type !== 'object') {
66- if (type === 'number') return input - input === 0 ? 'n' + input : 'L';
77- if (type === 'string') return 's' + input;
88- if (type === 'bigint') return 'n' + input;
99- if (type === 'boolean') return input ? 'T' : 'F';
1010- // functions, symbols, undefined are dropped and treated as identity equal.
44+ let out: string, i = 0, keys: any, tmp: any;
55+66+ if ((tmp = typeof input) !== 'object') {
77+ if (tmp === 'number') return input - input === 0 ? 'n' + input : 'L';
88+ if (tmp === 'string') return 's' + input;
99+ if (tmp === 'bigint') return 'n' + input;
1010+ if (tmp === 'boolean') return input ? 'T' : 'F';
1111 return;
1212 }
13131414- // Arrays are the most common container, so settle them before the rarer
1515- // Date/RegExp leaves to keep the hot path short.
1614 let is_arr = Array.isArray(input);
1715 if (!is_arr) {
1816 if (input instanceof Date) return 'd' + +input;
1917 if (input instanceof RegExp) return 'r' + input.source + input.flags;
1818+2019 if (typeof input.toJSON === 'function' && !ArrayBuffer.isView(input)) {
2120 input = input.toJSON();
2222- if (typeof input !== 'object' || input === null) return walk(input, seen);
2121+ if (input === null) return 'L';
2222+ if (typeof input !== 'object') return walk(input, seen);
2323 is_arr = Array.isArray(input);
2424 }
2525 }
26262727- let ref: any = seen.indexOf(input);
2828- if (~ref) return '~' + (ref + 1);
2727+ tmp = seen.indexOf(input);
2828+ if (~tmp) return '~' + (tmp + 1);
2929 seen.push(input);
30303131- let out: string, i = 0, keys: any, tmp: any;
3232-3331 if (is_arr) {
3432 for (
3533 out = 'a';
···4038 out = 'e';
4139 for (let value of input) out += (tmp = walk(value, seen)) === undefined ? 'L' : tmp;
4240 } else if (input instanceof Map) {
4343- out = 'o';
4444- if (input.size > 1) {
4545- for (keys = [...input.keys()].sort(); i < keys.length; i++) {
4646- (tmp = walk(input.get(keys[i]), seen)) !== undefined && (out += keys[i] + tmp);
4747- }
4848- } else {
4949- for (keys of input) {
5050- (tmp = walk(keys[1], seen)) !== undefined && (out += keys[0] + tmp);
5151- }
4141+ keys = [...input.keys()];
4242+ if (keys.length > 1) keys.sort();
4343+ for (out = 'o'; i < keys.length; i++) {
4444+ if ((tmp = walk(input.get(keys[i]), seen)) !== undefined) out += keys[i] + tmp;
5245 }
5353- } // Plain objects, class instances and null-prototype objects have no
5454- // `Symbol.toStringTag`. Typed arrays (and other ArrayBuffer views) do, but
5555- // JSON treats them as index-keyed objects, so we walk their keys the same way.
5656- // Other exotic builtins (Promise, WeakMap, ArrayBuffer) fall through to the throw.
5757- else if (input[Symbol.toStringTag] === undefined || ArrayBuffer.isView(input)) {
5858- out = 'o';
4646+ } else if (input[Symbol.toStringTag] === undefined || ArrayBuffer.isView(input)) {
5947 keys = Object.keys(input);
6048 if (keys.length > 1) keys.sort();
6161- for (; i < keys.length; i++) {
4949+ for (out = 'o'; i < keys.length; i++) {
6250 if ((tmp = walk(input[keys[i]], seen)) !== undefined) out += keys[i] + tmp;
6351 }
6452 } else {
+1-1
readme.md
···2828- 🧬 **Canonical.** The same shape always produces the same id.
2929- 🌀 **Deep and cycle-safe.** Handles nested objects, arrays, sets, maps, and circular references.
3030- 🏎 **Fast.** See the [benchmarks](#-benchmark).
3131-- 🪶 **Tiny.** Around 571B minified and gzipped, with zero
3131+- 🪶 **Tiny.** Around 535B minified and gzipped, with zero
3232 [dependencies](https://npm.anvaka.com/#/view/2d/object-identity/).
33333434## ⚙️ Install