hoister.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. function t() {
  7. var data = _interopRequireWildcard(require("@babel/types"));
  8. t = function t() {
  9. return data;
  10. };
  11. return data;
  12. }
  13. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
  14. var referenceVisitor = {
  15. ReferencedIdentifier: function ReferencedIdentifier(path, state) {
  16. if (path.isJSXIdentifier() && t().react.isCompatTag(path.node.name) && !path.parentPath.isJSXMemberExpression()) {
  17. return;
  18. }
  19. if (path.node.name === "this") {
  20. var scope = path.scope;
  21. do {
  22. if (scope.path.isFunction() && !scope.path.isArrowFunctionExpression()) {
  23. break;
  24. }
  25. } while (scope = scope.parent);
  26. if (scope) state.breakOnScopePaths.push(scope.path);
  27. }
  28. var binding = path.scope.getBinding(path.node.name);
  29. if (!binding) return;
  30. if (binding !== state.scope.getBinding(path.node.name)) return;
  31. state.bindings[path.node.name] = binding;
  32. }
  33. };
  34. var PathHoister = function () {
  35. function PathHoister(path, scope) {
  36. this.breakOnScopePaths = [];
  37. this.bindings = {};
  38. this.scopes = [];
  39. this.scope = scope;
  40. this.path = path;
  41. this.attachAfter = false;
  42. }
  43. var _proto = PathHoister.prototype;
  44. _proto.isCompatibleScope = function isCompatibleScope(scope) {
  45. for (var key in this.bindings) {
  46. var binding = this.bindings[key];
  47. if (!scope.bindingIdentifierEquals(key, binding.identifier)) {
  48. return false;
  49. }
  50. }
  51. return true;
  52. };
  53. _proto.getCompatibleScopes = function getCompatibleScopes() {
  54. var scope = this.path.scope;
  55. do {
  56. if (this.isCompatibleScope(scope)) {
  57. this.scopes.push(scope);
  58. } else {
  59. break;
  60. }
  61. if (this.breakOnScopePaths.indexOf(scope.path) >= 0) {
  62. break;
  63. }
  64. } while (scope = scope.parent);
  65. };
  66. _proto.getAttachmentPath = function getAttachmentPath() {
  67. var path = this._getAttachmentPath();
  68. if (!path) return;
  69. var targetScope = path.scope;
  70. if (targetScope.path === path) {
  71. targetScope = path.scope.parent;
  72. }
  73. if (targetScope.path.isProgram() || targetScope.path.isFunction()) {
  74. for (var name in this.bindings) {
  75. if (!targetScope.hasOwnBinding(name)) continue;
  76. var binding = this.bindings[name];
  77. if (binding.kind === "param" || binding.path.parentKey === "params") {
  78. continue;
  79. }
  80. var bindingParentPath = this.getAttachmentParentForPath(binding.path);
  81. if (bindingParentPath.key >= path.key) {
  82. this.attachAfter = true;
  83. path = binding.path;
  84. var _arr = binding.constantViolations;
  85. for (var _i = 0; _i < _arr.length; _i++) {
  86. var violationPath = _arr[_i];
  87. if (this.getAttachmentParentForPath(violationPath).key > path.key) {
  88. path = violationPath;
  89. }
  90. }
  91. }
  92. }
  93. }
  94. return path;
  95. };
  96. _proto._getAttachmentPath = function _getAttachmentPath() {
  97. var scopes = this.scopes;
  98. var scope = scopes.pop();
  99. if (!scope) return;
  100. if (scope.path.isFunction()) {
  101. if (this.hasOwnParamBindings(scope)) {
  102. if (this.scope === scope) return;
  103. var bodies = scope.path.get("body").get("body");
  104. for (var i = 0; i < bodies.length; i++) {
  105. if (bodies[i].node._blockHoist) continue;
  106. return bodies[i];
  107. }
  108. } else {
  109. return this.getNextScopeAttachmentParent();
  110. }
  111. } else if (scope.path.isProgram()) {
  112. return this.getNextScopeAttachmentParent();
  113. }
  114. };
  115. _proto.getNextScopeAttachmentParent = function getNextScopeAttachmentParent() {
  116. var scope = this.scopes.pop();
  117. if (scope) return this.getAttachmentParentForPath(scope.path);
  118. };
  119. _proto.getAttachmentParentForPath = function getAttachmentParentForPath(path) {
  120. do {
  121. if (!path.parentPath || Array.isArray(path.container) && path.isStatement()) {
  122. return path;
  123. }
  124. } while (path = path.parentPath);
  125. };
  126. _proto.hasOwnParamBindings = function hasOwnParamBindings(scope) {
  127. for (var name in this.bindings) {
  128. if (!scope.hasOwnBinding(name)) continue;
  129. var binding = this.bindings[name];
  130. if (binding.kind === "param" && binding.constant) return true;
  131. }
  132. return false;
  133. };
  134. _proto.run = function run() {
  135. this.path.traverse(referenceVisitor, this);
  136. this.getCompatibleScopes();
  137. var attachTo = this.getAttachmentPath();
  138. if (!attachTo) return;
  139. if (attachTo.getFunctionParent() === this.path.getFunctionParent()) return;
  140. var uid = attachTo.scope.generateUidIdentifier("ref");
  141. var declarator = t().variableDeclarator(uid, this.path.node);
  142. var insertFn = this.attachAfter ? "insertAfter" : "insertBefore";
  143. var _attachTo$insertFn = attachTo[insertFn]([attachTo.isVariableDeclarator() ? declarator : t().variableDeclaration("var", [declarator])]),
  144. attached = _attachTo$insertFn[0];
  145. var parent = this.path.parentPath;
  146. if (parent.isJSXElement() && this.path.container === parent.node.children) {
  147. uid = t().JSXExpressionContainer(uid);
  148. }
  149. this.path.replaceWith(t().cloneNode(uid));
  150. return attachTo.isVariableDeclarator() ? attached.get("init") : attached.get("declarations.0.init");
  151. };
  152. return PathHoister;
  153. }();
  154. exports.default = PathHoister;