FindAllDefinitionsResolver.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import isReactComponentClass from '../utils/isReactComponentClass.js';
  2. import isReactCreateClassCall from '../utils/isReactCreateClassCall.js';
  3. import isReactForwardRefCall from '../utils/isReactForwardRefCall.js';
  4. import isStatelessComponent from '../utils/isStatelessComponent.js';
  5. import normalizeClassDefinition from '../utils/normalizeClassDefinition.js';
  6. import resolveToValue from '../utils/resolveToValue.js';
  7. import { visitors } from '@babel/traverse';
  8. function classVisitor(path, state) {
  9. if (isReactComponentClass(path)) {
  10. normalizeClassDefinition(path);
  11. state.foundDefinitions.add(path);
  12. }
  13. path.skip();
  14. }
  15. function statelessVisitor(path, state) {
  16. if (isStatelessComponent(path)) {
  17. state.foundDefinitions.add(path);
  18. }
  19. path.skip();
  20. }
  21. const explodedVisitors = visitors.explode({
  22. FunctionDeclaration: { enter: statelessVisitor },
  23. FunctionExpression: { enter: statelessVisitor },
  24. ObjectMethod: { enter: statelessVisitor },
  25. ArrowFunctionExpression: { enter: statelessVisitor },
  26. ClassExpression: { enter: classVisitor },
  27. ClassDeclaration: { enter: classVisitor },
  28. CallExpression: {
  29. enter: function (path, state) {
  30. const argument = path.get('arguments')[0];
  31. if (!argument) {
  32. return;
  33. }
  34. if (isReactForwardRefCall(path)) {
  35. // If the the inner function was previously identified as a component
  36. // replace it with the parent node
  37. const inner = resolveToValue(argument);
  38. state.foundDefinitions.delete(inner);
  39. state.foundDefinitions.add(path);
  40. // Do not traverse into arguments
  41. return path.skip();
  42. }
  43. else if (isReactCreateClassCall(path)) {
  44. const resolvedPath = resolveToValue(argument);
  45. if (resolvedPath.isObjectExpression()) {
  46. state.foundDefinitions.add(resolvedPath);
  47. }
  48. // Do not traverse into arguments
  49. return path.skip();
  50. }
  51. },
  52. },
  53. });
  54. /**
  55. * Given an AST, this function tries to find all object expressions that are
  56. * passed to `React.createClass` calls, by resolving all references properly.
  57. */
  58. export default class FindAllDefinitionsResolver {
  59. resolve(file) {
  60. const state = {
  61. foundDefinitions: new Set(),
  62. };
  63. file.traverse(explodedVisitors, state);
  64. return Array.from(state.foundDefinitions);
  65. }
  66. }