From 85bd8acc42096e3cd4a6aa7cbefc7ada999d8c49 Mon Sep 17 00:00:00 2001 From: Boopathi Rajaa Date: Wed, 24 May 2017 14:55:41 +0200 Subject: [PATCH] Remove redundant use strict (Fix #542) --- .../__tests__/dead-code-elimination-test.js | 24 ++++++++ .../src/index.js | 13 +++++ .../src/remove-use-strict.js | 56 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 packages/babel-plugin-minify-dead-code-elimination/src/remove-use-strict.js 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 f1fc9a3fe..22efc14e6 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/packages/babel-plugin-minify-dead-code-elimination/src/index.js b/packages/babel-plugin-minify-dead-code-elimination/src/index.js index 16dd3b47d..ee3e2f0bb 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 000000000..64fe4a430 --- /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; + }); +}