getMethodDocumentation.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import { getDocblock } from './docblock.js';
  2. import getFlowType from './getFlowType.js';
  3. import getTSType from './getTSType.js';
  4. import getParameterName from './getParameterName.js';
  5. import getPropertyName from './getPropertyName.js';
  6. import getTypeAnnotation from './getTypeAnnotation.js';
  7. import resolveToValue from './resolveToValue.js';
  8. import printValue from './printValue.js';
  9. function getMethodFunctionExpression(methodPath) {
  10. if (methodPath.isClassMethod() || methodPath.isObjectMethod()) {
  11. return methodPath;
  12. }
  13. const potentialFunctionExpression = methodPath.isAssignmentExpression()
  14. ? methodPath.get('right')
  15. : methodPath.get('value');
  16. const functionExpression = resolveToValue(potentialFunctionExpression);
  17. if (functionExpression.isFunction()) {
  18. return functionExpression;
  19. }
  20. return null;
  21. }
  22. function getMethodParamOptional(path) {
  23. let identifier = path;
  24. if (identifier.isTSParameterProperty()) {
  25. identifier = identifier.get('parameter');
  26. }
  27. if (identifier.isAssignmentPattern()) {
  28. // A default value always makes the param optional
  29. return true;
  30. }
  31. return identifier.isIdentifier() ? Boolean(identifier.node.optional) : false;
  32. }
  33. function getMethodParamsDoc(methodPath) {
  34. const params = [];
  35. const functionExpression = getMethodFunctionExpression(methodPath);
  36. if (functionExpression) {
  37. // Extract param types.
  38. functionExpression.get('params').forEach((paramPath) => {
  39. let type = null;
  40. const typePath = getTypeAnnotation(paramPath);
  41. if (typePath) {
  42. if (typePath.isFlowType()) {
  43. type = getFlowType(typePath, null);
  44. if (typePath.isGenericTypeAnnotation()) {
  45. type.alias = printValue(typePath.get('id'));
  46. }
  47. }
  48. else if (typePath.isTSType()) {
  49. type = getTSType(typePath, null);
  50. if (typePath.isTSTypeReference()) {
  51. type.alias = printValue(typePath.get('typeName'));
  52. }
  53. }
  54. }
  55. const param = {
  56. name: getParameterName(paramPath),
  57. optional: getMethodParamOptional(paramPath),
  58. type,
  59. };
  60. params.push(param);
  61. });
  62. }
  63. return params;
  64. }
  65. // Extract flow return type.
  66. function getMethodReturnDoc(methodPath) {
  67. const functionExpression = getMethodFunctionExpression(methodPath);
  68. if (functionExpression && functionExpression.node.returnType) {
  69. const returnType = getTypeAnnotation(functionExpression.get('returnType'));
  70. if (!returnType) {
  71. return null;
  72. }
  73. if (returnType.isFlowType()) {
  74. return { type: getFlowType(returnType, null) };
  75. }
  76. else if (returnType.isTSType()) {
  77. return { type: getTSType(returnType, null) };
  78. }
  79. }
  80. return null;
  81. }
  82. function getMethodModifiers(methodPath, options) {
  83. if (methodPath.isAssignmentExpression()) {
  84. return ['static'];
  85. }
  86. // Otherwise this is a method/property node
  87. const modifiers = [];
  88. if (options.isStatic === true ||
  89. ((methodPath.isClassProperty() || methodPath.isClassMethod()) &&
  90. methodPath.node.static)) {
  91. modifiers.push('static');
  92. }
  93. const functionExpression = getMethodFunctionExpression(methodPath);
  94. if (functionExpression) {
  95. if (functionExpression.isClassMethod() ||
  96. functionExpression.isObjectMethod()) {
  97. if (functionExpression.node.kind === 'get' ||
  98. functionExpression.node.kind === 'set') {
  99. modifiers.push(functionExpression.node.kind);
  100. }
  101. }
  102. if (functionExpression.node.generator) {
  103. modifiers.push('generator');
  104. }
  105. if (functionExpression.node.async) {
  106. modifiers.push('async');
  107. }
  108. }
  109. return modifiers;
  110. }
  111. function getMethodName(methodPath) {
  112. if (methodPath.isAssignmentExpression()) {
  113. const left = methodPath.get('left');
  114. if (left.isMemberExpression()) {
  115. const property = left.get('property');
  116. if (!left.node.computed && property.isIdentifier()) {
  117. return property.node.name;
  118. }
  119. if (property.isStringLiteral() || property.isNumericLiteral()) {
  120. return String(property.node.value);
  121. }
  122. }
  123. return null;
  124. }
  125. return getPropertyName(methodPath);
  126. }
  127. function getMethodAccessibility(methodPath) {
  128. if (methodPath.isClassMethod() || methodPath.isClassProperty()) {
  129. return methodPath.node.accessibility || null;
  130. }
  131. // Otherwise this is a object method/property or assignment expression
  132. return null;
  133. }
  134. function getMethodDocblock(methodPath) {
  135. if (methodPath.isAssignmentExpression()) {
  136. let path = methodPath;
  137. do {
  138. path = path.parentPath;
  139. } while (path && !path.isExpressionStatement());
  140. if (path) {
  141. return getDocblock(path);
  142. }
  143. return null;
  144. }
  145. // Otherwise this is a method/property node
  146. return getDocblock(methodPath);
  147. }
  148. // Gets the documentation object for a component method.
  149. // Component methods may be represented as class/object method/property nodes
  150. // or as assignment expression of the form `Component.foo = function() {}`
  151. export default function getMethodDocumentation(methodPath, options = {}) {
  152. if (getMethodAccessibility(methodPath) === 'private' ||
  153. methodPath.isClassPrivateMethod()) {
  154. return null;
  155. }
  156. const name = getMethodName(methodPath);
  157. if (!name)
  158. return null;
  159. return {
  160. name,
  161. docblock: getMethodDocblock(methodPath),
  162. modifiers: getMethodModifiers(methodPath, options),
  163. params: getMethodParamsDoc(methodPath),
  164. returns: getMethodReturnDoc(methodPath),
  165. };
  166. }