JSFiddle - React, Tailwind, and code Playground
by alexb
HTML
<!DOCTYPE html>
<title>JSON Selector</title>
<script src="https://unpkg.com/[email protected]/build.js"></script>
<div><tt>const obj = </tt><textarea>{
"vals": {
"more": [
{
"a":1,
"b":2
},
{
"a":3,
"b":4
}
]
}
}</textarea></div>
<p><tt></tt></p>
CSS
div {
display: flex;
}
textarea {
flex-grow: 1;
height: 300px;
}
JavaScript
function cursorCompare(a, b) {
return a.line - b.line || a.column - b.column;
}
function cursorBetween(cursor, start, end) {
return cursorCompare(cursor, start) >= 0 && cursorCompare(cursor, end) <= 0;
}
/**
* @param {object} ast
* @param {{ line: number, column: number }} cursor
* @returns {string[]}
*/
function accessor(ast, cursor, path = []) {
if (ast && ast.children) {
for (const i in ast.children) {
const child = ast.children[i];
if (cursorBetween(cursor, child.loc.start, child.loc.end)) {
const [key, value] = child.key
? [child.key.value, child.value]
: [i, child];
path.push(key);
return accessor(value, cursor, path);
}
}
}
return path;
}
// Code below demonstrates use of `accessor` function.
const input = document.querySelector("textarea");
const p = document.querySelector("p tt");
let ast, cursorPos;
function updateAST() {
try {
ast = jsonToAst(input.value, { loc: true });
} catch (e) {
ast = null;
}
}
function updateCursorPosition() {
if (input.selectionStart !== cursorPos) {
cursorPos = input.selectionStart;
onCursorPositionChange();
}
}
input.addEventListener("input", updateAST);
input.addEventListener("click", updateCursorPosition);
input.addEventListener("keyup", updateCursorPosition);
function onCursorPositionChange() {
if (!ast) {
p.textContent = 'Invalid JSON';
return;
}
const beforeCursor = input.value.substr(0, cursorPos);
const lines = beforeCursor.split(/\r\n?|\n/);
const cursor = {
line: lines.length,
column: lines[lines.length - 1].length + 1
};
const path = accessor(ast, cursor);
const pathStr = path
.map(p => (/^\d+$/.test(p) ? `[${p}]` : `['${p}']`))
.join("");
p.textContent = "obj" + pathStr;
}
updateAST();
updateCursorPosition();