@winglet/json
Version:
TypeScript library for safe and efficient JSON data manipulation with RFC 6901 (JSON Pointer) and RFC 6902 (JSON Patch) compliance, featuring prototype pollution protection and immutable operations
53 lines (50 loc) • 1.98 kB
JavaScript
import { isObject, isArray } from '@winglet/common-utils/filter';
import { hasOwnProperty } from '@winglet/common-utils/lib';
const JSON_PATH_ROOT = '$';
const DOT = '.';
const BRACKET_OPEN = '[';
const BRACKET_CLOSE = ']';
const QUOTE = "'";
const needsBracketNotation = (key) => key.indexOf(DOT) !== -1;
const getJSONPath = (root, target) => {
if (root === target)
return JSON_PATH_ROOT;
const pathSegments = getJSONPathSegments(root, target);
return pathSegments !== null ? `${JSON_PATH_ROOT}${pathSegments}` : null;
};
const getJSONPathSegments = (root, target) => {
const stack = [[root, '']];
while (stack.length > 0) {
const [currentNode, currentPath] = stack.pop();
if (isObject(currentNode)) {
if (isArray(currentNode)) {
for (let i = 0, l = currentNode.length; i < l; i++) {
const value = currentNode[i];
const segment = `${BRACKET_OPEN}${i}${BRACKET_CLOSE}`;
const path = currentPath + segment;
if (value === target)
return path;
if (isObject(value))
stack[stack.length] = [value, path];
}
}
else {
for (const key in currentNode) {
if (!hasOwnProperty(currentNode, key))
continue;
const value = currentNode[key];
const segment = needsBracketNotation(key)
? `${BRACKET_OPEN}${QUOTE}${key}${QUOTE}${BRACKET_CLOSE}`
: `${DOT}${key}`;
const path = currentPath + segment;
if (value === target)
return path;
if (isObject(value))
stack[stack.length] = [value, path];
}
}
}
}
return null;
};
export { getJSONPath };