diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 897919c8a3cee..8c6dd1818f189 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4562,16 +4562,17 @@ namespace Parser { else { parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.WithKeyword)); } - parseExpected(SyntaxKind.ColonToken); - attributes = parseImportAttributes(currentToken as SyntaxKind.WithKeyword | SyntaxKind.AssertKeyword, /*skipKeyword*/ true); - if (!parseExpected(SyntaxKind.CloseBraceToken)) { - const lastError = lastOrUndefined(parseDiagnostics); - if (lastError && lastError.code === Diagnostics._0_expected.code) { - addRelatedInfo( - lastError, - createDetachedDiagnostic(fileName, sourceText, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}"), - ); - } + parseExpected(SyntaxKind.ColonToken); + attributes = parseImportAttributes(currentToken as SyntaxKind.WithKeyword | SyntaxKind.AssertKeyword, /*skipKeyword*/ true); + parseOptional(SyntaxKind.CommaToken); // Allow trailing comma after import attributes + if (!parseExpected(SyntaxKind.CloseBraceToken)) { + const lastError = lastOrUndefined(parseDiagnostics); + if (lastError && lastError.code === Diagnostics._0_expected.code) { + addRelatedInfo( + lastError, + createDetachedDiagnostic(fileName, sourceText, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}"), + ); + } } } parseExpected(SyntaxKind.CloseParenToken); diff --git a/tests/baselines/reference/importTypeTrailingComma.errors.txt b/tests/baselines/reference/importTypeTrailingComma.errors.txt new file mode 100644 index 0000000000000..96353eab59292 --- /dev/null +++ b/tests/baselines/reference/importTypeTrailingComma.errors.txt @@ -0,0 +1,44 @@ +importTypeTrailingComma.ts(5,17): error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? +importTypeTrailingComma.ts(8,17): error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? +importTypeTrailingComma.ts(11,17): error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? +importTypeTrailingComma.ts(14,17): error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? +importTypeTrailingComma.ts(17,24): error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? +importTypeTrailingComma.ts(20,17): error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? +importTypeTrailingComma.ts(20,42): error TS1464: Type import attributes should have exactly one key - 'resolution-mode' - with value 'import' or 'require'. + + +==== importTypeTrailingComma.ts (7 errors) ==== + // Test that trailing commas are allowed in import type attributes + // This should work consistently with dynamic imports + + // Trailing comma inside with object (already worked) + type A = import("./nonexistent", { with: { type: "json", } }) + ~~~~~~~~~~~~~~~ +!!! error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? + + // Trailing comma after with object (this is the fix) + type B = import("./nonexistent", { with: { type: "json" }, }) + ~~~~~~~~~~~~~~~ +!!! error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? + + // No trailing comma for comparison + type C = import("./nonexistent", { with: { type: "json" } }) + ~~~~~~~~~~~~~~~ +!!! error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? + + // Assert syntax with trailing comma + type D = import("./nonexistent", { assert: { type: "json" }, }) + ~~~~~~~~~~~~~~~ +!!! error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? + + // typeof with trailing comma + type E = typeof import("./nonexistent", { with: { type: "json" }, }) + ~~~~~~~~~~~~~~~ +!!! error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? + + // Multiple properties in with object with trailing comma after + type F = import("./nonexistent", { with: { type: "json", "resolution-mode": "import" }, }) + ~~~~~~~~~~~~~~~ +!!! error TS2792: Cannot find module './nonexistent'. Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option? + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1464: Type import attributes should have exactly one key - 'resolution-mode' - with value 'import' or 'require'. \ No newline at end of file diff --git a/tests/baselines/reference/importTypeTrailingComma.js b/tests/baselines/reference/importTypeTrailingComma.js new file mode 100644 index 0000000000000..c3c20ac12e795 --- /dev/null +++ b/tests/baselines/reference/importTypeTrailingComma.js @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/importTypeTrailingComma.ts] //// + +//// [importTypeTrailingComma.ts] +// Test that trailing commas are allowed in import type attributes +// This should work consistently with dynamic imports + +// Trailing comma inside with object (already worked) +type A = import("./nonexistent", { with: { type: "json", } }) + +// Trailing comma after with object (this is the fix) +type B = import("./nonexistent", { with: { type: "json" }, }) + +// No trailing comma for comparison +type C = import("./nonexistent", { with: { type: "json" } }) + +// Assert syntax with trailing comma +type D = import("./nonexistent", { assert: { type: "json" }, }) + +// typeof with trailing comma +type E = typeof import("./nonexistent", { with: { type: "json" }, }) + +// Multiple properties in with object with trailing comma after +type F = import("./nonexistent", { with: { type: "json", "resolution-mode": "import" }, }) + +//// [importTypeTrailingComma.js] +// Test that trailing commas are allowed in import type attributes +// This should work consistently with dynamic imports diff --git a/tests/baselines/reference/importTypeTrailingComma.symbols b/tests/baselines/reference/importTypeTrailingComma.symbols new file mode 100644 index 0000000000000..5e935134051fd --- /dev/null +++ b/tests/baselines/reference/importTypeTrailingComma.symbols @@ -0,0 +1,30 @@ +//// [tests/cases/compiler/importTypeTrailingComma.ts] //// + +=== importTypeTrailingComma.ts === +// Test that trailing commas are allowed in import type attributes +// This should work consistently with dynamic imports + +// Trailing comma inside with object (already worked) +type A = import("./nonexistent", { with: { type: "json", } }) +>A : Symbol(A, Decl(importTypeTrailingComma.ts, 0, 0)) + +// Trailing comma after with object (this is the fix) +type B = import("./nonexistent", { with: { type: "json" }, }) +>B : Symbol(B, Decl(importTypeTrailingComma.ts, 4, 61)) + +// No trailing comma for comparison +type C = import("./nonexistent", { with: { type: "json" } }) +>C : Symbol(C, Decl(importTypeTrailingComma.ts, 7, 61)) + +// Assert syntax with trailing comma +type D = import("./nonexistent", { assert: { type: "json" }, }) +>D : Symbol(D, Decl(importTypeTrailingComma.ts, 10, 60)) + +// typeof with trailing comma +type E = typeof import("./nonexistent", { with: { type: "json" }, }) +>E : Symbol(E, Decl(importTypeTrailingComma.ts, 13, 63)) + +// Multiple properties in with object with trailing comma after +type F = import("./nonexistent", { with: { type: "json", "resolution-mode": "import" }, }) +>F : Symbol(F, Decl(importTypeTrailingComma.ts, 16, 68)) + diff --git a/tests/baselines/reference/importTypeTrailingComma.types b/tests/baselines/reference/importTypeTrailingComma.types new file mode 100644 index 0000000000000..dac105327395d --- /dev/null +++ b/tests/baselines/reference/importTypeTrailingComma.types @@ -0,0 +1,48 @@ +//// [tests/cases/compiler/importTypeTrailingComma.ts] //// + +=== importTypeTrailingComma.ts === +// Test that trailing commas are allowed in import type attributes +// This should work consistently with dynamic imports + +// Trailing comma inside with object (already worked) +type A = import("./nonexistent", { with: { type: "json", } }) +>A : any +> : ^^^ +>type : any +> : ^^^ + +// Trailing comma after with object (this is the fix) +type B = import("./nonexistent", { with: { type: "json" }, }) +>B : any +> : ^^^ +>type : any +> : ^^^ + +// No trailing comma for comparison +type C = import("./nonexistent", { with: { type: "json" } }) +>C : any +> : ^^^ +>type : any +> : ^^^ + +// Assert syntax with trailing comma +type D = import("./nonexistent", { assert: { type: "json" }, }) +>D : any +> : ^^^ +>type : any +> : ^^^ + +// typeof with trailing comma +type E = typeof import("./nonexistent", { with: { type: "json" }, }) +>E : any +> : ^^^ +>type : any +> : ^^^ + +// Multiple properties in with object with trailing comma after +type F = import("./nonexistent", { with: { type: "json", "resolution-mode": "import" }, }) +>F : any +> : ^^^ +>type : any +> : ^^^ + diff --git a/tests/cases/compiler/importTypeTrailingComma.ts b/tests/cases/compiler/importTypeTrailingComma.ts new file mode 100644 index 0000000000000..f3e7a0bce40f6 --- /dev/null +++ b/tests/cases/compiler/importTypeTrailingComma.ts @@ -0,0 +1,21 @@ +// @module: esnext +// Test that trailing commas are allowed in import type attributes +// This should work consistently with dynamic imports + +// Trailing comma inside with object (already worked) +type A = import("./nonexistent", { with: { type: "json", } }) + +// Trailing comma after with object (this is the fix) +type B = import("./nonexistent", { with: { type: "json" }, }) + +// No trailing comma for comparison +type C = import("./nonexistent", { with: { type: "json" } }) + +// Assert syntax with trailing comma +type D = import("./nonexistent", { assert: { type: "json" }, }) + +// typeof with trailing comma +type E = typeof import("./nonexistent", { with: { type: "json" }, }) + +// Multiple properties in with object with trailing comma after +type F = import("./nonexistent", { with: { type: "json", "resolution-mode": "import" }, }) \ No newline at end of file