botbook/node_modules/@sagold/json-query/dist/module/lib/interpreter/index.js

102 lines
3 KiB
JavaScript
Raw Normal View History

2024-09-04 13:13:15 -03:00
import { expand, select, cache } from "./nodes";
import { VALUE_INDEX, KEY_INDEX, PARENT_INDEX, POINTER_INDEX } from "./keys";
function collect(func, input, node, pointer) {
const result = [];
for (let i = 0, l = input.length; i < l; i += 1) {
result.push(...func(node, input[i], node, pointer));
}
return result;
}
function reduce(func, input, node, pointer) {
const result = [];
for (let i = 0, l = input.length; i < l; i += 1) {
const output = func(node, input[i], pointer);
if (output) {
result.push(output);
}
}
return result;
}
function query(data, ast, pointer) {
let result = data;
ast.children.forEach((node) => {
if (expand[node.type]) {
result = collect(expand[node.type], result, node, pointer);
}
else if (select[node.type]) {
result = reduce(select[node.type], result, node, pointer);
}
else {
throw new Error(`Unknown filter ${node.type}`);
}
});
return result;
}
function runPatternOnce(inputSet, ast, pointer) {
const resultingSet = [];
let workingSet = inputSet;
ast.children.forEach((node) => {
if (node.type === "orPattern") {
resultingSet.push(...workingSet);
workingSet = inputSet;
return;
}
workingSet = runNode(workingSet, node, pointer);
});
resultingSet.push(...workingSet);
return resultingSet;
}
function getIterationCount(quantifier) {
if (quantifier == null) {
return 1; // default, simple group
}
if (quantifier === "*" || quantifier === "+") {
return Infinity;
}
const count = parseInt(quantifier);
return isNaN(count) ? 1 : count;
}
function pattern(data, ast, pointer) {
const result = [];
const quantifier = ast.children.find((node) => node.type === "quantifier");
const iterationCount = getIterationCount(quantifier && quantifier.text);
let workingSet = data;
if (quantifier && quantifier.text === "*") {
result.push(...workingSet);
}
let count = 0;
while (workingSet.length > 0 && count < iterationCount) {
workingSet = runPatternOnce(workingSet, ast, pointer);
result.push(...workingSet);
count += 1;
}
return result;
}
function skip(data, ast, pointer) {
let result = data;
ast.children.forEach((n) => (result = runNode(result, n, pointer)));
return result;
}
function runNode(data, ast, pointer) {
let result;
if (ast.type === "query") {
result = query(data, ast, pointer);
}
else if (ast.type === "pattern") {
result = pattern(data, ast, pointer);
}
else {
result = skip(data, ast, pointer);
}
// after each query or pattern, reset the cache, to (re)enable nested queries
cache.reset();
cache.mem.push(data);
return result;
}
export function run(data, ast) {
cache.reset();
cache.mem.push(data);
return runNode([[data, null, null, "#"]], ast);
}
export { VALUE_INDEX, KEY_INDEX, PARENT_INDEX, POINTER_INDEX };