enhance `unsafe` `comparisons` (#3381)
authorAlex Lam S.L <alexlamsl@gmail.com>
Wed, 24 Apr 2019 16:08:08 +0000 (00:08 +0800)
committerGitHub <noreply@github.com>
Wed, 24 Apr 2019 16:08:08 +0000 (00:08 +0800)
lib/compress.js
test/compress/comparisons.js

index 758e459..7108135 100644 (file)
@@ -5495,6 +5495,7 @@ merge(Compressor.prototype, {
         return this;
     });
 
+    var indexFns = makePredicate("indexOf lastIndexOf");
     var commutativeOperators = makePredicate("== === != !== * & | ^");
     function is_object(node) {
         return node instanceof AST_Array
@@ -5913,6 +5914,25 @@ merge(Compressor.prototype, {
                 }
             }
         }
+        if (compressor.option("unsafe")
+            && self.right instanceof AST_Call
+            && self.right.expression instanceof AST_Dot
+            && indexFns[self.right.expression.property]) {
+            if (compressor.option("comparisons") && is_indexOf_match_pattern()) {
+                var node = make_node(AST_UnaryPrefix, self, {
+                    operator: "!",
+                    expression: make_node(AST_UnaryPrefix, self, {
+                        operator: "~",
+                        expression: self.right
+                    })
+                });
+                if (self.operator == "!=" || self.operator == "<=") node = make_node(AST_UnaryPrefix, self, {
+                    operator: "!",
+                    expression: node
+                });
+                return node.optimize(compressor);
+            }
+        }
         // x && (y && z)  ==>  x && y && z
         // x || (y || z)  ==>  x || y || z
         // x + ("y" + z)  ==>  x + "y" + z
@@ -5946,6 +5966,23 @@ merge(Compressor.prototype, {
             if (node.is_truthy()) return true;
             return node.evaluate(compressor);
         }
+
+        function is_indexOf_match_pattern() {
+            switch (self.operator) {
+              case ">":
+              case "<=":
+                // 0 > array.indexOf(string) => !~array.indexOf(string)
+                // 0 <= array.indexOf(string) => !!~array.indexOf(string)
+                return self.left instanceof AST_Number && self.left.getValue() == 0;
+              case "==":
+              case "!=":
+                // -1 == array.indexOf(string) => !~array.indexOf(string)
+                // -1 != array.indexOf(string) => !!~array.indexOf(string)
+                return self.left instanceof AST_Number && self.left.getValue() == -1
+                    || self.left instanceof AST_UnaryPrefix && self.left.operator == "-"
+                        && self.left.expression instanceof AST_Number && self.left.expression.getValue() == 1;
+            }
+        }
     });
 
     function recursive_ref(compressor, def) {
index 4680562..ef0db00 100644 (file)
@@ -365,3 +365,18 @@ is_defined: {
         "WARN: Expression always defined [test/compress/comparisons.js:2,19]",
     ]
 }
+
+unsafe_indexOf: {
+    options = {
+        booleans: true,
+        comparisons: true,
+        unsafe: true,
+    }
+    input: {
+        if (Object.keys({ foo: 42 }).indexOf("foo") >= 0) console.log("PASS");
+    }
+    expect: {
+        if (~Object.keys({ foo: 42 }).indexOf("foo")) console.log("PASS");
+    }
+    expect_stdout: "PASS"
+}