diff --git a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts index 09d9c70acc9..b7c9ad7ab97 100644 --- a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts +++ b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts @@ -259,11 +259,18 @@ export class ExportAnalyzer { importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode, moduleSpecifier: string ): boolean { - const resolvedModule: ts.ResolvedModuleFull = this._getResolvedModule( - importOrExportDeclaration, + const resolvedModule: ts.ResolvedModuleFull | undefined = TypeScriptInternals.getResolvedModule( + importOrExportDeclaration.getSourceFile(), moduleSpecifier ); + if (resolvedModule === undefined) { + // The TS compiler API `getResolvedModule` cannot resolve ambient modules. Thus, to match API Extractor's + // previous behavior, simply treat all ambient modules as external. This bug is tracked by + // https://github.com/microsoft/rushstack/issues/3335. + return true; + } + // Either something like `jquery` or `@microsoft/api-extractor`. const packageName: string | undefined = resolvedModule.packageId?.name; if (packageName !== undefined && this._bundledPackageNames.has(packageName)) { @@ -856,11 +863,23 @@ export class ExportAnalyzer { exportSymbol: ts.Symbol ): AstModule { const moduleSpecifier: string = this._getModuleSpecifier(importOrExportDeclaration); - const resolvedModule: ts.ResolvedModuleFull = this._getResolvedModule( - importOrExportDeclaration, + const resolvedModule: ts.ResolvedModuleFull | undefined = TypeScriptInternals.getResolvedModule( + importOrExportDeclaration.getSourceFile(), moduleSpecifier ); + if (resolvedModule === undefined) { + // Encountered in https://github.com/microsoft/rushstack/issues/1914. + // + // It's also possible for this to occur with ambient modules. However, in practice this doesn't happen + // as API Extractor treats all ambient modules as external per the logic in `_isExternalModulePath`, and + // thus this code path is never reached for ambient modules. + throw new InternalError( + `getResolvedModule() could not resolve module name ${JSON.stringify(moduleSpecifier)}\n` + + SourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration) + ); + } + // Map the filename back to the corresponding SourceFile. This circuitous approach is needed because // we have no way to access the compiler's internal resolveExternalModuleName() function const moduleSourceFile: ts.SourceFile | undefined = this._program.getSourceFile( @@ -919,29 +938,6 @@ export class ExportAnalyzer { return astImport; } - private _getResolvedModule( - importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode, - moduleSpecifier: string - ): ts.ResolvedModuleFull { - const resolvedModule: ts.ResolvedModuleFull | undefined = TypeScriptInternals.getResolvedModule( - importOrExportDeclaration.getSourceFile(), - moduleSpecifier - ); - - if (resolvedModule === undefined) { - // This should not happen, since getResolvedModule() specifically looks up names that the compiler - // found in export declarations for this source file - // - // Encountered in https://github.com/microsoft/rushstack/issues/1914 - throw new InternalError( - `getResolvedModule() could not resolve module name ${JSON.stringify(moduleSpecifier)}\n` + - SourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration) - ); - } - - return resolvedModule; - } - private _getModuleSpecifier( importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode ): string { diff --git a/build-tests/api-extractor-scenarios/config/build-config.json b/build-tests/api-extractor-scenarios/config/build-config.json index a6c0a5e7e64..dc194fe5192 100644 --- a/build-tests/api-extractor-scenarios/config/build-config.json +++ b/build-tests/api-extractor-scenarios/config/build-config.json @@ -34,7 +34,6 @@ "inconsistentReleaseTags", "internationalCharacters", "namedDefaultImport", - "pathMappings", "preapproved", "spanSorting", "typeOf", diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/pathMappings/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/pathMappings/api-extractor-scenarios.api.json deleted file mode 100644 index fddf491490f..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/pathMappings/api-extractor-scenarios.api.json +++ /dev/null @@ -1,448 +0,0 @@ -{ - "metadata": { - "toolPackage": "@microsoft/api-extractor", - "toolVersion": "[test mode]", - "schemaVersion": 1005, - "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 - } - } - }, - "kind": "Package", - "canonicalReference": "api-extractor-scenarios!", - "docComment": "", - "name": "api-extractor-scenarios", - "members": [ - { - "kind": "EntryPoint", - "canonicalReference": "api-extractor-scenarios!", - "name": "", - "members": [ - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!AbstractClass:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export abstract class AbstractClass " - } - ], - "releaseTag": "Public", - "name": "AbstractClass", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!AbstractClass#member:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "public abstract member(): " - }, - { - "kind": "Content", - "text": "void" - }, - { - "kind": "Content", - "text": ";" - } - ], - "isOptional": false, - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "member" - } - ], - "implementsTokenRanges": [] - }, - { - "kind": "Enum", - "canonicalReference": "api-extractor-scenarios!RegularEnum:enum", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export enum RegularEnum " - } - ], - "releaseTag": "Public", - "name": "RegularEnum", - "members": [ - { - "kind": "EnumMember", - "canonicalReference": "api-extractor-scenarios!RegularEnum.One:member", - "docComment": "/**\n * These are some docs for One\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "One = " - }, - { - "kind": "Content", - "text": "1" - } - ], - "releaseTag": "Public", - "name": "One", - "initializerTokenRange": { - "startIndex": 1, - "endIndex": 2 - } - }, - { - "kind": "EnumMember", - "canonicalReference": "api-extractor-scenarios!RegularEnum.Two:member", - "docComment": "/**\n * These are some docs for Two\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "Two = " - }, - { - "kind": "Reference", - "text": "RegularEnum.One", - "canonicalReference": "api-extractor-scenarios!RegularEnum.One:member" - }, - { - "kind": "Content", - "text": " + 1" - } - ], - "releaseTag": "Public", - "name": "Two", - "initializerTokenRange": { - "startIndex": 1, - "endIndex": 3 - } - }, - { - "kind": "EnumMember", - "canonicalReference": "api-extractor-scenarios!RegularEnum.Zero:member", - "docComment": "/**\n * These are some docs for Zero\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "Zero" - } - ], - "releaseTag": "Public", - "name": "Zero", - "initializerTokenRange": { - "startIndex": 0, - "endIndex": 0 - } - } - ] - }, - { - "kind": "Class", - "canonicalReference": "api-extractor-scenarios!SimpleClass:class", - "docComment": "/**\n * @public\n */\n", - "excerptTokens": [ - { - "kind": "Content", - "text": "export class SimpleClass " - } - ], - "releaseTag": "Public", - "name": "SimpleClass", - "members": [ - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!SimpleClass#member:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "public member(): " - }, - { - "kind": "Content", - "text": "void " - }, - { - "kind": "Content", - "text": "{}" - } - ], - "isOptional": false, - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [], - "name": "member" - }, - { - "kind": "Method", - "canonicalReference": "api-extractor-scenarios!SimpleClass#optionalParamMethod:member(1)", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "public optionalParamMethod(x?: " - }, - { - "kind": "Content", - "text": "number" - }, - { - "kind": "Content", - "text": "): " - }, - { - "kind": "Content", - "text": "void " - }, - { - "kind": "Content", - "text": "{}" - } - ], - "isOptional": false, - "isStatic": false, - "returnTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 - }, - "releaseTag": "Public", - "overloadIndex": 1, - "parameters": [ - { - "parameterName": "x", - "parameterTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isOptional": true - } - ], - "name": "optionalParamMethod" - }, - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!SimpleClass#readonlyProperty:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "public get readonlyProperty(): " - }, - { - "kind": "Content", - "text": "string " - }, - { - "kind": "Content", - "text": "{\n return 'hello';\n }" - } - ], - "isOptional": false, - "releaseTag": "Public", - "name": "readonlyProperty", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - }, - { - "kind": "Property", - "canonicalReference": "api-extractor-scenarios!SimpleClass#writeableProperty:member", - "docComment": "", - "excerptTokens": [ - { - "kind": "Content", - "text": "public get writeableProperty(): " - }, - { - "kind": "Content", - "text": "string " - }, - { - "kind": "Content", - "text": "{\n return 'hello';\n }" - }, - { - "kind": "Content", - "text": "\n\npublic set writeableProperty(value: string) {}" - } - ], - "isOptional": false, - "releaseTag": "Public", - "name": "writeableProperty", - "propertyTypeTokenRange": { - "startIndex": 1, - "endIndex": 2 - }, - "isStatic": false - } - ], - "implementsTokenRanges": [] - } - ] - } - ] -} diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/pathMappings/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/pathMappings/api-extractor-scenarios.api.md deleted file mode 100644 index a932d81a1a0..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/pathMappings/api-extractor-scenarios.api.md +++ /dev/null @@ -1,45 +0,0 @@ -## 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 abstract class AbstractClass { - // (undocumented) - public abstract member(): void; -} - -// @public (undocumented) -export enum RegularEnum { - One = 1, - - Two = RegularEnum.One + 1, - - Zero -} - -// @public (undocumented) -export class SimpleClass { - // (undocumented) - public member(): void {} - - // (undocumented) - public optionalParamMethod(x?: number): void {} - - // (undocumented) - public get readonlyProperty(): string { - return 'hello'; - } - - // (undocumented) - public get writeableProperty(): string { - return 'hello'; - } - - public set writeableProperty(value: string) {} -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/pathMappings/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/pathMappings/rollup.d.ts deleted file mode 100644 index d7f81f3baab..00000000000 --- a/build-tests/api-extractor-scenarios/etc/test-outputs/pathMappings/rollup.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** @public */ -export declare abstract class AbstractClass { - public abstract member(): void; -} - -/** @public */ -export declare enum RegularEnum { - /** - * These are some docs for Zero - */ - Zero, - - /** - * These are some docs for One - */ - One = 1, - - /** - * These are some docs for Two - */ - Two = RegularEnum.One + 1 -} - -/** @public */ -export declare class SimpleClass { - public member(): void {} - - public optionalParamMethod(x?: number): void {} - - public get readonlyProperty(): string { - return 'hello'; - } - - public get writeableProperty(): string { - return 'hello'; - } - public set writeableProperty(value: string) {} -} - -export { } diff --git a/build-tests/api-extractor-scenarios/src/pathMappings/index.ts b/build-tests/api-extractor-scenarios/src/pathMappings/index.ts deleted file mode 100644 index 90683d28bd7..00000000000 --- a/build-tests/api-extractor-scenarios/src/pathMappings/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -// Relies upon tsconfig `baseUrl` & `paths`. -export { AbstractClass } from 'path-mapping'; -export { SimpleClass } from 'wildcard-path-mapping/apiItemKinds'; - -// Relies upon only tsconfig `baseUrl`. -export { RegularEnum } from 'src/apiItemKinds'; diff --git a/build-tests/api-extractor-scenarios/tsconfig.json b/build-tests/api-extractor-scenarios/tsconfig.json index ced6570b1b2..1799652cc42 100644 --- a/build-tests/api-extractor-scenarios/tsconfig.json +++ b/build-tests/api-extractor-scenarios/tsconfig.json @@ -10,14 +10,7 @@ "strictNullChecks": true, "types": ["node", "jest"], "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib", - - // These properties are only used by the pathMappings/ test scenario. - "baseUrl": ".", - "paths": { - "path-mapping": ["src/apiItemKinds"], - "wildcard-path-mapping/*": ["src/*"] - } + "outDir": "lib" }, "include": ["src/**/*.ts", "typings/tsd.d.ts"] } 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 24daa6581aa..1883010fbd5 100644 --- a/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml +++ b/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml @@ -5,13 +5,13 @@ importers: typescript-newest-test: specifiers: '@rushstack/eslint-config': file:rushstack-eslint-config-2.5.2.tgz - '@rushstack/heft': file:rushstack-heft-0.44.5.tgz + '@rushstack/heft': file:rushstack-heft-0.44.7.tgz eslint: ~8.7.0 tslint: ~5.20.1 typescript: ~4.5.2 devDependencies: '@rushstack/eslint-config': file:../temp/tarballs/rushstack-eslint-config-2.5.2.tgz_eslint@8.7.0+typescript@4.5.2 - '@rushstack/heft': file:../temp/tarballs/rushstack-heft-0.44.5.tgz + '@rushstack/heft': file:../temp/tarballs/rushstack-heft-0.44.7.tgz eslint: 8.7.0 tslint: 5.20.1_typescript@4.5.2 typescript: 4.5.2 @@ -19,13 +19,13 @@ importers: typescript-v3-test: specifiers: '@rushstack/eslint-config': file:rushstack-eslint-config-2.5.2.tgz - '@rushstack/heft': file:rushstack-heft-0.44.5.tgz + '@rushstack/heft': file:rushstack-heft-0.44.7.tgz eslint: ~8.7.0 tslint: ~5.20.1 typescript: ~4.5.2 devDependencies: '@rushstack/eslint-config': file:../temp/tarballs/rushstack-eslint-config-2.5.2.tgz_eslint@8.7.0+typescript@4.5.2 - '@rushstack/heft': file:../temp/tarballs/rushstack-heft-0.44.5.tgz + '@rushstack/heft': file:../temp/tarballs/rushstack-heft-0.44.7.tgz eslint: 8.7.0 tslint: 5.20.1_typescript@4.5.2 typescript: 4.5.2 @@ -1720,10 +1720,10 @@ packages: - typescript dev: true - file:../temp/tarballs/rushstack-heft-0.44.5.tgz: - resolution: {tarball: file:../temp/tarballs/rushstack-heft-0.44.5.tgz} + file:../temp/tarballs/rushstack-heft-0.44.7.tgz: + resolution: {tarball: file:../temp/tarballs/rushstack-heft-0.44.7.tgz} name: '@rushstack/heft' - version: 0.44.5 + version: 0.44.7 engines: {node: '>=10.13.0'} hasBin: true dependencies: diff --git a/common/changes/@microsoft/api-extractor/ambient-module-fix_2022-04-09-15-19.json b/common/changes/@microsoft/api-extractor/ambient-module-fix_2022-04-09-15-19.json new file mode 100644 index 00000000000..d78b14c2a46 --- /dev/null +++ b/common/changes/@microsoft/api-extractor/ambient-module-fix_2022-04-09-15-19.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/api-extractor", + "comment": "Fix ambient modules bug caused by #3321.", + "type": "patch" + } + ], + "packageName": "@microsoft/api-extractor" +} \ No newline at end of file