Skip to content

Commit 88f025b

Browse files
Copilotjakebailey
andcommitted
Reject import assert in parser and remove checker assert-specific logic
Error at parse time when 'assert' keyword is used for import attributes (in all 3 parse locations: tryParseImportAttributes, parseExportDeclaration, parseImportType). Remove checker logic that distinguished between 'assert' and 'with' tokens, always using 'import attributes' messages. Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
1 parent e99e2c5 commit 88f025b

26 files changed

Lines changed: 1225 additions & 187 deletions

File tree

internal/checker/checker.go

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3231,9 +3231,7 @@ func (c *Checker) checkImportType(node *ast.Node) {
32313231
func (c *Checker) getResolutionModeOverride(node *ast.ImportAttributes, reportErrors bool) core.ResolutionMode {
32323232
if len(node.Attributes.Nodes) != 1 {
32333233
if reportErrors {
3234-
c.grammarErrorOnNode(node.AsNode(), core.IfElse(node.Token == ast.KindWithKeyword,
3235-
diagnostics.Type_import_attributes_should_have_exactly_one_key_resolution_mode_with_value_import_or_require,
3236-
diagnostics.Type_import_assertions_should_have_exactly_one_key_resolution_mode_with_value_import_or_require))
3234+
c.grammarErrorOnNode(node.AsNode(), diagnostics.Type_import_attributes_should_have_exactly_one_key_resolution_mode_with_value_import_or_require)
32373235
}
32383236
return core.ResolutionModeNone
32393237
}
@@ -3243,9 +3241,7 @@ func (c *Checker) getResolutionModeOverride(node *ast.ImportAttributes, reportEr
32433241
}
32443242
if elem.Name().Text() != "resolution-mode" {
32453243
if reportErrors {
3246-
c.grammarErrorOnNode(elem.Name(), core.IfElse(node.Token == ast.KindWithKeyword,
3247-
diagnostics.X_resolution_mode_is_the_only_valid_key_for_type_import_attributes,
3248-
diagnostics.X_resolution_mode_is_the_only_valid_key_for_type_import_assertions))
3244+
c.grammarErrorOnNode(elem.Name(), diagnostics.X_resolution_mode_is_the_only_valid_key_for_type_import_attributes)
32493245
}
32503246
return core.ResolutionModeNone
32513247
}
@@ -5207,14 +5203,11 @@ func (c *Checker) checkExternalImportOrExportDeclaration(node *ast.Node) bool {
52075203
if !ast.IsImportEqualsDeclaration(node) {
52085204
attributes := ast.GetImportAttributes(node)
52095205
if attributes != nil {
5210-
diagnostic := core.IfElse(attributes.AsImportAttributes().Token == ast.KindWithKeyword,
5211-
diagnostics.Import_attribute_values_must_be_string_literal_expressions,
5212-
diagnostics.Import_assertion_values_must_be_string_literal_expressions)
52135206
hasError := false
52145207
for _, attr := range attributes.AsImportAttributes().Attributes.Nodes {
52155208
if !ast.IsStringLiteral(attr.AsImportAttribute().Value) {
52165209
hasError = true
5217-
c.error(attr.AsImportAttribute().Value, diagnostic)
5210+
c.error(attr.AsImportAttribute().Value, diagnostics.Import_attribute_values_must_be_string_literal_expressions)
52185211
}
52195212
}
52205213
return !hasError
@@ -5260,40 +5253,24 @@ func (c *Checker) checkImportAttributes(declaration *ast.Node) {
52605253
}
52615254
isTypeOnly := ast.IsExclusivelyTypeOnlyImportOrExport(declaration)
52625255
override := c.getResolutionModeOverride(node.AsImportAttributes(), isTypeOnly)
5263-
isImportAttributes := node.AsImportAttributes().Token == ast.KindWithKeyword
52645256
if isTypeOnly && override != core.ResolutionModeNone {
52655257
return // Other grammar checks do not apply to type-only imports with resolution mode assertions
52665258
}
52675259

52685260
if !c.moduleKind.SupportsImportAttributes() {
5269-
if isImportAttributes {
5270-
c.grammarErrorOnNode(node, diagnostics.Import_attributes_are_only_supported_when_the_module_option_is_set_to_esnext_node18_node20_nodenext_or_preserve)
5271-
} else {
5272-
c.grammarErrorOnNode(node, diagnostics.Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_node18_node20_nodenext_or_preserve)
5273-
}
5274-
return
5275-
}
5276-
5277-
if core.ModuleKindNode20 <= c.moduleKind && c.moduleKind <= core.ModuleKindNodeNext && !isImportAttributes {
5278-
c.grammarErrorOnNode(node, diagnostics.Import_assertions_have_been_replaced_by_import_attributes_Use_with_instead_of_assert)
5261+
c.grammarErrorOnNode(node, diagnostics.Import_attributes_are_only_supported_when_the_module_option_is_set_to_esnext_node18_node20_nodenext_or_preserve)
52795262
return
52805263
}
52815264

52825265
if moduleSpecifier := getModuleSpecifierFromNode(declaration); moduleSpecifier != nil {
52835266
if c.getEmitSyntaxForModuleSpecifierExpression(moduleSpecifier) == core.ModuleKindCommonJS {
5284-
if isImportAttributes {
5285-
c.grammarErrorOnNode(node, diagnostics.Import_attributes_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls)
5286-
} else {
5287-
c.grammarErrorOnNode(node, diagnostics.Import_assertions_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls)
5288-
}
5267+
c.grammarErrorOnNode(node, diagnostics.Import_attributes_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls)
52895268
return
52905269
}
52915270
}
52925271

52935272
if isTypeOnly {
5294-
c.grammarErrorOnNode(node, core.IfElse(isImportAttributes,
5295-
diagnostics.Import_attributes_cannot_be_used_with_type_only_imports_or_exports,
5296-
diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports))
5273+
c.grammarErrorOnNode(node, diagnostics.Import_attributes_cannot_be_used_with_type_only_imports_or_exports)
52975274
return
52985275
}
52995276
if override != core.ResolutionModeNone {

internal/parser/parser.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2379,6 +2379,9 @@ func (p *Parser) parseModuleExportName(disallowKeywords bool) (node *ast.Node, n
23792379

23802380
func (p *Parser) tryParseImportAttributes() *ast.Node {
23812381
if p.token == ast.KindWithKeyword || (p.token == ast.KindAssertKeyword && !p.hasPrecedingLineBreak()) {
2382+
if p.token == ast.KindAssertKeyword {
2383+
p.parseErrorAtCurrentToken(diagnostics.Import_assertions_have_been_replaced_by_import_attributes_Use_with_instead_of_assert)
2384+
}
23822385
return p.parseImportAttributes(p.token, false /*skipKeyword*/)
23832386
}
23842387
return nil
@@ -2443,6 +2446,9 @@ func (p *Parser) parseExportDeclaration(pos int, hasJSDoc bool, modifiers *ast.M
24432446
}
24442447
}
24452448
if moduleSpecifier != nil && (p.token == ast.KindWithKeyword || p.token == ast.KindAssertKeyword) && !p.hasPrecedingLineBreak() {
2449+
if p.token == ast.KindAssertKeyword {
2450+
p.parseErrorAtCurrentToken(diagnostics.Import_assertions_have_been_replaced_by_import_attributes_Use_with_instead_of_assert)
2451+
}
24462452
attributes = p.parseImportAttributes(p.token, false /*skipKeyword*/)
24472453
}
24482454
p.parseSemicolon()
@@ -2914,6 +2920,9 @@ func (p *Parser) parseImportType() *ast.Node {
29142920
p.parseExpected(ast.KindOpenBraceToken)
29152921
currentToken := p.token
29162922
if currentToken == ast.KindWithKeyword || currentToken == ast.KindAssertKeyword {
2923+
if currentToken == ast.KindAssertKeyword {
2924+
p.parseErrorAtCurrentToken(diagnostics.Import_assertions_have_been_replaced_by_import_attributes_Use_with_instead_of_assert)
2925+
}
29172926
p.nextToken()
29182927
} else {
29192928
p.parseErrorAtCurrentToken(diagnostics.X_0_expected, scanner.TokenToString(ast.KindWithKeyword))
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/a.ts(1,35): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
2+
/b.ts(1,37): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
3+
/c.ts(1,51): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
4+
5+
6+
==== /a.ts (1 errors) ====
7+
import json from "./package.json" assert { type: "json" };
8+
~~~~~~
9+
!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
10+
11+
==== /b.ts (1 errors) ====
12+
import * as data from "./data.json" assert { type: "json" };
13+
~~~~~~
14+
!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
15+
16+
==== /c.ts (1 errors) ====
17+
export { default as config } from "./config.json" assert { type: "json" };
18+
~~~~~~
19+
!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
20+
21+
==== /package.json (0 errors) ====
22+
{}
23+
24+
==== /data.json (0 errors) ====
25+
{}
26+
27+
==== /config.json (0 errors) ====
28+
{}
29+

testdata/baselines/reference/submodule/compiler/importAssertionsDeprecated.errors.txt.diff

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/a.ts(2,35): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
2+
/b.ts(1,37): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
3+
/c.ts(1,51): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
4+
5+
6+
==== /a.ts (1 errors) ====
7+
// With ignoreDeprecations: "6.0", import assertions should not produce a deprecation error.
8+
import json from "./package.json" assert { type: "json" };
9+
~~~~~~
10+
!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
11+
12+
==== /b.ts (1 errors) ====
13+
import * as data from "./data.json" assert { type: "json" };
14+
~~~~~~
15+
!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
16+
17+
==== /c.ts (1 errors) ====
18+
export { default as config } from "./config.json" assert { type: "json" };
19+
~~~~~~
20+
!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
21+
22+
==== /package.json (0 errors) ====
23+
{}
24+
25+
==== /data.json (0 errors) ====
26+
{}
27+
28+
==== /config.json (0 errors) ====
29+
{}
30+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--- old.importAssertionsDeprecatedIgnored.errors.txt
2+
+++ new.importAssertionsDeprecatedIgnored.errors.txt
3+
@@= skipped -0, +0 lines =@@
4+
-<no content>
5+
+/a.ts(2,35): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
6+
+/b.ts(1,37): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
7+
+/c.ts(1,51): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
8+
+
9+
+
10+
+==== /a.ts (1 errors) ====
11+
+ // With ignoreDeprecations: "6.0", import assertions should not produce a deprecation error.
12+
+ import json from "./package.json" assert { type: "json" };
13+
+ ~~~~~~
14+
+!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
15+
+
16+
+==== /b.ts (1 errors) ====
17+
+ import * as data from "./data.json" assert { type: "json" };
18+
+ ~~~~~~
19+
+!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
20+
+
21+
+==== /c.ts (1 errors) ====
22+
+ export { default as config } from "./config.json" assert { type: "json" };
23+
+ ~~~~~~
24+
+!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
25+
+
26+
+==== /package.json (0 errors) ====
27+
+ {}
28+
+
29+
+==== /data.json (0 errors) ====
30+
+ {}
31+
+
32+
+==== /config.json (0 errors) ====
33+
+ {}
34+
+

testdata/baselines/reference/submodule/compiler/parseAssertEntriesError.errors.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/index.ts(2,7): error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
2+
/index.ts(2,23): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
23
/index.ts(2,32): error TS1478: Identifier or string literal expected.
34
/index.ts(2,32): error TS2695: Left side of comma operator is unused and has no side effects.
45
/index.ts(2,55): error TS1005: ';' expected.
@@ -10,6 +11,7 @@
1011
/index.ts(3,36): error TS1005: ':' expected.
1112
/index.ts(3,70): error TS2339: Property 'ImportInterface' does not exist on type 'Promise<{ default: typeof import("/node_modules/pkg/import"); }>'.
1213
/index.ts(5,34): error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
14+
/index.ts(5,50): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
1315
/index.ts(5,59): error TS1478: Identifier or string literal expected.
1416
/index.ts(5,59): error TS2695: Left side of comma operator is unused and has no side effects.
1517
/index.ts(5,82): error TS1005: ';' expected.
@@ -21,6 +23,7 @@
2123
/index.ts(5,98): error TS2304: Cannot find name 'RequireInterface'.
2224
/index.ts(5,114): error TS1128: Declaration or statement expected.
2325
/index.ts(6,34): error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
26+
/index.ts(6,50): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
2427
/index.ts(6,59): error TS1478: Identifier or string literal expected.
2528
/index.ts(6,59): error TS2695: Left side of comma operator is unused and has no side effects.
2629
/index.ts(6,82): error TS1005: ';' expected.
@@ -33,11 +36,13 @@
3336
/index.ts(6,112): error TS1128: Declaration or statement expected.
3437

3538

36-
==== /index.ts (33 errors) ====
39+
==== /index.ts (36 errors) ====
3740
export type LocalInterface =
3841
& import("pkg", { assert: {1234, "resolution-mode": "require"} }).RequireInterface
3942
~~~~~~~~~~~~~~~~~~~~~~~~~
4043
!!! error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
44+
~~~~~~
45+
!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
4146
~~~~
4247
!!! error TS1478: Identifier or string literal expected.
4348
~~~~
@@ -63,6 +68,8 @@
6368
export const a = (null as any as import("pkg", { assert: {1234, "resolution-mode": "require"} }).RequireInterface);
6469
~~~~~~~~~~~~~~~~~~~~~~~~~
6570
!!! error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
71+
~~~~~~
72+
!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
6673
~~~~
6774
!!! error TS1478: Identifier or string literal expected.
6875
~~~~
@@ -86,6 +93,8 @@
8693
export const b = (null as any as import("pkg", { assert: {1234, "resolution-mode": "import"} }).ImportInterface);
8794
~~~~~~~~~~~~~~~~~~~~~~~~~
8895
!!! error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
96+
~~~~~~
97+
!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
8998
~~~~
9099
!!! error TS1478: Identifier or string literal expected.
91100
~~~~
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--- old.parseAssertEntriesError.errors.txt
2+
+++ new.parseAssertEntriesError.errors.txt
3+
@@= skipped -0, +0 lines =@@
4+
/index.ts(2,7): error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
5+
+/index.ts(2,23): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
6+
/index.ts(2,32): error TS1478: Identifier or string literal expected.
7+
/index.ts(2,32): error TS2695: Left side of comma operator is unused and has no side effects.
8+
/index.ts(2,55): error TS1005: ';' expected.
9+
@@= skipped -9, +10 lines =@@
10+
/index.ts(3,36): error TS1005: ':' expected.
11+
/index.ts(3,70): error TS2339: Property 'ImportInterface' does not exist on type 'Promise<{ default: typeof import("/node_modules/pkg/import"); }>'.
12+
/index.ts(5,34): error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
13+
+/index.ts(5,50): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
14+
/index.ts(5,59): error TS1478: Identifier or string literal expected.
15+
/index.ts(5,59): error TS2695: Left side of comma operator is unused and has no side effects.
16+
/index.ts(5,82): error TS1005: ';' expected.
17+
@@= skipped -11, +12 lines =@@
18+
/index.ts(5,98): error TS2304: Cannot find name 'RequireInterface'.
19+
/index.ts(5,114): error TS1128: Declaration or statement expected.
20+
/index.ts(6,34): error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
21+
+/index.ts(6,50): error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
22+
/index.ts(6,59): error TS1478: Identifier or string literal expected.
23+
/index.ts(6,59): error TS2695: Left side of comma operator is unused and has no side effects.
24+
/index.ts(6,82): error TS1005: ';' expected.
25+
@@= skipped -12, +13 lines =@@
26+
/index.ts(6,112): error TS1128: Declaration or statement expected.
27+
28+
29+
-==== /index.ts (33 errors) ====
30+
+==== /index.ts (36 errors) ====
31+
export type LocalInterface =
32+
& import("pkg", { assert: {1234, "resolution-mode": "require"} }).RequireInterface
33+
~~~~~~~~~~~~~~~~~~~~~~~~~
34+
!!! error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
35+
+ ~~~~~~
36+
+!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
37+
~~~~
38+
!!! error TS1478: Identifier or string literal expected.
39+
~~~~
40+
@@= skipped -30, +32 lines =@@
41+
export const a = (null as any as import("pkg", { assert: {1234, "resolution-mode": "require"} }).RequireInterface);
42+
~~~~~~~~~~~~~~~~~~~~~~~~~
43+
!!! error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
44+
+ ~~~~~~
45+
+!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
46+
~~~~
47+
!!! error TS1478: Identifier or string literal expected.
48+
~~~~
49+
@@= skipped -23, +25 lines =@@
50+
export const b = (null as any as import("pkg", { assert: {1234, "resolution-mode": "import"} }).ImportInterface);
51+
~~~~~~~~~~~~~~~~~~~~~~~~~
52+
!!! error TS1340: Module 'pkg' does not refer to a type, but is used as a type here. Did you mean 'typeof import('pkg')'?
53+
+ ~~~~~~
54+
+!!! error TS2880: Import assertions have been replaced by import attributes. Use 'with' instead of 'assert'.
55+
~~~~
56+
!!! error TS1478: Identifier or string literal expected.
57+
~~~~

0 commit comments

Comments
 (0)