Add `json-edit` suite of scriptlets; extend `replace=` option · gorhill/uBlock@b18daa5 · GitHub | Latest TMZ Celebrity News & Gossip | Watch TMZ Live
Skip to content

Commit b18daa5

Browse files
committed
Add json-edit suite of scriptlets; extend replace= option
Scriptlets added: - json-edit - trusted-json-edit - json-edit-xhr-response - trusted-json-edit-xhr-response - json-edit-fetch-response - trusted-json-edit-fetch-response - jsonl-edit-xhr-response - trusted-jsonl-edit-xhr-response - jsonl-edit-fetch-response - trusted-jsonl-edit-fetch-response These scriptlets are functionally similar to their `json-prune` counterpart, except that they all use the new uBO-flavored JSONPath syntax, and the `trusted-` versions allow to modify values instead of just removing them. The `replace=` filter option has been extended to support applying uBO-flavored JSONPath syntax to the response body. If the `replace=` value starts with `json:` or `jsonl:`, the remaining of the value will be interpreted as a JSONPath directive, which can be used to either remove or modify property in a JSON document.
1 parent 1ce00e4 commit b18daa5

File tree

7 files changed

+801
-279
lines changed

7 files changed

+801
-279
lines changed

src/js/jsonpath.js

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,62 @@ export class JSONPath {
2828
jsonp.compile(query);
2929
return jsonp;
3030
}
31+
static toJSON(obj, stringifier, ...args) {
32+
return (stringifier || JSON.stringify)(obj, ...args)
33+
.replace(/\//g, '\\/');
34+
}
35+
get value() {
36+
return this.#compiled && this.#compiled.rval;
37+
}
38+
set value(v) {
39+
if ( this.#compiled === undefined ) { return; }
40+
this.#compiled.rval = v;
41+
}
42+
get valid() {
43+
return this.#compiled !== undefined;
44+
}
3145
compile(query) {
32-
this.#compiled = this.#compile(query, 0);
33-
return this.#compiled ? this.#compiled.i : 0;
46+
const r = this.#compile(query, 0);
47+
if ( r === undefined ) { return; }
48+
if ( r.i !== query.length ) {
49+
if ( query.startsWith('=', r.i) === false ) { return; }
50+
try { r.rval = JSON.parse(query.slice(r.i+1)); }
51+
catch { return; }
52+
}
53+
this.#compiled = r;
3454
}
3555
evaluate(root) {
36-
if ( this.#compiled === undefined ) { return []; }
37-
this.root = root;
38-
return this.#evaluate(this.#compiled.steps, []);
56+
if ( this.valid === false ) { return []; }
57+
this.#root = root;
58+
const paths = this.#evaluate(this.#compiled.steps, []);
59+
this.#root = null;
60+
return paths;
3961
}
40-
resolvePath(path) {
41-
if ( path.length === 0 ) { return { value: this.root }; }
42-
const key = path.at(-1);
43-
let obj = this.root
44-
for ( let i = 0, n = path.length-1; i < n; i++ ) {
45-
obj = obj[path[i]];
62+
apply(root) {
63+
if ( this.valid === false ) { return 0; }
64+
const { rval } = this.#compiled;
65+
this.#root = root;
66+
const paths = this.#evaluate(this.#compiled.steps, []);
67+
const n = paths.length;
68+
let i = n;
69+
while ( i-- ) {
70+
const { obj, key } = this.#resolvePath(paths[i]);
71+
if ( rval !== undefined ) {
72+
obj[key] = rval;
73+
} else if ( Array.isArray(obj) && typeof key === 'number' ) {
74+
obj.splice(key, 1);
75+
} else {
76+
delete obj[key];
77+
}
4678
}
47-
return { obj, key, value: obj[key] };
79+
this.#root = null;
80+
return n;
81+
}
82+
toJSON(obj, ...args) {
83+
return JSONPath.toJSON(obj, null, ...args)
4884
}
49-
toString() {
50-
return JSON.stringify(this.#compiled);
85+
get [Symbol.toStringTag]() {
86+
return 'JSONPath';
5187
}
5288
#UNDEFINED = 0;
5389
#ROOT = 1;
@@ -57,6 +93,7 @@ export class JSONPath {
5793
#reUnquotedIdentifier = /^[A-Za-z_][\w]*|^\*/;
5894
#reExpr = /^([!=^$*]=|[<>]=?)(.+?)\)\]/;
5995
#reIndice = /^\[-?\d+\]/;
96+
#root;
6097
#compiled;
6198
#compile(query, i) {
6299
if ( query.length === 0 ) { return; }
@@ -88,7 +125,7 @@ export class JSONPath {
88125
if ( mv === this.#UNDEFINED ) {
89126
const step = steps.at(-1);
90127
if ( step === undefined ) { return; }
91-
i = this.#compileExpr(step, query, i);
128+
i = this.#compileExpr(query, step, i);
92129
break;
93130
}
94131
const s = this.#consumeUnquotedIdentifier(query, i);
@@ -166,7 +203,7 @@ export class JSONPath {
166203
const listout = [];
167204
const recursive = step.mv === this.#DESCENDANTS;
168205
for ( const pathin of listin ) {
169-
const { value: v } = this.resolvePath(pathin);
206+
const { value: v } = this.#resolvePath(pathin);
170207
if ( v === null ) { continue; }
171208
if ( v === undefined ) { continue; }
172209
const { steps, k } = step;
@@ -298,7 +335,7 @@ export class JSONPath {
298335
if ( match === null ) { return; }
299336
return match[0];
300337
}
301-
#compileExpr(step, query, i) {
338+
#compileExpr(query, step, i) {
302339
const match = this.#reExpr.exec(query.slice(i));
303340
if ( match === null ) { return i; }
304341
try {
@@ -308,8 +345,17 @@ export class JSONPath {
308345
}
309346
return i + match[1].length + match[2].length;
310347
}
348+
#resolvePath(path) {
349+
if ( path.length === 0 ) { return { value: this.#root }; }
350+
const key = path.at(-1);
351+
let obj = this.#root
352+
for ( let i = 0, n = path.length-1; i < n; i++ ) {
353+
obj = obj[path[i]];
354+
}
355+
return { obj, key, value: obj[key] };
356+
}
311357
#evaluateExpr(step, path, out) {
312-
const { obj: o, key: k } = this.resolvePath(path);
358+
const { obj: o, key: k } = this.#resolvePath(path);
313359
const hasOwn = o instanceof Object && Object.hasOwn(o, k);
314360
const v = o[k];
315361
let outcome = true;

0 commit comments

Comments
 (0)

TMZ Celebrity News – Breaking Stories, Videos & Gossip

Looking for the latest TMZ celebrity news? You've come to the right place. From shocking Hollywood scandals to exclusive videos, TMZ delivers it all in real time.

Whether it’s a red carpet slip-up, a viral paparazzi moment, or a legal drama involving your favorite stars, TMZ news is always first to break the story. Stay in the loop with daily updates, insider tips, and jaw-dropping photos.

🎥 Watch TMZ Live

TMZ Live brings you daily celebrity news and interviews straight from the TMZ newsroom. Don’t miss a beat—watch now and see what’s trending in Hollywood.