···133133 assertEquals(identify(o), identify({ a: 1 }));
134134});
135135136136+Deno.test('toJSON :: result cycling back to the original does not overflow', () => {
137137+ const fresh: any = {};
138138+ fresh.toJSON = () => ({ wrap: fresh });
139139+140140+ const stable: any = {};
141141+ const wrapper = { wrap: stable };
142142+ stable.toJSON = () => wrapper;
143143+144144+ assertEquals(identify(fresh), identify(fresh));
145145+ assertEquals(identify(fresh), identify(stable));
146146+});
147147+148148+Deno.test('toJSON :: result resolving to an ancestor closes the cycle', () => {
149149+ const getter: any = {
150150+ get g() {
151151+ return { toJSON: () => getter };
152152+ },
153153+ };
154154+ assert(identify(getter));
155155+ assertEquals(identify(getter), identify(getter));
156156+157157+ const parent: any = {};
158158+ const child: any = { toJSON: () => parent };
159159+ parent.child = child;
160160+ assert(identify(parent));
161161+ assertEquals(identify(parent), identify(parent));
162162+163163+ const root: any = {};
164164+ const mid: any = {};
165165+ root.mid = mid;
166166+ mid.leaf = { toJSON: () => root };
167167+ assert(identify(root));
168168+ assertEquals(identify(root), identify(root));
169169+});
170170+171171+Deno.test('toJSON :: ancestor cycles resolve through every container', () => {
172172+ const viaSet: any = { s: new Set() };
173173+ viaSet.s.add({ toJSON: () => viaSet });
174174+175175+ const viaMap: any = { m: new Map() };
176176+ viaMap.m.set('k', { toJSON: () => viaMap });
177177+178178+ const viaArray: any = { arr: [] as unknown[] };
179179+ viaArray.arr.push({ toJSON: () => viaArray });
180180+181181+ assertEquals(identify(viaSet), identify(viaSet));
182182+ assertEquals(identify(viaMap), identify(viaMap));
183183+ assertEquals(identify(viaArray), identify(viaArray));
184184+});
185185+186186+Deno.test('toJSON :: array and mutual results still resolve cycles', () => {
187187+ const arr: any = {};
188188+ arr.toJSON = () => [arr];
189189+ assertEquals(identify(arr), identify(arr));
190190+191191+ const a: any = {};
192192+ const b: any = {};
193193+ a.toJSON = () => ({ b });
194194+ b.toJSON = () => ({ a });
195195+ assertEquals(identify(a), identify(a));
196196+ assertEquals(identify(b), identify(b));
197197+});
198198+136199// ~> Dates & RegExps
137200138201Deno.test('dates :: equal instants match, different instants differ', () => {
+11-10
lib/mod.ts
···11function walk(input: any, seen: any[]): string | undefined {
22 if (input === null) return 'L';
3344- let out: string, i = 0, keys: any, tmp: any;
44+ let out: string, i = 0, keys: any = input, tmp: any = typeof input;
5566- if ((tmp = typeof input) !== 'object') {
66+ if (tmp !== '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;
···1515 if (!is_arr) {
1616 if (input instanceof Date) return 'd' + +input;
1717 if (input instanceof RegExp) return 'r' + input.source + input.flags;
1818-1919- if (typeof input.toJSON === 'function' && !ArrayBuffer.isView(input)) {
2020- input = input.toJSON();
2121- if (input === null) return 'L';
2222- if (typeof input !== 'object') return walk(input, seen);
2323- is_arr = Array.isArray(input);
2424- }
2518 }
26192720 tmp = seen.indexOf(input);
2821 if (~tmp) return '~' + (tmp + 1);
2929- seen.push(input);
2222+2323+ if (typeof input.toJSON === 'function' && !ArrayBuffer.isView(input)) {
2424+ input = input.toJSON();
2525+ if (input === null || typeof input !== 'object') return walk(input, seen);
2626+ tmp = seen.indexOf(input);
2727+ if (~tmp) return '~' + (tmp + 1);
2828+ is_arr = Array.isArray(input);
2929+ }
3030+ seen.push(keys);
30313132 if (is_arr) {
3233 for (
+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 535B minified and gzipped, with zero
3131+- 🪶 **Tiny.** Around 543B minified and gzipped, with zero
3232 [dependencies](https://npm.anvaka.com/#/view/2d/object-identity/).
33333434## ⚙️ Install