feat(rslint_parser): Parse 2nd param for JsImportCallExpression
MODIFY
crates/rome_formatter/src/ts/import/mod.rs
crates/rome_formatter/src/ts/import/mod.rs
@@ -5,9 +5,7 @@ impl ToFormatElement for JsImportCallExpression {
fn to_format_element(&self, formatter: &Formatter) -> FormatResult<FormatElement> {
Ok(format_elements![
formatter.format_token(&self.import_token()?)?,
- formatter.format_token(&self.l_paren_token()?)?,
- formatter.format_node(self.argument()?)?,
- formatter.format_token(&self.r_paren_token()?)?,
+ formatter.format_node(self.arguments()?)?,
])
}
}

MODIFY
crates/rome_formatter/tests/specs/js/import/import_call.js
crates/rome_formatter/tests/specs/js/import/import_call.js
import(x)
import('x')
-import(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)
+import(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, {assert: {type:'json'}})

MODIFY
crates/rome_formatter/tests/specs/js/import/import_call.js.snap
crates/rome_formatter/tests/specs/js/import/import_call.js.snap
@@ -6,11 +6,13 @@ expression: import_call.js
# Input
import(x)
import('x')
-import(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)
+import(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, {assert: {type:'json'}})
---
# Output
import(x);
import("x");
-import(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
+import(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, {
+ assert: { type: "json" },
+});

MODIFY
crates/rslint_parser/src/ast/generated/nodes.rs
crates/rslint_parser/src/ast/generated/nodes.rs
@@ -1143,14 +1143,8 @@ impl JsImportCallExpression {
pub fn import_token(&self) -> SyntaxResult<SyntaxToken> {
support::required_token(&self.syntax, 0usize)
}
- pub fn l_paren_token(&self) -> SyntaxResult<SyntaxToken> {
- support::required_token(&self.syntax, 1usize)
- }
- pub fn argument(&self) -> SyntaxResult<JsAnyExpression> {
- support::required_node(&self.syntax, 2usize)
- }
- pub fn r_paren_token(&self) -> SyntaxResult<SyntaxToken> {
- support::required_token(&self.syntax, 3usize)
+ pub fn arguments(&self) -> SyntaxResult<JsCallArguments> {
+ support::required_node(&self.syntax, 1usize)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
@@ -5689,15 +5683,7 @@ impl std::fmt::Debug for JsImportCallExpression {
"import_token",
&support::DebugSyntaxResult(self.import_token()),
)
- .field(
- "l_paren_token",
- &support::DebugSyntaxResult(self.l_paren_token()),
- )
- .field("argument", &support::DebugSyntaxResult(self.argument()))
- .field(
- "r_paren_token",
- &support::DebugSyntaxResult(self.r_paren_token()),
- )
+ .field("arguments", &support::DebugSyntaxResult(self.arguments()))
.finish()
}
}

MODIFY
crates/rslint_parser/src/ast/generated/syntax_factory.rs
crates/rslint_parser/src/ast/generated/syntax_factory.rs
@@ -2905,7 +2905,7 @@ impl SyntaxFactory for JsSyntaxFactory {
}
JS_IMPORT_CALL_EXPRESSION => {
let mut elements = (&children).into_iter();
- let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default();
+ let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default();
let mut current_element = elements.next();
if let Some(element) = &current_element {
if element.kind() == T![import] {
@@ -2915,21 +2915,7 @@ impl SyntaxFactory for JsSyntaxFactory {
}
slots.next_slot();
if let Some(element) = &current_element {
- if element.kind() == T!['('] {
- slots.mark_present();
- current_element = elements.next();
- }
- }
- slots.next_slot();
- if let Some(element) = &current_element {
- if JsAnyExpression::can_cast(element.kind()) {
- slots.mark_present();
- current_element = elements.next();
- }
- }
- slots.next_slot();
- if let Some(element) = &current_element {
- if element.kind() == T![')'] {
+ if JsCallArguments::can_cast(element.kind()) {
slots.mark_present();
current_element = elements.next();
}

MODIFY
crates/rslint_parser/src/syntax/expr.rs
crates/rslint_parser/src/syntax/expr.rs
@@ -1091,21 +1091,62 @@ fn parse_primary_expression(p: &mut Parser) -> ParsedSyntax {
p.error(err);
m.complete(p, JS_UNKNOWN)
}
- } else {
- // test_err import_call_no_arg
- // let a = import();
- // foo();
-
+ } else if p.at(T!['(']) {
// test import_call
// import("foo")
+ // import("foo", { assert: { type: 'json' } })
- // test_err import_call
+ // test_err import_invalid_args
// import()
- p.expect(T!['(']);
+ // import(...["foo"])
+ // import("foo", { assert: { type: 'json' } }, "bar")
+
+ let args = p.start();
+ p.bump(T!['(']);
+ let args_list = p.start();
+
+ let mut progress = ParserProgress::default();
+ let mut error_range_start = p.cur_tok().start();
+ let mut args_count = 0;
+
+ while !p.at(EOF) && !p.at(T![')']) {
+ progress.assert_progressing(p);
+ args_count += 1;
+
+ if args_count == 3 {
+ error_range_start = p.cur_tok().start();
+ }
+
+ if p.at(T![...]) {
+ let err = p
+ .err_builder("`...` is not allowed in `import()`")
+ .primary(p.cur_tok().range(), "");
+ p.error(err);
+ } else {
parse_expr_or_assignment(p)
.or_add_diagnostic(p, js_parse_error::expected_expression_assignment);
+ }
+
+ if p.at(T![,]) {
+ p.bump_any();
+ } else {
+ break;
+ }
+ }
+
+ args_list.complete(p, JS_CALL_ARGUMENT_LIST);
+ if args_count == 0 || args_count > 2 {
+ let err = p
+ .err_builder("`import()` requires exactly one or two arguments. ")
+ .primary(error_range_start..p.cur_tok().end(), "");
+ p.error(err);
+ }
+
p.expect(T![')']);
+ args.complete(p, JS_CALL_ARGUMENTS);
m.complete(p, JS_IMPORT_CALL_EXPRESSION)
+ } else {
+ return Absent;
}
}
BACKTICK => parse_template_literal(p, Absent),

DELETE
crates/rslint_parser/test_data/inline/err/import_call.js
-import()

DELETE
crates/rslint_parser/test_data/inline/err/import_call_no_arg.js
-let a = import();
-foo();

ADD
crates/rslint_parser/test_data/inline/err/import_invalid_args.js
+import()
+import(...["foo"])
+import("foo", { assert: { type: 'json' } }, "bar")

MODIFY
crates/rslint_parser/test_data/inline/ok/import_call.js
crates/rslint_parser/test_data/inline/ok/import_call.js
import("foo")
+import("foo", { assert: { type: 'json' } })

MODIFY
crates/rslint_parser/test_data/inline/ok/import_call.rast
crates/rslint_parser/test_data/inline/ok/import_call.rast
@@ -5,28 +5,106 @@ JsModule {
JsExpressionStatement {
expression: JsImportCallExpression {
import_token: IMPORT_KW@0..6 "import" [] [],
+ arguments: JsCallArguments {
l_paren_token: L_PAREN@6..7 "(" [] [],
- argument: JsStringLiteralExpression {
+ args: JsCallArgumentList [
+ JsStringLiteralExpression {
value_token: JS_STRING_LITERAL@7..12 "\"foo\"" [] [],
},
+ ],
r_paren_token: R_PAREN@12..13 ")" [] [],
},
+ },
+ semicolon_token: missing (optional),
+ },
+ JsExpressionStatement {
+ expression: JsImportCallExpression {
+ import_token: IMPORT_KW@13..20 "import" [Whitespace("\n")] [],
+ arguments: JsCallArguments {
+ l_paren_token: L_PAREN@20..21 "(" [] [],
+ args: JsCallArgumentList [
+ JsStringLiteralExpression {
+ value_token: JS_STRING_LITERAL@21..26 "\"foo\"" [] [],
+ },
+ COMMA@26..28 "," [] [Whitespace(" ")],
+ JsObjectExpression {
+ l_curly_token: L_CURLY@28..30 "{" [] [Whitespace(" ")],
+ members: JsObjectMemberList [
+ JsPropertyObjectMember {
+ name: JsLiteralMemberName {
+ value: IDENT@30..36 "assert" [] [],
+ },
+ colon_token: COLON@36..38 ":" [] [Whitespace(" ")],
+ value: JsObjectExpression {
+ l_curly_token: L_CURLY@38..40 "{" [] [Whitespace(" ")],
+ members: JsObjectMemberList [
+ JsPropertyObjectMember {
+ name: JsLiteralMemberName {
+ value: IDENT@40..44 "type" [] [],
+ },
+ colon_token: COLON@44..46 ":" [] [Whitespace(" ")],
+ value: JsStringLiteralExpression {
+ value_token: JS_STRING_LITERAL@46..53 "'json'" [] [Whitespace(" ")],
+ },
+ },
+ ],
+ r_curly_token: R_CURLY@53..55 "}" [] [Whitespace(" ")],
+ },
+ },
+ ],
+ r_curly_token: R_CURLY@55..56 "}" [] [],
+ },
+ ],
+ r_paren_token: R_PAREN@56..57 ")" [] [],
+ },
+ },
semicolon_token: missing (optional),
},
],
- eof_token: EOF@13..14 "" [Whitespace("\n")] [],
+ eof_token: EOF@57..58 "" [Whitespace("\n")] [],
}
-0: JS_MODULE@0..14
+0: JS_MODULE@0..58
0: (empty)
1: JS_DIRECTIVE_LIST@0..0
- 2: JS_MODULE_ITEM_LIST@0..13
+ 2: JS_MODULE_ITEM_LIST@0..57
0: JS_EXPRESSION_STATEMENT@0..13
0: JS_IMPORT_CALL_EXPRESSION@0..13
0: IMPORT_KW@0..6 "import" [] []
- 1: L_PAREN@6..7 "(" [] []
- 2: JS_STRING_LITERAL_EXPRESSION@7..12
+ 1: JS_CALL_ARGUMENTS@6..13
+ 0: L_PAREN@6..7 "(" [] []
+ 1: JS_CALL_ARGUMENT_LIST@7..12
+ 0: JS_STRING_LITERAL_EXPRESSION@7..12
0: JS_STRING_LITERAL@7..12 "\"foo\"" [] []
- 3: R_PAREN@12..13 ")" [] []
+ 2: R_PAREN@12..13 ")" [] []
+ 1: (empty)
+ 1: JS_EXPRESSION_STATEMENT@13..57
+ 0: JS_IMPORT_CALL_EXPRESSION@13..57
+ 0: IMPORT_KW@13..20 "import" [Whitespace("\n")] []
+ 1: JS_CALL_ARGUMENTS@20..57
+ 0: L_PAREN@20..21 "(" [] []
+ 1: JS_CALL_ARGUMENT_LIST@21..56
+ 0: JS_STRING_LITERAL_EXPRESSION@21..26
+ 0: JS_STRING_LITERAL@21..26 "\"foo\"" [] []
+ 1: COMMA@26..28 "," [] [Whitespace(" ")]
+ 2: JS_OBJECT_EXPRESSION@28..56
+ 0: L_CURLY@28..30 "{" [] [Whitespace(" ")]
+ 1: JS_OBJECT_MEMBER_LIST@30..55
+ 0: JS_PROPERTY_OBJECT_MEMBER@30..55
+ 0: JS_LITERAL_MEMBER_NAME@30..36
+ 0: IDENT@30..36 "assert" [] []
+ 1: COLON@36..38 ":" [] [Whitespace(" ")]
+ 2: JS_OBJECT_EXPRESSION@38..55
+ 0: L_CURLY@38..40 "{" [] [Whitespace(" ")]
+ 1: JS_OBJECT_MEMBER_LIST@40..53
+ 0: JS_PROPERTY_OBJECT_MEMBER@40..53
+ 0: JS_LITERAL_MEMBER_NAME@40..44
+ 0: IDENT@40..44 "type" [] []
+ 1: COLON@44..46 ":" [] [Whitespace(" ")]
+ 2: JS_STRING_LITERAL_EXPRESSION@46..53
+ 0: JS_STRING_LITERAL@46..53 "'json'" [] [Whitespace(" ")]
+ 2: R_CURLY@53..55 "}" [] [Whitespace(" ")]
+ 2: R_CURLY@55..56 "}" [] []
+ 2: R_PAREN@56..57 ")" [] []
1: (empty)
- 3: EOF@13..14 "" [Whitespace("\n")] []
+ 3: EOF@57..58 "" [Whitespace("\n")] []

MODIFY
xtask/js.ungram
xtask/js.ungram
@@ -354,9 +354,7 @@ JsYieldArgument =
JsImportCallExpression =
'import'
- '('
- argument: JsAnyExpression
- ')'
+ arguments: JsCallArguments
// new target expression
NewTarget = 'new' '.' 'target'

feat(rslint_parser): Parse 2nd param for JsImportCallExpression (#1923)