Skip to content

[api-extractor]: Nested export * as namespaces get flattened to root level during rollup #5336

@ritz078

Description

@ritz078

Summary

I was trying to create a properly encapsulated namespace structure using chained export * as statements. The goal was to have FunctionsNamespace only accessible through the full path RootNamespace.FunctionsNamespace. However, when running API Extractor, the nested namespaces are being flattened to the root level, exposing FunctionsNamespace directly instead of maintaining the intended encapsulation. This breaks the namespace hierarchy and exposes internal APIs that should remain nested.

Repro steps

  1. Create a new project with API Extractor

  2. Create this minimal file structure:

    src/
    ├── index.ts
    ├── FunctionsNamespace.ts
    └── functions.ts
    
  3. Use these minimal exports:

src/functions.ts:

export function sum(a: number, b: number) {
  return a + b;
}

export function multiply(a: number, b: number) {
  return a * b;
}

src/FunctionsNamespace.ts:

export * as FunctionsNamespace from "./functions";

src/index.ts:

export * as RootNamespace from "./FunctionsNamespace";
  1. Run api-extractor run

Expected result: FunctionsNamespace should only be accessible through the full namespace path: RootNamespace.FunctionsNamespace.sum and RootNamespace.FunctionsNamespace.multiply

Actual result: FunctionsNamespace is incorrectly exposed directly at the root level, making it accessible as FunctionsNamespace.sum and FunctionsNamespace.multiply, breaking the intended encapsulation.

Details

The issue appears to be in how API Extractor processes nested export * as statements during the rollup process. Instead of maintaining the namespace hierarchy, it's flattening all namespaces to the root level. This makes it impossible to properly encapsulate internal namespaces and can lead to unintended API exposure and namespace pollution.

Critical Impact: This bug also breaks TypeDoc documentation generation. When TypeDoc processes the malformed .d.ts file, it misunderstands the exported namespaces and hierarchy. The flattened namespaces create incorrect documentation structure, making it impossible to generate accurate API documentation that reflects the intended namespace organization.

The generated .d.ts output shows:

export declare namespace FunctionsNamespace {
    export function sum(a: number, b: number): number;
    export function multiply(a: number, b: number): number;
}

export declare namespace RootNamespace {
    export {
        FunctionsNamespace
    }
}

This suggests the rollup process is not properly handling the nested namespace structure and is exposing internal namespaces at the root level.

This bug effectively breaks both the type declarations AND the documentation generation, making it a significant blocker for libraries that need proper API documentation.

Standard questions

Please answer these questions to help us investigate your issue more quickly:

Question Answer
@microsoft/api-extractor version? 7.40.0
Operating system? Mac
API Extractor scenario? rollups (.d.ts)
Would you consider contributing a PR? No
TypeScript compiler version? 5.9.2
Node.js version (node -v)? 20.x

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Needs triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions