traverse.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import { createPath } from "./node-path";
  2. import { unionTypesMap, nodeAndUnionTypes } from "./nodes"; // recursively walks the AST starting at the given node. The callback is invoked for
  3. // and object that has a 'type' property.
  4. function walk(context, callback) {
  5. var stop = false;
  6. function innerWalk(context, callback) {
  7. if (stop) {
  8. return;
  9. }
  10. var node = context.node;
  11. if (node === undefined) {
  12. console.warn("traversing with an empty context");
  13. return;
  14. }
  15. if (node._deleted === true) {
  16. return;
  17. }
  18. var path = createPath(context);
  19. callback(node.type, path);
  20. if (path.shouldStop) {
  21. stop = true;
  22. return;
  23. }
  24. Object.keys(node).forEach(function (prop) {
  25. var value = node[prop];
  26. if (value === null || value === undefined) {
  27. return;
  28. }
  29. var valueAsArray = Array.isArray(value) ? value : [value];
  30. valueAsArray.forEach(function (childNode) {
  31. if (typeof childNode.type === "string") {
  32. var childContext = {
  33. node: childNode,
  34. parentKey: prop,
  35. parentPath: path,
  36. shouldStop: false,
  37. inList: Array.isArray(value)
  38. };
  39. innerWalk(childContext, callback);
  40. }
  41. });
  42. });
  43. }
  44. innerWalk(context, callback);
  45. }
  46. var noop = function noop() {};
  47. export function traverse(node, visitors) {
  48. var before = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : noop;
  49. var after = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : noop;
  50. Object.keys(visitors).forEach(function (visitor) {
  51. if (!nodeAndUnionTypes.includes(visitor)) {
  52. throw new Error("Unexpected visitor ".concat(visitor));
  53. }
  54. });
  55. var context = {
  56. node: node,
  57. inList: false,
  58. shouldStop: false,
  59. parentPath: null,
  60. parentKey: null
  61. };
  62. walk(context, function (type, path) {
  63. if (typeof visitors[type] === "function") {
  64. before(type, path);
  65. visitors[type](path);
  66. after(type, path);
  67. }
  68. var unionTypes = unionTypesMap[type];
  69. if (!unionTypes) {
  70. throw new Error("Unexpected node type ".concat(type));
  71. }
  72. unionTypes.forEach(function (unionType) {
  73. if (typeof visitors[unionType] === "function") {
  74. before(unionType, path);
  75. visitors[unionType](path);
  76. after(unionType, path);
  77. }
  78. });
  79. });
  80. }