Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃 Pick PR #47657 (fix(47597): preProcessFile incorrec...) into release-4.6 #48223

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/services/preProcess.ts
Expand Up @@ -345,6 +345,42 @@ namespace ts {
break;
}

if (scanner.getToken() === SyntaxKind.TemplateHead) {
const stack = [scanner.getToken()];
let token = scanner.scan();
loop: while (length(stack)) {
switch (token) {
case SyntaxKind.EndOfFileToken:
break loop;
case SyntaxKind.ImportKeyword:
tryConsumeImport();
break;
case SyntaxKind.TemplateHead:
stack.push(token);
break;
case SyntaxKind.OpenBraceToken:
if (length(stack)) {
stack.push(token);
}
break;
case SyntaxKind.CloseBraceToken:
if (length(stack)) {
if (lastOrUndefined(stack) === SyntaxKind.TemplateHead) {
if (scanner.reScanTemplateToken(/* isTaggedTemplate */ false) === SyntaxKind.TemplateTail) {
stack.pop();
}
}
else {
stack.pop();
}
}
break;
}
token = scanner.scan();
}
nextToken();
}

// check if at least one of alternative have moved scanner forward
if (tryConsumeDeclare() ||
tryConsumeImport() ||
Expand Down
171 changes: 171 additions & 0 deletions src/testRunner/unittests/services/preProcessFile.ts
Expand Up @@ -176,6 +176,177 @@ describe("unittests:: services:: PreProcessFile:", () => {
});
});

it("Correctly ignore commented imports following template expression", () => {
/* eslint-disable no-template-curly-in-string */
test("/**" + "\n" +
" * Before" + "\n" +
" * ```" + "\n" +
" * import * as a from \"a\";" + "\n" +
" * ```" + "\n" +
" */" + "\n" +
"type Foo = `${string}`;" + "\n" +
"/**" + "\n" +
" * After" + "\n" +
" * ```" + "\n" +
" * import { B } from \"b\";" + "\n" +
" * import * as c from \"c\";" + "\n" +
" * ```" + "\n" +
" */",
/*readImportFile*/ true,
/*detectJavaScriptImports*/ true,
{
referencedFiles: [],
typeReferenceDirectives: [],
libReferenceDirectives: [],
importedFiles: [],
ambientExternalModules: undefined,
isLibFile: false
});
/* eslint-enable no-template-curly-in-string */
});

it("Correctly returns imports after a template expression", () => {
/* eslint-disable no-template-curly-in-string */
test("`${foo}`; import \"./foo\";",
/*readImportFile*/ true,
/*detectJavaScriptImports*/ true,
{
referencedFiles: [],
typeReferenceDirectives: [],
libReferenceDirectives: [],
importedFiles: [
{ fileName: "./foo", pos: 17, end: 22 }
],
ambientExternalModules: undefined,
isLibFile: false
});
/* eslint-enable no-template-curly-in-string */
});

it("Correctly returns dynamic imports from template expression", () => {
/* eslint-disable no-template-curly-in-string */
test("`${(<div>Text `` ${} text {} " + "\n" +
"${import(\"a\")} {import(\"b\")} " + "\n" +
"${/* A comment */} ${/* import(\"ignored\") */} </div>)}`",
/*readImportFile*/ true,
/*detectJavaScriptImports*/ true,
{
referencedFiles: [],
typeReferenceDirectives: [],
libReferenceDirectives: [],
importedFiles: [
{ fileName: "a", pos: 39, end: 40 },
{ fileName: "b", pos: 53, end: 54 }
],
ambientExternalModules: undefined,
isLibFile: false
});
/* eslint-enable no-template-curly-in-string */
});

it("Correctly returns dynamic imports from nested template expression", () => {
/* eslint-disable no-template-curly-in-string */
test("`${foo(`${bar(`${import(\"a\")} ${import(\"b\")}`, `${baz(`${import(\"c\") ${import(\"d\")}`)}`)}`)}`",
/*readImportFile*/ true,
/*detectJavaScriptImports*/ true,
{
referencedFiles: [],
typeReferenceDirectives: [],
libReferenceDirectives: [],
importedFiles: [
{ fileName: "a", pos: 24, end: 25 },
{ fileName: "b", pos: 39, end: 40 },
{ fileName: "c", pos: 64, end: 65 },
{ fileName: "d", pos: 78, end: 79 },
],
ambientExternalModules: undefined,
isLibFile: false
});
/* eslint-enable no-template-curly-in-string */
});

it("Correctly returns dynamic imports from tagged template expression", () => {
/* eslint-disable no-template-curly-in-string */
test("foo`${ fn({ a: 100 }, import(\"a\"), `${import(\"b\")}`, import(\"c\"), `${import(\"d\")} foo`, import(\"e\")) }`",
/*readImportFile*/ true,
/*detectJavaScriptImports*/ true,
{
referencedFiles: [],
typeReferenceDirectives: [],
libReferenceDirectives: [],
importedFiles: [
{ fileName: "a", pos: 29, end: 30 },
{ fileName: "b", pos: 45, end: 46 },
{ fileName: "c", pos: 60, end: 61 },
{ fileName: "d", pos: 76, end: 77 },
{ fileName: "e", pos: 95, end: 96 },
],
ambientExternalModules: undefined,
isLibFile: false
});
/* eslint-enable no-template-curly-in-string */
});

it("Correctly returns dynamic imports from template expression and imports following it", () => {
/* eslint-disable no-template-curly-in-string */
test("const x = `hello ${await import(\"a\").default}`;" + "\n\n" +
"import { y } from \"b\";",
/*readImportFile*/ true,
/*detectJavaScriptImports*/ true,
{
referencedFiles: [],
typeReferenceDirectives: [],
libReferenceDirectives: [],
importedFiles: [
{ fileName: "a", pos: 32, end: 33 },
{ fileName: "b", pos: 67, end: 68 },
],
ambientExternalModules: undefined,
isLibFile: false
});
/* eslint-enable no-template-curly-in-string */
});

it("Correctly returns dynamic imports from template expressions and other imports", () => {
/* eslint-disable no-template-curly-in-string */
test("const x = `x ${await import(\"a\").default}`;" + "\n\n" +
"import { y } from \"b\";" + "\n" +
"const y = `y ${import(\"c\")}`;" + "\n\n" +
"import { d } from \"d\";",
/*readImportFile*/ true,
/*detectJavaScriptImports*/ true,
{
referencedFiles: [],
typeReferenceDirectives: [],
libReferenceDirectives: [],
importedFiles: [
{ fileName: "a", pos: 28, end: 29 },
{ fileName: "b", pos: 63, end: 64 },
{ fileName: "c", pos: 90, end: 91 },
{ fileName: "d", pos: 117, end: 118 },
],
ambientExternalModules: undefined,
isLibFile: false
});
/* eslint-enable no-template-curly-in-string */
});

it("Correctly returns empty importedFiles with incorrect template expression", () => {
/* eslint-disable no-template-curly-in-string */
test("const foo = `${",
/*readImportFile*/ true,
/*detectJavaScriptImports*/ true,
{
referencedFiles: [],
typeReferenceDirectives: [],
libReferenceDirectives: [],
importedFiles: [],
ambientExternalModules: undefined,
isLibFile: false
});
/* eslint-enable no-template-curly-in-string */
});

it("Correctly return ES6 exports", () => {
test("export * from \"m1\";" + "\n" +
"export {a} from \"m2\";" + "\n" +
Expand Down