diff --git a/packages/babel-plugin-transform-optional-chaining/src/index.js b/packages/babel-plugin-transform-optional-chaining/src/index.js index 5493230d88..aca9d8e6c3 100644 --- a/packages/babel-plugin-transform-optional-chaining/src/index.js +++ b/packages/babel-plugin-transform-optional-chaining/src/index.js @@ -1,61 +1,44 @@ -import createTemplate from "babel-template"; -import traverse from "babel-traverse"; - -const nullOrUndefinedCheck = createTemplate(` - typeof CHECK !== "undefined" && CHECK !== null - ? NEXT - : null -`); - -function isNodeOptional(node) { - return node.optional === true; -} - -const nullOrUndefinedCheckVisitor = { - noScope: true, - - Identifier(path, replacements) { - if (path.node.name in replacements) { - path.replaceInline(replacements[path.node.name]); - } - }, -}; - -function createCheck(node, object) { - - const template = nullOrUndefinedCheck(); - - traverse(template, nullOrUndefinedCheckVisitor, null, { - CHECK: object, - NEXT: node, - }); - - return template; -} - export default function ({ types: t }) { + function createCondition(ref, access, nextProperty) { + + return t.conditionalExpression( + createCheckAgainstNull( + t.AssignmentExpression("=", ref, access) + ), + + t.memberExpression(ref, nextProperty), + t.NullLiteral() + ); + } + + function createCheckAgainstNull(left) { + return t.BinaryExpression("!=", left, t.NullLiteral()); + } + + function isNodeOptional(node) { + return node.optional === true; + } + return { visitor: { - MemberExpression(path) { - - if (isNodeOptional(path.node)) { - let { object } = path.node; - - do { - object = createCheck( - object, - object.object - ); - - } while (t.isMemberExpression(object) && isNodeOptional(object)); - - path.replaceWith( - createCheck(path.node, object) - ); - - path.stop(); + MemberExpression(path, state) { + if (!isNodeOptional(path.node)) { + return; } + + const { object, property } = path.node; + + if (!state.optionalTemp) { + const id = path.scope.generateUidIdentifier(); + + state.optionalTemp = id; + path.scope.push({ id }); + } + + path.replaceWith( + createCondition(state.optionalTemp, object, property) + ); }, }, }; diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/expected.js index 473cdedb0f..beb5eddc75 100644 --- a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/expected.js +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/member-access/expected.js @@ -1 +1,3 @@ -typeof foo !== "undefined" && foo !== null ? foo.bar : null; \ No newline at end of file +var _temp; + +(_temp = foo) != null ? _temp.bar : null; diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/nested-member-access/actual.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/nested-member-access/actual.js index fc0ce9aea6..f9e4957390 100644 --- a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/nested-member-access/actual.js +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/nested-member-access/actual.js @@ -1 +1 @@ -foo?.bar?.vroum +a?.b.c?.d.e diff --git a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/nested-member-access/expected.js b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/nested-member-access/expected.js index 3c37951fcf..59d23923f8 100644 --- a/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/nested-member-access/expected.js +++ b/packages/babel-plugin-transform-optional-chaining/test/fixtures/general/nested-member-access/expected.js @@ -1 +1,3 @@ -typeof (typeof foo !== "undefined" && foo !== null ? foo.bar : null) !== "undefined" && (typeof foo !== "undefined" && foo !== null ? foo.bar : null) !== null ? foo.bar.vroum : null; \ No newline at end of file +var _temp; + +((_temp = ((_temp = a) != null ? _temp.b : null).c) != null ? _temp.d : null).e;