diff --git a/packages/babel-traverse/src/path/evaluation.js b/packages/babel-traverse/src/path/evaluation.js index 90029cbe1e3c..a970bd9aee73 100644 --- a/packages/babel-traverse/src/path/evaluation.js +++ b/packages/babel-traverse/src/path/evaluation.js @@ -257,7 +257,7 @@ function _evaluate(path, state) { } if (path.isLogicalExpression()) { - // If we are confident that one side of an && is false, or the left + // If we are confident that the left side of an && is false, or the left // side of an || is true, we can be confident about the entire expression const wasConfident = state.confident; const left = evaluateCached(path.get("left"), state); @@ -265,25 +265,17 @@ function _evaluate(path, state) { state.confident = wasConfident; const right = evaluateCached(path.get("right"), state); const rightConfident = state.confident; - state.confident = leftConfident && rightConfident; switch (node.operator) { case "||": // TODO consider having a "truthy type" that doesn't bail on // left uncertainty but can still evaluate to truthy. - if (left && leftConfident) { - state.confident = true; - return left; - } - + state.confident = leftConfident && (!!left || rightConfident); if (!state.confident) return; return left || right; case "&&": - if ((!left && leftConfident) || (!right && rightConfident)) { - state.confident = true; - } - + state.confident = leftConfident && (!left || rightConfident); if (!state.confident) return; return left && right; diff --git a/packages/babel-traverse/test/evaluation.js b/packages/babel-traverse/test/evaluation.js index 5c1b51beb02e..a9502b1c8025 100644 --- a/packages/babel-traverse/test/evaluation.js +++ b/packages/babel-traverse/test/evaluation.js @@ -40,6 +40,29 @@ describe("evaluation", function() { ).toBe(false); }); + it("should short-circuit && and ||", function() { + expect( + getPath("x === 'y' || 42") + .get("body")[0] + .evaluate().confident, + ).toBe(false); + expect( + getPath("x === 'y' && 0") + .get("body")[0] + .evaluate().confident, + ).toBe(false); + expect( + getPath("42 || x === 'y'") + .get("body")[0] + .evaluate().value, + ).toBe(42); + expect( + getPath("0 && x === 'y'") + .get("body")[0] + .evaluate().value, + ).toBe(0); + }); + it("should work with repeated, indeterminate identifiers", function() { expect( getPath("var num = foo(); (num > 0 && num < 100);")