diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 4c31ece8602..6098245cb6c 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -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) {
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index 3d035053761..463651bdb00 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -1182,6 +1182,7 @@ export const notImplementedResolver: EmitResolver = {
isBindingCapturedByNode: notImplemented,
getDeclarationStatementsForSourceFile: notImplemented,
isImportRequiredByAugmentation: notImplemented,
+ tryFindAmbientModule: notImplemented,
};
/**
diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts
index 05b5ad1c8b9..512c2eb4704 100644
--- a/src/compiler/transformers/declarations.ts
+++ b/src/compiler/transformers/declarations.ts
@@ -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;
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 9a185a49232..a64c4c86b59 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -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
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index 126b74d91da..8d4a3d24969 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -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);
}
diff --git a/tests/baselines/reference/declarationEmitBundleWithAmbientReferences.js b/tests/baselines/reference/declarationEmitBundleWithAmbientReferences.js
index 0d6946277ad..ece01c1794a 100644
--- a/tests/baselines/reference/declarationEmitBundleWithAmbientReferences.js
+++ b/tests/baselines/reference/declarationEmitBundleWithAmbientReferences.js
@@ -37,6 +37,7 @@ define("conditional_directive_field", ["require", "exports"], function (require,
//// [datastore.bundle.d.ts]
+///
declare module "datastore_result" {
import { Result } from "lib/result";
export type T = Result;
diff --git a/tests/baselines/reference/declarationEmitTripleSlashReferenceAmbientModule.js b/tests/baselines/reference/declarationEmitTripleSlashReferenceAmbientModule.js
new file mode 100644
index 00000000000..b283b08edcd
--- /dev/null
+++ b/tests/baselines/reference/declarationEmitTripleSlashReferenceAmbientModule.js
@@ -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]
+///
+export { parse } from "url";
+//// [usage2.d.ts]
+///
+export declare const thing: import("url").Url;
+//// [usage3.d.ts]
+///
+export declare const thing: import("url").Url;
diff --git a/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=node16).js b/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=node16).js
index 7c584a82861..0d0046de24d 100644
--- a/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=node16).js
+++ b/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=node16).js
@@ -40,6 +40,7 @@ export * as fs from "fs";
//// [index.d.ts]
+///
export * from "fs";
export * as fs from "fs";
//// [index.d.ts]
diff --git a/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=nodenext).js b/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=nodenext).js
index 7c584a82861..0d0046de24d 100644
--- a/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=nodenext).js
+++ b/tests/baselines/reference/nodeModulesAllowJsImportHelpersCollisions2(module=nodenext).js
@@ -40,6 +40,7 @@ export * as fs from "fs";
//// [index.d.ts]
+///
export * from "fs";
export * as fs from "fs";
//// [index.d.ts]
diff --git a/tests/baselines/reference/nodeModulesImportAssignments(module=node16).js b/tests/baselines/reference/nodeModulesImportAssignments(module=node16).js
index e56ab00bb87..779a5236c5d 100644
--- a/tests/baselines/reference/nodeModulesImportAssignments(module=node16).js
+++ b/tests/baselines/reference/nodeModulesImportAssignments(module=node16).js
@@ -58,8 +58,11 @@ export { fs2 };
//// [index.d.ts]
+///
export import fs2 = require("fs");
//// [index.d.ts]
+///
export import fs2 = require("fs");
//// [file.d.ts]
+///
export import fs2 = require("fs");
diff --git a/tests/baselines/reference/nodeModulesImportAssignments(module=nodenext).js b/tests/baselines/reference/nodeModulesImportAssignments(module=nodenext).js
index e56ab00bb87..779a5236c5d 100644
--- a/tests/baselines/reference/nodeModulesImportAssignments(module=nodenext).js
+++ b/tests/baselines/reference/nodeModulesImportAssignments(module=nodenext).js
@@ -58,8 +58,11 @@ export { fs2 };
//// [index.d.ts]
+///
export import fs2 = require("fs");
//// [index.d.ts]
+///
export import fs2 = require("fs");
//// [file.d.ts]
+///
export import fs2 = require("fs");
diff --git a/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=node16).js b/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=node16).js
index e8e9b78464c..53eeb9bd5a7 100644
--- a/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=node16).js
+++ b/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=node16).js
@@ -40,8 +40,10 @@ export * as fs from "fs";
//// [index.d.ts]
+///
export * from "fs";
export * as fs from "fs";
//// [index.d.ts]
+///
export * from "fs";
export * as fs from "fs";
diff --git a/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=nodenext).js b/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=nodenext).js
index e8e9b78464c..53eeb9bd5a7 100644
--- a/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=nodenext).js
+++ b/tests/baselines/reference/nodeModulesImportHelpersCollisions2(module=nodenext).js
@@ -40,8 +40,10 @@ export * as fs from "fs";
//// [index.d.ts]
+///
export * from "fs";
export * as fs from "fs";
//// [index.d.ts]
+///
export * from "fs";
export * as fs from "fs";
diff --git a/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=node16).js b/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=node16).js
index 8abf8ba9ada..5f98164aaaa 100644
--- a/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=node16).js
+++ b/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=node16).js
@@ -39,6 +39,8 @@ export { default } from "fs";
//// [index.d.ts]
+///
export { default } from "fs";
//// [index.d.ts]
+///
export { default } from "fs";
diff --git a/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=nodenext).js b/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=nodenext).js
index 8abf8ba9ada..5f98164aaaa 100644
--- a/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=nodenext).js
+++ b/tests/baselines/reference/nodeModulesImportHelpersCollisions3(module=nodenext).js
@@ -39,6 +39,8 @@ export { default } from "fs";
//// [index.d.ts]
+///
export { default } from "fs";
//// [index.d.ts]
+///
export { default } from "fs";
diff --git a/tests/cases/compiler/declarationEmitTripleSlashReferenceAmbientModule.ts b/tests/cases/compiler/declarationEmitTripleSlashReferenceAmbientModule.ts
new file mode 100644
index 00000000000..df9274fa371
--- /dev/null
+++ b/tests/cases/compiler/declarationEmitTripleSlashReferenceAmbientModule.ts
@@ -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();