index.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _helperPluginUtils = require("@babel/helper-plugin-utils");
  7. var _helperSkipTransparentExpressionWrappers = require("@babel/helper-skip-transparent-expression-wrappers");
  8. var _pluginSyntaxOptionalChaining = _interopRequireDefault(require("@babel/plugin-syntax-optional-chaining"));
  9. var _core = require("@babel/core");
  10. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  11. var _default = (0, _helperPluginUtils.declare)((api, options) => {
  12. api.assertVersion(7);
  13. const {
  14. loose = false
  15. } = options;
  16. function isSimpleMemberExpression(expression) {
  17. expression = (0, _helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers)(expression);
  18. return _core.types.isIdentifier(expression) || _core.types.isSuper(expression) || _core.types.isMemberExpression(expression) && !expression.computed && isSimpleMemberExpression(expression.object);
  19. }
  20. function needsMemoize(path) {
  21. let optionalPath = path;
  22. const {
  23. scope
  24. } = path;
  25. while (optionalPath.isOptionalMemberExpression() || optionalPath.isOptionalCallExpression()) {
  26. const {
  27. node
  28. } = optionalPath;
  29. const childKey = optionalPath.isOptionalMemberExpression() ? "object" : "callee";
  30. const childPath = (0, _helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers)(optionalPath.get(childKey));
  31. if (node.optional) {
  32. return !scope.isStatic(childPath.node);
  33. }
  34. optionalPath = childPath;
  35. }
  36. }
  37. return {
  38. name: "proposal-optional-chaining",
  39. inherits: _pluginSyntaxOptionalChaining.default,
  40. visitor: {
  41. "OptionalCallExpression|OptionalMemberExpression"(path) {
  42. const {
  43. scope
  44. } = path;
  45. let maybeWrapped = path;
  46. const parentPath = path.findParent(p => {
  47. if (!(0, _helperSkipTransparentExpressionWrappers.isTransparentExprWrapper)(p)) return true;
  48. maybeWrapped = p;
  49. });
  50. let isDeleteOperation = false;
  51. const parentIsCall = parentPath.isCallExpression({
  52. callee: maybeWrapped.node
  53. }) && path.isOptionalMemberExpression();
  54. const optionals = [];
  55. let optionalPath = path;
  56. if (scope.path.isPattern() && needsMemoize(optionalPath)) {
  57. path.replaceWith(_core.template.ast`(() => ${path.node})()`);
  58. return;
  59. }
  60. while (optionalPath.isOptionalMemberExpression() || optionalPath.isOptionalCallExpression()) {
  61. const {
  62. node
  63. } = optionalPath;
  64. if (node.optional) {
  65. optionals.push(node);
  66. }
  67. if (optionalPath.isOptionalMemberExpression()) {
  68. optionalPath.node.type = "MemberExpression";
  69. optionalPath = (0, _helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers)(optionalPath.get("object"));
  70. } else if (optionalPath.isOptionalCallExpression()) {
  71. optionalPath.node.type = "CallExpression";
  72. optionalPath = (0, _helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers)(optionalPath.get("callee"));
  73. }
  74. }
  75. let replacementPath = path;
  76. if (parentPath.isUnaryExpression({
  77. operator: "delete"
  78. })) {
  79. replacementPath = parentPath;
  80. isDeleteOperation = true;
  81. }
  82. for (let i = optionals.length - 1; i >= 0; i--) {
  83. const node = optionals[i];
  84. const isCall = _core.types.isCallExpression(node);
  85. const replaceKey = isCall ? "callee" : "object";
  86. const chainWithTypes = node[replaceKey];
  87. let chain = chainWithTypes;
  88. while ((0, _helperSkipTransparentExpressionWrappers.isTransparentExprWrapper)(chain)) {
  89. chain = chain.expression;
  90. }
  91. let ref;
  92. let check;
  93. if (isCall && _core.types.isIdentifier(chain, {
  94. name: "eval"
  95. })) {
  96. check = ref = chain;
  97. node[replaceKey] = _core.types.sequenceExpression([_core.types.numericLiteral(0), ref]);
  98. } else if (loose && isCall && isSimpleMemberExpression(chain)) {
  99. check = ref = chainWithTypes;
  100. } else {
  101. ref = scope.maybeGenerateMemoised(chain);
  102. if (ref) {
  103. check = _core.types.assignmentExpression("=", _core.types.cloneNode(ref), chainWithTypes);
  104. node[replaceKey] = ref;
  105. } else {
  106. check = ref = chainWithTypes;
  107. }
  108. }
  109. if (isCall && _core.types.isMemberExpression(chain)) {
  110. if (loose && isSimpleMemberExpression(chain)) {
  111. node.callee = chainWithTypes;
  112. } else {
  113. const {
  114. object
  115. } = chain;
  116. let context = scope.maybeGenerateMemoised(object);
  117. if (context) {
  118. chain.object = _core.types.assignmentExpression("=", context, object);
  119. } else if (_core.types.isSuper(object)) {
  120. context = _core.types.thisExpression();
  121. } else {
  122. context = object;
  123. }
  124. node.arguments.unshift(_core.types.cloneNode(context));
  125. node.callee = _core.types.memberExpression(node.callee, _core.types.identifier("call"));
  126. }
  127. }
  128. let replacement = replacementPath.node;
  129. if (i === 0 && parentIsCall) {
  130. var _baseRef;
  131. const object = (0, _helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers)(replacementPath.get("object")).node;
  132. let baseRef;
  133. if (!loose || !isSimpleMemberExpression(object)) {
  134. baseRef = scope.maybeGenerateMemoised(object);
  135. if (baseRef) {
  136. replacement.object = _core.types.assignmentExpression("=", baseRef, object);
  137. }
  138. }
  139. replacement = _core.types.callExpression(_core.types.memberExpression(replacement, _core.types.identifier("bind")), [_core.types.cloneNode((_baseRef = baseRef) != null ? _baseRef : object)]);
  140. }
  141. replacementPath.replaceWith(_core.types.conditionalExpression(loose ? _core.types.binaryExpression("==", _core.types.cloneNode(check), _core.types.nullLiteral()) : _core.types.logicalExpression("||", _core.types.binaryExpression("===", _core.types.cloneNode(check), _core.types.nullLiteral()), _core.types.binaryExpression("===", _core.types.cloneNode(ref), scope.buildUndefinedNode())), isDeleteOperation ? _core.types.booleanLiteral(true) : scope.buildUndefinedNode(), replacement));
  142. replacementPath = (0, _helperSkipTransparentExpressionWrappers.skipTransparentExprWrappers)(replacementPath.get("alternate"));
  143. }
  144. }
  145. }
  146. };
  147. });
  148. exports.default = _default;