-
-
Notifications
You must be signed in to change notification settings - Fork 225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shorten assignments to itself #230
Changes from 15 commits
3344baa
a4d10bc
c666da1
c6ec99d
6b913fe
c1aa0ca
6dfe218
6813842
5ddc5f8
2c7a0d5
4f7e8eb
64ed8d9
8c0a456
6eaded6
edd236f
b058bd0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,62 @@ module.exports = ({ types: t }) => { | |
const or = (a, b) => t.logicalExpression("||", a, b); | ||
const and = (a, b) => t.logicalExpression("&&", a, b); | ||
|
||
const operators = new Set([ | ||
"+", "-", "*", "%", | ||
"<<", ">>", ">>>", | ||
"&", "|", "^", "/", | ||
"**" | ||
]); | ||
|
||
const updateOperators = new Set([ | ||
"+", "-" | ||
]); | ||
|
||
function isEqual(arr1, arr2) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ugh, good catch. So the reason it works is because property names are resolved RTL so There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is specific to this feature, we should have a comment or change name to indicate that, since this is at the top level (nearly). |
||
return arr1.every((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; | ||
} | ||
|
||
let obj = path.get("object"); | ||
|
||
const prop = path.get("property"); | ||
const propNames = [getName(prop.node)]; | ||
|
||
while (obj.type === "MemberExpression") { | ||
const node = obj.get("property").node; | ||
if (node) { | ||
propNames.push(getName(node)); | ||
} | ||
obj = obj.get("object"); | ||
} | ||
propNames.push(getName(obj.node)); | ||
|
||
return propNames; | ||
} | ||
const OP_AND = (input) => input === "&&"; | ||
const OP_OR = (input) => input === "||"; | ||
|
||
|
@@ -194,6 +250,57 @@ module.exports = ({ types: t }) => { | |
} | ||
}, | ||
|
||
AssignmentExpression(path) { | ||
|
||
const rightExpr = path.get("right"); | ||
const leftExpr = path.get("left"); | ||
|
||
const canBeUpdateExpression = ( | ||
rightExpr.get("right").isNumericLiteral() && | ||
rightExpr.get("right").node.value === 1 && | ||
updateOperators.has(rightExpr.node.operator)); | ||
|
||
if (leftExpr.isMemberExpression()) { | ||
|
||
const leftPropNames = getPropNames(leftExpr); | ||
const rightPropNames = getPropNames(rightExpr.get("left")); | ||
|
||
if (!leftPropNames || | ||
leftPropNames.indexOf(undefined) > -1 || | ||
!rightPropNames || | ||
rightPropNames.indexOf(undefined) > -1 || | ||
!operators.has(rightExpr.node.operator) || | ||
!isEqual(leftPropNames, rightPropNames)) { | ||
return; | ||
} | ||
} | ||
else { | ||
if (!rightExpr.isBinaryExpression() || | ||
!operators.has(rightExpr.node.operator) || | ||
leftExpr.node.name !== rightExpr.node.left.name) { | ||
return; | ||
} | ||
} | ||
|
||
let newExpression; | ||
|
||
// 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: { | ||
enter: [ | ||
// !foo ? 'foo' : 'bar' -> foo ? 'bar' : 'foo' | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to consider splitting plugins into multiple modules. This kind of mixing of helpers and supplemental stuff is not great ^. I think we could even strive for 1 type-of-transform per file.