Skip to content

Commit faff035

Browse files
committed
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.
1 parent 5629bf8 commit faff035

File tree

4 files changed

+55
-36
lines changed

4 files changed

+55
-36
lines changed

src/js/jsonpath.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,12 @@ export class JSONPath {
124124
return paths;
125125
}
126126
apply(root) {
127-
if ( this.valid === false ) { return 0; }
127+
if ( this.valid === false ) { return; }
128128
const { rval } = this.#compiled;
129-
this.#root = root;
129+
this.#root = { '$': root };
130130
const paths = this.#evaluate(this.#compiled.steps, []);
131-
const n = paths.length;
132-
let i = n;
131+
let i = paths.length
132+
if ( i === 0 ) { this.#root = null; return; }
133133
while ( i-- ) {
134134
const { obj, key } = this.#resolvePath(paths[i]);
135135
if ( rval !== undefined ) {
@@ -140,8 +140,9 @@ export class JSONPath {
140140
delete obj[key];
141141
}
142142
}
143+
const result = this.#root['$'] ?? null;
143144
this.#root = null;
144-
return n;
145+
return result;
145146
}
146147
dump() {
147148
return JSON.stringify(this.#compiled);
@@ -166,8 +167,15 @@ export class JSONPath {
166167
if ( query.length === 0 ) { return; }
167168
const steps = [];
168169
let c = query.charCodeAt(i);
169-
steps.push({ mv: c === 0x24 /* $ */ ? this.#ROOT : this.#CURRENT });
170-
if ( c === 0x24 /* $ */ || c === 0x40 /* @ */ ) { i += 1; }
170+
if ( c === 0x24 /* $ */ ) {
171+
steps.push({ mv: this.#ROOT });
172+
i += 1;
173+
} else if ( c === 0x40 /* @ */ ) {
174+
steps.push({ mv: this.#CURRENT });
175+
i += 1;
176+
} else {
177+
steps.push({ mv: i === 0 ? this.#ROOT : this.#CURRENT });
178+
}
171179
let mv = this.#UNDEFINED;
172180
for (;;) {
173181
if ( i === query.length ) { break; }
@@ -229,7 +237,8 @@ export class JSONPath {
229237
i = r.i + 1;
230238
mv = this.#UNDEFINED;
231239
}
232-
if ( steps.length <= 1 ) { return; }
240+
if ( steps.length === 0 ) { return; }
241+
if ( mv !== this.#UNDEFINED ) { return; }
233242
return { steps, i };
234243
}
235244
#evaluate(steps, pathin) {
@@ -238,7 +247,7 @@ export class JSONPath {
238247
for ( const step of steps ) {
239248
switch ( step.mv ) {
240249
case this.#ROOT:
241-
resultset = [ [] ];
250+
resultset = [ [ '$' ] ];
242251
break;
243252
case this.#CURRENT:
244253
resultset = [ pathin ];

src/js/resources/json-edit.js

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,13 @@ function editOutboundObjectFn(
5151
}
5252
proxyApplyFn(propChain, function(context) {
5353
const obj = context.reflect();
54-
if ( jsonp.apply(obj) === 0 ) { return obj; }
54+
const objAfter = jsonp.apply(obj);
55+
if ( objAfter === undefined ) { return obj; }
5556
safe.uboLog(logPrefix, 'Edited');
5657
if ( safe.logLevel > 1 ) {
57-
safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(obj, null, 2)}`);
58+
safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(objAfter, null, 2)}`);
5859
}
59-
return obj;
60+
return objAfter;
6061
});
6162
}
6263
registerScriptlet(editOutboundObjectFn, {
@@ -206,12 +207,13 @@ function editInboundObjectFn(
206207
} catch {
207208
}
208209
if ( typeof clone !== 'object' || clone === null ) { return; }
209-
if ( jsonp.apply(clone) === 0 ) { return; }
210+
const objAfter = jsonp.apply(clone);
211+
if ( objAfter === undefined ) { return; }
210212
safe.uboLog(logPrefix, 'Edited');
211213
if ( safe.logLevel > 1 ) {
212-
safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(clone, null, 2)}`);
214+
safe.uboLog(logPrefix, `After edit:\n${safe.JSON_stringify(objAfter, null, 2)}`);
213215
}
214-
return clone;
216+
return objAfter;
215217
};
216218
proxyApplyFn(propChain, function(context) {
217219
const i = getArgPos(context.args);
@@ -343,13 +345,17 @@ function jsonEditXhrResponseFn(trusted, jsonq = '') {
343345
} else if ( typeof innerResponse === 'string' ) {
344346
try { obj = safe.JSON_parse(innerResponse); } catch { }
345347
}
346-
if ( typeof obj !== 'object' || obj === null || jsonp.apply(obj) === 0 ) {
348+
if ( typeof obj !== 'object' || obj === null ) {
349+
return (xhrDetails.response = innerResponse);
350+
}
351+
const objAfter = jsonp.apply(obj);
352+
if ( objAfter === undefined ) {
347353
return (xhrDetails.response = innerResponse);
348354
}
349355
safe.uboLog(logPrefix, 'Edited');
350356
const outerResponse = typeof innerResponse === 'string'
351-
? JSONPath.toJSON(obj, safe.JSON_stringify)
352-
: obj;
357+
? JSONPath.toJSON(objAfter, safe.JSON_stringify)
358+
: objAfter;
353359
return (xhrDetails.response = outerResponse);
354360
}
355361
get responseText() {
@@ -467,9 +473,9 @@ function jsonEditXhrRequestFn(trusted, jsonq = '') {
467473
try { data = safe.JSON_parse(body); }
468474
catch { }
469475
if ( data instanceof Object === false ) { return; }
470-
const n = jsonp.apply(data);
471-
if ( n === 0 ) { return; }
472-
body = safe.JSON_stringify(data);
476+
const objAfter = jsonp.apply(data);
477+
if ( objAfter === undefined ) { return; }
478+
body = safe.JSON_stringify(objAfter);
473479
safe.uboLog(logPrefix, 'Edited');
474480
if ( safe.logLevel > 1 ) {
475481
safe.uboLog(logPrefix, `After edit:\n${body}`);
@@ -583,9 +589,10 @@ function jsonEditFetchResponseFn(trusted, jsonq = '') {
583589
const response = responseBefore.clone();
584590
return response.json().then(obj => {
585591
if ( typeof obj !== 'object' ) { return responseBefore; }
586-
if ( jsonp.apply(obj) === 0 ) { return responseBefore; }
592+
const objAfter = jsonp.apply(obj);
593+
if ( objAfter === undefined ) { return responseBefore; }
587594
safe.uboLog(logPrefix, 'Edited');
588-
const responseAfter = Response.json(obj, {
595+
const responseAfter = Response.json(objAfter, {
589596
status: responseBefore.status,
590597
statusText: responseBefore.statusText,
591598
headers: responseBefore.headers,
@@ -694,9 +701,9 @@ function jsonEditFetchRequestFn(trusted, jsonq = '') {
694701
try { data = safe.JSON_parse(body); }
695702
catch { }
696703
if ( data instanceof Object === false ) { return; }
697-
const n = jsonp.apply(data);
698-
if ( n === 0 ) { return; }
699-
return safe.JSON_stringify(data);
704+
const objAfter = jsonp.apply(data);
705+
if ( objAfter === undefined ) { return; }
706+
return safe.JSON_stringify(objAfter);
700707
}
701708
const proxyHandler = context => {
702709
const args = context.callArgs;
@@ -813,11 +820,12 @@ function jsonlEditFn(jsonp, text = '') {
813820
linesAfter.push(lineBefore);
814821
continue;
815822
}
816-
if ( jsonp.apply(obj) === 0 ) {
823+
const objAfter = jsonp.apply(obj);
824+
if ( objAfter === undefined ) {
817825
linesAfter.push(lineBefore);
818826
continue;
819827
}
820-
const lineAfter = safe.JSON_stringify(obj);
828+
const lineAfter = safe.JSON_stringify(objAfter);
821829
linesAfter.push(lineAfter);
822830
}
823831
return linesAfter.join(lineSeparator);

src/js/traffic.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -651,8 +651,9 @@ function textResponseFilterer(session, directives) {
651651
const json = session.getString();
652652
let obj;
653653
try { obj = JSON.parse(json); } catch { break; }
654-
if ( cache.jsonp.apply(obj) === 0 ) { break; }
655-
session.setString(cache.jsonp.toJSON(obj));
654+
const objAfter = cache.jsonp.apply(obj);
655+
if ( objAfter === undefined ) { break; }
656+
session.setString(cache.jsonp.toJSON(objAfter));
656657
applied.push(directive);
657658
break;
658659
}
@@ -666,11 +667,12 @@ function textResponseFilterer(session, directives) {
666667
linesAfter.push(lineBefore);
667668
continue;
668669
}
669-
if ( cache.jsonp.apply(obj) === 0 ) {
670+
const objAfter = cache.jsonp.apply(obj);
671+
if ( objAfter === undefined ) {
670672
linesAfter.push(lineBefore);
671673
continue;
672674
}
673-
linesAfter.push(cache.jsonp.toJSON(obj));
675+
linesAfter.push(cache.jsonp.toJSON(objAfter));
674676
}
675677
session.setString(linesAfter.join('\n'));
676678
break;

tools/jsonpath-tool.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,12 @@ <h2>uBO-flavored JSONPath tool</h2>
150150
const jsonpath = input.value;
151151
jsonp.compile(jsonpath);
152152
const jsonDataIn = readJSON();
153-
const result = formatResult(jsonp.evaluate(jsonDataIn));
153+
const left = formatResult(jsonp.evaluate(jsonDataIn));
154154
const pathsDiv = document.querySelector('#jsonpath-result');
155-
pathsDiv.textContent = result;
155+
pathsDiv.textContent = left;
156156
const jsonDataOut = readJSON();
157-
jsonp.apply(jsonDataOut);
158-
const bText = JSON.stringify(jsonDataOut, null, 2);
157+
const objAfter = jsonp.apply(jsonDataOut);
158+
const bText = JSON.stringify(objAfter !== undefined ? objAfter : jsonDataOut, null, 2);
159159
cmMergeView.b.dispatch({
160160
changes: {
161161
from: 0, to: cmMergeView.b.state.doc.length,

0 commit comments

Comments
 (0)