UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

126 lines (125 loc) 3.83 kB
/** * JSONPath utility functions */ /** * Convert a JSONPath to a human-readable string representation */ export function jsonPathToString(jsonPath) { let result = '$'; for (const segment of jsonPath.segments) { if (segment.selectors.length === 1) { const selector = segment.selectors[0]; result += selectorToString(selector); } else { // Multiple selectors (union) - not fully implemented result += '[' + segment.selectors.map(selectorToString).join(',') + ']'; } } return result; } /** * Convert a selector to string representation */ function selectorToString(selector) { switch (selector.type) { case 'name': return `.${selector.name}`; case 'index': return `[${selector.index}]`; case 'slice': { let sliceStr = '['; if (selector.start !== undefined) sliceStr += selector.start; sliceStr += ':'; if (selector.end !== undefined) sliceStr += selector.end; if (selector.step !== undefined) sliceStr += `:${selector.step}`; sliceStr += ']'; return sliceStr; } case 'wildcard': return '.*'; case 'recursive-descent': return `..${selectorToString(selector.selector)}`; case 'filter': return '[?(...)]'; // Simplified representation default: return ''; } } /** * Check if two JSONPath expressions are equivalent */ export function jsonPathEquals(path1, path2) { if (path1.segments.length !== path2.segments.length) { return false; } for (let i = 0; i < path1.segments.length; i++) { const seg1 = path1.segments[i]; const seg2 = path2.segments[i]; if (seg1.recursive !== seg2.recursive) { return false; } if (seg1.selectors.length !== seg2.selectors.length) { return false; } for (let j = 0; j < seg1.selectors.length; j++) { if (!selectorEquals(seg1.selectors[j], seg2.selectors[j])) { return false; } } } return true; } /** * Check if two selectors are equivalent */ function selectorEquals(sel1, sel2) { if (sel1.type !== sel2.type) { return false; } switch (sel1.type) { case 'name': return sel1.name === sel2.name; case 'index': return sel1.index === sel2.index; case 'slice': { const s2 = sel2; return sel1.start === s2.start && sel1.end === s2.end && sel1.step === s2.step; } case 'wildcard': return true; case 'recursive-descent': { const rdSel = sel2; return selectorEquals(sel1.selector, rdSel.selector); } case 'filter': // For now, just return true - would need deep comparison of filter expressions return true; default: return false; } } /** * Get all property names that could be accessed by a JSONPath * This is a simple analysis that doesn't handle complex filters */ export function getAccessedProperties(jsonPath) { const properties = []; for (const segment of jsonPath.segments) { for (const selector of segment.selectors) { if (selector.type === 'name') { properties.push(selector.name); } else if (selector.type === 'recursive-descent') { if (selector.selector.type === 'name') { const nameSelector = selector.selector; properties.push(nameSelector.name); } } } } return properties; }