diff --git a/apps/api-extractor/src/collector/Collector.ts b/apps/api-extractor/src/collector/Collector.ts index f5ca10d6802..6869d70d499 100644 --- a/apps/api-extractor/src/collector/Collector.ts +++ b/apps/api-extractor/src/collector/Collector.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as path from 'path'; + import * as ts from 'typescript'; import * as tsdoc from '@microsoft/tsdoc'; import { PackageJsonLookup, Sort, InternalError } from '@rushstack/node-core-library'; @@ -43,6 +45,29 @@ export interface ICollectorOptions { extractorConfig: ExtractorConfig; } +/** + * Resolve the name of a file to an absolute path relative to a TypeScript SourceFile node. + */ +function resolveNameRelativeToSourceFile(name: string, source: ts.SourceFile): string { + const output: string[] = source.fileName.split(path.sep).slice(0, -1); + + // Process the file name, treating special selectors such as '..' and '.' and '' correctly + for (const fragment of name.split('/')) { + switch (fragment) { + case '..': // parent selector + output.pop(); + break; + case '.': // same-dir selectors + case '': + break; + default: + output.push(fragment); + } + } + + return output.join(path.sep); +} + /** * The `Collector` manages the overall data set that is used by `ApiModelGenerator`, * `DtsRollupGenerator`, and `ApiReportGenerator`. Starting from the working package's entry point, @@ -84,6 +109,7 @@ export class Collector { private readonly _dtsTypeReferenceDirectives: Set = new Set(); private readonly _dtsLibReferenceDirectives: Set = new Set(); + private readonly _dtsFileReferenceDirectives: Set = new Set(); // Used by getOverloadIndex() private readonly _cachedOverloadIndexesByDeclaration: Map; @@ -158,6 +184,17 @@ export class Collector { return this._dtsLibReferenceDirectives; } + /** + * A list of names (e.g. "runtime-library") that should appear in a path-based reference like this: + * + * ``` + * /// + * ``` + */ + public get dtsFileReferenceDirectives(): ReadonlySet { + return this._dtsFileReferenceDirectives; + } + public get entities(): ReadonlyArray { return this._entities; } @@ -262,6 +299,7 @@ export class Collector { Sort.sortBy(this._entities, (x) => x.getSortKey()); Sort.sortSet(this._dtsTypeReferenceDirectives); Sort.sortSet(this._dtsLibReferenceDirectives); + Sort.sortSet(this._dtsFileReferenceDirectives); this._starExportedExternalModulePaths.sort(); } @@ -875,6 +913,11 @@ export class Collector { ); this._dtsLibReferenceDirectives.add(name); } + + for (const referencedFile of sourceFile.referencedFiles) { + const name: string = sourceFile.text.substring(referencedFile.pos, referencedFile.end); + this._dtsFileReferenceDirectives.add(resolveNameRelativeToSourceFile(name, sourceFile)); + } } } } diff --git a/apps/api-extractor/src/generators/DtsRollupGenerator.ts b/apps/api-extractor/src/generators/DtsRollupGenerator.ts index 8c7b46bc2cd..f9e9d399887 100644 --- a/apps/api-extractor/src/generators/DtsRollupGenerator.ts +++ b/apps/api-extractor/src/generators/DtsRollupGenerator.ts @@ -3,6 +3,8 @@ /* eslint-disable no-bitwise */ +import * as path from 'path'; + import * as ts from 'typescript'; import { FileSystem, NewlineKind, InternalError } from '@rushstack/node-core-library'; import { ReleaseTag } from '@microsoft/api-extractor-model'; @@ -59,7 +61,7 @@ export class DtsRollupGenerator { ): void { const stringWriter: StringWriter = new StringWriter(); - DtsRollupGenerator._generateTypingsFileContent(collector, stringWriter, dtsKind); + DtsRollupGenerator._generateTypingsFileContent(collector, dtsFilename, stringWriter, dtsKind); FileSystem.writeFile(dtsFilename, stringWriter.toString(), { convertLineEndings: newlineKind, @@ -69,6 +71,7 @@ export class DtsRollupGenerator { private static _generateTypingsFileContent( collector: Collector, + dtsFilename: string, stringWriter: StringWriter, dtsKind: DtsRollupKind ): void { @@ -87,6 +90,12 @@ export class DtsRollupGenerator { stringWriter.writeLine(`/// `); } + for (const fileDirectiveReference of collector.dtsFileReferenceDirectives) { + const dtsDirname: string = path.dirname(dtsFilename); + const correctedRelativePath: string = path.relative(dtsDirname, fileDirectiveReference); + stringWriter.writeLine(`/// `); + } + // Emit the imports for (const entity of collector.entities) { if (entity.astEntity instanceof AstImport) { diff --git a/build-tests/api-extractor-scenarios/config/build-config.json b/build-tests/api-extractor-scenarios/config/build-config.json index f8ad516b6bd..90d60c83e82 100644 --- a/build-tests/api-extractor-scenarios/config/build-config.json +++ b/build-tests/api-extractor-scenarios/config/build-config.json @@ -21,6 +21,7 @@ "exportStar", "exportStar2", "exportStar3", + "fileReferenceDirectives", "functionOverload", "importEquals", "inconsistentReleaseTags", diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/fileReferenceDirectives/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/fileReferenceDirectives/api-extractor-scenarios.api.json new file mode 100644 index 00000000000..f976fbfe1df --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/test-outputs/fileReferenceDirectives/api-extractor-scenarios.api.json @@ -0,0 +1,43 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "[test mode]", + "schemaVersion": 1003, + "oldestForwardsCompatibleVersion": 1001 + }, + "kind": "Package", + "canonicalReference": "api-extractor-scenarios!", + "docComment": "", + "name": "api-extractor-scenarios", + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-scenarios!", + "name": "", + "members": [ + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!X:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "X: " + }, + { + "kind": "Reference", + "text": "Foo", + "canonicalReference": "!Foo:interface" + } + ], + "releaseTag": "Public", + "name": "X", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/fileReferenceDirectives/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/fileReferenceDirectives/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..26b1faadd39 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/test-outputs/fileReferenceDirectives/api-extractor-scenarios.api.md @@ -0,0 +1,13 @@ +## 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 const X: Foo; + + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/fileReferenceDirectives/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/fileReferenceDirectives/rollup.d.ts new file mode 100644 index 00000000000..7fe7b6563c2 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/test-outputs/fileReferenceDirectives/rollup.d.ts @@ -0,0 +1,8 @@ +/// + +/** + * @public + */ +export declare const X: Foo; + +export { } diff --git a/build-tests/api-extractor-scenarios/src/fileReferenceDirectives/index.ts b/build-tests/api-extractor-scenarios/src/fileReferenceDirectives/index.ts new file mode 100644 index 00000000000..189b96c55f7 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/fileReferenceDirectives/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 { X } from './nested/module'; diff --git a/build-tests/api-extractor-scenarios/src/fileReferenceDirectives/nested/module.ts b/build-tests/api-extractor-scenarios/src/fileReferenceDirectives/nested/module.ts new file mode 100644 index 00000000000..8297f17196a --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/fileReferenceDirectives/nested/module.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. + +/// + +/** + * @public + */ +export const X: Foo = {}; diff --git a/build-tests/api-extractor-scenarios/src/fileReferenceDirectives/shim.d.ts b/build-tests/api-extractor-scenarios/src/fileReferenceDirectives/shim.d.ts new file mode 100644 index 00000000000..f0bc540f55d --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/fileReferenceDirectives/shim.d.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. + +declare interface Foo {}