ancestry.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.find = find;
  6. exports.findParent = findParent;
  7. exports.getAncestry = getAncestry;
  8. exports.getDeepestCommonAncestorFrom = getDeepestCommonAncestorFrom;
  9. exports.getEarliestCommonAncestorFrom = getEarliestCommonAncestorFrom;
  10. exports.getFunctionParent = getFunctionParent;
  11. exports.getStatementParent = getStatementParent;
  12. exports.inType = inType;
  13. exports.isAncestor = isAncestor;
  14. exports.isDescendant = isDescendant;
  15. var _t = require("@babel/types");
  16. var _index = require("./index");
  17. const {
  18. VISITOR_KEYS
  19. } = _t;
  20. function findParent(callback) {
  21. let path = this;
  22. while (path = path.parentPath) {
  23. if (callback(path)) return path;
  24. }
  25. return null;
  26. }
  27. function find(callback) {
  28. let path = this;
  29. do {
  30. if (callback(path)) return path;
  31. } while (path = path.parentPath);
  32. return null;
  33. }
  34. function getFunctionParent() {
  35. return this.findParent(p => p.isFunction());
  36. }
  37. function getStatementParent() {
  38. let path = this;
  39. do {
  40. if (!path.parentPath || Array.isArray(path.container) && path.isStatement()) {
  41. break;
  42. } else {
  43. path = path.parentPath;
  44. }
  45. } while (path);
  46. if (path && (path.isProgram() || path.isFile())) {
  47. throw new Error("File/Program node, we can't possibly find a statement parent to this");
  48. }
  49. return path;
  50. }
  51. function getEarliestCommonAncestorFrom(paths) {
  52. return this.getDeepestCommonAncestorFrom(paths, function (deepest, i, ancestries) {
  53. let earliest;
  54. const keys = VISITOR_KEYS[deepest.type];
  55. for (const ancestry of ancestries) {
  56. const path = ancestry[i + 1];
  57. if (!earliest) {
  58. earliest = path;
  59. continue;
  60. }
  61. if (path.listKey && earliest.listKey === path.listKey) {
  62. if (path.key < earliest.key) {
  63. earliest = path;
  64. continue;
  65. }
  66. }
  67. const earliestKeyIndex = keys.indexOf(earliest.parentKey);
  68. const currentKeyIndex = keys.indexOf(path.parentKey);
  69. if (earliestKeyIndex > currentKeyIndex) {
  70. earliest = path;
  71. }
  72. }
  73. return earliest;
  74. });
  75. }
  76. function getDeepestCommonAncestorFrom(paths, filter) {
  77. if (!paths.length) {
  78. return this;
  79. }
  80. if (paths.length === 1) {
  81. return paths[0];
  82. }
  83. let minDepth = Infinity;
  84. let lastCommonIndex, lastCommon;
  85. const ancestries = paths.map(path => {
  86. const ancestry = [];
  87. do {
  88. ancestry.unshift(path);
  89. } while ((path = path.parentPath) && path !== this);
  90. if (ancestry.length < minDepth) {
  91. minDepth = ancestry.length;
  92. }
  93. return ancestry;
  94. });
  95. const first = ancestries[0];
  96. depthLoop: for (let i = 0; i < minDepth; i++) {
  97. const shouldMatch = first[i];
  98. for (const ancestry of ancestries) {
  99. if (ancestry[i] !== shouldMatch) {
  100. break depthLoop;
  101. }
  102. }
  103. lastCommonIndex = i;
  104. lastCommon = shouldMatch;
  105. }
  106. if (lastCommon) {
  107. if (filter) {
  108. return filter(lastCommon, lastCommonIndex, ancestries);
  109. } else {
  110. return lastCommon;
  111. }
  112. } else {
  113. throw new Error("Couldn't find intersection");
  114. }
  115. }
  116. function getAncestry() {
  117. let path = this;
  118. const paths = [];
  119. do {
  120. paths.push(path);
  121. } while (path = path.parentPath);
  122. return paths;
  123. }
  124. function isAncestor(maybeDescendant) {
  125. return maybeDescendant.isDescendant(this);
  126. }
  127. function isDescendant(maybeAncestor) {
  128. return !!this.findParent(parent => parent === maybeAncestor);
  129. }
  130. function inType(...candidateTypes) {
  131. let path = this;
  132. while (path) {
  133. for (const type of candidateTypes) {
  134. if (path.node.type === type) return true;
  135. }
  136. path = path.parentPath;
  137. }
  138. return false;
  139. }