UNPKG

twing

Version:

First-class Twig engine for Node.js

122 lines (121 loc) 5.56 kB
"use strict"; 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;