getMemberExpressionValuePath.js 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { visitors } from '@babel/traverse';
  2. import getNameOrValue from './getNameOrValue.js';
  3. import { String as toString } from './expressionTo.js';
  4. import isReactForwardRefCall from './isReactForwardRefCall.js';
  5. function resolveName(path) {
  6. if (path.isVariableDeclaration()) {
  7. const declarations = path.get('declarations');
  8. if (declarations.length > 1) {
  9. throw new TypeError('Got unsupported VariableDeclaration. VariableDeclaration must only ' +
  10. 'have a single VariableDeclarator. Got ' +
  11. declarations.length +
  12. ' declarations.');
  13. }
  14. // VariableDeclarator always has at least one declaration, hence the non-null-assertion
  15. const id = declarations[0].get('id');
  16. if (id.isIdentifier()) {
  17. return id.node.name;
  18. }
  19. return;
  20. }
  21. if (path.isFunctionDeclaration()) {
  22. const id = path.get('id');
  23. if (id.isIdentifier()) {
  24. return id.node.name;
  25. }
  26. return;
  27. }
  28. if (path.isFunctionExpression() ||
  29. path.isArrowFunctionExpression() ||
  30. path.isTaggedTemplateExpression() ||
  31. path.isCallExpression() ||
  32. isReactForwardRefCall(path)) {
  33. let currentPath = path;
  34. while (currentPath.parentPath) {
  35. if (currentPath.parentPath.isVariableDeclarator()) {
  36. const id = currentPath.parentPath.get('id');
  37. if (id.isIdentifier()) {
  38. return id.node.name;
  39. }
  40. return;
  41. }
  42. currentPath = currentPath.parentPath;
  43. }
  44. return;
  45. }
  46. throw new TypeError('Attempted to resolveName for an unsupported path. resolveName does not accept ' +
  47. path.node.type +
  48. '".');
  49. }
  50. const explodedVisitors = visitors.explode({
  51. AssignmentExpression: {
  52. enter: function (path, state) {
  53. const memberPath = path.get('left');
  54. if (!memberPath.isMemberExpression()) {
  55. return;
  56. }
  57. const property = memberPath.get('property');
  58. if ((!memberPath.node.computed ||
  59. property.isStringLiteral() ||
  60. property.isNumericLiteral()) &&
  61. getNameOrValue(property) === state.memberName &&
  62. toString(memberPath.get('object')) === state.localName) {
  63. state.result = path.get('right');
  64. path.stop();
  65. }
  66. },
  67. },
  68. });
  69. export default function getMemberExpressionValuePath(variableDefinition, memberName) {
  70. const localName = resolveName(variableDefinition);
  71. if (!localName) {
  72. // likely an immediately exported and therefore nameless/anonymous node
  73. // passed in
  74. return null;
  75. }
  76. const state = {
  77. localName,
  78. memberName,
  79. result: null,
  80. };
  81. variableDefinition.hub.file.traverse(explodedVisitors, state);
  82. return state.result;
  83. }