Skip to content

Instantly share code, notes, and snippets.

@swashcap
Created January 19, 2020 03:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save swashcap/8803fdedb5b04331ad658c2031ddcd0e to your computer and use it in GitHub Desktop.
Save swashcap/8803fdedb5b04331ad658c2031ddcd0e to your computer and use it in GitHub Desktop.
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