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.

239 lines
6.7 KiB

4 years ago
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.explode = explode;
  6. exports.verify = verify;
  7. exports.merge = merge;
  8. var virtualTypes = _interopRequireWildcard(require("./path/lib/virtual-types"));
  9. var t = _interopRequireWildcard(require("@babel/types"));
  10. var _clone = _interopRequireDefault(require("lodash/clone"));
  11. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  12. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
  13. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  14. function explode(visitor) {
  15. if (visitor._exploded) return visitor;
  16. visitor._exploded = true;
  17. for (const nodeType of Object.keys(visitor)) {
  18. if (shouldIgnoreKey(nodeType)) continue;
  19. const parts = nodeType.split("|");
  20. if (parts.length === 1) continue;
  21. const fns = visitor[nodeType];
  22. delete visitor[nodeType];
  23. for (const part of parts) {
  24. visitor[part] = fns;
  25. }
  26. }
  27. verify(visitor);
  28. delete visitor.__esModule;
  29. ensureEntranceObjects(visitor);
  30. ensureCallbackArrays(visitor);
  31. for (const nodeType of Object.keys(visitor)) {
  32. if (shouldIgnoreKey(nodeType)) continue;
  33. const wrapper = virtualTypes[nodeType];
  34. if (!wrapper) continue;
  35. const fns = visitor[nodeType];
  36. for (const type of Object.keys(fns)) {
  37. fns[type] = wrapCheck(wrapper, fns[type]);
  38. }
  39. delete visitor[nodeType];
  40. if (wrapper.types) {
  41. for (const type of wrapper.types) {
  42. if (visitor[type]) {
  43. mergePair(visitor[type], fns);
  44. } else {
  45. visitor[type] = fns;
  46. }
  47. }
  48. } else {
  49. mergePair(visitor, fns);
  50. }
  51. }
  52. for (const nodeType of Object.keys(visitor)) {
  53. if (shouldIgnoreKey(nodeType)) continue;
  54. const fns = visitor[nodeType];
  55. let aliases = t.FLIPPED_ALIAS_KEYS[nodeType];
  56. const deprecratedKey = t.DEPRECATED_KEYS[nodeType];
  57. if (deprecratedKey) {
  58. console.trace(`Visitor defined for ${nodeType} but it has been renamed to ${deprecratedKey}`);
  59. aliases = [deprecratedKey];
  60. }
  61. if (!aliases) continue;
  62. delete visitor[nodeType];
  63. for (const alias of aliases) {
  64. const existing = visitor[alias];
  65. if (existing) {
  66. mergePair(existing, fns);
  67. } else {
  68. visitor[alias] = (0, _clone.default)(fns);
  69. }
  70. }
  71. }
  72. for (const nodeType of Object.keys(visitor)) {
  73. if (shouldIgnoreKey(nodeType)) continue;
  74. ensureCallbackArrays(visitor[nodeType]);
  75. }
  76. return visitor;
  77. }
  78. function verify(visitor) {
  79. if (visitor._verified) return;
  80. if (typeof visitor === "function") {
  81. throw new Error("You passed `traverse()` a function when it expected a visitor object, " + "are you sure you didn't mean `{ enter: Function }`?");
  82. }
  83. for (const nodeType of Object.keys(visitor)) {
  84. if (nodeType === "enter" || nodeType === "exit") {
  85. validateVisitorMethods(nodeType, visitor[nodeType]);
  86. }
  87. if (shouldIgnoreKey(nodeType)) continue;
  88. if (t.TYPES.indexOf(nodeType) < 0) {
  89. throw new Error(`You gave us a visitor for the node type ${nodeType} but it's not a valid type`);
  90. }
  91. const visitors = visitor[nodeType];
  92. if (typeof visitors === "object") {
  93. for (const visitorKey of Object.keys(visitors)) {
  94. if (visitorKey === "enter" || visitorKey === "exit") {
  95. validateVisitorMethods(`${nodeType}.${visitorKey}`, visitors[visitorKey]);
  96. } else {
  97. throw new Error("You passed `traverse()` a visitor object with the property " + `${nodeType} that has the invalid property ${visitorKey}`);
  98. }
  99. }
  100. }
  101. }
  102. visitor._verified = true;
  103. }
  104. function validateVisitorMethods(path, val) {
  105. const fns = [].concat(val);
  106. for (const fn of fns) {
  107. if (typeof fn !== "function") {
  108. throw new TypeError(`Non-function found defined in ${path} with type ${typeof fn}`);
  109. }
  110. }
  111. }
  112. function merge(visitors, states = [], wrapper) {
  113. const rootVisitor = {};
  114. for (let i = 0; i < visitors.length; i++) {
  115. const visitor = visitors[i];
  116. const state = states[i];
  117. explode(visitor);
  118. for (const type of Object.keys(visitor)) {
  119. let visitorType = visitor[type];
  120. if (state || wrapper) {
  121. visitorType = wrapWithStateOrWrapper(visitorType, state, wrapper);
  122. }
  123. const nodeVisitor = rootVisitor[type] = rootVisitor[type] || {};
  124. mergePair(nodeVisitor, visitorType);
  125. }
  126. }
  127. return rootVisitor;
  128. }
  129. function wrapWithStateOrWrapper(oldVisitor, state, wrapper) {
  130. const newVisitor = {};
  131. for (const key of Object.keys(oldVisitor)) {
  132. let fns = oldVisitor[key];
  133. if (!Array.isArray(fns)) continue;
  134. fns = fns.map(function (fn) {
  135. let newFn = fn;
  136. if (state) {
  137. newFn = function (path) {
  138. return fn.call(state, path, state);
  139. };
  140. }
  141. if (wrapper) {
  142. newFn = wrapper(state.key, key, newFn);
  143. }
  144. return newFn;
  145. });
  146. newVisitor[key] = fns;
  147. }
  148. return newVisitor;
  149. }
  150. function ensureEntranceObjects(obj) {
  151. for (const key of Object.keys(obj)) {
  152. if (shouldIgnoreKey(key)) continue;
  153. const fns = obj[key];
  154. if (typeof fns === "function") {
  155. obj[key] = {
  156. enter: fns
  157. };
  158. }
  159. }
  160. }
  161. function ensureCallbackArrays(obj) {
  162. if (obj.enter && !Array.isArray(obj.enter)) obj.enter = [obj.enter];
  163. if (obj.exit && !Array.isArray(obj.exit)) obj.exit = [obj.exit];
  164. }
  165. function wrapCheck(wrapper, fn) {
  166. const newFn = function (path) {
  167. if (wrapper.checkPath(path)) {
  168. return fn.apply(this, arguments);
  169. }
  170. };
  171. newFn.toString = () => fn.toString();
  172. return newFn;
  173. }
  174. function shouldIgnoreKey(key) {
  175. if (key[0] === "_") return true;
  176. if (key === "enter" || key === "exit" || key === "shouldSkip") return true;
  177. if (key === "blacklist" || key === "noScope" || key === "skipKeys") {
  178. return true;
  179. }
  180. return false;
  181. }
  182. function mergePair(dest, src) {
  183. for (const key of Object.keys(src)) {
  184. dest[key] = [].concat(dest[key] || [], src[key]);
  185. }
  186. }