• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

reactjs / react-docgen / 12954943867

24 Jan 2025 05:58PM CUT coverage: 96.391% (+0.01%) from 96.38%
12954943867

Pull #969

github

web-flow
Merge 27a26da4a into f9fc65e9c
Pull Request #969: Expose more Typescript types

1378 of 1478 branches covered (93.23%)

Branch coverage included in aggregate %.

46 of 46 new or added lines in 1 file covered. (100.0%)

7196 of 7417 relevant lines covered (97.02%)

433.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.72
/packages/react-docgen/src/utils/getMethodDocumentation.ts
1
import type { NodePath } from '@babel/traverse';
3✔
2
import type {
3✔
3
  AssignmentExpression,
3✔
4
  ClassMethod,
3✔
5
  ClassPrivateMethod,
3✔
6
  ClassProperty,
3✔
7
  Function as FunctionType,
3✔
8
  ObjectMethod,
3✔
9
  ObjectProperty,
3✔
10
} from '@babel/types';
3✔
11
import { getDocblock } from './docblock.js';
3✔
12
import getFlowType from './getFlowType.js';
3✔
13
import getTSType from './getTSType.js';
3✔
14
import getParameterName from './getParameterName.js';
3✔
15
import getPropertyName from './getPropertyName.js';
3✔
16
import getTypeAnnotation from './getTypeAnnotation.js';
3✔
17
import resolveToValue from './resolveToValue.js';
3✔
18
import printValue from './printValue.js';
3✔
19
import type {
3✔
20
  MethodDescriptor,
3✔
21
  MethodModifier,
3✔
22
  MethodParameter,
3✔
23
  MethodReturn,
3✔
24
  TypeDescriptor,
3✔
25
} from '../Documentation.js';
3✔
26

3✔
27
export type MethodNodePath =
3✔
28
  | NodePath<AssignmentExpression>
3✔
29
  | NodePath<ClassMethod>
3✔
30
  | NodePath<ClassPrivateMethod>
3✔
31
  | NodePath<ClassProperty>
3✔
32
  | NodePath<ObjectMethod>
3✔
33
  | NodePath<ObjectProperty>;
3✔
34

3✔
35
function getMethodFunctionExpression(
585✔
36
  methodPath: MethodNodePath,
585✔
37
): NodePath<FunctionType> | null {
585✔
38
  if (methodPath.isClassMethod() || methodPath.isObjectMethod()) {
585✔
39
    return methodPath;
279✔
40
  }
279✔
41

306✔
42
  const potentialFunctionExpression = methodPath.isAssignmentExpression()
306✔
43
    ? methodPath.get('right')
72✔
44
    : (methodPath.get('value') as NodePath);
234✔
45

585✔
46
  const functionExpression = resolveToValue(potentialFunctionExpression);
585✔
47

585✔
48
  if (functionExpression.isFunction()) {
585✔
49
    return functionExpression;
306✔
50
  }
306!
51

×
52
  return null;
×
53
}
×
54

3✔
55
function getMethodParamOptional(
63✔
56
  path: NodePath<FunctionType['params'][number]>,
63✔
57
): boolean {
63✔
58
  let identifier: NodePath = path;
63✔
59

63✔
60
  if (identifier.isTSParameterProperty()) {
63!
61
    identifier = identifier.get('parameter');
×
62
  }
×
63
  if (identifier.isAssignmentPattern()) {
63!
64
    // A default value always makes the param optional
×
65
    return true;
×
66
  }
×
67

63✔
68
  return identifier.isIdentifier() ? Boolean(identifier.node.optional) : false;
63✔
69
}
63✔
70

3✔
71
function getMethodParamsDoc(methodPath: MethodNodePath): MethodParameter[] {
207✔
72
  const params: MethodParameter[] = [];
207✔
73
  const functionExpression = getMethodFunctionExpression(methodPath);
207✔
74

207✔
75
  if (functionExpression) {
207✔
76
    // Extract param types.
207✔
77
    functionExpression.get('params').forEach((paramPath) => {
207✔
78
      let type: TypeDescriptor | null = null;
63✔
79
      const typePath = getTypeAnnotation(paramPath);
63✔
80

63✔
81
      if (typePath) {
63✔
82
        if (typePath.isFlowType()) {
60✔
83
          type = getFlowType(typePath, null);
48✔
84
          if (typePath.isGenericTypeAnnotation()) {
48✔
85
            type.alias = printValue(typePath.get('id'));
3✔
86
          }
3✔
87
        } else if (typePath.isTSType()) {
60✔
88
          type = getTSType(typePath, null);
12✔
89
          if (typePath.isTSTypeReference()) {
12✔
90
            type.alias = printValue(typePath.get('typeName'));
3✔
91
          }
3✔
92
        }
12✔
93
      }
60✔
94

63✔
95
      const param = {
63✔
96
        name: getParameterName(paramPath),
63✔
97
        optional: getMethodParamOptional(paramPath),
63✔
98
        type,
63✔
99
      };
63✔
100

63✔
101
      params.push(param);
63✔
102
    });
207✔
103
  }
207✔
104

207✔
105
  return params;
207✔
106
}
207✔
107

