Skip to content

Conversation

@ItsChrisHickman
Copy link

Summary

Fixes #5516

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.

Input:

export declare namespace SDK {
  export { Color, Vector3 };
}

Before (invalid):

export declare namespace SDK {
        { Color, Vector3, };
}

After (valid):

export declare namespace SDK {
        export { Color, Vector3, };
}

Details

The issue is in DtsRollupGenerator.ts and ApiReportGenerator.ts. Both files unconditionally skip all ExportKeyword tokens (lines ~272-276), then re-add them for declaration types (interface, class, enum, namespace, function, type). However, ExportDeclaration nodes (like export { Foo }) were not handled, so the export keyword was stripped but never restored.

The fix checks if an ExportKeyword is part of an ExportDeclaration that is inside a ModuleBlock (namespace body), and if so, preserves it.

How it was tested

  1. Created a minimal reproduction case with a namespace containing export { } declarations
  2. Verified that tsc produces valid output
  3. Verified that api-extractor (before fix) produces invalid output (TS1109)
  4. Applied fix and verified api-extractor now produces valid output

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 microsoft#5516
@ItsChrisHickman
Copy link
Author

@microsoft-github-policy-service agree

@ItsChrisHickman ItsChrisHickman force-pushed the fix/api-extractor-namespace-export-keyword branch from 39fd3ef to b776182 Compare December 24, 2025 23:28
break;

case ts.SyntaxKind.ExportKeyword:
// Check if this export keyword is part of an ExportDeclaration inside a namespace
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you deduplicate this and the other instance of this same code in the API report generator?

span.modification.skipAll();
break;

case ts.SyntaxKind.DefaultKeyword:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the default need to be retained in these cases as well?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Needs triage

Development

Successfully merging this pull request may close these issues.

[api-extractor] Missing 'export' keyword for namespace re-exports produces invalid TypeScript

2 participants