Created
September 1, 2016 03:58
-
-
Save snydergd/8d6b361cd698a7d3046505b2491116a3 to your computer and use it in GitHub Desktop.
Javascript Cyclic Nested Object Property Search
This file contains 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
/* | |
* Finds locations within data structure that a specific key/value can be found | |
* - Handles looping data structures (for instance window.window = window) | |
* - Flexible query format (provide key to match, value to match, or both) | |
* - Handy for reverse engineering and understanding javascript code on websites | |
* - Note, it's a little hack-ish, but it's just a tool anyway | |
* Examples: | |
* a = {b: 4, c: [1, 2, {d: 5, e: [0, 5, 2]}]}; | |
* searchObj(a, {key: d}); // --> ["root.c.2.d"] | |
* searchObj(a, {value: 2}); // --> ["root.c.1", "root.c.2.e.2"] | |
* searchObj(a, {key: 1, value: 2}); // --> ["root.c.1"] | |
**/ | |
var searchObj = (function () { | |
var uniqueId = 0; | |
return function(obj, query) { | |
if (!("key" in query || "value" in query)) return -1; | |
var stack = [[["root", obj]]]; // remaining tree to traverse | |
var objStack = []; // current object path | |
var i; | |
var visited = {}; // handle cycles | |
result = []; // object paths found | |
function addResult(last) { | |
var i, r = []; | |
for (i in objStack) r.push(objStack[i]); | |
r.push(last); | |
result.push(r.join(".")); | |
} | |
while (stack.length > 0) { | |
if (stack[stack.length-1].length == 0) { | |
stack.pop(); | |
if (objStack.length) objStack.pop(); | |
continue; | |
} | |
obj = stack[stack.length-1].pop(); | |
if (!obj[1].hasOwnProperty('unique_id')) Object.defineProperty(obj[1], 'unique_id', {value: uniqueId++}); // non-iterable property | |
visited[obj[1].unique_id] = true; | |
objStack.push(obj[0]); | |
stack.push([]); | |
for (var t in Object.getOwnPropertyNames(obj[1])) { | |
i = Object.getOwnPropertyNames(obj[1])[t]; | |
try { | |
if ((!("key" in query) || query["key"] == i) && | |
(!("value" in query) || query["value"] == obj[1][i])) | |
addResult(i); | |
if (typeof(obj[1][i]) == "object" && obj[1][i] != null && (!("unique_id" in obj[1][i]) || !visited[obj[1][i].unique_id])) { | |
stack[stack.length-1].push([i, obj[1][i]]); | |
} | |
} catch (exception) { | |
console.log("Caught exception on " + objStack.concat([i]).join(".") + ": " + exception); | |
} | |
} | |
} | |
return result; | |
}})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment