Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions apps/api-extractor/src/collector/Collector.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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 {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you simply use path.relative()?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this one, I don't think so. I need to boot into Windows and check it, but I believe that the reference directive in text has to follow the POSIX convention and use forward slash as its path separator just like a node module, but the file name of the source file could be in Windows convention, so relying on path to process the reference path may not be safe. Need to do some testing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the input and output paths are POSIX format, then you can use path.posix.relative().

If the input path is Windows style and you want to convert to POSIX, there is no theoretically correct API for that, but Text.replaceAll(thePath, '\\', '/') works reasonably well with Node.js

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,
Expand Down Expand Up @@ -84,6 +109,7 @@ export class Collector {

private readonly _dtsTypeReferenceDirectives: Set<string> = new Set<string>();
private readonly _dtsLibReferenceDirectives: Set<string> = new Set<string>();
private readonly _dtsFileReferenceDirectives: Set<string> = new Set<string>();

// Used by getOverloadIndex()
private readonly _cachedOverloadIndexesByDeclaration: Map<AstDeclaration, number>;
Expand Down Expand Up @@ -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:
*
* ```
* /// <reference path="path/to/example.d.ts" />
* ```
*/
public get dtsFileReferenceDirectives(): ReadonlySet<string> {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The runtime-library example is not intended to be a path. Maybe something like this:

  /**
   * A list of paths (e.g. "path/to/file.d.ts") that should appear in a reference like this:
   *
   * ```
   * /// <reference path="path/to/file.d.ts" />
   * ```
   *
   * The paths are resolved relative to the source file containing the reference.
   */

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yeah just missed this when copying the doc string 👍

return this._dtsFileReferenceDirectives;
}

public get entities(): ReadonlyArray<CollectorEntity> {
return this._entities;
}
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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));
}
}
}
}
Expand Down
11 changes: 10 additions & 1 deletion apps/api-extractor/src/generators/DtsRollupGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand All @@ -69,6 +71,7 @@ export class DtsRollupGenerator {

private static _generateTypingsFileContent(
collector: Collector,
dtsFilename: string,
stringWriter: StringWriter,
dtsKind: DtsRollupKind
): void {
Expand All @@ -87,6 +90,12 @@ export class DtsRollupGenerator {
stringWriter.writeLine(`/// <reference lib="${libDirectiveReference}" />`);
}

for (const fileDirectiveReference of collector.dtsFileReferenceDirectives) {
const dtsDirname: string = path.dirname(dtsFilename);
const correctedRelativePath: string = path.relative(dtsDirname, fileDirectiveReference);
stringWriter.writeLine(`/// <reference path="${correctedRelativePath}" />`);
}

// Emit the imports
for (const entity of collector.entities) {
if (entity.astEntity instanceof AstImport) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"exportStar",
"exportStar2",
"exportStar3",
"fileReferenceDirectives",
"functionOverload",
"importEquals",
"inconsistentReleaseTags",
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -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)

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// <reference path="../../../src/fileReferenceDirectives/shim.d.ts" />

/**
* @public
*/
export declare const X: Foo;

export { }
Original file line number Diff line number Diff line change
@@ -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';
Original file line number Diff line number Diff line change
@@ -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.

/// <reference path="../shim.d.ts" />

/**
* @public
*/
export const X: Foo = {};
Original file line number Diff line number Diff line change
@@ -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 {}