Skip to content

Commit e956802

Browse files
authored
Remove match utility and cleanup code (#744)
1 parent 5215bab commit e956802

17 files changed

+136
-126
lines changed

.changeset/lazy-lions-dress.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'react-docgen': major
3+
---
4+
5+
Remove match utility.
6+
7+
The utility can be replaced by babel helpers and is not needed anymore. Also
8+
using explicit checks like `path.isMemberExpression()` is better for type safety
9+
and catching potential bugs.

packages/react-docgen/src/handlers/componentMethodsHandler.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ const explodedVisitors = visitors.explode<TraverseState>({
6666
if (
6767
binding &&
6868
left.isMemberExpression() &&
69-
left.get('object').isIdentifier() &&
70-
(left.node.object as Identifier).name === name &&
69+
left.get('object').isIdentifier({ name }) &&
7170
binding.scope === scope &&
7271
resolveToValue(assignmentPath.get('right')).isFunction()
7372
) {

packages/react-docgen/src/importer/makeFsImporter.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { dirname, extname } from 'path';
44
import fs from 'fs';
55
import type { NodePath } from '@babel/traverse';
66
import { visitors } from '@babel/traverse';
7-
import type { ExportSpecifier, Identifier, ObjectProperty } from '@babel/types';
7+
import type { ExportSpecifier, ObjectProperty } from '@babel/types';
88
import type { Importer, ImportPath } from './index.js';
99
import type FileState from '../FileState.js';
1010
import { resolveObjectPatternPropertyToValue } from '../utils/index.js';
@@ -164,7 +164,7 @@ export default function makeFsImporter(
164164
const id = declPath.get('id');
165165
const init = declPath.get('init');
166166

167-
if (id.isIdentifier() && id.node.name === name && init.hasNode()) {
167+
if (id.isIdentifier({ name }) && init.hasNode()) {
168168
// export const/var a = <init>
169169

170170
state.resultPath = init;
@@ -177,7 +177,7 @@ export default function makeFsImporter(
177177
if (prop.isObjectProperty()) {
178178
const value = prop.get('value');
179179

180-
return value.isIdentifier() && value.node.name === name;
180+
return value.isIdentifier({ name });
181181
}
182182
// We don't handle RestElement here yet as complicated
183183

@@ -197,8 +197,7 @@ export default function makeFsImporter(
197197
} else if (
198198
declaration.hasNode() &&
199199
declaration.has('id') &&
200-
(declaration.get('id') as NodePath).isIdentifier() &&
201-
(declaration.get('id') as NodePath<Identifier>).node.name === name
200+
(declaration.get('id') as NodePath).isIdentifier({ name })
202201
) {
203202
// export function/class/type/interface/enum ...
204203

@@ -212,7 +211,7 @@ export default function makeFsImporter(
212211
}
213212
const exported = specifierPath.get('exported');
214213

215-
if (exported.isIdentifier() && exported.node.name === name) {
214+
if (exported.isIdentifier({ name })) {
216215
// export ... from ''
217216
if (path.has('source')) {
218217
const local = specifierPath.isExportSpecifier()
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { parse } from '../../../tests/utils';
2+
import isReactChildrenElementCall from '../isReactChildrenElementCall.js';
3+
import { describe, expect, test } from 'vitest';
4+
5+
describe('isReactChildrenElementCall', () => {
6+
describe('true', () => {
7+
test('React.Children.map', () => {
8+
const def = parse.expressionLast(`
9+
var React = require("React");
10+
React.Children.map(() => {});
11+
`);
12+
13+
expect(isReactChildrenElementCall(def)).toBe(true);
14+
});
15+
16+
test('React.Children.only', () => {
17+
const def = parse.expressionLast(`
18+
var React = require("React");
19+
React.Children.only(() => {});
20+
`);
21+
22+
expect(isReactChildrenElementCall(def)).toBe(true);
23+
});
24+
});
25+
describe('false', () => {
26+
test('not call expression', () => {
27+
const def = parse.expressionLast(`
28+
var React = require("React");
29+
React.Children.map;
30+
`);
31+
32+
expect(isReactChildrenElementCall(def)).toBe(false);
33+
});
34+
35+
test('not MemberExpression', () => {
36+
const def = parse.expressionLast(`
37+
var React = require("React");
38+
map();
39+
`);
40+
41+
expect(isReactChildrenElementCall(def)).toBe(false);
42+
});
43+
44+
test('not only or map', () => {
45+
const def = parse.expressionLast(`
46+
var React = require("React");
47+
React.Children.abc(() => {});
48+
`);
49+
50+
expect(isReactChildrenElementCall(def)).toBe(false);
51+
});
52+
53+
test('not double MemberExpression', () => {
54+
const def = parse.expressionLast(`
55+
var React = require("React");
56+
Children.map(() => {});
57+
`);
58+
59+
expect(isReactChildrenElementCall(def)).toBe(false);
60+
});
61+
62+
test('not Children', () => {
63+
const def = parse.expressionLast(`
64+
var React = require("React");
65+
React.Parent.map(() => {});
66+
`);
67+
68+
expect(isReactChildrenElementCall(def)).toBe(false);
69+
});
70+
71+
test('not react module', () => {
72+
const def = parse.expressionLast(`
73+
var React = require("test");
74+
React.Children.map(() => {});
75+
`);
76+
77+
expect(isReactChildrenElementCall(def)).toBe(false);
78+
});
79+
});
80+
});

packages/react-docgen/src/utils/__tests__/match-test.ts

Lines changed: 0 additions & 36 deletions
This file was deleted.

packages/react-docgen/src/utils/getFlowType.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,7 @@ function handleGenericTypeAnnotation(
124124
const id = path.get('id');
125125
const typeParameters = path.get('typeParameters');
126126

127-
if (
128-
id.isIdentifier() &&
129-
id.node.name === '$Keys' &&
130-
typeParameters.hasNode()
131-
) {
127+
if (id.isIdentifier({ name: '$Keys' }) && typeParameters.hasNode()) {
132128
return handleKeysHelper(path);
133129
}
134130

@@ -137,7 +133,7 @@ function handleGenericTypeAnnotation(
137133
if (id.isQualifiedTypeIdentifier()) {
138134
const qualification = id.get('qualification');
139135

140-
if (qualification.isIdentifier() && qualification.node.name === 'React') {
136+
if (qualification.isIdentifier({ name: 'React' })) {
141137
type = {
142138
name: `${qualification.node.name}${id.node.id.name}`,
143139
raw: printValue(id),
@@ -391,7 +387,7 @@ function getFlowTypeWithResolvedTypes(
391387

392388
const isTypeAlias = parent.isTypeAlias();
393389

394-
// When we see a typealias mark it as visited so that the next
390+
// When we see a TypeAlias mark it as visited so that the next
395391
// call of this function does not run into an endless loop
396392
if (isTypeAlias) {
397393
if (visitedTypes[parent.node.id.name] === true) {

packages/react-docgen/src/utils/getTSType.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,7 @@ function handleTSTypeReference(
9090
const left = typeName.get('left');
9191
const right = typeName.get('right');
9292

93-
if (
94-
left.isIdentifier() &&
95-
left.node.name === 'React' &&
96-
right.isIdentifier()
97-
) {
93+
if (left.isIdentifier({ name: 'React' }) && right.isIdentifier()) {
9894
type = {
9995
name: `${left.node.name}${right.node.name}`,
10096
raw: printValue(typeName),

packages/react-docgen/src/utils/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ export { default as isReactModuleName } from './isReactModuleName.js';
4848
export { default as isRequiredPropType } from './isRequiredPropType.js';
4949
export { default as isStatelessComponent } from './isStatelessComponent.js';
5050
export { default as isUnreachableFlowType } from './isUnreachableFlowType.js';
51-
export { default as match } from './match.js';
5251
export { default as normalizeClassDefinition } from './normalizeClassDefinition.js';
5352
export { default as parseJsDoc } from './parseJsDoc.js';
5453
export { default as postProcessDocumentation } from './postProcessDocumentation.js';

packages/react-docgen/src/utils/isDestructuringAssignment.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,5 @@ export default function isDestructuringAssignment(
1414

1515
const id = path.get('key');
1616

17-
return (
18-
id.isIdentifier() &&
19-
id.node.name === name &&
20-
path.parentPath.isObjectPattern()
21-
);
17+
return id.isIdentifier({ name }) && path.parentPath.isObjectPattern();
2218
}

packages/react-docgen/src/utils/isReactBuiltinCall.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import isReactModuleName from './isReactModuleName.js';
2-
import match from './match.js';
32
import resolveToModule from './resolveToModule.js';
43
import resolveToValue from './resolveToValue.js';
54
import isDestructuringAssignment from './isDestructuringAssignment.js';
65
import type { NodePath } from '@babel/traverse';
7-
import type { CallExpression, MemberExpression } from '@babel/types';
6+
import type { CallExpression } from '@babel/types';
87

98
function isNamedMemberExpression(value: NodePath, name: string): boolean {
109
if (!value.isMemberExpression()) {
@@ -33,8 +32,8 @@ function isNamedImportDeclaration(
3332
const local = specifier.get('local');
3433

3534
return (
36-
((imported.isIdentifier() && imported.node.name === name) ||
37-
(imported.isStringLiteral() && imported.node.value === name)) &&
35+
(imported.isIdentifier({ name }) ||
36+
imported.isStringLiteral({ value: name })) &&
3837
local.node.name === callee.node.name
3938
);
4039
});
@@ -53,17 +52,20 @@ export default function isReactBuiltinCall(
5352
}
5453

5554
if (path.isCallExpression()) {
56-
if (match(path.node, { callee: { property: { name } } })) {
57-
const module = resolveToModule(
58-
(path.get('callee') as NodePath<MemberExpression>).get('object'),
59-
);
55+
const callee = path.get('callee');
56+
57+
if (
58+
callee.isMemberExpression() &&
59+
callee.get('property').isIdentifier({ name })
60+
) {
61+
const module = resolveToModule(callee.get('object'));
6062

6163
return Boolean(module && isReactModuleName(module));
6264
}
6365

64-
const value = resolveToValue(path.get('callee'));
66+
const value = resolveToValue(callee);
6567

66-
if (value === path.get('callee')) {
68+
if (value === callee) {
6769
return false;
6870
}
6971

@@ -73,7 +75,7 @@ export default function isReactBuiltinCall(
7375
// `require('react').createElement`
7476
isNamedMemberExpression(value, name) ||
7577
// `import { createElement } from 'react'`
76-
isNamedImportDeclaration(value, path.get('callee'), name)
78+
isNamedImportDeclaration(value, callee, name)
7779
) {
7880
const module = resolveToModule(value);
7981

packages/react-docgen/src/utils/isReactChildrenElementCall.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,36 @@
11
import type { NodePath } from '@babel/traverse';
2-
import type { MemberExpression } from '@babel/types';
32
import isReactModuleName from './isReactModuleName.js';
4-
import match from './match.js';
53
import resolveToModule from './resolveToModule.js';
64

7-
// TODO unit tests
8-
95
/**
106
* Returns true if the expression is a function call of the form
11-
* `React.Children.only(...)`.
7+
* `React.Children.only(...)` or `React.Children.map(...)`.
128
*/
139
export default function isReactChildrenElementCall(path: NodePath): boolean {
1410
if (path.isExpressionStatement()) {
1511
path = path.get('expression');
1612
}
1713

14+
if (!path.isCallExpression()) {
15+
return false;
16+
}
17+
18+
const callee = path.get('callee');
19+
1820
if (
19-
!match(path.node, { callee: { property: { name: 'only' } } }) &&
20-
!match(path.node, { callee: { property: { name: 'map' } } })
21+
!callee.isMemberExpression() ||
22+
(!callee.get('property').isIdentifier({ name: 'only' }) &&
23+
!callee.get('property').isIdentifier({ name: 'map' }))
2124
) {
2225
return false;
2326
}
2427

25-
const calleeObj = (path.get('callee') as NodePath<MemberExpression>).get(
26-
'object',
27-
);
28+
const calleeObj = callee.get('object');
2829

29-
if (!match(calleeObj.node, { property: { name: 'Children' } })) {
30+
if (
31+
!calleeObj.isMemberExpression() ||
32+
!calleeObj.get('property').isIdentifier({ name: 'Children' })
33+
) {
3034
return false;
3135
}
3236

packages/react-docgen/src/utils/isRequiredPropType.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ import getMembers from '../utils/getMembers.js';
77
export default function isRequiredPropType(path: NodePath<Node>): boolean {
88
return getMembers(path).some(
99
({ computed, path: memberPath }) =>
10-
(!computed &&
11-
memberPath.isIdentifier() &&
12-
memberPath.node.name === 'isRequired') ||
13-
(memberPath.isStringLiteral() && memberPath.node.value === 'isRequired'),
10+
(!computed && memberPath.isIdentifier({ name: 'isRequired' })) ||
11+
memberPath.isStringLiteral({ value: 'isRequired' }),
1412
);
1513
}

packages/react-docgen/src/utils/match.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)