"use strict"; exports.__esModule = true; var _typeof2 = require("babel-runtime/helpers/typeof"); var _typeof3 = _interopRequireDefault(_typeof2); var _getIterator2 = require("babel-runtime/core-js/get-iterator"); var _getIterator3 = _interopRequireDefault(_getIterator2); var _map = require("babel-runtime/core-js/map"); var _map2 = _interopRequireDefault(_map); exports.evaluateTruthy = evaluateTruthy; exports.evaluate = evaluate; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var VALID_CALLEES = ["String", "Number", "Math"]; var INVALID_METHODS = ["random"]; function evaluateTruthy() { var res = this.evaluate(); if (res.confident) return !!res.value; } function evaluate() { var confident = true; var deoptPath = void 0; var seen = new _map2.default(); function deopt(path) { if (!confident) return; deoptPath = path; confident = false; } var value = evaluate(this); if (!confident) value = undefined; return { confident: confident, deopt: deoptPath, value: value }; function evaluate(path) { var node = path.node; if (seen.has(node)) { var existing = seen.get(node); if (existing.resolved) { return existing.value; } else { deopt(path); return; } } else { var item = { resolved: false }; seen.set(node, item); var val = _evaluate(path); if (confident) { item.resolved = true; item.value = val; } return val; } } function _evaluate(path) { if (!confident) return; var node = path.node; if (path.isSequenceExpression()) { var exprs = path.get("expressions"); return evaluate(exprs[exprs.length - 1]); } if (path.isStringLiteral() || path.isNumericLiteral() || path.isBooleanLiteral()) { return node.value; } if (path.isNullLiteral()) { return null; } if (path.isTemplateLiteral()) { var str = ""; var i = 0; var _exprs = path.get("expressions"); for (var _iterator = node.quasis, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3.default)(_iterator);;) { var _ref; if (_isArray) { if (_i >= _iterator.length) break; _ref = _iterator[_i++]; } else { _i = _iterator.next(); if (_i.done) break; _ref = _i.value; } var elem = _ref; if (!confident) break; str += elem.value.cooked; var expr = _exprs[i++]; if (expr) str += String(evaluate(expr)); } if (!confident) return; return str; } if (path.isConditionalExpression()) { var testResult = evaluate(path.get("test")); if (!confident) return; if (testResult) { return evaluate(path.get("consequent")); } else { return evaluate(path.get("alternate")); } } if (path.isExpressionWrapper()) { return evaluate(path.get("expression")); } if (path.isMemberExpression() && !path.parentPath.isCallExpression({ callee: node })) { var property = path.get("property"); var object = path.get("object"); if (object.isLiteral() && property.isIdentifier()) { var _value = object.node.value; var type = typeof _value === "undefined" ? "undefined" : (0, _typeof3.default)(_value); if (type === "number" || type === "string") { return _value[property.node.name]; } } } if (path.isReferencedIdentifier()) { var binding = path.scope.getBinding(node.name); if (binding && binding.constantViolations.length > 0) { return deopt(binding.path); } if (binding && path.node.start < binding.path.node.end) { return deopt(binding.path); } if (binding && binding.hasValue) { return binding.value; } else { if (node.name === "undefined") { return binding ? deopt(binding.path) : undefined; } else if (node.name === "Infinity") { return binding ? deopt(binding.path) : Infinity; } else if (node.name === "NaN") { return binding ? deopt(binding.path) : NaN; } var resolved = path.resolve(); if (resolved === path) { return deopt(path); } else { return evaluate(resolved); } } } if (path.isUnaryExpression({ prefix: true })) { if (node.operator === "void") { return undefined; } var argument = path.get("argument"); if (node.operator === "typeof" && (argument.isFunction() || argument.isClass())) { return "function"; } var arg = evaluate(argument); if (!confident) return; switch (node.operator) { case "!": return !arg; case "+": return +arg; case "-": return -arg; case "~": return ~arg; case "typeof": return typeof arg === "undefined" ? "undefined" : (0, _typeof3.default)(arg); } } if (path.isArrayExpression()) { var arr = []; var elems = path.get("elements"); for (var _iterator2 = elems, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : (0, _getIterator3.default)(_iterator2);;) { var _ref2; if (_isArray2) { if (_i2 >= _iterator2.length) break; _ref2 = _iterator2[_i2++]; } else { _i2 = _iterator2.next(); if (_i2.done) break; _ref2 = _i2.value; } var _elem = _ref2; _elem = _elem.evaluate(); if (_elem.confident) { arr.push(_elem.value); } else { return deopt(_elem); } } return arr; } if (path.isObjectExpression()) { var obj = {}; var props = path.get("properties"); for (var _iterator3 = props, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : (0, _getIterator3.default)(_iterator3);;) { var _ref3; if (_isArray3) { if (_i3 >= _iterator3.length) break; _ref3 = _iterator3[_i3++]; } else { _i3 = _iterator3.next(); if (_i3.done) break; _ref3 = _i3.value; } var prop = _ref3; if (prop.isObjectMethod() || prop.isSpreadProperty()) { return deopt(prop); } var keyPath = prop.get("key"); var key = keyPath; if (prop.node.computed) { key = key.evaluate(); if (!key.confident) { return deopt(keyPath); } key = key.value; } else if (key.isIdentifier()) { key = key.node.name; } else { key = key.node.value; } var valuePath = prop.get("value"); var _value2 = valuePath.evaluate(); if (!_value2.confident) { return deopt(valuePath); } _value2 = _value2.value; obj[key] = _value2; } return obj; } if (path.isLogicalExpression()) { var wasConfident = confident; var left = evaluate(path.get("left")); var leftConfident = confident; confident = wasConfident; var right = evaluate(path.get("right")); var rightConfident = confident; confident = leftConfident && rightConfident; switch (node.operator) { case "||": if (left && leftConfident) { confident = true; return left; } if (!confident) return; return left || right; case "&&": if (!left && leftConfident || !right && rightConfident) { confident = true; } if (!confident) return; return left && right; } } if (path.isBinaryExpression()) { var _left = evaluate(path.get("left")); if (!confident) return; var _right = evaluate(path.get("right")); if (!confident) return; switch (node.operator) { case "-": return _left - _right; case "+": return _left + _right; case "/": return _left / _right; case "*": return _left * _right; case "%": return _left % _right; case "**": return Math.pow(_left, _right); case "<": return _left < _right; case ">": return _left > _right; case "<=": return _left <= _right; case ">=": return _left >= _right; case "==": return _left == _right; case "!=": return _left != _right; case "===": return _left === _right; case "!==": return _left !== _right; case "|": return _left | _right; case "&": return _left & _right; case "^": return _left ^ _right; case "<<": return _left << _right; case ">>": return _left >> _right; case ">>>": return _left >>> _right; } } if (path.isCallExpression()) { var callee = path.get("callee"); var context = void 0; var func = void 0; if (callee.isIdentifier() && !path.scope.getBinding(callee.node.name, true) && VALID_CALLEES.indexOf(callee.node.name) >= 0) { func = global[node.callee.name]; } if (callee.isMemberExpression()) { var _object = callee.get("object"); var _property = callee.get("property"); if (_object.isIdentifier() && _property.isIdentifier() && VALID_CALLEES.indexOf(_object.node.name) >= 0 && INVALID_METHODS.indexOf(_property.node.name) < 0) { context = global[_object.node.name]; func = context[_property.node.name]; } if (_object.isLiteral() && _property.isIdentifier()) { var _type = (0, _typeof3.default)(_object.node.value); if (_type === "string" || _type === "number") { context = _object.node.value; func = context[_property.node.name]; } } } if (func) { var args = path.get("arguments").map(evaluate); if (!confident) return; return func.apply(context, args); } } deopt(path); } }