diff --git a/packages/babel-plugin-minify-simplify/src/index.js b/packages/babel-plugin-minify-simplify/src/index.js index 50e2afaab..426634f69 100644 --- a/packages/babel-plugin-minify-simplify/src/index.js +++ b/packages/babel-plugin-minify-simplify/src/index.js @@ -490,16 +490,6 @@ module.exports = ({ types: t }) => { return; } node.body = statements; - - // this additional traversal is horrible but it's done to fix - // https://github.com/babel/minify/issues/323 - // in which type annotation somehow gets messed up - // during sequence expression transformation - path.traverse({ - Identifier: function(path) { - path.getTypeAnnotation(); - } - }); }, BlockStatement: { diff --git a/packages/babel-plugin-transform-simplify-comparison-operators/src/index.js b/packages/babel-plugin-transform-simplify-comparison-operators/src/index.js index 5633e5a24..28891b9f1 100644 --- a/packages/babel-plugin-transform-simplify-comparison-operators/src/index.js +++ b/packages/babel-plugin-transform-simplify-comparison-operators/src/index.js @@ -1,6 +1,67 @@ "use strict"; -module.exports = function() { +module.exports = function({ types: t }) { + // custom implementation of getTypeAnnotation that fixes + // the type information that is lost during sequence expression transformation + // https://github.com/babel/minify/issues/323 + function customTypeAnnotation(path) { + if (path.typeAnnotation) { + return path.typeAnnotation; + } + + // We are not handling the case of literals and other base types + // since they are already handled via getTypeAnnotation + const { node } = path; + const binding = path.parentPath.scope.getBinding(node.name); + + const types = []; + if (binding && binding.constantViolations) { + if (binding.identifier.typeAnnotation) { + return binding.identifier.typeAnnotation; + } + if (binding.constantViolations) { + const violations = binding.constantViolations; + for (let violation of violations) { + types.push(violation.getTypeAnnotation()); + } + } + } + + if (types.length > 0) { + return t.createUnionTypeAnnotation(types); + } + return types; + } + + // Based on the type inference in Babel + function baseTypeStrictlyMatches(left, right) { + let leftTypes, rightTypes; + + if (t.isIdentifier(left)) { + leftTypes = customTypeAnnotation(left); + } else if (t.isIdentifier(right)) { + rightTypes = customTypeAnnotation(right); + } + + // Early exit + if (t.isAnyTypeAnnotation(leftTypes) || t.isAnyTypeAnnotation(rightTypes)) { + return false; + } + + leftTypes = [].concat(leftTypes, left.getTypeAnnotation()); + rightTypes = [].concat(rightTypes, right.getTypeAnnotation()); + + leftTypes = t.createUnionTypeAnnotation(leftTypes); + rightTypes = t.createUnionTypeAnnotation(rightTypes); + + if ( + !t.isAnyTypeAnnotation(leftTypes) && + t.isFlowBaseAnnotation(leftTypes) + ) { + return leftTypes.type === rightTypes.type; + } + } + return { name: "transform-simplify-comparison-operators", visitor: { @@ -15,7 +76,8 @@ module.exports = function() { const left = path.get("left"); const right = path.get("right"); - const strictMatch = left.baseTypeStrictlyMatches(right); + + const strictMatch = baseTypeStrictlyMatches(left, right); if (strictMatch) { node.operator = node.operator.slice(0, -1); }