Add type reference directive for all visited references to ambient modules (#56015)

This commit is contained in:
Andrew Branch 2023-10-09 11:38:15 -07:00 committed by GitHub
parent 9144836360
commit d0d406747d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 104 additions and 3 deletions

View File

@ -47930,6 +47930,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return !sym.exports ? [] : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker, bundled);
},
isImportRequiredByAugmentation,
tryFindAmbientModule: moduleReferenceExpression => {
const node = getParseTreeNode(moduleReferenceExpression);
const moduleSpecifier = node && isStringLiteralLike(node) ? node.text : undefined;
return moduleSpecifier !== undefined ? tryFindAmbientModule(moduleSpecifier, /*withAugmentations*/ true) : undefined;
},
};
function isImportRequiredByAugmentation(node: ImportDeclaration) {

View File

@ -1182,6 +1182,7 @@ export const notImplementedResolver: EmitResolver = {
isBindingCapturedByNode: notImplemented,
getDeclarationStatementsForSourceFile: notImplemented,
isImportRequiredByAugmentation: notImplemented,
tryFindAmbientModule: notImplemented,
};
/**

View File

@ -212,6 +212,7 @@ import {
TransformationContext,
transformNodes,
tryCast,
tryGetModuleSpecifierFromDeclaration,
TypeAliasDeclaration,
TypeNode,
TypeParameterDeclaration,
@ -345,6 +346,18 @@ export function transformDeclarations(context: TransformationContext) {
refs.set(getOriginalNodeId(container), container);
}
function trackReferencedAmbientModuleFromImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration | ImportTypeNode) {
const moduleSpecifier = tryGetModuleSpecifierFromDeclaration(node);
const symbol = moduleSpecifier && resolver.tryFindAmbientModule(moduleSpecifier);
if (symbol?.declarations) {
for (const decl of symbol.declarations) {
if (isAmbientModule(decl) && getSourceFileOfNode(decl) !== currentSourceFile) {
trackReferencedAmbientModule(decl, symbol);
}
}
}
}
function handleSymbolAccessibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) {
if (symbolAccessibilityResult.accessibility === SymbolAccessibility.Accessible) {
// Add aliases back onto the possible imports list if they're not there so we can try them again with updated visibility info
@ -1312,6 +1325,7 @@ export function transformDeclarations(context: TransformationContext) {
}
case SyntaxKind.ImportType: {
if (!isLiteralImportTypeNode(input)) return cleanup(input);
trackReferencedAmbientModuleFromImport(input);
return cleanup(factory.updateImportTypeNode(
input,
factory.updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)),
@ -1370,6 +1384,7 @@ export function transformDeclarations(context: TransformationContext) {
}
resultHasScopeMarker = true;
// Always visible if the parent node isn't dropped for being not visible
trackReferencedAmbientModuleFromImport(input);
// Rewrite external module names if necessary
return factory.updateExportDeclaration(
input,
@ -1456,10 +1471,18 @@ export function transformDeclarations(context: TransformationContext) {
if (shouldStripInternal(input)) return;
switch (input.kind) {
case SyntaxKind.ImportEqualsDeclaration: {
return transformImportEqualsDeclaration(input);
const transformed = transformImportEqualsDeclaration(input);
if (transformed) {
trackReferencedAmbientModuleFromImport(input);
}
return transformed;
}
case SyntaxKind.ImportDeclaration: {
return transformImportDeclaration(input);
const transformed = transformImportDeclaration(input);
if (transformed) {
trackReferencedAmbientModuleFromImport(input);
}
return transformed;
}
}
if (isDeclaration(input) && isDeclarationAndNotVisible(input)) return;

View File

@ -5675,6 +5675,7 @@ export interface EmitResolver {
isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean;
getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, tracker: SymbolTracker, bundled?: boolean): Statement[] | undefined;
isImportRequiredByAugmentation(decl: ImportDeclaration): boolean;
tryFindAmbientModule(moduleReferenceExpression: Expression): Symbol | undefined;
}
// dprint-ignore

View File

@ -3975,12 +3975,13 @@ export function isFunctionSymbol(symbol: Symbol | undefined) {
}
/** @internal */
export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode): StringLiteralLike | undefined {
export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode): StringLiteralLike | undefined {
switch (node.kind) {
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
return findAncestor(node.initializer, (node): node is RequireOrImportCall => isRequireCall(node, /*requireStringLiteralLikeArgument*/ true))?.arguments[0];
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ExportDeclaration:
return tryCast(node.moduleSpecifier, isStringLiteralLike);
case SyntaxKind.ImportEqualsDeclaration:
return tryCast(tryCast(node.moduleReference, isExternalModuleReference)?.expression, isStringLiteralLike);
@ -3992,6 +3993,8 @@ export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAcce
return tryCast(node.parent.parent.moduleSpecifier, isStringLiteralLike);
case SyntaxKind.ImportSpecifier:
return tryCast(node.parent.parent.parent.moduleSpecifier, isStringLiteralLike);
case SyntaxKind.ImportType:
return isLiteralImportTypeNode(node) ? node.argument.literal : undefined;
default:
Debug.assertNever(node);
}

View File

@ -37,6 +37,7 @@ define("conditional_directive_field", ["require", "exports"], function (require,
//// [datastore.bundle.d.ts]
/// <reference path="../lib/lib.d.ts" />
declare module "datastore_result" {
import { Result } from "lib/result";
export type T<T> = Result<Error, T>;

View File

@ -0,0 +1,31 @@
//// [tests/cases/compiler/declarationEmitTripleSlashReferenceAmbientModule.ts] ////
//// [index.d.ts]
declare module "url" {
export class Url {}
export function parse(): Url;
}
//// [usage1.ts]
export { parse } from "url";
//// [usage2.ts]
import { parse } from "url";
export const thing: import("url").Url = parse();
//// [usage3.ts]
import { parse } from "url";
export const thing = parse();
//// [usage1.d.ts]
/// <reference types="node" />
export { parse } from "url";
//// [usage2.d.ts]
/// <reference types="node" />
export declare const thing: import("url").Url;
//// [usage3.d.ts]
/// <reference types="node" />
export declare const thing: import("url").Url;

View File

@ -40,6 +40,7 @@ export * as fs from "fs";
//// [index.d.ts]
/// <reference path="../../types.d.ts" />
export * from "fs";
export * as fs from "fs";
//// [index.d.ts]

View File

@ -40,6 +40,7 @@ export * as fs from "fs";
//// [index.d.ts]
/// <reference path="../../types.d.ts" />
export * from "fs";
export * as fs from "fs";
//// [index.d.ts]

View File

@ -58,8 +58,11 @@ export { fs2 };
//// [index.d.ts]
/// <reference path="../types.d.ts" />
export import fs2 = require("fs");
//// [index.d.ts]
/// <reference path="types.d.ts" />
export import fs2 = require("fs");
//// [file.d.ts]
/// <reference path="types.d.ts" />
export import fs2 = require("fs");

View File

@ -58,8 +58,11 @@ export { fs2 };
//// [index.d.ts]
/// <reference path="../types.d.ts" />
export import fs2 = require("fs");
//// [index.d.ts]
/// <reference path="types.d.ts" />
export import fs2 = require("fs");
//// [file.d.ts]
/// <reference path="types.d.ts" />
export import fs2 = require("fs");

View File

@ -40,8 +40,10 @@ export * as fs from "fs";
//// [index.d.ts]
/// <reference path="../types.d.ts" />
export * from "fs";
export * as fs from "fs";
//// [index.d.ts]
/// <reference path="types.d.ts" />
export * from "fs";
export * as fs from "fs";

View File

@ -40,8 +40,10 @@ export * as fs from "fs";
//// [index.d.ts]
/// <reference path="../types.d.ts" />
export * from "fs";
export * as fs from "fs";
//// [index.d.ts]
/// <reference path="types.d.ts" />
export * from "fs";
export * as fs from "fs";

View File

@ -39,6 +39,8 @@ export { default } from "fs";
//// [index.d.ts]
/// <reference path="../types.d.ts" />
export { default } from "fs";
//// [index.d.ts]
/// <reference path="types.d.ts" />
export { default } from "fs";

View File

@ -39,6 +39,8 @@ export { default } from "fs";
//// [index.d.ts]
/// <reference path="../types.d.ts" />
export { default } from "fs";
//// [index.d.ts]
/// <reference path="types.d.ts" />
export { default } from "fs";

View File

@ -0,0 +1,20 @@
// @declaration: true
// @emitDeclarationOnly: true
// @noTypesAndSymbols: true
// @Filename: /node_modules/@types/node/index.d.ts
declare module "url" {
export class Url {}
export function parse(): Url;
}
// @Filename: /usage1.ts
export { parse } from "url";
// @Filename: /usage2.ts
import { parse } from "url";
export const thing: import("url").Url = parse();
// @Filename: /usage3.ts
import { parse } from "url";
export const thing = parse();