context.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _path = require("./path");
  7. var t = require("@babel/types");
  8. const testing = process.env.NODE_ENV === "test";
  9. class TraversalContext {
  10. constructor(scope, opts, state, parentPath) {
  11. this.queue = null;
  12. this.priorityQueue = null;
  13. this.parentPath = parentPath;
  14. this.scope = scope;
  15. this.state = state;
  16. this.opts = opts;
  17. }
  18. shouldVisit(node) {
  19. const opts = this.opts;
  20. if (opts.enter || opts.exit) return true;
  21. if (opts[node.type]) return true;
  22. const keys = t.VISITOR_KEYS[node.type];
  23. if (!(keys != null && keys.length)) return false;
  24. for (const key of keys) {
  25. if (node[key]) return true;
  26. }
  27. return false;
  28. }
  29. create(node, obj, key, listKey) {
  30. return _path.default.get({
  31. parentPath: this.parentPath,
  32. parent: node,
  33. container: obj,
  34. key: key,
  35. listKey
  36. });
  37. }
  38. maybeQueue(path, notPriority) {
  39. if (this.trap) {
  40. throw new Error("Infinite cycle detected");
  41. }
  42. if (this.queue) {
  43. if (notPriority) {
  44. this.queue.push(path);
  45. } else {
  46. this.priorityQueue.push(path);
  47. }
  48. }
  49. }
  50. visitMultiple(container, parent, listKey) {
  51. if (container.length === 0) return false;
  52. const queue = [];
  53. for (let key = 0; key < container.length; key++) {
  54. const node = container[key];
  55. if (node && this.shouldVisit(node)) {
  56. queue.push(this.create(parent, container, key, listKey));
  57. }
  58. }
  59. return this.visitQueue(queue);
  60. }
  61. visitSingle(node, key) {
  62. if (this.shouldVisit(node[key])) {
  63. return this.visitQueue([this.create(node, node, key)]);
  64. } else {
  65. return false;
  66. }
  67. }
  68. visitQueue(queue) {
  69. this.queue = queue;
  70. this.priorityQueue = [];
  71. const visited = new WeakSet();
  72. let stop = false;
  73. for (const path of queue) {
  74. path.resync();
  75. if (path.contexts.length === 0 || path.contexts[path.contexts.length - 1] !== this) {
  76. path.pushContext(this);
  77. }
  78. if (path.key === null) continue;
  79. if (testing && queue.length >= 10000) {
  80. this.trap = true;
  81. }
  82. const {
  83. node
  84. } = path;
  85. if (visited.has(node)) continue;
  86. if (node) visited.add(node);
  87. if (path.visit()) {
  88. stop = true;
  89. break;
  90. }
  91. if (this.priorityQueue.length) {
  92. stop = this.visitQueue(this.priorityQueue);
  93. this.priorityQueue = [];
  94. this.queue = queue;
  95. if (stop) break;
  96. }
  97. }
  98. for (const path of queue) {
  99. path.popContext();
  100. }
  101. this.queue = null;
  102. return stop;
  103. }
  104. visit(node, key) {
  105. const nodes = node[key];
  106. if (!nodes) return false;
  107. if (Array.isArray(nodes)) {
  108. return this.visitMultiple(nodes, node, key);
  109. } else {
  110. return this.visitSingle(node, key);
  111. }
  112. }
  113. }
  114. exports.default = TraversalContext;