mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
As discussed with filter list maintainers.
Examples of usage:
$ => result is `null`
$+={"modifyOrCreate": "..."}
These expressions were not working with previous version.
197 lines
5 KiB
HTML
197 lines
5 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
|
|
Requires a local server in root of uBlock repo:
|
|
python3 -m http.server
|
|
|
|
Then load the following URL in the browser:
|
|
http://localhost:8000/tools/jsonpath-tool.html
|
|
|
|
-->
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>JSONPath tool</title>
|
|
<style>
|
|
body {
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-direction: column;
|
|
font-size: 16px;
|
|
gap: 0;
|
|
height: 100vh;
|
|
margin: 0;
|
|
padding: 0.5em;
|
|
width: 100vw;
|
|
}
|
|
h2 {
|
|
margin: 0;
|
|
}
|
|
main {
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-grow: 1;
|
|
gap: 0.5em;
|
|
}
|
|
section {
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
gap: 0.5em;
|
|
max-height: 80cqh;
|
|
overflow: auto;
|
|
}
|
|
section > * {
|
|
border: 1px solid gray;
|
|
box-sizing: border-box;
|
|
flex-grow: 1;
|
|
font-family: monospace;
|
|
font-size: small;
|
|
}
|
|
section .cm-lineWrapping {
|
|
word-break: break-all !important;
|
|
}
|
|
#jsondata-in {
|
|
min-height: 50vh;
|
|
resize: vertical;
|
|
}
|
|
#jsonpath-input {
|
|
font-size: medium;
|
|
}
|
|
#jsonpath-result {
|
|
background-color: #eee;
|
|
flex-grow: 1;
|
|
white-space: pre-wrap;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h2>uBO-flavored JSONPath tool</h2>
|
|
<main>
|
|
<section>
|
|
</section>
|
|
<input id="jsonpath-input" placeholder="JSON path expression" spellcheck="false" value="$..book[?@.price<10]" />
|
|
<div id="jsonpath-result"> </div>
|
|
</main>
|
|
|
|
<script src="../platform/mv3/extension/lib/codemirror/codemirror-ubol/dist/cm6.bundle.ubol.min.js"></script>
|
|
<script type="module">
|
|
// Requires a local server in root of repo:
|
|
// python3 -m http.server
|
|
//
|
|
// Then load the following URL in the browser:
|
|
// http://localhost:8000/tools/jsonpath-tool.html
|
|
|
|
import { JSONPath } from '../src/js/jsonpath.js';
|
|
|
|
let aLastText = JSON.stringify({
|
|
store: {
|
|
book: [ {
|
|
category: "reference",
|
|
author: "Nigel Rees",
|
|
title: "Sayings of the Century",
|
|
price: 8.95
|
|
}, {
|
|
category: "fiction",
|
|
author: "Evelyn Waugh",
|
|
title: "Sword of Honour",
|
|
price: 12.99
|
|
}, {
|
|
category: "fiction",
|
|
author: "Herman Melville",
|
|
title: "Moby Dick",
|
|
isbn: "0-553-21311-3",
|
|
price: 8.99
|
|
}, {
|
|
category: "fiction",
|
|
author: "J. R. R. Tolkien",
|
|
title: "The Lord of the Rings",
|
|
isbn: "0-395-19395-8",
|
|
price: 22.99
|
|
} ],
|
|
bicycle: {
|
|
color: "red",
|
|
price: 19.95
|
|
}
|
|
}
|
|
}, null, 2);
|
|
|
|
function readJSON() {
|
|
const textarea = document.querySelector('#jsondata-in');
|
|
let data;
|
|
try {
|
|
const text = cmMergeView.a.state.doc.toString();
|
|
data = JSON.parse(text);
|
|
} catch {
|
|
data = {};
|
|
}
|
|
if ( typeof data !== 'object' || data === null ) {
|
|
data = {};
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function formatResult(a) {
|
|
if ( a === undefined ) { return 'undefined'; }
|
|
if ( jsonp.valid === false ) { return 'bad expression'; }
|
|
if ( Array.isArray(a) === false ) {
|
|
return JSON.stringify(a, null, 2);
|
|
}
|
|
const out = [];
|
|
for ( const i of a ) {
|
|
out.push(`[ ${i.map(j => JSON.stringify(j)).join(', ')} ]`);
|
|
}
|
|
return out.join('\n');
|
|
}
|
|
|
|
function process() {
|
|
const input = document.querySelector('#jsonpath-input');
|
|
const jsonpath = input.value;
|
|
jsonp.compile(jsonpath);
|
|
const jsonDataIn = readJSON();
|
|
const left = formatResult(jsonp.evaluate(jsonDataIn));
|
|
const pathsDiv = document.querySelector('#jsonpath-result');
|
|
pathsDiv.textContent = left;
|
|
const jsonDataOut = readJSON();
|
|
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,
|
|
insert: bText,
|
|
},
|
|
});
|
|
}
|
|
|
|
const jsonp = new JSONPath();
|
|
let jsonDataIn = {};
|
|
let processTimer;
|
|
|
|
const cmMergeView = self.cm6.createMergeView({
|
|
aDoc: aLastText,
|
|
aUpdateListener: info => {
|
|
if ( info.docChanged === false ) { return; }
|
|
if ( processTimer !== undefined ) { return; }
|
|
processTimer = setTimeout(( ) => {
|
|
processTimer = undefined;
|
|
const aNewText = info.state.doc.toString();
|
|
if ( aNewText === aLastText ) { return; }
|
|
aLastText = aNewText;
|
|
process();
|
|
}, 71);
|
|
},
|
|
}, document.querySelector('section'));
|
|
|
|
{
|
|
const input = document.querySelector('#jsonpath-input');
|
|
input.addEventListener('input', ( ) => {
|
|
process();
|
|
});
|
|
}
|
|
|
|
process();
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|