nimma
Version:
Scalable JSONPath engine.
199 lines (160 loc) • 4.45 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var guards = require('./guards.cjs');
function emptyState() {
return {
absoluteOffset: -1,
groupNumbers: [],
indexed: true,
isLastNode: true,
numbers: [-1, -1],
offset: -1,
usesState: false,
};
}
class Iterator {
nodes;
constructor(nodes) {
this.modifiers = Iterator.trim(nodes);
this.nodes = Iterator.compact(nodes);
this.feedback = Iterator.analyze(this.nodes);
this.length = this.nodes.length;
this.state = emptyState();
if (this.feedback.fixed && this.modifiers.parents > this.length) {
this.length = -1;
}
}
static compact(nodes) {
let marked;
for (let i = 0; i < nodes.length; i++) {
if (
guards.isWildcardExpression(nodes[i]) &&
guards.isDeep(nodes[i]) &&
i !== nodes.length - 1
) {
(marked ??= []).push(i);
}
}
if (marked === void 0) {
return nodes;
}
const _nodes = nodes.slice();
for (let i = 0; i < marked.length; i++) {
_nodes[marked[i] - i + 1].deep = true;
_nodes.splice(marked[i] - i, 1);
}
return _nodes;
}
static trim(nodes) {
const modifiers = {
keyed: false,
parents: 0,
};
while (nodes.length > 0 && guards.isModifierExpression(nodes[nodes.length - 1])) {
switch (nodes.pop().type) {
case 'KeyExpression':
modifiers.keyed = true;
modifiers.parents = 0;
break;
case 'ParentExpression':
modifiers.parents++;
break;
}
}
return modifiers;
}
static analyze(nodes) {
const feedback = {
fixed: true,
inverseOffset: -1,
minimumDepth: -1,
shorthands: 0,
stateOffset: -1,
};
let deep = -1;
let potentialInverseOffset = -1;
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (guards.isShorthandExpression(node)) {
if (node.arguments[0] > 0) {
feedback.stateOffset = i;
}
feedback.minimumDepth = i - 1;
feedback.shorthands++;
feedback.fixed = false;
}
if (!guards.isDeep(node)) {
if (guards.isScriptFilterExpression(node) || guards.isNegativeSliceExpression(node)) {
if (i === nodes.length - 1) {
feedback.inverseOffset = potentialInverseOffset;
} else {
feedback.stateOffset = deep === -1 ? i : deep;
}
} else {
feedback.inverseOffset = potentialInverseOffset;
}
continue;
}
if (potentialInverseOffset === -1) {
potentialInverseOffset = i;
}
if (deep !== -1) {
feedback.stateOffset = deep;
break;
} else if (guards.isScriptFilterExpression(node) && i !== nodes.length - 1) {
feedback.stateOffset = i;
deep = i;
break;
}
deep = i;
}
if (feedback.shorthands === 0) {
feedback.fixed = deep === -1;
feedback.minimumDepth =
feedback.stateOffset === -1 ? nodes.length - 1 : feedback.stateOffset;
}
return feedback;
}
*[Symbol.iterator]() {
const { feedback, nodes, state } = this;
Object.assign(state, emptyState());
for (let i = 0; i < nodes.length; i++) {
state.absoluteOffset = i;
if (guards.isDeep(nodes[i])) {
state.offset = -1;
state.indexed = false;
if (state.groupNumbers.length > 0) {
state.groupNumbers.length = 0;
}
}
if (feedback.stateOffset === i) {
state.offset = -1;
state.usesState = true;
}
if (feedback.inverseOffset === i) {
state.offset = i - nodes.length;
} else {
state.offset++;
}
if (state.usesState) {
if (state.numbers[0] === -1) {
state.numbers[0] = 0;
state.numbers[1] = 1;
} else {
state.numbers[0] = state.numbers[1];
state.numbers[1] = (state.numbers[1] << 1) + 1;
}
state.groupNumbers.push(state.numbers[0]);
}
state.isLastNode = i === nodes.length - 1;
yield nodes[i];
if (guards.isShorthandExpression(nodes[i])) {
let depth = nodes[i].arguments[0];
while (depth-- > 0) {
state.numbers[1] = (state.numbers[1] << 1) + 1;
}
}
}
}
}
exports.default = Iterator;