Skip to content

Commit

Permalink
feat(fe): parse JSX in attribute without {}: <E a=<B></B> />
Browse files Browse the repository at this point in the history
  • Loading branch information
strager committed Dec 29, 2023
1 parent 0775622 commit 253983c
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ Semantic Versioning.
Masani][].)
* Detection of multiple `export default` statements ([E0715][]) now also applies
to `export {... as default};` statements.
* JSX elements and fragments are now allowed in JSX attributes without
surrounding them in `{` and `}` (e.g.
`<List header=<ListHeader />>{items}</List>`).
* TypeScript support (still experimental):
* `export as namespace` statements are now parsed.
* Const generic parameters (`<const T>`) are now parsed.
Expand Down
5 changes: 5 additions & 0 deletions src/quick-lint-js/fe/parse-expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3861,6 +3861,11 @@ Expression* Parser::parse_jsx_element_or_fragment(Parse_Visitor_Base& v,
break;
}

// <current attribute=<Element />>
case Token_Type::less:
children.emplace_back(this->parse_jsx_element_or_fragment(v));
break;

default:
QLJS_PARSER_UNIMPLEMENTED();
break;
Expand Down
27 changes: 27 additions & 0 deletions test/test-parse-expression-jsx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,24 @@ TEST_F(Test_Parse_Expression_JSX, tag_with_attributes) {
ASSERT_EQ(summarize(ast), "jsxelement(input)");
}

{
Test_Parser p(u8"<div attr=<span /> />"_sv, jsx_options);
Expression* ast = p.parse_expression();
ASSERT_EQ(summarize(ast), "jsxelement(div, jsxelement(span))");
}

{
Test_Parser p(u8"<div attr=<span>{child}</span> />"_sv, jsx_options);
Expression* ast = p.parse_expression();
ASSERT_EQ(summarize(ast), "jsxelement(div, jsxelement(span, var child))");
}

{
Test_Parser p(u8"<div attr=<>{child}</> />"_sv, jsx_options);
Expression* ast = p.parse_expression();
ASSERT_EQ(summarize(ast), "jsxelement(div, jsxfragment(var child))");
}

{
Test_Parser p(u8"<input {...attributes} />"_sv, jsx_options);
Expression* ast = p.parse_expression();
Expand Down Expand Up @@ -401,6 +419,15 @@ TEST_F(Test_Parse_Expression_JSX,
EXPECT_EQ(summarize(ast), "jsxelement(const)");
}
}

TEST_F(Test_Parse_Expression_JSX, greater_greater_token_is_split) {
{
Test_Parser p(u8"<A attr=<B />> </A>"_sv, jsx_options);
// ^^ Token should be split into two '>'s.
Expression* ast = p.parse_expression();
ASSERT_EQ(summarize(ast), "jsxelement(A, jsxelement(B))");
}
}
}
}

Expand Down

0 comments on commit 253983c

Please sign in to comment.