Skip to content

Commit 62e692f

Browse files
committed
resolveToValue resolves to ImportSpecifiers
1 parent 0641700 commit 62e692f

File tree

8 files changed

+52
-23
lines changed

8 files changed

+52
-23
lines changed

Diff for: .changeset/four-teachers-tan.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'react-docgen': major
3+
---
4+
5+
`resolveToValue` will not resolve to `ImportDeclaration` anymore but instead to
6+
one of the possible specifiers (`ImportSpecifier`, `ImportDefaultSpecifier` or
7+
`ImportNamespaceSpecifier`). This gives better understanding to which specifier
8+
exactly `resolveToValue` did resolve a NodePath to.
9+
10+
Here is a possible easy fix for this in a code snippet that uses
11+
`resolveToValue`
12+
13+
```diff
14+
const resolved = resolveToValue(path);
15+
16+
-if (resolved.isImportDeclaration()) {
17+
+if (resolved.parentPath?.isImportDeclaration()) {
18+
// do smth
19+
}
20+
```

Diff for: packages/react-docgen/src/handlers/defaultPropsHandler.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function getDefaultValue(path: NodePath): DefaultValueDescriptor | null {
3838
} else {
3939
resolvedPath = resolveToValue(path);
4040
}
41-
if (resolvedPath.isImportDeclaration() && path.isIdentifier()) {
41+
if (resolvedPath.parentPath?.isImportDeclaration() && path.isIdentifier()) {
4242
defaultValue = path.node.name;
4343
} else {
4444
valuePath = resolvedPath;

Diff for: packages/react-docgen/src/utils/__tests__/isUnreachableFlowType-test.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ImportDeclaration } from '@babel/types';
12
import { parse } from '../../../tests/utils';
23
import isUnreachableFlowType from '../isUnreachableFlowType.js';
34
import { describe, expect, test } from 'vitest';
@@ -7,10 +8,14 @@ describe('isUnreachableFlowType', () => {
78
expect(isUnreachableFlowType(parse.expression('foo'))).toBe(true);
89
});
910

10-
test('considers ImportDeclaration as unreachable', () => {
11-
expect(isUnreachableFlowType(parse.statement('import x from "";'))).toBe(
12-
true,
13-
);
11+
test('considers any ImportSpecifier as unreachable', () => {
12+
expect(
13+
isUnreachableFlowType(
14+
parse
15+
.statement<ImportDeclaration>('import x from "";')
16+
.get('specifiers')[0],
17+
),
18+
).toBe(true);
1419
});
1520

1621
test('considers CallExpression as unreachable', () => {

Diff for: packages/react-docgen/src/utils/__tests__/resolveToValue-test.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ describe('resolveToValue', () => {
157157
);
158158
const value = resolveToValue(path);
159159

160-
expect(value.node.type).toBe('ImportDeclaration');
160+
expect(value.node.type).toBe('ImportDefaultSpecifier');
161161
});
162162

163163
test('resolves unresolvable named import references to the import declaration', () => {
@@ -166,7 +166,7 @@ describe('resolveToValue', () => {
166166
);
167167
const value = resolveToValue(path);
168168

169-
expect(value.node.type).toBe('ImportDeclaration');
169+
expect(value.node.type).toBe('ImportSpecifier');
170170
});
171171

172172
test('resolves unresolvable aliased import references to the import declaration', () => {
@@ -175,7 +175,7 @@ describe('resolveToValue', () => {
175175
);
176176
const value = resolveToValue(path);
177177

178-
expect(value.node.type).toBe('ImportDeclaration');
178+
expect(value.node.type).toBe('ImportSpecifier');
179179
});
180180

181181
test('resolves unresolvable namespace import references to the import declaration', () => {
@@ -184,7 +184,7 @@ describe('resolveToValue', () => {
184184
);
185185
const value = resolveToValue(path);
186186

187-
expect(value.node.type).toBe('ImportDeclaration');
187+
expect(value.node.type).toBe('ImportNamespaceSpecifier');
188188
});
189189

190190
test('resolves namespace import references to the import declaration', () => {

Diff for: packages/react-docgen/src/utils/getPropType.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ function getEnumValuesFromArrayExpression(
3737
const value = resolveToValue(elementPath as NodePath<Expression>);
3838

3939
return values.push({
40-
value: printValue(value.isImportDeclaration() ? elementPath : value),
40+
value: printValue(
41+
value.parentPath?.isImportDeclaration() ? elementPath : value,
42+
),
4143
computed: !value.isLiteral(),
4244
});
4345
});

Diff for: packages/react-docgen/src/utils/isUnreachableFlowType.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import type { NodePath } from '@babel/traverse';
22

33
/**
44
* Returns true of the path is an unreachable TypePath
5+
* This evaluates the NodePaths returned from resolveToValue
56
*/
67
export default (path: NodePath): boolean => {
78
return (
8-
path.isIdentifier() || path.isImportDeclaration() || path.isCallExpression()
9+
path.isIdentifier() ||
10+
path.parentPath?.isImportDeclaration() ||
11+
path.isCallExpression()
912
);
1013
};

Diff for: packages/react-docgen/src/utils/resolveToModule.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ export default function resolveToModule(path: NodePath): string | null {
3232
}
3333
} else if (path.isObjectProperty() || path.isObjectPattern()) {
3434
return resolveToModule(path.parentPath);
35-
} else if (path.isImportDeclaration()) {
36-
return path.node.source.value;
35+
} else if (path.parentPath?.isImportDeclaration()) {
36+
return path.parentPath.node.source.value;
3737
} else if (path.isMemberExpression()) {
3838
path = getMemberExpressionRoot(path);
3939

Diff for: packages/react-docgen/src/utils/resolveToValue.ts

+9-10
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,17 @@ export default function resolveToValue(path: NodePath): NodePath {
188188
return resolveToValue(memberPath);
189189
}
190190
}
191-
} else if (resolved.isImportDeclaration() && resolved.node.specifiers) {
191+
} else if (
192+
resolved.isImportSpecifier() ||
193+
resolved.isImportDefaultSpecifier() ||
194+
resolved.isImportNamespaceSpecifier()
195+
) {
196+
const declaration = resolved.parentPath as NodePath<ImportDeclaration>;
197+
192198
// Handle references to namespace imports, e.g. import * as foo from 'bar'.
193199
// Try to find a specifier that matches the root of the member expression, and
194200
// find the export that matches the property name.
195-
for (const specifier of resolved.get('specifiers')) {
201+
for (const specifier of declaration.get('specifiers')) {
196202
const property = path.get('property');
197203
let propertyName: string | undefined;
198204

@@ -206,21 +212,14 @@ export default function resolveToValue(path: NodePath): NodePath {
206212
propertyName &&
207213
specifier.node.local.name === root.node.name
208214
) {
209-
const resolvedPath = path.hub.import(resolved, propertyName);
215+
const resolvedPath = path.hub.import(declaration, propertyName);
210216

211217
if (resolvedPath) {
212218
return resolveToValue(resolvedPath);
213219
}
214220
}
215221
}
216222
}
217-
} else if (
218-
path.isImportDefaultSpecifier() ||
219-
path.isImportNamespaceSpecifier() ||
220-
path.isImportSpecifier()
221-
) {
222-
// go up to the import declaration
223-
return path.parentPath;
224223
} else if (
225224
path.isTypeCastExpression() ||
226225
path.isTSAsExpression() ||

0 commit comments

Comments
 (0)