From 9708717204ccc732fdb76b777b06ce15e13835b2 Mon Sep 17 00:00:00 2001 From: Qjuh <76154676+Qjuh@users.noreply.github.com> Date: Sat, 7 Jun 2025 13:17:29 +0200 Subject: [PATCH] fix(api-extractor): links including entrypoints (#10924) --- .../src/generators/ApiModelGenerator.ts | 81 +++++++++++-------- .../DeclarationReferenceGenerator.ts | 69 +++++++++++----- .../src/generators/ExcerptBuilder.ts | 7 +- 3 files changed, 100 insertions(+), 57 deletions(-) diff --git a/packages/api-extractor/src/generators/ApiModelGenerator.ts b/packages/api-extractor/src/generators/ApiModelGenerator.ts index e6950c1af..bea171257 100644 --- a/packages/api-extractor/src/generators/ApiModelGenerator.ts +++ b/packages/api-extractor/src/generators/ApiModelGenerator.ts @@ -56,6 +56,7 @@ import type { ApiItemMetadata } from '../collector/ApiItemMetadata.js'; import type { Collector } from '../collector/Collector.js'; import type { DeclarationMetadata } from '../collector/DeclarationMetadata.js'; import type { ISourceLocation } from '../collector/SourceMapper.js'; +import type { IWorkingPackageEntryPoint } from '../collector/WorkingPackage.js'; import { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator.js'; import { ExcerptBuilder, type IExcerptBuilderNodeToCapture } from './ExcerptBuilder.js'; @@ -205,6 +206,7 @@ export interface DocgenJson { typedefs: DocgenTypedefJson[]; } interface IProcessAstEntityContext { + entryPoint: IWorkingPackageEntryPoint; isExported: boolean; name: string; parentApiItem: ApiItemContainerMixin; @@ -305,6 +307,7 @@ export class ApiModelGenerator { // we are including forgotten exports, then process everything. if (entity.exportedFromEntryPoint || this._collector.extractorConfig.docModelIncludeForgottenExports) { this._processAstEntity(entity.astEntity, { + entryPoint, name: entity.nameForEmit!, isExported: entity.exportedFromEntryPoint, parentApiItem: apiEntryPoint, @@ -352,7 +355,7 @@ export class ApiModelGenerator { private _processAstNamespaceImport(astNamespaceImport: AstNamespaceImport, context: IProcessAstEntityContext): void { const astModule: AstModule = astNamespaceImport.astModule; - const { name, isExported, parentApiItem } = context; + const { entryPoint, name, isExported, parentApiItem } = context; const containerKey: string = ApiNamespace.getContainerKey(name); const sourceLocation: ISourceLocation = this._getSourceLocation(astNamespaceImport.declaration); @@ -375,6 +378,7 @@ export class ApiModelGenerator { // eslint-disable-next-line unicorn/no-array-for-each astModule.astModuleExportInfo!.exportedLocalEntities.forEach((exportedEntity: AstEntity, exportedName: string) => { this._processAstEntity(exportedEntity, { + entryPoint, name: exportedName, isExported: true, parentApiItem: apiNamespace!, @@ -533,7 +537,7 @@ export class ApiModelGenerator { } private _processApiCallSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { parentApiItem } = context; + const { entryPoint, parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiCallSignature.getContainerKey(overloadIndex); @@ -556,7 +560,7 @@ export class ApiModelGenerator { const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, callSignature.parameters); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -580,7 +584,7 @@ export class ApiModelGenerator { } private _processApiConstructor(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { parentApiItem } = context; + const { entryPoint, parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiConstructor.getContainerKey(overloadIndex); @@ -597,7 +601,7 @@ export class ApiModelGenerator { constructorDeclaration.parameters, ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = parent?.construct ? this._tsDocParser.parseString( @@ -629,7 +633,7 @@ export class ApiModelGenerator { } private _processApiClass(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { name, isExported, parentApiItem } = context; + const { entryPoint, name, isExported, parentApiItem } = context; const containerKey: string = ApiClass.getContainerKey(name); let apiClass: ApiClass | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiClass; @@ -683,7 +687,7 @@ export class ApiModelGenerator { } } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( @@ -732,7 +736,7 @@ export class ApiModelGenerator { } private _processApiConstructSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { parentApiItem } = context; + const { entryPoint, parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiConstructSignature.getContainerKey(overloadIndex); @@ -757,7 +761,7 @@ export class ApiModelGenerator { const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, constructSignature.parameters); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = parent?.construct ? this._tsDocParser.parseString( @@ -789,13 +793,13 @@ export class ApiModelGenerator { } private _processApiEnum(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { name, isExported, parentApiItem } = context; + const { entryPoint, name, isExported, parentApiItem } = context; const containerKey: string = ApiEnum.getContainerKey(name); let apiEnum: ApiEnum | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiEnum; if (apiEnum === undefined) { - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, []); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, [], entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -823,7 +827,7 @@ export class ApiModelGenerator { } private _processApiEnumMember(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { name, parentApiItem } = context; + const { entryPoint, name, parentApiItem } = context; const containerKey: string = ApiEnumMember.getContainerKey(name); let apiEnumMember: ApiEnumMember | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiEnumMember; @@ -839,7 +843,7 @@ export class ApiModelGenerator { nodesToCapture.push({ node: enumMember.initializer, tokenRange: initializerTokenRange }); } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -865,7 +869,7 @@ export class ApiModelGenerator { context: IProcessAstEntityContext, altFunctionDeclaration?: ts.FunctionDeclaration, ): void { - const { name, isExported, parentApiItem } = context; + const { entryPoint, name, isExported, parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiFunction.getContainerKey(name, overloadIndex); @@ -894,7 +898,7 @@ export class ApiModelGenerator { jsDoc?.params, ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( @@ -938,7 +942,7 @@ export class ApiModelGenerator { } private _processApiIndexSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { parentApiItem } = context; + const { entryPoint, parentApiItem } = context; const overloadIndex: number = this._collector.getOverloadIndex(astDeclaration); const containerKey: string = ApiIndexSignature.getContainerKey(overloadIndex); @@ -956,7 +960,7 @@ export class ApiModelGenerator { const parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, indexSignature.parameters); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -981,7 +985,7 @@ export class ApiModelGenerator { } private _processApiInterface(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { name, isExported, parentApiItem } = context; + const { entryPoint, name, isExported, parentApiItem } = context; const containerKey: string = ApiInterface.getContainerKey(name); let apiInterface: ApiInterface | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiInterface; @@ -1022,7 +1026,7 @@ export class ApiModelGenerator { } } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( @@ -1064,7 +1068,7 @@ export class ApiModelGenerator { } private _processApiMethod(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void { - const { name, parentApiItem } = context; + const { entryPoint, name, parentApiItem } = context; const parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined; const jsDoc = parent?.methods?.find((method) => method.name === name); const isStatic: boolean = astDeclaration @@ -1095,7 +1099,7 @@ export class ApiModelGenerator { jsDoc?.params, ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( @@ -1163,7 +1167,7 @@ export class ApiModelGenerator { } private _processApiMethodSignature(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void { - const { name, parentApiItem } = context; + const { entryPoint, name, parentApiItem } = context; const overloadIndex: number = astDeclaration ? this._collector.getOverloadIndex(astDeclaration) : 1; const containerKey: string = ApiMethodSignature.getContainerKey(name, overloadIndex); @@ -1193,7 +1197,7 @@ export class ApiModelGenerator { jsDoc?.params, ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( @@ -1241,13 +1245,13 @@ export class ApiModelGenerator { } private _processApiNamespace(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { name, isExported, parentApiItem } = context; + const { entryPoint, name, isExported, parentApiItem } = context; const containerKey: string = ApiNamespace.getContainerKey(name); let apiNamespace: ApiNamespace | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiNamespace; if (apiNamespace === undefined) { - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, []); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, [], entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -1273,7 +1277,7 @@ export class ApiModelGenerator { } private _processApiProperty(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void { - const { name, parentApiItem } = context; + const { entryPoint, name, parentApiItem } = context; const parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | DocgenTypedefJson | undefined; const jsDoc = parent?.props?.find((prop) => prop.name === name); const isStatic: boolean = astDeclaration @@ -1314,7 +1318,7 @@ export class ApiModelGenerator { nodesToCapture.push({ node: declaration.initializer, tokenRange: initializerTokenRange }); } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( @@ -1371,7 +1375,7 @@ export class ApiModelGenerator { } private _processApiPropertySignature(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void { - const { name, parentApiItem } = context; + const { entryPoint, name, parentApiItem } = context; const containerKey: string = ApiPropertySignature.getContainerKey(name); let apiPropertySignature: ApiPropertySignature | undefined = parentApiItem.tryGetMemberByKey( @@ -1392,7 +1396,7 @@ export class ApiModelGenerator { const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: propertySignature.type, tokenRange: propertyTypeTokenRange }); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( @@ -1440,7 +1444,7 @@ export class ApiModelGenerator { } private _processApiTypeAlias(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { name, isExported, parentApiItem } = context; + const { entryPoint, name, isExported, parentApiItem } = context; const containerKey: string = ApiTypeAlias.getContainerKey(name); @@ -1464,7 +1468,7 @@ export class ApiModelGenerator { const typeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); nodesToCapture.push({ node: typeAliasDeclaration.type, tokenRange: typeTokenRange }); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = jsDoc ? this._tsDocParser.parseString( @@ -1506,7 +1510,7 @@ export class ApiModelGenerator { } private _processApiVariable(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void { - const { name, isExported, parentApiItem } = context; + const { entryPoint, name, isExported, parentApiItem } = context; const containerKey: string = ApiVariable.getContainerKey(name); @@ -1526,7 +1530,7 @@ export class ApiModelGenerator { nodesToCapture.push({ node: variableDeclaration.initializer, tokenRange: initializerTokenRange }); } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -1652,18 +1656,25 @@ export class ApiModelGenerator { private _buildExcerptTokens( astDeclaration: AstDeclaration, nodesToCapture: IExcerptBuilderNodeToCapture[], + entryPoint: IWorkingPackageEntryPoint, ): IExcerptToken[] { const excerptTokens: IExcerptToken[] = []; // Build the main declaration - ExcerptBuilder.addDeclaration(excerptTokens, astDeclaration, nodesToCapture, this._referenceGenerator); + ExcerptBuilder.addDeclaration(excerptTokens, astDeclaration, nodesToCapture, this._referenceGenerator, entryPoint); const declarationMetadata: DeclarationMetadata = this._collector.fetchDeclarationMetadata(astDeclaration); // Add any ancillary declarations for (const ancillaryDeclaration of declarationMetadata.ancillaryDeclarations) { ExcerptBuilder.addBlankLine(excerptTokens); - ExcerptBuilder.addDeclaration(excerptTokens, ancillaryDeclaration, nodesToCapture, this._referenceGenerator); + ExcerptBuilder.addDeclaration( + excerptTokens, + ancillaryDeclaration, + nodesToCapture, + this._referenceGenerator, + entryPoint, + ); } return excerptTokens; diff --git a/packages/api-extractor/src/generators/DeclarationReferenceGenerator.ts b/packages/api-extractor/src/generators/DeclarationReferenceGenerator.ts index 399ef5697..e34409c81 100644 --- a/packages/api-extractor/src/generators/DeclarationReferenceGenerator.ts +++ b/packages/api-extractor/src/generators/DeclarationReferenceGenerator.ts @@ -15,6 +15,7 @@ import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers.js'; import { TypeScriptInternals } from '../analyzer/TypeScriptInternals.js'; import type { Collector } from '../collector/Collector.js'; import type { CollectorEntity } from '../collector/CollectorEntity.js'; +import type { IWorkingPackageEntryPoint } from '../collector/WorkingPackage.js'; export class DeclarationReferenceGenerator { public static readonly unknownReference: string = '?'; @@ -28,14 +29,25 @@ export class DeclarationReferenceGenerator { /** * Gets the UID for a TypeScript Identifier that references a type. */ - public getDeclarationReferenceForIdentifier(node: ts.Identifier): DeclarationReference | undefined { + public getDeclarationReferenceForIdentifier( + node: ts.Identifier, + entryPoint: IWorkingPackageEntryPoint, + ): DeclarationReference | undefined { const symbol: ts.Symbol | undefined = this._collector.typeChecker.getSymbolAtLocation(node); if (symbol !== undefined) { const isExpression: boolean = DeclarationReferenceGenerator._isInExpressionContext(node); return ( - this.getDeclarationReferenceForSymbol(symbol, isExpression ? ts.SymbolFlags.Value : ts.SymbolFlags.Type) ?? - this.getDeclarationReferenceForSymbol(symbol, isExpression ? ts.SymbolFlags.Type : ts.SymbolFlags.Value) ?? - this.getDeclarationReferenceForSymbol(symbol, ts.SymbolFlags.Namespace) + this.getDeclarationReferenceForSymbol( + symbol, + isExpression ? ts.SymbolFlags.Value : ts.SymbolFlags.Type, + entryPoint, + ) ?? + this.getDeclarationReferenceForSymbol( + symbol, + isExpression ? ts.SymbolFlags.Type : ts.SymbolFlags.Value, + entryPoint, + ) ?? + this.getDeclarationReferenceForSymbol(symbol, ts.SymbolFlags.Namespace, entryPoint) ); } @@ -48,8 +60,9 @@ export class DeclarationReferenceGenerator { public getDeclarationReferenceForSymbol( symbol: ts.Symbol, meaning: ts.SymbolFlags, + entryPoint: IWorkingPackageEntryPoint, ): DeclarationReference | undefined { - return this._symbolToDeclarationReference(symbol, meaning, /* includeModuleSymbols*/ false); + return this._symbolToDeclarationReference(symbol, meaning, /* includeModuleSymbols*/ false, entryPoint); } private static _isInExpressionContext(node: ts.Node): boolean { @@ -197,6 +210,7 @@ export class DeclarationReferenceGenerator { symbol: ts.Symbol, meaning: ts.SymbolFlags, includeModuleSymbols: boolean, + entryPoint: IWorkingPackageEntryPoint, ): DeclarationReference | undefined { const declaration: ts.Node | undefined = TypeScriptHelpers.tryGetADeclaration(symbol); const sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile(); @@ -221,7 +235,7 @@ export class DeclarationReferenceGenerator { return undefined; } - return new DeclarationReference(this._sourceFileToModuleSource(sourceFile)); + return new DeclarationReference(this._sourceFileToModuleSource(sourceFile, entryPoint)); } // Do not generate a declaration reference for a type parameter. @@ -229,7 +243,7 @@ export class DeclarationReferenceGenerator { return undefined; } - let parentRef: DeclarationReference | undefined = this._getParentReference(followedSymbol); + let parentRef: DeclarationReference | undefined = this._getParentReference(followedSymbol, entryPoint); if (!parentRef) { return undefined; } @@ -276,7 +290,10 @@ export class DeclarationReferenceGenerator { .withMeaning(DeclarationReferenceGenerator._getMeaningOfSymbol(followedSymbol, meaning) as any); } - private _getParentReference(symbol: ts.Symbol): DeclarationReference | undefined { + private _getParentReference( + symbol: ts.Symbol, + entryPoint: IWorkingPackageEntryPoint, + ): DeclarationReference | undefined { const declaration: ts.Node | undefined = TypeScriptHelpers.tryGetADeclaration(symbol); const sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile(); @@ -286,7 +303,7 @@ export class DeclarationReferenceGenerator { const entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(symbol); if (entity) { if (entity.exportedFromEntryPoint) { - return new DeclarationReference(this._sourceFileToModuleSource(sourceFile)); + return new DeclarationReference(this._sourceFileToModuleSource(sourceFile, entryPoint)); } const firstExportingConsumableParent: CollectorEntity | undefined = entity.getFirstExportingConsumableParent(); @@ -296,7 +313,12 @@ export class DeclarationReferenceGenerator { this._collector.typeChecker, ); if (parentSymbol) { - return this._symbolToDeclarationReference(parentSymbol, parentSymbol.flags, /* includeModuleSymbols*/ true); + return this._symbolToDeclarationReference( + parentSymbol, + parentSymbol.flags, + /* includeModuleSymbols*/ true, + entryPoint, + ); } } } @@ -304,7 +326,12 @@ export class DeclarationReferenceGenerator { // Next, try to find a parent symbol via the symbol tree. const parentSymbol: ts.Symbol | undefined = TypeScriptInternals.getSymbolParent(symbol); if (parentSymbol) { - return this._symbolToDeclarationReference(parentSymbol, parentSymbol.flags, /* includeModuleSymbols*/ true); + return this._symbolToDeclarationReference( + parentSymbol, + parentSymbol.flags, + /* includeModuleSymbols*/ true, + entryPoint, + ); } // If that doesn't work, try to find a parent symbol via the node tree. As far as we can tell, @@ -330,20 +357,22 @@ export class DeclarationReferenceGenerator { grandParentSymbol, grandParentSymbol.flags, /* includeModuleSymbols*/ true, + entryPoint, ); } } // At this point, we have a local symbol in a module. if (sourceFile && ts.isExternalModule(sourceFile)) { - return new DeclarationReference(this._sourceFileToModuleSource(sourceFile)); + return new DeclarationReference(this._sourceFileToModuleSource(sourceFile, entryPoint)); } else { return new DeclarationReference(GlobalSource.instance); } } - private _getEntryPointName(sourceFile: ts.SourceFile): string { + private _getEntryPointName(sourceFile: ts.SourceFile, entry: IWorkingPackageEntryPoint): string { if (this._collector.program.isSourceFileFromExternalLibrary(sourceFile)) { + console.log(sourceFile.fileName, 'is external!'); const packageJson: INodePackageJson | undefined = this._collector.packageJsonLookup.tryLoadNodePackageJsonFor( sourceFile.fileName, ); @@ -365,19 +394,17 @@ export class DeclarationReferenceGenerator { return DeclarationReferenceGenerator.unknownReference; } - let modulePath = ''; - for (const entryPoint of this._collector.workingPackage.entryPoints) { - if (entryPoint.sourceFile === sourceFile) { - modulePath = entryPoint.modulePath; - } - } + const modulePath = entry.modulePath; return `${this._collector.workingPackage.name}${modulePath ? `/${modulePath}` : ''}`; } - private _sourceFileToModuleSource(sourceFile: ts.SourceFile | undefined): GlobalSource | ModuleSource { + private _sourceFileToModuleSource( + sourceFile: ts.SourceFile | undefined, + entryPoint: IWorkingPackageEntryPoint, + ): GlobalSource | ModuleSource { if (sourceFile && ts.isExternalModule(sourceFile)) { - const packageName: string = this._getEntryPointName(sourceFile); + const packageName: string = this._getEntryPointName(sourceFile, entryPoint); if (this._collector.bundledPackageNames.has(packageName)) { // The api-extractor.json config file has a "bundledPackages" setting, which causes imports from diff --git a/packages/api-extractor/src/generators/ExcerptBuilder.ts b/packages/api-extractor/src/generators/ExcerptBuilder.ts index 05f79ac66..ca19ea1e7 100644 --- a/packages/api-extractor/src/generators/ExcerptBuilder.ts +++ b/packages/api-extractor/src/generators/ExcerptBuilder.ts @@ -11,6 +11,7 @@ import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/De import * as ts from 'typescript'; import type { AstDeclaration } from '../analyzer/AstDeclaration.js'; import { Span } from '../analyzer/Span.js'; +import type { IWorkingPackageEntryPoint } from '../collector/WorkingPackage.js'; import type { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator.js'; /** @@ -32,6 +33,8 @@ export interface IExcerptBuilderNodeToCapture { * Internal state for ExcerptBuilder */ interface IBuildSpanState { + entryPoint: IWorkingPackageEntryPoint; + /** * Tracks whether the last appended token was a separator. If so, and we're in the middle of * capturing a token range, then omit the separator from the range. @@ -90,6 +93,7 @@ export class ExcerptBuilder { astDeclaration: AstDeclaration, nodesToCapture: IExcerptBuilderNodeToCapture[], referenceGenerator: DeclarationReferenceGenerator, + entryPoint: IWorkingPackageEntryPoint, ): void { let stopBeforeChildKind: ts.SyntaxKind | undefined; @@ -118,6 +122,7 @@ export class ExcerptBuilder { } ExcerptBuilder._buildSpan(excerptTokens, span, { + entryPoint, referenceGenerator, startingNode: span.node, stopBeforeChildKind, @@ -185,7 +190,7 @@ export class ExcerptBuilder { if (ts.isIdentifier(span.node)) { const name: ts.Identifier = span.node; - canonicalReference = state.referenceGenerator.getDeclarationReferenceForIdentifier(name); + canonicalReference = state.referenceGenerator.getDeclarationReferenceForIdentifier(name, state.entryPoint); } if (canonicalReference) {