/
findReferences.js
46 lines (40 loc) · 1.35 KB
/
findReferences.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
'use strict';
const _ = require('lodash');
/**
* Find all objects with a given value within a given root object.
* The search is implemented non-recursive to prevent stackoverflows and will
* do a complete deep search including arrays.
* @param root {Object} Root object for search
* @param value {Object} Value to search
* @returns {Array<String>} Paths to all self references found within the object
*/
function findReferences(root, value) {
const visitedObjects = [];
const resourcePaths = [];
const stack = [{ propValue: root, path: '' }];
while (stack.length) {
const property = stack.pop();
if (property.propValue) {
Object.entries(property.propValue).forEach(([key, propValue]) => {
let propKey;
if (Array.isArray(property.propValue)) {
propKey = `[${key}]`;
} else {
propKey = !property.path ? `${key}` : `.${key}`;
}
if (propValue === value) {
resourcePaths.push(`${property.path}${propKey}`);
} else if (_.isObject(propValue)) {
// Prevent circular references
if (visitedObjects.includes(propValue)) {
return;
}
visitedObjects.push(propValue);
stack.push({ propValue, path: `${property.path}${propKey}` });
}
});
}
}
return resourcePaths;
}
module.exports = findReferences;