@qualifyze/airtable-formulator
Version:
Airtable Formula Manipulator
90 lines • 3.84 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.reduceOperations = exports.isOperationNode = void 0;
const primitives_1 = require("./primitives");
const expression_1 = require("./expression");
const utils_1 = require("./utils");
const node_reducer_1 = require("./node-reducer");
function isOperationNodeMember(node) {
return (0, expression_1.isExpressionNode)(node) || (0, primitives_1.isOperator)(node) || (0, primitives_1.isSpace)(node);
}
function isOperationNode(node) {
const { operator, left, right } = node;
return ((0, primitives_1.isGroupNode)(node) &&
node.members.every(isOperationNodeMember) &&
node.type === "operation" &&
(0, primitives_1.isNode)(operator) &&
(0, primitives_1.isOperator)(operator) &&
(0, primitives_1.isNode)(left) &&
(0, expression_1.isExpressionNode)(left) &&
(0, primitives_1.isNode)(right) &&
(0, expression_1.isExpressionNode)(right));
}
exports.isOperationNode = isOperationNode;
function createOperation(nodes) {
const operation = (0, primitives_1.createGroup)("operation", nodes);
const [left, operator, right, invalid] = (0, primitives_1.filterMeaningfulNodes)(nodes);
if (!left || !(0, expression_1.isExpressionNode)(left)) {
throw new Error((0, primitives_1.createNodeErrorMessage)(operation, `expected left operand to be an expression type, but got ${left.type}`));
}
if (!operator || !(0, primitives_1.isOperator)(operator)) {
throw new Error((0, primitives_1.createNodeErrorMessage)(operation, `expected an operator, but got ${operator.type}`));
}
if (!right || !(0, expression_1.isExpressionNode)(right)) {
throw new Error((0, primitives_1.createNodeErrorMessage)(operation, `expected right operand to be an expression type, but got ${right.type}`));
}
if (invalid) {
throw new Error((0, primitives_1.createNodeErrorMessage)(operation, `expected only left operand, operator, and right operand, but got an extra ${invalid.type}`));
}
return {
...operation,
left,
operator,
right,
};
}
// XXX I could not find any reliable sources on airtable operator precedence,
// so I am assuming that it will be similar to javascript's operator precedence.
const operatorPrecedence = [
"&",
"*",
"/",
"+",
"-",
"<",
"<=",
">",
">=",
"=",
"!=",
];
exports.reduceOperations = (0, node_reducer_1.eagerlyRepeat)(([...nodes]) => {
const meaningfulNodes = (0, primitives_1.filterMeaningfulNodes)(nodes);
const operatorNodes = meaningfulNodes.filter(primitives_1.isOperator);
// Sort operators by precedence
operatorNodes.sort((a, b) => {
const aIndex = operatorPrecedence.indexOf(a.value);
const bIndex = operatorPrecedence.indexOf(b.value);
return aIndex - bIndex;
});
const replacement = operatorNodes
.map((operator) => {
const operatorIndex = meaningfulNodes.indexOf(operator);
const left = meaningfulNodes[operatorIndex - 1];
const right = meaningfulNodes[operatorIndex + 1];
return { left, operator, right };
})
.find(({ left, right }) => left && (0, expression_1.isExpressionNode)(left) && right && (0, expression_1.isExpressionNode)(right));
if (replacement) {
const { left, right } = replacement;
const leftIndex = nodes.indexOf(left);
const rightIndex = nodes.indexOf(right);
const members = nodes.slice(leftIndex, rightIndex + 1);
if ((0, utils_1.checkArray)(members, isOperationNodeMember)) {
const operation = createOperation(members);
nodes.splice(leftIndex, members.length, operation);
}
}
return nodes;
});
//# sourceMappingURL=operation.js.map