function jsonQuery(json, path, defaultValue = null) { let toks = tokenizePath(path); let ptr = json; let search = null; let searchTok = null; let multiResult = null; let tok; while (tok = toks.shift()) { switch (tok) { case ".": // find key search = 'key'; break; case "[": // find array index search = "array"; break; case "]": // find // if searchTok is "", match all items if (search !== "array") { throw new Error("Invalid path"); } if (searchTok === null) { if (multiResult !== null) { throw new Error("Can't match full arrays on multiple levels"); } multiResult = []; ptr.forEach(item => { let res = jsonQuery(item, toks.join("")); multiResult.push(res); }); return multiResult; } if (typeof ptr[searchTok] === 'undefined') { return defaultValue; } ptr = ptr[searchTok]; break; default: if (search === 'key') { // find key tok in ptr if (typeof ptr[tok] === 'undefined') { return defaultValue; } else { ptr = ptr[tok]; } } else if (search === 'array') { // find index tok in ptr after finding a ] searchTok = tok; } } } return ptr; } function jsonPatch(json, path, value) { let toks = tokenizePath(path); json = structuredClone(json); let ptr = json; let search = null; let searchTok = null; let multiResult = null; let tok; while (tok = toks.shift()) { switch (tok) { case ".": // find key search = 'key'; break; case "[": // find array index search = "array"; break; case "]": // find // if searchTok is "", match all items if (search !== "array") { throw new Error("Invalid path"); } if (searchTok === null) { throw new Error("Can't patch arrays yet"); } if (typeof ptr[searchTok] === 'undefined') { return json; } ptr = ptr[searchTok]; break; default: if (search === 'key') { // find key tok in ptr if (typeof ptr[tok] === 'undefined') { return defaultValue; } else { if (toks.length === 0) { ptr[tok] = value; return json; } else { ptr = ptr[tok]; } } } else if (search === 'array') { // find index tok in ptr after finding a ] searchTok = tok; } } } // ptr = value; return json; } function tokenizePath(path) { let t = []; let b = null; for (let p = 0; p < path.length; p++) { let c = path[p]; if (c == ".") { if (b !== null) t.push(b); b = null; t.push("."); } else if (c == "[") { if (b !== null) t.push(b); b = null; t.push("["); } else if (c == "]") { if (b !== null) t.push(b); b = null; t.push("]"); } else { b = ((b===null)?"":b) + c; } } if (b !== null) t.push(b); return t; } export { tokenizePath, jsonQuery, jsonPatch, };