twing
Version:
First-class Twig engine for Node.js
122 lines (121 loc) • 5.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCoreNodeVisitor = void 0;
const attribute_accessor_1 = require("../node/expression/attribute-accessor");
const name_1 = require("../node/expression/name");
const block_function_1 = require("../node/expression/block-function");
const constant_1 = require("../node/expression/constant");
const method_call_1 = require("../node/expression/method-call");
const parsing_1 = require("../error/parsing");
const test_1 = require("../node/expression/call/test");
const array_1 = require("../node/expression/array");
const conditional_1 = require("../node/expression/conditional");
const get_key_value_pairs_1 = require("../helpers/get-key-value-pairs");
const createCoreNodeVisitor = () => {
const enteredNodes = [];
const enterDefaultFilterNode = (node) => {
const { line, column } = node;
const { arguments: methodArguments } = node.children;
const operand = node.children.operand;
let newNode;
if (operand.type === "name" || operand.type === "attribute_accessor") {
const testNode = (0, test_1.createTestNode)(operand, "defined", (0, array_1.createArrayNode)([], line, column), line, column);
const values = (0, get_key_value_pairs_1.getKeyValuePairs)(methodArguments).map(({ value }) => value);
const falseNode = values.length > 0 ? values[0] : (0, constant_1.createConstantNode)('', line, column);
newNode = (0, conditional_1.createConditionalNode)(testNode, node, falseNode, line, column);
}
else {
newNode = node;
}
return newNode;
};
const enterDefinedTestNode = (node, source) => {
const operand = node.children.operand;
if (operand.type !== "name" &&
operand.type !== "attribute_accessor" &&
operand.type !== "block_function" &&
operand.type !== "constant" &&
operand.type !== "array" &&
operand.type !== "hash" &&
operand.type !== "method_call" &&
!(operand.type === "function" && operand.attributes.operatorName === 'constant')) {
throw (0, parsing_1.createParsingError)('The "defined" test only works with simple variables.', node, source);
}
let newOperand;
if (operand.type === "block_function") {
const blockReferenceExpressionNode = (0, block_function_1.cloneBlockReferenceExpressionNode)(operand);
blockReferenceExpressionNode.attributes.shouldTestExistence = true;
newOperand = blockReferenceExpressionNode;
}
else if (operand.type === "constant" || operand.type === "array") {
newOperand = (0, constant_1.createConstantNode)(true, operand.line, operand.column);
}
else if (operand.type === "name") {
const nameNode = (0, name_1.cloneNameNode)(operand);
nameNode.attributes.shouldTestExistence = true;
newOperand = nameNode;
}
else if (operand.type === "method_call") {
const methodCallNode = (0, method_call_1.cloneMethodCallNode)(operand);
methodCallNode.attributes.shouldTestExistence = true;
newOperand = methodCallNode;
}
else if (operand.type === "attribute_accessor") {
const getAttributeNode = (0, attribute_accessor_1.cloneGetAttributeNode)(operand);
getAttributeNode.attributes.shouldTestExistence = true;
const traverse = (node) => {
node.attributes.isOptimizable = false;
node.attributes.shouldIgnoreStrictCheck = true;
if (node.children.target.type === "attribute_accessor") {
const clonedTarget = (0, attribute_accessor_1.cloneGetAttributeNode)(node.children.target);
traverse(clonedTarget);
node.children.target = clonedTarget;
}
};
traverse(getAttributeNode);
newOperand = getAttributeNode;
}
else {
newOperand = operand;
}
node.children.operand = newOperand;
return node;
};
const leaveGetAttributeNode = (node) => {
const { shouldIgnoreStrictCheck } = node.attributes;
const { target } = node.children;
if (shouldIgnoreStrictCheck) {
if (target.type === "name") {
const nameNode = (0, name_1.cloneNameNode)(target);
nameNode.attributes.shouldIgnoreStrictCheck = true;
node.children.target = nameNode;
}
}
return node;
};
return {
enterNode: (node, source) => {
if (!enteredNodes.includes(node)) {
enteredNodes.push(node);
if (node.type === "filter") {
if (node.attributes.operatorName === "default") {
return enterDefaultFilterNode(node);
}
}
if (node.type === "test") {
if (node.attributes.operatorName === "defined") {
return enterDefinedTestNode(node, source);
}
}
}
return node;
},
leaveNode: (node) => {
if (node.type === "attribute_accessor") {
return leaveGetAttributeNode(node);
}
return node;
}
};
};
exports.createCoreNodeVisitor = createCoreNodeVisitor;