Skip to content

Commit 47f1e89

Browse files
committed
Detect exports in namespaces
1 parent 6d78350 commit 47f1e89

File tree

7 files changed

+181
-23
lines changed

7 files changed

+181
-23
lines changed

src/parsers/exportParser.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,33 @@ import { ExportNode } from '../models';
77
export function parseExport(
88
exportSymbol: ts.Symbol,
99
parserContext: ParserContext,
10-
): ExportNode | undefined {
10+
parentNamespaces: string[] = [],
11+
): ExportNode[] | undefined {
1112
const { checker, sourceFile } = parserContext;
1213

1314
const exportDeclaration = exportSymbol.declarations?.[0];
1415
if (!exportDeclaration) {
1516
return;
1617
}
1718

19+
if (ts.isModuleDeclaration(exportDeclaration)) {
20+
// Handle exported namespace
21+
const namespaceSymbol = checker.getSymbolAtLocation(exportDeclaration.name);
22+
if (!namespaceSymbol) return;
23+
const members = checker.getExportsOfModule(namespaceSymbol);
24+
const nsName = exportDeclaration.name.getText();
25+
const results: ExportNode[] = [];
26+
for (const member of members) {
27+
const memberExports = parseExport(member, parserContext, [...parentNamespaces, nsName]);
28+
if (Array.isArray(memberExports)) {
29+
results.push(...memberExports);
30+
} else if (memberExports) {
31+
results.push(memberExports);
32+
}
33+
}
34+
return results;
35+
}
36+
1837
if (ts.isExportSpecifier(exportDeclaration)) {
1938
// export { x }
2039
// export { x as y }
@@ -38,7 +57,7 @@ export function parseExport(
3857
}
3958

4059
const type = checker.getTypeOfSymbol(targetSymbol);
41-
return createExportNode(exportSymbol.name, targetSymbol, type);
60+
return createExportNode(exportSymbol.name, targetSymbol, type, parentNamespaces);
4261
} else if (ts.isExportAssignment(exportDeclaration)) {
4362
// export default x
4463
const exportedSymbol = checker.getSymbolAtLocation(exportDeclaration.expression);
@@ -51,6 +70,7 @@ export function parseExport(
5170
exportSymbol.name,
5271
exportedSymbol,
5372
checker.getTypeOfSymbol(exportedSymbol),
73+
parentNamespaces,
5474
);
5575
} else if (
5676
ts.isVariableDeclaration(exportDeclaration) ||
@@ -69,7 +89,7 @@ export function parseExport(
6989
}
7090

7191
const type = checker.getTypeOfSymbol(exportedSymbol);
72-
return createExportNode(exportSymbol.name, exportedSymbol, type);
92+
return createExportNode(exportSymbol.name, exportedSymbol, type, parentNamespaces);
7393
} else if (ts.isEnumDeclaration(exportDeclaration)) {
7494
// export enum x {}
7595
if (!exportDeclaration.name) {
@@ -87,13 +107,22 @@ export function parseExport(
87107
}
88108

89109
const type = checker.getTypeAtLocation(exportedSymbol.declarations[0]);
90-
return createExportNode(exportSymbol.name, exportedSymbol, type);
110+
return createExportNode(exportSymbol.name, exportedSymbol, type, parentNamespaces);
91111
}
92112

93-
function createExportNode(name: string, symbol: ts.Symbol, type: ts.Type) {
113+
function createExportNode(
114+
name: string,
115+
symbol: ts.Symbol,
116+
type: ts.Type,
117+
parentNamespaces: string[],
118+
) {
94119
const parsedType = resolveType(type, symbol.getName(), parserContext);
95120
if (parsedType) {
96-
return new ExportNode(name, parsedType, getDocumentationFromSymbol(symbol, checker));
121+
// Patch parentNamespaces if the type supports it
122+
if (parsedType && 'parentNamespaces' in parsedType) {
123+
parsedType.parentNamespaces = parentNamespaces;
124+
}
125+
return [new ExportNode(name, parsedType, getDocumentationFromSymbol(symbol, checker))];
97126
}
98127
}
99128
}

src/parsers/moduleParser.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ export function parseModule(sourceFile: ts.SourceFile, context: ParserContext):
2020
if (!parsedExport) {
2121
continue;
2222
}
23-
24-
parsedModuleExports.push(parsedExport);
23+
if (Array.isArray(parsedExport)) {
24+
parsedModuleExports.push(...parsedExport);
25+
} else {
26+
parsedModuleExports.push(parsedExport);
27+
}
2528
}
2629

2730
parsedModuleExports = augmentComponentNodes(parsedModuleExports, context);

test/base-ui-component/output.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
"type": {
77
"kind": "component",
88
"name": "ForwardRefExoticComponent",
9-
"parentNamespaces": [
10-
"React"
11-
],
9+
"parentNamespaces": [],
1210
"props": [
1311
{
1412
"name": "value",

test/component-function-variable/output.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@
5656
"type": {
5757
"kind": "component",
5858
"name": "FC",
59-
"parentNamespaces": [
60-
"React"
61-
],
59+
"parentNamespaces": [],
6260
"props": [
6361
{
6462
"name": "className",
@@ -108,9 +106,7 @@
108106
"type": {
109107
"kind": "component",
110108
"name": "FunctionComponent",
111-
"parentNamespaces": [
112-
"React"
113-
],
109+
"parentNamespaces": [],
114110
"props": [
115111
{
116112
"name": "className",

test/forwardRef/output.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
"type": {
77
"kind": "component",
88
"name": "ForwardRefExoticComponent",
9-
"parentNamespaces": [
10-
"React"
11-
],
9+
"parentNamespaces": [],
1210
"props": [
1311
{
1412
"name": "className",

test/memo/output.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
"type": {
77
"kind": "component",
88
"name": "NamedExoticComponent",
9-
"parentNamespaces": [
10-
"React"
11-
],
9+
"parentNamespaces": [],
1210
"props": [
1311
{
1412
"name": "className",

test/namespaces/output.json

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,142 @@
5555
}
5656
]
5757
}
58+
},
59+
{
60+
"name": "fn2",
61+
"type": {
62+
"kind": "function",
63+
"name": "fn2",
64+
"parentNamespaces": [
65+
"Root"
66+
],
67+
"callSignatures": [
68+
{
69+
"parameters": [],
70+
"returnValueType": {
71+
"kind": "intrinsic",
72+
"parentNamespaces": [],
73+
"name": "void"
74+
}
75+
}
76+
]
77+
}
78+
},
79+
{
80+
"name": "fn1",
81+
"type": {
82+
"kind": "function",
83+
"name": "fn1",
84+
"parentNamespaces": [
85+
"Root",
86+
"Sub"
87+
],
88+
"callSignatures": [
89+
{
90+
"parameters": [
91+
{
92+
"type": {
93+
"kind": "object",
94+
"name": "Params",
95+
"parentNamespaces": [
96+
"Root",
97+
"Sub"
98+
],
99+
"properties": [
100+
{
101+
"name": "s",
102+
"type": {
103+
"kind": "enum",
104+
"name": "Grade",
105+
"parentNamespaces": [
106+
"Root",
107+
"Sub"
108+
],
109+
"members": [
110+
{
111+
"name": "good",
112+
"value": 0
113+
},
114+
{
115+
"name": "bad",
116+
"value": 1
117+
}
118+
]
119+
},
120+
"optional": false
121+
}
122+
]
123+
},
124+
"name": "params",
125+
"optional": false
126+
}
127+
],
128+
"returnValueType": {
129+
"kind": "intrinsic",
130+
"parentNamespaces": [],
131+
"name": "void"
132+
}
133+
}
134+
]
135+
}
136+
},
137+
{
138+
"name": "Component",
139+
"type": {
140+
"kind": "component",
141+
"name": "Component",
142+
"parentNamespaces": [
143+
"Root",
144+
"Sub"
145+
],
146+
"props": []
147+
}
148+
},
149+
{
150+
"name": "useHook",
151+
"type": {
152+
"kind": "function",
153+
"name": "useHook",
154+
"parentNamespaces": [
155+
"Root",
156+
"Sub"
157+
],
158+
"callSignatures": [
159+
{
160+
"parameters": [],
161+
"returnValueType": {
162+
"kind": "object",
163+
"name": "__object",
164+
"parentNamespaces": [
165+
"Root",
166+
"Sub"
167+
],
168+
"properties": []
169+
}
170+
}
171+
]
172+
}
173+
},
174+
{
175+
"name": "Grade",
176+
"type": {
177+
"kind": "enum",
178+
"name": "Grade",
179+
"parentNamespaces": [
180+
"Root",
181+
"Sub"
182+
],
183+
"members": [
184+
{
185+
"name": "good",
186+
"value": 0
187+
},
188+
{
189+
"name": "bad",
190+
"value": 1
191+
}
192+
]
193+
}
58194
}
59195
]
60196
}

0 commit comments

Comments
 (0)