Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(js_parser): desambigaute JSX and const type param of arrow function #845

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -63,6 +63,10 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom

### Parser

#### Bug fixes

- Fix [#846](https://github.com/biomejs/biome/issues/846) that erroneously parsed `<const T,>() => {}` as a JSX tag instead of an arrow function when both TypeScript and JSX are enabled.

### VSCode

## 1.3.3 (2023-10-31)
37 changes: 23 additions & 14 deletions crates/biome_js_parser/src/syntax/function.rs
Original file line number Diff line number Diff line change
@@ -754,34 +754,37 @@ fn is_parenthesized_arrow_function_expression_impl(
}
// potential start of type parameters
T![<] => {
if is_nth_at_type_parameter_modifier(p, n + 1) && !JsSyntaxFeature::Jsx.is_supported(p)
{
// <const T>...
IsParenthesizedArrowFunctionExpression::True
} else if !is_nth_at_identifier(p, n + 1) {
// <5...
IsParenthesizedArrowFunctionExpression::False
}
// test jsx jsx_type_arguments
// // These may look like a valid arrows but are JSX
// <A extends>() =</A>;
// <A extends="B">() =</A>;
// <A extends ok>() =</A>;
// <const A>() =</const>;
// <const A extends/>;
// <A extends/>;

// test tsx tsx_type_arguments
// // These are valid type arguments
// <A,>() => {};
// <const A,>() => {};
// <A extends B>() => {};
// <A=string>() => {};
// <A, B>() => {};
// <A extends B<C>>() => {}

// <a... JSX override
else if JsSyntaxFeature::Jsx.is_supported(p) {
// <A extends B<C>>() => {};

if JsSyntaxFeature::Jsx.is_supported(p) {
// Disambiguate between JSX and type parameters
// Type parameters of arrow functions accept only the `const` modifier.
let n = if p.nth_at(n + 1, T![const]) { n + 1 } else { n };
if !is_nth_at_identifier(p, n + 1) {
// <5...
return IsParenthesizedArrowFunctionExpression::False;
};
match p.nth(n + 2) {
T![extends] => {
// `<a extends=` OR `<a extends>` is a JSX start element
// `<a extends=` OR `<a extends/>` OR `<a extends>` is a JSX element
// and a `extends` type refinement: `<A extends string>`
if matches!(p.nth(n + 3), T![=] | T![>]) {
if matches!(p.nth(n + 3), T![=] | T![/] | T![>]) {
IsParenthesizedArrowFunctionExpression::False
}
// `<A extends B>` Could be either
@@ -796,6 +799,12 @@ fn is_parenthesized_arrow_function_expression_impl(
T![=] | T![,] => IsParenthesizedArrowFunctionExpression::True,
_ => IsParenthesizedArrowFunctionExpression::False,
}
} else if is_nth_at_type_parameter_modifier(p, n + 1) {
// <const T>...
IsParenthesizedArrowFunctionExpression::True
} else if !is_nth_at_identifier(p, n + 1) {
// <5...
IsParenthesizedArrowFunctionExpression::False
} else {
// <a...
IsParenthesizedArrowFunctionExpression::Unknown
Original file line number Diff line number Diff line change
@@ -2,3 +2,6 @@
<A extends>() =</A>;
<A extends="B">() =</A>;
<A extends ok>() =</A>;
<const A>() =</const>;
<const A extends/>;
<A extends/>;
152 changes: 148 additions & 4 deletions crates/biome_js_parser/test_data/inline/ok/jsx_type_arguments.rast
Original file line number Diff line number Diff line change
@@ -122,15 +122,101 @@ JsModule {
},
semicolon_token: [email protected] ";" [] [],
},
JsExpressionStatement {
expression: JsxTagExpression {
tag: JsxElement {
opening_element: JsxOpeningElement {
l_angle_token: [email protected] "<" [Newline("\n")] [],
name: JsxName {
value_token: [email protected] "const" [] [Whitespace(" ")],
},
type_arguments: missing (optional),
attributes: JsxAttributeList [
JsxAttribute {
name: JsxName {
value_token: [email protected] "A" [] [],
},
initializer: missing (optional),
},
],
r_angle_token: [email protected] ">" [] [],
},
children: JsxChildList [
JsxText {
value_token: [email protected] "() =" [] [],
},
],
closing_element: JsxClosingElement {
l_angle_token: [email protected] "<" [] [],
slash_token: [email protected] "/" [] [],
name: JsxName {
value_token: [email protected] "const" [] [],
},
r_angle_token: [email protected] ">" [] [],
},
},
},
semicolon_token: [email protected] ";" [] [],
},
JsExpressionStatement {
expression: JsxTagExpression {
tag: JsxSelfClosingElement {
l_angle_token: [email protected] "<" [Newline("\n")] [],
name: JsxName {
value_token: [email protected] "const" [] [Whitespace(" ")],
},
type_arguments: missing (optional),
attributes: JsxAttributeList [
JsxAttribute {
name: JsxName {
value_token: [email protected] "A" [] [Whitespace(" ")],
},
initializer: missing (optional),
},
JsxAttribute {
name: JsxName {
value_token: [email protected] "extends" [] [],
},
initializer: missing (optional),
},
],
slash_token: [email protected] "/" [] [],
r_angle_token: [email protected] ">" [] [],
},
},
semicolon_token: [email protected] ";" [] [],
},
JsExpressionStatement {
expression: JsxTagExpression {
tag: JsxSelfClosingElement {
l_angle_token: [email protected] "<" [Newline("\n")] [],
name: JsxReferenceIdentifier {
value_token: [email protected] "A" [] [Whitespace(" ")],
},
type_arguments: missing (optional),
attributes: JsxAttributeList [
JsxAttribute {
name: JsxName {
value_token: [email protected] "extends" [] [],
},
initializer: missing (optional),
},
],
slash_token: [email protected] "/" [] [],
r_angle_token: [email protected] ">" [] [],
},
},
semicolon_token: [email protected] ";" [] [],
},
],
eof_token: EOF@119..120 "" [Newline("\n")] [],
eof_token: EOF@176..177 "" [Newline("\n")] [],
}

0: JS_MODULE@0..120
0: JS_MODULE@0..177
0: (empty)
1: (empty)
2: [email protected]
3: JS_MODULE_ITEM_LIST@0..119
3: JS_MODULE_ITEM_LIST@0..176
0: [email protected]
0: [email protected]
0: [email protected]
@@ -210,4 +296,62 @@ JsModule {
0: [email protected] "A" [] []
3: [email protected] ">" [] []
1: [email protected] ";" [] []
4: [email protected] "" [Newline("\n")] []
3: [email protected]
0: [email protected]
0: [email protected]
0: [email protected]
0: [email protected] "<" [Newline("\n")] []
1: [email protected]
0: [email protected] "const" [] [Whitespace(" ")]
2: (empty)
3: [email protected]
0: [email protected]
0: [email protected]
0: [email protected] "A" [] []
1: (empty)
4: [email protected] ">" [] []
1: [email protected]
0: [email protected]
0: [email protected] "() =" [] []
2: [email protected]
0: [email protected] "<" [] []
1: [email protected] "/" [] []
2: [email protected]
0: [email protected] "const" [] []
3: [email protected] ">" [] []
1: [email protected] ";" [] []
4: [email protected]
0: [email protected]
0: [email protected]
0: [email protected] "<" [Newline("\n")] []
1: [email protected]
0: [email protected] "const" [] [Whitespace(" ")]
2: (empty)
3: [email protected]
0: [email protected]
0: [email protected]
0: [email protected] "A" [] [Whitespace(" ")]
1: (empty)
1: [email protected]
0: [email protected]
0: [email protected] "extends" [] []
1: (empty)
4: [email protected] "/" [] []
5: [email protected] ">" [] []
1: [email protected] ";" [] []
5: [email protected]
0: [email protected]
0: [email protected]
0: [email protected] "<" [Newline("\n")] []
1: [email protected]
0: [email protected] "A" [] [Whitespace(" ")]
2: (empty)
3: [email protected]
0: [email protected]
0: [email protected]
0: [email protected] "extends" [] []
1: (empty)
4: [email protected] "/" [] []
5: [email protected] ">" [] []
1: [email protected] ";" [] []
4: [email protected] "" [Newline("\n")] []
442 changes: 284 additions & 158 deletions crates/biome_js_parser/test_data/inline/ok/tsx_type_arguments.rast

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// These are valid type arguments
<A,>() => {};
<const A,>() => {};
<A extends B>() => {};
<A=string>() => {};
<A, B>() => {};
<A extends B<C>>() => {}
<A extends B<C>>() => {};
4 changes: 4 additions & 0 deletions website/src/content/docs/internals/changelog.mdx
Original file line number Diff line number Diff line change
@@ -69,6 +69,10 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom

### Parser

#### Bug fixes

- Fix [#846](https://github.com/biomejs/biome/issues/846) that erroneously parsed `<const T,>() => {}` as a JSX tag instead of an arrow function when both TypeScript and JSX are enabled.

### VSCode

## 1.3.3 (2023-10-31)