[api-extractor] Allow configuration of external packages
Summary
I am having a monorepo setup where some files are included via code sharing (using typescript path mappings).
In such a setup API extractor detects the imported files from the other projects as internal and tries to crawl and bundle them into the final types and API.
But according to my build setup the imported files will be external references in the final output.
To mitigate this problem I want to tell API extractor somehow that these imports are external modules.
Details
- API extractor detects the external modules here: https://github.com/microsoft/rushstack/blob/f1bdeddfc0abcc987fdfe0b4d1e82f1ea2b4f65f/apps/api-extractor/src/analyzer/ExportAnalyzer.ts#L264-L313
- There is already an option to additionally include packages
- There is no option to force an import to be an external module.
Bundlers like Rollup/Rolldown have dedicated options like: https://rollupjs.org/configuration-options/#external to control the externals. I think a similar string+regex option could solve this.
Standard questions
Please answer these questions to help us investigate your issue more quickly:
| Question | Answer |
|---|---|
@microsoft/api-extractor version? |
7.53.1 |
| Operating system? | Wom |
| API Extractor scenario? | rollups (.d.ts) --> |
| Would you consider contributing a PR? | Yes |
| TypeScript compiler version? | 5.9.3 |
Node.js version (node -v)? |
v24.11.0 |
Here a workaround I started to use by patching out the method with the additional logic to check against a list. Normally this list would come via options.
import { ExportAnalyzer } from '@microsoft/api-extractor/lib/analyzer/ExportAnalyzer';
// normally via options, here simply a global which is set from somewhere else.
let exportAnalyzerExternals: (string | RegExp)[] = [];
// patch out method from prototype (before running the api extrator via API)
const original = (ExportAnalyzer.prototype as any)._isExternalModulePath;
(ExportAnalyzer.prototype as any)._isExternalModulePath = function (
importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode,
moduleSpecifier: string
) {
if (exportAnalyzerExternals.length > 0) {
for (const ex of exportAnalyzerExternals) {
if (typeof ex === 'string' && ex === moduleSpecifier) {
return true;
} else if (ex instanceof RegExp && ex.test(moduleSpecifier)) {
return true;
}
}
}
// call original
return original.call(this, importOrExportDeclaration, moduleSpecifier);
};