Microbouji patch/8136 (#9073)

* Fix optional chaining bug regarding spread in function calls

* Revamp optional-chain to be top down

Instead of going both upwards and downwards from the first real optional expression, we can just start from the top down.

* Add more tests
This commit is contained in:
Justin Ridgewell 2018-11-24 09:32:24 -05:00 committed by GitHub
parent 856edbf95f
commit 844dd33f3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 122 deletions

View File

@ -7,32 +7,40 @@ export default declare((api, options) => {
const { loose = false } = options; const { loose = false } = options;
function optional(path, replacementPath) { return {
const { scope } = path; name: "proposal-optional-chaining",
inherits: syntaxOptionalChaining,
visitor: {
"OptionalCallExpression|OptionalMemberExpression"(path) {
const { parentPath, scope } = path;
const optionals = []; const optionals = [];
let objectPath = path; let optionalPath = path;
while ( while (
objectPath.isOptionalMemberExpression() || optionalPath.isOptionalMemberExpression() ||
objectPath.isOptionalCallExpression() optionalPath.isOptionalCallExpression()
) { ) {
const { node } = objectPath; const { node } = optionalPath;
if (node.optional) { if (node.optional) {
optionals.push(node); optionals.push(node);
} }
if (objectPath.isOptionalMemberExpression()) { if (optionalPath.isOptionalMemberExpression()) {
objectPath.node.type = "MemberExpression"; optionalPath.node.type = "MemberExpression";
objectPath = objectPath.get("object"); optionalPath = optionalPath.get("object");
} else { } else if (optionalPath.isOptionalCallExpression()) {
objectPath.node.type = "CallExpression"; optionalPath.node.type = "CallExpression";
objectPath = objectPath.get("callee"); optionalPath = optionalPath.get("callee");
} }
} }
let replacementPath = path;
if (parentPath.isUnaryExpression({ operator: "delete" })) {
replacementPath = parentPath;
}
for (let i = optionals.length - 1; i >= 0; i--) { for (let i = optionals.length - 1; i >= 0; i--) {
const node = optionals[i]; const node = optionals[i];
node.optional = false;
const isCall = t.isCallExpression(node); const isCall = t.isCallExpression(node);
const replaceKey = isCall ? "callee" : "object"; const replaceKey = isCall ? "callee" : "object";
@ -79,7 +87,10 @@ export default declare((api, options) => {
} }
node.arguments.unshift(t.cloneNode(context)); node.arguments.unshift(t.cloneNode(context));
node.callee = t.memberExpression(node.callee, t.identifier("call")); node.callee = t.memberExpression(
node.callee,
t.identifier("call"),
);
} }
} }
@ -89,7 +100,11 @@ export default declare((api, options) => {
? t.binaryExpression("==", t.cloneNode(check), t.nullLiteral()) ? t.binaryExpression("==", t.cloneNode(check), t.nullLiteral())
: t.logicalExpression( : t.logicalExpression(
"||", "||",
t.binaryExpression("===", t.cloneNode(check), t.nullLiteral()), t.binaryExpression(
"===",
t.cloneNode(check),
t.nullLiteral(),
),
t.binaryExpression( t.binaryExpression(
"===", "===",
t.cloneNode(ref), t.cloneNode(ref),
@ -103,40 +118,6 @@ export default declare((api, options) => {
replacementPath = replacementPath.get("alternate"); replacementPath = replacementPath.get("alternate");
} }
}
function findReplacementPath(path) {
return path.find(path => {
const { parentPath } = path;
if (path.key == "object" && parentPath.isOptionalMemberExpression()) {
return false;
}
if (path.key == "callee" && parentPath.isOptionalCallExpression()) {
return false;
}
if (
path.key == "argument" &&
parentPath.isUnaryExpression({ operator: "delete" })
) {
return false;
}
return true;
});
}
return {
name: "proposal-optional-chaining",
inherits: syntaxOptionalChaining,
visitor: {
"OptionalCallExpression|OptionalMemberExpression"(path) {
if (!path.node.optional) {
return;
}
optional(path, findReplacementPath(path));
}, },
}, },
}; };

View File

@ -0,0 +1,7 @@
a?.(...args);
a?.b(...args);
a?.b(...args).c;
a?.b(...args).c(...args);

View File

@ -0,0 +1,7 @@
{
"plugins": [
"external-helpers",
"proposal-optional-chaining",
"transform-spread"
]
}

View File

@ -0,0 +1,6 @@
var _a, _a2, _a3, _a4, _a4$b;
(_a = a) === null || _a === void 0 ? void 0 : _a.apply(void 0, babelHelpers.toConsumableArray(args));
(_a2 = a) === null || _a2 === void 0 ? void 0 : _a2.b.apply(_a2, babelHelpers.toConsumableArray(args));
(_a3 = a) === null || _a3 === void 0 ? void 0 : _a3.b.apply(_a3, babelHelpers.toConsumableArray(args)).c;
(_a4 = a) === null || _a4 === void 0 ? void 0 : (_a4$b = _a4.b.apply(_a4, babelHelpers.toConsumableArray(args))).c.apply(_a4$b, babelHelpers.toConsumableArray(args));