From 6fac3ddfd42472556610c22ba657a3a6b3d95156 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 4 Jan 2021 15:08:57 -0800 Subject: [PATCH] Fix module resolution for import call emit (#41390) --- src/compiler/checker.ts | 7 +++++-- src/compiler/factory/utilities.ts | 14 +++++++------- src/compiler/transformers/module/module.ts | 5 ++++- src/compiler/transformers/module/system.ts | 6 +++++- src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 8 +++++++- .../reference/outFilerootDirModuleNamesAmd.js | 6 +++++- .../reference/outFilerootDirModuleNamesAmd.symbols | 4 ++++ .../reference/outFilerootDirModuleNamesAmd.types | 5 +++++ .../reference/outFilerootDirModuleNamesSystem.js | 5 +++++ .../outFilerootDirModuleNamesSystem.symbols | 4 ++++ .../outFilerootDirModuleNamesSystem.types | 5 +++++ .../outFilerootDirModuleNamesAmd.ts | 3 +++ .../outFilerootDirModuleNamesSystem.ts | 3 +++ 14 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6c240dce412..1f4fb57515e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -38654,7 +38654,10 @@ namespace ts { isOptionalParameter, moduleExportsSomeValue, isArgumentsLocalBinding, - getExternalModuleFileFromDeclaration, + getExternalModuleFileFromDeclaration: nodeIn => { + const node = getParseTreeNode(nodeIn, hasPossibleExternalModuleReference); + return node && getExternalModuleFileFromDeclaration(node); + }, getTypeReferenceDirectivesForEntityName, getTypeReferenceDirectivesForSymbol, isLiteralConstDeclaration, @@ -38815,7 +38818,7 @@ namespace ts { } } - function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration | ImportTypeNode): SourceFile | undefined { + function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall): SourceFile | undefined { const specifier = declaration.kind === SyntaxKind.ModuleDeclaration ? tryCast(declaration.name, isStringLiteral) : getExternalModuleName(declaration); const moduleSymbol = resolveExternalModuleNameWorker(specifier!, specifier!, /*moduleNotFoundError*/ undefined); // TODO: GH#18217 if (!moduleSymbol) { diff --git a/src/compiler/factory/utilities.ts b/src/compiler/factory/utilities.ts index 0960509ae4d..8b18c3152e3 100644 --- a/src/compiler/factory/utilities.ts +++ b/src/compiler/factory/utilities.ts @@ -511,12 +511,12 @@ namespace ts { * 3- The containing SourceFile has an entry in renamedDependencies for the import as requested by some module loaders (e.g. System). * Otherwise, a new StringLiteral node representing the module name will be returned. */ - export function getExternalModuleNameLiteral(factory: NodeFactory, importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, compilerOptions: CompilerOptions) { - const moduleName = getExternalModuleName(importNode)!; // TODO: GH#18217 - if (moduleName.kind === SyntaxKind.StringLiteral) { + export function getExternalModuleNameLiteral(factory: NodeFactory, importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration | ImportCall, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, compilerOptions: CompilerOptions) { + const moduleName = getExternalModuleName(importNode); + if (moduleName && isStringLiteral(moduleName)) { return tryGetModuleNameFromDeclaration(importNode, host, factory, resolver, compilerOptions) - || tryRenameExternalModule(factory, moduleName, sourceFile) - || factory.cloneNode(moduleName); + || tryRenameExternalModule(factory, moduleName, sourceFile) + || factory.cloneNode(moduleName); } return undefined; @@ -528,7 +528,7 @@ namespace ts { */ function tryRenameExternalModule(factory: NodeFactory, moduleName: LiteralExpression, sourceFile: SourceFile) { const rename = sourceFile.renamedDependencies && sourceFile.renamedDependencies.get(moduleName.text); - return rename && factory.createStringLiteral(rename); + return rename ? factory.createStringLiteral(rename) : undefined; } /** @@ -551,7 +551,7 @@ namespace ts { return undefined; } - function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration, host: EmitHost, factory: NodeFactory, resolver: EmitResolver, compilerOptions: CompilerOptions) { + function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ImportCall, host: EmitHost, factory: NodeFactory, resolver: EmitResolver, compilerOptions: CompilerOptions) { return tryGetModuleNameFromFile(factory, resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions); } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 12871142561..d2f4917d50b 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -609,7 +609,10 @@ namespace ts { } function visitImportCallExpression(node: ImportCall): Expression { - const argument = visitNode(firstOrUndefined(node.arguments), moduleExpressionElementVisitor); + const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions); + const firstArgument = visitNode(firstOrUndefined(node.arguments), moduleExpressionElementVisitor); + // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output. + const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; const containsLexicalThis = !!(node.transformFlags & TransformFlags.ContainsLexicalThis); switch (compilerOptions.module) { case ModuleKind.AMD: diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 5935a3e7f5e..a5e0c9bbbf4 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -1495,13 +1495,17 @@ namespace ts { // } // }; // }); + const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions); + const firstArgument = visitNode(firstOrUndefined(node.arguments), destructuringAndImportCallVisitor); + // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output. + const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; return factory.createCallExpression( factory.createPropertyAccessExpression( contextObject, factory.createIdentifier("import") ), /*typeArguments*/ undefined, - some(node.arguments) ? [visitNode(node.arguments[0], destructuringAndImportCallVisitor)] : [] + argument ? [argument] : [] ); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 81181164a79..0dfc911a623 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4607,7 +4607,7 @@ namespace ts { isOptionalParameter(node: ParameterDeclaration): boolean; moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean; isArgumentsLocalBinding(node: Identifier): boolean; - getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): SourceFile | undefined; + getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode | ImportCall): SourceFile | undefined; getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): string[] | undefined; getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[] | undefined; isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b19a70e8dbc..476a73f55c0 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -907,6 +907,10 @@ namespace ts { } } + export function hasPossibleExternalModuleReference(node: Node): node is AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall { + return isAnyImportOrReExport(node) || isModuleDeclaration(node) || isImportTypeNode(node) || isImportCall(node); + } + export function isAnyImportOrReExport(node: Node): node is AnyImportOrReExport { return isAnyImportSyntax(node) || isExportDeclaration(node); } @@ -2426,7 +2430,7 @@ namespace ts { } } - export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode): Expression | undefined { + export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode | ImportCall): Expression | undefined { switch (node.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: @@ -2435,6 +2439,8 @@ namespace ts { return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? node.moduleReference.expression : undefined; case SyntaxKind.ImportType: return isLiteralImportTypeNode(node) ? node.argument.literal : undefined; + case SyntaxKind.CallExpression: + return node.arguments[0]; default: return Debug.assertNever(node); } diff --git a/tests/baselines/reference/outFilerootDirModuleNamesAmd.js b/tests/baselines/reference/outFilerootDirModuleNamesAmd.js index 91665513153..29306773dab 100644 --- a/tests/baselines/reference/outFilerootDirModuleNamesAmd.js +++ b/tests/baselines/reference/outFilerootDirModuleNamesAmd.js @@ -8,7 +8,9 @@ foo(); //// [b.ts] import Foo from "./a"; export default function foo() { new Foo(); } - + +// https://github.com/microsoft/TypeScript/issues/37429 +import("./a"); //// [output.js] define("b", ["require", "exports", "a"], function (require, exports, a_1) { @@ -16,6 +18,8 @@ define("b", ["require", "exports", "a"], function (require, exports, a_1) { Object.defineProperty(exports, "__esModule", { value: true }); function foo() { new a_1.default(); } exports.default = foo; + // https://github.com/microsoft/TypeScript/issues/37429 + new Promise((resolve_1, reject_1) => { require(["a"], resolve_1, reject_1); }); }); define("a", ["require", "exports", "b"], function (require, exports, b_1) { "use strict"; diff --git a/tests/baselines/reference/outFilerootDirModuleNamesAmd.symbols b/tests/baselines/reference/outFilerootDirModuleNamesAmd.symbols index fea742c20ca..8b079c39038 100644 --- a/tests/baselines/reference/outFilerootDirModuleNamesAmd.symbols +++ b/tests/baselines/reference/outFilerootDirModuleNamesAmd.symbols @@ -16,3 +16,7 @@ export default function foo() { new Foo(); } >foo : Symbol(foo, Decl(b.ts, 0, 22)) >Foo : Symbol(Foo, Decl(b.ts, 0, 6)) +// https://github.com/microsoft/TypeScript/issues/37429 +import("./a"); +>"./a" : Symbol("tests/cases/conformance/es6/moduleExportsAmd/src/a", Decl(a.ts, 0, 0)) + diff --git a/tests/baselines/reference/outFilerootDirModuleNamesAmd.types b/tests/baselines/reference/outFilerootDirModuleNamesAmd.types index 617096fd0dd..c5bd43ce968 100644 --- a/tests/baselines/reference/outFilerootDirModuleNamesAmd.types +++ b/tests/baselines/reference/outFilerootDirModuleNamesAmd.types @@ -18,3 +18,8 @@ export default function foo() { new Foo(); } >new Foo() : Foo >Foo : typeof Foo +// https://github.com/microsoft/TypeScript/issues/37429 +import("./a"); +>import("./a") : Promise +>"./a" : "./a" + diff --git a/tests/baselines/reference/outFilerootDirModuleNamesSystem.js b/tests/baselines/reference/outFilerootDirModuleNamesSystem.js index 0cf43e047a0..c8dc34abbb4 100644 --- a/tests/baselines/reference/outFilerootDirModuleNamesSystem.js +++ b/tests/baselines/reference/outFilerootDirModuleNamesSystem.js @@ -8,6 +8,9 @@ foo(); //// [b.ts] import Foo from "./a"; export default function foo() { new Foo(); } + +// https://github.com/microsoft/TypeScript/issues/37429 +import("./a"); //// [output.js] @@ -24,6 +27,8 @@ System.register("b", ["a"], function (exports_1, context_1) { } ], execute: function () { + // https://github.com/microsoft/TypeScript/issues/37429 + context_1.import("a"); } }; }); diff --git a/tests/baselines/reference/outFilerootDirModuleNamesSystem.symbols b/tests/baselines/reference/outFilerootDirModuleNamesSystem.symbols index 535c037f5af..6272c39572e 100644 --- a/tests/baselines/reference/outFilerootDirModuleNamesSystem.symbols +++ b/tests/baselines/reference/outFilerootDirModuleNamesSystem.symbols @@ -16,3 +16,7 @@ export default function foo() { new Foo(); } >foo : Symbol(foo, Decl(b.ts, 0, 22)) >Foo : Symbol(Foo, Decl(b.ts, 0, 6)) +// https://github.com/microsoft/TypeScript/issues/37429 +import("./a"); +>"./a" : Symbol("tests/cases/conformance/es6/moduleExportsSystem/src/a", Decl(a.ts, 0, 0)) + diff --git a/tests/baselines/reference/outFilerootDirModuleNamesSystem.types b/tests/baselines/reference/outFilerootDirModuleNamesSystem.types index 2f0e23c2e81..8dc137cf76d 100644 --- a/tests/baselines/reference/outFilerootDirModuleNamesSystem.types +++ b/tests/baselines/reference/outFilerootDirModuleNamesSystem.types @@ -18,3 +18,8 @@ export default function foo() { new Foo(); } >new Foo() : Foo >Foo : typeof Foo +// https://github.com/microsoft/TypeScript/issues/37429 +import("./a"); +>import("./a") : Promise +>"./a" : "./a" + diff --git a/tests/cases/conformance/es6/moduleExportsAmd/outFilerootDirModuleNamesAmd.ts b/tests/cases/conformance/es6/moduleExportsAmd/outFilerootDirModuleNamesAmd.ts index 7f6fad73490..ae207e8f341 100644 --- a/tests/cases/conformance/es6/moduleExportsAmd/outFilerootDirModuleNamesAmd.ts +++ b/tests/cases/conformance/es6/moduleExportsAmd/outFilerootDirModuleNamesAmd.ts @@ -10,3 +10,6 @@ foo(); // @filename: src/b.ts import Foo from "./a"; export default function foo() { new Foo(); } + +// https://github.com/microsoft/TypeScript/issues/37429 +import("./a"); \ No newline at end of file diff --git a/tests/cases/conformance/es6/moduleExportsSystem/outFilerootDirModuleNamesSystem.ts b/tests/cases/conformance/es6/moduleExportsSystem/outFilerootDirModuleNamesSystem.ts index 5708c84c4bd..a301df92a17 100644 --- a/tests/cases/conformance/es6/moduleExportsSystem/outFilerootDirModuleNamesSystem.ts +++ b/tests/cases/conformance/es6/moduleExportsSystem/outFilerootDirModuleNamesSystem.ts @@ -10,3 +10,6 @@ foo(); // @filename: src/b.ts import Foo from "./a"; export default function foo() { new Foo(); } + +// https://github.com/microsoft/TypeScript/issues/37429 +import("./a");