From 184cede94683aefa5cca33741fb5900ef87bec16 Mon Sep 17 00:00:00 2001 From: Vignesh Shanmugam Date: Tue, 18 Apr 2017 23:59:19 +0200 Subject: [PATCH] avoid transforming side effecty member expression checks[fix #469] --- .../__tests__/guarded-expressions-test.js | 12 ++++++ .../src/index.js | 37 ++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/packages/babel-plugin-minify-guarded-expressions/__tests__/guarded-expressions-test.js b/packages/babel-plugin-minify-guarded-expressions/__tests__/guarded-expressions-test.js index cd6161fd2..e59321a36 100644 --- a/packages/babel-plugin-minify-guarded-expressions/__tests__/guarded-expressions-test.js +++ b/packages/babel-plugin-minify-guarded-expressions/__tests__/guarded-expressions-test.js @@ -178,4 +178,16 @@ describe("guarded-expressions-plugin", () => { ); expect(transform(source)).toBe(source); }); + + it("should not minify side effecty member expression checks", () => { + let source = unpad( + ` + { + var a = {}; + } + var b = a && a[foo]; + ` + ); + expect(transform(source)).toBe(source); + }); }); diff --git a/packages/babel-plugin-minify-guarded-expressions/src/index.js b/packages/babel-plugin-minify-guarded-expressions/src/index.js index 92d1adb60..1e070331b 100644 --- a/packages/babel-plugin-minify-guarded-expressions/src/index.js +++ b/packages/babel-plugin-minify-guarded-expressions/src/index.js @@ -1,8 +1,39 @@ "use strict"; +function getBlockPath(path) { + var parent = path.findParent(function(p) { + return p.isBlockStatement(); + }); + // return program path if null + return parent !== null ? parent : path.getFunctionParent(); +} + module.exports = function({ types: t }) { const flipExpressions = require("babel-helper-flip-expressions")(t); + // identify defined check patterns like a && a.foo + // a && a['foo'] + // should bail in this case if declaration is inside other block + function isDefinedCheck(path, left, right) { + if (t.isIdentifier(left) && t.isMemberExpression(right)) { + const binding = path.scope.getBinding(left.node.name); + // should bail only for var + if (binding === null || binding.kind !== "var") { + return false; + } + const expressionParent = getBlockPath(path); + const bindingParent = getBlockPath(binding.path); + // bail if referenced in the same block + if (expressionParent !== bindingParent) { + return true; + } + + const { object } = right.node; + return left.node.name !== object.name; + } + return false; + } + return { name: "minify-guarded-expressions", visitor: { @@ -32,7 +63,11 @@ module.exports = function({ types: t }) { if (leftTruthy === false) { // Short-circuit path.replaceWith(node.left); - } else if (leftTruthy === true && left.isPure()) { + } else if ( + leftTruthy === true && + left.isPure() && + !isDefinedCheck(path, left, right) + ) { path.replaceWith(node.right); } else if ( right.evaluateTruthy() === false &&