summaryrefslogtreecommitdiff
path: root/node_modules/babel-plugin-minify-simplify/lib
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2024-08-30 17:21:18 +0800
committerlittleblack111 <littleblack11111@gmail.com>2024-08-30 17:21:18 +0800
commitefbc2ffe6a1ee5ec38a4396305561d6515d0943e (patch)
tree2b4c94f18f2c792dfda813050755d5c0273fae22 /node_modules/babel-plugin-minify-simplify/lib
parent43acceb75957c880a5ba5a31aae221394a36d5f6 (diff)
node fixes, updates
Diffstat (limited to 'node_modules/babel-plugin-minify-simplify/lib')
-rw-r--r--node_modules/babel-plugin-minify-simplify/lib/assignment-expression.js96
-rw-r--r--node_modules/babel-plugin-minify-simplify/lib/conditional-expression.js39
-rw-r--r--node_modules/babel-plugin-minify-simplify/lib/helpers.js56
-rw-r--r--node_modules/babel-plugin-minify-simplify/lib/if-statement.js273
-rw-r--r--node_modules/babel-plugin-minify-simplify/lib/index.js1179
-rw-r--r--node_modules/babel-plugin-minify-simplify/lib/logical-expression.js75
-rw-r--r--node_modules/babel-plugin-minify-simplify/lib/pattern-match.js156
7 files changed, 1874 insertions, 0 deletions
diff --git a/node_modules/babel-plugin-minify-simplify/lib/assignment-expression.js b/node_modules/babel-plugin-minify-simplify/lib/assignment-expression.js
new file mode 100644
index 00000000..3f9b0ce4
--- /dev/null
+++ b/node_modules/babel-plugin-minify-simplify/lib/assignment-expression.js
@@ -0,0 +1,96 @@
+"use strict";
+
+const operators = new Set(["+", "-", "*", "%", "<<", ">>", ">>>", "&", "|", "^", "/", "**"]);
+const updateOperators = new Set(["+", "-"]);
+
+module.exports = t => {
+ function simplify(path) {
+ const rightExpr = path.get("right");
+ const leftExpr = path.get("left");
+
+ if (path.node.operator !== "=") {
+ return;
+ }
+
+ const canBeUpdateExpression = rightExpr.get("right").isNumericLiteral() && rightExpr.get("right").node.value === 1 && updateOperators.has(rightExpr.node.operator);
+
+ if (leftExpr.isMemberExpression()) {
+ const leftPropNames = getPropNames(leftExpr);
+ const rightPropNames = getPropNames(rightExpr.get("left"));
+
+ if (!leftPropNames || leftPropNames.indexOf(undefined) > -1 || !rightPropNames || rightPropNames.indexOf(undefined) > -1 || !operators.has(rightExpr.node.operator) || !areArraysEqual(leftPropNames, rightPropNames)) {
+ return;
+ }
+ } else {
+ if (!rightExpr.isBinaryExpression() || !operators.has(rightExpr.node.operator) || leftExpr.node.name !== rightExpr.node.left.name) {
+ return;
+ }
+ }
+
+ let newExpression; // special case x=x+1 --> ++x
+
+ if (canBeUpdateExpression) {
+ newExpression = t.updateExpression(rightExpr.node.operator + rightExpr.node.operator, t.clone(leftExpr.node), true
+ /* prefix */
+ );
+ } else {
+ newExpression = t.assignmentExpression(rightExpr.node.operator + "=", t.clone(leftExpr.node), t.clone(rightExpr.node.right));
+ }
+
+ path.replaceWith(newExpression);
+ }
+
+ return {
+ simplify
+ };
+};
+
+function areArraysEqual(arr1, arr2) {
+ return arr1.every((value, index) => {
+ return String(value) === String(arr2[index]);
+ });
+}
+
+function getPropNames(path) {
+ if (!path.isMemberExpression()) {
+ return;
+ }
+
+ let obj = path.get("object");
+ const prop = path.get("property");
+ const propNames = [getName(prop.node)];
+
+ while (obj.type === "MemberExpression") {
+ const node = obj.get("property").node;
+
+ if (node) {
+ propNames.push(getName(node));
+ }
+
+ obj = obj.get("object");
+ }
+
+ propNames.push(getName(obj.node));
+ return propNames;
+}
+
+function getName(node) {
+ if (node.type === "ThisExpression") {
+ return "this";
+ }
+
+ if (node.type === "Super") {
+ return "super";
+ }
+
+ if (node.type === "NullLiteral") {
+ return "null";
+ } // augment identifiers so that they don't match
+ // string/number literals
+ // but still match against each other
+
+
+ return node.name ? node.name + "_" : node.value
+ /* Literal */
+ ;
+} \ No newline at end of file
diff --git a/node_modules/babel-plugin-minify-simplify/lib/conditional-expression.js b/node_modules/babel-plugin-minify-simplify/lib/conditional-expression.js
new file mode 100644
index 00000000..9640e8c8
--- /dev/null
+++ b/node_modules/babel-plugin-minify-simplify/lib/conditional-expression.js
@@ -0,0 +1,39 @@
+"use strict";
+
+const h = require("./helpers");
+
+const PatternMatch = require("./pattern-match");
+
+module.exports = t => {
+ // small abstractions
+ const not = node => t.unaryExpression("!", node);
+
+ const notnot = node => not(not(node));
+
+ const or = (a, b) => t.logicalExpression("||", a, b);
+
+ const and = (a, b) => t.logicalExpression("&&", a, b);
+
+ function simplifyPatterns(path) {
+ const test = path.get("test");
+ const consequent = path.get("consequent");
+ const alternate = path.get("alternate");
+
+ const _h$typeSymbols = h.typeSymbols(t),
+ EX = _h$typeSymbols.Expression; // Convention:
+ // ===============
+ // for each pattern [test, consequent, alternate, handler(expr, cons, alt)]
+
+
+ const matcher = new PatternMatch([[EX, true, false, e => notnot(e)], [EX, false, true, e => not(e)], [EX, true, EX, (e, c, a) => or(notnot(e), a)], [EX, false, EX, (e, c, a) => and(not(e), a)], [EX, EX, true, (e, c) => or(not(e), c)], [EX, EX, false, (e, c) => and(notnot(e), c)]]);
+ const result = matcher.match([test, consequent, alternate], h.isPatternMatchesPath(t));
+
+ if (result.match) {
+ path.replaceWith(result.value(test.node, consequent.node, alternate.node));
+ }
+ }
+
+ return {
+ simplifyPatterns
+ };
+}; \ No newline at end of file
diff --git a/node_modules/babel-plugin-minify-simplify/lib/helpers.js b/node_modules/babel-plugin-minify-simplify/lib/helpers.js
new file mode 100644
index 00000000..dfbe7c2a
--- /dev/null
+++ b/node_modules/babel-plugin-minify-simplify/lib/helpers.js
@@ -0,0 +1,56 @@
+"use strict";
+
+const VOID_0 = t => t.unaryExpression("void", t.numericLiteral(0), true);
+
+const evaluate = require("babel-helper-evaluate-path"); // Types as Symbols - for comparing types
+
+
+const types = {}; // This is a test key which is used to avoid Object.keys check
+// Object.keys() check is really expensive
+// https://gist.github.com/vigneshshanmugam/c766550ecd02292dcdfbf0bf013b9d3d
+
+const testKey = "Expression";
+
+const typeSymbols = t => {
+ // don't recompute
+ if (types[testKey] !== undefined) {
+ return types;
+ }
+
+ t.TYPES.forEach(type => {
+ types[type] = Symbol.for(type);
+ });
+ return types;
+};
+
+const isNodeOfType = (t, node, typeSymbol) => typeof typeSymbol !== "symbol" ? false : t["is" + Symbol.keyFor(typeSymbol)](node);
+
+const isPatternMatchesPath = t => function _isPatternMatchesPath(patternValue, inputPath) {
+ if (Array.isArray(patternValue)) {
+ for (let i = 0; i < patternValue.length; i++) {
+ if (_isPatternMatchesPath(patternValue[i], inputPath)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ if (typeof patternValue === "function") {
+ return patternValue(inputPath);
+ }
+
+ if (isNodeOfType(t, inputPath.node, patternValue)) return true;
+ const evalResult = evaluate(inputPath);
+ if (!evalResult.confident || !inputPath.isPure()) return false;
+ return evalResult.value === patternValue;
+};
+
+module.exports = {
+ VOID_0,
+ // Types as Symbols
+ typeSymbols,
+ // This is required for resolving type aliases
+ isNodeOfType,
+ isPatternMatchesPath
+}; \ No newline at end of file
diff --git a/node_modules/babel-plugin-minify-simplify/lib/if-statement.js b/node_modules/babel-plugin-minify-simplify/lib/if-statement.js
new file mode 100644
index 00000000..f6ad4de2
--- /dev/null
+++ b/node_modules/babel-plugin-minify-simplify/lib/if-statement.js
@@ -0,0 +1,273 @@
+"use strict";
+
+const REPLACED = Symbol("replaced");
+
+const h = require("./helpers");
+
+module.exports = t => {
+ function mergeNestedIfs(path) {
+ const consequent = path.get("consequent");
+ const alternate = path.get("alternate"); // not nested if
+
+ if (!consequent.isIfStatement()) return; // there are no alternate nodes in both the if statements (nested)
+
+ if (alternate.node || consequent.get("alternate").node) return;
+ const test = path.get("test");
+ test.replaceWith(t.logicalExpression("&&", test.node, consequent.get("test").node));
+ consequent.replaceWith(t.clone(consequent.get("consequent").node));
+ } // No alternate, make into a guarded expression
+
+
+ function toGuardedExpression(path) {
+ const node = path.node;
+
+ if (node.consequent && !node.alternate && node.consequent.type === "ExpressionStatement") {
+ let op = "&&";
+
+ if (t.isUnaryExpression(node.test, {
+ operator: "!"
+ })) {
+ node.test = node.test.argument;
+ op = "||";
+ }
+
+ path.replaceWith(t.expressionStatement(t.logicalExpression(op, node.test, node.consequent.expression)));
+ return REPLACED;
+ }
+ } // both consequent and alternate are expressions, turn into ternary
+
+
+ function toTernary(path) {
+ const node = path.node;
+
+ if (t.isExpressionStatement(node.consequent) && t.isExpressionStatement(node.alternate)) {
+ path.replaceWith(t.conditionalExpression(node.test, node.consequent.expression, node.alternate.expression));
+ return REPLACED;
+ }
+ } // consequent and alternate are return -- conditional.
+
+
+ function toConditional(path) {
+ const node = path.node;
+
+ if (t.isReturnStatement(node.consequent) && t.isReturnStatement(node.alternate)) {
+ if (!node.consequent.argument && !node.alternate.argument) {
+ path.replaceWith(t.expressionStatement(node.test));
+ return REPLACED;
+ }
+
+ path.replaceWith(t.returnStatement(t.conditionalExpression(node.test, node.consequent.argument || h.VOID_0(t), node.alternate.argument || h.VOID_0(t))));
+ return REPLACED;
+ }
+ } // There is nothing after this If block. And one or both
+ // of the consequent and alternate are either expression statment
+ // or return statements.
+
+
+ function toReturn(path) {
+ const node = path.node;
+
+ if (!path.getSibling(path.key + 1).node && path.parentPath && path.parentPath.parentPath && path.parentPath.parentPath.isFunction()) {
+ // Only the consequent is a return, void the alternate.
+ if (t.isReturnStatement(node.consequent) && t.isExpressionStatement(node.alternate)) {
+ if (!node.consequent.argument) {
+ path.replaceWith(t.expressionStatement(t.logicalExpression("||", node.test, node.alternate.expression)));
+ return REPLACED;
+ }
+
+ path.replaceWith(t.returnStatement(t.conditionalExpression(node.test, node.consequent.argument || h.VOID_0(t), t.unaryExpression("void", node.alternate.expression, true))));
+ return REPLACED;
+ } // Only the alternate is a return, void the consequent.
+
+
+ if (t.isReturnStatement(node.alternate) && t.isExpressionStatement(node.consequent)) {
+ if (!node.alternate.argument) {
+ path.replaceWith(t.expressionStatement(t.logicalExpression("&&", node.test, node.consequent.expression)));
+ return REPLACED;
+ }
+
+ path.replaceWith(t.returnStatement(t.conditionalExpression(node.test, t.unaryExpression("void", node.consequent.expression, true), node.alternate.argument || h.VOID_0(t))));
+ return REPLACED;
+ }
+
+ if (t.isReturnStatement(node.consequent) && !node.alternate) {
+ if (!node.consequent.argument) {
+ path.replaceWith(t.expressionStatement(node.test));
+ return REPLACED;
+ } // This would only be worth it if the previous statement was an if
+ // because then we may merge to create a conditional.
+
+
+ if (path.getSibling(path.key - 1).isIfStatement()) {
+ path.replaceWith(t.returnStatement(t.conditionalExpression(node.test, node.consequent.argument || h.VOID_0(t), h.VOID_0(t))));
+ return REPLACED;
+ }
+ }
+
+ if (t.isReturnStatement(node.alternate) && !node.consequent) {
+ if (!node.alternate.argument) {
+ path.replaceWith(t.expressionStatement(node.test));
+ return REPLACED;
+ } // Same as above.
+
+
+ if (path.getSibling(path.key - 1).isIfStatement()) {
+ path.replaceWith(t.returnStatement(t.conditionalExpression(node.test, node.alternate.argument || h.VOID_0(t), h.VOID_0(t))));
+ return REPLACED;
+ }
+ }
+ }
+
+ let next = path.getSibling(path.key + 1); // If the next satatement(s) is an if statement and we can simplify that
+ // to potentailly be an expression (or a return) then this will make it
+ // easier merge.
+
+ if (next.isIfStatement()) {
+ next.pushContext(path.context);
+ next.visit();
+ next.popContext();
+ next = path.getSibling(path.key + 1);
+ } // Some other visitor might have deleted our node. OUR NODE ;_;
+
+
+ if (!path.node) {
+ return;
+ } // No alternate but the next statement is a return
+ // also turn into a return conditional
+
+
+ if (t.isReturnStatement(node.consequent) && !node.alternate && next.isReturnStatement()) {
+ const nextArg = next.node.argument || h.VOID_0(t);
+ next.remove();
+ path.replaceWith(t.returnStatement(t.conditionalExpression(node.test, node.consequent.argument || h.VOID_0(t), nextArg)));
+ return REPLACED;
+ } // Next is the last expression, turn into a return while void'ing the exprs
+
+
+ if (path.parentPath && path.parentPath.parentPath && path.parentPath.parentPath.isFunction() && !path.getSibling(path.key + 2).node && t.isReturnStatement(node.consequent) && !node.alternate && next.isExpressionStatement()) {
+ const nextExpr = next.node.expression;
+ next.remove();
+
+ if (node.consequent.argument) {
+ path.replaceWith(t.returnStatement(t.conditionalExpression(node.test, node.consequent.argument, t.unaryExpression("void", nextExpr, true))));
+ return REPLACED;
+ }
+
+ path.replaceWith(t.logicalExpression("||", node.test, nextExpr));
+ return REPLACED;
+ }
+ } // Remove else for if-return
+
+
+ function removeUnnecessaryElse(path) {
+ const node = path.node;
+ const consequent = path.get("consequent");
+ const alternate = path.get("alternate");
+
+ if (consequent.node && alternate.node && (consequent.isReturnStatement() || consequent.isBlockStatement() && t.isReturnStatement(consequent.node.body[consequent.node.body.length - 1])) && ( // don't hoist declarations
+ // TODO: validate declarations after fixing scope issues
+ alternate.isBlockStatement() ? !alternate.get("body").some(stmt => stmt.isVariableDeclaration({
+ kind: "let"
+ }) || stmt.isVariableDeclaration({
+ kind: "const"
+ })) : true)) {
+ path.insertAfter(alternate.isBlockStatement() ? alternate.node.body.map(el => t.clone(el)) : t.clone(alternate.node));
+ node.alternate = null;
+ return REPLACED;
+ }
+ }
+
+ function runTransforms(path) {
+ // ordered
+ const transforms = [toGuardedExpression, toTernary, toConditional, toReturn, removeUnnecessaryElse]; // run each of the replacement till we replace something
+ // which is identified by the Symbol(REPLACED) that each of the
+ // functions return when they replace something
+
+ for (var _i = 0; _i < transforms.length; _i++) {
+ const transform = transforms[_i];
+
+ if (transform(path) === REPLACED) {
+ break;
+ }
+ }
+ } // If the consequent is if and the altenrate is not then
+ // switch them out. That way we know we don't have to print
+ // a block.x
+
+
+ function switchConsequent(path) {
+ const node = path.node;
+
+ if (!node.alternate) {
+ return;
+ }
+
+ if (!t.isIfStatement(node.consequent)) {
+ return;
+ }
+
+ if (t.isIfStatement(node.alternate)) {
+ return;
+ }
+
+ node.test = t.unaryExpression("!", node.test, true);
+ var _ref = [node.consequent, node.alternate];
+ node.alternate = _ref[0];
+ node.consequent = _ref[1];
+ } // Make if statements with conditional returns in the body into
+ // an if statement that guards the rest of the block.
+
+
+ function conditionalReturnToGuards(path) {
+ const node = path.node;
+
+ if (!path.inList || !path.get("consequent").isBlockStatement() || node.alternate) {
+ return;
+ }
+
+ let ret;
+ let test;
+ const exprs = [];
+ const statements = node.consequent.body;
+
+ for (let i = 0, statement; statement = statements[i]; i++) {
+ if (t.isExpressionStatement(statement)) {
+ exprs.push(statement.expression);
+ } else if (t.isIfStatement(statement)) {
+ if (i < statements.length - 1) {
+ // This isn't the last statement. Bail.
+ return;
+ }
+
+ if (statement.alternate) {
+ return;
+ }
+
+ if (!t.isReturnStatement(statement.consequent)) {
+ return;
+ }
+
+ ret = statement.consequent;
+ test = statement.test;
+ } else {
+ return;
+ }
+ }
+
+ if (!test || !ret) {
+ return;
+ }
+
+ exprs.push(test);
+ const expr = exprs.length === 1 ? exprs[0] : t.sequenceExpression(exprs);
+ const replacement = t.logicalExpression("&&", node.test, expr);
+ path.replaceWith(t.ifStatement(replacement, ret, null));
+ }
+
+ return {
+ mergeNestedIfs,
+ simplify: runTransforms,
+ switchConsequent,
+ conditionalReturnToGuards
+ };
+}; \ No newline at end of file
diff --git a/node_modules/babel-plugin-minify-simplify/lib/index.js b/node_modules/babel-plugin-minify-simplify/lib/index.js
new file mode 100644
index 00000000..98b6190d
--- /dev/null
+++ b/node_modules/babel-plugin-minify-simplify/lib/index.js
@@ -0,0 +1,1179 @@
+"use strict";
+
+function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
+
+function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
+
+function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
+
+function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
+
+module.exports = ({
+ types: t
+}) => {
+ const flipExpressions = require("babel-helper-flip-expressions")(t);
+
+ const toMultipleSequenceExpressions = require("babel-helper-to-multiple-sequence-expressions")(t);
+
+ const ifStatement = require("./if-statement")(t);
+
+ const conditionalExpression = require("./conditional-expression")(t);
+
+ const logicalExpression = require("./logical-expression")(t);
+
+ const assignmentExpression = require("./assignment-expression")(t);
+
+ const VOID_0 = t.unaryExpression("void", t.numericLiteral(0), true);
+ const condExprSeen = Symbol("condExprSeen");
+ const seqExprSeen = Symbol("seqExprSeen");
+ const shouldRevisit = Symbol("shouldRevisit");
+ return {
+ name: "minify-simplify",
+ visitor: {
+ Statement: {
+ exit(path) {
+ if (path.node[shouldRevisit]) {
+ delete path.node[shouldRevisit];
+ path.visit();
+ }
+ }
+
+ },
+ // CallExpression(path) {
+ // const { node } = path;
+
+ /* (function() {})() -> !function() {}()
+ There is a bug in babel in printing this. Disabling for now.
+ if (t.isFunctionExpression(node.callee) &&
+ (t.isExpressionStatement(parent) ||
+ (t.isSequenceExpression(parent) && parent.expressions[0] === node))
+ ) {
+ path.replaceWith(
+ t.callExpression(
+ t.unaryExpression("!", node.callee, true),
+ node.arguments
+ )
+ );
+ return;
+ }*/
+ // },
+ UnaryExpression: {
+ enter: [// Demorgans.
+ function (path) {
+ const node = path.node;
+
+ if (node.operator !== "!" || flipExpressions.hasSeen(node)) {
+ return;
+ }
+
+ const expr = node.argument; // We need to make sure that the return type will always be boolean.
+
+ if (!(t.isLogicalExpression(expr) || t.isConditionalExpression(expr) || t.isBinaryExpression(expr))) {
+ return;
+ }
+
+ if (t.isBinaryExpression(expr) && t.COMPARISON_BINARY_OPERATORS.indexOf(expr.operator) === -1) {
+ return;
+ }
+
+ if (flipExpressions.shouldFlip(expr, 1)) {
+ const newNode = flipExpressions.flip(expr);
+ path.replaceWith(newNode);
+ }
+ }, // !(a, b, c) -> a, b, !c
+ function (path) {
+ const node = path.node;
+
+ if (node.operator !== "!") {
+ return;
+ }
+
+ if (!t.isSequenceExpression(node.argument)) {
+ return;
+ }
+
+ const seq = node.argument.expressions;
+ const expr = seq[seq.length - 1];
+ seq[seq.length - 1] = t.unaryExpression("!", expr, true);
+ path.replaceWith(node.argument);
+ }, // !(a ? b : c) -> a ? !b : !c
+ function (path) {
+ const node = path.node;
+
+ if (node.operator !== "!") {
+ return;
+ }
+
+ if (!t.isConditional(node.argument)) {
+ return;
+ }
+
+ const cond = node.argument;
+ cond.alternate = t.unaryExpression("!", cond.alternate, true);
+ cond.consequent = t.unaryExpression("!", cond.consequent, true);
+ path.replaceWith(node.argument);
+ }]
+ },
+
+ BinaryExpression(path) {
+ if (["!=", "=="].indexOf(path.node.operator) !== -1) {
+ undefinedToNull(path.get("left"));
+ undefinedToNull(path.get("right"));
+ }
+ },
+
+ LogicalExpression: {
+ exit: logicalExpression.simplifyPatterns
+ },
+ AssignmentExpression: assignmentExpression.simplify,
+ ConditionalExpression: {
+ enter: [// !foo ? 'foo' : 'bar' -> foo ? 'bar' : 'foo'
+ // foo !== 'lol' ? 'foo' : 'bar' -> foo === 'lol' ? 'bar' : 'foo'
+ function flipIfOrConditional(path) {
+ const node = path.node;
+
+ if (!path.get("test").isLogicalExpression()) {
+ flipNegation(node);
+ return;
+ }
+
+ if (flipExpressions.shouldFlip(node.test)) {
+ node.test = flipExpressions.flip(node.test);
+ var _ref = [node.consequent, node.alternate];
+ node.alternate = _ref[0];
+ node.consequent = _ref[1];
+ }
+ }, conditionalExpression.simplifyPatterns],
+ exit: [// a ? x = foo : b ? x = bar : x = baz;
+ // x = a ? foo : b ? bar : baz;
+ function (topPath) {
+ if (!topPath.parentPath.isExpressionStatement() && !topPath.parentPath.isSequenceExpression()) {
+ return;
+ }
+
+ const mutations = [];
+ let firstLeft = null;
+ let operator = null;
+
+ function visit(path) {
+ if (path.isConditionalExpression()) {
+ let bail = visit(path.get("consequent"));
+
+ if (bail) {
+ return true;
+ }
+
+ bail = visit(path.get("alternate"));
+ return bail;
+ }
+
+ if (operator == null) {
+ operator = path.node.operator;
+ } else if (path.node.operator !== operator) {
+ return true;
+ }
+
+ if (!path.isAssignmentExpression() || !(path.get("left").isIdentifier() || path.get("left").isMemberExpression())) {
+ return true;
+ }
+
+ const left = path.get("left").node;
+
+ if (firstLeft == null) {
+ firstLeft = left;
+ } else if (!t.isNodesEquivalent(left, firstLeft)) {
+ return true;
+ }
+
+ mutations.push(() => path.replaceWith(path.get("right").node));
+ }
+
+ const bail = visit(topPath);
+
+ if (bail) {
+ return;
+ }
+
+ mutations.forEach(f => f());
+ topPath.replaceWith(t.assignmentExpression(operator, firstLeft, topPath.node));
+ }, // bar ? void 0 : void 0
+ // (bar, void 0)
+ // TODO: turn this into general equiv check
+ function (path) {
+ const node = path.node;
+
+ if (isVoid0(node.consequent) && isVoid0(node.alternate)) {
+ path.replaceWith(t.sequenceExpression([path.node.test, VOID_0]));
+ }
+ }, // bar ? void 0 : foo ? void 0 : <etc>
+ // bar || foo : void 0
+ // TODO: turn this into general equiv check
+ function (path) {
+ const node = path.node;
+
+ if (node[condExprSeen] || !isVoid0(node.consequent)) {
+ return;
+ }
+
+ node[condExprSeen] = true;
+ const tests = [node.test];
+ const mutations = [];
+ let alt;
+
+ for (let next = path.get("alternate"); next.isConditionalExpression(); next = next.get("alternate")) {
+ next.node[condExprSeen] = true;
+ alt = next.node.alternate;
+
+ if (isVoid0(next.node.consequent)) {
+ tests.push(next.node.test);
+ mutations.push(() => next.remove());
+ } else {
+ alt = next.node;
+ break;
+ }
+ }
+
+ if (tests.length === 1) {
+ return;
+ }
+
+ const test = tests.reduce((expr, curTest) => t.logicalExpression("||", expr, curTest));
+ path.replaceWith(t.conditionalExpression(test, VOID_0, alt));
+ }]
+ },
+ // concat
+ VariableDeclaration: {
+ enter: [// Put vars with no init at the top.
+ function (path) {
+ const node = path.node;
+
+ if (node.declarations.length < 2) {
+ return;
+ }
+
+ const inits = [];
+ const empty = [];
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = node.declarations[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ const decl = _step.value;
+
+ if (!decl.init) {
+ empty.push(decl);
+ } else {
+ inits.push(decl);
+ }
+ } // This is based on exprimintation but there is a significant
+ // imrpovement when we place empty vars at the top in smaller
+ // files. Whereas it hurts in larger files.
+
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ if (this.fitsInSlidingWindow) {
+ node.declarations = empty.concat(inits);
+ } else {
+ node.declarations = inits.concat(empty);
+ }
+ }]
+ },
+ Function: {
+ exit(path) {
+ earlyReturnTransform(path);
+
+ if (!path.node[shouldRevisit]) {
+ return;
+ }
+
+ delete path.node[shouldRevisit];
+ path.visit();
+ }
+
+ },
+ For: {
+ enter: earlyContinueTransform,
+ exit: earlyContinueTransform
+ },
+ ForStatement: {
+ // Merge previous expressions in the init part of the for.
+ enter(path) {
+ const node = path.node;
+
+ if (!path.inList || node.init && !t.isExpression(node.init)) {
+ return;
+ }
+
+ const prev = path.getSibling(path.key - 1);
+ let consumed = false;
+
+ if (prev.isVariableDeclaration()) {
+ let referencedOutsideLoop = false; // we don't care if vars are referenced outside the loop as they are fn scope
+
+ if (prev.node.kind === "let" || prev.node.kind === "const") {
+ const ids = Object.keys(prev.getBindingIdentifiers());
+
+ idloop: for (let i = 0; i < ids.length; i++) {
+ const binding = prev.scope.bindings[ids[i]]; // TODO
+ // Temporary Fix
+ // if there is no binding, we assume it is referenced outside
+ // and deopt to avoid bugs
+
+ if (!binding) {
+ referencedOutsideLoop = true;
+ break idloop;
+ }
+
+ const refs = binding.referencePaths;
+
+ for (let j = 0; j < refs.length; j++) {
+ if (!isAncestor(path, refs[j])) {
+ referencedOutsideLoop = true;
+ break idloop;
+ }
+ }
+ }
+ }
+
+ if (!node.init && !referencedOutsideLoop) {
+ node.init = prev.node;
+ consumed = true;
+ }
+ } else if (prev.isExpressionStatement()) {
+ const expr = prev.node.expression;
+
+ if (node.init) {
+ if (t.isSequenceExpression(expr)) {
+ expr.expressions.push(node.init);
+ node.init = expr;
+ } else {
+ node.init = t.sequenceExpression([expr, node.init]);
+ }
+ } else {
+ node.init = expr;
+ }
+
+ consumed = true;
+ }
+
+ if (consumed) {
+ prev.remove();
+ }
+ },
+
+ exit(path) {
+ const node = path.node;
+
+ if (!node.test) {
+ return;
+ }
+
+ if (!path.get("body").isBlockStatement()) {
+ const bodyNode = path.get("body").node;
+
+ if (!t.isIfStatement(bodyNode)) {
+ return;
+ }
+
+ if (t.isBreakStatement(bodyNode.consequent, {
+ label: null
+ })) {
+ node.test = t.logicalExpression("&&", node.test, t.unaryExpression("!", bodyNode.test, true));
+ node.body = bodyNode.alternate || t.emptyStatement();
+ return;
+ }
+
+ if (t.isBreakStatement(bodyNode.alternate, {
+ label: null
+ })) {
+ node.test = t.logicalExpression("&&", node.test, bodyNode.test);
+ node.body = bodyNode.consequent || t.emptyStatement();
+ return;
+ }
+
+ return;
+ }
+
+ const statements = node.body.body;
+ const exprs = [];
+ let ifStatement = null;
+ let breakAt = null;
+ let i = 0;
+
+ for (let statement; statement = statements[i]; i++) {
+ if (t.isIfStatement(statement)) {
+ if (t.isBreakStatement(statement.consequent, {
+ label: null
+ })) {
+ ifStatement = statement;
+ breakAt = "consequent";
+ } else if (t.isBreakStatement(statement.alternate, {
+ label: null
+ })) {
+ ifStatement = statement;
+ breakAt = "alternate";
+ }
+
+ break;
+ } // A statement appears before the break statement then bail.
+
+
+ if (!t.isExpressionStatement(statement)) {
+ return;
+ }
+
+ exprs.push(statement.expression);
+ }
+
+ if (!ifStatement) {
+ return;
+ }
+
+ const rest = [];
+
+ if (breakAt === "consequent") {
+ if (t.isBlockStatement(ifStatement.alternate)) {
+ rest.push(...ifStatement.alternate.body);
+ } else if (ifStatement.alternate) {
+ rest.push(ifStatement.alternate);
+ }
+ } else {
+ if (t.isBlockStatement(ifStatement.consequent)) {
+ rest.push(...ifStatement.consequent.body);
+ } else if (ifStatement.consequent) {
+ rest.push(ifStatement.consequent);
+ }
+ }
+
+ rest.push(...statements.slice(i + 1));
+ const test = breakAt === "consequent" ? t.unaryExpression("!", ifStatement.test, true) : ifStatement.test;
+ let expr;
+
+ if (exprs.length === 1) {
+ expr = t.sequenceExpression([exprs[0], test]);
+ } else if (exprs.length) {
+ exprs.push(test);
+ expr = t.sequenceExpression(exprs);
+ } else {
+ expr = test;
+ }
+
+ node.test = t.logicalExpression("&&", node.test, expr);
+
+ if (rest.length === 1) {
+ node.body = rest[0];
+ } else if (rest.length) {
+ node.body = t.blockStatement(rest);
+ } else {
+ node.body = t.emptyStatement();
+ }
+ }
+
+ },
+
+ Program(path) {
+ // An approximation of the resultant gzipped code after minification
+ this.fitsInSlidingWindow = path.getSource().length / 10 < 33000;
+ const node = path.node;
+ const statements = toMultipleSequenceExpressions(node.body);
+
+ if (!statements.length) {
+ return;
+ }
+
+ node.body = statements;
+ },
+
+ BlockStatement: {
+ enter(path) {
+ const node = path.node,
+ parent = path.parent;
+ const top = [];
+ const bottom = [];
+
+ for (let i = 0; i < node.body.length; i++) {
+ const bodyNode = node.body[i];
+
+ if (t.isFunctionDeclaration(bodyNode)) {
+ top.push(bodyNode);
+ } else {
+ bottom.push(bodyNode);
+ }
+ }
+
+ const statements = top.concat(toMultipleSequenceExpressions(bottom));
+
+ if (!statements.length) {
+ return;
+ }
+
+ if (statements.length > 1 || needsBlock(node, parent) || node.directives) {
+ node.body = statements;
+ return;
+ }
+
+ if (statements.length) {
+ path.replaceWith(statements[0]);
+ return;
+ }
+ },
+
+ exit(path) {
+ const node = path.node,
+ parent = path.parent;
+
+ if (t.isArrowFunctionExpression(parent) && node.body.length === 1 && t.isReturnStatement(node.body[0]) && node.body[0].argument !== null) {
+ path.replaceWith(node.body[0].argument);
+ return;
+ }
+
+ if (needsBlock(node, parent)) {
+ return;
+ }
+
+ if (node.body.length === 1) {
+ path.get("body")[0].inList = false;
+ path.replaceWith(node.body[0]);
+ return;
+ }
+
+ if (node.body.length === 0) {
+ path.replaceWith(t.emptyStatement());
+ return;
+ } // Check if oppurtinties to merge statements are available.
+
+
+ const statements = node.body;
+
+ if (!statements.length) {
+ return;
+ }
+
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = statements[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ const statement = _step2.value;
+
+ if (!t.isExpressionStatement(statement)) {
+ return;
+ }
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ path.visit();
+ }
+
+ },
+ ThrowStatement: createPrevExpressionEater("throw"),
+ // Try to merge previous statements into a sequence
+ ReturnStatement: {
+ enter: [createPrevExpressionEater("return"), // Remove return if last statement with no argument.
+ // Replace return with `void` argument with argument.
+ function (path) {
+ const node = path.node;
+
+ if (!path.parentPath.parentPath.isFunction() || path.getSibling(path.key + 1).node) {
+ return;
+ }
+
+ if (!node.argument) {
+ path.remove();
+ return;
+ }
+
+ if (t.isUnaryExpression(node.argument, {
+ operator: "void"
+ })) {
+ path.replaceWith(node.argument.argument);
+ }
+ }]
+ },
+ // turn blocked ifs into single statements
+ IfStatement: {
+ exit: [ifStatement.mergeNestedIfs, ifStatement.simplify, ifStatement.switchConsequent, ifStatement.conditionalReturnToGuards, createPrevExpressionEater("if")]
+ },
+
+ WhileStatement(path) {
+ const node = path.node;
+ path.replaceWith(t.forStatement(null, node.test, null, node.body));
+ },
+
+ ForInStatement: createPrevExpressionEater("for-in"),
+ // Flatten sequence expressions.
+ SequenceExpression: {
+ exit(path) {
+ if (path.node[seqExprSeen]) {
+ return;
+ }
+
+ function flatten(node) {
+ node[seqExprSeen] = true;
+ const ret = [];
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = node.expressions[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ const n = _step3.value;
+
+ if (t.isSequenceExpression(n)) {
+ ret.push(...flatten(n));
+ } else {
+ ret.push(n);
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ path.node.expressions = flatten(path.node);
+ }
+
+ },
+
+ SwitchCase(path) {
+ const node = path.node;
+
+ if (!node.consequent.length) {
+ return;
+ }
+
+ node.consequent = toMultipleSequenceExpressions(node.consequent);
+ },
+
+ SwitchStatement: {
+ exit: [// Convert switch statements with all returns in their cases
+ // to return conditional.
+ function (path) {
+ const node = path.node; // Need to be careful of side-effects.
+
+ if (!t.isIdentifier(node.discriminant)) {
+ return;
+ }
+
+ if (!node.cases.length) {
+ return;
+ }
+
+ const consTestPairs = [];
+ let fallThru = [];
+ let defaultRet;
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = node.cases[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ const switchCase = _step4.value;
+
+ if (switchCase.consequent.length > 1) {
+ return;
+ }
+
+ const cons = switchCase.consequent[0]; // default case
+
+ if (!switchCase.test) {
+ if (!t.isReturnStatement(cons)) {
+ return;
+ }
+
+ defaultRet = cons;
+ continue;
+ }
+
+ if (!switchCase.consequent.length) {
+ fallThru.push(switchCase.test);
+ continue;
+ } // TODO: can we void it?
+
+
+ if (!t.isReturnStatement(cons)) {
+ return;
+ }
+
+ let test = t.binaryExpression("===", node.discriminant, switchCase.test);
+
+ if (fallThru.length && !defaultRet) {
+ test = fallThru.reduceRight((right, test) => t.logicalExpression("||", t.binaryExpression("===", node.discriminant, test), right), test);
+ }
+
+ fallThru = [];
+ consTestPairs.push([test, cons.argument || VOID_0]);
+ } // Bail if we have any remaining fallthrough
+
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
+ _iterator4.return();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ if (fallThru.length) {
+ return;
+ } // We need the default to be there to make sure there is an oppurtinity
+ // not to return.
+
+
+ if (!defaultRet) {
+ if (path.inList) {
+ const nextPath = path.getSibling(path.key + 1);
+
+ if (nextPath.isReturnStatement()) {
+ defaultRet = nextPath.node;
+ nextPath.remove();
+ } else if (!nextPath.node && path.parentPath.parentPath.isFunction()) {
+ // If this is the last statement in a function we just fake a void return.
+ defaultRet = t.returnStatement(VOID_0);
+ } else {
+ return;
+ }
+ } else {
+ return;
+ }
+ }
+
+ const cond = consTestPairs.reduceRight((alt, [test, cons]) => t.conditionalExpression(test, cons, alt), defaultRet.argument || VOID_0);
+ path.replaceWith(t.returnStatement(cond)); // Maybe now we can merge with some previous switch statement.
+
+ if (path.inList) {
+ const prev = path.getSibling(path.key - 1);
+
+ if (prev.isSwitchStatement()) {
+ prev.visit();
+ }
+ }
+ }, // Convert switches into conditionals.
+ function (path) {
+ const node = path.node; // Need to be careful of side-effects.
+
+ if (!t.isIdentifier(node.discriminant)) {
+ return;
+ }
+
+ if (!node.cases.length) {
+ return;
+ }
+
+ const exprTestPairs = [];
+ let fallThru = [];
+ let defaultExpr;
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = node.cases[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ const switchCase = _step5.value;
+
+ if (!switchCase.test) {
+ if (switchCase.consequent.length !== 1) {
+ return;
+ }
+
+ if (!t.isExpressionStatement(switchCase.consequent[0])) {
+ return;
+ }
+
+ defaultExpr = switchCase.consequent[0].expression;
+ continue;
+ }
+
+ if (!switchCase.consequent.length) {
+ fallThru.push(switchCase.test);
+ continue;
+ }
+
+ const _switchCase$consequen = _slicedToArray(switchCase.consequent, 2),
+ cons = _switchCase$consequen[0],
+ breakStatement = _switchCase$consequen[1];
+
+ if (switchCase === node.cases[node.cases.length - 1]) {
+ if (breakStatement && !t.isBreakStatement(breakStatement)) {
+ return;
+ }
+ } else if (!t.isBreakStatement(breakStatement)) {
+ return;
+ }
+
+ if (!t.isExpressionStatement(cons) || switchCase.consequent.length > 2) {
+ return;
+ }
+
+ let test = t.binaryExpression("===", node.discriminant, switchCase.test);
+
+ if (fallThru.length && !defaultExpr) {
+ test = fallThru.reduceRight((right, test) => t.logicalExpression("||", t.binaryExpression("===", node.discriminant, test), right), test);
+ }
+
+ fallThru = [];
+ exprTestPairs.push([test, cons.expression]);
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5.return != null) {
+ _iterator5.return();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ if (fallThru.length) {
+ return;
+ }
+
+ const cond = exprTestPairs.reduceRight((alt, [test, cons]) => t.conditionalExpression(test, cons, alt), defaultExpr || VOID_0);
+ path.replaceWith(cond);
+ }, function (path) {
+ const node = path.node;
+
+ if (!node.cases.length) {
+ return;
+ }
+
+ const lastCase = path.get("cases")[node.cases.length - 1];
+
+ if (!lastCase.node.consequent.length) {
+ return;
+ }
+
+ const potentialBreak = lastCase.get("consequent")[lastCase.node.consequent.length - 1];
+
+ if (t.isBreakStatement(potentialBreak) && potentialBreak.node.label === null) {
+ potentialBreak.remove();
+ }
+ }, createPrevExpressionEater("switch")]
+ }
+ }
+ };
+
+ function flipNegation(node) {
+ if (!node.consequent || !node.alternate) {
+ return;
+ }
+
+ const test = node.test;
+ let flip = false;
+
+ if (t.isBinaryExpression(test)) {
+ if (test.operator === "!==") {
+ test.operator = "===";
+ flip = true;
+ }
+
+ if (test.operator === "!=") {
+ test.operator = "==";
+ flip = true;
+ }
+ }
+
+ if (t.isUnaryExpression(test, {
+ operator: "!"
+ })) {
+ node.test = test.argument;
+ flip = true;
+ }
+
+ if (flip) {
+ const consequent = node.consequent;
+ node.consequent = node.alternate;
+ node.alternate = consequent;
+ }
+ }
+
+ function needsBlock(node, parent) {
+ return t.isFunction(parent) && node === parent.body || t.isTryStatement(parent) || t.isCatchClause(parent) || t.isSwitchStatement(parent) || isSingleBlockScopeDeclaration(node) && (t.isIfStatement(parent) || t.isLoop(parent));
+ }
+
+ function isSingleBlockScopeDeclaration(block) {
+ return t.isBlockStatement(block) && block.body.length === 1 && (t.isVariableDeclaration(block.body[0], {
+ kind: "let"
+ }) || t.isVariableDeclaration(block.body[0], {
+ kind: "const"
+ }) || t.isFunctionDeclaration(block.body[0]));
+ }
+
+ function isVoid0(expr) {
+ return expr === VOID_0 || t.isUnaryExpression(expr, {
+ operator: "void"
+ }) && t.isNumericLiteral(expr.argument, {
+ value: 0
+ });
+ }
+
+ function earlyReturnTransform(path) {
+ const block = path.get("body");
+
+ if (!block.isBlockStatement()) {
+ return;
+ }
+
+ const body = block.get("body");
+
+ for (let i = body.length - 1; i >= 0; i--) {
+ const statement = body[i];
+
+ if (t.isIfStatement(statement.node) && !statement.node.alternate && t.isReturnStatement(statement.node.consequent) && !statement.node.consequent.argument) {
+ genericEarlyExitTransform(statement);
+ }
+ }
+ }
+
+ function earlyContinueTransform(path) {
+ const block = path.get("body");
+
+ if (!block.isBlockStatement()) {
+ return;
+ }
+
+ let body = block.get("body");
+
+ for (let i = body.length - 1; i >= 0; i--) {
+ const statement = body[i];
+
+ if (t.isIfStatement(statement.node) && !statement.node.alternate && t.isContinueStatement(statement.node.consequent) && !statement.node.consequent.label) {
+ genericEarlyExitTransform(statement);
+ }
+ } // because we might have folded or removed statements
+
+
+ body = block.get("body"); // We may have reduced the body to a single statement.
+
+ if (body.length === 1 && !needsBlock(block.node, path.node)) {
+ block.replaceWith(body[0].node);
+ }
+ }
+
+ function genericEarlyExitTransform(path) {
+ const node = path.node;
+ const statements = path.parentPath.get(path.listKey).slice(path.key + 1).filter(stmt => !stmt.isFunctionDeclaration()); // deopt for any block scoped bindings
+ // issue#399
+
+ const deopt = !statements.every(stmt => {
+ if (!(stmt.isVariableDeclaration({
+ kind: "let"
+ }) || stmt.isVariableDeclaration({
+ kind: "const"
+ }))) {
+ return true;
+ }
+
+ const ids = Object.keys(stmt.getBindingIdentifiers());
+
+ for (var _i2 = 0; _i2 < ids.length; _i2++) {
+ const id = ids[_i2];
+ const binding = path.scope.getBinding(id); // TODO
+ // Temporary Fix
+ // if there is no binding, we assume it is referenced outside
+ // and deopt to avoid bugs
+
+ if (!binding) {
+ return false;
+ }
+
+ const refs = [...binding.referencePaths, ...binding.constantViolations];
+
+ for (var _i3 = 0; _i3 < refs.length; _i3++) {
+ const ref = refs[_i3];
+ if (!ref.isIdentifier()) return false;
+ const fnParent = ref.getFunctionParent(); // TODO
+ // Usage of scopes and bindings in simplify plugin results in
+ // undefined bindings because scope changes are not updated in the
+ // scope tree. So, we deopt whenever we encounter one such issue
+ // and not perform the transformation
+
+ if (!fnParent) {
+ return false;
+ }
+
+ if (fnParent.scope !== path.scope) return false;
+ }
+ }
+
+ return true;
+ });
+
+ if (deopt) {
+ path.visit();
+ return false;
+ }
+
+ if (!statements.length) {
+ path.replaceWith(t.expressionStatement(node.test));
+ return;
+ }
+
+ const test = node.test;
+
+ if (t.isBinaryExpression(test) && test.operator === "!==") {
+ test.operator = "===";
+ } else if (t.isBinaryExpression(test) && test.operator === "!=") {
+ test.operator = "==";
+ } else if (t.isUnaryExpression(test, {
+ operator: "!"
+ })) {
+ node.test = test.argument;
+ } else {
+ node.test = t.unaryExpression("!", node.test, true);
+ }
+
+ path.get("consequent").replaceWith(t.blockStatement(statements.map(stmt => t.clone(stmt.node))));
+ let l = statements.length;
+
+ while (l-- > 0) {
+ if (!statements[l].isFunctionDeclaration()) {
+ path.getSibling(path.key + 1).remove();
+ }
+ } // this should take care of removing the block
+
+
+ path.visit();
+ }
+
+ function createPrevExpressionEater(keyword) {
+ let key;
+
+ switch (keyword) {
+ case "switch":
+ key = "discriminant";
+ break;
+
+ case "throw":
+ case "return":
+ key = "argument";
+ break;
+
+ case "if":
+ key = "test";
+ break;
+
+ case "for-in":
+ key = "right";
+ break;
+ }
+
+ return function (path) {
+ if (!path.inList) {
+ return;
+ }
+
+ const node = path.node;
+ const prev = path.getSibling(path.key - 1);
+
+ if (!prev.isExpressionStatement()) {
+ return;
+ }
+
+ let seq = prev.node.expression;
+
+ if (node[key]) {
+ if (t.isSequenceExpression(seq)) {
+ seq.expressions.push(node[key]);
+ } else {
+ seq = t.sequenceExpression([seq, node[key]]);
+ }
+ } else {
+ if (t.isSequenceExpression(seq)) {
+ const lastExpr = seq.expressions[seq.expressions.length - 1];
+ seq.expressions[seq.expressions.length - 1] = t.unaryExpression("void", lastExpr, true);
+ } else {
+ seq = t.unaryExpression("void", seq, true);
+ }
+ }
+
+ if (seq) {
+ node[key] = seq;
+ prev.remove(); // Since we were able to merge some stuff it's possible that this has opened
+ // oppurtinties for other transforms to happen.
+ // TODO: Look into changing the traversal order from bottom to up to avoid
+ // having to revisit things.
+
+ if (path.parentPath.parent) {
+ path.parentPath.parent[shouldRevisit] = true;
+ }
+ }
+ };
+ } // path1 -> path2
+ // is path1 an ancestor of path2
+
+
+ function isAncestor(path1, path2) {
+ return !!path2.findParent(parent => parent === path1);
+ }
+
+ function isPureVoid(path) {
+ return path.isUnaryExpression({
+ operator: "void"
+ }) && path.isPure();
+ }
+
+ function isGlobalUndefined(path) {
+ return path.isIdentifier({
+ name: "undefined"
+ }) && !path.scope.getBinding("undefined");
+ }
+
+ function undefinedToNull(path) {
+ if (isGlobalUndefined(path) || isPureVoid(path)) {
+ path.replaceWith(t.nullLiteral());
+ }
+ }
+}; \ No newline at end of file
diff --git a/node_modules/babel-plugin-minify-simplify/lib/logical-expression.js b/node_modules/babel-plugin-minify-simplify/lib/logical-expression.js
new file mode 100644
index 00000000..a91af230
--- /dev/null
+++ b/node_modules/babel-plugin-minify-simplify/lib/logical-expression.js
@@ -0,0 +1,75 @@
+"use strict";
+
+const h = require("./helpers");
+
+const PatternMatch = require("./pattern-match");
+
+const evaluate = require("babel-helper-evaluate-path");
+
+module.exports = t => {
+ const OP_AND = input => input === "&&";
+
+ const OP_OR = input => input === "||";
+
+ function simplifyPatterns(path) {
+ // cache of evaluate(path)
+ const evaluateMemo = new Map();
+
+ const TRUTHY = input => {
+ // !NaN and !undefined are truthy
+ // separate check here as they are considered impure by babel
+ if (input.isUnaryExpression() && input.get("argument").isIdentifier()) {
+ if (input.node.argument.name === "NaN" || input.node.argument.name === "undefined") {
+ return true;
+ }
+ }
+
+ const evalResult = evaluate(input);
+ evaluateMemo.set(input, evalResult);
+ return evalResult.confident && input.isPure() && evalResult.value;
+ };
+
+ const FALSY = input => {
+ // NaN and undefined are falsy
+ // separate check here as they are considered impure by babel
+ if (input.isIdentifier()) {
+ if (input.node.name === "NaN" || input.node.name === "undefined") {
+ return true;
+ }
+ }
+
+ const evalResult = evaluate(input);
+ evaluateMemo.set(input, evalResult);
+ return evalResult.confident && input.isPure() && !evalResult.value;
+ };
+
+ const _h$typeSymbols = h.typeSymbols(t),
+ EX = _h$typeSymbols.Expression; // Convention:
+ // [left, operator, right, handler(leftNode, rightNode)]
+
+
+ const matcher = new PatternMatch([[TRUTHY, OP_AND, EX, (l, r) => r], [FALSY, OP_AND, EX, l => l], [TRUTHY, OP_OR, EX, l => l], [FALSY, OP_OR, EX, (l, r) => r]]);
+ const left = path.get("left");
+ const right = path.get("right");
+ const operator = path.node.operator;
+ const result = matcher.match([left, operator, right], h.isPatternMatchesPath(t));
+
+ if (result.match) {
+ // here we are sure that left.evaluate is always confident becuase
+ // it satisfied one of TRUTHY/FALSY paths
+ let value;
+
+ if (evaluateMemo.has(left)) {
+ value = evaluateMemo.get(left).value;
+ } else {
+ value = evaluate(left).value;
+ }
+
+ path.replaceWith(result.value(t.valueToNode(value), right.node));
+ }
+ }
+
+ return {
+ simplifyPatterns
+ };
+}; \ No newline at end of file
diff --git a/node_modules/babel-plugin-minify-simplify/lib/pattern-match.js b/node_modules/babel-plugin-minify-simplify/lib/pattern-match.js
new file mode 100644
index 00000000..e5c34f6d
--- /dev/null
+++ b/node_modules/babel-plugin-minify-simplify/lib/pattern-match.js
@@ -0,0 +1,156 @@
+"use strict";
+
+function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest(); }
+
+function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
+
+function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
+
+function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
+
+const LEAF_NODE = Symbol("LEAF_NODE");
+module.exports = class PatternMatch {
+ constructor(patterns) {
+ this.decisionTree = this.makeDecisionTree(patterns);
+ }
+
+ handle(input, isMatch) {
+ const result = this.match(input, isMatch);
+
+ if (!result.match) {
+ throw new Error("No Match Found for " + input.toString());
+ }
+
+ if (typeof result.value !== "function") {
+ throw new Error("Expecting a function. Instead got - " + result.value.toString());
+ }
+
+ result.value.call(null, input, result.keys);
+ }
+
+ match(input, isMatch = (a, b) => a === b) {
+ let current = this.decisionTree;
+ const result = {
+ match: false,
+ value: void 0,
+ keys: []
+ }; // to handle falsy keys
+
+ const NO_MATCH = Symbol("NO_MATCH");
+
+ for (let i = 0; i < input.length; i++) {
+ let matchedKey = NO_MATCH; // because map doesn't support custom key equal function
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = current.keys()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ const key = _step.value;
+
+ if (isMatch(key, input[i])) {
+ matchedKey = key;
+ result.keys.push(matchedKey);
+ break;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ if (matchedKey !== NO_MATCH) {
+ current = current.get(matchedKey);
+
+ if (i === input.length - 1) {
+ if (current.has(LEAF_NODE)) {
+ result.match = true;
+ result.value = current.get(LEAF_NODE);
+ }
+
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ makeDecisionTree(patterns) {
+ // order of keys in a Map is the order of insertion
+ const root = new Map();
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = patterns[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ const pattern = _step2.value;
+ make(root, pattern);
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ return root;
+
+ function make(parent, pattern) {
+ if (pattern.length < 2) {
+ throw new Error("at least 2 elements required in a pattern");
+ }
+
+ if (pattern.length === 2) {
+ if (parent.has(pattern[0])) {
+ const pattern0 = parent.get(pattern[0]);
+
+ if (!pattern0.has(LEAF_NODE)) {
+ pattern0.set(LEAF_NODE, pattern[1]);
+ } // here we don't handle duplicates
+ // this pattern would have already been matched
+
+ } else {
+ parent.set(pattern[0], new Map([[LEAF_NODE, pattern[1]]]));
+ }
+
+ return parent;
+ }
+
+ const _pattern = _toArray(pattern),
+ current = _pattern[0],
+ rest = _pattern.slice(1);
+
+ if (parent.has(current)) {
+ make(parent.get(current), rest);
+ } else {
+ parent.set(current, make(new Map(), rest));
+ }
+
+ return parent;
+ }
+ }
+
+}; \ No newline at end of file