Repository: babel/babili (js)

Issue:
Remove unnecessary "use strict"
If the parent has a "use strict" directive, it's not necessary to have it in the children. 

Pull request description:
Remove redundant use strict (Fix #542)

Patch:
diff --git a/packages/babel-plugin-minify-dead-code-elimination/src/index.js b/packages/babel-plugin-minify-dead-code-elimination/src/index.js
index 16dd3b4..ee3e2f0 100644
--- a/packages/babel-plugin-minify-dead-code-elimination/src/index.js
+++ b/packages/babel-plugin-minify-dead-code-elimination/src/index.js
@@ -2,6 +2,7 @@
 
 const some = require("lodash.some");
 const { markEvalScopes, hasEval } = require("babel-helper-mark-eval-scopes");
+const removeUseStrict = require("./remove-use-strict");
 
 function prevSiblings(path) {
   const parentPath = path.parentPath;
@@ -743,6 +744,18 @@ module.exports = ({ types: t, traverse }) => {
   return {
     name: "minify-dead-code-elimination",
     visitor: {
+      Function: {
+        exit(path) {
+          /**
+           * Use exit handler to traverse in a dfs post-order fashion
+           * to remove use strict
+           */
+          const body = path.get("body");
+          if (body.isBlockStatement()) {
+            removeUseStrict(body);
+          }
+        }
+      },
       IfStatement: {
         exit(path) {
           const consequent = path.get("consequent");
diff --git a/packages/babel-plugin-minify-dead-code-elimination/src/remove-use-strict.js b/packages/babel-plugin-minify-dead-code-elimination/src/remove-use-strict.js
new file mode 100644
index 0000000..64fe4a4
--- /dev/null
+++ b/packages/babel-plugin-minify-dead-code-elimination/src/remove-use-strict.js
@@ -0,0 +1,56 @@
+"use strict";
+
+module.exports = removeUseStrict;
+
+const newIssueUrl = "https://github.com/babel/babili/issues/new";
+
+const useStrict = "use strict";
+
+/**
+ * Remove redundant use strict
+ * If the parent has a "use strict" directive, it is not required in
+ * the children
+ *
+ * @param {NodePath} block BlockStatement
+ */
+function removeUseStrict(block) {
+  if (!block.isBlockStatement()) {
+    throw new Error(
+      `Received ${block.type}. Expected BlockStatement. ` +
+        `Please report at ${newIssueUrl}`
+    );
+  }
+
+  const useStricts = getUseStrictDirectives(block);
+
+  // early exit
+  if (useStricts.length < 1) return;
+
+  // only keep the first use strict
+  if (useStricts.length > 1) {
+    for (let i = 1; i < useStricts.length; i++) {
+      useStricts[i].remove();
+    }
+  }
+
+  // check if parent has an use strict
+  if (hasStrictParent(block)) {
+    useStricts[0].remove();
+  }
+}
+
+function hasStrictParent(path) {
+  return path.findParent(
+    parent => parent.isBlockStatement() && isStrict(parent)
+  );
+}
+
+function isStrict(block) {
+  return getUseStrictDirectives(block).length > 0;
+}
+
+function getUseStrictDirectives(block) {
+  return block.get("directives").filter(directive => {
+    return directive.node.value.value === useStrict;
+  });
+}


Test patch:
diff --git a/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js b/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js
index f1fc9a3..22efc14 100644
--- a/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js
+++ b/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js
@@ -2686,4 +2686,28 @@ describe("dce-plugin", () => {
     `);
     expect(transform(source)).toBe(expected);
   });
+
+  it("should remove unnecessary use strict directives", () => {
+    const source = unpad(`
+      function foo() {
+        "use strict";
+        function bar() {
+          "use strict";
+          bar();
+        }
+        bar.call();
+      }
+    `);
+    const expected = unpad(`
+      function foo() {
+        "use strict";
+
+        function bar() {
+          bar();
+        }
+        bar.call();
+      }
+    `);
+    expect(transform(source)).toBe(expected);
+  });
 });
diff --git a/smoke/smoke-test.js b/smoke/smoke-test.js
index ee58d38..6ec0528 100644
--- a/smoke/smoke-test.js
+++ b/smoke/smoke-test.js
@@ -60,7 +60,8 @@ class SmokeTest {
   }
 
   run() {
-    return this.install()
+    return this.cleanup()
+      .then(() => this.install())
       .then(() => this.build())
       .then(() => this.minifyAll())
       .then(() => this.test())