Skip to content

Commit ec161a1

Browse files
fix(api-extractor): preserve export keyword for namespace re-exports
When a namespace contains `export { Foo, Bar };` re-export declarations, api-extractor was incorrectly stripping the `export` keyword, producing `{ Foo, Bar, };` which is syntactically invalid TypeScript (TS1109). This fix checks if an ExportKeyword is part of an ExportDeclaration that is inside a ModuleBlock (namespace body), and if so, preserves it instead of stripping it. Fixes #5516
1 parent 745aec6 commit ec161a1

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

apps/api-extractor/src/generators/ApiReportGenerator.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,23 @@ export class ApiReportGenerator {
302302
break;
303303

304304
case ts.SyntaxKind.ExportKeyword:
305+
// Check if this export keyword is part of an ExportDeclaration inside a namespace
306+
// (e.g., "export { Foo, Bar };" inside "declare namespace SDK { ... }")
307+
// In that case, we must preserve the export keyword, otherwise the output is invalid TypeScript.
308+
if (span.node.parent && ts.isExportDeclaration(span.node.parent)) {
309+
const moduleBlock: ts.ModuleBlock | undefined = TypeScriptHelpers.findFirstParent(
310+
span.node,
311+
ts.SyntaxKind.ModuleBlock
312+
);
313+
if (moduleBlock) {
314+
// This is an export declaration inside a namespace - preserve the export keyword
315+
break;
316+
}
317+
}
318+
// Otherwise, delete the export keyword -- we will re-add it below
319+
span.modification.skipAll();
320+
break;
321+
305322
case ts.SyntaxKind.DefaultKeyword:
306323
case ts.SyntaxKind.DeclareKeyword:
307324
// Delete any explicit "export" or "declare" keywords -- we will re-add them below

apps/api-extractor/src/generators/DtsRollupGenerator.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,23 @@ export class DtsRollupGenerator {
270270
break;
271271

272272
case ts.SyntaxKind.ExportKeyword:
273+
// Check if this export keyword is part of an ExportDeclaration inside a namespace
274+
// (e.g., "export { Foo, Bar };" inside "declare namespace SDK { ... }")
275+
// In that case, we must preserve the export keyword, otherwise the output is invalid TypeScript.
276+
if (span.node.parent && ts.isExportDeclaration(span.node.parent)) {
277+
const moduleBlock: ts.ModuleBlock | undefined = TypeScriptHelpers.findFirstParent(
278+
span.node,
279+
ts.SyntaxKind.ModuleBlock
280+
);
281+
if (moduleBlock) {
282+
// This is an export declaration inside a namespace - preserve the export keyword
283+
break;
284+
}
285+
}
286+
// Otherwise, delete the export keyword -- we will re-add it below
287+
span.modification.skipAll();
288+
break;
289+
273290
case ts.SyntaxKind.DefaultKeyword:
274291
case ts.SyntaxKind.DeclareKeyword:
275292
// Delete any explicit "export" or "declare" keywords -- we will re-add them below

0 commit comments

Comments
 (0)