From a2c26a03de8bd8d7b2c25d4f83d4b1652adcfdb4 Mon Sep 17 00:00:00 2001 From: Carson McManus Date: Sat, 25 Oct 2025 12:17:41 -0400 Subject: [PATCH] feat(parse/html): parse svelte shorthand props and spread props --- .changeset/odd-lizards-build.md | 5 + .../src/html/any/attribute.rs | 1 + .../src/html/lists/attribute_list.rs | 3 + .../src/svelte/auxiliary/text_expression.rs | 0 crates/biome_html_parser/src/syntax/mod.rs | 9 +- .../src/syntax/parse_error.rs | 4 + .../error/interpolation-attributes.html | 1 + .../error/interpolation-attributes.html.snap | 116 ++++++++++++++++++ .../html_specs/ok/svelte/dynamic-prop.svelte | 1 + .../ok/svelte/dynamic-prop.svelte.snap | 101 +++++++++++++++ .../ok/svelte/shorthand-prop.svelte | 1 + .../ok/svelte/shorthand-prop.svelte.snap | 88 +++++++++++++ .../ok/svelte/shorthand-spread-props.svelte | 1 + .../svelte/shorthand-spread-props.svelte.snap | 88 +++++++++++++ .../biome_html_syntax/src/generated/nodes.rs | 27 +++- xtask/codegen/html.ungram | 1 + 16 files changed, 444 insertions(+), 3 deletions(-) create mode 100644 .changeset/odd-lizards-build.md delete mode 100644 crates/biome_html_formatter/src/svelte/auxiliary/text_expression.rs create mode 100644 crates/biome_html_parser/tests/html_specs/error/interpolation-attributes.html create mode 100644 crates/biome_html_parser/tests/html_specs/error/interpolation-attributes.html.snap create mode 100644 crates/biome_html_parser/tests/html_specs/ok/svelte/dynamic-prop.svelte create mode 100644 crates/biome_html_parser/tests/html_specs/ok/svelte/dynamic-prop.svelte.snap create mode 100644 crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-prop.svelte create mode 100644 crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-prop.svelte.snap create mode 100644 crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-spread-props.svelte create mode 100644 crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-spread-props.svelte.snap diff --git a/.changeset/odd-lizards-build.md b/.changeset/odd-lizards-build.md new file mode 100644 index 000000000000..e87c5a1eb9f9 --- /dev/null +++ b/.changeset/odd-lizards-build.md @@ -0,0 +1,5 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#7861](https://github.com/biomejs/biome/issues/7861): The HTML parser will now accept Svelte attribute shorthand syntax in `.svelte` files. diff --git a/crates/biome_html_formatter/src/html/any/attribute.rs b/crates/biome_html_formatter/src/html/any/attribute.rs index a52030c5a345..b1c6704f75bf 100644 --- a/crates/biome_html_formatter/src/html/any/attribute.rs +++ b/crates/biome_html_formatter/src/html/any/attribute.rs @@ -11,6 +11,7 @@ impl FormatRule for FormatAnyHtmlAttribute { AnyHtmlAttribute::HtmlAttribute(node) => node.format().fmt(f), AnyHtmlAttribute::HtmlBogusAttribute(node) => node.format().fmt(f), AnyHtmlAttribute::HtmlDoubleTextExpression(node) => node.format().fmt(f), + AnyHtmlAttribute::HtmlSingleTextExpression(node) => node.format().fmt(f), } } } diff --git a/crates/biome_html_formatter/src/html/lists/attribute_list.rs b/crates/biome_html_formatter/src/html/lists/attribute_list.rs index 098e85b40a7f..26252d23f692 100644 --- a/crates/biome_html_formatter/src/html/lists/attribute_list.rs +++ b/crates/biome_html_formatter/src/html/lists/attribute_list.rs @@ -63,6 +63,9 @@ impl FormatRule for FormatHtmlAttributeList { AnyHtmlAttribute::HtmlDoubleTextExpression(attr) => { attr.format().fmt(f) } + AnyHtmlAttribute::HtmlSingleTextExpression(attr) => { + attr.format().fmt(f) + } AnyHtmlAttribute::HtmlBogusAttribute(attr) => { attr.format().fmt(f) } diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/text_expression.rs b/crates/biome_html_formatter/src/svelte/auxiliary/text_expression.rs deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/crates/biome_html_parser/src/syntax/mod.rs b/crates/biome_html_parser/src/syntax/mod.rs index 2b3e77be002c..0a3654a82542 100644 --- a/crates/biome_html_parser/src/syntax/mod.rs +++ b/crates/biome_html_parser/src/syntax/mod.rs @@ -312,6 +312,13 @@ fn parse_attribute(p: &mut HtmlParser) -> ParsedSyntax { .ok(); Present(m.complete(p, HTML_ATTRIBUTE)) + } else if p.at(T!['{']) { + m.abandon(p); + HtmlSyntaxFeatures::SingleTextExpressions.parse_exclusive_syntax( + p, + |p| parse_single_text_expression(p, HtmlLexContext::InsideTag), + |p: &HtmlParser<'_>, m: &CompletedMarker| disabled_svelte_prop(p, m.range(p)), + ) } else { parse_literal(p, HTML_ATTRIBUTE_NAME).or_add_diagnostic(p, expected_attribute); if p.at(T![=]) { @@ -324,7 +331,7 @@ fn parse_attribute(p: &mut HtmlParser) -> ParsedSyntax { } fn is_at_attribute_start(p: &mut HtmlParser) -> bool { - p.at(HTML_LITERAL) || p.at(T!["{{"]) || p.at(T!['{']) + p.at_ts(token_set![HTML_LITERAL, T!["{{"], T!['{']]) } fn parse_literal(p: &mut HtmlParser, kind: HtmlSyntaxKind) -> ParsedSyntax { diff --git a/crates/biome_html_parser/src/syntax/parse_error.rs b/crates/biome_html_parser/src/syntax/parse_error.rs index e4865578bbde..9d855140d883 100644 --- a/crates/biome_html_parser/src/syntax/parse_error.rs +++ b/crates/biome_html_parser/src/syntax/parse_error.rs @@ -13,6 +13,10 @@ pub(crate) fn disabled_interpolation(p: &HtmlParser, range: TextRange) -> ParseD p.err_builder("Text expressions aren't supported.", range).with_hint(markup!("Remove it or enable the parsing using the ""html.parser.interpolation"" option.")) } +pub(crate) fn disabled_svelte_prop(p: &HtmlParser, range: TextRange) -> ParseDiagnostic { + p.err_builder("This looks like Svelte syntax, but this is not a Svelte file.", range).with_hint(markup!("Remove it or rename this file to have the "".svelte"" file extension.")) +} + pub(crate) fn expected_text_expression( p: &HtmlParser, curr_range: TextRange, diff --git a/crates/biome_html_parser/tests/html_specs/error/interpolation-attributes.html b/crates/biome_html_parser/tests/html_specs/error/interpolation-attributes.html new file mode 100644 index 000000000000..625c793e1a08 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/interpolation-attributes.html @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/error/interpolation-attributes.html.snap b/crates/biome_html_parser/tests/html_specs/error/interpolation-attributes.html.snap new file mode 100644 index 000000000000..503ecf4b6e79 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/interpolation-attributes.html.snap @@ -0,0 +1,116 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```html + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlBogusElement { + items: [ + HtmlBogus { + items: [ + L_ANGLE@0..1 "<" [] [], + HtmlTagName { + value_token: HTML_LITERAL@1..8 "button" [] [Whitespace(" ")], + }, + HtmlBogus { + items: [ + HtmlBogusElement { + items: [ + L_CURLY@8..9 "{" [] [], + HTML_LITERAL@9..19 "disabled}>" [] [], + ], + }, + ], + }, + ], + }, + HtmlElementList [], + HtmlClosingElement { + l_angle_token: L_ANGLE@19..20 "<" [] [], + slash_token: SLASH@20..21 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@21..27 "button" [] [], + }, + r_angle_token: R_ANGLE@27..28 ">" [] [], + }, + ], + }, + ], + eof_token: EOF@28..29 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..29 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..28 + 0: HTML_BOGUS_ELEMENT@0..28 + 0: HTML_BOGUS@0..19 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..8 + 0: HTML_LITERAL@1..8 "button" [] [Whitespace(" ")] + 2: HTML_BOGUS@8..19 + 0: HTML_BOGUS_ELEMENT@8..19 + 0: L_CURLY@8..9 "{" [] [] + 1: HTML_LITERAL@9..19 "disabled}>" [] [] + 1: HTML_ELEMENT_LIST@19..19 + 2: HTML_CLOSING_ELEMENT@19..28 + 0: L_ANGLE@19..20 "<" [] [] + 1: SLASH@20..21 "/" [] [] + 2: HTML_TAG_NAME@21..27 + 0: HTML_LITERAL@21..27 "button" [] [] + 3: R_ANGLE@27..28 ">" [] [] + 4: EOF@28..29 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +interpolation-attributes.html:1:9 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '{disabled}>'. + + > 1 │ + │ ^^^^^^^^^^^ + 2 │ + + i Expected an attribute here. + + > 1 │ + │ ^^^^^^^^^^^ + 2 │ + +interpolation-attributes.html:1:20 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + > 1 │ + │ ^ + 2 │ + + i Expected an attribute here. + + > 1 │ + │ ^ + 2 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/dynamic-prop.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/dynamic-prop.svelte new file mode 100644 index 000000000000..15613307778a --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/dynamic-prop.svelte @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/dynamic-prop.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/dynamic-prop.svelte.snap new file mode 100644 index 000000000000..af17d566f9b0 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/dynamic-prop.svelte.snap @@ -0,0 +1,101 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..8 "button" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@8..16 "disabled" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@16..17 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@17..18 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@18..23 "false" [] [], + }, + r_curly_token: R_CURLY@23..24 "}" [] [], + }, + }, + }, + ], + r_angle_token: R_ANGLE@24..25 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@25..33 "Click me" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@33..34 "<" [] [], + slash_token: SLASH@34..35 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@35..41 "button" [] [], + }, + r_angle_token: R_ANGLE@41..42 ">" [] [], + }, + }, + ], + eof_token: EOF@42..43 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..43 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..42 + 0: HTML_ELEMENT@0..42 + 0: HTML_OPENING_ELEMENT@0..25 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..8 + 0: HTML_LITERAL@1..8 "button" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@8..24 + 0: HTML_ATTRIBUTE@8..24 + 0: HTML_ATTRIBUTE_NAME@8..16 + 0: HTML_LITERAL@8..16 "disabled" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@16..24 + 0: EQ@16..17 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@17..24 + 0: L_CURLY@17..18 "{" [] [] + 1: HTML_TEXT_EXPRESSION@18..23 + 0: HTML_LITERAL@18..23 "false" [] [] + 2: R_CURLY@23..24 "}" [] [] + 3: R_ANGLE@24..25 ">" [] [] + 1: HTML_ELEMENT_LIST@25..33 + 0: HTML_CONTENT@25..33 + 0: HTML_LITERAL@25..33 "Click me" [] [] + 2: HTML_CLOSING_ELEMENT@33..42 + 0: L_ANGLE@33..34 "<" [] [] + 1: SLASH@34..35 "/" [] [] + 2: HTML_TAG_NAME@35..41 + 0: HTML_LITERAL@35..41 "button" [] [] + 3: R_ANGLE@41..42 ">" [] [] + 4: EOF@42..43 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-prop.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-prop.svelte new file mode 100644 index 000000000000..fa7b55b83d1d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-prop.svelte @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-prop.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-prop.svelte.snap new file mode 100644 index 000000000000..144579ab1b16 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-prop.svelte.snap @@ -0,0 +1,88 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..8 "button" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlSingleTextExpression { + l_curly_token: L_CURLY@8..9 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@9..17 "disabled" [] [], + }, + r_curly_token: R_CURLY@17..18 "}" [] [], + }, + ], + r_angle_token: R_ANGLE@18..19 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@19..27 "Click me" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@27..28 "<" [] [], + slash_token: SLASH@28..29 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@29..35 "button" [] [], + }, + r_angle_token: R_ANGLE@35..36 ">" [] [], + }, + }, + ], + eof_token: EOF@36..37 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..37 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..36 + 0: HTML_ELEMENT@0..36 + 0: HTML_OPENING_ELEMENT@0..19 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..8 + 0: HTML_LITERAL@1..8 "button" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@8..18 + 0: HTML_SINGLE_TEXT_EXPRESSION@8..18 + 0: L_CURLY@8..9 "{" [] [] + 1: HTML_TEXT_EXPRESSION@9..17 + 0: HTML_LITERAL@9..17 "disabled" [] [] + 2: R_CURLY@17..18 "}" [] [] + 3: R_ANGLE@18..19 ">" [] [] + 1: HTML_ELEMENT_LIST@19..27 + 0: HTML_CONTENT@19..27 + 0: HTML_LITERAL@19..27 "Click me" [] [] + 2: HTML_CLOSING_ELEMENT@27..36 + 0: L_ANGLE@27..28 "<" [] [] + 1: SLASH@28..29 "/" [] [] + 2: HTML_TAG_NAME@29..35 + 0: HTML_LITERAL@29..35 "button" [] [] + 3: R_ANGLE@35..36 ">" [] [] + 4: EOF@36..37 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-spread-props.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-spread-props.svelte new file mode 100644 index 000000000000..e8701962e828 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-spread-props.svelte @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-spread-props.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-spread-props.svelte.snap new file mode 100644 index 000000000000..385241c54392 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/shorthand-spread-props.svelte.snap @@ -0,0 +1,88 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..8 "button" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlSingleTextExpression { + l_curly_token: L_CURLY@8..9 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@9..17 "...props" [] [], + }, + r_curly_token: R_CURLY@17..18 "}" [] [], + }, + ], + r_angle_token: R_ANGLE@18..19 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@19..27 "Click me" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@27..28 "<" [] [], + slash_token: SLASH@28..29 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@29..35 "button" [] [], + }, + r_angle_token: R_ANGLE@35..36 ">" [] [], + }, + }, + ], + eof_token: EOF@36..37 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..37 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..36 + 0: HTML_ELEMENT@0..36 + 0: HTML_OPENING_ELEMENT@0..19 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..8 + 0: HTML_LITERAL@1..8 "button" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@8..18 + 0: HTML_SINGLE_TEXT_EXPRESSION@8..18 + 0: L_CURLY@8..9 "{" [] [] + 1: HTML_TEXT_EXPRESSION@9..17 + 0: HTML_LITERAL@9..17 "...props" [] [] + 2: R_CURLY@17..18 "}" [] [] + 3: R_ANGLE@18..19 ">" [] [] + 1: HTML_ELEMENT_LIST@19..27 + 0: HTML_CONTENT@19..27 + 0: HTML_LITERAL@19..27 "Click me" [] [] + 2: HTML_CLOSING_ELEMENT@27..36 + 0: L_ANGLE@27..28 "<" [] [] + 1: SLASH@28..29 "/" [] [] + 2: HTML_TAG_NAME@29..35 + 0: HTML_LITERAL@29..35 "button" [] [] + 3: R_ANGLE@35..36 ">" [] [] + 4: EOF@36..37 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_syntax/src/generated/nodes.rs b/crates/biome_html_syntax/src/generated/nodes.rs index b6cbdab84914..30f78b7ca4e1 100644 --- a/crates/biome_html_syntax/src/generated/nodes.rs +++ b/crates/biome_html_syntax/src/generated/nodes.rs @@ -873,6 +873,7 @@ pub enum AnyHtmlAttribute { HtmlAttribute(HtmlAttribute), HtmlBogusAttribute(HtmlBogusAttribute), HtmlDoubleTextExpression(HtmlDoubleTextExpression), + HtmlSingleTextExpression(HtmlSingleTextExpression), } impl AnyHtmlAttribute { pub fn as_html_attribute(&self) -> Option<&HtmlAttribute> { @@ -893,6 +894,12 @@ impl AnyHtmlAttribute { _ => None, } } + pub fn as_html_single_text_expression(&self) -> Option<&HtmlSingleTextExpression> { + match &self { + Self::HtmlSingleTextExpression(item) => Some(item), + _ => None, + } + } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyHtmlAttributeInitializer { @@ -2121,15 +2128,24 @@ impl From for AnyHtmlAttribute { Self::HtmlDoubleTextExpression(node) } } +impl From for AnyHtmlAttribute { + fn from(node: HtmlSingleTextExpression) -> Self { + Self::HtmlSingleTextExpression(node) + } +} impl AstNode for AnyHtmlAttribute { type Language = Language; const KIND_SET: SyntaxKindSet = HtmlAttribute::KIND_SET .union(HtmlBogusAttribute::KIND_SET) - .union(HtmlDoubleTextExpression::KIND_SET); + .union(HtmlDoubleTextExpression::KIND_SET) + .union(HtmlSingleTextExpression::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - HTML_ATTRIBUTE | HTML_BOGUS_ATTRIBUTE | HTML_DOUBLE_TEXT_EXPRESSION + HTML_ATTRIBUTE + | HTML_BOGUS_ATTRIBUTE + | HTML_DOUBLE_TEXT_EXPRESSION + | HTML_SINGLE_TEXT_EXPRESSION ) } fn cast(syntax: SyntaxNode) -> Option { @@ -2139,6 +2155,9 @@ impl AstNode for AnyHtmlAttribute { HTML_DOUBLE_TEXT_EXPRESSION => { Self::HtmlDoubleTextExpression(HtmlDoubleTextExpression { syntax }) } + HTML_SINGLE_TEXT_EXPRESSION => { + Self::HtmlSingleTextExpression(HtmlSingleTextExpression { syntax }) + } _ => return None, }; Some(res) @@ -2148,6 +2167,7 @@ impl AstNode for AnyHtmlAttribute { Self::HtmlAttribute(it) => &it.syntax, Self::HtmlBogusAttribute(it) => &it.syntax, Self::HtmlDoubleTextExpression(it) => &it.syntax, + Self::HtmlSingleTextExpression(it) => &it.syntax, } } fn into_syntax(self) -> SyntaxNode { @@ -2155,6 +2175,7 @@ impl AstNode for AnyHtmlAttribute { Self::HtmlAttribute(it) => it.syntax, Self::HtmlBogusAttribute(it) => it.syntax, Self::HtmlDoubleTextExpression(it) => it.syntax, + Self::HtmlSingleTextExpression(it) => it.syntax, } } } @@ -2164,6 +2185,7 @@ impl std::fmt::Debug for AnyHtmlAttribute { Self::HtmlAttribute(it) => std::fmt::Debug::fmt(it, f), Self::HtmlBogusAttribute(it) => std::fmt::Debug::fmt(it, f), Self::HtmlDoubleTextExpression(it) => std::fmt::Debug::fmt(it, f), + Self::HtmlSingleTextExpression(it) => std::fmt::Debug::fmt(it, f), } } } @@ -2173,6 +2195,7 @@ impl From for SyntaxNode { AnyHtmlAttribute::HtmlAttribute(it) => it.into(), AnyHtmlAttribute::HtmlBogusAttribute(it) => it.into(), AnyHtmlAttribute::HtmlDoubleTextExpression(it) => it.into(), + AnyHtmlAttribute::HtmlSingleTextExpression(it) => it.into(), } } } diff --git a/xtask/codegen/html.ungram b/xtask/codegen/html.ungram index f8c0045d656e..1dfa7733bd2a 100644 --- a/xtask/codegen/html.ungram +++ b/xtask/codegen/html.ungram @@ -159,6 +159,7 @@ HtmlAttributeList = AnyHtmlAttribute* AnyHtmlAttribute = HtmlAttribute | HtmlDoubleTextExpression + | HtmlSingleTextExpression | HtmlBogusAttribute //