3✔
108
// Extract flow return type.
3✔
109
function getMethodReturnDoc(methodPath: MethodNodePath): MethodReturn | null {
207✔
110
  const functionExpression = getMethodFunctionExpression(methodPath);
207✔
111

207✔
112
  if (functionExpression && functionExpression.node.returnType) {
207✔
113
    const returnType = getTypeAnnotation(functionExpression.get('returnType'));
51✔
114

51✔
115
    if (!returnType) {
51!
116
      return null;
×
117
    }
×
118

51✔
119
    if (returnType.isFlowType()) {
51✔
120
      return { type: getFlowType(returnType, null) };
45✔
121
    } else if (returnType.isTSType()) {
45✔
122
      return { type: getTSType(returnType, null) };
6✔
123
    }
6✔
124
  }
51✔
125

156✔
126
  return null;
156✔
127
}
156✔
128

3✔
129
function getMethodModifiers(
207✔
130
  methodPath: MethodNodePath,
207✔
131
  options: { isStatic?: boolean },
207✔
132
): MethodModifier[] {
207✔
133
  if (methodPath.isAssignmentExpression()) {
207✔
134
    return ['static'];
36✔
135
  }
36✔
136

171✔
137
  // Otherwise this is a method/property node
171✔
138

171✔
139
  const modifiers: MethodModifier[] = [];
171✔
140

171✔
141
  if (
171✔
142
    options.isStatic === true ||
171✔
143
    ((methodPath.isClassProperty() || methodPath.isClassMethod()) &&
162✔
144
      methodPath.node.static)
117✔
145
  ) {
207✔
146
    modifiers.push('static');
27✔
147
  }
27✔
148

171✔
149
  const functionExpression = getMethodFunctionExpression(methodPath);
171✔
150

171✔
151
  if (functionExpression) {
171✔
152
    if (
171✔
153
      functionExpression.isClassMethod() ||
171✔
154
      functionExpression.isObjectMethod()
93✔
155
    ) {
171✔
156
      if (
93✔
157
        functionExpression.node.kind === 'get' ||
93✔
158
        functionExpression.node.kind === 'set'
87✔
159
      ) {
93✔
160
        modifiers.push(functionExpression.node.kind);
6✔
161
      }
6✔
162
    }
93✔
163

171✔
164
    if (functionExpression.node.generator) {
171✔
165
      modifiers.push('generator');
3✔
166
    }
3✔
167
    if (functionExpression.node.async) {
171✔
168
      modifiers.push('async');
6✔
169
    }
6✔
170
  }
171✔
171

171✔
172
  return modifiers;
171✔
173
}
171✔
174

3✔
175
function getMethodName(
216✔
176
  methodPath: Exclude<MethodNodePath, NodePath<ClassPrivateMethod>>,
216✔
177
): string | null {
216✔
178
  if (methodPath.isAssignmentExpression()) {
216✔
179
    const left = methodPath.get('left');
36✔
180

36✔
181
    if (left.isMemberExpression()) {
36✔
182
      const property = left.get('property');
36✔
183

36✔
184
      if (!left.node.computed && property.isIdentifier()) {
36✔
185
        return property.node.name;
36✔
186
      }
36!
187
      if (property.isStringLiteral() || property.isNumericLiteral()) {
36!
188
        return String(property.node.value);
×
189
      }
×
190
    }
36!
191

×
192
    return null;
×
193
  }
✔
194

180✔
195
  return getPropertyName(methodPath);
180✔
196
}
180✔
197

3✔
198
function getMethodAccessibility(
225✔
199
  methodPath: MethodNodePath,
225✔
200
): 'private' | 'protected' | 'public' | null {
225✔
201
  if (methodPath.isClassMethod() || methodPath.isClassProperty()) {
225✔
202
    return methodPath.node.accessibility || null;
132✔
203
  }
132✔
204

93✔
205
  // Otherwise this is a object method/property or assignment expression
93✔
206
  return null;
93✔
207
}
93✔
208

3✔
209
function getMethodDocblock(methodPath: MethodNodePath): string | null {
207✔
210
  if (methodPath.isAssignmentExpression()) {
207✔
211
    let path: NodePath | null = methodPath;
36✔
212

36✔
213
    do {
36✔
214
      path = path.parentPath;
36✔
215
    } while (path && !path.isExpressionStatement());
36✔
216

36✔
217
    if (path) {
36✔
218
      return getDocblock(path);
36✔
219
    }
36!
220

×
221
    return null;
×
222
  }
✔
223

171✔
224
  // Otherwise this is a method/property node
171✔
225
  return getDocblock(methodPath);
171✔
226
}
171✔
227

3✔
228
// Gets the documentation object for a component method.
3✔
229
// Component methods may be represented as class/object method/property nodes
3✔
230
// or as assignment expression of the form `Component.foo = function() {}`
3✔
231
export default function getMethodDocumentation(
225✔
232
  methodPath: MethodNodePath,
225✔
233
  options: { isStatic?: boolean } = {},
225✔
234
): MethodDescriptor | null {
225✔
235
  if (
225✔
236
    getMethodAccessibility(methodPath) === 'private' ||
225✔
237
    methodPath.isClassPrivateMethod()
219✔
238
  ) {
225✔
239
    return null;
9✔
240
  }
9✔
241

216✔
242
  const name = getMethodName(methodPath);
216✔
243

216✔
244
  if (!name) return null;
225✔
245

207✔
246
  return {
207✔
247
    name,
207✔
248
    docblock: getMethodDocblock(methodPath),
207✔
249
    modifiers: getMethodModifiers(methodPath, options),
207✔
250
    params: getMethodParamsDoc(methodPath),
207✔
251
    returns: getMethodReturnDoc(methodPath),
207✔
252
  };
207✔
253
}
207✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc