Created
January 19, 2020 03:25
-
-
Save swashcap/8803fdedb5b04331ad658c2031ddcd0e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var assert = require('assert').strict | |
// Accects `obj`, ideally a JSON-parsed data structure returned from a RESTful | |
// API | |
function countReferences (obj) { | |
if (obj === null || typeof obj !== 'object') { | |
return [ | |
obj, | |
function () {} | |
] | |
} | |
var ACCESS_REF = Symbol('ACCESS_REF') | |
var handler = { | |
get: function (obj, prop, receiver) { | |
var value | |
if (typeof obj[prop] === 'object' && obj[prop] !== null) { | |
value = obj[prop] | |
if (!obj[ACCESS_REF][prop]) { | |
obj[ACCESS_REF][prop] = | |
value[ACCESS_REF] = | |
Array.isArray(value) ? [] : {} | |
} | |
return new Proxy(value, handler) | |
} | |
value = Reflect.get(obj, prop, receiver) | |
if (prop in obj) { | |
obj[ACCESS_REF][prop] = value | |
} | |
return value | |
}, | |
set: function (obj, prop, value) { | |
if (prop === ACCESS_REF) { | |
obj[prop] = value | |
return value | |
} | |
throw new Error('set not implemented') | |
}, | |
delete: function () { | |
throw new Error('delete not implemented') | |
} | |
} | |
// Track accessed properties to `obj` | |
var accessed = Array.isArray(obj) ? [] : {} | |
var newTarget = Object.create(obj) | |
Object.defineProperty(newTarget, ACCESS_REF, { | |
enumerable: false, | |
value: accessed | |
}) | |
var proxy = new Proxy(newTarget, handler) | |
return [ | |
proxy, | |
function () { | |
return accessed | |
} | |
] | |
} | |
// Tests | |
function getData () { | |
return { | |
a: 'a', | |
b: { | |
c: 'c', | |
d: null | |
}, | |
e: [ | |
true, | |
false, | |
{ | |
f: 'foobar' | |
}, | |
[9, 8, 7] | |
], | |
g: { | |
h: { | |
i: -1, | |
j: 200 | |
} | |
}, | |
'k-l': null | |
} | |
} | |
assert.equal(countReferences(null)[0], null) | |
assert.equal(countReferences('spahgetti')[0], 'spahgetti') | |
var [data1, getRef1] = countReferences(getData()) | |
data1.a | |
data1.e[0] | |
data1['k-l'] | |
assert.deepEqual(getRef1(), { | |
a: 'a', | |
e: [true], | |
'k-l': null | |
}) | |
var [data2, getRef2] = countReferences(getData()) | |
data2.m | |
data2.e[100] | |
assert.deepEqual(getRef2(), { | |
e: [] | |
}) | |
var [data3, getRef3] = countReferences(getData()) | |
data3.e[2].f | |
data3.e[3][2] | |
data3.g.h.j | |
assert.deepEqual(getRef3(), { | |
e: [ | |
, | |
, | |
{ | |
f: 'foobar' | |
}, | |
[, , 7] | |
], | |
g: { | |
h: { | |
j: 200 | |
} | |
} | |
}) | |
console.log('✅') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment