diff --git a/apps/api-extractor/src/analyzer/AstNamespaceImport.ts b/apps/api-extractor/src/analyzer/AstNamespaceImport.ts index 955ef903d27..acb4bd4c578 100644 --- a/apps/api-extractor/src/analyzer/AstNamespaceImport.ts +++ b/apps/api-extractor/src/analyzer/AstNamespaceImport.ts @@ -11,6 +11,7 @@ export interface IAstNamespaceImportOptions { readonly astModule: AstModule; readonly namespaceName: string; readonly declaration: ts.Declaration; + readonly symbol: ts.Symbol; } /** @@ -67,11 +68,17 @@ export class AstNamespaceImport extends AstSyntheticEntity { */ 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/ExportAnalyzer.ts b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts index 33867923bb5..3610f828c07 100644 --- a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts +++ b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts @@ -626,7 +626,8 @@ export class ExportAnalyzer { namespaceImport = new AstNamespaceImport({ namespaceName: declarationSymbol.name, astModule: astModule, - declaration: declaration + declaration: declaration, + symbol: declarationSymbol }); this._astNamespaceImportByModule.set(astModule, namespaceImport); } diff --git a/apps/api-extractor/src/collector/Collector.ts b/apps/api-extractor/src/collector/Collector.ts index 06420065f3a..ea2a2dba145 100644 --- a/apps/api-extractor/src/collector/Collector.ts +++ b/apps/api-extractor/src/collector/Collector.ts @@ -82,6 +82,7 @@ export class Collector { AstEntity, CollectorEntity >(); + private readonly _entitiesBySymbol: Map = new Map(); private readonly _starExportedExternalModulePaths: string[] = []; @@ -294,6 +295,14 @@ export class Collector { return undefined; } + /** + * For a given analyzed ts.Symbol, return the CollectorEntity that it refers to. Returns undefined if it + * doesn't refer to anything interesting. + */ + public tryGetEntityForSymbol(symbol: ts.Symbol): CollectorEntity | undefined { + return this._entitiesBySymbol.get(symbol); + } + /** * Returns the associated `CollectorEntity` for the given `astEntity`, if one was created during analysis. */ @@ -420,6 +429,11 @@ export class Collector { entity = new CollectorEntity(astEntity); this._entitiesByAstEntity.set(astEntity, entity); + if (astEntity instanceof AstSymbol) { + this._entitiesBySymbol.set(astEntity.followedSymbol, entity); + } else if (astEntity instanceof AstNamespaceImport) { + this._entitiesBySymbol.set(astEntity.symbol, entity); + } this._entities.push(entity); this._collectReferenceDirectives(astEntity); } diff --git a/apps/api-extractor/src/collector/CollectorEntity.ts b/apps/api-extractor/src/collector/CollectorEntity.ts index 227fad25cee..db52e1f4ad9 100644 --- a/apps/api-extractor/src/collector/CollectorEntity.ts +++ b/apps/api-extractor/src/collector/CollectorEntity.ts @@ -175,6 +175,19 @@ export class CollectorEntity { return false; } + /** + * Return the first consumable parent that exports this entity. If there is none, returns + * `undefined`. + */ + public getFirstExportingConsumableParent(): CollectorEntity | undefined { + for (const [parent, localExportNames] of this._localExportNamesByParent) { + if (parent.consumable && localExportNames.size > 0) { + return parent; + } + } + return undefined; + } + /** * Adds a new export name to the entity. */ diff --git a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts index ccfe9347d26..c5008cba592 100644 --- a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts +++ b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts @@ -15,6 +15,7 @@ import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; import { TypeScriptInternals } from '../analyzer/TypeScriptInternals'; import { Collector } from '../collector/Collector'; import { CollectorEntity } from '../collector/CollectorEntity'; +import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; export class DeclarationReferenceGenerator { public static readonly unknownReference: string = '?'; @@ -109,34 +110,27 @@ export class DeclarationReferenceGenerator { return Navigation.Exports; } - // Otherwise, this symbol is from the current package. - if (parent) { - // If we've found an exported CollectorEntity, then it's exported from the package entry point, so - // use Exports. - const namedDeclaration: ts.DeclarationName | undefined = ( - declaration as ts.NamedDeclaration | undefined - )?.name; - if (namedDeclaration && ts.isIdentifier(namedDeclaration)) { - const collectorEntity: CollectorEntity | undefined = - this._collector.tryGetEntityForNode(namedDeclaration); - if (collectorEntity && collectorEntity.exported) { - return Navigation.Exports; - } - } - - // If its parent symbol is not a source file, then use either Exports or Members. If the parent symbol - // is a source file, but it wasn't exported from the package entry point (in the check above), then the - // symbol is a local, so fall through below. - if (!DeclarationReferenceGenerator._isExternalModuleSymbol(parent)) { - if ( - parent.members && - DeclarationReferenceGenerator._isSameSymbol(parent.members.get(symbol.escapedName), symbol) - ) { - return Navigation.Members; - } + // Otherwise, this symbol is from the current package. If we've found an associated consumable + // `CollectorEntity`, then use Exports. We use `consumable` here instead of `exported` because + // if the symbol is exported from a non-consumable `AstNamespaceImport`, we don't want to use + // Exports. We should use Locals instead. + const entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(symbol); + if (entity?.consumable) { + return Navigation.Exports; + } - return Navigation.Exports; + // If its parent symbol is not a source file, then use either Exports or Members. If the parent symbol + // is a source file, but it wasn't exported from the package entry point (in the check above), then the + // symbol is a local, so fall through below. + if (parent && !DeclarationReferenceGenerator._isExternalModuleSymbol(parent)) { + if ( + parent.members && + DeclarationReferenceGenerator._isSameSymbol(parent.members.get(symbol.escapedName), symbol) + ) { + return Navigation.Members; } + + return Navigation.Exports; } // Otherwise, we have a local symbol, so use a Locals navigation. These are either: @@ -209,6 +203,12 @@ 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)) { @@ -229,6 +229,11 @@ export class DeclarationReferenceGenerator { } let localName: string = followedSymbol.name; + const entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(followedSymbol); + if (entity?.nameForEmit) { + localName = entity.nameForEmit; + } + if (followedSymbol.escapedName === ts.InternalSymbolName.Constructor) { localName = 'constructor'; } else { @@ -267,8 +272,38 @@ export class DeclarationReferenceGenerator { private _getParentReference(symbol: ts.Symbol): DeclarationReference | undefined { const declaration: ts.Node | undefined = TypeScriptHelpers.tryGetADeclaration(symbol); + const sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile(); + + // Note that it's possible for a symbol to be exported from an entry point as well as one or more + // namespaces. In that case, it's not clear what to choose as its parent. Today's logic is neither + // perfect nor particularly stable to API items being renamed and shuffled around. + const entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(symbol); + if (entity) { + if (entity.exportedFromEntryPoint) { + return new DeclarationReference(this._sourceFileToModuleSource(sourceFile)); + } + + const firstExportingConsumableParent: CollectorEntity | undefined = + entity.getFirstExportingConsumableParent(); + if ( + firstExportingConsumableParent && + firstExportingConsumableParent.astEntity instanceof AstNamespaceImport + ) { + const parentSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration( + firstExportingConsumableParent.astEntity.declaration, + this._collector.typeChecker + ); + if (parentSymbol) { + return this._symbolToDeclarationReference( + parentSymbol, + parentSymbol.flags, + /*includeModuleSymbols*/ true + ); + } + } + } - // First, try to find a parent symbol via the symbol tree. + // Next, try to find a parent symbol via the symbol tree. const parentSymbol: ts.Symbol | undefined = TypeScriptInternals.getSymbolParent(symbol); if (parentSymbol) { return this._symbolToDeclarationReference( @@ -306,7 +341,6 @@ export class DeclarationReferenceGenerator { } // At this point, we have a local symbol in a module. - const sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile(); if (sourceFile && ts.isExternalModule(sourceFile)) { return new DeclarationReference(this._sourceFileToModuleSource(sourceFile)); } else { diff --git a/build-tests/api-extractor-scenarios/config/build-config.json b/build-tests/api-extractor-scenarios/config/build-config.json index 1761235a0ad..3c41f30a625 100644 --- a/build-tests/api-extractor-scenarios/config/build-config.json +++ b/build-tests/api-extractor-scenarios/config/build-config.json @@ -14,6 +14,8 @@ "docReferences", "docReferences2", "docReferences3", + "docReferencesAlias", + "docReferencesNamespaceAlias", "dynamicImportType", "dynamicImportType2", "dynamicImportType3", diff --git a/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json index 334ad0d65a5..1b66cfe5812 100644 --- a/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json @@ -197,7 +197,7 @@ { "kind": "Reference", "text": "MyPromise", - "canonicalReference": "api-extractor-scenarios!~Promise:class" + "canonicalReference": "api-extractor-scenarios!~Promise_2:class" }, { "kind": "Content", diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.json new file mode 100644 index 00000000000..4cefa690518 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.json @@ -0,0 +1,296 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "[test mode]", + "schemaVersion": 1009, + "oldestForwardsCompatibleVersion": 1001, + "tsdocConfig": { + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "noStandardTags": true, + "tagDefinitions": [ + { + "tagName": "@alpha", + "syntaxKind": "modifier" + }, + { + "tagName": "@beta", + "syntaxKind": "modifier" + }, + { + "tagName": "@defaultValue", + "syntaxKind": "block" + }, + { + "tagName": "@decorator", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@deprecated", + "syntaxKind": "block" + }, + { + "tagName": "@eventProperty", + "syntaxKind": "modifier" + }, + { + "tagName": "@example", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@experimental", + "syntaxKind": "modifier" + }, + { + "tagName": "@inheritDoc", + "syntaxKind": "inline" + }, + { + "tagName": "@internal", + "syntaxKind": "modifier" + }, + { + "tagName": "@label", + "syntaxKind": "inline" + }, + { + "tagName": "@link", + "syntaxKind": "inline", + "allowMultiple": true + }, + { + "tagName": "@override", + "syntaxKind": "modifier" + }, + { + "tagName": "@packageDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@param", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@privateRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@public", + "syntaxKind": "modifier" + }, + { + "tagName": "@readonly", + "syntaxKind": "modifier" + }, + { + "tagName": "@remarks", + "syntaxKind": "block" + }, + { + "tagName": "@returns", + "syntaxKind": "block" + }, + { + "tagName": "@sealed", + "syntaxKind": "modifier" + }, + { + "tagName": "@see", + "syntaxKind": "block" + }, + { + "tagName": "@throws", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@typeParam", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@virtual", + "syntaxKind": "modifier" + }, + { + "tagName": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@alpha": true, + "@beta": true, + "@defaultValue": true, + "@decorator": true, + "@deprecated": true, + "@eventProperty": true, + "@example": true, + "@experimental": true, + "@inheritDoc": true, + "@internal": true, + "@label": true, + "@link": true, + "@override": true, + "@packageDocumentation": true, + "@param": true, + "@privateRemarks": true, + "@public": true, + "@readonly": true, + "@remarks": true, + "@returns": true, + "@sealed": true, + "@see": true, + "@throws": true, + "@typeParam": true, + "@virtual": true, + "@betaDocumentation": true, + "@internalRemarks": true, + "@preapproved": true + }, + "reportUnsupportedHtmlElements": false + } + }, + "kind": "Package", + "canonicalReference": "api-extractor-scenarios!", + "docComment": "", + "name": "api-extractor-scenarios", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-scenarios!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!Item:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default class Item " + } + ], + "releaseTag": "Public", + "name": "Item", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#options:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "options: " + }, + { + "kind": "Reference", + "text": "Options", + "canonicalReference": "api-extractor-scenarios!renamed_Options:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "options", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!renamed_Options:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default interface Options " + } + ], + "releaseTag": "Public", + "name": "renamed_Options", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed_Options#color:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "color: " + }, + { + "kind": "Content", + "text": "'red' | 'blue'" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "color", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed_Options#name:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "name: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "name", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..e5dbeddb60e --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.md @@ -0,0 +1,23 @@ +## API Report File for "api-extractor-scenarios" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class Item { + // (undocumented) + options: renamed_Options; +} + +// @public (undocumented) +export interface renamed_Options { + // (undocumented) + color: 'red' | 'blue'; + // (undocumented) + name: string; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesAlias/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/rollup.d.ts new file mode 100644 index 00000000000..36cac4b715d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/rollup.d.ts @@ -0,0 +1,12 @@ +/** @public */ +export declare class Item { + options: renamed_Options; +} + +/** @public */ +export declare interface renamed_Options { + name: string; + color: 'red' | 'blue'; +} + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.json new file mode 100644 index 00000000000..d04711be940 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.json @@ -0,0 +1,390 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "[test mode]", + "schemaVersion": 1009, + "oldestForwardsCompatibleVersion": 1001, + "tsdocConfig": { + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "noStandardTags": true, + "tagDefinitions": [ + { + "tagName": "@alpha", + "syntaxKind": "modifier" + }, + { + "tagName": "@beta", + "syntaxKind": "modifier" + }, + { + "tagName": "@defaultValue", + "syntaxKind": "block" + }, + { + "tagName": "@decorator", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@deprecated", + "syntaxKind": "block" + }, + { + "tagName": "@eventProperty", + "syntaxKind": "modifier" + }, + { + "tagName": "@example", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@experimental", + "syntaxKind": "modifier" + }, + { + "tagName": "@inheritDoc", + "syntaxKind": "inline" + }, + { + "tagName": "@internal", + "syntaxKind": "modifier" + }, + { + "tagName": "@label", + "syntaxKind": "inline" + }, + { + "tagName": "@link", + "syntaxKind": "inline", + "allowMultiple": true + }, + { + "tagName": "@override", + "syntaxKind": "modifier" + }, + { + "tagName": "@packageDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@param", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@privateRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@public", + "syntaxKind": "modifier" + }, + { + "tagName": "@readonly", + "syntaxKind": "modifier" + }, + { + "tagName": "@remarks", + "syntaxKind": "block" + }, + { + "tagName": "@returns", + "syntaxKind": "block" + }, + { + "tagName": "@sealed", + "syntaxKind": "modifier" + }, + { + "tagName": "@see", + "syntaxKind": "block" + }, + { + "tagName": "@throws", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@typeParam", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@virtual", + "syntaxKind": "modifier" + }, + { + "tagName": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@alpha": true, + "@beta": true, + "@defaultValue": true, + "@decorator": true, + "@deprecated": true, + "@eventProperty": true, + "@example": true, + "@experimental": true, + "@inheritDoc": true, + "@internal": true, + "@label": true, + "@link": true, + "@override": true, + "@packageDocumentation": true, + "@param": true, + "@privateRemarks": true, + "@public": true, + "@readonly": true, + "@remarks": true, + "@returns": true, + "@sealed": true, + "@see": true, + "@throws": true, + "@typeParam": true, + "@virtual": true, + "@betaDocumentation": true, + "@internalRemarks": true, + "@preapproved": true + }, + "reportUnsupportedHtmlElements": false + } + }, + "kind": "Package", + "canonicalReference": "api-extractor-scenarios!", + "docComment": "", + "name": "api-extractor-scenarios", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-scenarios!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!Item:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default class Item " + } + ], + "releaseTag": "Public", + "name": "Item", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Property", + "canonicalReference": "api-extractor-scenarios!Item#options:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "options: " + }, + { + "kind": "Reference", + "text": "Options", + "canonicalReference": "api-extractor-scenarios!renamed.Options:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "options", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false + } + ], + "implementsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!renamed:namespace", + "docComment": "", + "excerptTokens": [], + "releaseTag": "None", + "name": "renamed", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!renamed.Options:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default interface Options " + } + ], + "releaseTag": "Public", + "name": "Options", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed.Options#color:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "color: " + }, + { + "kind": "Content", + "text": "'red' | 'blue'" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "color", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed.Options#name:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "name: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "name", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed.Options#subOptions:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "subOptions: " + }, + { + "kind": "Reference", + "text": "SubOptions", + "canonicalReference": "api-extractor-scenarios!renamed.sub.SubOptions:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "subOptions", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!renamed.sub:namespace", + "docComment": "", + "excerptTokens": [], + "releaseTag": "None", + "name": "sub", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!renamed.sub.SubOptions:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export default interface SubOptions " + } + ], + "releaseTag": "Public", + "name": "SubOptions", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!renamed.sub.SubOptions#count:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "count: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "count", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + } + ] + } + ] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..090e96727ac --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.md @@ -0,0 +1,45 @@ +## API Report File for "api-extractor-scenarios" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class Item { + // (undocumented) + options: Options; +} + +// @public (undocumented) +interface Options { + // (undocumented) + color: 'red' | 'blue'; + // (undocumented) + name: string; + // (undocumented) + subOptions: SubOptions; +} + +declare namespace renamed { + export { + sub, + Options + } +} +export { renamed } + +declare namespace sub { + export { + SubOptions + } +} + +// @public (undocumented) +interface SubOptions { + // (undocumented) + count: number; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/rollup.d.ts new file mode 100644 index 00000000000..0c7a1f4c742 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/rollup.d.ts @@ -0,0 +1,32 @@ +/** @public */ +export declare class Item { + options: Options; +} + +/** @public */ +declare interface Options { + name: string; + color: 'red' | 'blue'; + subOptions: SubOptions; +} + +declare namespace renamed { + export { + sub, + Options + } +} +export { renamed } + +declare namespace sub { + export { + SubOptions + } +} + +/** @public */ +declare interface SubOptions { + count: number; +} + +export { } 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 fc67ce054b7..5ac4b1403d8 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 @@ -190,14 +190,10 @@ "kind": "Content", "text": "export declare function exportedApi(): " }, - { - "kind": "Content", - "text": "forgottenNs." - }, { "kind": "Reference", - "text": "ForgottenClass", - "canonicalReference": "api-extractor-scenarios!ForgottenClass:class" + "text": "forgottenNs.ForgottenClass", + "canonicalReference": "api-extractor-scenarios!~ForgottenClass:class" }, { "kind": "Content", @@ -206,7 +202,7 @@ ], "returnTypeTokenRange": { "startIndex": 1, - "endIndex": 3 + "endIndex": 2 }, "releaseTag": "Public", "overloadIndex": 1, diff --git a/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.json index c7fd110c62c..838ef3da2a9 100644 --- a/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.json @@ -183,11 +183,11 @@ }, { "kind": "Content", - "text": "typeof colors." + "text": "typeof " }, { "kind": "Reference", - "text": "zebra", + "text": "colors.zebra", "canonicalReference": "colors!zebra:var" }, { 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 44f24de36f1..637c6966322 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 @@ -456,7 +456,7 @@ { "kind": "Reference", "text": "DuplicateName", - "canonicalReference": "api-extractor-scenarios!~DuplicateName:type" + "canonicalReference": "api-extractor-scenarios!~DuplicateName_2:type" }, { "kind": "Content", @@ -509,14 +509,10 @@ "kind": "Content", "text": "export declare function someFunction5(): " }, - { - "kind": "Content", - "text": "internal2." - }, { "kind": "Reference", - "text": "ForgottenExport6", - "canonicalReference": "api-extractor-scenarios!ForgottenExport6:class" + "text": "internal2.ForgottenExport6", + "canonicalReference": "api-extractor-scenarios!~ForgottenExport6:class" }, { "kind": "Content", @@ -525,7 +521,7 @@ ], "returnTypeTokenRange": { "startIndex": 1, - "endIndex": 3 + "endIndex": 2 }, "releaseTag": "Public", "overloadIndex": 1, @@ -572,7 +568,7 @@ { "kind": "Reference", "text": "AnotherDuplicateName", - "canonicalReference": "api-extractor-scenarios!~AnotherDuplicateName:class" + "canonicalReference": "api-extractor-scenarios!~AnotherDuplicateName_2:class" }, { "kind": "Content", diff --git a/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.json index b6b1a46acac..4f050369a44 100644 --- a/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.json @@ -257,14 +257,10 @@ "kind": "Content", "text": "export declare function someFunction(): " }, - { - "kind": "Content", - "text": "i1.internal." - }, { "kind": "Reference", - "text": "SomeClass", - "canonicalReference": "api-extractor-scenarios!SomeClass:class" + "text": "i1.internal.SomeClass", + "canonicalReference": "api-extractor-scenarios!i1.internal.SomeClass:class" }, { "kind": "Content", @@ -273,7 +269,7 @@ ], "returnTypeTokenRange": { "startIndex": 1, - "endIndex": 3 + "endIndex": 2 }, "releaseTag": "Public", "overloadIndex": 1, diff --git a/build-tests/api-extractor-scenarios/src/docReferencesAlias/Item.ts b/build-tests/api-extractor-scenarios/src/docReferencesAlias/Item.ts new file mode 100644 index 00000000000..fd9fe5ecfe5 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesAlias/Item.ts @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import Options from './Options'; + +/** @public */ +export default class Item { + options: Options; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesAlias/Options.ts b/build-tests/api-extractor-scenarios/src/docReferencesAlias/Options.ts new file mode 100644 index 00000000000..a2586a59a87 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesAlias/Options.ts @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** @public */ +export default interface Options { + name: string; + color: 'red' | 'blue'; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesAlias/index.ts b/build-tests/api-extractor-scenarios/src/docReferencesAlias/index.ts new file mode 100644 index 00000000000..5eb64bd7644 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesAlias/index.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export { default as renamed_Options } from './Options'; +export { default as Item } from './Item'; diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/Item.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/Item.ts new file mode 100644 index 00000000000..247b3f48835 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/Item.ts @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import Options from './renamed/Options'; + +/** @public */ +export default class Item { + options: Options; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/index.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/index.ts new file mode 100644 index 00000000000..e5ae676d355 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/index.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as renamed from './renamed'; +export { renamed }; +export { default as Item } from './Item'; diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/Options.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/Options.ts new file mode 100644 index 00000000000..d58c03679aa --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/Options.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import SubOptions from './sub/SubOptions'; + +/** @public */ +export default interface Options { + name: string; + color: 'red' | 'blue'; + subOptions: SubOptions; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/index.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/index.ts new file mode 100644 index 00000000000..1066c9b2a0d --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/index.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as sub from './sub'; +export { sub }; +export { default as Options } from './Options'; diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/SubOptions.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/SubOptions.ts new file mode 100644 index 00000000000..bc413e17cc0 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/SubOptions.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** @public */ +export default interface SubOptions { + count: number; +} diff --git a/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/index.ts b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/index.ts new file mode 100644 index 00000000000..bbef81bf862 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/docReferencesNamespaceAlias/renamed/sub/index.ts @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export { default as SubOptions } from './SubOptions'; diff --git a/build-tests/api-extractor-scenarios/src/runScenarios.ts b/build-tests/api-extractor-scenarios/src/runScenarios.ts index a973ed03b0e..54863dc9863 100644 --- a/build-tests/api-extractor-scenarios/src/runScenarios.ts +++ b/build-tests/api-extractor-scenarios/src/runScenarios.ts @@ -58,6 +58,8 @@ export function runScenarios(buildConfigPath: string): void { apiJsonFilePath: `/etc/${scenarioFolderName}/.api.json` }, + newlineKind: 'os', + messages: { extractorMessageReporting: { // For test purposes, write these warnings into .api.md diff --git a/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml b/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml index d2a0cecd89a..15f9f5dd235 100644 --- a/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml +++ b/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml @@ -460,7 +460,7 @@ packages: dev: true /concat-map/0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true /cross-spawn/7.0.3: diff --git a/common/changes/@microsoft/api-extractor/fwienber-api-extractor-fix-3593-reference-alias_2022-08-29-07-53.json b/common/changes/@microsoft/api-extractor/fwienber-api-extractor-fix-3593-reference-alias_2022-08-29-07-53.json new file mode 100644 index 00000000000..5e475cc3da5 --- /dev/null +++ b/common/changes/@microsoft/api-extractor/fwienber-api-extractor-fix-3593-reference-alias_2022-08-29-07-53.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/api-extractor", + "comment": "Fix an issue where aliased classes sometimes had incorrect canonical references in *.api.json (GitHub #3593)", + "type": "minor" + } + ], + "packageName": "@microsoft/api-extractor" +} \ No newline at end of file