summaryrefslogtreecommitdiff
path: root/node_modules/babel-plugin-minify-dead-code-elimination
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2024-08-30 17:21:18 +0800
committerlittleblack111 <littleblack11111@gmail.com>2024-08-30 17:21:18 +0800
commitefbc2ffe6a1ee5ec38a4396305561d6515d0943e (patch)
tree2b4c94f18f2c792dfda813050755d5c0273fae22 /node_modules/babel-plugin-minify-dead-code-elimination
parent43acceb75957c880a5ba5a31aae221394a36d5f6 (diff)
node fixes, updates
Diffstat (limited to 'node_modules/babel-plugin-minify-dead-code-elimination')
-rw-r--r--node_modules/babel-plugin-minify-dead-code-elimination/LICENSE22
-rw-r--r--node_modules/babel-plugin-minify-dead-code-elimination/README.md74
-rw-r--r--node_modules/babel-plugin-minify-dead-code-elimination/lib/index.js1396
-rw-r--r--node_modules/babel-plugin-minify-dead-code-elimination/lib/remove-use-strict.js48
-rw-r--r--node_modules/babel-plugin-minify-dead-code-elimination/package.json21
5 files changed, 1561 insertions, 0 deletions
diff --git a/node_modules/babel-plugin-minify-dead-code-elimination/LICENSE b/node_modules/babel-plugin-minify-dead-code-elimination/LICENSE
new file mode 100644
index 00000000..f9f0a7f3
--- /dev/null
+++ b/node_modules/babel-plugin-minify-dead-code-elimination/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2015-2016 Amjad Masad <amjad.masad@gmail.com>
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/babel-plugin-minify-dead-code-elimination/README.md b/node_modules/babel-plugin-minify-dead-code-elimination/README.md
new file mode 100644
index 00000000..61a61727
--- /dev/null
+++ b/node_modules/babel-plugin-minify-dead-code-elimination/README.md
@@ -0,0 +1,74 @@
+# babel-plugin-minify-dead-code-elimination
+
+Inlines bindings when possible. Tries to evaluate expressions and prunes unreachable as a result.
+
+## Example
+
+**In**
+
+```javascript
+function foo() {var x = 1;}
+function bar() { var x = f(); }
+function baz() {
+ var x = 1;
+ console.log(x);
+ function unused() {
+ return 5;
+ }
+}
+```
+
+**Out**
+
+```javascript
+function foo() {}
+function bar() { f(); }
+function baz() {
+ console.log(1);
+}
+```
+
+## Installation
+
+```sh
+npm install babel-plugin-minify-dead-code-elimination --save-dev
+```
+
+## Usage
+
+### Via `.babelrc` (Recommended)
+
+**.babelrc**
+
+```json
+// without options
+{
+ "plugins": ["minify-dead-code-elimination"]
+}
+
+// with options
+{
+ "plugins": ["minify-dead-code-elimination", { "optimizeRawSize": true }]
+}
+```
+
+### Via CLI
+
+```sh
+babel --plugins minify-dead-code-elimination script.js
+```
+
+### Via Node API
+
+```javascript
+require("@babel/core").transform("code", {
+ plugins: ["minify-dead-code-elimination"]
+});
+```
+
+## Options
+
++ `keepFnName` - prevent plugin from removing function name. Useful for code depending on `fn.name`
++ `keepFnArgs` - prevent plugin from removing function args. Useful for code depending on `fn.length`
++ `keepClassName` - prevent plugin from removing class name. Useful for code depending on `cls.name`
++ `tdz` - Account for TDZ (Temporal Dead Zone)
diff --git a/node_modules/babel-plugin-minify-dead-code-elimination/lib/index.js b/node_modules/babel-plugin-minify-dead-code-elimination/lib/index.js
new file mode 100644
index 00000000..d49e362c
--- /dev/null
+++ b/node_modules/babel-plugin-minify-dead-code-elimination/lib/index.js
@@ -0,0 +1,1396 @@
+"use strict";
+
+function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
+
+const some = require("lodash/some");
+
+const _require = require("babel-helper-mark-eval-scopes"),
+ markEvalScopes = _require.markEvalScopes,
+ hasEval = _require.hasEval;
+
+const removeUseStrict = require("./remove-use-strict");
+
+const evaluate = require("babel-helper-evaluate-path");
+
+function evaluateTruthy(path) {
+ const res = evaluate(path);
+ if (res.confident) return !!res.value;
+}
+
+function prevSiblings(path) {
+ const parentPath = path.parentPath;
+ const siblings = [];
+ let key = parentPath.key;
+
+ while ((path = parentPath.getSibling(--key)).type) {
+ siblings.push(path);
+ }
+
+ return siblings;
+}
+
+function forEachAncestor(path, callback) {
+ while (path = path.parentPath) {
+ callback(path);
+ }
+}
+
+module.exports = ({
+ types: t,
+ traverse
+}) => {
+ const removeOrVoid = require("babel-helper-remove-or-void")(t);
+
+ const shouldRevisit = Symbol("shouldRevisit"); // this is used for tracking fn params that can be removed
+ // as traversal takes place from left and
+ // unused params can be removed only on the right
+
+ const markForRemoval = Symbol("markForRemoval");
+ const main = {
+ // remove side effectless statement
+ ExpressionStatement(path) {
+ if (path.get("expression").isPure()) {
+ removeOrVoid(path);
+ }
+ },
+
+ Function: {
+ // Let's take all the vars in a function that are not in the top level scope and hoist them
+ // with the first var declaration in the top-level scope. This transform in itself may
+ // not yield much returns (or even can be marginally harmful to size). However it's great
+ // for taking away statements from blocks that can be only expressions which the `simplify`
+ // plugin can turn into other things (e.g. if => conditional).
+ exit(path) {
+ // This hurts gzip size.
+ if (!this.optimizeRawSize) {
+ return;
+ }
+
+ const node = path.node,
+ scope = path.scope;
+ const seen = new Set();
+ const declars = [];
+ const mutations = [];
+
+ for (const name in scope.bindings) {
+ const binding = scope.bindings[name];
+
+ if (!binding.path.isVariableDeclarator()) {
+ continue;
+ }
+
+ const declarPath = binding.path.parentPath;
+
+ if (seen.has(declarPath)) {
+ continue;
+ }
+
+ seen.add(declarPath);
+
+ if (declarPath.parentPath.isForInStatement()) {
+ continue;
+ }
+
+ if (declarPath.parentPath.parentPath.isFunction()) {
+ continue;
+ }
+
+ if (!declarPath.node || !declarPath.node.declarations) {
+ continue;
+ }
+
+ const assignmentSequence = [];
+
+ var _iterator = _createForOfIteratorHelper(declarPath.node.declarations),
+ _step;
+
+ try {
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
+ const declar = _step.value;
+ declars.push(declar);
+
+ if (declar.init) {
+ assignmentSequence.push(t.assignmentExpression("=", declar.id, declar.init));
+ mutations.push(() => {
+ declar.init = null;
+ });
+ }
+ }
+ } catch (err) {
+ _iterator.e(err);
+ } finally {
+ _iterator.f();
+ }
+
+ if (assignmentSequence.length) {
+ mutations.push(() => declarPath.replaceWith(t.sequenceExpression(assignmentSequence)));
+ } else {
+ mutations.push(() => removeOrVoid(declarPath));
+ }
+ }
+
+ if (declars.length) {
+ mutations.forEach(f => f());
+
+ var _iterator2 = _createForOfIteratorHelper(node.body.body),
+ _step2;
+
+ try {
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
+ const statement = _step2.value;
+
+ if (t.isVariableDeclaration(statement)) {
+ statement.declarations.push(...declars);
+ return;
+ }
+ }
+ } catch (err) {
+ _iterator2.e(err);
+ } finally {
+ _iterator2.f();
+ }
+
+ const varDecl = t.variableDeclaration("var", declars);
+ node.body.body.unshift(varDecl);
+ }
+ }
+
+ },
+ // Remove bindings with no references.
+ Scope: {
+ exit(path) {
+ if (path.node[shouldRevisit]) {
+ delete path.node[shouldRevisit];
+ path.visit();
+ }
+ },
+
+ enter(path) {
+ if (path.isProgram()) {
+ return;
+ }
+
+ if (hasEval(path.scope)) {
+ return;
+ }
+
+ const scope = path.scope; // if the scope is created by a function, we obtain its
+ // parameter list
+
+ const canRemoveParams = path.isFunction() && path.node.kind !== "set";
+ const paramsList = canRemoveParams ? path.get("params") : [];
+
+ for (let i = paramsList.length - 1; i >= 0; i--) {
+ const param = paramsList[i];
+
+ if (param.isIdentifier()) {
+ const binding = scope.bindings[param.node.name];
+ if (!binding) continue;
+
+ if (binding.referenced) {
+ // when the first binding is referenced (right to left)
+ // exit without marking anything after this
+ break;
+ }
+
+ binding[markForRemoval] = true;
+ continue;
+ } else if (param.isAssignmentPattern()) {
+ const left = param.get("left");
+ const right = param.get("right");
+
+ if (left.isIdentifier() && right.isPure()) {
+ const binding = scope.bindings[left.node.name];
+
+ if (binding.referenced) {
+ // when the first binding is referenced (right to left)
+ // exit without marking anything after this
+ break;
+ }
+
+ binding[markForRemoval] = true;
+ continue;
+ }
+ } // other patterns - assignment, object have side-effects
+ // and cannot be safely removed
+
+
+ break;
+ }
+
+ for (const name in scope.bindings) {
+ const binding = scope.bindings[name];
+
+ if (!binding.referenced && binding.kind !== "module") {
+ if (binding.kind === "param" && (this.keepFnArgs || !binding[markForRemoval])) {
+ continue;
+ } else if (binding.path.isVariableDeclarator()) {
+ const declaration = binding.path.parentPath;
+ const maybeBlockParent = declaration.parentPath;
+
+ if (maybeBlockParent && maybeBlockParent.isForXStatement({
+ left: declaration.node
+ })) {
+ // Can't remove if in a for-in/for-of/for-await statement `for (var x in wat)`.
+ continue;
+ }
+ } else if (!scope.isPure(binding.path.node)) {
+ // TODO: AssignmentPattern are marked as impure and unused ids aren't removed yet
+ continue;
+ } else if (binding.path.isFunctionExpression() || binding.path.isClassExpression()) {
+ // `bar(function foo() {})` foo is not referenced but it's used.
+ continue;
+ } else if ( // ClassDeclaration has binding in two scopes
+ // 1. The scope in which it is declared
+ // 2. The class's own scope
+ binding.path.isClassDeclaration() && binding.path === scope.path) {
+ continue;
+ }
+
+ const mutations = [];
+ let bail = false; // Make sure none of the assignments value is used
+
+ binding.constantViolations.forEach(p => {
+ if (bail || p === binding.path) {
+ return;
+ }
+
+ if (!p.parentPath.isExpressionStatement()) {
+ bail = true;
+ }
+
+ if (p.isAssignmentExpression()) {
+ if (t.isArrayPattern(p.node.left) || t.isObjectPattern(p.node.left)) {
+ bail = true;
+ } else if (p.get("right").isPure()) {
+ mutations.push(() => removeOrVoid(p));
+ } else {
+ mutations.push(() => p.replaceWith(p.get("right")));
+ }
+ }
+ });
+
+ if (bail) {
+ continue;
+ }
+
+ if (binding.path.isVariableDeclarator()) {
+ if (!binding.path.get("id").isIdentifier()) {
+ // deopt for object and array pattern
+ continue;
+ } // if declarator has some impure init expression
+ // var x = foo();
+ // => foo();
+
+
+ if (binding.path.node.init && !scope.isPure(binding.path.node.init) && binding.path.parentPath.node.declarations) {
+ // binding path has more than one declarations
+ if (binding.path.parentPath.node.declarations.length !== 1) {
+ continue;
+ }
+
+ binding.path.parentPath.replaceWith(binding.path.node.init);
+ } else {
+ updateReferences(binding.path, this);
+ removeOrVoid(binding.path);
+ }
+ } else {
+ updateReferences(binding.path, this);
+ removeOrVoid(binding.path);
+ }
+
+ mutations.forEach(f => f());
+ scope.removeBinding(name);
+ } else if (binding.constant) {
+ if (binding.path.isFunctionDeclaration() || binding.path.isVariableDeclarator() && binding.path.get("init").isFunction()) {
+ const fun = binding.path.isFunctionDeclaration() ? binding.path : binding.path.get("init");
+ let allInside = true;
+
+ var _iterator3 = _createForOfIteratorHelper(binding.referencePaths),
+ _step3;
+
+ try {
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
+ const ref = _step3.value;
+
+ if (!ref.find(p => p.node === fun.node)) {
+ allInside = false;
+ break;
+ }
+ }
+ } catch (err) {
+ _iterator3.e(err);
+ } finally {
+ _iterator3.f();
+ }
+
+ if (allInside) {
+ scope.removeBinding(name);
+ updateReferences(binding.path, this);
+ removeOrVoid(binding.path);
+ continue;
+ }
+ }
+
+ if (binding.references === 1 && binding.kind !== "param" && binding.kind !== "module" && binding.constant) {
+ let replacement = binding.path.node;
+ let replacementPath = binding.path;
+ let isReferencedBefore = false;
+ const refPath = binding.referencePaths[0];
+
+ if (t.isVariableDeclarator(replacement)) {
+ const _prevSiblings = prevSiblings(replacementPath); // traverse ancestors of a reference checking if it's before declaration
+
+
+ forEachAncestor(refPath, ancestor => {
+ if (_prevSiblings.indexOf(ancestor) > -1) {
+ isReferencedBefore = true;
+ }
+ }); // deopt if reference is in different scope than binding
+ // since we don't know if it's sync or async execution
+ // (i.e. whether value has been assigned to a reference or not)
+
+ if (isReferencedBefore && refPath.scope !== binding.scope) {
+ continue;
+ } // simulate hoisting by replacing value
+ // with undefined if declaration is after reference
+
+
+ replacement = isReferencedBefore ? t.unaryExpression("void", t.numericLiteral(0), true) : replacement.init; // Bail out for ArrayPattern and ObjectPattern
+ // TODO: maybe a more intelligent approach instead of simply bailing out
+
+ if (!replacementPath.get("id").isIdentifier()) {
+ continue;
+ }
+
+ replacementPath = replacementPath.get("init");
+ }
+
+ if (!replacement) {
+ continue;
+ }
+
+ if (!scope.isPure(replacement, true) && !isReferencedBefore) {
+ continue;
+ }
+
+ let bail = false;
+
+ if (replacementPath.isIdentifier()) {
+ const binding = scope.getBinding(replacement.name); // the reference should be in the same scope
+ // and the replacement should be a constant - this is to
+ // ensure that the duplication of replacement is not affected
+ // https://github.com/babel/minify/issues/685
+
+ bail = !(binding && refPath.scope.getBinding(replacement.name) === binding && binding.constantViolations.length === 0);
+ } else if (replacementPath.isThisExpression()) {
+ bail = true;
+ } else {
+ replacementPath.traverse({
+ Function(path) {
+ path.skip();
+ },
+
+ ThisExpression(path) {
+ bail = true;
+ path.stop();
+ },
+
+ ReferencedIdentifier({
+ node
+ }) {
+ const binding = scope.getBinding(node.name);
+
+ if (binding && refPath.scope.getBinding(node.name) === binding) {
+ bail = binding.constantViolations.length > 0;
+
+ if (bail) {
+ path.stop();
+ }
+ }
+ }
+
+ });
+ }
+
+ if (bail) {
+ continue;
+ }
+
+ let parent = binding.path.parent;
+
+ if (t.isVariableDeclaration(parent)) {
+ parent = binding.path.parentPath.parent;
+ } // 1. Make sure we share the parent with the node. In other words it's lexically defined
+ // and not in an if statement or otherwise.
+ // 2. If the replacement is an object then we have to make sure we are not in a loop or a function
+ // because otherwise we'll be inlining and doing a lot more allocation than we have to
+ // which would also could affect correctness in that they are not the same reference.
+
+
+ let mayLoop = false;
+ const sharesRoot = refPath.find(({
+ node
+ }) => {
+ if (!mayLoop) {
+ mayLoop = t.isWhileStatement(node) || t.isFor(node) || t.isFunction(node);
+ }
+
+ return node === parent;
+ }); // Anything that inherits from Object.
+
+ const isObj = n => t.isFunction(n) || t.isObjectExpression(n) || t.isArrayExpression(n) || t.isRegExpLiteral(n);
+
+ const isReplacementObj = isObj(replacement) || some(replacement, isObj);
+
+ if (!sharesRoot || isReplacementObj && mayLoop) {
+ continue;
+ } // check if it's safe to replace
+ // To solve https://github.com/babel/minify/issues/691
+ // Here we bail for property checks using the "in" operator
+ // This is because - `in` is a side-effect-free operation but the property
+ // could be deleted between the replacementPath and referencePath
+ // It is expensive to compute the delete operation and we bail for
+ // all the binary "in" operations
+
+
+ let inExpression = replacementPath.isBinaryExpression({
+ operator: "in"
+ });
+
+ if (!inExpression) {
+ replacementPath.traverse({
+ Function(path) {
+ path.skip();
+ },
+
+ BinaryExpression(path) {
+ if (path.node.operator === "in") {
+ inExpression = true;
+ path.stop();
+ }
+ }
+
+ });
+ }
+
+ if (inExpression) {
+ continue;
+ }
+
+ const replaced = replace(binding.referencePaths[0], {
+ binding,
+ scope,
+ replacement,
+ replacementPath
+ });
+
+ if (replaced) {
+ scope.removeBinding(name);
+
+ if (binding.path.node) {
+ removeOrVoid(binding.path);
+ }
+ }
+ }
+ }
+ } // end-for-of
+
+ }
+
+ },
+
+ // Remove unreachable code.
+ BlockStatement(path) {
+ const paths = path.get("body");
+ let purge = false;
+
+ for (let i = 0; i < paths.length; i++) {
+ const p = paths[i];
+
+ if (!purge && p.isCompletionStatement()) {
+ purge = true;
+ continue;
+ }
+
+ if (purge && !canExistAfterCompletion(p)) {
+ removeOrVoid(p);
+ }
+ }
+ },
+
+ // Double check unreachable code and remove return statements that
+ // have no semantic meaning
+ ReturnStatement(path) {
+ const node = path.node;
+
+ if (!path.inList) {
+ return;
+ } // Not last in its block? (See BlockStatement visitor)
+
+
+ if (path.container.length - 1 !== path.key && !canExistAfterCompletion(path.getSibling(path.key + 1)) && path.parentPath.isBlockStatement()) {
+ // This is probably a new oppurtinity by some other transform
+ // let's call the block visitor on this again before proceeding.
+ path.parentPath.pushContext(path.context);
+ path.parentPath.visit();
+ path.parentPath.popContext();
+ return;
+ }
+
+ if (node.argument) {
+ return;
+ }
+
+ let noNext = true;
+ let parentPath = path.parentPath;
+
+ while (parentPath && !parentPath.isFunction() && noNext) {
+ // https://github.com/babel/minify/issues/265
+ if (hasLoopParent(parentPath)) {
+ noNext = false;
+ break;
+ }
+
+ const nextPath = parentPath.getSibling(parentPath.key + 1);
+
+ if (nextPath.node) {
+ if (nextPath.isReturnStatement()) {
+ nextPath.pushContext(path.context);
+ nextPath.visit();
+ nextPath.popContext();
+
+ if (parentPath.getSibling(parentPath.key + 1).node) {
+ noNext = false;
+ break;
+ }
+ } else {
+ noNext = false;
+ break;
+ }
+ }
+
+ parentPath = parentPath.parentPath;
+ }
+
+ if (noNext) {
+ removeOrVoid(path);
+ }
+ },
+
+ ConditionalExpression(path) {
+ const node = path.node;
+ const evaluateTest = evaluateTruthy(path.get("test"));
+
+ if (evaluateTest === true) {
+ path.replaceWith(node.consequent);
+ } else if (evaluateTest === false) {
+ path.replaceWith(node.alternate);
+ }
+ },
+
+ SwitchStatement: {
+ exit(path) {
+ const discriminantPath = path.get("discriminant");
+ const evaluated = evaluate(discriminantPath, {
+ tdz: this.tdz
+ });
+ if (!evaluated.confident) return; // the simplify transformation might have brought in the previous
+ // expressions into the switch's test expression and instead of
+ // bailing out of impure path, we collect the impurities of it's
+ // a sequence expression and bail out if the primary test itself
+ // is impure
+
+ let beforeTest = [];
+
+ if (t.isSequenceExpression(discriminantPath.node)) {
+ const expressions = discriminantPath.get("expressions");
+ const lastExpression = expressions[expressions.length - 1];
+
+ if (!lastExpression.isPure()) {
+ return;
+ }
+
+ beforeTest = [t.expressionStatement(t.sequenceExpression(expressions.slice(0, expressions.length - 1).map(path => path.node)))];
+ } else if (!discriminantPath.isPure()) {
+ return;
+ }
+
+ const discriminant = evaluated.value;
+ const cases = path.get("cases");
+ let matchingCaseIndex = -1;
+ let defaultCaseIndex = -1;
+
+ for (let i = 0; i < cases.length; i++) {
+ const test = cases[i].get("test"); // handle default case
+
+ if (test.node === null) {
+ defaultCaseIndex = i;
+ continue;
+ }
+
+ const testResult = evaluate(test, {
+ tdz: this.tdz
+ }); // if we are not able to deternine a test during
+ // compile time, we terminate immediately
+
+ if (!testResult.confident) return;
+
+ if (testResult.value === discriminant) {
+ matchingCaseIndex = i;
+ break;
+ }
+ }
+
+ let result;
+
+ if (matchingCaseIndex === -1) {
+ if (defaultCaseIndex === -1) {
+ path.skip();
+ path.replaceWithMultiple(extractVars(path));
+ return;
+ } else {
+ result = getStatementsUntilBreak(defaultCaseIndex);
+ }
+ } else {
+ result = getStatementsUntilBreak(matchingCaseIndex);
+ }
+
+ if (result.bail) return; // we extract vars from the entire switch statement
+ // and there will be duplicates which
+ // will be again removed by DCE
+
+ replaceSwitch([...extractVars(path), ...beforeTest, ...result.statements]);
+
+ function getStatementsUntilBreak(start) {
+ const result = {
+ bail: false,
+ statements: []
+ };
+
+ for (let i = start; i < cases.length; i++) {
+ const consequent = cases[i].get("consequent");
+
+ for (let j = 0; j < consequent.length; j++) {
+ const _isBreaking = isBreaking(consequent[j], path);
+
+ if (_isBreaking.bail) {
+ result.bail = true;
+ return result;
+ }
+
+ if (_isBreaking.break) {
+ // compute no more
+ // exit out of the loop
+ return result;
+ } else {
+ result.statements.push(consequent[j].node);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ function replaceSwitch(statements) {
+ let isBlockRequired = false;
+
+ for (let i = 0; i < statements.length; i++) {
+ if (t.isVariableDeclaration(statements[i], {
+ kind: "let"
+ })) {
+ isBlockRequired = true;
+ break;
+ }
+
+ if (t.isVariableDeclaration(statements[i], {
+ kind: "const"
+ })) {
+ isBlockRequired = true;
+ break;
+ }
+ }
+
+ if (isBlockRequired) {
+ path.replaceWith(t.BlockStatement(statements));
+ } else {
+ path.replaceWithMultiple(statements);
+ }
+ }
+ }
+
+ },
+
+ WhileStatement(path) {
+ const test = path.get("test");
+ const result = evaluate(test, {
+ tdz: this.tdz
+ });
+
+ if (result.confident && test.isPure() && !result.value) {
+ path.replaceWithMultiple(extractVars(path.get("body")));
+ }
+ },
+
+ ForStatement(path) {
+ const test = path.get("test");
+ if (!test.isPure()) return;
+ const result = evaluate(test, {
+ tdz: this.tdz
+ });
+
+ if (result.confident) {
+ if (result.value) {
+ test.remove();
+ } else {
+ const init = path.get("init");
+
+ if (init.node && !init.isPure()) {
+ path.replaceWith(init);
+ } else {
+ path.remove();
+ }
+ }
+ }
+ },
+
+ DoWhileStatement(path) {
+ const test = path.get("test");
+ const result = evaluate(test, {
+ tdz: this.tdz
+ });
+
+ if (result.confident && test.isPure() && !result.value) {
+ const body = path.get("body");
+
+ if (body.isBlockStatement()) {
+ const stmts = body.get("body");
+
+ var _iterator4 = _createForOfIteratorHelper(stmts),
+ _step4;
+
+ try {
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
+ const stmt = _step4.value;
+
+ const _isBreaking = isBreaking(stmt, path);
+
+ if (_isBreaking.bail || _isBreaking.break) return;
+
+ const _isContinuing = isContinuing(stmt, path);
+
+ if (_isContinuing.bail || isContinuing.continue) return;
+ }
+ } catch (err) {
+ _iterator4.e(err);
+ } finally {
+ _iterator4.f();
+ }
+
+ path.replaceWith(body.node);
+ } else if (body.isBreakStatement()) {
+ const _isBreaking = isBreaking(body, path);
+
+ if (_isBreaking.bail) return;
+ if (_isBreaking.break) path.remove();
+ } else if (body.isContinueStatement()) {
+ return;
+ } else {
+ path.replaceWith(body.node);
+ }
+ }
+ },
+
+ // Join assignment and definition when in sequence.
+ // var x; x = 1; -> var x = 1;
+ AssignmentExpression(path) {
+ if (!path.get("left").isIdentifier() || !path.parentPath.isExpressionStatement()) {
+ return;
+ }
+
+ const prev = path.parentPath.getSibling(path.parentPath.key - 1);
+
+ if (!(prev && prev.isVariableDeclaration())) {
+ return;
+ }
+
+ const declars = prev.node.declarations;
+
+ if (declars.length !== 1 || declars[0].init || declars[0].id.name !== path.get("left").node.name) {
+ return;
+ }
+
+ declars[0].init = path.node.right;
+ removeOrVoid(path);
+ },
+
+ // Remove named function expression name. While this is dangerous as it changes
+ // `function.name` all minifiers do it and hence became a standard.
+ FunctionExpression(path) {
+ if (!this.keepFnName) {
+ removeUnreferencedId(path);
+ }
+ },
+
+ // remove class names
+ ClassExpression(path) {
+ if (!this.keepClassName) {
+ removeUnreferencedId(path);
+ }
+ },
+
+ // Put the `var` in the left if feasible.
+ ForInStatement(path) {
+ const left = path.get("left");
+
+ if (!left.isIdentifier()) {
+ return;
+ }
+
+ const binding = path.scope.getBinding(left.node.name);
+
+ if (!binding) {
+ return;
+ }
+
+ if (binding.scope.getFunctionParent() !== path.scope.getFunctionParent()) {
+ return;
+ }
+
+ if (!binding.path.isVariableDeclarator()) {
+ return;
+ }
+
+ if (binding.path.parentPath.parentPath.isForInStatement({
+ left: binding.path.parent
+ })) {
+ return;
+ } // If it has company then it's probably more efficient to keep.
+
+
+ if (binding.path.parent.declarations.length > 1) {
+ return;
+ } // meh
+
+
+ if (binding.path.node.init) {
+ return;
+ }
+
+ removeOrVoid(binding.path);
+ path.node.left = t.variableDeclaration("var", [t.variableDeclarator(left.node)]);
+ binding.path = path.get("left").get("declarations")[0];
+ }
+
+ };
+ 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, {
+ opts: {
+ tdz = false
+ } = {}
+ }) {
+ const consequent = path.get("consequent");
+ const alternate = path.get("alternate");
+ const test = path.get("test");
+ const evalResult = evaluate(test, {
+ tdz
+ });
+ const isPure = test.isPure();
+ const replacements = [];
+
+ if (evalResult.confident && !isPure && test.isSequenceExpression()) {
+ replacements.push(t.expressionStatement(extractSequenceImpure(test)));
+ } // we can check if a test will be truthy 100% and if so then we can inline
+ // the consequent and completely ignore the alternate
+ //
+ // if (true) { foo; } -> { foo; }
+ // if ("foo") { foo; } -> { foo; }
+ //
+
+
+ if (evalResult.confident && evalResult.value) {
+ path.replaceWithMultiple([...replacements, ...toStatements(consequent), ...extractVars(alternate)]);
+ return;
+ } // we can check if a test will be falsy 100% and if so we can inline the
+ // alternate if there is one and completely remove the consequent
+ //
+ // if ("") { bar; } else { foo; } -> { foo; }
+ // if ("") { bar; } ->
+ //
+
+
+ if (evalResult.confident && !evalResult.value) {
+ if (alternate.node) {
+ path.replaceWithMultiple([...replacements, ...toStatements(alternate), ...extractVars(consequent)]);
+ return;
+ } else {
+ path.replaceWithMultiple([...replacements, ...extractVars(consequent)]);
+ }
+ } // remove alternate blocks that are empty
+ //
+ // if (foo) { foo; } else {} -> if (foo) { foo; }
+ //
+
+
+ if (alternate.isBlockStatement() && !alternate.node.body.length) {
+ alternate.remove(); // For if-statements babel-traverse replaces with an empty block
+
+ path.node.alternate = null;
+ } // if the consequent block is empty turn alternate blocks into a consequent
+ // and flip the test
+ //
+ // if (foo) {} else { bar; } -> if (!foo) { bar; }
+ //
+
+
+ if (consequent.isBlockStatement() && !consequent.node.body.length && alternate.isBlockStatement() && alternate.node.body.length) {
+ consequent.replaceWith(alternate.node);
+ alternate.remove(); // For if-statements babel-traverse replaces with an empty block
+
+ path.node.alternate = null;
+ test.replaceWith(t.unaryExpression("!", test.node, true));
+ }
+ }
+
+ },
+
+ EmptyStatement(path) {
+ if (path.parentPath.isBlockStatement() || path.parentPath.isProgram()) {
+ path.remove();
+ }
+ },
+
+ Program: {
+ exit(path, {
+ opts: {
+ // set defaults
+ optimizeRawSize = false,
+ keepFnName = false,
+ keepClassName = false,
+ keepFnArgs = false,
+ tdz = false
+ } = {}
+ } = {}) {
+ (traverse.clearCache || traverse.cache.clear)();
+ path.scope.crawl();
+ markEvalScopes(path); // We need to run this plugin in isolation.
+
+ path.traverse(main, {
+ functionToBindings: new Map(),
+ optimizeRawSize,
+ keepFnName,
+ keepClassName,
+ keepFnArgs,
+ tdz
+ });
+ }
+
+ }
+ }
+ };
+
+ function toStatements(path) {
+ const node = path.node;
+
+ if (path.isBlockStatement()) {
+ let hasBlockScoped = false;
+
+ for (let i = 0; i < node.body.length; i++) {
+ const bodyNode = node.body[i];
+
+ if (t.isBlockScoped(bodyNode)) {
+ hasBlockScoped = true;
+ }
+ }
+
+ if (!hasBlockScoped) {
+ return node.body;
+ }
+ }
+
+ return [node];
+ } // Extracts vars from a path
+ // Useful for removing blocks or paths that can contain
+ // variable declarations inside them
+ // Note:
+ // drops are inits
+ // extractVars({ var x = 5, y = x }) => var x, y;
+
+
+ function extractVars(path) {
+ const declarators = [];
+
+ if (path.isVariableDeclaration({
+ kind: "var"
+ })) {
+ var _iterator5 = _createForOfIteratorHelper(path.node.declarations),
+ _step5;
+
+ try {
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
+ const decl = _step5.value;
+ const bindingIds = Object.keys(t.getBindingIdentifiers(decl.id));
+ declarators.push(...bindingIds.map(name => t.variableDeclarator(t.identifier(name))));
+ }
+ } catch (err) {
+ _iterator5.e(err);
+ } finally {
+ _iterator5.f();
+ }
+ } else {
+ path.traverse({
+ VariableDeclaration(varPath) {
+ if (!varPath.isVariableDeclaration({
+ kind: "var"
+ })) return;
+ if (!isSameFunctionScope(varPath, path)) return;
+
+ var _iterator6 = _createForOfIteratorHelper(varPath.node.declarations),
+ _step6;
+
+ try {
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
+ const decl = _step6.value;
+ const bindingIds = Object.keys(t.getBindingIdentifiers(decl.id));
+ declarators.push(...bindingIds.map(name => t.variableDeclarator(t.identifier(name))));
+ }
+ } catch (err) {
+ _iterator6.e(err);
+ } finally {
+ _iterator6.f();
+ }
+ }
+
+ });
+ }
+
+ if (declarators.length <= 0) return [];
+ return [t.variableDeclaration("var", declarators)];
+ }
+
+ function replace(path, options) {
+ const replacement = options.replacement,
+ replacementPath = options.replacementPath,
+ scope = options.scope,
+ binding = options.binding; // Same name, different binding.
+
+ if (scope.getBinding(path.node.name) !== binding) {
+ return;
+ } // We don't want to move code around to different scopes because:
+ // 1. Original bindings that is referenced could be shadowed
+ // 2. Moving defintions to potentially hot code is bad
+
+
+ if (scope !== path.scope) {
+ if (t.isClass(replacement) || t.isFunction(replacement)) {
+ return;
+ }
+
+ let bail = false;
+ traverse(replacement, {
+ Function(path) {
+ if (bail) {
+ return;
+ }
+
+ bail = true;
+ path.stop();
+ }
+
+ }, scope);
+
+ if (bail) {
+ return;
+ }
+ } // Avoid recursion.
+
+
+ if (path.find(({
+ node
+ }) => node === replacement)) {
+ return;
+ } // https://github.com/babel/minify/issues/611
+ // this is valid only for FunctionDeclaration where we convert
+ // function declaration to expression in the next step
+
+
+ if (replacementPath.isFunctionDeclaration()) {
+ const fnName = replacementPath.get("id").node.name;
+
+ for (let name in replacementPath.scope.bindings) {
+ if (name === fnName) {
+ return;
+ }
+ }
+ } // https://github.com/babel/minify/issues/130
+
+
+ if (!t.isExpression(replacement)) {
+ t.toExpression(replacement);
+ } // We don't remove fn name here, we let the FnExpr & ClassExpr visitors
+ // check its references and remove unreferenced ones
+ // if (t.isFunction(replacement)) {
+ // replacement.id = null;
+ // }
+
+
+ path.replaceWith(replacement);
+ return true;
+ }
+
+ function updateReferences(fnToDeletePath) {
+ if (!fnToDeletePath.isFunction()) {
+ return;
+ }
+
+ fnToDeletePath.traverse({
+ ReferencedIdentifier(path) {
+ const node = path.node,
+ scope = path.scope;
+ const binding = scope.getBinding(node.name);
+
+ if (!binding || !binding.path.isFunction() || binding.scope === scope || !binding.constant) {
+ return;
+ }
+
+ const index = binding.referencePaths.indexOf(path);
+
+ if (index === -1) {
+ return;
+ }
+
+ binding.references--;
+ binding.referencePaths.splice(index, 1);
+
+ if (binding.references === 0) {
+ binding.referenced = false;
+ }
+
+ if (binding.references <= 1 && binding.scope.path.node) {
+ binding.scope.path.node[shouldRevisit] = true;
+ }
+ }
+
+ });
+ }
+
+ function removeUnreferencedId(path) {
+ const id = path.get("id").node;
+
+ if (!id) {
+ return;
+ }
+
+ const node = path.node,
+ scope = path.scope;
+ const binding = scope.getBinding(id.name); // Check if shadowed or is not referenced.
+
+ if (binding && (binding.path.node !== node || !binding.referenced)) {
+ node.id = null;
+ }
+ } // path1 -> path2
+ // is path1 an ancestor of path2
+
+
+ function isAncestor(path1, path2) {
+ return !!path2.findParent(parent => parent === path1);
+ }
+
+ function isSameFunctionScope(path1, path2) {
+ return path1.scope.getFunctionParent() === path2.scope.getFunctionParent();
+ }
+
+ function isBreaking(stmt, path) {
+ return isControlTransfer(stmt, path, "break");
+ }
+
+ function isContinuing(stmt, path) {
+ return isControlTransfer(stmt, path, "continue");
+ } // tells if a "stmt" is a break/continue statement
+
+
+ function isControlTransfer(stmt, path, control = "break") {
+ const _break$continue = {
+ break: "BreakStatement",
+ continue: "ContinueStatement"
+ },
+ type = _break$continue[control];
+
+ if (!type) {
+ throw new Error("Can only handle break and continue statements");
+ }
+
+ const checker = `is${type}`;
+
+ if (stmt[checker]()) {
+ return _isControlTransfer(stmt, path);
+ }
+
+ let isTransferred = false;
+ let result = {
+ [control]: false,
+ bail: false
+ };
+ stmt.traverse({
+ [type](cPath) {
+ // if we already detected a break/continue statement,
+ if (isTransferred) return;
+ result = _isControlTransfer(cPath, path);
+
+ if (result.bail || result[control]) {
+ isTransferred = true;
+ }
+ }
+
+ });
+ return result;
+
+ function _isControlTransfer(cPath, path) {
+ const label = cPath.get("label");
+
+ if (label.node !== null) {
+ // labels are fn scoped and not accessible by inner functions
+ // path is the switch statement
+ if (!isSameFunctionScope(path, cPath)) {
+ // we don't have to worry about this break statement
+ return {
+ break: false,
+ bail: false
+ };
+ } // here we handle the break labels
+ // if they are outside switch, we bail out
+ // if they are within the case, we keep them
+
+
+ let labelPath;
+
+ if (path.scope.getLabel) {
+ labelPath = getLabel(label.node.name, path);
+ } else {
+ labelPath = path.scope.getBinding(label.node.name).path;
+ }
+
+ const _isAncestor = isAncestor(labelPath, path);
+
+ return {
+ bail: _isAncestor,
+ [control]: _isAncestor
+ };
+ } // set the flag that it is indeed breaking
+
+
+ let isCTransfer = true; // this flag is to capture
+ // switch(0) { case 0: while(1) if (x) break; }
+
+ let possibleRunTimeControlTransfer = false; // and compute if it's breaking the correct thing
+
+ let parent = cPath.parentPath;
+
+ while (parent !== stmt.parentPath) {
+ // loops and nested switch cases
+ if (parent.isLoop() || parent.isSwitchCase()) {
+ // invalidate all the possible runtime breaks captured
+ // while (1) { if (x) break; }
+ possibleRunTimeControlTransfer = false; // and set that it's not breaking our switch statement
+
+ isCTransfer = false;
+ break;
+ } //
+ // this is a special case and depends on
+ // the fact that SwitchStatement is handled in the
+ // exit hook of the traverse
+ //
+ // switch (0) {
+ // case 0: if (x) break;
+ // }
+ //
+ // here `x` is runtime only.
+ // in this case, we need to bail out. So we depend on exit hook
+ // of switch so that, it would have visited the IfStatement first
+ // before the SwitchStatement and would have removed the
+ // IfStatement if it was a compile time determined
+ //
+
+
+ if (parent.isIfStatement()) {
+ possibleRunTimeControlTransfer = true;
+ }
+
+ parent = parent.parentPath;
+ }
+
+ return {
+ [control]: possibleRunTimeControlTransfer || isCTransfer,
+ bail: possibleRunTimeControlTransfer
+ };
+ }
+ } // things that are hoisted
+
+
+ function canExistAfterCompletion(path) {
+ return path.isFunctionDeclaration() || path.isVariableDeclaration({
+ kind: "var"
+ });
+ }
+
+ function getLabel(name, _path) {
+ let label,
+ path = _path;
+
+ do {
+ label = path.scope.getLabel(name);
+
+ if (label) {
+ return label;
+ }
+ } while (path = path.parentPath);
+
+ return null;
+ }
+
+ function hasLoopParent(path) {
+ let parent = path;
+
+ do {
+ if (parent.isLoop()) {
+ return true;
+ }
+ } while (parent = parent.parentPath);
+
+ return false;
+ }
+
+ function extractSequenceImpure(seq) {
+ const expressions = seq.get("expressions");
+ const result = [];
+
+ for (let i = 0; i < expressions.length; i++) {
+ if (!expressions[i].isPure()) {
+ result.push(expressions[i].node);
+ }
+ }
+
+ return t.sequenceExpression(result);
+ }
+}; \ No newline at end of file
diff --git a/node_modules/babel-plugin-minify-dead-code-elimination/lib/remove-use-strict.js b/node_modules/babel-plugin-minify-dead-code-elimination/lib/remove-use-strict.js
new file mode 100644
index 00000000..eb4cbe3a
--- /dev/null
+++ b/node_modules/babel-plugin-minify-dead-code-elimination/lib/remove-use-strict.js
@@ -0,0 +1,48 @@
+"use strict";
+
+module.exports = removeUseStrict;
+const newIssueUrl = "https://github.com/babel/minify/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) {
+ var dir = block.get("directives");
+ return Array.isArray(dir) ? dir.filter(function (directive) {
+ return directive.node.value.value === useStrict;
+ }) : [];
+} \ No newline at end of file
diff --git a/node_modules/babel-plugin-minify-dead-code-elimination/package.json b/node_modules/babel-plugin-minify-dead-code-elimination/package.json
new file mode 100644
index 00000000..db27e8ea
--- /dev/null
+++ b/node_modules/babel-plugin-minify-dead-code-elimination/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "babel-plugin-minify-dead-code-elimination",
+ "version": "0.5.2",
+ "description": "",
+ "keywords": [
+ "babel-plugin"
+ ],
+ "homepage": "https://github.com/babel/minify#readme",
+ "bugs": "https://github.com/babel/minify/issues",
+ "license": "MIT",
+ "author": "amasad",
+ "main": "lib/index.js",
+ "repository": "https://github.com/babel/minify/tree/master/packages/babel-plugin-minify-dead-code-elimination",
+ "dependencies": {
+ "babel-helper-evaluate-path": "^0.5.0",
+ "babel-helper-mark-eval-scopes": "^0.4.3",
+ "babel-helper-remove-or-void": "^0.4.3",
+ "lodash": "^4.17.11"
+ },
+ "gitHead": "8f9c7c0a32103653bd6793d0ce44730f937e1ddf"
+}