babel-plugin-minify-simplify
Advanced tools
Comparing version 0.0.4 to 0.0.5
235
lib/index.js
@@ -5,4 +5,2 @@ "use strict"; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
@@ -15,3 +13,2 @@ | ||
var isNodesEquiv = require("babel-helper-is-nodes-equiv")(t); | ||
var flipExpressions = require("babel-helper-flip-expressions")(t); | ||
@@ -31,3 +28,3 @@ var toMultipleSequenceExpressions = require("babel-helper-to-multiple-sequence-expressions")(t); | ||
var isNodeOfType = function isNodeOfType(node, typeSymbol) { | ||
if ((typeof typeSymbol === "undefined" ? "undefined" : _typeof(typeSymbol)) !== "symbol") return false; | ||
if (typeof typeSymbol !== "symbol") return false; | ||
return t["is" + Symbol.keyFor(typeSymbol)](node); | ||
@@ -50,2 +47,56 @@ }; | ||
var operators = new Set(["+", "-", "*", "%", "<<", ">>", ">>>", "&", "|", "^", "/", "**"]); | ||
var updateOperators = new Set(["+", "-"]); | ||
function areArraysEqual(arr1, arr2) { | ||
return arr1.every(function (value, index) { | ||
return String(value) === String(arr2[index]); | ||
}); | ||
} | ||
function getName(node) { | ||
if (node.type === "ThisExpression") { | ||
return "this"; | ||
} | ||
if (node.type === "Super") { | ||
return "super"; | ||
} | ||
if (node.type === "NullLiteral") { | ||
return "null"; | ||
} | ||
// augment identifiers so that they don't match | ||
// string/number literals | ||
// but still match against each other | ||
return node.name ? node.name + "_" : node.value /* Literal */; | ||
} | ||
function getPropNames(path) { | ||
if (!path.isMemberExpression()) { | ||
return; | ||
} | ||
var obj = path.get("object"); | ||
var prop = path.get("property"); | ||
var propNames = [getName(prop.node)]; | ||
while (obj.type === "MemberExpression") { | ||
var node = obj.get("property").node; | ||
if (node) { | ||
propNames.push(getName(node)); | ||
} | ||
obj = obj.get("object"); | ||
} | ||
propNames.push(getName(obj.node)); | ||
return propNames; | ||
} | ||
var OP_AND = function OP_AND(input) { | ||
return input === "&&"; | ||
}; | ||
var OP_OR = function OP_OR(input) { | ||
return input === "||"; | ||
}; | ||
return { | ||
@@ -55,3 +106,3 @@ name: "minify-simplify", | ||
Statement: { | ||
exit: function exit(path) { | ||
exit(path) { | ||
if (path.node[shouldRevisit]) { | ||
@@ -150,2 +201,101 @@ delete path.node[shouldRevisit]; | ||
LogicalExpression: { | ||
exit(path) { | ||
// cache of path.evaluate() | ||
var evaluateMemo = new Map(); | ||
var TRUTHY = function TRUTHY(input) { | ||
// !NaN and !undefined are truthy | ||
// separate check here as they are considered impure by babel | ||
if (input.isUnaryExpression() && input.get("argument").isIdentifier()) { | ||
if (input.node.argument.name === "NaN" || input.node.argument.name === "undefined") { | ||
return true; | ||
} | ||
} | ||
var evalResult = input.evaluate(); | ||
evaluateMemo.set(input, evalResult); | ||
return evalResult.confident && input.isPure() && evalResult.value; | ||
}; | ||
var FALSY = function FALSY(input) { | ||
// NaN and undefined are falsy | ||
// separate check here as they are considered impure by babel | ||
if (input.isIdentifier()) { | ||
if (input.node.name === "NaN" || input.node.name === "undefined") { | ||
return true; | ||
} | ||
} | ||
var evalResult = input.evaluate(); | ||
evaluateMemo.set(input, evalResult); | ||
return evalResult.confident && input.isPure() && !evalResult.value; | ||
}; | ||
var EX = types.Expression; | ||
// Convention: | ||
// [left, operator, right, handler(leftNode, rightNode)] | ||
var matcher = new PatternMatch([[TRUTHY, OP_AND, EX, function (l, r) { | ||
return r; | ||
}], [FALSY, OP_AND, EX, function (l) { | ||
return l; | ||
}], [TRUTHY, OP_OR, EX, function (l) { | ||
return l; | ||
}], [FALSY, OP_OR, EX, function (l, r) { | ||
return r; | ||
}]]); | ||
var left = path.get("left"); | ||
var right = path.get("right"); | ||
var operator = path.node.operator; | ||
var result = matcher.match([left, operator, right], isPatternMatchesPath); | ||
if (result.match) { | ||
// here we are sure that left.evaluate is always confident becuase | ||
// it satisfied one of TRUTHY/FALSY paths | ||
var value = void 0; | ||
if (evaluateMemo.has(left)) { | ||
value = evaluateMemo.get(left).value; | ||
} else { | ||
value = left.evaluate().value; | ||
} | ||
path.replaceWith(result.value(t.valueToNode(value), right.node)); | ||
} | ||
} | ||
}, | ||
AssignmentExpression(path) { | ||
var rightExpr = path.get("right"); | ||
var leftExpr = path.get("left"); | ||
var canBeUpdateExpression = rightExpr.get("right").isNumericLiteral() && rightExpr.get("right").node.value === 1 && updateOperators.has(rightExpr.node.operator); | ||
if (leftExpr.isMemberExpression()) { | ||
var leftPropNames = getPropNames(leftExpr); | ||
var rightPropNames = getPropNames(rightExpr.get("left")); | ||
if (!leftPropNames || leftPropNames.indexOf(undefined) > -1 || !rightPropNames || rightPropNames.indexOf(undefined) > -1 || !operators.has(rightExpr.node.operator) || !areArraysEqual(leftPropNames, rightPropNames)) { | ||
return; | ||
} | ||
} else { | ||
if (!rightExpr.isBinaryExpression() || !operators.has(rightExpr.node.operator) || leftExpr.node.name !== rightExpr.node.left.name) { | ||
return; | ||
} | ||
} | ||
var newExpression = void 0; | ||
// special case x=x+1 --> ++x | ||
if (canBeUpdateExpression) { | ||
newExpression = t.updateExpression(rightExpr.node.operator + rightExpr.node.operator, t.clone(leftExpr.node), true /* prefix */); | ||
} else { | ||
newExpression = t.assignmentExpression(rightExpr.node.operator + "=", t.clone(leftExpr.node), t.clone(rightExpr.node.right)); | ||
} | ||
path.replaceWith(newExpression); | ||
}, | ||
ConditionalExpression: { | ||
@@ -242,3 +392,3 @@ enter: [ | ||
firstLeft = left; | ||
} else if (!isNodesEquiv(left, firstLeft)) { | ||
} else if (!t.isNodesEquivalent(left, firstLeft)) { | ||
return true; | ||
@@ -380,6 +530,3 @@ } | ||
Function: { | ||
enter: earlyReturnTransform, | ||
exit: function exit(path) { | ||
// Useful to do on enter and exit because more oppurtinties can open. | ||
exit(path) { | ||
earlyReturnTransform(path); | ||
@@ -404,3 +551,3 @@ | ||
// Merge previous expressions in the init part of the for. | ||
enter: function enter(path) { | ||
enter(path) { | ||
var node = path.node; | ||
@@ -454,3 +601,4 @@ | ||
}, | ||
exit: function exit(path) { | ||
exit(path) { | ||
var node = path.node; | ||
@@ -552,3 +700,3 @@ | ||
Program: function Program(path) { | ||
Program(path) { | ||
// An approximation of the resultant gzipped code after minification | ||
@@ -566,5 +714,4 @@ this.fitsInSlidingWindow = path.getSource().length / 10 < 33000; | ||
BlockStatement: { | ||
enter: function enter(path) { | ||
enter(path) { | ||
var node = path.node, | ||
@@ -602,3 +749,4 @@ parent = path.parent; | ||
}, | ||
exit: function exit(path) { | ||
exit(path) { | ||
var node = path.node, | ||
@@ -726,2 +874,13 @@ parent = path.parent; | ||
// Easy: consequent and alternate are return -- conditional. | ||
if (t.isReturnStatement(node.consequent) && t.isReturnStatement(node.alternate)) { | ||
if (!node.consequent.argument && !node.alternate.argument) { | ||
path.replaceWith(t.expressionStatement(node.test)); | ||
return; | ||
} | ||
path.replaceWith(t.returnStatement(t.conditionalExpression(node.test, node.consequent.argument || VOID_0, node.alternate.argument || VOID_0))); | ||
return; | ||
} | ||
// There is nothing after this block. And one or both | ||
@@ -731,13 +890,2 @@ // of the consequent and alternate are either expression statment | ||
if (!path.getSibling(path.key + 1).node && path.parentPath && path.parentPath.parentPath && path.parentPath.parentPath.isFunction()) { | ||
// Easy: consequent and alternate are return -- conditional. | ||
if (t.isReturnStatement(node.consequent) && t.isReturnStatement(node.alternate)) { | ||
if (!node.consequent.argument && !node.altenrate.argument) { | ||
path.replaceWith(t.expressionStatement(node.test)); | ||
return; | ||
} | ||
path.replaceWith(t.returnStatement(t.conditionalExpression(node.test, node.consequent.argument || VOID_0, node.alternate.argument || VOID_0))); | ||
return; | ||
} | ||
// Only the consequent is a return, void the alternate. | ||
@@ -914,3 +1062,3 @@ if (t.isReturnStatement(node.consequent) && t.isExpressionStatement(node.alternate)) { | ||
WhileStatement: function WhileStatement(path) { | ||
WhileStatement(path) { | ||
var node = path.node; | ||
@@ -921,3 +1069,2 @@ | ||
ForInStatement: createPrevExpressionEater("for-in"), | ||
@@ -927,3 +1074,3 @@ | ||
SequenceExpression: { | ||
exit: function exit(path) { | ||
exit(path) { | ||
if (path.node[seqExprSeen]) { | ||
@@ -972,3 +1119,3 @@ return; | ||
SwitchCase: function SwitchCase(path) { | ||
SwitchCase(path) { | ||
var node = path.node; | ||
@@ -984,3 +1131,2 @@ | ||
SwitchStatement: { | ||
@@ -1225,7 +1371,5 @@ exit: [ | ||
var potentialBreak = lastCase.get("consequent")[lastCase.node.consequent.length - 1]; | ||
if (!t.isBreakStatement(potentialBreak)) { | ||
return; | ||
if (t.isBreakStatement(potentialBreak) && potentialBreak.node.label === null) { | ||
potentialBreak.remove(); | ||
} | ||
potentialBreak.remove(); | ||
}, createPrevExpressionEater("switch")] | ||
@@ -1321,3 +1465,6 @@ } | ||
var statements = path.container.slice(path.key + 1); | ||
var statements = path.container.slice(path.key + 1).filter(function (stmt) { | ||
return !t.isFunctionDeclaration(stmt); | ||
}); | ||
if (!statements.length) { | ||
@@ -1341,11 +1488,10 @@ path.replaceWith(t.expressionStatement(node.test)); | ||
while (l-- > 0) { | ||
path.getSibling(path.key + 1).remove(); | ||
if (!t.isFunctionDeclaration(statements[l])) { | ||
path.getSibling(path.key + 1).remove(); | ||
} | ||
} | ||
if (statements.length === 1) { | ||
node.consequent = statements[0]; | ||
} else { | ||
node.consequent = t.blockStatement(statements); | ||
} | ||
node.consequent = t.blockStatement(statements); | ||
// this should take care of removing the block | ||
path.visit(); | ||
@@ -1420,2 +1566,5 @@ } | ||
} | ||
if (typeof patternValue === "function") { | ||
return patternValue(inputPath); | ||
} | ||
if (isNodeOfType(inputPath.node, patternValue)) return true; | ||
@@ -1422,0 +1571,0 @@ var evalResult = inputPath.evaluate(); |
@@ -9,2 +9,4 @@ "use strict"; | ||
var LEAF_NODE = Symbol("LEAF_NODE"); | ||
module.exports = function () { | ||
@@ -35,5 +37,5 @@ function PatternMatch(patterns) { | ||
value: function match(input) { | ||
var isMatch = arguments.length <= 1 || arguments[1] === undefined ? function (a, b) { | ||
var isMatch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function (a, b) { | ||
return a === b; | ||
} : arguments[1]; | ||
}; | ||
@@ -87,6 +89,10 @@ var current = this.decisionTree; | ||
if (i === input.length - 1) { | ||
result.match = true; | ||
result.value = current; | ||
if (current.has(LEAF_NODE)) { | ||
result.match = true; | ||
result.value = current.get(LEAF_NODE); | ||
} | ||
break; | ||
} | ||
} else { | ||
break; | ||
} | ||
@@ -135,6 +141,11 @@ } | ||
if (pattern.length === 2) { | ||
// here we don't handle duplicates | ||
// this pattern would have already been matched | ||
if (!parent.has(pattern[0])) { | ||
parent.set(pattern[0], pattern[1]); | ||
if (parent.has(pattern[0])) { | ||
var pattern0 = parent.get(pattern[0]); | ||
if (!pattern0.has(LEAF_NODE)) { | ||
pattern0.set(LEAF_NODE, pattern[1]); | ||
} | ||
// here we don't handle duplicates | ||
// this pattern would have already been matched | ||
} else { | ||
parent.set(pattern[0], new Map([[LEAF_NODE, pattern[1]]])); | ||
} | ||
@@ -145,8 +156,6 @@ | ||
var _pattern = _toArray(pattern); | ||
var _pattern = _toArray(pattern), | ||
current = _pattern[0], | ||
rest = _pattern.slice(1); | ||
var current = _pattern[0]; | ||
var rest = _pattern.slice(1); | ||
if (parent.has(current)) { | ||
@@ -153,0 +162,0 @@ make(parent.get(current), rest); |
{ | ||
"name": "babel-plugin-minify-simplify", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/babel/babili#readme", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
56680
1421
1