From 50b93bc8035091e42dc02d19b5e6d68099fa7906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 24 Jun 2025 18:49:37 +0200 Subject: [PATCH] Allow trailing commas after import attributes in `ImportType` (#61920) --- src/compiler/parser.ts | 1 + .../reference/importAttributes10.errors.txt | 49 +++++++++++++ .../baselines/reference/importAttributes10.js | 41 +++++++++++ .../reference/importAttributes10.symbols | 50 ++++++++++++++ .../reference/importAttributes10.types | 69 +++++++++++++++++++ .../importAttributes/importAttributes10.ts | 36 ++++++++++ 6 files changed, 246 insertions(+) create mode 100644 tests/baselines/reference/importAttributes10.errors.txt create mode 100644 tests/baselines/reference/importAttributes10.js create mode 100644 tests/baselines/reference/importAttributes10.symbols create mode 100644 tests/baselines/reference/importAttributes10.types create mode 100644 tests/cases/conformance/importAttributes/importAttributes10.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 897919c8a3c..e7fd14cf105 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4564,6 +4564,7 @@ namespace Parser { } parseExpected(SyntaxKind.ColonToken); attributes = parseImportAttributes(currentToken as SyntaxKind.WithKeyword | SyntaxKind.AssertKeyword, /*skipKeyword*/ true); + parseOptional(SyntaxKind.CommaToken); if (!parseExpected(SyntaxKind.CloseBraceToken)) { const lastError = lastOrUndefined(parseDiagnostics); if (lastError && lastError.code === Diagnostics._0_expected.code) { diff --git a/tests/baselines/reference/importAttributes10.errors.txt b/tests/baselines/reference/importAttributes10.errors.txt new file mode 100644 index 00000000000..6ade684ac99 --- /dev/null +++ b/tests/baselines/reference/importAttributes10.errors.txt @@ -0,0 +1,49 @@ +b.ts(22,5): error TS1005: '}' expected. +b.ts(23,1): error TS1128: Declaration or statement expected. +b.ts(23,2): error TS1128: Declaration or statement expected. +b.ts(27,18): error TS1478: Identifier or string literal expected. + + +==== ./a.json (0 errors) ==== + { "key": "value" } + +==== ./b.ts (4 errors) ==== + declare global { + interface ImportAttributes { + type: "json" + } + } + + export type Test1 = typeof import("./a.json", { + with: { + type: "json" + }, + }); + + export type Test2 = typeof import("./a.json", { + with: { + type: "json", + } + }); + + export type Test3 = typeof import("./a.json", { + with: { + type: "json" + },, + ~ +!!! error TS1005: '}' expected. +!!! related TS1007 b.ts:19:47: The parser expected to find a '}' to match the '{' token here. + }); + ~ +!!! error TS1128: Declaration or statement expected. + ~ +!!! error TS1128: Declaration or statement expected. + + export type Test4 = typeof import("./a.json", { + with: { + type: "json",, + ~ +!!! error TS1478: Identifier or string literal expected. + } + }); + \ No newline at end of file diff --git a/tests/baselines/reference/importAttributes10.js b/tests/baselines/reference/importAttributes10.js new file mode 100644 index 00000000000..85768b224f8 --- /dev/null +++ b/tests/baselines/reference/importAttributes10.js @@ -0,0 +1,41 @@ +//// [tests/cases/conformance/importAttributes/importAttributes10.ts] //// + +//// [a.json] +{ "key": "value" } + +//// [b.ts] +declare global { + interface ImportAttributes { + type: "json" + } +} + +export type Test1 = typeof import("./a.json", { + with: { + type: "json" + }, +}); + +export type Test2 = typeof import("./a.json", { + with: { + type: "json", + } +}); + +export type Test3 = typeof import("./a.json", { + with: { + type: "json" + },, +}); + +export type Test4 = typeof import("./a.json", { + with: { + type: "json",, + } +}); + + +//// [b.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +; diff --git a/tests/baselines/reference/importAttributes10.symbols b/tests/baselines/reference/importAttributes10.symbols new file mode 100644 index 00000000000..c875016f69d --- /dev/null +++ b/tests/baselines/reference/importAttributes10.symbols @@ -0,0 +1,50 @@ +//// [tests/cases/conformance/importAttributes/importAttributes10.ts] //// + +=== ./a.json === +{ "key": "value" } +>"key" : Symbol("key", Decl(a.json, 0, 1)) + +=== ./b.ts === +declare global { +>global : Symbol(global, Decl(b.ts, 0, 0)) + + interface ImportAttributes { +>ImportAttributes : Symbol(ImportAttributes, Decl(lib.es5.d.ts, --, --), Decl(b.ts, 0, 16)) + + type: "json" +>type : Symbol(ImportAttributes.type, Decl(b.ts, 1, 32)) + } +} + +export type Test1 = typeof import("./a.json", { +>Test1 : Symbol(Test1, Decl(b.ts, 4, 1)) + + with: { + type: "json" + }, +}); + +export type Test2 = typeof import("./a.json", { +>Test2 : Symbol(Test2, Decl(b.ts, 10, 3)) + + with: { + type: "json", + } +}); + +export type Test3 = typeof import("./a.json", { +>Test3 : Symbol(Test3, Decl(b.ts, 16, 3)) + + with: { + type: "json" + },, +}); + +export type Test4 = typeof import("./a.json", { +>Test4 : Symbol(Test4, Decl(b.ts, 22, 3)) + + with: { + type: "json",, + } +}); + diff --git a/tests/baselines/reference/importAttributes10.types b/tests/baselines/reference/importAttributes10.types new file mode 100644 index 00000000000..deb38bef9e2 --- /dev/null +++ b/tests/baselines/reference/importAttributes10.types @@ -0,0 +1,69 @@ +//// [tests/cases/conformance/importAttributes/importAttributes10.ts] //// + +=== ./a.json === +{ "key": "value" } +>{ "key": "value" } : { key: string; } +> : ^^^^^^^^^^^^^^^^ +>"key" : string +> : ^^^^^^ +>"value" : "value" +> : ^^^^^^^ + +=== ./b.ts === +declare global { +>global : any +> : ^^^ + + interface ImportAttributes { + type: "json" +>type : "json" +> : ^^^^^^ + } +} + +export type Test1 = typeof import("./a.json", { +>Test1 : { key: string; } +> : ^^^^^^^^^^^^^^^^ + + with: { + type: "json" +>type : any +> : ^^^ + + }, +}); + +export type Test2 = typeof import("./a.json", { +>Test2 : { key: string; } +> : ^^^^^^^^^^^^^^^^ + + with: { + type: "json", +>type : any +> : ^^^ + } +}); + +export type Test3 = typeof import("./a.json", { +>Test3 : { key: string; } +> : ^^^^^^^^^^^^^^^^ + + with: { + type: "json" +>type : any +> : ^^^ + + },, +}); + +export type Test4 = typeof import("./a.json", { +>Test4 : { key: string; } +> : ^^^^^^^^^^^^^^^^ + + with: { + type: "json",, +>type : any +> : ^^^ + } +}); + diff --git a/tests/cases/conformance/importAttributes/importAttributes10.ts b/tests/cases/conformance/importAttributes/importAttributes10.ts new file mode 100644 index 00000000000..d359816eb76 --- /dev/null +++ b/tests/cases/conformance/importAttributes/importAttributes10.ts @@ -0,0 +1,36 @@ +// @module: nodenext +// @target: esnext +// @moduleResolution: nodenext +// @filename: ./a.json +{ "key": "value" } + +// @filename: ./b.ts +declare global { + interface ImportAttributes { + type: "json" + } +} + +export type Test1 = typeof import("./a.json", { + with: { + type: "json" + }, +}); + +export type Test2 = typeof import("./a.json", { + with: { + type: "json", + } +}); + +export type Test3 = typeof import("./a.json", { + with: { + type: "json" + },, +}); + +export type Test4 = typeof import("./a.json", { + with: { + type: "json",, + } +});