fix(rome_js_parser): call expression in optional member chain followed by `<`
MODIFY
crates/rome_js_parser/src/syntax/expr.rs
crates/rome_js_parser/src/syntax/expr.rs
@@ -1720,10 +1720,8 @@ fn parse_call_expression_rest(
parse_call_arguments(p)
.or_add_diagnostic(p, |p, _| expected_token(T!['(']).to_diagnostic(p));
lhs = m.complete(p, JS_CALL_EXPRESSION);
- continue;
- }
-
- if in_optional_chain {
+ } else {
+ break if optional_chain_call {
// If the `?.` is present and what followed was neither a valid type arguments nor valid arguments.
// In this case, parse this as a static member access with an optional chain
@@ -1732,8 +1730,12 @@ fn parse_call_expression_rest(
// a.test?.;
// a.test?.<ab;
p.error(expected_identifier(p, p.cur_range()));
- lhs = m.complete(p, JS_STATIC_MEMBER_EXPRESSION);
+ m.complete(p, JS_STATIC_MEMBER_EXPRESSION)
} else {
+ // test ts optional_chain_call_less_than
+ // String(item)?.b < 0;
+ // String(item)?.b <aBcd;
+
// Safety:
// * The method initially checks if the parsers at a '<', '(', or '?.' token.
// * if the parser is at '?.': It takes the branch right above, ensuring that no token was consumed
@@ -1741,9 +1743,9 @@ fn parse_call_expression_rest(
// * if the parser is at '(': This always parses out as valid arguments.
debug_assert_eq!(p.tokens.position(), start_pos);
m.abandon(p);
+ lhs
+ };
}
-
- break lhs;
}
}

