Skip to content

Instantly share code, notes, and snippets.

@j1elo
Last active October 10, 2022 15:37
Show Gist options
  • Save j1elo/0acaf233de9f4b2d8bd7f27b9f9a3fb3 to your computer and use it in GitHub Desktop.
Save j1elo/0acaf233de9f4b2d8bd7f27b9f9a3fb3 to your computer and use it in GitHub Desktop.
Prints the path to all values whose names match the given regular expression.
/**
* Prints the path to all values whose names match the given regular expression.
*
* @param {Object} input - An object that contains the parent from where to
* start searching recursively for all key names.
*
* The input object can be passed with just an standalone value, which then
* will be used itself as the prefix for the result.
*
* For example, for a parent object `root` which contains a hierarchy of
* other objects, `findValues({ root }, /stream/i)` outputs this:
*
* root.some.other.array[0].myStream
*
* To customize the prefix, pass the input with an explicit key name.
*
* For example, `findValues({ myPrefix: root }, /stream/i)` outputs this:
*
* myPrefix.some.other.array[0].myStream
*
* @param {RegExp} nameRegex - A JavaScript [Regular Expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
* which matches the value names that you want to find.
*
* @returns {void} Nothing. Results of this function go to `console.log()`.
*/
function findValues(input, nameRegex) {
// Used to avoid circular references.
const seen = new WeakSet();
function _findValues(input, nameRegex) {
const parentPath = Object.keys(input)[0];
const parentObj = Object.values(input)[0];
if (seen.has(parentObj)) {
return;
} else {
seen.add(parentObj);
}
for (let [key, value] of Object.entries(parentObj)) {
let newPath;
if (Array.isArray(parentObj)) {
newPath = parentPath + `[${key}]`;
} else if (/^[a-zA-Z_$][a-zA-Z\d_$]*$/.test(key)) {
// Simple identifier: Can be accessed directly with Dot notation.
// FIXME: This test is very simplistic and could be improved. Valid
// JavaScript identifiers can be much, _much_ more complex!
// See: [What characters are valid for JavaScript variable names?](https://stackoverflow.com/a/9337047)
newPath = parentPath + `.${key}`;
} else {
// Complex identifier: Must be accessed with Bracket notation.
newPath = parentPath + `["${key}"]`;
}
if (nameRegex.test(key)) {
console.log(`${newPath}`);
}
if (typeof value === "object" && value !== null) {
_findValues({ [newPath]: value }, nameRegex);
}
}
}
_findValues(input, nameRegex);
}
/*
* Usage examples
* ==============
*/
if (false) {
// Use the variable `globalThis`, which is the parent global variable defined
// in both web browsers (same as `window`) and Node.js (same as `global`).
findValues({ globalThis }, /myValue/);
}
if (false) {
// Any root object or array can be passed to this function.
const rootObject = {
number: 42,
string: "test",
"complex-key": { stream1: 1 },
object: { stream2: 2 },
array: [{ openh264: 3 }, { OpenVidu: 4 }],
};
findValues({ test: rootObject }, /[oO]pen[vV]idu|[sS]tream|pc/);
// Output:
// test["complex-key"].stream1
// test.object.stream2
// test.array[1].OpenVidu
}
if (false) {
// This searches through all of Angular values in the OpenVidu Call
// application, to find the [RTCPeerConnection](https://developer.mozilla.org/docs/Web/API/RTCPeerConnection)
// that corresponds to an active Publisher stream.
// In case of OpenVidu Call, this should be stored inside a WebRtcPeer, so the
// output should look something like this:
//
// (... Angular stuff).session.connection.stream.webRtcPeer.pc
findValues(
{
"window.getAllAngularRootElements()": window.getAllAngularRootElements(),
},
/^pc$/
);
// Output:
// window.getAllAngularRootElements()[0].__ngContext__[10].engine._transitionEngine
// ._namespaceLookup["c146-0"].hostElement.__ngContext__[13][8].openviduService
// .OV.publishers[0].videos[0].video.__ngContext__[0].__ngContext__[0]
// .__ngContext__[0].__ngContext__[3][0].__ngContext__[0].__ngContext__[0]
// .__ngContext__[0].__ngContext__[0].__ngContext__[17][4][4][4][4][4][4][4][4][4][4][9][0][0]
// .__ngContext__[3][0].__ngContext__[0].__ngContext__[0].__ngContext__[0].__ngContext__[14][9][0][3][4][8][0]
// ._lView[13][8][0]._lView[13][8][0]._lView[13][8][0]._lView[13][8]
// .session.connection.stream.webRtcPeer.pc
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment