This commit is contained in:
Sven SAULEAU
2017-05-07 11:21:27 +02:00
committed by Justin Ridgewell
parent cc6959e1fa
commit 3faca62a77
9 changed files with 125 additions and 16 deletions

View File

@@ -1,4 +1,15 @@
export default function ({ types: t }) {
const nilIdentifier = t.identifier("undefined");
function setOptionalTransformed(node) {
t.assertMemberExpression(node); // Dev
node._optionalTransformed = true;
}
function isOptionalTransformed(node) {
t.assertMemberExpression(node); // Dev
return node._optionalTransformed === true;
}
function createCondition(ref, access, nextProperty, bailout) {
@@ -23,8 +34,87 @@ export default function ({ types: t }) {
return {
visitor: {
AssignmentExpression(path, state) {
const { left } = path.node;
if (!isNodeOptional(left) || isOptionalTransformed(left)) {
return;
}
if (!state.optionalTemp) {
const id = path.scope.generateUidIdentifier();
state.optionalTemp = id;
path.scope.push({ id });
}
const { object, property } = left;
const isChainNil = t.BinaryExpression(
"!=",
createCondition(
state.optionalTemp,
object,
property,
nilIdentifier,
),
nilIdentifier,
);
// FIXME(sven): if will be a ConditionalExpression for childs, only top level will be ifStatement
const remplacement = t.ifStatement(isChainNil, t.blockStatement([t.expressionStatement(path.node)]));
setOptionalTransformed(left);
path.traverse({
MemberExpression({ node }) {
setOptionalTransformed(node);
},
});
path.parentPath.replaceWith(remplacement);
},
UnaryExpression(path, state) {
const { operator, argument } = path.node;
if (operator !== "delete") {
return;
}
if (!isNodeOptional(argument) || isOptionalTransformed(argument)) {
return;
}
if (!state.optionalTemp) {
const id = path.scope.generateUidIdentifier();
state.optionalTemp = id;
path.scope.push({ id });
}
const { object, property } = argument;
const isChainNil = t.BinaryExpression(
"!=",
createCondition(
state.optionalTemp,
object,
property,
nilIdentifier,
),
nilIdentifier,
);
const remplacement = t.ifStatement(isChainNil, t.blockStatement([t.expressionStatement(path.node)]));
setOptionalTransformed(argument);
path.parentPath.replaceWith(remplacement);
},
MemberExpression(path, state) {
if (!isNodeOptional(path.node)) {
if (!isNodeOptional(path.node) || isOptionalTransformed(path.node)) {
return;
}
@@ -38,15 +128,9 @@ export default function ({ types: t }) {
}
if (t.isAssignmentExpression(path.parent)) {
const remplacement = createCondition(
t.identifier("temp_here_please"),
object,
property,
t.identifier("undefined"),
);
path.parentPath.replaceWith(remplacement);
return;
} else if (t.isUnaryExpression(path.parent)) {
return;
} else if (t.isCallExpression(path.parent)) {
const remplacement = createCondition(
@@ -56,6 +140,7 @@ export default function ({ types: t }) {
t.callExpression(t.identifier("Function"), []),
);
setOptionalTransformed(path.node);
path.replaceWith(remplacement);
} else {
@@ -63,9 +148,10 @@ export default function ({ types: t }) {
state.optionalTemp,
object,
property,
t.identifier("undefined"),
nilIdentifier,
);
setOptionalTransformed(path.node);
path.replaceWith(remplacement);
}
},