diff --git a/src/services/preProcess.ts b/src/services/preProcess.ts index fc22b274ddbbd..ca4adc00b3e77 100644 --- a/src/services/preProcess.ts +++ b/src/services/preProcess.ts @@ -89,7 +89,7 @@ namespace ts { token = nextToken(); if (token === SyntaxKind.OpenParenToken) { token = nextToken(); - if (token === SyntaxKind.StringLiteral) { + if (token === SyntaxKind.StringLiteral || token === SyntaxKind.NoSubstitutionTemplateLiteral) { // import("mod"); recordModuleName(); return true; @@ -224,13 +224,14 @@ namespace ts { return false; } - function tryConsumeRequireCall(skipCurrentToken: boolean): boolean { + function tryConsumeRequireCall(skipCurrentToken: boolean, allowTemplateLiterals = false): boolean { let token = skipCurrentToken ? nextToken() : scanner.getToken(); if (token === SyntaxKind.RequireKeyword) { token = nextToken(); if (token === SyntaxKind.OpenParenToken) { token = nextToken(); - if (token === SyntaxKind.StringLiteral) { + if (token === SyntaxKind.StringLiteral || + allowTemplateLiterals && token === SyntaxKind.NoSubstitutionTemplateLiteral) { // require("mod"); recordModuleName(); } @@ -249,7 +250,7 @@ namespace ts { } token = nextToken(); - if (token === SyntaxKind.StringLiteral) { + if (token === SyntaxKind.StringLiteral || token === SyntaxKind.NoSubstitutionTemplateLiteral) { // looks like define ("modname", ... - skip string literal and comma token = nextToken(); if (token === SyntaxKind.CommaToken) { @@ -271,7 +272,7 @@ namespace ts { // scan until ']' or EOF while (token !== SyntaxKind.CloseBracketToken && token !== SyntaxKind.EndOfFileToken) { // record string literals as module names - if (token === SyntaxKind.StringLiteral) { + if (token === SyntaxKind.StringLiteral || token === SyntaxKind.NoSubstitutionTemplateLiteral) { recordModuleName(); } @@ -313,7 +314,10 @@ namespace ts { if (tryConsumeDeclare() || tryConsumeImport() || tryConsumeExport() || - (detectJavaScriptImports && (tryConsumeRequireCall(/*skipCurrentToken*/ false) || tryConsumeDefine()))) { + (detectJavaScriptImports && ( + tryConsumeRequireCall(/*skipCurrentToken*/ false, /*allowTemplateLiterals*/ true) || + tryConsumeDefine() + ))) { continue; } else { diff --git a/src/testRunner/unittests/services/preProcessFile.ts b/src/testRunner/unittests/services/preProcessFile.ts index 766c7d7078beb..57198c23c10ac 100644 --- a/src/testRunner/unittests/services/preProcessFile.ts +++ b/src/testRunner/unittests/services/preProcessFile.ts @@ -530,6 +530,65 @@ describe("unittests:: services:: PreProcessFile:", () => { isLibFile: false }); }); + + it("Correctly handles dynamic imports with template literals", () => { + test("const m1 = import('mod1');" + "\n" + + "const m2 = import(`mod2`);" + "\n" + + "Promise.all([import('mod3'), import(`mod4`)]);" + "\n" + + "import(/* webpackChunkName: 'module5' */ `mod5`);" + "\n", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "mod1", pos: 18, end: 22 }, + { fileName: "mod2", pos: 45, end: 49 }, + { fileName: "mod3", pos: 74, end: 78 }, + { fileName: "mod4", pos: 90, end: 94 }, + { fileName: "mod5", pos: 142, end: 146 } + ], + ambientExternalModules: undefined, + isLibFile: false + }); + }); + + it("Correctly handles require calls with template literals in JS files", () => { + test("const m1 = require(`mod1`);" + "\n" + + "f(require(`mod2`));" + "\n" + + "const a = { x: require(`mod3`) };" + "\n", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "mod1", pos: 19, end: 23 }, + { fileName: "mod2", pos: 38, end: 42 }, + { fileName: "mod3", pos: 71, end: 75 } + ], + ambientExternalModules: undefined, + isLibFile: false + }); + }); + + it("Correctly handles dependency lists in define(modName, [deplist]) calls with template literals in JS files", () => { + test("define(`mod`, [`mod1`, `mod2`], (m1, m2) => {});", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "mod1", pos: 15, end: 19 }, + { fileName: "mod2", pos: 23, end: 27 }, + ], + ambientExternalModules: undefined, + isLibFile: false + }); + }); }); }); -