diff --git a/apps/api-extractor/src/analyzer/AstImport.ts b/apps/api-extractor/src/analyzer/AstImport.ts index bc2b685949d..5d17a19b48f 100644 --- a/apps/api-extractor/src/analyzer/AstImport.ts +++ b/apps/api-extractor/src/analyzer/AstImport.ts @@ -27,12 +27,7 @@ export enum AstImportKind { /** * An import statement such as `import x = require("y");`. */ - EqualsImport, - - /** - * An import statement such as `interface foo { foo: import("bar").a.b.c }`. - */ - ImportType + EqualsImport } /** @@ -150,14 +145,6 @@ export class AstImport extends AstSyntheticEntity { return `${options.modulePath}:*`; case AstImportKind.EqualsImport: return `${options.modulePath}:=`; - case AstImportKind.ImportType: { - const subKey: string = !options.exportName - ? '*' // Equivalent to StarImport - : options.exportName.includes('.') // Equivalent to a named export - ? options.exportName.split('.')[0] - : options.exportName; - return `${options.modulePath}:${subKey}`; - } default: throw new InternalError('Unknown AstImportKind'); } diff --git a/apps/api-extractor/src/analyzer/AstNamespaceImport.ts b/apps/api-extractor/src/analyzer/AstNamespaceImport.ts index 09304b9efcb..baa8bf707f2 100644 --- a/apps/api-extractor/src/analyzer/AstNamespaceImport.ts +++ b/apps/api-extractor/src/analyzer/AstNamespaceImport.ts @@ -11,7 +11,6 @@ export interface IAstNamespaceImportOptions { readonly astModule: AstModule; readonly namespaceName: string; readonly declaration: ts.Declaration; - readonly symbol: ts.Symbol; } /** @@ -64,21 +63,15 @@ export class AstNamespaceImport extends AstSyntheticEntity { public readonly namespaceName: string; /** - * The original `ts.SyntaxKind.NamespaceImport` which can be used as a location for error messages. + * The (first) original `ts.SyntaxKind.NamespaceImport` (or `ts.SyntaxKind.SourceFile` if import declaration doesn't exist) which can be used as a location for error messages. */ public readonly declaration: ts.Declaration; - /** - * The original `ts.SymbolFlags.Namespace` symbol. - */ - public readonly symbol: ts.Symbol; - public constructor(options: IAstNamespaceImportOptions) { super(); this.astModule = options.astModule; this.namespaceName = options.namespaceName; this.declaration = options.declaration; - this.symbol = options.symbol; } /** {@inheritdoc} */ diff --git a/apps/api-extractor/src/analyzer/AstSubPathImport.ts b/apps/api-extractor/src/analyzer/AstSubPathImport.ts new file mode 100644 index 00000000000..fe27b8e9418 --- /dev/null +++ b/apps/api-extractor/src/analyzer/AstSubPathImport.ts @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { InternalError } from '@rushstack/node-core-library'; +import { type AstEntity, AstSyntheticEntity } from './AstEntity'; + +export interface IAstSubPathImportOptions { + readonly astEntity: AstEntity; + readonly exportPath: string[]; +} + +/** + * `AstSubPathImport` represents a sub-path import, such as `import("foo").X.Y.Z` will import Y.Z from X of "foo". + * + * @remarks + * + * The base AstEntity can be either local or external entity. + * + * ```ts + * // import from AstImport (NamedImport, modulePath="foo", exportName="X"), with exportPath ["Y", "Z"] + * const bar: import("foo").X.Y.Z; + * + * // import from AstImport (DefaultImport, modulePath="foo"), with exportPath ["X", "Y", "Z"] + * const bar: import("foo").default.X.Y.Z; + * + * // import from AstEntity of X, with exportPath ["Y", "Z"] + * const bar: import("./foo").X.Y.Z; + * ``` + */ +export class AstSubPathImport extends AstSyntheticEntity { + /** + * The AstEntity that is imported from. + * + * @remarks + * + * The AstEntity can be either local or external entity. + */ + public readonly baseAstEntity: AstEntity; + + /** + * The path to the entity within the `baseAstEntity`. + */ + public readonly exportPath: string[]; + + public constructor(options: IAstSubPathImportOptions) { + super(); + + if (options.exportPath.length === 0) { + throw new InternalError('AstSubPathImport.exportPath cannot be empty'); + } + + this.baseAstEntity = options.astEntity; + this.exportPath = options.exportPath; + } + + /** {@inheritdoc} */ + public get localName(): string { + // abstract + return this.exportPath[this.exportPath.length - 1]; + } +} diff --git a/apps/api-extractor/src/analyzer/AstSymbolTable.ts b/apps/api-extractor/src/analyzer/AstSymbolTable.ts index e589ea10097..22e92c19187 100644 --- a/apps/api-extractor/src/analyzer/AstSymbolTable.ts +++ b/apps/api-extractor/src/analyzer/AstSymbolTable.ts @@ -18,6 +18,7 @@ import type { MessageRouter } from '../collector/MessageRouter'; import { TypeScriptInternals, type IGlobalVariableAnalyzer } from './TypeScriptInternals'; import { SyntaxHelpers } from './SyntaxHelpers'; import { SourceFileLocationFormatter } from './SourceFileLocationFormatter'; +import { AstSubPathImport } from './AstSubPathImport'; /** * Options for `AstSymbolTable._fetchAstSymbol()` @@ -318,21 +319,29 @@ export class AstSymbolTable { // If this symbol is non-external (i.e. it belongs to the working package), then we also analyze any // referencedAstSymbols that are non-external. For example, this ensures that forgotten exports // get analyzed. - rootAstSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { - for (const referencedAstEntity of astDeclaration.referencedAstEntities) { - // Walk up to the root of the tree, looking for any imports along the way - if (referencedAstEntity instanceof AstSymbol) { - if (!referencedAstEntity.isExternal) { - this._analyzeAstSymbol(referencedAstEntity); - } + const analyzeReferencedLocalAstEntity = (referencedAstEntity: AstEntity): void => { + if (referencedAstEntity instanceof AstSymbol) { + if (!referencedAstEntity.isExternal) { + this._analyzeAstSymbol(referencedAstEntity); } + } - if (referencedAstEntity instanceof AstNamespaceImport) { - if (!referencedAstEntity.astModule.isExternal) { - this._analyzeAstNamespaceImport(referencedAstEntity); - } + if (referencedAstEntity instanceof AstNamespaceImport) { + if (!referencedAstEntity.astModule.isExternal) { + this._analyzeAstNamespaceImport(referencedAstEntity); } } + + if (referencedAstEntity instanceof AstSubPathImport) { + analyzeReferencedLocalAstEntity(referencedAstEntity.baseAstEntity); + } + }; + + rootAstSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { + for (const referencedAstEntity of astDeclaration.referencedAstEntities) { + // Walk up to the root of the tree, looking for any imports along the way + analyzeReferencedLocalAstEntity(referencedAstEntity); + } }); } } diff --git a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts index d8a68a2b76c..26a58218f7f 100644 --- a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts +++ b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts @@ -15,6 +15,7 @@ import type { AstEntity } from './AstEntity'; import { AstNamespaceImport } from './AstNamespaceImport'; import { SyntaxHelpers } from './SyntaxHelpers'; import { AstNamespaceExport } from './AstNamespaceExport'; +import { AstSubPathImport, type IAstSubPathImportOptions } from './AstSubPathImport'; /** * Exposes the minimal APIs from AstSymbolTable that are needed by ExportAnalyzer. @@ -68,6 +69,10 @@ export class ExportAnalyzer { private readonly _importableAmbientSourceFiles: Set = new Set(); private readonly _astImportsByKey: Map = new Map(); + private readonly _astSubPathImportsByKey: Map> = new Map< + AstEntity, + Map + >(); private readonly _astNamespaceImportByModule: Map = new Map(); public constructor( @@ -435,93 +440,84 @@ export class ExportAnalyzer { node: ts.ImportTypeNode, referringModuleIsExternal: boolean ): AstEntity | undefined { + const importPath: ts.Identifier[] = []; + if (node.qualifier) { + let leftNode: ts.EntityName = node.qualifier; + while (leftNode.kind === ts.SyntaxKind.QualifiedName) { + importPath.unshift(leftNode.right); + leftNode = leftNode.left; + } + importPath.unshift(leftNode); + } + const externalModulePath: string | undefined = this._tryGetExternalModulePath(node); if (externalModulePath) { - let exportName: string; - if (node.qualifier) { - // Example input: - // import('api-extractor-lib1-test').Lib1GenericType - // - // Extracted qualifier: - // Lib1GenericType - exportName = node.qualifier.getText().trim(); + if (importPath.length > 0) { + const exportName: string = importPath[0].getText().trim(); + // There is no symbol property in a ImportTypeNode, obtain the associated export symbol + const exportSymbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(importPath[0]); + let exportAstEntity: AstEntity; + if (exportName === ts.InternalSymbolName.Default) { + // Example input: + // import('api-extractor-lib1-test').default + // + // Extracted import base: + // import apiExtractorLib1Test from 'api-extractor-lib1-test'; + exportAstEntity = this._fetchAstImport(exportSymbol, { + importKind: AstImportKind.DefaultImport, + modulePath: externalModulePath, + exportName: SyntaxHelpers.makeCamelCaseIdentifier(externalModulePath), + isTypeOnly: true + }); + } else { + // Example input: + // import('api-extractor-lib1-test').Lib1GenericType + // + // Extracted import base: + // import { Lib1GenericType } from 'api-extractor-lib1-test'; + exportAstEntity = this._fetchAstImport(exportSymbol, { + importKind: AstImportKind.NamedImport, + exportName: exportName, + modulePath: externalModulePath, + isTypeOnly: true + }); + } + return this._fetchAstSubPathImport({ + astEntity: exportAstEntity, + exportPath: importPath.slice(1).map((id) => id.getText().trim()) + }); } else { // Example input: // import('api-extractor-lib1-test') // - // Extracted qualifier: - // apiExtractorLib1Test + // Extracted import base: + // import * as apiExtractorLib1Test from 'api-extractor-lib1-test'; - exportName = SyntaxHelpers.makeCamelCaseIdentifier(externalModulePath); + // Here importSymbol=undefined because {@inheritDoc} and such are not going to work correctly for + // a package or source file. + return this._fetchAstImport(undefined, { + importKind: AstImportKind.StarImport, + exportName: SyntaxHelpers.makeCamelCaseIdentifier(externalModulePath), + modulePath: externalModulePath, + isTypeOnly: false + }); } - - return this._fetchAstImport(undefined, { - importKind: AstImportKind.ImportType, - exportName: exportName, - modulePath: externalModulePath, - isTypeOnly: false - }); - } - - // Internal reference: AstSymbol - const rightMostToken: ts.Identifier | ts.ImportTypeNode = node.qualifier - ? node.qualifier.kind === ts.SyntaxKind.QualifiedName - ? node.qualifier.right - : node.qualifier - : node; - - // There is no symbol property in a ImportTypeNode, obtain the associated export symbol - const exportSymbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(rightMostToken); - if (!exportSymbol) { - throw new InternalError( - `Symbol not found for identifier: ${node.getText()}\n` + - SourceFileLocationFormatter.formatDeclaration(node) - ); } - let followedSymbol: ts.Symbol = exportSymbol; - for (;;) { - const referencedAstEntity: AstEntity | undefined = this.fetchReferencedAstEntity( - followedSymbol, - referringModuleIsExternal - ); - - if (referencedAstEntity) { - return referencedAstEntity; - } - - const followedSymbolNode: ts.Node | ts.ImportTypeNode | undefined = - followedSymbol.declarations && (followedSymbol.declarations[0] as ts.Node | undefined); - - if (followedSymbolNode && followedSymbolNode.kind === ts.SyntaxKind.ImportType) { - return this.fetchReferencedAstEntityFromImportTypeNode( - followedSymbolNode as ts.ImportTypeNode, - referringModuleIsExternal - ); - } - - // eslint-disable-next-line no-bitwise - if (!(followedSymbol.flags & ts.SymbolFlags.Alias)) { - break; - } - - const currentAlias: ts.Symbol = this._typeChecker.getAliasedSymbol(followedSymbol); - if (!currentAlias || currentAlias === followedSymbol) { - break; - } - - followedSymbol = currentAlias; + // Internal reference + const astModule: AstModule = this._fetchSpecifierAstModule(node, undefined); + if (importPath.length > 0) { + const exportName: ts.Identifier = importPath[0]; + const exportAstEntity: AstEntity = this._getExportOfAstModule(exportName.getText().trim(), astModule); + return this._fetchAstSubPathImport({ + astEntity: exportAstEntity, + exportPath: importPath.slice(1).map((id) => id.getText().trim()) + }); + } else { + const localName: string = SyntaxHelpers.makeCamelCaseIdentifier(this._getModuleSpecifier(node)); + return this._getAstNamespaceImport(astModule, localName, astModule.sourceFile); } - - const astSymbol: AstSymbol | undefined = this._astSymbolTable.fetchAstSymbol({ - followedSymbol: followedSymbol, - isExternal: referringModuleIsExternal, - includeNominalAnalysis: false, - addIfMissing: true - }); - - return astSymbol; } private _tryMatchExportDeclaration( @@ -605,15 +601,14 @@ export class ExportAnalyzer { ): AstNamespaceExport { const imoprtNamespace: AstNamespaceImport = this._getAstNamespaceImport( astModule, - declarationSymbol, + declarationSymbol.name, declaration ); return new AstNamespaceExport({ namespaceName: imoprtNamespace.localName, astModule: astModule, - declaration, - symbol: declarationSymbol + declaration }); } @@ -644,7 +639,7 @@ export class ExportAnalyzer { if (externalModulePath === undefined) { const astModule: AstModule = this._fetchSpecifierAstModule(importDeclaration, declarationSymbol); - return this._getAstNamespaceImport(astModule, declarationSymbol, declaration); + return this._getAstNamespaceImport(astModule, declarationSymbol.name, declaration); } // Here importSymbol=undefined because {@inheritDoc} and such are not going to work correctly for @@ -773,16 +768,15 @@ export class ExportAnalyzer { private _getAstNamespaceImport( astModule: AstModule, - declarationSymbol: ts.Symbol, + localName: string, declaration: ts.Declaration ): AstNamespaceImport { let namespaceImport: AstNamespaceImport | undefined = this._astNamespaceImportByModule.get(astModule); if (namespaceImport === undefined) { namespaceImport = new AstNamespaceImport({ - namespaceName: declarationSymbol.name, + namespaceName: localName, astModule: astModule, - declaration: declaration, - symbol: declarationSymbol + declaration: declaration }); this._astNamespaceImportByModule.set(astModule, namespaceImport); } @@ -901,16 +895,20 @@ export class ExportAnalyzer { * and fetches the corresponding AstModule object. */ private _fetchSpecifierAstModule( - importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration, - exportSymbol: ts.Symbol + importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode, + exportSymbol: ts.Symbol | undefined ): AstModule { const moduleSpecifier: string = this._getModuleSpecifier(importOrExportDeclaration); + const moduleSpecifierNode: ts.Expression | undefined = ts.isImportTypeNode(importOrExportDeclaration) + ? ts.isLiteralTypeNode(importOrExportDeclaration.argument) + ? importOrExportDeclaration.argument.literal + : undefined + : importOrExportDeclaration.moduleSpecifier; const mode: ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined = - importOrExportDeclaration.moduleSpecifier && - ts.isStringLiteralLike(importOrExportDeclaration.moduleSpecifier) + moduleSpecifierNode && ts.isStringLiteralLike(moduleSpecifierNode) ? TypeScriptInternals.getModeForUsageLocation( importOrExportDeclaration.getSourceFile(), - importOrExportDeclaration.moduleSpecifier, + moduleSpecifierNode, this._program.getCompilerOptions() ) : undefined; @@ -948,10 +946,12 @@ export class ExportAnalyzer { } const isExternal: boolean = this._isExternalModulePath(importOrExportDeclaration, moduleSpecifier); - const moduleReference: IAstModuleReference = { - moduleSpecifier: moduleSpecifier, - moduleSpecifierSymbol: exportSymbol - }; + const moduleReference: IAstModuleReference | undefined = exportSymbol + ? { + moduleSpecifier: moduleSpecifier, + moduleSpecifierSymbol: exportSymbol + } + : undefined; const specifierAstModule: AstModule = this.fetchAstModuleFromSourceFile( moduleSourceFile, moduleReference, @@ -991,6 +991,29 @@ export class ExportAnalyzer { return astImport; } + private _fetchAstSubPathImport(options: IAstSubPathImportOptions): AstEntity { + if (options.exportPath.length === 0) { + // If the exportPath is empty, just use the AstEntity directly instead of creating an unnecessary AstSubPathImport. + // e.g. return AstImport for `import("foo").Bar`, return AstEntity of Bar for `import("./foo").Bar`. + return options.astEntity; + } + + let astSubPathImportsByExportPath: Map | undefined = + this._astSubPathImportsByKey.get(options.astEntity); + if (astSubPathImportsByExportPath === undefined) { + astSubPathImportsByExportPath = new Map(); + this._astSubPathImportsByKey.set(options.astEntity, astSubPathImportsByExportPath); + } + + const exportPathKey: string = options.exportPath.join('.'); + let astSubPathImport: AstSubPathImport | undefined = astSubPathImportsByExportPath.get(exportPathKey); + if (astSubPathImport === undefined) { + astSubPathImport = new AstSubPathImport(options); + astSubPathImportsByExportPath.set(exportPathKey, astSubPathImport); + } + return astSubPathImport; + } + private _getModuleSpecifier( importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode ): string { diff --git a/apps/api-extractor/src/collector/Collector.ts b/apps/api-extractor/src/collector/Collector.ts index 8f6d74320ed..fb2394ae8cb 100644 --- a/apps/api-extractor/src/collector/Collector.ts +++ b/apps/api-extractor/src/collector/Collector.ts @@ -34,6 +34,7 @@ import { ExtractorConfig } from '../api/ExtractorConfig'; import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; import { AstImport } from '../analyzer/AstImport'; import type { SourceMapper } from './SourceMapper'; +import { AstSubPathImport } from '../analyzer/AstSubPathImport'; /** * Options for Collector constructor. @@ -522,7 +523,7 @@ export class Collector { if (astEntity instanceof AstSymbol) { this._entitiesBySymbol.set(astEntity.followedSymbol, entity); } else if (astEntity instanceof AstNamespaceImport) { - this._entitiesBySymbol.set(astEntity.symbol, entity); + this._entitiesBySymbol.set(astEntity.astModule.moduleSymbol, entity); } this._entities.push(entity); this._collectReferenceDirectives(astEntity); @@ -578,6 +579,12 @@ export class Collector { this._recursivelyCreateEntities(localAstEntity, alreadySeenAstEntities); } } + + if (astEntity instanceof AstSubPathImport) { + this._createCollectorEntity(astEntity.baseAstEntity); + this._createCollectorEntity(astEntity); + this._recursivelyCreateEntities(astEntity.baseAstEntity, alreadySeenAstEntities); + } } /** diff --git a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts index 4171f819f94..2dd8e0fa16a 100644 --- a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts +++ b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts @@ -204,15 +204,13 @@ export class DeclarationReferenceGenerator { } if (followedSymbol.flags & ts.SymbolFlags.Alias) { followedSymbol = this._collector.typeChecker.getAliasedSymbol(followedSymbol); - - // Without this logic, we end up following the symbol `ns` in `import * as ns from './file'` to - // the actual file `file.ts`. We don't want to do this, so revert to the original symbol. - if (followedSymbol.flags & ts.SymbolFlags.ValueModule) { - followedSymbol = symbol; - } } - if (DeclarationReferenceGenerator._isExternalModuleSymbol(followedSymbol)) { + const entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(followedSymbol); + if ( + DeclarationReferenceGenerator._isExternalModuleSymbol(followedSymbol) && + !(entity?.astEntity instanceof AstNamespaceImport) // skip local namespace import + ) { if (!includeModuleSymbols) { return undefined; } @@ -230,7 +228,6 @@ export class DeclarationReferenceGenerator { } let localName: string = followedSymbol.name; - const entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(followedSymbol); if (entity?.nameForEmit) { localName = entity.nameForEmit; } @@ -290,10 +287,8 @@ export class DeclarationReferenceGenerator { firstExportingConsumableParent && firstExportingConsumableParent.astEntity instanceof AstNamespaceImport ) { - const parentSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration( - firstExportingConsumableParent.astEntity.declaration, - this._collector.typeChecker - ); + const parentSymbol: ts.Symbol | undefined = + firstExportingConsumableParent.astEntity.astModule.moduleSymbol; if (parentSymbol) { return this._symbolToDeclarationReference( parentSymbol, diff --git a/apps/api-extractor/src/generators/DtsEmitHelpers.ts b/apps/api-extractor/src/generators/DtsEmitHelpers.ts index 3e7a339115e..3e16f928b5f 100644 --- a/apps/api-extractor/src/generators/DtsEmitHelpers.ts +++ b/apps/api-extractor/src/generators/DtsEmitHelpers.ts @@ -5,12 +5,13 @@ import * as ts from 'typescript'; import { InternalError } from '@rushstack/node-core-library'; import type { CollectorEntity } from '../collector/CollectorEntity'; -import { AstImport, AstImportKind } from '../analyzer/AstImport'; +import { type AstImport, AstImportKind } from '../analyzer/AstImport'; import { AstDeclaration } from '../analyzer/AstDeclaration'; import type { Collector } from '../collector/Collector'; import type { Span } from '../analyzer/Span'; import type { IndentedWriter } from './IndentedWriter'; import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; +import { AstSubPathImport } from '../analyzer/AstSubPathImport'; /** * Some common code shared between DtsRollupGenerator and ApiReportGenerator. @@ -50,21 +51,6 @@ export class DtsEmitHelpers { `${importPrefix} ${collectorEntity.nameForEmit} = require('${astImport.modulePath}');` ); break; - case AstImportKind.ImportType: - if (!astImport.exportName) { - writer.writeLine( - `${importPrefix} * as ${collectorEntity.nameForEmit} from '${astImport.modulePath}';` - ); - } else { - const topExportName: string = astImport.exportName.split('.')[0]; - if (collectorEntity.nameForEmit === topExportName) { - writer.write(`${importPrefix} { ${topExportName} }`); - } else { - writer.write(`${importPrefix} { ${topExportName} as ${collectorEntity.nameForEmit} }`); - } - writer.writeLine(` from '${astImport.modulePath}';`); - } - break; default: throw new InternalError('Unimplemented AstImportKind'); } @@ -109,6 +95,8 @@ export class DtsEmitHelpers { throw new InternalError('referencedEntry.nameForEmit is undefined'); } + const typeofPrefix: string = node.isTypeOf ? 'typeof ' : ''; + let typeArgumentsText: string = ''; if (node.typeArguments && node.typeArguments.length > 0) { @@ -146,27 +134,25 @@ export class DtsEmitHelpers { const separatorAfter: string = /(\s*)$/.exec(span.getText())?.[1] ?? ''; - if ( - referencedEntity.astEntity instanceof AstImport && - referencedEntity.astEntity.importKind === AstImportKind.ImportType && - referencedEntity.astEntity.exportName - ) { - // For an ImportType with a namespace chain, only the top namespace is imported. - // Must add the original nested qualifiers to the rolled up import. - const qualifiersText: string = node.qualifier?.getText() ?? ''; - const nestedQualifiersStart: number = qualifiersText.indexOf('.'); - // Including the leading "." - const nestedQualifiersText: string = - nestedQualifiersStart >= 0 ? qualifiersText.substring(nestedQualifiersStart) : ''; - - const replacement: string = `${referencedEntity.nameForEmit}${nestedQualifiersText}${typeArgumentsText}${separatorAfter}`; + if (referencedEntity.astEntity instanceof AstSubPathImport) { + const baseEntity: CollectorEntity | undefined = collector.tryGetCollectorEntity( + referencedEntity.astEntity.baseAstEntity + ); + if (!baseEntity) { + throw new InternalError( + `Collector entity for import() not found: ${node.getText()}\n` + + SourceFileLocationFormatter.formatDeclaration(node) + ); + } + const exportPathText: string = referencedEntity.astEntity.exportPath.join('.'); + const replacement: string = `${typeofPrefix}${baseEntity.nameForEmit}.${exportPathText}${typeArgumentsText}${separatorAfter}`; span.modification.skipAll(); span.modification.prefix = replacement; } else { // Replace with internal symbol or AstImport span.modification.skipAll(); - span.modification.prefix = `${referencedEntity.nameForEmit}${typeArgumentsText}${separatorAfter}`; + span.modification.prefix = `${typeofPrefix}${referencedEntity.nameForEmit}${typeArgumentsText}${separatorAfter}`; } } } diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.json index 3a7783606e3..e1974b396e9 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.json @@ -188,6 +188,71 @@ "name": "Item", "preserveMemberOrder": false, "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#defaultImport:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "defaultImport: " + }, + { + "kind": "Content", + "text": "import('api-extractor-lib2-test')." + }, + { + "kind": "Reference", + "text": "default", + "canonicalReference": "api-extractor-lib2-test!DefaultClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "defaultImport", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#externalModule:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "externalModule: " + }, + { + "kind": "Content", + "text": "typeof import('api-extractor-lib3-test')" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "externalModule", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, { "kind": "Property", "canonicalReference": "api-extractor-scenarios!Item#lib1:member", @@ -293,6 +358,36 @@ "isProtected": false, "isAbstract": false }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#localModule:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "localModule: " + }, + { + "kind": "Content", + "text": "typeof import('./Options')" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "localModule", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, { "kind": "Property", "canonicalReference": "api-extractor-scenarios!Item#options:member", @@ -309,7 +404,7 @@ { "kind": "Reference", "text": "Options", - "canonicalReference": "api-extractor-scenarios!~Options:interface" + "canonicalReference": "api-extractor-scenarios!~Options_2~Options:interface" }, { "kind": "Content", @@ -330,12 +425,47 @@ }, { "kind": "Property", - "canonicalReference": "api-extractor-scenarios!Item#reExport:member", + "canonicalReference": "api-extractor-scenarios!Item#reExportExternal:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "reExportExternal: " + }, + { + "kind": "Content", + "text": "import('./re-export')." + }, + { + "kind": "Reference", + "text": "Lib3Class", + "canonicalReference": "api-extractor-lib3-test!Lib3Class:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "reExportExternal", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#reExportLocal:member", "docComment": "", "excerptTokens": [ { "kind": "Content", - "text": "reExport: " + "text": "reExportLocal: " }, { "kind": "Content", @@ -354,7 +484,77 @@ "isReadonly": false, "isOptional": false, "releaseTag": "Public", - "name": "reExport", + "name": "reExportLocal", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#typeofImportExternal:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "typeofImportExternal: " + }, + { + "kind": "Content", + "text": "typeof import('api-extractor-lib3-test')." + }, + { + "kind": "Reference", + "text": "Lib1Class", + "canonicalReference": "api-extractor-lib1-test!Lib1Class:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "typeofImportExternal", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#typeofImportLocal:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "typeofImportLocal: " + }, + { + "kind": "Content", + "text": "typeof import('./Options')." + }, + { + "kind": "Reference", + "text": "OptionsClass", + "canonicalReference": "api-extractor-scenarios!~Options_2~OptionsClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "typeofImportLocal", "propertyTypeTokenRange": { "startIndex": 1, "endIndex": 3 diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.md index 999494f5feb..78242f58c33 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.md @@ -4,26 +4,45 @@ ```ts +import type apiExtractorLib2Test from 'api-extractor-lib2-test'; +import * as apiExtractorLib3Test from 'api-extractor-lib3-test'; import * as Lib1 from 'api-extractor-lib1-test'; -import { Lib1Class } from 'api-extractor-lib3-test'; -import { Lib1Interface } from 'api-extractor-lib1-test'; +import type { Lib1Class } from 'api-extractor-lib3-test'; +import type { Lib1Interface } from 'api-extractor-lib1-test'; import { Lib2Class } from 'api-extractor-lib2-test'; import { Lib2Interface } from 'api-extractor-lib2-test'; +import { Lib3Class } from 'api-extractor-lib3-test'; // @public (undocumented) export class Item { + // (undocumented) + defaultImport: apiExtractorLib2Test; + // (undocumented) + externalModule: typeof apiExtractorLib3Test; // (undocumented) lib1: Lib1Interface; // (undocumented) lib2: Lib2Interface; // (undocumented) lib3: Lib1Class; + // Warning: (ae-forgotten-export) The symbol "Options_2" needs to be exported by the entry point index.d.ts + // + // (undocumented) + localModule: typeof Options_2; // Warning: (ae-forgotten-export) The symbol "Options" needs to be exported by the entry point index.d.ts // // (undocumented) options: Options; // (undocumented) - reExport: Lib2Class; + reExportExternal: Lib3Class; + // (undocumented) + reExportLocal: Lib2Class; + // (undocumented) + typeofImportExternal: typeof Lib1Class; + // Warning: (ae-forgotten-export) The symbol "OptionsClass" needs to be exported by the entry point index.d.ts + // + // (undocumented) + typeofImportLocal: typeof OptionsClass; } export { Lib1 } diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/dynamicImportType/rollup.d.ts index 93bc8c69f24..a68d5772bb1 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType/rollup.d.ts @@ -1,8 +1,11 @@ +import type apiExtractorLib2Test from 'api-extractor-lib2-test'; +import * as apiExtractorLib3Test from 'api-extractor-lib3-test'; import * as Lib1 from 'api-extractor-lib1-test'; -import { Lib1Class } from 'api-extractor-lib3-test'; -import { Lib1Interface } from 'api-extractor-lib1-test'; +import type { Lib1Class } from 'api-extractor-lib3-test'; +import type { Lib1Interface } from 'api-extractor-lib1-test'; import { Lib2Class } from 'api-extractor-lib2-test'; import { Lib2Interface } from 'api-extractor-lib2-test'; +import { Lib3Class } from 'api-extractor-lib3-test'; /** @public */ export declare class Item { @@ -10,7 +13,13 @@ export declare class Item { lib1: Lib1Interface; lib2: Lib2Interface; lib3: Lib1Class; - reExport: Lib2Class; + defaultImport: apiExtractorLib2Test; + externalModule: typeof apiExtractorLib3Test; + localModule: typeof Options_2; + typeofImportLocal: typeof OptionsClass; + typeofImportExternal: typeof Lib1Class; + reExportLocal: Lib2Class; + reExportExternal: Lib3Class; } export { Lib1 } @@ -22,4 +31,14 @@ declare interface Options { color: 'red' | 'blue'; } +declare namespace Options_2 { + export { + Options, + OptionsClass + } +} + +declare class OptionsClass { +} + export { } diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.json index b7a2b150998..92c8bcc4753 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.json @@ -258,6 +258,98 @@ "startIndex": 1, "endIndex": 4 } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!IExample#localDottedImportType:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "localDottedImportType: " + }, + { + "kind": "Content", + "text": "import('./namespace-export')." + }, + { + "kind": "Reference", + "text": "LocalModule.LocalClass", + "canonicalReference": "api-extractor-scenarios!~LocalModule~LocalClass_2:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "localDottedImportType", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!IExample#localDottedImportType2:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "localDottedImportType2: " + }, + { + "kind": "Content", + "text": "import('./namespace-export')." + }, + { + "kind": "Reference", + "text": "LocalNS.LocalNSClass", + "canonicalReference": "api-extractor-scenarios!~LocalNS.LocalNSClass:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "localDottedImportType2", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!IExample#predefinedNamedImport:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "predefinedNamedImport: " + }, + { + "kind": "Reference", + "text": "Lib1Namespace.Inner.X", + "canonicalReference": "api-extractor-lib1-test!Lib1Namespace.Inner.X:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "predefinedNamedImport", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } } ], "extendsTokenRanges": [] diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.md index 46ecc077ba9..5c30ced621c 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.md @@ -12,6 +12,12 @@ export interface IExample { dottedImportType: Lib1Namespace.Inner.X | undefined; // (undocumented) dottedImportType2: Lib1Namespace.Y | undefined; + // (undocumented) + localDottedImportType: LocalModule.LocalClass; + // (undocumented) + localDottedImportType2: LocalNS.LocalNSClass; + // (undocumented) + predefinedNamedImport: Lib1Namespace.Inner.X; } // (No @packageDocumentation comment for this package) diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/rollup.d.ts index c8d465c2ca5..08fabbba796 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/rollup.d.ts @@ -2,8 +2,31 @@ import { Lib1Namespace } from 'api-extractor-lib1-test'; /** @public */ export declare interface IExample { + predefinedNamedImport: Lib1Namespace.Inner.X; dottedImportType: Lib1Namespace.Inner.X | undefined; dottedImportType2: Lib1Namespace.Y | undefined; + localDottedImportType: LocalModule.LocalClass; + localDottedImportType2: LocalNS.LocalNSClass; +} + +declare class LocalClass_2 { +} + +declare interface LocalInterface { +} + +declare namespace LocalModule { + export { + LocalClass_2 as LocalClass, + LocalInterface + } +} + +declare namespace LocalNS { + class LocalNSClass { + } + interface LocalNSInterface { + } } export { } diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.md index ee8c43fff7c..c663e207a88 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.md @@ -4,8 +4,8 @@ ```ts -import { Lib1GenericType } from 'api-extractor-lib1-test'; -import { Lib1Interface } from 'api-extractor-lib1-test'; +import type { Lib1GenericType } from 'api-extractor-lib1-test'; +import type { Lib1Interface } from 'api-extractor-lib1-test'; // @public (undocumented) export interface IExample { diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/rollup.d.ts index dcbb364c050..06d40f3f74e 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType3/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/rollup.d.ts @@ -1,5 +1,5 @@ -import { Lib1GenericType } from 'api-extractor-lib1-test'; -import { Lib1Interface } from 'api-extractor-lib1-test'; +import type { Lib1GenericType } from 'api-extractor-lib1-test'; +import type { Lib1Interface } from 'api-extractor-lib1-test'; /** @public */ export declare interface IExample { diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.json index 569dc468334..b9c436be1d4 100644 --- a/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.json @@ -194,7 +194,7 @@ { "kind": "Reference", "text": "forgottenNs.ForgottenClass", - "canonicalReference": "api-extractor-scenarios!~ForgottenClass:class" + "canonicalReference": "api-extractor-scenarios!~forgottenNs~ForgottenClass:class" }, { "kind": "Content", diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.json index 3d6aed02798..bfeec33aa0d 100644 --- a/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.json @@ -194,7 +194,7 @@ { "kind": "Reference", "text": "forgottenNs.ForgottenClass", - "canonicalReference": "api-extractor-scenarios!~ForgottenClass:class" + "canonicalReference": "api-extractor-scenarios!~forgottenNs~ForgottenClass:class" }, { "kind": "Content", diff --git a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json index 9a755f8d5cf..ecc2a23d4d0 100644 --- a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json @@ -532,7 +532,7 @@ { "kind": "Reference", "text": "internal2.ForgottenExport6", - "canonicalReference": "api-extractor-scenarios!~ForgottenExport6:class" + "canonicalReference": "api-extractor-scenarios!~internal2~ForgottenExport6:class" }, { "kind": "Content", diff --git a/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.md index 286bbca3991..a47e6542cb2 100644 --- a/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.md @@ -4,12 +4,13 @@ ```ts +import type apiExtractorLib2Test from 'api-extractor-lib2-test'; import { default as default_2 } from 'api-extractor-lib2-test'; // @public (undocumented) export interface DefaultImportTypes { // (undocumented) - dynamicImport: default_2; + dynamicImport: apiExtractorLib2Test; // (undocumented) namedImport: default_2; // (undocumented) diff --git a/build-tests/api-extractor-scenarios/etc/namedDefaultImport/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/rollup.d.ts index 0bf69c07b82..4563c831830 100644 --- a/build-tests/api-extractor-scenarios/etc/namedDefaultImport/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/rollup.d.ts @@ -1,10 +1,11 @@ +import type apiExtractorLib2Test from 'api-extractor-lib2-test'; import { default as default_2 } from 'api-extractor-lib2-test'; /** @public */ export declare interface DefaultImportTypes { namedImport: default_2; reExport: default_2; - dynamicImport: default_2; + dynamicImport: apiExtractorLib2Test; } export { } diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType/Item.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType/Item.ts index 5f638c0854c..cb90bdad480 100644 --- a/build-tests/api-extractor-scenarios/src/dynamicImportType/Item.ts +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType/Item.ts @@ -7,5 +7,11 @@ export class Item { lib1: import('api-extractor-lib1-test').Lib1Interface; lib2: import('api-extractor-lib2-test').Lib2Interface; lib3: import('api-extractor-lib3-test').Lib1Class; - reExport: import('./re-export').Lib2Class; + defaultImport: import('api-extractor-lib2-test').default; + externalModule: typeof import('api-extractor-lib3-test'); + localModule: typeof import('./Options'); + typeofImportLocal: typeof import('./Options').OptionsClass; + typeofImportExternal: typeof import('api-extractor-lib3-test').Lib1Class; + reExportLocal: import('./re-export').Lib2Class; + reExportExternal: import('./re-export').Lib3Class; } diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType/Options.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType/Options.ts index 938f0a920d0..9280b77276d 100644 --- a/build-tests/api-extractor-scenarios/src/dynamicImportType/Options.ts +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType/Options.ts @@ -5,3 +5,5 @@ export interface Options { name: string; color: 'red' | 'blue'; } + +export class OptionsClass {} diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType/re-export.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType/re-export.ts index 6f1dedc68cf..decfe0cd89f 100644 --- a/build-tests/api-extractor-scenarios/src/dynamicImportType/re-export.ts +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType/re-export.ts @@ -1,4 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +export * from 'api-extractor-lib3-test'; + export { Lib2Class } from 'api-extractor-lib2-test'; diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType2/index.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType2/index.ts index 5d211e8470e..eee2fae57a1 100644 --- a/build-tests/api-extractor-scenarios/src/dynamicImportType2/index.ts +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType2/index.ts @@ -1,8 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { Lib1Namespace } from 'api-extractor-lib1-test'; /** @public */ export interface IExample { + predefinedNamedImport: Lib1Namespace.Inner.X; dottedImportType: import('api-extractor-lib1-test').Lib1Namespace.Inner.X | undefined; dottedImportType2: import('api-extractor-lib1-test').Lib1Namespace.Y | undefined; + localDottedImportType: import('./namespace-export').LocalModule.LocalClass; + localDottedImportType2: import('./namespace-export').LocalNS.LocalNSClass; } diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType2/local-module.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType2/local-module.ts new file mode 100644 index 00000000000..4d6133b75ae --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType2/local-module.ts @@ -0,0 +1,3 @@ +export class LocalClass {} + +export interface LocalInterface {} diff --git a/build-tests/api-extractor-scenarios/src/dynamicImportType2/namespace-export.ts b/build-tests/api-extractor-scenarios/src/dynamicImportType2/namespace-export.ts new file mode 100644 index 00000000000..4508abf2461 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/dynamicImportType2/namespace-export.ts @@ -0,0 +1,7 @@ +import * as LocalModule from './local-module'; +export { LocalModule }; + +export namespace LocalNS { + export class LocalNSClass {} + export interface LocalNSInterface {} +} diff --git a/common/changes/@microsoft/api-extractor/feat-api-extractor-import-type_2025-08-28-05-55.json b/common/changes/@microsoft/api-extractor/feat-api-extractor-import-type_2025-08-28-05-55.json new file mode 100644 index 00000000000..c665ab293a9 --- /dev/null +++ b/common/changes/@microsoft/api-extractor/feat-api-extractor-import-type_2025-08-28-05-55.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/api-extractor", + "comment": "refactor import() type support, to support more cases", + "type": "patch" + } + ], + "packageName": "@microsoft/api-extractor" +} \ No newline at end of file