rushstack icon indicating copy to clipboard operation
rushstack copied to clipboard

[api-extractor] Allow configuration of external packages

Open Danielku15 opened this issue 2 months ago • 1 comments

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

  1. API extractor detects the external modules here: https://github.com/microsoft/rushstack/blob/f1bdeddfc0abcc987fdfe0b4d1e82f1ea2b4f65f/apps/api-extractor/src/analyzer/ExportAnalyzer.ts#L264-L313
  2. There is already an option to additionally include packages
  3. 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

Danielku15 avatar Nov 30 '25 17:11 Danielku15

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);
};

Danielku15 avatar Nov 30 '25 17:11 Danielku15