mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
JSONPath: Add ability to select root node for appending/modifying
As discussed with filter list maintainers.
Examples of usage:
$ => result is `null`
$+={"modifyOrCreate": "..."}
These expressions were not working with previous version.
This commit is contained in:
parent
5629bf8a23
commit
faff035203
4 changed files with 55 additions and 36 deletions
|
|
@ -124,12 +124,12 @@ export class JSONPath {
|
|||
return paths;
|
||||
}
|
||||
apply(root) {
|
||||
if ( this.valid === false ) { return 0; }
|
||||
if ( this.valid === false ) { return; }
|
||||
const { rval } = this.#compiled;
|
||||
this.#root = root;
|
||||
this.#root = { '$': root };
|
||||
const paths = this.#evaluate(this.#compiled.steps, []);
|
||||
const n = paths.length;
|
||||
let i = n;
|
||||
let i = paths.length
|
||||
if ( i === 0 ) { this.#root = null; return; }
|
||||
while ( i-- ) {
|
||||
const { obj, key } = this.#resolvePath(paths[i]);
|
||||
if ( rval !== undefined ) {
|
||||
|
|
@ -140,8 +140,9 @@ export class JSONPath {
|
|||
delete obj[key];
|
||||
}
|
||||
}
|
||||
const result = this.#root['$'] ?? null;
|
||||
this.#root = null;
|
||||
return n;
|
||||
return result;
|
||||
}
|
||||
dump() {
|
||||
return JSON.stringify(this.#compiled);
|
||||
|
|
@ -166,8 +167,15 @@ export class JSONPath {
|
|||
if ( query.length === 0 ) { return; }
|
||||
const steps = [];
|
||||
let c = query.charCodeAt(i);
|
||||
steps.push({ mv: c === 0x24 /* $ */ ? this.#ROOT : this.#CURRENT });
|
||||
if ( c === 0x24 /* $ */ || c === 0x40 /* @ */ ) { i += 1; }
|
||||
if ( c === 0x24 /* $ */ ) {
|
||||
steps.push({ mv: this.#ROOT });
|
||||
i += 1;
|
||||
} else if ( c === 0x40 /* @ */ ) {
|
||||
steps.push({ mv: this.#CURRENT });
|
||||
i += 1;
|
||||
} else {
|
||||
steps.push({ mv: i === 0 ? this.#ROOT : this.#CURRENT });
|
||||
}
|
||||
let mv = this.#UNDEFINED;
|
||||
for (;;) {
|
||||
if ( i === query.length ) { break; }
|
||||
|
|
@ -229,7 +237,8 @@ export class JSONPath {
|
|||
i = r.i + 1;
|
||||
mv = this.#UNDEFINED;
|
||||
}
|
||||
if ( steps.length <= 1 ) { return; }
|
||||
if ( steps.length === 0 ) { return; }
|
||||
if ( mv !== this.#UNDEFINED ) { return; }
|
||||
return { steps, i };
|
||||
}
|
||||
#evaluate(steps, pathin) {
|
||||
|
|
@ -238,7 +247,7 @@ export class JSONPath {
|
|||
for ( const step of steps ) {
|
||||
switch ( step.mv ) {
|
||||
case this.#ROOT:
|
||||
resultset = [ [] ];
|
||||
resultset = [ [ '$' ] ];
|
||||
break;
|
||||
case this.#CURRENT:
|
||||
resultset = [ pathin ];
|
||||
|
|
|
|||
|
|
@ -51,12 +51,13 @@ function editOutboundObjectFn(
|
|||
}
|
||||
proxyApplyFn(propChain, function(context) {
|
||||
const obj = context.reflect();
|
||||
if ( jsonp.apply(obj) === 0 ) { return obj; }
|
||||
const objAfter = jsonp.apply(obj);
|
||||
if ( objAfter === undefined ) { return obj; }
|
||||
safe.uboLog(logPrefix, 'Edited');
|
||||
if ( safe.logLevel > 1 ) {
|
||||
safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(obj, null, 2)}`);
|
||||
safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(objAfter, null, 2)}`);
|
||||
}
|
||||
return obj;
|
||||
return objAfter;
|
||||
});
|
||||
}
|
||||
registerScriptlet(editOutboundObjectFn, {
|
||||
|
|
@ -206,12 +207,13 @@ function editInboundObjectFn(
|
|||
} catch {
|
||||
}
|
||||
if ( typeof clone !== 'object' || clone === null ) { return; }
|
||||
if ( jsonp.apply(clone) === 0 ) { return; }
|
||||
const objAfter = jsonp.apply(clone);
|
||||
if ( objAfter === undefined ) { return; }
|
||||
safe.uboLog(logPrefix, 'Edited');
|
||||
if ( safe.logLevel > 1 ) {
|
||||
safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(clone, null, 2)}`);
|
||||
safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(objAfter, null, 2)}`);
|
||||
}
|
||||
return clone;
|
||||
return objAfter;
|
||||
};
|
||||
proxyApplyFn(propChain, function(context) {
|
||||
const i = getArgPos(context.args);
|
||||
|
|
@ -343,13 +345,17 @@ function jsonEditXhrResponseFn(trusted, jsonq = '') {
|
|||
} else if ( typeof innerResponse === 'string' ) {
|
||||
try { obj = safe.JSON_parse(innerResponse); } catch { }
|
||||
}
|
||||
if ( typeof obj !== 'object' || obj === null || jsonp.apply(obj) === 0 ) {
|
||||
if ( typeof obj !== 'object' || obj === null ) {
|
||||
return (xhrDetails.response = innerResponse);
|
||||
}
|
||||
const objAfter = jsonp.apply(obj);
|
||||
if ( objAfter === undefined ) {
|
||||
return (xhrDetails.response = innerResponse);
|
||||
}
|
||||
safe.uboLog(logPrefix, 'Edited');
|
||||
const outerResponse = typeof innerResponse === 'string'
|
||||
? JSONPath.toJSON(obj, safe.JSON_stringify)
|
||||
: obj;
|
||||
? JSONPath.toJSON(objAfter, safe.JSON_stringify)
|
||||
: objAfter;
|
||||
return (xhrDetails.response = outerResponse);
|
||||
}
|
||||
get responseText() {
|
||||
|
|
@ -467,9 +473,9 @@ function jsonEditXhrRequestFn(trusted, jsonq = '') {
|
|||
try { data = safe.JSON_parse(body); }
|
||||
catch { }
|
||||
if ( data instanceof Object === false ) { return; }
|
||||
const n = jsonp.apply(data);
|
||||
if ( n === 0 ) { return; }
|
||||
body = safe.JSON_stringify(data);
|
||||
const objAfter = jsonp.apply(data);
|
||||
if ( objAfter === undefined ) { return; }
|
||||
body = safe.JSON_stringify(objAfter);
|
||||
safe.uboLog(logPrefix, 'Edited');
|
||||
if ( safe.logLevel > 1 ) {
|
||||
safe.uboLog(logPrefix, `After edit:\n${body}`);
|
||||
|
|
@ -583,9 +589,10 @@ function jsonEditFetchResponseFn(trusted, jsonq = '') {
|
|||
const response = responseBefore.clone();
|
||||
return response.json().then(obj => {
|
||||
if ( typeof obj !== 'object' ) { return responseBefore; }
|
||||
if ( jsonp.apply(obj) === 0 ) { return responseBefore; }
|
||||
const objAfter = jsonp.apply(obj);
|
||||
if ( objAfter === undefined ) { return responseBefore; }
|
||||
safe.uboLog(logPrefix, 'Edited');
|
||||
const responseAfter = Response.json(obj, {
|
||||
const responseAfter = Response.json(objAfter, {
|
||||
status: responseBefore.status,
|
||||
statusText: responseBefore.statusText,
|
||||
headers: responseBefore.headers,
|
||||
|
|
@ -694,9 +701,9 @@ function jsonEditFetchRequestFn(trusted, jsonq = '') {
|
|||
try { data = safe.JSON_parse(body); }
|
||||
catch { }
|
||||
if ( data instanceof Object === false ) { return; }
|
||||
const n = jsonp.apply(data);
|
||||
if ( n === 0 ) { return; }
|
||||
return safe.JSON_stringify(data);
|
||||
const objAfter = jsonp.apply(data);
|
||||
if ( objAfter === undefined ) { return; }
|
||||
return safe.JSON_stringify(objAfter);
|
||||
}
|
||||
const proxyHandler = context => {
|
||||
const args = context.callArgs;
|
||||
|
|
@ -813,11 +820,12 @@ function jsonlEditFn(jsonp, text = '') {
|
|||
linesAfter.push(lineBefore);
|
||||
continue;
|
||||
}
|
||||
if ( jsonp.apply(obj) === 0 ) {
|
||||
const objAfter = jsonp.apply(obj);
|
||||
if ( objAfter === undefined ) {
|
||||
linesAfter.push(lineBefore);
|
||||
continue;
|
||||
}
|
||||
const lineAfter = safe.JSON_stringify(obj);
|
||||
const lineAfter = safe.JSON_stringify(objAfter);
|
||||
linesAfter.push(lineAfter);
|
||||
}
|
||||
return linesAfter.join(lineSeparator);
|
||||
|
|
|
|||
|
|
@ -651,8 +651,9 @@ function textResponseFilterer(session, directives) {
|
|||
const json = session.getString();
|
||||
let obj;
|
||||
try { obj = JSON.parse(json); } catch { break; }
|
||||
if ( cache.jsonp.apply(obj) === 0 ) { break; }
|
||||
session.setString(cache.jsonp.toJSON(obj));
|
||||
const objAfter = cache.jsonp.apply(obj);
|
||||
if ( objAfter === undefined ) { break; }
|
||||
session.setString(cache.jsonp.toJSON(objAfter));
|
||||
applied.push(directive);
|
||||
break;
|
||||
}
|
||||
|
|
@ -666,11 +667,12 @@ function textResponseFilterer(session, directives) {
|
|||
linesAfter.push(lineBefore);
|
||||
continue;
|
||||
}
|
||||
if ( cache.jsonp.apply(obj) === 0 ) {
|
||||
const objAfter = cache.jsonp.apply(obj);
|
||||
if ( objAfter === undefined ) {
|
||||
linesAfter.push(lineBefore);
|
||||
continue;
|
||||
}
|
||||
linesAfter.push(cache.jsonp.toJSON(obj));
|
||||
linesAfter.push(cache.jsonp.toJSON(objAfter));
|
||||
}
|
||||
session.setString(linesAfter.join('\n'));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -150,12 +150,12 @@ section .cm-lineWrapping {
|
|||
const jsonpath = input.value;
|
||||
jsonp.compile(jsonpath);
|
||||
const jsonDataIn = readJSON();
|
||||
const result = formatResult(jsonp.evaluate(jsonDataIn));
|
||||
const left = formatResult(jsonp.evaluate(jsonDataIn));
|
||||
const pathsDiv = document.querySelector('#jsonpath-result');
|
||||
pathsDiv.textContent = result;
|
||||
pathsDiv.textContent = left;
|
||||
const jsonDataOut = readJSON();
|
||||
jsonp.apply(jsonDataOut);
|
||||
const bText = JSON.stringify(jsonDataOut, null, 2);
|
||||
const objAfter = jsonp.apply(jsonDataOut);
|
||||
const bText = JSON.stringify(objAfter !== undefined ? objAfter : jsonDataOut, null, 2);
|
||||
cmMergeView.b.dispatch({
|
||||
changes: {
|
||||
from: 0, to: cmMergeView.b.state.doc.length,
|
||||
|
|
|
|||
Loading…
Reference in a new issue