microsoft / rushstack

Monorepo for tools developed by the Rush Stack community
https://rushstack.io/
Other
5.94k stars 599 forks source link

[api-extractor] Re-exported `import *` namespaces produce malformed .d.ts rollups (with `bundledPackages`) #4807

Open Josmithr opened 4 months ago

Josmithr commented 4 months ago

Summary

See this repo for a repro of the issue: https://github.com/Josmithr/api-extractor-playground/tree/re-export-module-namespace

The repo contains 2 packages, package-a and package-b. package-b depends on package-a, and both are configured with API-Extractor.

In this scenario, package-a contains a single root export, which is a "namespace" generated via:

package-a/src/index.ts

import * as A from './NamespaceModule.js';
export { A };

It's type rollup, generated by API-Extractor looks like this:

package-a/dist/rollup.d.ts

declare namespace A {
    export { Foo, bar, Baz };
}
export { A };

/** @public */
declare const bar = 5;

/** @public */
declare interface Baz {
    value: string;
}

/** @public */
declare class Foo {}

export {};

package-b also contains a single root export, which is simply a re-export of namespace A from package-a. It is also configured with package-a specified in its bundledPackages. Its export looks like this:

package-b/src/index.ts

export { A } from 'package-a';

I would expect package-b's type roll-up to look identical to that of package-a, but instead, a malformed rollup is generated:

package-b/dist/rollup.d.ts with bundledPackages

export declare namespace A {
    {
        Foo, bar, Baz;
    }
}

export {};

package-b/dist/rollup.d.ts WITHOUT bundledPackages

import { A } from "package-a";
export { A }

Notice that the necessary imports are missing for Foo, bar, and Baz.

Standard questions

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

Question Answer
@microsoft/api-extractor version? 7.47.0
Operating system? Linux (GitHub Codespace)
API Extractor scenario? reporting (.api.md) / rollups (.d.ts) / docs (.api.json)
Would you consider contributing a PR? Yes
TypeScript compiler version? 5.5.2
Node.js version (node -v)? 20.12.1
iclanton commented 4 months ago

@octogonz

octogonz commented 2 months ago

Question: Why doesn't this:

export declare namespace A {
    {
        Foo, bar, Baz;
    }
}

export {};

...look like this:

export declare namespace A {
    export { // πŸ‘ˆπŸ‘ˆπŸ‘ˆ
        Foo, bar, Baz;
    }
}

export {};
octogonz commented 2 months ago

Discussed on 9/5/2024: I think this repro can be simplified to eliminate bundledPackages. My guess is that this construct:

package-x/lib/index.d.ts

declare interface Foo {
  x: string;
}

export declare namespace A {
    export { 
        Foo
    }
}

export { };

...would not get rolled up correctly. It would forget to include Foo because the analyzer doesn't understand export { . . . } inside a namespace block.

A different way to say that, is that API Extractor cannot roll up a structure that API Extractor itself emits as output.

If that's true, then this issue is unrelated to bundledPackages, and is really just another syntax we need to support.

octogonz commented 2 months ago

This is the hard case to think about:

import * as A from './NamespaceModule.js';
export { A };

import * as B from './NamespaceModule.js';
export { B };