From d804098f8b6100114d00ba748c7cab92c236597d Mon Sep 17 00:00:00 2001 From: MLuc24 Date: Mon, 17 Aug 2026 13:56:16 +0700 Subject: [PATCH] [api-extractor] Report unresolvable inline import paths in .d.ts rollups When an inline import() type could not be resolved to a rolled up entity, its span was emitted verbatim. A relative path such as import('../Bar') means nothing next to the rollup, which does not preserve the original file layout, so the emitted .d.ts does not compile and the only clue was an unrelated ae-forgotten-export warning. Such paths are now reported as ae-unresolved-import-path. --- apps/api-extractor/src/api/ExtractorMessageId.ts | 8 +++++++- .../src/generators/DtsEmitHelpers.ts | 15 +++++++++++++++ ...-relative-import-path_2026-08-17-06-54-27.json | 10 ++++++++++ common/reviews/api/api-extractor.api.md | 1 + 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 common/changes/@microsoft/api-extractor/fix-api-extractor-relative-import-path_2026-08-17-06-54-27.json diff --git a/apps/api-extractor/src/api/ExtractorMessageId.ts b/apps/api-extractor/src/api/ExtractorMessageId.ts index 9e423d9a420..7265b9a4900 100644 --- a/apps/api-extractor/src/api/ExtractorMessageId.ts +++ b/apps/api-extractor/src/api/ExtractorMessageId.ts @@ -117,7 +117,12 @@ export enum ExtractorMessageId { MissingGetter = 'ae-missing-getter', /** - * "Incorrect file type; API Extractor expects to analyze compiler outputs with the .d.ts file extension. + * "The inline import path ___ cannot be resolved in the .d.ts rollup, because the rollup does not + * preserve the original file layout." + */ + UnresolvedImportPath = 'ae-unresolved-import-path', + + to analyze compiler outputs with the .d.ts file extension. * Troubleshooting tips: `https://api-extractor.com/link/dts-error`" */ WrongInputFileType = 'ae-wrong-input-file-type' @@ -141,5 +146,6 @@ export const allExtractorMessageIds: Set = new Set([ 'ae-unresolved-link', 'ae-setter-with-docs', 'ae-missing-getter', + 'ae-unresolved-import-path', 'ae-wrong-input-file-type' ]); diff --git a/apps/api-extractor/src/generators/DtsEmitHelpers.ts b/apps/api-extractor/src/generators/DtsEmitHelpers.ts index 7cde437bee8..708ddd27f38 100644 --- a/apps/api-extractor/src/generators/DtsEmitHelpers.ts +++ b/apps/api-extractor/src/generators/DtsEmitHelpers.ts @@ -13,6 +13,7 @@ import type { Span } from '../analyzer/Span'; import type { IndentedWriter } from './IndentedWriter'; import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; +import { ExtractorMessageId } from '../api/ExtractorMessageId'; /** * Some common code shared between DtsRollupGenerator and ApiReportGenerator. @@ -170,6 +171,20 @@ export class DtsEmitHelpers { span.modification.skipAll(); span.modification.prefix = `${referencedEntity.nameForEmit}${typeArgumentsText}${separatorAfter}`; } + } else if (ts.isLiteralTypeNode(node.argument) && ts.isStringLiteral(node.argument.literal)) { + // The import was not resolved to a rolled up entity, so its span gets emitted verbatim. A relative + // path is meaningless in the rollup, which does not preserve the original file layout, so the + // emitted .d.ts would not compile. Report that instead of leaving the user to discover it later. + const modulePath: string = node.argument.literal.text; + if (modulePath.startsWith('.')) { + collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.UnresolvedImportPath, + `The inline import path "${modulePath}" could not be resolved, so it would be emitted unchanged` + + ` into the .d.ts rollup, where it does not resolve to anything. Import the symbol at the top` + + ` of the file instead of using an inline import() type.`, + astDeclaration + ); + } } } diff --git a/common/changes/@microsoft/api-extractor/fix-api-extractor-relative-import-path_2026-08-17-06-54-27.json b/common/changes/@microsoft/api-extractor/fix-api-extractor-relative-import-path_2026-08-17-06-54-27.json new file mode 100644 index 00000000000..717cc058515 --- /dev/null +++ b/common/changes/@microsoft/api-extractor/fix-api-extractor-relative-import-path_2026-08-17-06-54-27.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "Report a new `ae-unresolved-import-path` message when an inline `import()` type with a relative path cannot be resolved, instead of silently emitting the unusable path into the .d.ts rollup.", + "type": "minor", + "packageName": "@microsoft/api-extractor" + } + ], + "packageName": "@microsoft/api-extractor" +} diff --git a/common/reviews/api/api-extractor.api.md b/common/reviews/api/api-extractor.api.md index f44ecd8e92b..10ce98d6050 100644 --- a/common/reviews/api/api-extractor.api.md +++ b/common/reviews/api/api-extractor.api.md @@ -158,6 +158,7 @@ export enum ExtractorMessageId { PreapprovedUnsupportedType = "ae-preapproved-unsupported-type", SetterWithDocs = "ae-setter-with-docs", Undocumented = "ae-undocumented", + UnresolvedImportPath = "ae-unresolved-import-path", UnresolvedInheritDocBase = "ae-unresolved-inheritdoc-base", UnresolvedInheritDocReference = "ae-unresolved-inheritdoc-reference", UnresolvedLink = "ae-unresolved-link",