ADD
crates/rome_js_parser/test_data/inline/ok/optional_chain_call_less_than.rast
+JsModule {
+ interpreter_token: missing (optional),
+ directives: JsDirectiveList [],
+ items: JsModuleItemList [
+ JsExpressionStatement {
+ expression: JsBinaryExpression {
+ left: JsStaticMemberExpression {
+ object: JsCallExpression {
+ callee: JsIdentifierExpression {
+ name: JsReferenceIdentifier {
+ value_token: IDENT@0..6 "String" [] [],
+ },
+ },
+ optional_chain_token: missing (optional),
+ type_arguments: missing (optional),
+ arguments: JsCallArguments {
+ l_paren_token: L_PAREN@6..7 "(" [] [],
+ args: JsCallArgumentList [
+ JsIdentifierExpression {
+ name: JsReferenceIdentifier {
+ value_token: IDENT@7..11 "item" [] [],
+ },
+ },
+ ],
+ r_paren_token: R_PAREN@11..12 ")" [] [],
+ },
+ },
+ operator_token: QUESTIONDOT@12..14 "?." [] [],
+ member: JsName {
+ value_token: IDENT@14..16 "b" [] [Whitespace(" ")],
+ },
+ },
+ operator_token: L_ANGLE@16..18 "<" [] [Whitespace(" ")],
+ right: JsNumberLiteralExpression {
+ value_token: JS_NUMBER_LITERAL@18..19 "0" [] [],
+ },
+ },
+ semicolon_token: SEMICOLON@19..20 ";" [] [],
+ },
+ JsExpressionStatement {
+ expression: JsBinaryExpression {
+ left: JsStaticMemberExpression {
+ object: JsCallExpression {
+ callee: JsIdentifierExpression {
+ name: JsReferenceIdentifier {
+ value_token: IDENT@20..27 "String" [Newline("\n")] [],
+ },
+ },
+ optional_chain_token: missing (optional),
+ type_arguments: missing (optional),
+ arguments: JsCallArguments {
+ l_paren_token: L_PAREN@27..28 "(" [] [],
+ args: JsCallArgumentList [
+ JsIdentifierExpression {
+ name: JsReferenceIdentifier {
+ value_token: IDENT@28..32 "item" [] [],
+ },
+ },
+ ],
+ r_paren_token: R_PAREN@32..33 ")" [] [],
+ },
+ },
+ operator_token: QUESTIONDOT@33..35 "?." [] [],
+ member: JsName {
+ value_token: IDENT@35..37 "b" [] [Whitespace(" ")],
+ },
+ },
+ operator_token: L_ANGLE@37..38 "<" [] [],
+ right: JsIdentifierExpression {
+ name: JsReferenceIdentifier {
+ value_token: IDENT@38..42 "aBcd" [] [],
+ },
+ },
+ },
+ semicolon_token: SEMICOLON@42..43 ";" [] [],
+ },
+ ],
+ eof_token: EOF@43..44 "" [Newline("\n")] [],
+}
+
+0: JS_MODULE@0..44
+ 0: (empty)
+ 1: JS_DIRECTIVE_LIST@0..0
+ 2: JS_MODULE_ITEM_LIST@0..43
+ 0: JS_EXPRESSION_STATEMENT@0..20
+ 0: JS_BINARY_EXPRESSION@0..19
+ 0: JS_STATIC_MEMBER_EXPRESSION@0..16
+ 0: JS_CALL_EXPRESSION@0..12
+ 0: JS_IDENTIFIER_EXPRESSION@0..6
+ 0: JS_REFERENCE_IDENTIFIER@0..6
+ 0: IDENT@0..6 "String" [] []
+ 1: (empty)
+ 2: (empty)
+ 3: JS_CALL_ARGUMENTS@6..12
+ 0: L_PAREN@6..7 "(" [] []
+ 1: JS_CALL_ARGUMENT_LIST@7..11
+ 0: JS_IDENTIFIER_EXPRESSION@7..11
+ 0: JS_REFERENCE_IDENTIFIER@7..11
+ 0: IDENT@7..11 "item" [] []
+ 2: R_PAREN@11..12 ")" [] []
+ 1: QUESTIONDOT@12..14 "?." [] []
+ 2: JS_NAME@14..16
+ 0: IDENT@14..16 "b" [] [Whitespace(" ")]
+ 1: L_ANGLE@16..18 "<" [] [Whitespace(" ")]
+ 2: JS_NUMBER_LITERAL_EXPRESSION@18..19
+ 0: JS_NUMBER_LITERAL@18..19 "0" [] []
+ 1: SEMICOLON@19..20 ";" [] []
+ 1: JS_EXPRESSION_STATEMENT@20..43
+ 0: JS_BINARY_EXPRESSION@20..42
+ 0: JS_STATIC_MEMBER_EXPRESSION@20..37
+ 0: JS_CALL_EXPRESSION@20..33
+ 0: JS_IDENTIFIER_EXPRESSION@20..27
+ 0: JS_REFERENCE_IDENTIFIER@20..27
+ 0: IDENT@20..27 "String" [Newline("\n")] []
+ 1: (empty)
+ 2: (empty)
+ 3: JS_CALL_ARGUMENTS@27..33
+ 0: L_PAREN@27..28 "(" [] []
+ 1: JS_CALL_ARGUMENT_LIST@28..32
+ 0: JS_IDENTIFIER_EXPRESSION@28..32
+ 0: JS_REFERENCE_IDENTIFIER@28..32
+ 0: IDENT@28..32 "item" [] []
+ 2: R_PAREN@32..33 ")" [] []
+ 1: QUESTIONDOT@33..35 "?." [] []
+ 2: JS_NAME@35..37
+ 0: IDENT@35..37 "b" [] [Whitespace(" ")]
+ 1: L_ANGLE@37..38 "<" [] []
+ 2: JS_IDENTIFIER_EXPRESSION@38..42
+ 0: JS_REFERENCE_IDENTIFIER@38..42
+ 0: IDENT@38..42 "aBcd" [] []
+ 1: SEMICOLON@42..43 ";" [] []
+ 3: EOF@43..44 "" [Newline("\n")] []

ADD
crates/rome_js_parser/test_data/inline/ok/optional_chain_call_less_than.ts
+String(item)?.b < 0;
+String(item)?.b <aBcd;

fix(rome_js_parser): call expression in optional member chain followed by `<` (#3487)