Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

traverser.js 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /**
  2. * @fileoverview Traverser to traverse AST trees.
  3. * @author Nicholas C. Zakas
  4. * @author Toru Nagashima
  5. */
  6. "use strict";
  7. //------------------------------------------------------------------------------
  8. // Requirements
  9. //------------------------------------------------------------------------------
  10. const vk = require("eslint-visitor-keys");
  11. const debug = require("debug")("eslint:traverser");
  12. //------------------------------------------------------------------------------
  13. // Helpers
  14. //------------------------------------------------------------------------------
  15. /**
  16. * Do nothing.
  17. * @returns {void}
  18. */
  19. function noop() {
  20. // do nothing.
  21. }
  22. /**
  23. * Check whether the given value is an ASTNode or not.
  24. * @param {any} x The value to check.
  25. * @returns {boolean} `true` if the value is an ASTNode.
  26. */
  27. function isNode(x) {
  28. return x !== null && typeof x === "object" && typeof x.type === "string";
  29. }
  30. /**
  31. * Get the visitor keys of a given node.
  32. * @param {Object} visitorKeys The map of visitor keys.
  33. * @param {ASTNode} node The node to get their visitor keys.
  34. * @returns {string[]} The visitor keys of the node.
  35. */
  36. function getVisitorKeys(visitorKeys, node) {
  37. let keys = visitorKeys[node.type];
  38. if (!keys) {
  39. keys = vk.getKeys(node);
  40. debug("Unknown node type \"%s\": Estimated visitor keys %j", node.type, keys);
  41. }
  42. return keys;
  43. }
  44. /**
  45. * The traverser class to traverse AST trees.
  46. */
  47. class Traverser {
  48. constructor() {
  49. this._current = null;
  50. this._parents = [];
  51. this._skipped = false;
  52. this._broken = false;
  53. this._visitorKeys = null;
  54. this._enter = null;
  55. this._leave = null;
  56. }
  57. /**
  58. * @returns {ASTNode} The current node.
  59. */
  60. current() {
  61. return this._current;
  62. }
  63. /**
  64. * @returns {ASTNode[]} The ancestor nodes.
  65. */
  66. parents() {
  67. return this._parents.slice(0);
  68. }
  69. /**
  70. * Break the current traversal.
  71. * @returns {void}
  72. */
  73. break() {
  74. this._broken = true;
  75. }
  76. /**
  77. * Skip child nodes for the current traversal.
  78. * @returns {void}
  79. */
  80. skip() {
  81. this._skipped = true;
  82. }
  83. /**
  84. * Traverse the given AST tree.
  85. * @param {ASTNode} node The root node to traverse.
  86. * @param {Object} options The option object.
  87. * @param {Object} [options.visitorKeys=DEFAULT_VISITOR_KEYS] The keys of each node types to traverse child nodes. Default is `./default-visitor-keys.json`.
  88. * @param {Function} [options.enter=noop] The callback function which is called on entering each node.
  89. * @param {Function} [options.leave=noop] The callback function which is called on leaving each node.
  90. * @returns {void}
  91. */
  92. traverse(node, options) {
  93. this._current = null;
  94. this._parents = [];
  95. this._skipped = false;
  96. this._broken = false;
  97. this._visitorKeys = options.visitorKeys || vk.KEYS;
  98. this._enter = options.enter || noop;
  99. this._leave = options.leave || noop;
  100. this._traverse(node, null);
  101. }
  102. /**
  103. * Traverse the given AST tree recursively.
  104. * @param {ASTNode} node The current node.
  105. * @param {ASTNode|null} parent The parent node.
  106. * @returns {void}
  107. * @private
  108. */
  109. _traverse(node, parent) {
  110. if (!isNode(node)) {
  111. return;
  112. }
  113. this._current = node;
  114. this._skipped = false;
  115. this._enter(node, parent);
  116. if (!this._skipped && !this._broken) {
  117. const keys = getVisitorKeys(this._visitorKeys, node);
  118. if (keys.length >= 1) {
  119. this._parents.push(node);
  120. for (let i = 0; i < keys.length && !this._broken; ++i) {
  121. const child = node[keys[i]];
  122. if (Array.isArray(child)) {
  123. for (let j = 0; j < child.length && !this._broken; ++j) {
  124. this._traverse(child[j], node);
  125. }
  126. } else {
  127. this._traverse(child, node);
  128. }
  129. }
  130. this._parents.pop();
  131. }
  132. }
  133. if (!this._broken) {
  134. this._leave(node, parent);
  135. }
  136. this._current = parent;
  137. }
  138. /**
  139. * Calculates the keys to use for traversal.
  140. * @param {ASTNode} node The node to read keys from.
  141. * @returns {string[]} An array of keys to visit on the node.
  142. * @private
  143. */
  144. static getKeys(node) {
  145. return vk.getKeys(node);
  146. }
  147. /**
  148. * Traverse the given AST tree.
  149. * @param {ASTNode} node The root node to traverse.
  150. * @param {Object} options The option object.
  151. * @param {Object} [options.visitorKeys=DEFAULT_VISITOR_KEYS] The keys of each node types to traverse child nodes. Default is `./default-visitor-keys.json`.
  152. * @param {Function} [options.enter=noop] The callback function which is called on entering each node.
  153. * @param {Function} [options.leave=noop] The callback function which is called on leaving each node.
  154. * @returns {void}
  155. */
  156. static traverse(node, options) {
  157. new Traverser().traverse(node, options);
  158. }
  159. /**
  160. * The default visitor keys.
  161. * @type {Object}
  162. */
  163. static get DEFAULT_VISITOR_KEYS() {
  164. return vk.KEYS;
  165. }
  166. }
  167. module.exports = Traverser;