'use strict'; const getNodes = require("../node/get-nodes"); const getNodeSequences = require("../node/get-node-sequences"); /* Simple node types are always simple, no matter what. */ let simpleNodeTypes = new Set([ "Literal", "Identifier", "ThisExpression", "ContinueStatement", "MemberExpression", /* FIXME: This may be wrong if a computed property is involved? */ ]); /* "Semi-simple" node types are only considered simple if all of their children are also simple. */ let semiSimpleNodeTypes = new Set([ "BinaryExpression", "UnaryExpression", "UpdateExpression", "LogicalExpression", "AssignmentPattern", "AssignmentExpression", "VariableDeclarator", "Property", "ReturnStatement", "IfStatement", "ConditionalExpression", "ExpressionStatement" ]); /* TODO: CallExpression is only simple if nested one level deep at most. */ function checkChildNodes(node, predicate) { let nodeProperties = node.getNodeProperties(); let nodeSequenceProperties = node.getNodeSequenceProperties(); let checkFailed = false; for (let property of nodeProperties) { if (!predicate(node[property])) { checkFailed = true; } } for (let property of nodeSequenceProperties) { for (let item of node[property]) { if (!predicate(item)) { checkFailed = true; } } } return !checkFailed; } function _isSimple(node) { if (simpleNodeTypes.has(node.type)) { return true; } else if (semiSimpleNodeTypes.has(node.type)) { return checkChildNodes(node, (childNode) => childNode.isSimple()); } else if (node.type === "CallExpression") { return checkChildNodes(node, (childNode) => childNode.type !== "CallExpression" && childNode.isSimple()); } else if (node.type === "ObjectExpression") { return (node.properties.length === 0); } else if (node.type === "ArrayExpression") { return (node.elements.length === 0); } else { return false; } } function isSimple() { if (this._cacheIsSimple != null) { return this._cacheIsSimple; } else { let result = _isSimple(this); this._cacheIsSimple = result; return result; } } function getNodeProperties() { return getNodes(this); } function getNodeSequenceProperties() { return getNodeSequences(this); } module.exports = function createUtilityMethodsProcessor() { return { onEnter: function onEnter(node) { Object.assign(node, { isSimple: isSimple, getNodeProperties: getNodeProperties, getNodeSequenceProperties: getNodeSequenceProperties }); } }; };