Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
9 changes: 5 additions & 4 deletions apps/api-extractor/src/analyzer/AstModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import type { AstEntity } from './AstEntity';
/**
* Represents information collected by {@link AstSymbolTable.fetchAstModuleExportInfo}
*/
export class AstModuleExportInfo {
public readonly exportedLocalEntities: Map<string, AstEntity> = new Map<string, AstEntity>();
public readonly starExportedExternalModules: Set<AstModule> = new Set<AstModule>();
export interface IAstModuleExportInfo {
readonly visitedAstModules: Set<AstModule>;
readonly exportedLocalEntities: Map<string, AstEntity>;
readonly starExportedExternalModules: Set<AstModule>;
}

/**
Expand Down Expand Up @@ -64,7 +65,7 @@ export class AstModule {
/**
* Additional state calculated by `AstSymbolTable.fetchWorkingPackageModule()`.
*/
public astModuleExportInfo: AstModuleExportInfo | undefined;
public astModuleExportInfo: IAstModuleExportInfo | undefined;

public constructor(options: IAstModuleOptions) {
this.sourceFile = options.sourceFile;
Expand Down
6 changes: 3 additions & 3 deletions apps/api-extractor/src/analyzer/AstNamespaceImport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import type * as ts from 'typescript';

import type { AstModule, AstModuleExportInfo } from './AstModule';
import type { AstModule, IAstModuleExportInfo } from './AstModule';
import { AstSyntheticEntity } from './AstEntity';
import type { Collector } from '../collector/Collector';

Expand Down Expand Up @@ -87,8 +87,8 @@ export class AstNamespaceImport extends AstSyntheticEntity {
return this.namespaceName;
}

public fetchAstModuleExportInfo(collector: Collector): AstModuleExportInfo {
const astModuleExportInfo: AstModuleExportInfo = collector.astSymbolTable.fetchAstModuleExportInfo(
public fetchAstModuleExportInfo(collector: Collector): IAstModuleExportInfo {
const astModuleExportInfo: IAstModuleExportInfo = collector.astSymbolTable.fetchAstModuleExportInfo(
this.astModule
);
return astModuleExportInfo;
Expand Down
4 changes: 2 additions & 2 deletions apps/api-extractor/src/analyzer/AstSymbolTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { type PackageJsonLookup, InternalError } from '@rushstack/node-core-libr
import { AstDeclaration } from './AstDeclaration';
import { TypeScriptHelpers } from './TypeScriptHelpers';
import { AstSymbol } from './AstSymbol';
import type { AstModule, AstModuleExportInfo } from './AstModule';
import type { AstModule, IAstModuleExportInfo } from './AstModule';
import { PackageMetadataManager } from './PackageMetadataManager';
import { ExportAnalyzer } from './ExportAnalyzer';
import type { AstEntity } from './AstEntity';
Expand Down Expand Up @@ -124,7 +124,7 @@ export class AstSymbolTable {
/**
* This crawls the specified entry point and collects the full set of exported AstSymbols.
*/
public fetchAstModuleExportInfo(astModule: AstModule): AstModuleExportInfo {
public fetchAstModuleExportInfo(astModule: AstModule): IAstModuleExportInfo {
return this._exportAnalyzer.fetchAstModuleExportInfo(astModule);
}

Expand Down
27 changes: 14 additions & 13 deletions apps/api-extractor/src/analyzer/ExportAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { InternalError } from '@rushstack/node-core-library';
import { TypeScriptHelpers } from './TypeScriptHelpers';
import { AstSymbol } from './AstSymbol';
import { AstImport, type IAstImportOptions, AstImportKind } from './AstImport';
import { AstModule, AstModuleExportInfo } from './AstModule';
import { AstModule, type IAstModuleExportInfo } from './AstModule';
import { TypeScriptInternals } from './TypeScriptInternals';
import { SourceFileLocationFormatter } from './SourceFileLocationFormatter';
import type { IFetchAstSymbolOptions } from './AstSymbolTable';
Expand Down Expand Up @@ -237,15 +237,19 @@ export class ExportAnalyzer {
/**
* Implementation of {@link AstSymbolTable.fetchAstModuleExportInfo}.
*/
public fetchAstModuleExportInfo(entryPointAstModule: AstModule): AstModuleExportInfo {
public fetchAstModuleExportInfo(entryPointAstModule: AstModule): IAstModuleExportInfo {
if (entryPointAstModule.isExternal) {
throw new Error('fetchAstModuleExportInfo() is not supported for external modules');
}

if (entryPointAstModule.astModuleExportInfo === undefined) {
const astModuleExportInfo: AstModuleExportInfo = new AstModuleExportInfo();
const astModuleExportInfo: IAstModuleExportInfo = {
visitedAstModules: new Set<AstModule>(),
exportedLocalEntities: new Map<string, AstEntity>(),
starExportedExternalModules: new Set<AstModule>()
};

this._collectAllExportsRecursive(astModuleExportInfo, entryPointAstModule, new Set<AstModule>());
this._collectAllExportsRecursive(astModuleExportInfo, entryPointAstModule);

entryPointAstModule.astModuleExportInfo = astModuleExportInfo;
}
Expand Down Expand Up @@ -314,18 +318,15 @@ export class ExportAnalyzer {
return this._importableAmbientSourceFiles.has(sourceFile);
}

private _collectAllExportsRecursive(
astModuleExportInfo: AstModuleExportInfo,
astModule: AstModule,
visitedAstModules: Set<AstModule>
): void {
private _collectAllExportsRecursive(astModuleExportInfo: IAstModuleExportInfo, astModule: AstModule): void {
const { visitedAstModules, starExportedExternalModules, exportedLocalEntities } = astModuleExportInfo;
if (visitedAstModules.has(astModule)) {
return;
}
visitedAstModules.add(astModule);

if (astModule.isExternal) {
astModuleExportInfo.starExportedExternalModules.add(astModule);
starExportedExternalModules.add(astModule);
} else {
// Fetch each of the explicit exports for this module
if (astModule.moduleSymbol.exports) {
Expand All @@ -337,7 +338,7 @@ export class ExportAnalyzer {
default:
// Don't collect the "export default" symbol unless this is the entry point module
if (exportName !== ts.InternalSymbolName.Default || visitedAstModules.size === 1) {
if (!astModuleExportInfo.exportedLocalEntities.has(exportSymbol.name)) {
if (!exportedLocalEntities.has(exportSymbol.name)) {
const astEntity: AstEntity = this._getExportOfAstModule(exportSymbol.name, astModule);

if (astEntity instanceof AstSymbol && !astEntity.isExternal) {
Expand All @@ -348,7 +349,7 @@ export class ExportAnalyzer {
this._astSymbolTable.analyze(astEntity);
}

astModuleExportInfo.exportedLocalEntities.set(exportSymbol.name, astEntity);
exportedLocalEntities.set(exportSymbol.name, astEntity);
}
}
break;
Expand All @@ -357,7 +358,7 @@ export class ExportAnalyzer {
}

for (const starExportedModule of astModule.starExportedModules) {
this._collectAllExportsRecursive(astModuleExportInfo, starExportedModule, visitedAstModules);
this._collectAllExportsRecursive(astModuleExportInfo, starExportedModule);
}
}
}
Expand Down
21 changes: 15 additions & 6 deletions apps/api-extractor/src/collector/Collector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { ExtractorMessageId } from '../api/ExtractorMessageId';
import { CollectorEntity } from './CollectorEntity';
import { AstSymbolTable } from '../analyzer/AstSymbolTable';
import type { AstEntity } from '../analyzer/AstEntity';
import type { AstModule, AstModuleExportInfo } from '../analyzer/AstModule';
import type { AstModule, IAstModuleExportInfo } from '../analyzer/AstModule';
import { AstSymbol } from '../analyzer/AstSymbol';
import type { AstDeclaration } from '../analyzer/AstDeclaration';
import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers';
Expand Down Expand Up @@ -313,12 +313,12 @@ export class Collector {
this.workingPackage.tsdocComment = this.workingPackage.tsdocParserContext!.docComment;
}

const astModuleExportInfo: AstModuleExportInfo =
const { exportedLocalEntities, starExportedExternalModules, visitedAstModules }: IAstModuleExportInfo =
this.astSymbolTable.fetchAstModuleExportInfo(astEntryPoint);

// Create a CollectorEntity for each top-level export.
const processedAstEntities: AstEntity[] = [];
for (const [exportName, astEntity] of astModuleExportInfo.exportedLocalEntities) {
for (const [exportName, astEntity] of exportedLocalEntities) {
this._createCollectorEntity(astEntity, exportName);
processedAstEntities.push(astEntity);
}
Expand All @@ -333,9 +333,18 @@ export class Collector {
}
}

// Ensure references are collected from any intermediate files that
// only include exports
const visitedSourceFiles: Set<ts.SourceFile> = new Set();
for (const visitedAstModule of visitedAstModules) {
visitedSourceFiles.add(visitedAstModule.sourceFile);
}

this._collectReferenceDirectivesFromSourceFiles(visitedSourceFiles);

this._makeUniqueNames();

for (const starExportedExternalModule of astModuleExportInfo.starExportedExternalModules) {
for (const starExportedExternalModule of starExportedExternalModules) {
if (starExportedExternalModule.externalModulePath !== undefined) {
this._starExportedExternalModulePaths.push(starExportedExternalModule.externalModulePath);
}
Expand Down Expand Up @@ -539,7 +548,7 @@ export class Collector {
}

if (astEntity instanceof AstNamespaceImport) {
const astModuleExportInfo: AstModuleExportInfo = astEntity.fetchAstModuleExportInfo(this);
const astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(this);
const parentEntity: CollectorEntity | undefined = this._entitiesByAstEntity.get(astEntity);
if (!parentEntity) {
// This should never happen, as we've already created entities for all AstNamespaceImports.
Expand Down Expand Up @@ -1005,7 +1014,7 @@ export class Collector {
}
}

private _collectReferenceDirectivesFromSourceFiles(sourceFiles: ts.SourceFile[]): void {
private _collectReferenceDirectivesFromSourceFiles(sourceFiles: Iterable<ts.SourceFile>): void {
const seenFilenames: Set<string> = new Set<string>();

for (const sourceFile of sourceFiles) {
Expand Down
4 changes: 2 additions & 2 deletions apps/api-extractor/src/enhancers/ValidationEnhancer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { CollectorEntity } from '../collector/CollectorEntity';
import { ExtractorMessageId } from '../api/ExtractorMessageId';
import { ReleaseTag } from '@microsoft/api-extractor-model';
import { AstNamespaceImport } from '../analyzer/AstNamespaceImport';
import type { AstModuleExportInfo } from '../analyzer/AstModule';
import type { IAstModuleExportInfo } from '../analyzer/AstModule';
import type { AstEntity } from '../analyzer/AstEntity';

export class ValidationEnhancer {
Expand Down Expand Up @@ -47,7 +47,7 @@ export class ValidationEnhancer {
// A namespace created using "import * as ___ from ___"
const astNamespaceImport: AstNamespaceImport = entity.astEntity;

const astModuleExportInfo: AstModuleExportInfo =
const astModuleExportInfo: IAstModuleExportInfo =
astNamespaceImport.fetchAstModuleExportInfo(collector);

for (const namespaceMemberAstEntity of astModuleExportInfo.exportedLocalEntities.values()) {
Expand Down
4 changes: 2 additions & 2 deletions apps/api-extractor/src/generators/ApiReportGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { IndentedWriter } from './IndentedWriter';
import { DtsEmitHelpers } from './DtsEmitHelpers';
import { AstNamespaceImport } from '../analyzer/AstNamespaceImport';
import type { AstEntity } from '../analyzer/AstEntity';
import type { AstModuleExportInfo } from '../analyzer/AstModule';
import type { IAstModuleExportInfo } from '../analyzer/AstModule';
import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter';
import { ExtractorMessageId } from '../api/ExtractorMessageId';
import type { ApiReportVariant } from '../api/IConfigFile';
Expand Down Expand Up @@ -153,7 +153,7 @@ export class ApiReportGenerator {
}

if (astEntity instanceof AstNamespaceImport) {
const astModuleExportInfo: AstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector);
const astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector);

if (entity.nameForEmit === undefined) {
// This should never happen
Expand Down
4 changes: 2 additions & 2 deletions apps/api-extractor/src/generators/DtsRollupGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { IndentedWriter } from './IndentedWriter';
import { DtsEmitHelpers } from './DtsEmitHelpers';
import type { DeclarationMetadata } from '../collector/DeclarationMetadata';
import { AstNamespaceImport } from '../analyzer/AstNamespaceImport';
import type { AstModuleExportInfo } from '../analyzer/AstModule';
import type { IAstModuleExportInfo } from '../analyzer/AstModule';
import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter';
import type { AstEntity } from '../analyzer/AstEntity';

Expand Down Expand Up @@ -153,7 +153,7 @@ export class DtsRollupGenerator {
}

if (astEntity instanceof AstNamespaceImport) {
const astModuleExportInfo: AstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector);
const astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector);

if (entity.nameForEmit === undefined) {
// This should never happen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* @packageDocumentation
*/

/// <reference types="long" />

import { ISimpleInterface } from 'api-extractor-test-01';
import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01';
import * as semver1 from 'semver';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* @packageDocumentation
*/

/// <reference types="long" />

import { ISimpleInterface } from 'api-extractor-test-01';
import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01';
import * as semver1 from 'semver';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* @packageDocumentation
*/

/// <reference types="long" />

import { ISimpleInterface } from 'api-extractor-test-01';
import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01';
import * as semver1 from 'semver';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* @packageDocumentation
*/

/// <reference types="long" />

import { ISimpleInterface } from 'api-extractor-test-01';
import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01';
import * as semver1 from 'semver';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

```ts

/// <reference types="long" />

import { ISimpleInterface } from 'api-extractor-test-01';
import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01';
import * as semver1 from 'semver';
Expand Down
4 changes: 3 additions & 1 deletion build-tests/api-extractor-test-02/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
"_phase:build": "heft run --only build -- --clean"
},
"dependencies": {
"@types/long": "4.0.0",
"@types/semver": "7.5.0",
"api-extractor-test-01": "workspace:*",
"semver": "~7.5.4"
},
"devDependencies": {
"@rushstack/heft": "workspace:*",
"local-node-rig": "workspace:*"
"local-node-rig": "workspace:*",
"typescript": "5.7.3"
}
}
7 changes: 7 additions & 0 deletions build-tests/api-extractor-test-02/src/Ambient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AmbientConsumer } from 'api-extractor-test-01';

// Test that the ambient types are accessible even though api-extractor-02 doesn't
// import Jest
const x = new AmbientConsumer();
const y = x.definitelyTyped();
const z = y.results;
9 changes: 2 additions & 7 deletions build-tests/api-extractor-test-02/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// See LICENSE in the project root for license information.

/// <reference path="../typings/tsd.d.ts" />
/// <reference types="long" preserve="true" />

/**
* api-extractor-test-02
Expand All @@ -19,10 +20,4 @@ export { importDeduping1 } from './ImportDeduping1';
export { importDeduping2 } from './ImportDeduping2';
export { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01';

import { AmbientConsumer } from 'api-extractor-test-01';

// Test that the ambient types are accessible even though api-extractor-02 doesn't
// import Jest
const x = new AmbientConsumer();
const y = x.definitelyTyped();
const z = y.results;
export * from './Ambient';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@microsoft/api-extractor",
"comment": "Fix an issue where a triple-slash reference with `preserve=\"true\"` in a file that only contains re-exports does not end up in the API report and API rollup.",
"type": "patch"
}
],
"packageName": "@microsoft/api-extractor"
}
7 changes: 6 additions & 1 deletion common/config/subspaces/default/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion common/config/subspaces/default/repo-state.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.
{
"pnpmShrinkwrapHash": "0476ebdfbcb88d0d6c1587a2b3e40a946f843a26",
"pnpmShrinkwrapHash": "e43544f5a3ee15e44e24de0f9ef5b54a88414950",
"preferredVersionsHash": "ce857ea0536b894ec8f346aaea08cfd85a5af648"
}