diff --git a/.changeset/glimmer-template-support.md b/.changeset/glimmer-template-support.md new file mode 100644 index 000000000000..d8a8d8214bfc --- /dev/null +++ b/.changeset/glimmer-template-support.md @@ -0,0 +1,20 @@ +--- +"@biomejs/biome": minor +--- + +Added support for Glimmer template files (`.gjs` and `.gts`). Biome can now parse, format, and lint Glimmer Component files used in Ember.js applications. + +Glimmer templates are recognized using the `` syntax and can appear in: +- Variable assignments: `const Tpl = ;` +- Class bodies: `class C { }` +- Expression contexts +- Single unassigned templates (treated as default exports) + +**Phase 1 Implementation Notes:** +- Template content is treated as **opaque tokens** - the content is preserved exactly as written without internal parsing or linting +- The template syntax itself is validated (e.g., checking for unclosed tags) +- Templates work with whitespace in the opening tag (e.g., ` + │ ^ + 5 │ + + i Expected an element name here. + + 2 │ {{#if condition}} + 3 │
Content
+ > 4 │ + │ ^ + 5 │ + +missing_block_closing.gjs:4:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `>` but instead found `template` + + 2 │ {{#if condition}} + 3 │
Content
+ > 4 │ + │ ^^^^^^^^ + 5 │ + + i Remove template + +missing_block_closing.gjs:5:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected closing tag for block helper + + 3 │
Content
+ 4 │ + > 5 │ + │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/glimmer/missing_triple_closing.html b/crates/biome_html_parser/tests/html_specs/error/glimmer/missing_triple_closing.html new file mode 100644 index 000000000000..b02f2b09e8c8 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/glimmer/missing_triple_closing.html @@ -0,0 +1,9 @@ +
+ {{{unsafe content + Next element +
+ +
+ {{{unsafe content}}} + Valid +
diff --git a/crates/biome_html_parser/tests/html_specs/error/glimmer/missing_triple_closing.html.snap b/crates/biome_html_parser/tests/html_specs/error/glimmer/missing_triple_closing.html.snap new file mode 100644 index 000000000000..95945c963d83 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/glimmer/missing_triple_closing.html.snap @@ -0,0 +1,289 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```html +
+ {{{unsafe content + Next element +
+ +
+ {{{unsafe content}}} + Valid +
+ +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlBogusElement { + items: [ + HtmlOpeningElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..4 "div" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@4..5 ">" [] [], + }, + HtmlElementList [ + HtmlBogusElement { + items: [ + L_TRIPLE_CURLY@5..11 "{{{" [Newline("\n"), Whitespace(" ")] [], + GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@11..18 "unsafe" [] [Whitespace(" ")], + }, + ], + }, + GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@18..25 "content" [] [], + }, + ], + }, + }, + ], + ERROR_TOKEN@25..29 "<" [Newline("\n"), Whitespace(" ")] [], + HTML_LITERAL@29..46 "span>Next element" [] [], + ], + }, + ], + HtmlBogusElement { + items: [ + L_ANGLE@46..47 "<" [] [], + SLASH@47..48 "/" [] [], + HtmlTagName { + value_token: HTML_LITERAL@48..52 "span" [] [], + }, + R_ANGLE@52..53 ">" [] [], + ], + }, + HtmlElementList [], + HtmlClosingElement { + l_angle_token: L_ANGLE@53..55 "<" [Newline("\n")] [], + slash_token: SLASH@55..56 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@56..59 "div" [] [], + }, + r_angle_token: R_ANGLE@59..60 ">" [] [], + }, + ], + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@60..63 "<" [Newline("\n"), Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@63..66 "div" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@66..67 ">" [] [], + }, + children: HtmlElementList [ + GlimmerTripleStashExpression { + l_curly3_token_token: L_TRIPLE_CURLY@67..73 "{{{" [Newline("\n"), Whitespace(" ")] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@73..80 "unsafe" [] [Whitespace(" ")], + }, + ], + }, + arguments: GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@80..87 "content" [] [], + }, + ], + }, + }, + ], + r_curly3_token_token: R_TRIPLE_CURLY@87..90 "}}}" [] [], + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@90..94 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@94..98 "span" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@98..99 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@99..104 "Valid" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@104..105 "<" [] [], + slash_token: SLASH@105..106 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@106..110 "span" [] [], + }, + r_angle_token: R_ANGLE@110..111 ">" [] [], + }, + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@111..113 "<" [Newline("\n")] [], + slash_token: SLASH@113..114 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@114..117 "div" [] [], + }, + r_angle_token: R_ANGLE@117..118 ">" [] [], + }, + }, + ], + eof_token: EOF@118..119 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..119 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..118 + 0: HTML_BOGUS_ELEMENT@0..60 + 0: HTML_OPENING_ELEMENT@0..5 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..4 + 0: HTML_LITERAL@1..4 "div" [] [] + 2: HTML_ATTRIBUTE_LIST@4..4 + 3: R_ANGLE@4..5 ">" [] [] + 1: HTML_ELEMENT_LIST@5..46 + 0: HTML_BOGUS_ELEMENT@5..46 + 0: L_TRIPLE_CURLY@5..11 "{{{" [Newline("\n"), Whitespace(" ")] [] + 1: GLIMMER_PATH@11..18 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@11..18 + 0: GLIMMER_PATH_SEGMENT@11..18 + 0: IDENT@11..18 "unsafe" [] [Whitespace(" ")] + 2: GLIMMER_ARGUMENT_LIST@18..25 + 0: GLIMMER_POSITIONAL_ARGUMENT@18..25 + 0: GLIMMER_PATH@18..25 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@18..25 + 0: GLIMMER_PATH_SEGMENT@18..25 + 0: IDENT@18..25 "content" [] [] + 3: ERROR_TOKEN@25..29 "<" [Newline("\n"), Whitespace(" ")] [] + 4: HTML_LITERAL@29..46 "span>Next element" [] [] + 2: HTML_BOGUS_ELEMENT@46..53 + 0: L_ANGLE@46..47 "<" [] [] + 1: SLASH@47..48 "/" [] [] + 2: HTML_TAG_NAME@48..52 + 0: HTML_LITERAL@48..52 "span" [] [] + 3: R_ANGLE@52..53 ">" [] [] + 3: HTML_ELEMENT_LIST@53..53 + 4: HTML_CLOSING_ELEMENT@53..60 + 0: L_ANGLE@53..55 "<" [Newline("\n")] [] + 1: SLASH@55..56 "/" [] [] + 2: HTML_TAG_NAME@56..59 + 0: HTML_LITERAL@56..59 "div" [] [] + 3: R_ANGLE@59..60 ">" [] [] + 1: HTML_ELEMENT@60..118 + 0: HTML_OPENING_ELEMENT@60..67 + 0: L_ANGLE@60..63 "<" [Newline("\n"), Newline("\n")] [] + 1: HTML_TAG_NAME@63..66 + 0: HTML_LITERAL@63..66 "div" [] [] + 2: HTML_ATTRIBUTE_LIST@66..66 + 3: R_ANGLE@66..67 ">" [] [] + 1: HTML_ELEMENT_LIST@67..111 + 0: GLIMMER_TRIPLE_STASH_EXPRESSION@67..90 + 0: L_TRIPLE_CURLY@67..73 "{{{" [Newline("\n"), Whitespace(" ")] [] + 1: GLIMMER_PATH@73..80 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@73..80 + 0: GLIMMER_PATH_SEGMENT@73..80 + 0: IDENT@73..80 "unsafe" [] [Whitespace(" ")] + 2: GLIMMER_ARGUMENT_LIST@80..87 + 0: GLIMMER_POSITIONAL_ARGUMENT@80..87 + 0: GLIMMER_PATH@80..87 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@80..87 + 0: GLIMMER_PATH_SEGMENT@80..87 + 0: IDENT@80..87 "content" [] [] + 3: R_TRIPLE_CURLY@87..90 "}}}" [] [] + 1: HTML_ELEMENT@90..111 + 0: HTML_OPENING_ELEMENT@90..99 + 0: L_ANGLE@90..94 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@94..98 + 0: HTML_LITERAL@94..98 "span" [] [] + 2: HTML_ATTRIBUTE_LIST@98..98 + 3: R_ANGLE@98..99 ">" [] [] + 1: HTML_ELEMENT_LIST@99..104 + 0: HTML_CONTENT@99..104 + 0: HTML_LITERAL@99..104 "Valid" [] [] + 2: HTML_CLOSING_ELEMENT@104..111 + 0: L_ANGLE@104..105 "<" [] [] + 1: SLASH@105..106 "/" [] [] + 2: HTML_TAG_NAME@106..110 + 0: HTML_LITERAL@106..110 "span" [] [] + 3: R_ANGLE@110..111 ">" [] [] + 2: HTML_CLOSING_ELEMENT@111..118 + 0: L_ANGLE@111..113 "<" [Newline("\n")] [] + 1: SLASH@113..114 "/" [] [] + 2: HTML_TAG_NAME@114..117 + 0: HTML_LITERAL@114..117 "div" [] [] + 3: R_ANGLE@117..118 ">" [] [] + 4: EOF@118..119 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +missing_triple_closing.html:3:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected character `<` + + 1 │
+ 2 │ {{{unsafe content + > 3 │ Next element + │ ^ + 4 │
+ 5 │ + +missing_triple_closing.html:3:21 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a matching closing tag but instead found ''. + + 1 │
+ 2 │ {{{unsafe content + > 3 │ Next element + │ ^^^^^^^ + 4 │
+ 5 │ + + i Expected a matching closing tag here. + + 1 │
+ 2 │ {{{unsafe content + > 3 │ Next element + │ ^^^^^^^ + 4 │
+ 5 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/glimmer/unterminated_comment.html b/crates/biome_html_parser/tests/html_specs/error/glimmer/unterminated_comment.html new file mode 100644 index 000000000000..1975786fc58e --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/glimmer/unterminated_comment.html @@ -0,0 +1,9 @@ +
+ {{! This comment is not closed + Content +
+ +
+ {{!-- This block comment is not closed + Content +
diff --git a/crates/biome_html_parser/tests/html_specs/error/glimmer/unterminated_comment.html.snap b/crates/biome_html_parser/tests/html_specs/error/glimmer/unterminated_comment.html.snap new file mode 100644 index 000000000000..f899155dd00d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/glimmer/unterminated_comment.html.snap @@ -0,0 +1,109 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```html +
+ {{! This comment is not closed + Content +
+ +
+ {{!-- This block comment is not closed + Content +
+ +``` + + +## 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..4 "div" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@4..5 ">" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheComment { + comment_token_token: MUSTACHE_COMMENT@5..147 "{{! This comment is not closed\n Content\n\n\n
\n {{!-- This block comment is not closed\n Content\n
\n" [Newline("\n"), Whitespace(" ")] [], + }, + ], + closing_element: missing (required), + }, + ], + eof_token: EOF@147..147 "" [] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..147 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..147 + 0: HTML_ELEMENT@0..147 + 0: HTML_OPENING_ELEMENT@0..5 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..4 + 0: HTML_LITERAL@1..4 "div" [] [] + 2: HTML_ATTRIBUTE_LIST@4..4 + 3: R_ANGLE@4..5 ">" [] [] + 1: HTML_ELEMENT_LIST@5..147 + 0: GLIMMER_MUSTACHE_COMMENT@5..147 + 0: MUSTACHE_COMMENT@5..147 "{{! This comment is not closed\n Content\n\n\n
\n {{!-- This block comment is not closed\n Content\n
\n" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 4: EOF@147..147 "" [] [] + +``` + +## Diagnostics + +``` +unterminated_comment.html:2:3 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unterminated mustache comment, expected closing '}}' + + 1 │
+ > 2 │ {{! This comment is not closed + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + > 3 │ Content + > 4 │
+ > 5 │ + > 6 │
+ > 7 │ {{!-- This block comment is not closed + > 8 │ Content + > 9 │
+ > 10 │ + │ + +unterminated_comment.html:10:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a closing tag but instead found the end of the file. + + 8 │ Content + 9 │ + > 10 │ + │ + + i Expected a closing tag here. + + 8 │ Content + 9 │ + > 10 │ + │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_helper.gjs b/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_helper.gjs new file mode 100644 index 000000000000..5e09616573c5 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_helper.gjs @@ -0,0 +1,11 @@ +{{#if showTitle}} +

{{title}}

+{{/if}} + +{{#each items as |item index|}} +
  • {{item.name}}
  • +{{/each}} + +{{#with user as |u|}} +

    {{u.name}}

    +{{/with}} diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_helper.gjs.snap b/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_helper.gjs.snap new file mode 100644 index 000000000000..bdd38a8750c2 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_helper.gjs.snap @@ -0,0 +1,476 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```glimmer +{{#if showTitle}} +

    {{title}}

    +{{/if}} + +{{#each items as |item index|}} +
  • {{item.name}}
  • +{{/each}} + +{{#with user as |u|}} +

    {{u.name}}

    +{{/with}} + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + GlimmerBlockHelper { + opening: GlimmerBlockHelperOpening { + l_curly2_token_token: L_DOUBLE_CURLY@0..2 "{{" [] [], + hash_token_token: HASH@2..3 "#" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@3..6 "if" [] [Whitespace(" ")], + }, + ], + }, + arguments: GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@6..15 "showTitle" [] [], + }, + ], + }, + }, + ], + block_params: missing (optional), + r_curly2_token_token: R_DOUBLE_CURLY@15..17 "}}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@17..21 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@21..23 "h1" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@23..24 ">" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@24..26 "{{" [] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@26..31 "title" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly2_token_token: R_DOUBLE_CURLY@31..33 "}}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@33..34 "<" [] [], + slash_token: SLASH@34..35 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@35..37 "h1" [] [], + }, + r_angle_token: R_ANGLE@37..38 ">" [] [], + }, + }, + ], + closing: GlimmerBlockHelperClosing { + l_curly2_token_token: L_DOUBLE_CURLY@38..41 "{{" [Newline("\n")] [], + slash_token_token: SLASH@41..42 "/" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@42..44 "if" [] [], + }, + ], + }, + r_curly2_token_token: R_DOUBLE_CURLY@44..46 "}}" [] [], + }, + }, + GlimmerBlockHelper { + opening: GlimmerBlockHelperOpening { + l_curly2_token_token: L_DOUBLE_CURLY@46..50 "{{" [Newline("\n"), Newline("\n")] [], + hash_token_token: HASH@50..51 "#" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@51..56 "each" [] [Whitespace(" ")], + }, + ], + }, + arguments: GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@56..62 "items" [] [Whitespace(" ")], + }, + ], + }, + }, + ], + block_params: GlimmerBlockParams { + as_token_token: IDENT@62..65 "as" [] [Whitespace(" ")], + l_pipe_token_token: PIPE@65..66 "|" [] [], + params: GlimmerBlockParamList [ + GlimmerBlockParam { + name_token_token: IDENT@66..71 "item" [] [Whitespace(" ")], + }, + GlimmerBlockParam { + name_token_token: IDENT@71..76 "index" [] [], + }, + ], + r_pipe_token_token: PIPE@76..77 "|" [] [], + }, + r_curly2_token_token: R_DOUBLE_CURLY@77..79 "}}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@79..83 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@83..85 "li" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@85..86 ">" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@86..88 "{{" [] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@88..92 "item" [] [], + }, + DOT@92..93 "." [] [], + GlimmerPathSegment { + value_token_token: IDENT@93..97 "name" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly2_token_token: R_DOUBLE_CURLY@97..99 "}}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@99..100 "<" [] [], + slash_token: SLASH@100..101 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@101..103 "li" [] [], + }, + r_angle_token: R_ANGLE@103..104 ">" [] [], + }, + }, + ], + closing: GlimmerBlockHelperClosing { + l_curly2_token_token: L_DOUBLE_CURLY@104..107 "{{" [Newline("\n")] [], + slash_token_token: SLASH@107..108 "/" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@108..112 "each" [] [], + }, + ], + }, + r_curly2_token_token: R_DOUBLE_CURLY@112..114 "}}" [] [], + }, + }, + GlimmerBlockHelper { + opening: GlimmerBlockHelperOpening { + l_curly2_token_token: L_DOUBLE_CURLY@114..118 "{{" [Newline("\n"), Newline("\n")] [], + hash_token_token: HASH@118..119 "#" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@119..124 "with" [] [Whitespace(" ")], + }, + ], + }, + arguments: GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@124..129 "user" [] [Whitespace(" ")], + }, + ], + }, + }, + ], + block_params: GlimmerBlockParams { + as_token_token: IDENT@129..132 "as" [] [Whitespace(" ")], + l_pipe_token_token: PIPE@132..133 "|" [] [], + params: GlimmerBlockParamList [ + GlimmerBlockParam { + name_token_token: IDENT@133..134 "u" [] [], + }, + ], + r_pipe_token_token: PIPE@134..135 "|" [] [], + }, + r_curly2_token_token: R_DOUBLE_CURLY@135..137 "}}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@137..141 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@141..142 "p" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@142..143 ">" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@143..145 "{{" [] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@145..146 "u" [] [], + }, + DOT@146..147 "." [] [], + GlimmerPathSegment { + value_token_token: IDENT@147..151 "name" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly2_token_token: R_DOUBLE_CURLY@151..153 "}}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@153..154 "<" [] [], + slash_token: SLASH@154..155 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@155..156 "p" [] [], + }, + r_angle_token: R_ANGLE@156..157 ">" [] [], + }, + }, + ], + closing: GlimmerBlockHelperClosing { + l_curly2_token_token: L_DOUBLE_CURLY@157..160 "{{" [Newline("\n")] [], + slash_token_token: SLASH@160..161 "/" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@161..165 "with" [] [], + }, + ], + }, + r_curly2_token_token: R_DOUBLE_CURLY@165..167 "}}" [] [], + }, + }, + ], + eof_token: EOF@167..168 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..168 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..167 + 0: GLIMMER_BLOCK_HELPER@0..46 + 0: GLIMMER_BLOCK_HELPER_OPENING@0..17 + 0: L_DOUBLE_CURLY@0..2 "{{" [] [] + 1: HASH@2..3 "#" [] [] + 2: GLIMMER_PATH@3..6 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@3..6 + 0: GLIMMER_PATH_SEGMENT@3..6 + 0: IDENT@3..6 "if" [] [Whitespace(" ")] + 3: GLIMMER_ARGUMENT_LIST@6..15 + 0: GLIMMER_POSITIONAL_ARGUMENT@6..15 + 0: GLIMMER_PATH@6..15 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@6..15 + 0: GLIMMER_PATH_SEGMENT@6..15 + 0: IDENT@6..15 "showTitle" [] [] + 4: (empty) + 5: R_DOUBLE_CURLY@15..17 "}}" [] [] + 1: HTML_ELEMENT_LIST@17..38 + 0: HTML_ELEMENT@17..38 + 0: HTML_OPENING_ELEMENT@17..24 + 0: L_ANGLE@17..21 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@21..23 + 0: HTML_LITERAL@21..23 "h1" [] [] + 2: HTML_ATTRIBUTE_LIST@23..23 + 3: R_ANGLE@23..24 ">" [] [] + 1: HTML_ELEMENT_LIST@24..33 + 0: GLIMMER_MUSTACHE_EXPRESSION@24..33 + 0: L_DOUBLE_CURLY@24..26 "{{" [] [] + 1: GLIMMER_PATH@26..31 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@26..31 + 0: GLIMMER_PATH_SEGMENT@26..31 + 0: IDENT@26..31 "title" [] [] + 2: GLIMMER_ARGUMENT_LIST@31..31 + 3: R_DOUBLE_CURLY@31..33 "}}" [] [] + 2: HTML_CLOSING_ELEMENT@33..38 + 0: L_ANGLE@33..34 "<" [] [] + 1: SLASH@34..35 "/" [] [] + 2: HTML_TAG_NAME@35..37 + 0: HTML_LITERAL@35..37 "h1" [] [] + 3: R_ANGLE@37..38 ">" [] [] + 2: GLIMMER_BLOCK_HELPER_CLOSING@38..46 + 0: L_DOUBLE_CURLY@38..41 "{{" [Newline("\n")] [] + 1: SLASH@41..42 "/" [] [] + 2: GLIMMER_PATH@42..44 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@42..44 + 0: GLIMMER_PATH_SEGMENT@42..44 + 0: IDENT@42..44 "if" [] [] + 3: R_DOUBLE_CURLY@44..46 "}}" [] [] + 1: GLIMMER_BLOCK_HELPER@46..114 + 0: GLIMMER_BLOCK_HELPER_OPENING@46..79 + 0: L_DOUBLE_CURLY@46..50 "{{" [Newline("\n"), Newline("\n")] [] + 1: HASH@50..51 "#" [] [] + 2: GLIMMER_PATH@51..56 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@51..56 + 0: GLIMMER_PATH_SEGMENT@51..56 + 0: IDENT@51..56 "each" [] [Whitespace(" ")] + 3: GLIMMER_ARGUMENT_LIST@56..62 + 0: GLIMMER_POSITIONAL_ARGUMENT@56..62 + 0: GLIMMER_PATH@56..62 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@56..62 + 0: GLIMMER_PATH_SEGMENT@56..62 + 0: IDENT@56..62 "items" [] [Whitespace(" ")] + 4: GLIMMER_BLOCK_PARAMS@62..77 + 0: IDENT@62..65 "as" [] [Whitespace(" ")] + 1: PIPE@65..66 "|" [] [] + 2: GLIMMER_BLOCK_PARAM_LIST@66..76 + 0: GLIMMER_BLOCK_PARAM@66..71 + 0: IDENT@66..71 "item" [] [Whitespace(" ")] + 1: GLIMMER_BLOCK_PARAM@71..76 + 0: IDENT@71..76 "index" [] [] + 3: PIPE@76..77 "|" [] [] + 5: R_DOUBLE_CURLY@77..79 "}}" [] [] + 1: HTML_ELEMENT_LIST@79..104 + 0: HTML_ELEMENT@79..104 + 0: HTML_OPENING_ELEMENT@79..86 + 0: L_ANGLE@79..83 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@83..85 + 0: HTML_LITERAL@83..85 "li" [] [] + 2: HTML_ATTRIBUTE_LIST@85..85 + 3: R_ANGLE@85..86 ">" [] [] + 1: HTML_ELEMENT_LIST@86..99 + 0: GLIMMER_MUSTACHE_EXPRESSION@86..99 + 0: L_DOUBLE_CURLY@86..88 "{{" [] [] + 1: GLIMMER_PATH@88..97 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@88..97 + 0: GLIMMER_PATH_SEGMENT@88..92 + 0: IDENT@88..92 "item" [] [] + 1: DOT@92..93 "." [] [] + 2: GLIMMER_PATH_SEGMENT@93..97 + 0: IDENT@93..97 "name" [] [] + 2: GLIMMER_ARGUMENT_LIST@97..97 + 3: R_DOUBLE_CURLY@97..99 "}}" [] [] + 2: HTML_CLOSING_ELEMENT@99..104 + 0: L_ANGLE@99..100 "<" [] [] + 1: SLASH@100..101 "/" [] [] + 2: HTML_TAG_NAME@101..103 + 0: HTML_LITERAL@101..103 "li" [] [] + 3: R_ANGLE@103..104 ">" [] [] + 2: GLIMMER_BLOCK_HELPER_CLOSING@104..114 + 0: L_DOUBLE_CURLY@104..107 "{{" [Newline("\n")] [] + 1: SLASH@107..108 "/" [] [] + 2: GLIMMER_PATH@108..112 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@108..112 + 0: GLIMMER_PATH_SEGMENT@108..112 + 0: IDENT@108..112 "each" [] [] + 3: R_DOUBLE_CURLY@112..114 "}}" [] [] + 2: GLIMMER_BLOCK_HELPER@114..167 + 0: GLIMMER_BLOCK_HELPER_OPENING@114..137 + 0: L_DOUBLE_CURLY@114..118 "{{" [Newline("\n"), Newline("\n")] [] + 1: HASH@118..119 "#" [] [] + 2: GLIMMER_PATH@119..124 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@119..124 + 0: GLIMMER_PATH_SEGMENT@119..124 + 0: IDENT@119..124 "with" [] [Whitespace(" ")] + 3: GLIMMER_ARGUMENT_LIST@124..129 + 0: GLIMMER_POSITIONAL_ARGUMENT@124..129 + 0: GLIMMER_PATH@124..129 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@124..129 + 0: GLIMMER_PATH_SEGMENT@124..129 + 0: IDENT@124..129 "user" [] [Whitespace(" ")] + 4: GLIMMER_BLOCK_PARAMS@129..135 + 0: IDENT@129..132 "as" [] [Whitespace(" ")] + 1: PIPE@132..133 "|" [] [] + 2: GLIMMER_BLOCK_PARAM_LIST@133..134 + 0: GLIMMER_BLOCK_PARAM@133..134 + 0: IDENT@133..134 "u" [] [] + 3: PIPE@134..135 "|" [] [] + 5: R_DOUBLE_CURLY@135..137 "}}" [] [] + 1: HTML_ELEMENT_LIST@137..157 + 0: HTML_ELEMENT@137..157 + 0: HTML_OPENING_ELEMENT@137..143 + 0: L_ANGLE@137..141 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@141..142 + 0: HTML_LITERAL@141..142 "p" [] [] + 2: HTML_ATTRIBUTE_LIST@142..142 + 3: R_ANGLE@142..143 ">" [] [] + 1: HTML_ELEMENT_LIST@143..153 + 0: GLIMMER_MUSTACHE_EXPRESSION@143..153 + 0: L_DOUBLE_CURLY@143..145 "{{" [] [] + 1: GLIMMER_PATH@145..151 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@145..151 + 0: GLIMMER_PATH_SEGMENT@145..146 + 0: IDENT@145..146 "u" [] [] + 1: DOT@146..147 "." [] [] + 2: GLIMMER_PATH_SEGMENT@147..151 + 0: IDENT@147..151 "name" [] [] + 2: GLIMMER_ARGUMENT_LIST@151..151 + 3: R_DOUBLE_CURLY@151..153 "}}" [] [] + 2: HTML_CLOSING_ELEMENT@153..157 + 0: L_ANGLE@153..154 "<" [] [] + 1: SLASH@154..155 "/" [] [] + 2: HTML_TAG_NAME@155..156 + 0: HTML_LITERAL@155..156 "p" [] [] + 3: R_ANGLE@156..157 ">" [] [] + 2: GLIMMER_BLOCK_HELPER_CLOSING@157..167 + 0: L_DOUBLE_CURLY@157..160 "{{" [Newline("\n")] [] + 1: SLASH@160..161 "/" [] [] + 2: GLIMMER_PATH@161..165 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@161..165 + 0: GLIMMER_PATH_SEGMENT@161..165 + 0: IDENT@161..165 "with" [] [] + 3: R_DOUBLE_CURLY@165..167 "}}" [] [] + 4: EOF@167..168 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_params_with_as.gjs b/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_params_with_as.gjs new file mode 100644 index 000000000000..3c75517c5e21 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_params_with_as.gjs @@ -0,0 +1,9 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_params_with_as.gjs.snap b/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_params_with_as.gjs.snap new file mode 100644 index 000000000000..a2a4bace641e --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/block_params_with_as.gjs.snap @@ -0,0 +1,294 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```glimmer + + +``` + + +## 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..9 "template" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@9..10 ">" [] [], + }, + children: HtmlElementList [ + GlimmerBlockHelper { + opening: GlimmerBlockHelperOpening { + l_curly2_token_token: L_DOUBLE_CURLY@10..15 "{{" [Newline("\n"), Whitespace(" ")] [], + hash_token_token: HASH@15..16 "#" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@16..21 "each" [] [Whitespace(" ")], + }, + ], + }, + arguments: GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@21..27 "items" [] [Whitespace(" ")], + }, + ], + }, + }, + ], + block_params: GlimmerBlockParams { + as_token_token: IDENT@27..30 "as" [] [Whitespace(" ")], + l_pipe_token_token: PIPE@30..31 "|" [] [], + params: GlimmerBlockParamList [ + GlimmerBlockParam { + name_token_token: IDENT@31..35 "item" [] [], + }, + ], + r_pipe_token_token: PIPE@35..36 "|" [] [], + }, + r_curly2_token_token: R_DOUBLE_CURLY@36..38 "}}" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@38..45 "{{" [Newline("\n"), Whitespace(" ")] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@45..49 "item" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly2_token_token: R_DOUBLE_CURLY@49..51 "}}" [] [], + }, + ], + closing: GlimmerBlockHelperClosing { + l_curly2_token_token: L_DOUBLE_CURLY@51..56 "{{" [Newline("\n"), Whitespace(" ")] [], + slash_token_token: SLASH@56..57 "/" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@57..61 "each" [] [], + }, + ], + }, + r_curly2_token_token: R_DOUBLE_CURLY@61..63 "}}" [] [], + }, + }, + GlimmerBlockHelper { + opening: GlimmerBlockHelperOpening { + l_curly2_token_token: L_DOUBLE_CURLY@63..69 "{{" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + hash_token_token: HASH@69..70 "#" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@70..74 "let" [] [Whitespace(" ")], + }, + ], + }, + arguments: GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@74..80 "value" [] [Whitespace(" ")], + }, + ], + }, + }, + ], + block_params: GlimmerBlockParams { + as_token_token: IDENT@80..83 "as" [] [Whitespace(" ")], + l_pipe_token_token: PIPE@83..84 "|" [] [], + params: GlimmerBlockParamList [ + GlimmerBlockParam { + name_token_token: IDENT@84..85 "v" [] [], + }, + ], + r_pipe_token_token: PIPE@85..86 "|" [] [], + }, + r_curly2_token_token: R_DOUBLE_CURLY@86..88 "}}" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@88..95 "{{" [Newline("\n"), Whitespace(" ")] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@95..96 "v" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly2_token_token: R_DOUBLE_CURLY@96..98 "}}" [] [], + }, + ], + closing: GlimmerBlockHelperClosing { + l_curly2_token_token: L_DOUBLE_CURLY@98..103 "{{" [Newline("\n"), Whitespace(" ")] [], + slash_token_token: SLASH@103..104 "/" [] [], + helper: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@104..107 "let" [] [], + }, + ], + }, + r_curly2_token_token: R_DOUBLE_CURLY@107..109 "}}" [] [], + }, + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@109..111 "<" [Newline("\n")] [], + slash_token: SLASH@111..112 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@112..120 "template" [] [], + }, + r_angle_token: R_ANGLE@120..121 ">" [] [], + }, + }, + ], + eof_token: EOF@121..122 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..122 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..121 + 0: HTML_ELEMENT@0..121 + 0: HTML_OPENING_ELEMENT@0..10 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..9 + 0: HTML_LITERAL@1..9 "template" [] [] + 2: HTML_ATTRIBUTE_LIST@9..9 + 3: R_ANGLE@9..10 ">" [] [] + 1: HTML_ELEMENT_LIST@10..109 + 0: GLIMMER_BLOCK_HELPER@10..63 + 0: GLIMMER_BLOCK_HELPER_OPENING@10..38 + 0: L_DOUBLE_CURLY@10..15 "{{" [Newline("\n"), Whitespace(" ")] [] + 1: HASH@15..16 "#" [] [] + 2: GLIMMER_PATH@16..21 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@16..21 + 0: GLIMMER_PATH_SEGMENT@16..21 + 0: IDENT@16..21 "each" [] [Whitespace(" ")] + 3: GLIMMER_ARGUMENT_LIST@21..27 + 0: GLIMMER_POSITIONAL_ARGUMENT@21..27 + 0: GLIMMER_PATH@21..27 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@21..27 + 0: GLIMMER_PATH_SEGMENT@21..27 + 0: IDENT@21..27 "items" [] [Whitespace(" ")] + 4: GLIMMER_BLOCK_PARAMS@27..36 + 0: IDENT@27..30 "as" [] [Whitespace(" ")] + 1: PIPE@30..31 "|" [] [] + 2: GLIMMER_BLOCK_PARAM_LIST@31..35 + 0: GLIMMER_BLOCK_PARAM@31..35 + 0: IDENT@31..35 "item" [] [] + 3: PIPE@35..36 "|" [] [] + 5: R_DOUBLE_CURLY@36..38 "}}" [] [] + 1: HTML_ELEMENT_LIST@38..51 + 0: GLIMMER_MUSTACHE_EXPRESSION@38..51 + 0: L_DOUBLE_CURLY@38..45 "{{" [Newline("\n"), Whitespace(" ")] [] + 1: GLIMMER_PATH@45..49 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@45..49 + 0: GLIMMER_PATH_SEGMENT@45..49 + 0: IDENT@45..49 "item" [] [] + 2: GLIMMER_ARGUMENT_LIST@49..49 + 3: R_DOUBLE_CURLY@49..51 "}}" [] [] + 2: GLIMMER_BLOCK_HELPER_CLOSING@51..63 + 0: L_DOUBLE_CURLY@51..56 "{{" [Newline("\n"), Whitespace(" ")] [] + 1: SLASH@56..57 "/" [] [] + 2: GLIMMER_PATH@57..61 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@57..61 + 0: GLIMMER_PATH_SEGMENT@57..61 + 0: IDENT@57..61 "each" [] [] + 3: R_DOUBLE_CURLY@61..63 "}}" [] [] + 1: GLIMMER_BLOCK_HELPER@63..109 + 0: GLIMMER_BLOCK_HELPER_OPENING@63..88 + 0: L_DOUBLE_CURLY@63..69 "{{" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 1: HASH@69..70 "#" [] [] + 2: GLIMMER_PATH@70..74 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@70..74 + 0: GLIMMER_PATH_SEGMENT@70..74 + 0: IDENT@70..74 "let" [] [Whitespace(" ")] + 3: GLIMMER_ARGUMENT_LIST@74..80 + 0: GLIMMER_POSITIONAL_ARGUMENT@74..80 + 0: GLIMMER_PATH@74..80 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@74..80 + 0: GLIMMER_PATH_SEGMENT@74..80 + 0: IDENT@74..80 "value" [] [Whitespace(" ")] + 4: GLIMMER_BLOCK_PARAMS@80..86 + 0: IDENT@80..83 "as" [] [Whitespace(" ")] + 1: PIPE@83..84 "|" [] [] + 2: GLIMMER_BLOCK_PARAM_LIST@84..85 + 0: GLIMMER_BLOCK_PARAM@84..85 + 0: IDENT@84..85 "v" [] [] + 3: PIPE@85..86 "|" [] [] + 5: R_DOUBLE_CURLY@86..88 "}}" [] [] + 1: HTML_ELEMENT_LIST@88..98 + 0: GLIMMER_MUSTACHE_EXPRESSION@88..98 + 0: L_DOUBLE_CURLY@88..95 "{{" [Newline("\n"), Whitespace(" ")] [] + 1: GLIMMER_PATH@95..96 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@95..96 + 0: GLIMMER_PATH_SEGMENT@95..96 + 0: IDENT@95..96 "v" [] [] + 2: GLIMMER_ARGUMENT_LIST@96..96 + 3: R_DOUBLE_CURLY@96..98 "}}" [] [] + 2: GLIMMER_BLOCK_HELPER_CLOSING@98..109 + 0: L_DOUBLE_CURLY@98..103 "{{" [Newline("\n"), Whitespace(" ")] [] + 1: SLASH@103..104 "/" [] [] + 2: GLIMMER_PATH@104..107 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@104..107 + 0: GLIMMER_PATH_SEGMENT@104..107 + 0: IDENT@104..107 "let" [] [] + 3: R_DOUBLE_CURLY@107..109 "}}" [] [] + 2: HTML_CLOSING_ELEMENT@109..121 + 0: L_ANGLE@109..111 "<" [Newline("\n")] [] + 1: SLASH@111..112 "/" [] [] + 2: HTML_TAG_NAME@112..120 + 0: HTML_LITERAL@112..120 "template" [] [] + 3: R_ANGLE@120..121 ">" [] [] + 4: EOF@121..122 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/doctype_identifier.gjs b/crates/biome_html_parser/tests/html_specs/ok/glimmer/doctype_identifier.gjs new file mode 100644 index 000000000000..f2c718be8018 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/doctype_identifier.gjs @@ -0,0 +1,4 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/doctype_identifier.gjs.snap b/crates/biome_html_parser/tests/html_specs/ok/glimmer/doctype_identifier.gjs.snap new file mode 100644 index 000000000000..636cb7dc63fb --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/doctype_identifier.gjs.snap @@ -0,0 +1,117 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```glimmer + + +``` + + +## 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..9 "template" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@9..10 ">" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@10..15 "{{" [Newline("\n"), Whitespace(" ")] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@15..22 "doctype" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly2_token_token: R_DOUBLE_CURLY@22..24 "}}" [] [], + }, + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@24..29 "{{" [Newline("\n"), Whitespace(" ")] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@29..36 "DOCTYPE" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly2_token_token: R_DOUBLE_CURLY@36..38 "}}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@38..40 "<" [Newline("\n")] [], + slash_token: SLASH@40..41 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@41..49 "template" [] [], + }, + r_angle_token: R_ANGLE@49..50 ">" [] [], + }, + }, + ], + eof_token: EOF@50..51 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..51 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..50 + 0: HTML_ELEMENT@0..50 + 0: HTML_OPENING_ELEMENT@0..10 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..9 + 0: HTML_LITERAL@1..9 "template" [] [] + 2: HTML_ATTRIBUTE_LIST@9..9 + 3: R_ANGLE@9..10 ">" [] [] + 1: HTML_ELEMENT_LIST@10..38 + 0: GLIMMER_MUSTACHE_EXPRESSION@10..24 + 0: L_DOUBLE_CURLY@10..15 "{{" [Newline("\n"), Whitespace(" ")] [] + 1: GLIMMER_PATH@15..22 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@15..22 + 0: GLIMMER_PATH_SEGMENT@15..22 + 0: IDENT@15..22 "doctype" [] [] + 2: GLIMMER_ARGUMENT_LIST@22..22 + 3: R_DOUBLE_CURLY@22..24 "}}" [] [] + 1: GLIMMER_MUSTACHE_EXPRESSION@24..38 + 0: L_DOUBLE_CURLY@24..29 "{{" [Newline("\n"), Whitespace(" ")] [] + 1: GLIMMER_PATH@29..36 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@29..36 + 0: GLIMMER_PATH_SEGMENT@29..36 + 0: IDENT@29..36 "DOCTYPE" [] [] + 2: GLIMMER_ARGUMENT_LIST@36..36 + 3: R_DOUBLE_CURLY@36..38 "}}" [] [] + 2: HTML_CLOSING_ELEMENT@38..50 + 0: L_ANGLE@38..40 "<" [Newline("\n")] [] + 1: SLASH@40..41 "/" [] [] + 2: HTML_TAG_NAME@41..49 + 0: HTML_LITERAL@41..49 "template" [] [] + 3: R_ANGLE@49..50 ">" [] [] + 4: EOF@50..51 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache.gjs b/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache.gjs new file mode 100644 index 000000000000..77965fe122e1 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache.gjs @@ -0,0 +1,6 @@ +{{this.title}} +
    +

    {{@name}}

    +

    {{greeting "World"}}

    + {{helper arg1 arg2 key=value}} +
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache.gjs.snap b/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache.gjs.snap new file mode 100644 index 000000000000..efe00b70b4dc --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache.gjs.snap @@ -0,0 +1,334 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```glimmer +{{this.title}} +
    +

    {{@name}}

    +

    {{greeting "World"}}

    + {{helper arg1 arg2 key=value}} +
    + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@0..2 "{{" [] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@2..6 "this" [] [], + }, + DOT@6..7 "." [] [], + GlimmerPathSegment { + value_token_token: IDENT@7..12 "title" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly2_token_token: R_DOUBLE_CURLY@12..14 "}}" [] [], + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@14..16 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@16..19 "div" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@19..20 ">" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@20..24 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@24..26 "h1" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@26..27 ">" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@27..29 "{{" [] [], + path: GlimmerPath { + at_token_token: AT@29..30 "@" [] [], + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@30..34 "name" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly2_token_token: R_DOUBLE_CURLY@34..36 "}}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@36..37 "<" [] [], + slash_token: SLASH@37..38 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@38..40 "h1" [] [], + }, + r_angle_token: R_ANGLE@40..41 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@41..45 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@45..46 "p" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@46..47 ">" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@47..49 "{{" [] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@49..58 "greeting" [] [Whitespace(" ")], + }, + ], + }, + arguments: GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerStringLiteral { + value_token_token: HTML_STRING_LITERAL@58..65 "\"World\"" [] [], + }, + }, + ], + r_curly2_token_token: R_DOUBLE_CURLY@65..67 "}}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@67..68 "<" [] [], + slash_token: SLASH@68..69 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@69..70 "p" [] [], + }, + r_angle_token: R_ANGLE@70..71 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@71..75 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@75..79 "span" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@79..80 ">" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheExpression { + l_curly2_token_token: L_DOUBLE_CURLY@80..82 "{{" [] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@82..89 "helper" [] [Whitespace(" ")], + }, + ], + }, + arguments: GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@89..94 "arg1" [] [Whitespace(" ")], + }, + ], + }, + }, + GlimmerPositionalArgument { + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@94..99 "arg2" [] [Whitespace(" ")], + }, + ], + }, + }, + GlimmerNamedArgument { + name_token_token: IDENT@99..102 "key" [] [], + eq_token_token: EQ@102..103 "=" [] [], + value: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@103..108 "value" [] [], + }, + ], + }, + }, + ], + r_curly2_token_token: R_DOUBLE_CURLY@108..110 "}}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@110..111 "<" [] [], + slash_token: SLASH@111..112 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@112..116 "span" [] [], + }, + r_angle_token: R_ANGLE@116..117 ">" [] [], + }, + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@117..119 "<" [Newline("\n")] [], + slash_token: SLASH@119..120 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@120..123 "div" [] [], + }, + r_angle_token: R_ANGLE@123..124 ">" [] [], + }, + }, + ], + eof_token: EOF@124..125 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..125 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..124 + 0: GLIMMER_MUSTACHE_EXPRESSION@0..14 + 0: L_DOUBLE_CURLY@0..2 "{{" [] [] + 1: GLIMMER_PATH@2..12 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@2..12 + 0: GLIMMER_PATH_SEGMENT@2..6 + 0: IDENT@2..6 "this" [] [] + 1: DOT@6..7 "." [] [] + 2: GLIMMER_PATH_SEGMENT@7..12 + 0: IDENT@7..12 "title" [] [] + 2: GLIMMER_ARGUMENT_LIST@12..12 + 3: R_DOUBLE_CURLY@12..14 "}}" [] [] + 1: HTML_ELEMENT@14..124 + 0: HTML_OPENING_ELEMENT@14..20 + 0: L_ANGLE@14..16 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@16..19 + 0: HTML_LITERAL@16..19 "div" [] [] + 2: HTML_ATTRIBUTE_LIST@19..19 + 3: R_ANGLE@19..20 ">" [] [] + 1: HTML_ELEMENT_LIST@20..117 + 0: HTML_ELEMENT@20..41 + 0: HTML_OPENING_ELEMENT@20..27 + 0: L_ANGLE@20..24 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@24..26 + 0: HTML_LITERAL@24..26 "h1" [] [] + 2: HTML_ATTRIBUTE_LIST@26..26 + 3: R_ANGLE@26..27 ">" [] [] + 1: HTML_ELEMENT_LIST@27..36 + 0: GLIMMER_MUSTACHE_EXPRESSION@27..36 + 0: L_DOUBLE_CURLY@27..29 "{{" [] [] + 1: GLIMMER_PATH@29..34 + 0: AT@29..30 "@" [] [] + 1: GLIMMER_PATH_SEGMENT_LIST@30..34 + 0: GLIMMER_PATH_SEGMENT@30..34 + 0: IDENT@30..34 "name" [] [] + 2: GLIMMER_ARGUMENT_LIST@34..34 + 3: R_DOUBLE_CURLY@34..36 "}}" [] [] + 2: HTML_CLOSING_ELEMENT@36..41 + 0: L_ANGLE@36..37 "<" [] [] + 1: SLASH@37..38 "/" [] [] + 2: HTML_TAG_NAME@38..40 + 0: HTML_LITERAL@38..40 "h1" [] [] + 3: R_ANGLE@40..41 ">" [] [] + 1: HTML_ELEMENT@41..71 + 0: HTML_OPENING_ELEMENT@41..47 + 0: L_ANGLE@41..45 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@45..46 + 0: HTML_LITERAL@45..46 "p" [] [] + 2: HTML_ATTRIBUTE_LIST@46..46 + 3: R_ANGLE@46..47 ">" [] [] + 1: HTML_ELEMENT_LIST@47..67 + 0: GLIMMER_MUSTACHE_EXPRESSION@47..67 + 0: L_DOUBLE_CURLY@47..49 "{{" [] [] + 1: GLIMMER_PATH@49..58 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@49..58 + 0: GLIMMER_PATH_SEGMENT@49..58 + 0: IDENT@49..58 "greeting" [] [Whitespace(" ")] + 2: GLIMMER_ARGUMENT_LIST@58..65 + 0: GLIMMER_POSITIONAL_ARGUMENT@58..65 + 0: GLIMMER_STRING_LITERAL@58..65 + 0: HTML_STRING_LITERAL@58..65 "\"World\"" [] [] + 3: R_DOUBLE_CURLY@65..67 "}}" [] [] + 2: HTML_CLOSING_ELEMENT@67..71 + 0: L_ANGLE@67..68 "<" [] [] + 1: SLASH@68..69 "/" [] [] + 2: HTML_TAG_NAME@69..70 + 0: HTML_LITERAL@69..70 "p" [] [] + 3: R_ANGLE@70..71 ">" [] [] + 2: HTML_ELEMENT@71..117 + 0: HTML_OPENING_ELEMENT@71..80 + 0: L_ANGLE@71..75 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@75..79 + 0: HTML_LITERAL@75..79 "span" [] [] + 2: HTML_ATTRIBUTE_LIST@79..79 + 3: R_ANGLE@79..80 ">" [] [] + 1: HTML_ELEMENT_LIST@80..110 + 0: GLIMMER_MUSTACHE_EXPRESSION@80..110 + 0: L_DOUBLE_CURLY@80..82 "{{" [] [] + 1: GLIMMER_PATH@82..89 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@82..89 + 0: GLIMMER_PATH_SEGMENT@82..89 + 0: IDENT@82..89 "helper" [] [Whitespace(" ")] + 2: GLIMMER_ARGUMENT_LIST@89..108 + 0: GLIMMER_POSITIONAL_ARGUMENT@89..94 + 0: GLIMMER_PATH@89..94 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@89..94 + 0: GLIMMER_PATH_SEGMENT@89..94 + 0: IDENT@89..94 "arg1" [] [Whitespace(" ")] + 1: GLIMMER_POSITIONAL_ARGUMENT@94..99 + 0: GLIMMER_PATH@94..99 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@94..99 + 0: GLIMMER_PATH_SEGMENT@94..99 + 0: IDENT@94..99 "arg2" [] [Whitespace(" ")] + 2: GLIMMER_NAMED_ARGUMENT@99..108 + 0: IDENT@99..102 "key" [] [] + 1: EQ@102..103 "=" [] [] + 2: GLIMMER_PATH@103..108 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@103..108 + 0: GLIMMER_PATH_SEGMENT@103..108 + 0: IDENT@103..108 "value" [] [] + 3: R_DOUBLE_CURLY@108..110 "}}" [] [] + 2: HTML_CLOSING_ELEMENT@110..117 + 0: L_ANGLE@110..111 "<" [] [] + 1: SLASH@111..112 "/" [] [] + 2: HTML_TAG_NAME@112..116 + 0: HTML_LITERAL@112..116 "span" [] [] + 3: R_ANGLE@116..117 ">" [] [] + 2: HTML_CLOSING_ELEMENT@117..124 + 0: L_ANGLE@117..119 "<" [Newline("\n")] [] + 1: SLASH@119..120 "/" [] [] + 2: HTML_TAG_NAME@120..123 + 0: HTML_LITERAL@120..123 "div" [] [] + 3: R_ANGLE@123..124 ">" [] [] + 4: EOF@124..125 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache_comment.html b/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache_comment.html new file mode 100644 index 000000000000..18fa86a0ab10 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache_comment.html @@ -0,0 +1,7 @@ +{{! This is a single-line comment }} +
    + {{!-- This is a multi-line comment + that spans multiple lines + --}} +

    Hello World

    +
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache_comment.html.snap b/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache_comment.html.snap new file mode 100644 index 000000000000..9c62af184843 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/mustache_comment.html.snap @@ -0,0 +1,125 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```html +{{! This is a single-line comment }} +
    + {{!-- This is a multi-line comment + that spans multiple lines + --}} +

    Hello World

    +
    + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + GlimmerMustacheComment { + comment_token_token: MUSTACHE_COMMENT@0..36 "{{! This is a single-line comment }}" [] [], + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@36..38 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@38..41 "div" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@41..42 ">" [] [], + }, + children: HtmlElementList [ + GlimmerMustacheComment { + comment_token_token: MUSTACHE_COMMENT@42..116 "{{!-- This is a multi-line comment\n that spans multiple lines\n --}}" [Newline("\n"), Whitespace(" ")] [], + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@116..120 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@120..121 "p" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@121..122 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@122..133 "Hello World" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@133..134 "<" [] [], + slash_token: SLASH@134..135 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@135..136 "p" [] [], + }, + r_angle_token: R_ANGLE@136..137 ">" [] [], + }, + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@137..139 "<" [Newline("\n")] [], + slash_token: SLASH@139..140 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@140..143 "div" [] [], + }, + r_angle_token: R_ANGLE@143..144 ">" [] [], + }, + }, + ], + eof_token: EOF@144..145 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..145 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..144 + 0: GLIMMER_MUSTACHE_COMMENT@0..36 + 0: MUSTACHE_COMMENT@0..36 "{{! This is a single-line comment }}" [] [] + 1: HTML_ELEMENT@36..144 + 0: HTML_OPENING_ELEMENT@36..42 + 0: L_ANGLE@36..38 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@38..41 + 0: HTML_LITERAL@38..41 "div" [] [] + 2: HTML_ATTRIBUTE_LIST@41..41 + 3: R_ANGLE@41..42 ">" [] [] + 1: HTML_ELEMENT_LIST@42..137 + 0: GLIMMER_MUSTACHE_COMMENT@42..116 + 0: MUSTACHE_COMMENT@42..116 "{{!-- This is a multi-line comment\n that spans multiple lines\n --}}" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_ELEMENT@116..137 + 0: HTML_OPENING_ELEMENT@116..122 + 0: L_ANGLE@116..120 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@120..121 + 0: HTML_LITERAL@120..121 "p" [] [] + 2: HTML_ATTRIBUTE_LIST@121..121 + 3: R_ANGLE@121..122 ">" [] [] + 1: HTML_ELEMENT_LIST@122..133 + 0: HTML_CONTENT@122..133 + 0: HTML_LITERAL@122..133 "Hello World" [] [] + 2: HTML_CLOSING_ELEMENT@133..137 + 0: L_ANGLE@133..134 "<" [] [] + 1: SLASH@134..135 "/" [] [] + 2: HTML_TAG_NAME@135..136 + 0: HTML_LITERAL@135..136 "p" [] [] + 3: R_ANGLE@136..137 ">" [] [] + 2: HTML_CLOSING_ELEMENT@137..144 + 0: L_ANGLE@137..139 "<" [Newline("\n")] [] + 1: SLASH@139..140 "/" [] [] + 2: HTML_TAG_NAME@140..143 + 0: HTML_LITERAL@140..143 "div" [] [] + 3: R_ANGLE@143..144 ">" [] [] + 4: EOF@144..145 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/triple_stash.gjs b/crates/biome_html_parser/tests/html_specs/ok/glimmer/triple_stash.gjs new file mode 100644 index 000000000000..372940d1ca15 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/triple_stash.gjs @@ -0,0 +1,5 @@ +{{{this.htmlContent}}} +
    +

    {{{userProvidedHtml}}}

    + {{{helper "argument"}}} +
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/glimmer/triple_stash.gjs.snap b/crates/biome_html_parser/tests/html_specs/ok/glimmer/triple_stash.gjs.snap new file mode 100644 index 000000000000..a20400ba2795 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/glimmer/triple_stash.gjs.snap @@ -0,0 +1,190 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```glimmer +{{{this.htmlContent}}} +
    +

    {{{userProvidedHtml}}}

    + {{{helper "argument"}}} +
    + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + GlimmerTripleStashExpression { + l_curly3_token_token: L_TRIPLE_CURLY@0..3 "{{{" [] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@3..7 "this" [] [], + }, + DOT@7..8 "." [] [], + GlimmerPathSegment { + value_token_token: IDENT@8..19 "htmlContent" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly3_token_token: R_TRIPLE_CURLY@19..22 "}}}" [] [], + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@22..24 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@24..27 "div" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@27..28 ">" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@28..32 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@32..33 "p" [] [], + }, + attributes: HtmlAttributeList [], + r_angle_token: R_ANGLE@33..34 ">" [] [], + }, + children: HtmlElementList [ + GlimmerTripleStashExpression { + l_curly3_token_token: L_TRIPLE_CURLY@34..37 "{{{" [] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@37..53 "userProvidedHtml" [] [], + }, + ], + }, + arguments: GlimmerArgumentList [], + r_curly3_token_token: R_TRIPLE_CURLY@53..56 "}}}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@56..57 "<" [] [], + slash_token: SLASH@57..58 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@58..59 "p" [] [], + }, + r_angle_token: R_ANGLE@59..60 ">" [] [], + }, + }, + GlimmerTripleStashExpression { + l_curly3_token_token: L_TRIPLE_CURLY@60..66 "{{{" [Newline("\n"), Whitespace(" ")] [], + path: GlimmerPath { + at_token_token: missing (optional), + segments: GlimmerPathSegmentList [ + GlimmerPathSegment { + value_token_token: IDENT@66..73 "helper" [] [Whitespace(" ")], + }, + ], + }, + arguments: GlimmerArgumentList [ + GlimmerPositionalArgument { + value: GlimmerStringLiteral { + value_token_token: HTML_STRING_LITERAL@73..83 "\"argument\"" [] [], + }, + }, + ], + r_curly3_token_token: R_TRIPLE_CURLY@83..86 "}}}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@86..88 "<" [Newline("\n")] [], + slash_token: SLASH@88..89 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@89..92 "div" [] [], + }, + r_angle_token: R_ANGLE@92..93 ">" [] [], + }, + }, + ], + eof_token: EOF@93..94 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..94 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..93 + 0: GLIMMER_TRIPLE_STASH_EXPRESSION@0..22 + 0: L_TRIPLE_CURLY@0..3 "{{{" [] [] + 1: GLIMMER_PATH@3..19 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@3..19 + 0: GLIMMER_PATH_SEGMENT@3..7 + 0: IDENT@3..7 "this" [] [] + 1: DOT@7..8 "." [] [] + 2: GLIMMER_PATH_SEGMENT@8..19 + 0: IDENT@8..19 "htmlContent" [] [] + 2: GLIMMER_ARGUMENT_LIST@19..19 + 3: R_TRIPLE_CURLY@19..22 "}}}" [] [] + 1: HTML_ELEMENT@22..93 + 0: HTML_OPENING_ELEMENT@22..28 + 0: L_ANGLE@22..24 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@24..27 + 0: HTML_LITERAL@24..27 "div" [] [] + 2: HTML_ATTRIBUTE_LIST@27..27 + 3: R_ANGLE@27..28 ">" [] [] + 1: HTML_ELEMENT_LIST@28..86 + 0: HTML_ELEMENT@28..60 + 0: HTML_OPENING_ELEMENT@28..34 + 0: L_ANGLE@28..32 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@32..33 + 0: HTML_LITERAL@32..33 "p" [] [] + 2: HTML_ATTRIBUTE_LIST@33..33 + 3: R_ANGLE@33..34 ">" [] [] + 1: HTML_ELEMENT_LIST@34..56 + 0: GLIMMER_TRIPLE_STASH_EXPRESSION@34..56 + 0: L_TRIPLE_CURLY@34..37 "{{{" [] [] + 1: GLIMMER_PATH@37..53 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@37..53 + 0: GLIMMER_PATH_SEGMENT@37..53 + 0: IDENT@37..53 "userProvidedHtml" [] [] + 2: GLIMMER_ARGUMENT_LIST@53..53 + 3: R_TRIPLE_CURLY@53..56 "}}}" [] [] + 2: HTML_CLOSING_ELEMENT@56..60 + 0: L_ANGLE@56..57 "<" [] [] + 1: SLASH@57..58 "/" [] [] + 2: HTML_TAG_NAME@58..59 + 0: HTML_LITERAL@58..59 "p" [] [] + 3: R_ANGLE@59..60 ">" [] [] + 1: GLIMMER_TRIPLE_STASH_EXPRESSION@60..86 + 0: L_TRIPLE_CURLY@60..66 "{{{" [Newline("\n"), Whitespace(" ")] [] + 1: GLIMMER_PATH@66..73 + 0: (empty) + 1: GLIMMER_PATH_SEGMENT_LIST@66..73 + 0: GLIMMER_PATH_SEGMENT@66..73 + 0: IDENT@66..73 "helper" [] [Whitespace(" ")] + 2: GLIMMER_ARGUMENT_LIST@73..83 + 0: GLIMMER_POSITIONAL_ARGUMENT@73..83 + 0: GLIMMER_STRING_LITERAL@73..83 + 0: HTML_STRING_LITERAL@73..83 "\"argument\"" [] [] + 3: R_TRIPLE_CURLY@83..86 "}}}" [] [] + 2: HTML_CLOSING_ELEMENT@86..93 + 0: L_ANGLE@86..88 "<" [Newline("\n")] [] + 1: SLASH@88..89 "/" [] [] + 2: HTML_TAG_NAME@89..92 + 0: HTML_LITERAL@89..92 "div" [] [] + 3: R_ANGLE@92..93 ">" [] [] + 4: EOF@93..94 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/spec_test.rs b/crates/biome_html_parser/tests/spec_test.rs index 8cd3853bae03..036a89960f53 100644 --- a/crates/biome_html_parser/tests/spec_test.rs +++ b/crates/biome_html_parser/tests/spec_test.rs @@ -44,6 +44,7 @@ pub fn run(test_case: &str, _snapshot_name: &str, test_directory: &str, outcome_ HtmlVariant::Astro => "astro", HtmlVariant::Vue => "vue", HtmlVariant::Svelte => "svelte", + HtmlVariant::Glimmer => "glimmer", }; writeln!( snapshot, @@ -142,10 +143,10 @@ pub fn run(test_case: &str, _snapshot_name: &str, test_directory: &str, outcome_ #[ignore] #[test] pub fn quick_test() { - let code = r#"{@debug something, something, something} + let code = r#"{{{this.htmlContent}}} "#; - let root = parse_html(code, (&HtmlFileSource::svelte()).into()); + let root = parse_html(code, (&HtmlFileSource::glimmer()).into()); let syntax = root.syntax(); dbg!(&syntax, root.diagnostics(), root.has_errors()); if has_bogus_nodes_or_empty_slots(&syntax) { diff --git a/crates/biome_html_parser/tests/spec_tests.rs b/crates/biome_html_parser/tests/spec_tests.rs index 67a3919c310b..1951f8151371 100644 --- a/crates/biome_html_parser/tests/spec_tests.rs +++ b/crates/biome_html_parser/tests/spec_tests.rs @@ -6,11 +6,11 @@ use biome_html_syntax::ScriptType; use biome_rowan::AstNode; mod ok { - tests_macros::gen_tests! {"tests/html_specs/ok/**/*.{html,astro,vue,svelte}", crate::spec_test::run, "ok"} + tests_macros::gen_tests! {"tests/html_specs/ok/**/*.{html,astro,vue,svelte,gjs,gts}", crate::spec_test::run, "ok"} } mod error { - tests_macros::gen_tests! {"tests/html_specs/error/**/*.{html,astro,vue,svelte}", crate::spec_test::run, "error"} + tests_macros::gen_tests! {"tests/html_specs/error/**/*.{html,astro,vue,svelte,gjs,gts}", crate::spec_test::run, "error"} } #[test] diff --git a/crates/biome_html_syntax/src/element_ext.rs b/crates/biome_html_syntax/src/element_ext.rs index c3e08d5ef87e..378a0f0451bc 100644 --- a/crates/biome_html_syntax/src/element_ext.rs +++ b/crates/biome_html_syntax/src/element_ext.rs @@ -28,7 +28,9 @@ impl AnyHtmlElement { Self::AnyHtmlContent(_) | Self::HtmlBogusElement(_) | Self::HtmlSelfClosingElement(_) - | Self::HtmlCdataSection(_) => false, + | Self::HtmlCdataSection(_) + | Self::GlimmerMustacheComment(_) + | Self::GlimmerTripleStashExpression(_) => false, Self::HtmlElement(element) => element.is_javascript_tag(), } } @@ -38,7 +40,9 @@ impl AnyHtmlElement { Self::AnyHtmlContent(_) | Self::HtmlBogusElement(_) | Self::HtmlSelfClosingElement(_) - | Self::HtmlCdataSection(_) => false, + | Self::HtmlCdataSection(_) + | Self::GlimmerMustacheComment(_) + | Self::GlimmerTripleStashExpression(_) => false, Self::HtmlElement(element) => element.is_style_tag(), } } @@ -48,7 +52,11 @@ impl AnyHtmlElement { Self::HtmlElement(element) => element.find_attribute_by_name(name_to_lookup), Self::HtmlSelfClosingElement(element) => element.find_attribute_by_name(name_to_lookup), // Other variants don't have attributes - Self::AnyHtmlContent(_) | Self::HtmlBogusElement(_) | Self::HtmlCdataSection(_) => None, + Self::AnyHtmlContent(_) + | Self::HtmlBogusElement(_) + | Self::HtmlCdataSection(_) + | Self::GlimmerMustacheComment(_) + | Self::GlimmerTripleStashExpression(_) => None, } } diff --git a/crates/biome_html_syntax/src/file_source.rs b/crates/biome_html_syntax/src/file_source.rs index 2328c417f8d4..e5ea6027a085 100644 --- a/crates/biome_html_syntax/src/file_source.rs +++ b/crates/biome_html_syntax/src/file_source.rs @@ -31,6 +31,8 @@ pub enum HtmlVariant { Vue, /// Use this variant to parse a Svelte file Svelte, + /// Use this variant to parse a Glimmer file (.gjs, .gts) + Glimmer, } impl Default for HtmlVariant { @@ -99,6 +101,16 @@ impl HtmlFileSource { } } + pub fn glimmer() -> Self { + Self { + variant: HtmlVariant::Glimmer, + } + } + + pub const fn is_glimmer(&self) -> bool { + matches!(self.variant, HtmlVariant::Glimmer) + } + /// Try to return the HTML file source corresponding to this file name from well-known files pub fn try_from_well_known(path: &Utf8Path) -> Result { let Some(extension) = path.extension() else { @@ -116,6 +128,7 @@ impl HtmlFileSource { "astro" => Ok(Self::astro()), "vue" => Ok(Self::vue()), "svelte" => Ok(Self::svelte()), + "gjs" | "gts" => Ok(Self::glimmer()), _ => Err(FileSourceError::UnknownExtension), } } @@ -135,6 +148,7 @@ impl HtmlFileSource { "astro" => Ok(Self::astro()), "vuejs" | "vue" => Ok(Self::vue()), "svelte" => Ok(Self::svelte()), + "glimmer" | "glimmer-js" | "glimmer-ts" => Ok(Self::glimmer()), _ => Err(FileSourceError::UnknownLanguageId), } } @@ -156,3 +170,44 @@ impl TryFrom<&Utf8Path> for HtmlFileSource { Self::try_from_extension(&extension.to_ascii_lowercase_cow()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_glimmer_variant() { + let glimmer_source = HtmlFileSource::glimmer(); + assert!(glimmer_source.is_glimmer()); + assert!(!glimmer_source.is_html()); + assert!(!glimmer_source.is_vue()); + assert!(!glimmer_source.is_svelte()); + assert!(!glimmer_source.is_astro()); + } + + #[test] + fn test_glimmer_from_extension() { + let result = HtmlFileSource::try_from_extension("gjs"); + assert!(result.is_ok()); + assert!(result.unwrap().is_glimmer()); + + let result = HtmlFileSource::try_from_extension("gts"); + assert!(result.is_ok()); + assert!(result.unwrap().is_glimmer()); + } + + #[test] + fn test_glimmer_from_language_id() { + let result = HtmlFileSource::try_from_language_id("glimmer"); + assert!(result.is_ok()); + assert!(result.unwrap().is_glimmer()); + + let result = HtmlFileSource::try_from_language_id("glimmer-js"); + assert!(result.is_ok()); + assert!(result.unwrap().is_glimmer()); + + let result = HtmlFileSource::try_from_language_id("glimmer-ts"); + assert!(result.is_ok()); + assert!(result.unwrap().is_glimmer()); + } +} diff --git a/crates/biome_html_syntax/src/generated/kind.rs b/crates/biome_html_syntax/src/generated/kind.rs index abf41fbd3280..e1803eaeab78 100644 --- a/crates/biome_html_syntax/src/generated/kind.rs +++ b/crates/biome_html_syntax/src/generated/kind.rs @@ -30,6 +30,14 @@ pub enum HtmlSyntaxKind { SV_CURLY_SLASH, SV_CURLY_COLON, COMMA, + HASH, + DOT, + PIPE, + AT, + DOTDOTDOT, + L_PAREN, + R_PAREN, + COLON, NULL_KW, TRUE_KW, FALSE_KW, @@ -44,6 +52,9 @@ pub enum HtmlSyntaxKind { IDENT, HTML_IDENT, SVELTE_IDENT, + MUSTACHE_COMMENT, + L_TRIPLE_CURLY, + R_TRIPLE_CURLY, HTML_ROOT, HTML_DIRECTIVE, HTML_SELF_CLOSING_TAG, @@ -70,12 +81,36 @@ pub enum HtmlSyntaxKind { SVELTE_DEBUG_BLOCK, SVELTE_BINDING_LIST, SVELTE_NAME, + GLIMMER_MUSTACHE_EXPRESSION, + GLIMMER_MUSTACHE_COMMENT, + GLIMMER_TRIPLE_STASH_EXPRESSION, + GLIMMER_BLOCK_HELPER, + GLIMMER_BLOCK_HELPER_OPENING, + GLIMMER_BLOCK_HELPER_CLOSING, + GLIMMER_BLOCK_PARAMS, + GLIMMER_BLOCK_PARAM_LIST, + GLIMMER_BLOCK_PARAM, + GLIMMER_PATH, + GLIMMER_PATH_SEGMENT_LIST, + GLIMMER_PATH_SEGMENT, + GLIMMER_ARGUMENT_LIST, + GLIMMER_POSITIONAL_ARGUMENT, + GLIMMER_NAMED_ARGUMENT, + GLIMMER_SUBEXPRESSION, + GLIMMER_STRING_LITERAL, + GLIMMER_LITERAL, + GLIMMER_SPLATTRIBUTE, + GLIMMER_ELEMENT_MODIFIER, + GLIMMER_NAMED_BLOCK, + GLIMMER_NAMED_BLOCK_OPENING, + GLIMMER_NAMED_BLOCK_CLOSING, HTML_BOGUS, HTML_BOGUS_ELEMENT, HTML_BOGUS_ATTRIBUTE, HTML_BOGUS_TEXT_EXPRESSION, ASTRO_BOGUS_FRONTMATTER, SVELTE_BOGUS_BLOCK, + GLIMMER_BOGUS_EXPRESSION, #[doc(hidden)] __LAST, } @@ -102,6 +137,14 @@ impl HtmlSyntaxKind { | SV_CURLY_SLASH | SV_CURLY_COLON | COMMA + | HASH + | DOT + | PIPE + | AT + | DOTDOTDOT + | L_PAREN + | R_PAREN + | COLON ) } pub const fn is_literal(self) -> bool { @@ -110,7 +153,12 @@ impl HtmlSyntaxKind { pub const fn is_list(self) -> bool { matches!( self, - HTML_ELEMENT_LIST | HTML_ATTRIBUTE_LIST | SVELTE_BINDING_LIST + HTML_ELEMENT_LIST + | HTML_ATTRIBUTE_LIST + | SVELTE_BINDING_LIST + | GLIMMER_BLOCK_PARAM_LIST + | GLIMMER_PATH_SEGMENT_LIST + | GLIMMER_ARGUMENT_LIST ) } pub fn from_keyword(ident: &str) -> Option { @@ -145,6 +193,14 @@ impl HtmlSyntaxKind { SV_CURLY_SLASH => "{/", SV_CURLY_COLON => "{:", COMMA => ",", + HASH => "#", + DOT => ".", + PIPE => "|", + AT => "@", + DOTDOTDOT => "...", + L_PAREN => "(", + R_PAREN => ")", + COLON => ":", NULL_KW => "null", TRUE_KW => "true", FALSE_KW => "false", @@ -160,4 +216,4 @@ impl HtmlSyntaxKind { } #[doc = r" Utility macro for creating a SyntaxKind through simple macro syntax"] #[macro_export] -macro_rules ! T { [<] => { $ crate :: HtmlSyntaxKind :: L_ANGLE } ; [>] => { $ crate :: HtmlSyntaxKind :: R_ANGLE } ; [/] => { $ crate :: HtmlSyntaxKind :: SLASH } ; [=] => { $ crate :: HtmlSyntaxKind :: EQ } ; [!] => { $ crate :: HtmlSyntaxKind :: BANG } ; [-] => { $ crate :: HtmlSyntaxKind :: MINUS } ; [" { $ crate :: HtmlSyntaxKind :: CDATA_START } ; ["]]>"] => { $ crate :: HtmlSyntaxKind :: CDATA_END } ; [---] => { $ crate :: HtmlSyntaxKind :: FENCE } ; ['{'] => { $ crate :: HtmlSyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: HtmlSyntaxKind :: R_CURLY } ; ["{{"] => { $ crate :: HtmlSyntaxKind :: L_DOUBLE_CURLY } ; ["}}"] => { $ crate :: HtmlSyntaxKind :: R_DOUBLE_CURLY } ; ["{@"] => { $ crate :: HtmlSyntaxKind :: SV_CURLY_AT } ; ["{#"] => { $ crate :: HtmlSyntaxKind :: SV_CURLY_HASH } ; ["{/"] => { $ crate :: HtmlSyntaxKind :: SV_CURLY_SLASH } ; ["{:"] => { $ crate :: HtmlSyntaxKind :: SV_CURLY_COLON } ; [,] => { $ crate :: HtmlSyntaxKind :: COMMA } ; [null] => { $ crate :: HtmlSyntaxKind :: NULL_KW } ; [true] => { $ crate :: HtmlSyntaxKind :: TRUE_KW } ; [false] => { $ crate :: HtmlSyntaxKind :: FALSE_KW } ; [doctype] => { $ crate :: HtmlSyntaxKind :: DOCTYPE_KW } ; [html] => { $ crate :: HtmlSyntaxKind :: HTML_KW } ; [debug] => { $ crate :: HtmlSyntaxKind :: DEBUG_KW } ; [ident] => { $ crate :: HtmlSyntaxKind :: IDENT } ; [EOF] => { $ crate :: HtmlSyntaxKind :: EOF } ; [UNICODE_BOM] => { $ crate :: HtmlSyntaxKind :: UNICODE_BOM } ; [#] => { $ crate :: HtmlSyntaxKind :: HASH } ; } +macro_rules ! T { [<] => { $ crate :: HtmlSyntaxKind :: L_ANGLE } ; [>] => { $ crate :: HtmlSyntaxKind :: R_ANGLE } ; [/] => { $ crate :: HtmlSyntaxKind :: SLASH } ; [=] => { $ crate :: HtmlSyntaxKind :: EQ } ; [!] => { $ crate :: HtmlSyntaxKind :: BANG } ; [-] => { $ crate :: HtmlSyntaxKind :: MINUS } ; [" { $ crate :: HtmlSyntaxKind :: CDATA_START } ; ["]]>"] => { $ crate :: HtmlSyntaxKind :: CDATA_END } ; [---] => { $ crate :: HtmlSyntaxKind :: FENCE } ; ['{'] => { $ crate :: HtmlSyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: HtmlSyntaxKind :: R_CURLY } ; ["{{"] => { $ crate :: HtmlSyntaxKind :: L_DOUBLE_CURLY } ; ["}}"] => { $ crate :: HtmlSyntaxKind :: R_DOUBLE_CURLY } ; ["{@"] => { $ crate :: HtmlSyntaxKind :: SV_CURLY_AT } ; ["{#"] => { $ crate :: HtmlSyntaxKind :: SV_CURLY_HASH } ; ["{/"] => { $ crate :: HtmlSyntaxKind :: SV_CURLY_SLASH } ; ["{:"] => { $ crate :: HtmlSyntaxKind :: SV_CURLY_COLON } ; [,] => { $ crate :: HtmlSyntaxKind :: COMMA } ; [#] => { $ crate :: HtmlSyntaxKind :: HASH } ; [.] => { $ crate :: HtmlSyntaxKind :: DOT } ; [|] => { $ crate :: HtmlSyntaxKind :: PIPE } ; [@] => { $ crate :: HtmlSyntaxKind :: AT } ; [...] => { $ crate :: HtmlSyntaxKind :: DOTDOTDOT } ; ['('] => { $ crate :: HtmlSyntaxKind :: L_PAREN } ; [')'] => { $ crate :: HtmlSyntaxKind :: R_PAREN } ; [:] => { $ crate :: HtmlSyntaxKind :: COLON } ; [null] => { $ crate :: HtmlSyntaxKind :: NULL_KW } ; [true] => { $ crate :: HtmlSyntaxKind :: TRUE_KW } ; [false] => { $ crate :: HtmlSyntaxKind :: FALSE_KW } ; [doctype] => { $ crate :: HtmlSyntaxKind :: DOCTYPE_KW } ; [html] => { $ crate :: HtmlSyntaxKind :: HTML_KW } ; [debug] => { $ crate :: HtmlSyntaxKind :: DEBUG_KW } ; [ident] => { $ crate :: HtmlSyntaxKind :: IDENT } ; [EOF] => { $ crate :: HtmlSyntaxKind :: EOF } ; [UNICODE_BOM] => { $ crate :: HtmlSyntaxKind :: UNICODE_BOM } ; [#] => { $ crate :: HtmlSyntaxKind :: HASH } ; } diff --git a/crates/biome_html_syntax/src/generated/macros.rs b/crates/biome_html_syntax/src/generated/macros.rs index 104c566738e0..0a039462d9ac 100644 --- a/crates/biome_html_syntax/src/generated/macros.rs +++ b/crates/biome_html_syntax/src/generated/macros.rs @@ -24,6 +24,91 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::AstroFrontmatterElement::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::GLIMMER_BLOCK_HELPER => { + let $pattern = unsafe { $crate::GlimmerBlockHelper::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_BLOCK_HELPER_CLOSING => { + let $pattern = + unsafe { $crate::GlimmerBlockHelperClosing::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_BLOCK_HELPER_OPENING => { + let $pattern = + unsafe { $crate::GlimmerBlockHelperOpening::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_BLOCK_PARAM => { + let $pattern = unsafe { $crate::GlimmerBlockParam::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_BLOCK_PARAMS => { + let $pattern = unsafe { $crate::GlimmerBlockParams::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_ELEMENT_MODIFIER => { + let $pattern = unsafe { $crate::GlimmerElementModifier::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_LITERAL => { + let $pattern = unsafe { $crate::GlimmerLiteral::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_MUSTACHE_COMMENT => { + let $pattern = unsafe { $crate::GlimmerMustacheComment::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_MUSTACHE_EXPRESSION => { + let $pattern = + unsafe { $crate::GlimmerMustacheExpression::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_NAMED_ARGUMENT => { + let $pattern = unsafe { $crate::GlimmerNamedArgument::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_NAMED_BLOCK => { + let $pattern = unsafe { $crate::GlimmerNamedBlock::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_NAMED_BLOCK_CLOSING => { + let $pattern = unsafe { $crate::GlimmerNamedBlockClosing::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_NAMED_BLOCK_OPENING => { + let $pattern = unsafe { $crate::GlimmerNamedBlockOpening::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_PATH => { + let $pattern = unsafe { $crate::GlimmerPath::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_PATH_SEGMENT => { + let $pattern = unsafe { $crate::GlimmerPathSegment::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_POSITIONAL_ARGUMENT => { + let $pattern = + unsafe { $crate::GlimmerPositionalArgument::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_SPLATTRIBUTE => { + let $pattern = unsafe { $crate::GlimmerSplattribute::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_STRING_LITERAL => { + let $pattern = unsafe { $crate::GlimmerStringLiteral::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_SUBEXPRESSION => { + let $pattern = unsafe { $crate::GlimmerSubexpression::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_TRIPLE_STASH_EXPRESSION => { + let $pattern = + unsafe { $crate::GlimmerTripleStashExpression::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::HTML_ATTRIBUTE => { let $pattern = unsafe { $crate::HtmlAttribute::new_unchecked(node) }; $body @@ -105,6 +190,10 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::AstroBogusFrontmatter::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::GLIMMER_BOGUS_EXPRESSION => { + let $pattern = unsafe { $crate::GlimmerBogusExpression::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::HTML_BOGUS => { let $pattern = unsafe { $crate::HtmlBogus::new_unchecked(node) }; $body @@ -125,6 +214,18 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::SvelteBogusBlock::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::GLIMMER_ARGUMENT_LIST => { + let $pattern = unsafe { $crate::GlimmerArgumentList::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_BLOCK_PARAM_LIST => { + let $pattern = unsafe { $crate::GlimmerBlockParamList::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::GLIMMER_PATH_SEGMENT_LIST => { + let $pattern = unsafe { $crate::GlimmerPathSegmentList::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::HTML_ATTRIBUTE_LIST => { let $pattern = unsafe { $crate::HtmlAttributeList::new_unchecked(node) }; $body diff --git a/crates/biome_html_syntax/src/generated/nodes.rs b/crates/biome_html_syntax/src/generated/nodes.rs index 188d31eeada9..199a8fa33098 100644 --- a/crates/biome_html_syntax/src/generated/nodes.rs +++ b/crates/biome_html_syntax/src/generated/nodes.rs @@ -100,10 +100,10 @@ pub struct AstroFrontmatterElementFields { pub r_fence_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlAttribute { +pub struct GlimmerBlockHelper { pub(crate) syntax: SyntaxNode, } -impl HtmlAttribute { +impl GlimmerBlockHelper { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -113,20 +113,24 @@ impl HtmlAttribute { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlAttributeFields { - HtmlAttributeFields { - name: self.name(), - initializer: self.initializer(), + pub fn as_fields(&self) -> GlimmerBlockHelperFields { + GlimmerBlockHelperFields { + opening: self.opening(), + children: self.children(), + closing: self.closing(), } } - pub fn name(&self) -> SyntaxResult { + pub fn opening(&self) -> SyntaxResult { support::required_node(&self.syntax, 0usize) } - pub fn initializer(&self) -> Option { - support::node(&self.syntax, 1usize) + pub fn children(&self) -> HtmlElementList { + support::list(&self.syntax, 1usize) + } + pub fn closing(&self) -> SyntaxResult { + support::required_node(&self.syntax, 2usize) } } -impl Serialize for HtmlAttribute { +impl Serialize for GlimmerBlockHelper { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -135,15 +139,16 @@ impl Serialize for HtmlAttribute { } } #[derive(Serialize)] -pub struct HtmlAttributeFields { - pub name: SyntaxResult, - pub initializer: Option, +pub struct GlimmerBlockHelperFields { + pub opening: SyntaxResult, + pub children: HtmlElementList, + pub closing: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlAttributeInitializerClause { +pub struct GlimmerBlockHelperClosing { pub(crate) syntax: SyntaxNode, } -impl HtmlAttributeInitializerClause { +impl GlimmerBlockHelperClosing { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -153,20 +158,28 @@ impl HtmlAttributeInitializerClause { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlAttributeInitializerClauseFields { - HtmlAttributeInitializerClauseFields { - eq_token: self.eq_token(), - value: self.value(), + pub fn as_fields(&self) -> GlimmerBlockHelperClosingFields { + GlimmerBlockHelperClosingFields { + l_curly2_token_token: self.l_curly2_token_token(), + slash_token_token: self.slash_token_token(), + helper: self.helper(), + r_curly2_token_token: self.r_curly2_token_token(), } } - pub fn eq_token(&self) -> SyntaxResult { + pub fn l_curly2_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn value(&self) -> SyntaxResult { - support::required_node(&self.syntax, 1usize) + pub fn slash_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } + pub fn helper(&self) -> SyntaxResult { + support::required_node(&self.syntax, 2usize) + } + pub fn r_curly2_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 3usize) } } -impl Serialize for HtmlAttributeInitializerClause { +impl Serialize for GlimmerBlockHelperClosing { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -175,15 +188,17 @@ impl Serialize for HtmlAttributeInitializerClause { } } #[derive(Serialize)] -pub struct HtmlAttributeInitializerClauseFields { - pub eq_token: SyntaxResult, - pub value: SyntaxResult, +pub struct GlimmerBlockHelperClosingFields { + pub l_curly2_token_token: SyntaxResult, + pub slash_token_token: SyntaxResult, + pub helper: SyntaxResult, + pub r_curly2_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlAttributeName { +pub struct GlimmerBlockHelperOpening { pub(crate) syntax: SyntaxNode, } -impl HtmlAttributeName { +impl GlimmerBlockHelperOpening { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -193,16 +208,36 @@ impl HtmlAttributeName { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlAttributeNameFields { - HtmlAttributeNameFields { - value_token: self.value_token(), + pub fn as_fields(&self) -> GlimmerBlockHelperOpeningFields { + GlimmerBlockHelperOpeningFields { + l_curly2_token_token: self.l_curly2_token_token(), + hash_token_token: self.hash_token_token(), + helper: self.helper(), + arguments: self.arguments(), + block_params: self.block_params(), + r_curly2_token_token: self.r_curly2_token_token(), } } - pub fn value_token(&self) -> SyntaxResult { + pub fn l_curly2_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } + pub fn hash_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } + pub fn helper(&self) -> SyntaxResult { + support::required_node(&self.syntax, 2usize) + } + pub fn arguments(&self) -> GlimmerArgumentList { + support::list(&self.syntax, 3usize) + } + pub fn block_params(&self) -> Option { + support::node(&self.syntax, 4usize) + } + pub fn r_curly2_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 5usize) + } } -impl Serialize for HtmlAttributeName { +impl Serialize for GlimmerBlockHelperOpening { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -211,14 +246,19 @@ impl Serialize for HtmlAttributeName { } } #[derive(Serialize)] -pub struct HtmlAttributeNameFields { - pub value_token: SyntaxResult, +pub struct GlimmerBlockHelperOpeningFields { + pub l_curly2_token_token: SyntaxResult, + pub hash_token_token: SyntaxResult, + pub helper: SyntaxResult, + pub arguments: GlimmerArgumentList, + pub block_params: Option, + pub r_curly2_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlCdataSection { +pub struct GlimmerBlockParam { pub(crate) syntax: SyntaxNode, } -impl HtmlCdataSection { +impl GlimmerBlockParam { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -228,24 +268,16 @@ impl HtmlCdataSection { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlCdataSectionFields { - HtmlCdataSectionFields { - cdata_start_token: self.cdata_start_token(), - content_token: self.content_token(), - cdata_end_token: self.cdata_end_token(), + pub fn as_fields(&self) -> GlimmerBlockParamFields { + GlimmerBlockParamFields { + name_token_token: self.name_token_token(), } } - pub fn cdata_start_token(&self) -> SyntaxResult { + pub fn name_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn content_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 1usize) - } - pub fn cdata_end_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 2usize) - } } -impl Serialize for HtmlCdataSection { +impl Serialize for GlimmerBlockParam { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -254,16 +286,14 @@ impl Serialize for HtmlCdataSection { } } #[derive(Serialize)] -pub struct HtmlCdataSectionFields { - pub cdata_start_token: SyntaxResult, - pub content_token: SyntaxResult, - pub cdata_end_token: SyntaxResult, +pub struct GlimmerBlockParamFields { + pub name_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlClosingElement { +pub struct GlimmerBlockParams { pub(crate) syntax: SyntaxNode, } -impl HtmlClosingElement { +impl GlimmerBlockParams { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -273,28 +303,28 @@ impl HtmlClosingElement { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlClosingElementFields { - HtmlClosingElementFields { - l_angle_token: self.l_angle_token(), - slash_token: self.slash_token(), - name: self.name(), - r_angle_token: self.r_angle_token(), + pub fn as_fields(&self) -> GlimmerBlockParamsFields { + GlimmerBlockParamsFields { + as_token_token: self.as_token_token(), + l_pipe_token_token: self.l_pipe_token_token(), + params: self.params(), + r_pipe_token_token: self.r_pipe_token_token(), } } - pub fn l_angle_token(&self) -> SyntaxResult { + pub fn as_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn slash_token(&self) -> SyntaxResult { + pub fn l_pipe_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 1usize) } - pub fn name(&self) -> SyntaxResult { - support::required_node(&self.syntax, 2usize) + pub fn params(&self) -> GlimmerBlockParamList { + support::list(&self.syntax, 2usize) } - pub fn r_angle_token(&self) -> SyntaxResult { + pub fn r_pipe_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 3usize) } } -impl Serialize for HtmlClosingElement { +impl Serialize for GlimmerBlockParams { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -303,17 +333,17 @@ impl Serialize for HtmlClosingElement { } } #[derive(Serialize)] -pub struct HtmlClosingElementFields { - pub l_angle_token: SyntaxResult, - pub slash_token: SyntaxResult, - pub name: SyntaxResult, - pub r_angle_token: SyntaxResult, +pub struct GlimmerBlockParamsFields { + pub as_token_token: SyntaxResult, + pub l_pipe_token_token: SyntaxResult, + pub params: GlimmerBlockParamList, + pub r_pipe_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlContent { +pub struct GlimmerElementModifier { pub(crate) syntax: SyntaxNode, } -impl HtmlContent { +impl GlimmerElementModifier { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -323,16 +353,28 @@ impl HtmlContent { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlContentFields { - HtmlContentFields { - value_token: self.value_token(), + pub fn as_fields(&self) -> GlimmerElementModifierFields { + GlimmerElementModifierFields { + l_curly2_token_token: self.l_curly2_token_token(), + path: self.path(), + arguments: self.arguments(), + r_curly2_token_token: self.r_curly2_token_token(), } } - pub fn value_token(&self) -> SyntaxResult { + pub fn l_curly2_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } + pub fn path(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } + pub fn arguments(&self) -> GlimmerArgumentList { + support::list(&self.syntax, 2usize) + } + pub fn r_curly2_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 3usize) + } } -impl Serialize for HtmlContent { +impl Serialize for GlimmerElementModifier { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -341,14 +383,17 @@ impl Serialize for HtmlContent { } } #[derive(Serialize)] -pub struct HtmlContentFields { - pub value_token: SyntaxResult, +pub struct GlimmerElementModifierFields { + pub l_curly2_token_token: SyntaxResult, + pub path: SyntaxResult, + pub arguments: GlimmerArgumentList, + pub r_curly2_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlDirective { +pub struct GlimmerLiteral { pub(crate) syntax: SyntaxNode, } -impl HtmlDirective { +impl GlimmerLiteral { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -358,44 +403,51 @@ impl HtmlDirective { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlDirectiveFields { - HtmlDirectiveFields { - l_angle_token: self.l_angle_token(), - excl_token: self.excl_token(), - doctype_token: self.doctype_token(), - html_token: self.html_token(), - quirk_token: self.quirk_token(), - public_id_token: self.public_id_token(), - system_id_token: self.system_id_token(), - r_angle_token: self.r_angle_token(), + pub fn as_fields(&self) -> GlimmerLiteralFields { + GlimmerLiteralFields { + value_token_token: self.value_token_token(), } } - pub fn l_angle_token(&self) -> SyntaxResult { + pub fn value_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn excl_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 1usize) - } - pub fn doctype_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 2usize) - } - pub fn html_token(&self) -> Option { - support::token(&self.syntax, 3usize) - } - pub fn quirk_token(&self) -> Option { - support::token(&self.syntax, 4usize) +} +impl Serialize for GlimmerLiteral { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) } - pub fn public_id_token(&self) -> Option { - support::token(&self.syntax, 5usize) +} +#[derive(Serialize)] +pub struct GlimmerLiteralFields { + pub value_token_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct GlimmerMustacheComment { + pub(crate) syntax: SyntaxNode, +} +impl GlimmerMustacheComment { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } } - pub fn system_id_token(&self) -> Option { - support::token(&self.syntax, 6usize) + pub fn as_fields(&self) -> GlimmerMustacheCommentFields { + GlimmerMustacheCommentFields { + comment_token_token: self.comment_token_token(), + } } - pub fn r_angle_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 7usize) + pub fn comment_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) } } -impl Serialize for HtmlDirective { +impl Serialize for GlimmerMustacheComment { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -404,21 +456,14 @@ impl Serialize for HtmlDirective { } } #[derive(Serialize)] -pub struct HtmlDirectiveFields { - pub l_angle_token: SyntaxResult, - pub excl_token: SyntaxResult, - pub doctype_token: SyntaxResult, - pub html_token: Option, - pub quirk_token: Option, - pub public_id_token: Option, - pub system_id_token: Option, - pub r_angle_token: SyntaxResult, +pub struct GlimmerMustacheCommentFields { + pub comment_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlDoubleTextExpression { +pub struct GlimmerMustacheExpression { pub(crate) syntax: SyntaxNode, } -impl HtmlDoubleTextExpression { +impl GlimmerMustacheExpression { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -428,24 +473,28 @@ impl HtmlDoubleTextExpression { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlDoubleTextExpressionFields { - HtmlDoubleTextExpressionFields { - l_double_curly_token: self.l_double_curly_token(), - expression: self.expression(), - r_double_curly_token: self.r_double_curly_token(), + pub fn as_fields(&self) -> GlimmerMustacheExpressionFields { + GlimmerMustacheExpressionFields { + l_curly2_token_token: self.l_curly2_token_token(), + path: self.path(), + arguments: self.arguments(), + r_curly2_token_token: self.r_curly2_token_token(), } } - pub fn l_double_curly_token(&self) -> SyntaxResult { + pub fn l_curly2_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn expression(&self) -> SyntaxResult { + pub fn path(&self) -> SyntaxResult { support::required_node(&self.syntax, 1usize) } - pub fn r_double_curly_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 2usize) + pub fn arguments(&self) -> GlimmerArgumentList { + support::list(&self.syntax, 2usize) + } + pub fn r_curly2_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 3usize) } } -impl Serialize for HtmlDoubleTextExpression { +impl Serialize for GlimmerMustacheExpression { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -454,16 +503,17 @@ impl Serialize for HtmlDoubleTextExpression { } } #[derive(Serialize)] -pub struct HtmlDoubleTextExpressionFields { - pub l_double_curly_token: SyntaxResult, - pub expression: SyntaxResult, - pub r_double_curly_token: SyntaxResult, +pub struct GlimmerMustacheExpressionFields { + pub l_curly2_token_token: SyntaxResult, + pub path: SyntaxResult, + pub arguments: GlimmerArgumentList, + pub r_curly2_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlElement { +pub struct GlimmerNamedArgument { pub(crate) syntax: SyntaxNode, } -impl HtmlElement { +impl GlimmerNamedArgument { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -473,24 +523,24 @@ impl HtmlElement { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlElementFields { - HtmlElementFields { - opening_element: self.opening_element(), - children: self.children(), - closing_element: self.closing_element(), + pub fn as_fields(&self) -> GlimmerNamedArgumentFields { + GlimmerNamedArgumentFields { + name_token_token: self.name_token_token(), + eq_token_token: self.eq_token_token(), + value: self.value(), } } - pub fn opening_element(&self) -> SyntaxResult { - support::required_node(&self.syntax, 0usize) + pub fn name_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) } - pub fn children(&self) -> HtmlElementList { - support::list(&self.syntax, 1usize) + pub fn eq_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) } - pub fn closing_element(&self) -> SyntaxResult { + pub fn value(&self) -> SyntaxResult { support::required_node(&self.syntax, 2usize) } } -impl Serialize for HtmlElement { +impl Serialize for GlimmerNamedArgument { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -499,16 +549,16 @@ impl Serialize for HtmlElement { } } #[derive(Serialize)] -pub struct HtmlElementFields { - pub opening_element: SyntaxResult, - pub children: HtmlElementList, - pub closing_element: SyntaxResult, +pub struct GlimmerNamedArgumentFields { + pub name_token_token: SyntaxResult, + pub eq_token_token: SyntaxResult, + pub value: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlEmbeddedContent { +pub struct GlimmerNamedBlock { pub(crate) syntax: SyntaxNode, } -impl HtmlEmbeddedContent { +impl GlimmerNamedBlock { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -518,16 +568,24 @@ impl HtmlEmbeddedContent { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlEmbeddedContentFields { - HtmlEmbeddedContentFields { - value_token: self.value_token(), + pub fn as_fields(&self) -> GlimmerNamedBlockFields { + GlimmerNamedBlockFields { + opening: self.opening(), + children: self.children(), + closing: self.closing(), } } - pub fn value_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 0usize) + pub fn opening(&self) -> SyntaxResult { + support::required_node(&self.syntax, 0usize) + } + pub fn children(&self) -> HtmlElementList { + support::list(&self.syntax, 1usize) + } + pub fn closing(&self) -> SyntaxResult { + support::required_node(&self.syntax, 2usize) } } -impl Serialize for HtmlEmbeddedContent { +impl Serialize for GlimmerNamedBlock { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -536,14 +594,16 @@ impl Serialize for HtmlEmbeddedContent { } } #[derive(Serialize)] -pub struct HtmlEmbeddedContentFields { - pub value_token: SyntaxResult, +pub struct GlimmerNamedBlockFields { + pub opening: SyntaxResult, + pub children: HtmlElementList, + pub closing: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlOpeningElement { +pub struct GlimmerNamedBlockClosing { pub(crate) syntax: SyntaxNode, } -impl HtmlOpeningElement { +impl GlimmerNamedBlockClosing { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -553,28 +613,32 @@ impl HtmlOpeningElement { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlOpeningElementFields { - HtmlOpeningElementFields { - l_angle_token: self.l_angle_token(), - name: self.name(), - attributes: self.attributes(), - r_angle_token: self.r_angle_token(), + pub fn as_fields(&self) -> GlimmerNamedBlockClosingFields { + GlimmerNamedBlockClosingFields { + l_angle_token_token: self.l_angle_token_token(), + slash_token_token: self.slash_token_token(), + colon_token_token: self.colon_token_token(), + name_token_token: self.name_token_token(), + r_angle_token_token: self.r_angle_token_token(), } } - pub fn l_angle_token(&self) -> SyntaxResult { + pub fn l_angle_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn name(&self) -> SyntaxResult { - support::required_node(&self.syntax, 1usize) + pub fn slash_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) } - pub fn attributes(&self) -> HtmlAttributeList { - support::list(&self.syntax, 2usize) + pub fn colon_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 2usize) } - pub fn r_angle_token(&self) -> SyntaxResult { + pub fn name_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 3usize) } + pub fn r_angle_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 4usize) + } } -impl Serialize for HtmlOpeningElement { +impl Serialize for GlimmerNamedBlockClosing { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -583,17 +647,18 @@ impl Serialize for HtmlOpeningElement { } } #[derive(Serialize)] -pub struct HtmlOpeningElementFields { - pub l_angle_token: SyntaxResult, - pub name: SyntaxResult, - pub attributes: HtmlAttributeList, - pub r_angle_token: SyntaxResult, +pub struct GlimmerNamedBlockClosingFields { + pub l_angle_token_token: SyntaxResult, + pub slash_token_token: SyntaxResult, + pub colon_token_token: SyntaxResult, + pub name_token_token: SyntaxResult, + pub r_angle_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlRoot { +pub struct GlimmerNamedBlockOpening { pub(crate) syntax: SyntaxNode, } -impl HtmlRoot { +impl GlimmerNamedBlockOpening { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -603,32 +668,32 @@ impl HtmlRoot { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlRootFields { - HtmlRootFields { - bom_token: self.bom_token(), - frontmatter: self.frontmatter(), - directive: self.directive(), - html: self.html(), - eof_token: self.eof_token(), + pub fn as_fields(&self) -> GlimmerNamedBlockOpeningFields { + GlimmerNamedBlockOpeningFields { + l_angle_token_token: self.l_angle_token_token(), + colon_token_token: self.colon_token_token(), + name_token_token: self.name_token_token(), + attributes: self.attributes(), + r_angle_token_token: self.r_angle_token_token(), } } - pub fn bom_token(&self) -> Option { - support::token(&self.syntax, 0usize) + pub fn l_angle_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) } - pub fn frontmatter(&self) -> Option { - support::node(&self.syntax, 1usize) + pub fn colon_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) } - pub fn directive(&self) -> Option { - support::node(&self.syntax, 2usize) + pub fn name_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 2usize) } - pub fn html(&self) -> HtmlElementList { + pub fn attributes(&self) -> HtmlAttributeList { support::list(&self.syntax, 3usize) } - pub fn eof_token(&self) -> SyntaxResult { + pub fn r_angle_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 4usize) } } -impl Serialize for HtmlRoot { +impl Serialize for GlimmerNamedBlockOpening { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -637,18 +702,18 @@ impl Serialize for HtmlRoot { } } #[derive(Serialize)] -pub struct HtmlRootFields { - pub bom_token: Option, - pub frontmatter: Option, - pub directive: Option, - pub html: HtmlElementList, - pub eof_token: SyntaxResult, +pub struct GlimmerNamedBlockOpeningFields { + pub l_angle_token_token: SyntaxResult, + pub colon_token_token: SyntaxResult, + pub name_token_token: SyntaxResult, + pub attributes: HtmlAttributeList, + pub r_angle_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlSelfClosingElement { +pub struct GlimmerPath { pub(crate) syntax: SyntaxNode, } -impl HtmlSelfClosingElement { +impl GlimmerPath { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -658,32 +723,20 @@ impl HtmlSelfClosingElement { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlSelfClosingElementFields { - HtmlSelfClosingElementFields { - l_angle_token: self.l_angle_token(), - name: self.name(), - attributes: self.attributes(), - slash_token: self.slash_token(), - r_angle_token: self.r_angle_token(), + pub fn as_fields(&self) -> GlimmerPathFields { + GlimmerPathFields { + at_token_token: self.at_token_token(), + segments: self.segments(), } } - pub fn l_angle_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 0usize) - } - pub fn name(&self) -> SyntaxResult { - support::required_node(&self.syntax, 1usize) - } - pub fn attributes(&self) -> HtmlAttributeList { - support::list(&self.syntax, 2usize) - } - pub fn slash_token(&self) -> Option { - support::token(&self.syntax, 3usize) + pub fn at_token_token(&self) -> Option { + support::token(&self.syntax, 0usize) } - pub fn r_angle_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 4usize) + pub fn segments(&self) -> GlimmerPathSegmentList { + support::list(&self.syntax, 1usize) } } -impl Serialize for HtmlSelfClosingElement { +impl Serialize for GlimmerPath { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -692,18 +745,15 @@ impl Serialize for HtmlSelfClosingElement { } } #[derive(Serialize)] -pub struct HtmlSelfClosingElementFields { - pub l_angle_token: SyntaxResult, - pub name: SyntaxResult, - pub attributes: HtmlAttributeList, - pub slash_token: Option, - pub r_angle_token: SyntaxResult, +pub struct GlimmerPathFields { + pub at_token_token: Option, + pub segments: GlimmerPathSegmentList, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlSingleTextExpression { +pub struct GlimmerPathSegment { pub(crate) syntax: SyntaxNode, } -impl HtmlSingleTextExpression { +impl GlimmerPathSegment { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -713,24 +763,16 @@ impl HtmlSingleTextExpression { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlSingleTextExpressionFields { - HtmlSingleTextExpressionFields { - l_curly_token: self.l_curly_token(), - expression: self.expression(), - r_curly_token: self.r_curly_token(), + pub fn as_fields(&self) -> GlimmerPathSegmentFields { + GlimmerPathSegmentFields { + value_token_token: self.value_token_token(), } } - pub fn l_curly_token(&self) -> SyntaxResult { + pub fn value_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn expression(&self) -> SyntaxResult { - support::required_node(&self.syntax, 1usize) - } - pub fn r_curly_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 2usize) - } } -impl Serialize for HtmlSingleTextExpression { +impl Serialize for GlimmerPathSegment { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -739,16 +781,14 @@ impl Serialize for HtmlSingleTextExpression { } } #[derive(Serialize)] -pub struct HtmlSingleTextExpressionFields { - pub l_curly_token: SyntaxResult, - pub expression: SyntaxResult, - pub r_curly_token: SyntaxResult, +pub struct GlimmerPathSegmentFields { + pub value_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlString { +pub struct GlimmerPositionalArgument { pub(crate) syntax: SyntaxNode, } -impl HtmlString { +impl GlimmerPositionalArgument { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -758,16 +798,16 @@ impl HtmlString { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlStringFields { - HtmlStringFields { - value_token: self.value_token(), + pub fn as_fields(&self) -> GlimmerPositionalArgumentFields { + GlimmerPositionalArgumentFields { + value: self.value(), } } - pub fn value_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 0usize) + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 0usize) } } -impl Serialize for HtmlString { +impl Serialize for GlimmerPositionalArgument { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -776,14 +816,14 @@ impl Serialize for HtmlString { } } #[derive(Serialize)] -pub struct HtmlStringFields { - pub value_token: SyntaxResult, +pub struct GlimmerPositionalArgumentFields { + pub value: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlTagName { +pub struct GlimmerSplattribute { pub(crate) syntax: SyntaxNode, } -impl HtmlTagName { +impl GlimmerSplattribute { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -793,16 +833,20 @@ impl HtmlTagName { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlTagNameFields { - HtmlTagNameFields { - value_token: self.value_token(), + pub fn as_fields(&self) -> GlimmerSplattributeFields { + GlimmerSplattributeFields { + dotdotdot_token_token: self.dotdotdot_token_token(), + attributes_token_token: self.attributes_token_token(), } } - pub fn value_token(&self) -> SyntaxResult { + pub fn dotdotdot_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } + pub fn attributes_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } } -impl Serialize for HtmlTagName { +impl Serialize for GlimmerSplattribute { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -811,14 +855,15 @@ impl Serialize for HtmlTagName { } } #[derive(Serialize)] -pub struct HtmlTagNameFields { - pub value_token: SyntaxResult, +pub struct GlimmerSplattributeFields { + pub dotdotdot_token_token: SyntaxResult, + pub attributes_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct HtmlTextExpression { +pub struct GlimmerStringLiteral { pub(crate) syntax: SyntaxNode, } -impl HtmlTextExpression { +impl GlimmerStringLiteral { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -828,16 +873,16 @@ impl HtmlTextExpression { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> HtmlTextExpressionFields { - HtmlTextExpressionFields { - html_literal_token: self.html_literal_token(), + pub fn as_fields(&self) -> GlimmerStringLiteralFields { + GlimmerStringLiteralFields { + value_token_token: self.value_token_token(), } } - pub fn html_literal_token(&self) -> SyntaxResult { + pub fn value_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } } -impl Serialize for HtmlTextExpression { +impl Serialize for GlimmerStringLiteral { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -846,14 +891,14 @@ impl Serialize for HtmlTextExpression { } } #[derive(Serialize)] -pub struct HtmlTextExpressionFields { - pub html_literal_token: SyntaxResult, +pub struct GlimmerStringLiteralFields { + pub value_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct SvelteDebugBlock { +pub struct GlimmerSubexpression { pub(crate) syntax: SyntaxNode, } -impl SvelteDebugBlock { +impl GlimmerSubexpression { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -863,28 +908,28 @@ impl SvelteDebugBlock { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> SvelteDebugBlockFields { - SvelteDebugBlockFields { - sv_curly_at_token: self.sv_curly_at_token(), - debug_token: self.debug_token(), - bindings: self.bindings(), - r_curly_token: self.r_curly_token(), + pub fn as_fields(&self) -> GlimmerSubexpressionFields { + GlimmerSubexpressionFields { + l_paren_token_token: self.l_paren_token_token(), + path: self.path(), + arguments: self.arguments(), + r_paren_token_token: self.r_paren_token_token(), } } - pub fn sv_curly_at_token(&self) -> SyntaxResult { + pub fn l_paren_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn debug_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 1usize) + pub fn path(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) } - pub fn bindings(&self) -> SvelteBindingList { + pub fn arguments(&self) -> GlimmerArgumentList { support::list(&self.syntax, 2usize) } - pub fn r_curly_token(&self) -> SyntaxResult { + pub fn r_paren_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 3usize) } } -impl Serialize for SvelteDebugBlock { +impl Serialize for GlimmerSubexpression { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -893,17 +938,17 @@ impl Serialize for SvelteDebugBlock { } } #[derive(Serialize)] -pub struct SvelteDebugBlockFields { - pub sv_curly_at_token: SyntaxResult, - pub debug_token: SyntaxResult, - pub bindings: SvelteBindingList, - pub r_curly_token: SyntaxResult, +pub struct GlimmerSubexpressionFields { + pub l_paren_token_token: SyntaxResult, + pub path: SyntaxResult, + pub arguments: GlimmerArgumentList, + pub r_paren_token_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct SvelteName { +pub struct GlimmerTripleStashExpression { pub(crate) syntax: SyntaxNode, } -impl SvelteName { +impl GlimmerTripleStashExpression { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -913,16 +958,28 @@ impl SvelteName { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> SvelteNameFields { - SvelteNameFields { - svelte_ident_token: self.svelte_ident_token(), + pub fn as_fields(&self) -> GlimmerTripleStashExpressionFields { + GlimmerTripleStashExpressionFields { + l_curly3_token_token: self.l_curly3_token_token(), + path: self.path(), + arguments: self.arguments(), + r_curly3_token_token: self.r_curly3_token_token(), } } - pub fn svelte_ident_token(&self) -> SyntaxResult { + pub fn l_curly3_token_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } + pub fn path(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } + pub fn arguments(&self) -> GlimmerArgumentList { + support::list(&self.syntax, 2usize) + } + pub fn r_curly3_token_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 3usize) + } } -impl Serialize for SvelteName { +impl Serialize for GlimmerTripleStashExpression { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -931,204 +988,2209 @@ impl Serialize for SvelteName { } } #[derive(Serialize)] -pub struct SvelteNameFields { - pub svelte_ident_token: SyntaxResult, +pub struct GlimmerTripleStashExpressionFields { + pub l_curly3_token_token: SyntaxResult, + pub path: SyntaxResult, + pub arguments: GlimmerArgumentList, + pub r_curly3_token_token: SyntaxResult, } -#[derive(Clone, PartialEq, Eq, Hash, Serialize)] -pub enum AnyAstroFrontmatterElement { - AstroBogusFrontmatter(AstroBogusFrontmatter), - AstroFrontmatterElement(AstroFrontmatterElement), +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlAttribute { + pub(crate) syntax: SyntaxNode, } -impl AnyAstroFrontmatterElement { - pub fn as_astro_bogus_frontmatter(&self) -> Option<&AstroBogusFrontmatter> { - match &self { - Self::AstroBogusFrontmatter(item) => Some(item), - _ => None, - } - } - pub fn as_astro_frontmatter_element(&self) -> Option<&AstroFrontmatterElement> { - match &self { - Self::AstroFrontmatterElement(item) => Some(item), - _ => None, - } +impl HtmlAttribute { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } } -} -#[derive(Clone, PartialEq, Eq, Hash, Serialize)] -pub enum AnyHtmlAttribute { - HtmlAttribute(HtmlAttribute), - HtmlBogusAttribute(HtmlBogusAttribute), - HtmlDoubleTextExpression(HtmlDoubleTextExpression), - HtmlSingleTextExpression(HtmlSingleTextExpression), -} -impl AnyHtmlAttribute { - pub fn as_html_attribute(&self) -> Option<&HtmlAttribute> { - match &self { - Self::HtmlAttribute(item) => Some(item), - _ => None, + pub fn as_fields(&self) -> HtmlAttributeFields { + HtmlAttributeFields { + name: self.name(), + initializer: self.initializer(), } } - pub fn as_html_bogus_attribute(&self) -> Option<&HtmlBogusAttribute> { - match &self { - Self::HtmlBogusAttribute(item) => Some(item), - _ => None, - } + pub fn name(&self) -> SyntaxResult { + support::required_node(&self.syntax, 0usize) } - pub fn as_html_double_text_expression(&self) -> Option<&HtmlDoubleTextExpression> { - match &self { - Self::HtmlDoubleTextExpression(item) => Some(item), - _ => None, - } + pub fn initializer(&self) -> Option { + support::node(&self.syntax, 1usize) } - pub fn as_html_single_text_expression(&self) -> Option<&HtmlSingleTextExpression> { - match &self { - Self::HtmlSingleTextExpression(item) => Some(item), - _ => None, - } +} +impl Serialize for HtmlAttribute { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) } } -#[derive(Clone, PartialEq, Eq, Hash, Serialize)] -pub enum AnyHtmlAttributeInitializer { - HtmlSingleTextExpression(HtmlSingleTextExpression), - HtmlString(HtmlString), +#[derive(Serialize)] +pub struct HtmlAttributeFields { + pub name: SyntaxResult, + pub initializer: Option, } -impl AnyHtmlAttributeInitializer { - pub fn as_html_single_text_expression(&self) -> Option<&HtmlSingleTextExpression> { - match &self { - Self::HtmlSingleTextExpression(item) => Some(item), - _ => None, - } +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlAttributeInitializerClause { + pub(crate) syntax: SyntaxNode, +} +impl HtmlAttributeInitializerClause { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } } - pub fn as_html_string(&self) -> Option<&HtmlString> { - match &self { - Self::HtmlString(item) => Some(item), - _ => None, + pub fn as_fields(&self) -> HtmlAttributeInitializerClauseFields { + HtmlAttributeInitializerClauseFields { + eq_token: self.eq_token(), + value: self.value(), } } + pub fn eq_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } } -#[derive(Clone, PartialEq, Eq, Hash, Serialize)] -pub enum AnyHtmlContent { +impl Serialize for HtmlAttributeInitializerClause { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlAttributeInitializerClauseFields { + pub eq_token: SyntaxResult, + pub value: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlAttributeName { + pub(crate) syntax: SyntaxNode, +} +impl HtmlAttributeName { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlAttributeNameFields { + HtmlAttributeNameFields { + value_token: self.value_token(), + } + } + pub fn value_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +impl Serialize for HtmlAttributeName { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlAttributeNameFields { + pub value_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlCdataSection { + pub(crate) syntax: SyntaxNode, +} +impl HtmlCdataSection { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlCdataSectionFields { + HtmlCdataSectionFields { + cdata_start_token: self.cdata_start_token(), + content_token: self.content_token(), + cdata_end_token: self.cdata_end_token(), + } + } + pub fn cdata_start_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn content_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } + pub fn cdata_end_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 2usize) + } +} +impl Serialize for HtmlCdataSection { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlCdataSectionFields { + pub cdata_start_token: SyntaxResult, + pub content_token: SyntaxResult, + pub cdata_end_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlClosingElement { + pub(crate) syntax: SyntaxNode, +} +impl HtmlClosingElement { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlClosingElementFields { + HtmlClosingElementFields { + l_angle_token: self.l_angle_token(), + slash_token: self.slash_token(), + name: self.name(), + r_angle_token: self.r_angle_token(), + } + } + pub fn l_angle_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn slash_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } + pub fn name(&self) -> SyntaxResult { + support::required_node(&self.syntax, 2usize) + } + pub fn r_angle_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 3usize) + } +} +impl Serialize for HtmlClosingElement { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlClosingElementFields { + pub l_angle_token: SyntaxResult, + pub slash_token: SyntaxResult, + pub name: SyntaxResult, + pub r_angle_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlContent { + pub(crate) syntax: SyntaxNode, +} +impl HtmlContent { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlContentFields { + HtmlContentFields { + value_token: self.value_token(), + } + } + pub fn value_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +impl Serialize for HtmlContent { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlContentFields { + pub value_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlDirective { + pub(crate) syntax: SyntaxNode, +} +impl HtmlDirective { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlDirectiveFields { + HtmlDirectiveFields { + l_angle_token: self.l_angle_token(), + excl_token: self.excl_token(), + doctype_token: self.doctype_token(), + html_token: self.html_token(), + quirk_token: self.quirk_token(), + public_id_token: self.public_id_token(), + system_id_token: self.system_id_token(), + r_angle_token: self.r_angle_token(), + } + } + pub fn l_angle_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn excl_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } + pub fn doctype_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 2usize) + } + pub fn html_token(&self) -> Option { + support::token(&self.syntax, 3usize) + } + pub fn quirk_token(&self) -> Option { + support::token(&self.syntax, 4usize) + } + pub fn public_id_token(&self) -> Option { + support::token(&self.syntax, 5usize) + } + pub fn system_id_token(&self) -> Option { + support::token(&self.syntax, 6usize) + } + pub fn r_angle_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 7usize) + } +} +impl Serialize for HtmlDirective { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlDirectiveFields { + pub l_angle_token: SyntaxResult, + pub excl_token: SyntaxResult, + pub doctype_token: SyntaxResult, + pub html_token: Option, + pub quirk_token: Option, + pub public_id_token: Option, + pub system_id_token: Option, + pub r_angle_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlDoubleTextExpression { + pub(crate) syntax: SyntaxNode, +} +impl HtmlDoubleTextExpression { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlDoubleTextExpressionFields { + HtmlDoubleTextExpressionFields { + l_double_curly_token: self.l_double_curly_token(), + expression: self.expression(), + r_double_curly_token: self.r_double_curly_token(), + } + } + pub fn l_double_curly_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn expression(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } + pub fn r_double_curly_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 2usize) + } +} +impl Serialize for HtmlDoubleTextExpression { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlDoubleTextExpressionFields { + pub l_double_curly_token: SyntaxResult, + pub expression: SyntaxResult, + pub r_double_curly_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlElement { + pub(crate) syntax: SyntaxNode, +} +impl HtmlElement { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlElementFields { + HtmlElementFields { + opening_element: self.opening_element(), + children: self.children(), + closing_element: self.closing_element(), + } + } + pub fn opening_element(&self) -> SyntaxResult { + support::required_node(&self.syntax, 0usize) + } + pub fn children(&self) -> HtmlElementList { + support::list(&self.syntax, 1usize) + } + pub fn closing_element(&self) -> SyntaxResult { + support::required_node(&self.syntax, 2usize) + } +} +impl Serialize for HtmlElement { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlElementFields { + pub opening_element: SyntaxResult, + pub children: HtmlElementList, + pub closing_element: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlEmbeddedContent { + pub(crate) syntax: SyntaxNode, +} +impl HtmlEmbeddedContent { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlEmbeddedContentFields { + HtmlEmbeddedContentFields { + value_token: self.value_token(), + } + } + pub fn value_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +impl Serialize for HtmlEmbeddedContent { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlEmbeddedContentFields { + pub value_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlOpeningElement { + pub(crate) syntax: SyntaxNode, +} +impl HtmlOpeningElement { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlOpeningElementFields { + HtmlOpeningElementFields { + l_angle_token: self.l_angle_token(), + name: self.name(), + attributes: self.attributes(), + r_angle_token: self.r_angle_token(), + } + } + pub fn l_angle_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn name(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } + pub fn attributes(&self) -> HtmlAttributeList { + support::list(&self.syntax, 2usize) + } + pub fn r_angle_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 3usize) + } +} +impl Serialize for HtmlOpeningElement { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlOpeningElementFields { + pub l_angle_token: SyntaxResult, + pub name: SyntaxResult, + pub attributes: HtmlAttributeList, + pub r_angle_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlRoot { + pub(crate) syntax: SyntaxNode, +} +impl HtmlRoot { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlRootFields { + HtmlRootFields { + bom_token: self.bom_token(), + frontmatter: self.frontmatter(), + directive: self.directive(), + html: self.html(), + eof_token: self.eof_token(), + } + } + pub fn bom_token(&self) -> Option { + support::token(&self.syntax, 0usize) + } + pub fn frontmatter(&self) -> Option { + support::node(&self.syntax, 1usize) + } + pub fn directive(&self) -> Option { + support::node(&self.syntax, 2usize) + } + pub fn html(&self) -> HtmlElementList { + support::list(&self.syntax, 3usize) + } + pub fn eof_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 4usize) + } +} +impl Serialize for HtmlRoot { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlRootFields { + pub bom_token: Option, + pub frontmatter: Option, + pub directive: Option, + pub html: HtmlElementList, + pub eof_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlSelfClosingElement { + pub(crate) syntax: SyntaxNode, +} +impl HtmlSelfClosingElement { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlSelfClosingElementFields { + HtmlSelfClosingElementFields { + l_angle_token: self.l_angle_token(), + name: self.name(), + attributes: self.attributes(), + slash_token: self.slash_token(), + r_angle_token: self.r_angle_token(), + } + } + pub fn l_angle_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn name(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } + pub fn attributes(&self) -> HtmlAttributeList { + support::list(&self.syntax, 2usize) + } + pub fn slash_token(&self) -> Option { + support::token(&self.syntax, 3usize) + } + pub fn r_angle_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 4usize) + } +} +impl Serialize for HtmlSelfClosingElement { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlSelfClosingElementFields { + pub l_angle_token: SyntaxResult, + pub name: SyntaxResult, + pub attributes: HtmlAttributeList, + pub slash_token: Option, + pub r_angle_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlSingleTextExpression { + pub(crate) syntax: SyntaxNode, +} +impl HtmlSingleTextExpression { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlSingleTextExpressionFields { + HtmlSingleTextExpressionFields { + l_curly_token: self.l_curly_token(), + expression: self.expression(), + r_curly_token: self.r_curly_token(), + } + } + pub fn l_curly_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn expression(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } + pub fn r_curly_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 2usize) + } +} +impl Serialize for HtmlSingleTextExpression { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlSingleTextExpressionFields { + pub l_curly_token: SyntaxResult, + pub expression: SyntaxResult, + pub r_curly_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlString { + pub(crate) syntax: SyntaxNode, +} +impl HtmlString { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlStringFields { + HtmlStringFields { + value_token: self.value_token(), + } + } + pub fn value_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +impl Serialize for HtmlString { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlStringFields { + pub value_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlTagName { + pub(crate) syntax: SyntaxNode, +} +impl HtmlTagName { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlTagNameFields { + HtmlTagNameFields { + value_token: self.value_token(), + } + } + pub fn value_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +impl Serialize for HtmlTagName { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlTagNameFields { + pub value_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HtmlTextExpression { + pub(crate) syntax: SyntaxNode, +} +impl HtmlTextExpression { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> HtmlTextExpressionFields { + HtmlTextExpressionFields { + html_literal_token: self.html_literal_token(), + } + } + pub fn html_literal_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +impl Serialize for HtmlTextExpression { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct HtmlTextExpressionFields { + pub html_literal_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteDebugBlock { + pub(crate) syntax: SyntaxNode, +} +impl SvelteDebugBlock { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> SvelteDebugBlockFields { + SvelteDebugBlockFields { + sv_curly_at_token: self.sv_curly_at_token(), + debug_token: self.debug_token(), + bindings: self.bindings(), + r_curly_token: self.r_curly_token(), + } + } + pub fn sv_curly_at_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn debug_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } + pub fn bindings(&self) -> SvelteBindingList { + support::list(&self.syntax, 2usize) + } + pub fn r_curly_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 3usize) + } +} +impl Serialize for SvelteDebugBlock { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteDebugBlockFields { + pub sv_curly_at_token: SyntaxResult, + pub debug_token: SyntaxResult, + pub bindings: SvelteBindingList, + pub r_curly_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteName { + pub(crate) syntax: SyntaxNode, +} +impl SvelteName { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> SvelteNameFields { + SvelteNameFields { + svelte_ident_token: self.svelte_ident_token(), + } + } + pub fn svelte_ident_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +impl Serialize for SvelteName { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteNameFields { + pub svelte_ident_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyAstroFrontmatterElement { + AstroBogusFrontmatter(AstroBogusFrontmatter), + AstroFrontmatterElement(AstroFrontmatterElement), +} +impl AnyAstroFrontmatterElement { + pub fn as_astro_bogus_frontmatter(&self) -> Option<&AstroBogusFrontmatter> { + match &self { + Self::AstroBogusFrontmatter(item) => Some(item), + _ => None, + } + } + pub fn as_astro_frontmatter_element(&self) -> Option<&AstroFrontmatterElement> { + match &self { + Self::AstroFrontmatterElement(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyGlimmerArgument { + GlimmerNamedArgument(GlimmerNamedArgument), + GlimmerPositionalArgument(GlimmerPositionalArgument), +} +impl AnyGlimmerArgument { + pub fn as_glimmer_named_argument(&self) -> Option<&GlimmerNamedArgument> { + match &self { + Self::GlimmerNamedArgument(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_positional_argument(&self) -> Option<&GlimmerPositionalArgument> { + match &self { + Self::GlimmerPositionalArgument(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyGlimmerArgumentValue { + GlimmerLiteral(GlimmerLiteral), + GlimmerPath(GlimmerPath), + GlimmerStringLiteral(GlimmerStringLiteral), + GlimmerSubexpression(GlimmerSubexpression), +} +impl AnyGlimmerArgumentValue { + pub fn as_glimmer_literal(&self) -> Option<&GlimmerLiteral> { + match &self { + Self::GlimmerLiteral(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_path(&self) -> Option<&GlimmerPath> { + match &self { + Self::GlimmerPath(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_string_literal(&self) -> Option<&GlimmerStringLiteral> { + match &self { + Self::GlimmerStringLiteral(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_subexpression(&self) -> Option<&GlimmerSubexpression> { + match &self { + Self::GlimmerSubexpression(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyGlimmerExpression { + GlimmerBlockHelper(GlimmerBlockHelper), + GlimmerBogusExpression(GlimmerBogusExpression), + GlimmerMustacheComment(GlimmerMustacheComment), + GlimmerMustacheExpression(GlimmerMustacheExpression), + GlimmerNamedBlock(GlimmerNamedBlock), + GlimmerTripleStashExpression(GlimmerTripleStashExpression), +} +impl AnyGlimmerExpression { + pub fn as_glimmer_block_helper(&self) -> Option<&GlimmerBlockHelper> { + match &self { + Self::GlimmerBlockHelper(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_bogus_expression(&self) -> Option<&GlimmerBogusExpression> { + match &self { + Self::GlimmerBogusExpression(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_mustache_comment(&self) -> Option<&GlimmerMustacheComment> { + match &self { + Self::GlimmerMustacheComment(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_mustache_expression(&self) -> Option<&GlimmerMustacheExpression> { + match &self { + Self::GlimmerMustacheExpression(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_named_block(&self) -> Option<&GlimmerNamedBlock> { + match &self { + Self::GlimmerNamedBlock(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_triple_stash_expression(&self) -> Option<&GlimmerTripleStashExpression> { + match &self { + Self::GlimmerTripleStashExpression(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyHtmlAttribute { + GlimmerElementModifier(GlimmerElementModifier), + GlimmerSplattribute(GlimmerSplattribute), + HtmlAttribute(HtmlAttribute), + HtmlBogusAttribute(HtmlBogusAttribute), + HtmlDoubleTextExpression(HtmlDoubleTextExpression), + HtmlSingleTextExpression(HtmlSingleTextExpression), +} +impl AnyHtmlAttribute { + pub fn as_glimmer_element_modifier(&self) -> Option<&GlimmerElementModifier> { + match &self { + Self::GlimmerElementModifier(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_splattribute(&self) -> Option<&GlimmerSplattribute> { + match &self { + Self::GlimmerSplattribute(item) => Some(item), + _ => None, + } + } + pub fn as_html_attribute(&self) -> Option<&HtmlAttribute> { + match &self { + Self::HtmlAttribute(item) => Some(item), + _ => None, + } + } + pub fn as_html_bogus_attribute(&self) -> Option<&HtmlBogusAttribute> { + match &self { + Self::HtmlBogusAttribute(item) => Some(item), + _ => None, + } + } + pub fn as_html_double_text_expression(&self) -> Option<&HtmlDoubleTextExpression> { + match &self { + Self::HtmlDoubleTextExpression(item) => Some(item), + _ => 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 { + HtmlSingleTextExpression(HtmlSingleTextExpression), + HtmlString(HtmlString), +} +impl AnyHtmlAttributeInitializer { + pub fn as_html_single_text_expression(&self) -> Option<&HtmlSingleTextExpression> { + match &self { + Self::HtmlSingleTextExpression(item) => Some(item), + _ => None, + } + } + pub fn as_html_string(&self) -> Option<&HtmlString> { + match &self { + Self::HtmlString(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyHtmlContent { + AnyGlimmerExpression(AnyGlimmerExpression), AnyHtmlTextExpression(AnyHtmlTextExpression), HtmlContent(HtmlContent), HtmlEmbeddedContent(HtmlEmbeddedContent), } -impl AnyHtmlContent { - pub fn as_any_html_text_expression(&self) -> Option<&AnyHtmlTextExpression> { - match &self { - Self::AnyHtmlTextExpression(item) => Some(item), - _ => None, +impl AnyHtmlContent { + pub fn as_any_glimmer_expression(&self) -> Option<&AnyGlimmerExpression> { + match &self { + Self::AnyGlimmerExpression(item) => Some(item), + _ => None, + } + } + pub fn as_any_html_text_expression(&self) -> Option<&AnyHtmlTextExpression> { + match &self { + Self::AnyHtmlTextExpression(item) => Some(item), + _ => None, + } + } + pub fn as_html_content(&self) -> Option<&HtmlContent> { + match &self { + Self::HtmlContent(item) => Some(item), + _ => None, + } + } + pub fn as_html_embedded_content(&self) -> Option<&HtmlEmbeddedContent> { + match &self { + Self::HtmlEmbeddedContent(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyHtmlElement { + AnyHtmlContent(AnyHtmlContent), + GlimmerMustacheComment(GlimmerMustacheComment), + GlimmerTripleStashExpression(GlimmerTripleStashExpression), + HtmlBogusElement(HtmlBogusElement), + HtmlCdataSection(HtmlCdataSection), + HtmlElement(HtmlElement), + HtmlSelfClosingElement(HtmlSelfClosingElement), +} +impl AnyHtmlElement { + pub fn as_any_html_content(&self) -> Option<&AnyHtmlContent> { + match &self { + Self::AnyHtmlContent(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_mustache_comment(&self) -> Option<&GlimmerMustacheComment> { + match &self { + Self::GlimmerMustacheComment(item) => Some(item), + _ => None, + } + } + pub fn as_glimmer_triple_stash_expression(&self) -> Option<&GlimmerTripleStashExpression> { + match &self { + Self::GlimmerTripleStashExpression(item) => Some(item), + _ => None, + } + } + pub fn as_html_bogus_element(&self) -> Option<&HtmlBogusElement> { + match &self { + Self::HtmlBogusElement(item) => Some(item), + _ => None, + } + } + pub fn as_html_cdata_section(&self) -> Option<&HtmlCdataSection> { + match &self { + Self::HtmlCdataSection(item) => Some(item), + _ => None, + } + } + pub fn as_html_element(&self) -> Option<&HtmlElement> { + match &self { + Self::HtmlElement(item) => Some(item), + _ => None, + } + } + pub fn as_html_self_closing_element(&self) -> Option<&HtmlSelfClosingElement> { + match &self { + Self::HtmlSelfClosingElement(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyHtmlTextExpression { + AnySvelteBlock(AnySvelteBlock), + HtmlBogusTextExpression(HtmlBogusTextExpression), + HtmlDoubleTextExpression(HtmlDoubleTextExpression), + HtmlSingleTextExpression(HtmlSingleTextExpression), +} +impl AnyHtmlTextExpression { + pub fn as_any_svelte_block(&self) -> Option<&AnySvelteBlock> { + match &self { + Self::AnySvelteBlock(item) => Some(item), + _ => None, + } + } + pub fn as_html_bogus_text_expression(&self) -> Option<&HtmlBogusTextExpression> { + match &self { + Self::HtmlBogusTextExpression(item) => Some(item), + _ => None, + } + } + pub fn as_html_double_text_expression(&self) -> Option<&HtmlDoubleTextExpression> { + match &self { + Self::HtmlDoubleTextExpression(item) => Some(item), + _ => 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 AnySvelteBlock { + SvelteBogusBlock(SvelteBogusBlock), + SvelteDebugBlock(SvelteDebugBlock), +} +impl AnySvelteBlock { + pub fn as_svelte_bogus_block(&self) -> Option<&SvelteBogusBlock> { + match &self { + Self::SvelteBogusBlock(item) => Some(item), + _ => None, + } + } + pub fn as_svelte_debug_block(&self) -> Option<&SvelteDebugBlock> { + match &self { + Self::SvelteDebugBlock(item) => Some(item), + _ => None, + } + } +} +impl AstNode for AstroEmbeddedContent { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(ASTRO_EMBEDDED_CONTENT as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == ASTRO_EMBEDDED_CONTENT + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for AstroEmbeddedContent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("AstroEmbeddedContent") + .field( + "content_token", + &support::DebugOptionalElement(self.content_token()), + ) + .finish() + } else { + f.debug_struct("AstroEmbeddedContent").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: AstroEmbeddedContent) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: AstroEmbeddedContent) -> Self { + n.syntax.into() + } +} +impl AstNode for AstroFrontmatterElement { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(ASTRO_FRONTMATTER_ELEMENT as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == ASTRO_FRONTMATTER_ELEMENT + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for AstroFrontmatterElement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("AstroFrontmatterElement") + .field( + "l_fence_token", + &support::DebugSyntaxResult(self.l_fence_token()), + ) + .field("content", &support::DebugSyntaxResult(self.content())) + .field( + "r_fence_token", + &support::DebugSyntaxResult(self.r_fence_token()), + ) + .finish() + } else { + f.debug_struct("AstroFrontmatterElement").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: AstroFrontmatterElement) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: AstroFrontmatterElement) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerBlockHelper { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_BLOCK_HELPER as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_BLOCK_HELPER + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerBlockHelper { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerBlockHelper") + .field("opening", &support::DebugSyntaxResult(self.opening())) + .field("children", &self.children()) + .field("closing", &support::DebugSyntaxResult(self.closing())) + .finish() + } else { + f.debug_struct("GlimmerBlockHelper").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerBlockHelper) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerBlockHelper) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerBlockHelperClosing { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_BLOCK_HELPER_CLOSING as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_BLOCK_HELPER_CLOSING + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerBlockHelperClosing { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerBlockHelperClosing") + .field( + "l_curly2_token_token", + &support::DebugSyntaxResult(self.l_curly2_token_token()), + ) + .field( + "slash_token_token", + &support::DebugSyntaxResult(self.slash_token_token()), + ) + .field("helper", &support::DebugSyntaxResult(self.helper())) + .field( + "r_curly2_token_token", + &support::DebugSyntaxResult(self.r_curly2_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerBlockHelperClosing").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerBlockHelperClosing) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerBlockHelperClosing) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerBlockHelperOpening { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_BLOCK_HELPER_OPENING as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_BLOCK_HELPER_OPENING + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerBlockHelperOpening { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerBlockHelperOpening") + .field( + "l_curly2_token_token", + &support::DebugSyntaxResult(self.l_curly2_token_token()), + ) + .field( + "hash_token_token", + &support::DebugSyntaxResult(self.hash_token_token()), + ) + .field("helper", &support::DebugSyntaxResult(self.helper())) + .field("arguments", &self.arguments()) + .field( + "block_params", + &support::DebugOptionalElement(self.block_params()), + ) + .field( + "r_curly2_token_token", + &support::DebugSyntaxResult(self.r_curly2_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerBlockHelperOpening").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerBlockHelperOpening) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerBlockHelperOpening) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerBlockParam { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_BLOCK_PARAM as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_BLOCK_PARAM + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerBlockParam { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerBlockParam") + .field( + "name_token_token", + &support::DebugSyntaxResult(self.name_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerBlockParam").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerBlockParam) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerBlockParam) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerBlockParams { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_BLOCK_PARAMS as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_BLOCK_PARAMS + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerBlockParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerBlockParams") + .field( + "as_token_token", + &support::DebugSyntaxResult(self.as_token_token()), + ) + .field( + "l_pipe_token_token", + &support::DebugSyntaxResult(self.l_pipe_token_token()), + ) + .field("params", &self.params()) + .field( + "r_pipe_token_token", + &support::DebugSyntaxResult(self.r_pipe_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerBlockParams").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerBlockParams) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerBlockParams) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerElementModifier { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_ELEMENT_MODIFIER as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_ELEMENT_MODIFIER + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerElementModifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerElementModifier") + .field( + "l_curly2_token_token", + &support::DebugSyntaxResult(self.l_curly2_token_token()), + ) + .field("path", &support::DebugSyntaxResult(self.path())) + .field("arguments", &self.arguments()) + .field( + "r_curly2_token_token", + &support::DebugSyntaxResult(self.r_curly2_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerElementModifier").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerElementModifier) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerElementModifier) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerLiteral { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_LITERAL as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_LITERAL + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerLiteral { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerLiteral") + .field( + "value_token_token", + &support::DebugSyntaxResult(self.value_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerLiteral").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerLiteral) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerLiteral) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerMustacheComment { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_MUSTACHE_COMMENT as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_MUSTACHE_COMMENT + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerMustacheComment { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerMustacheComment") + .field( + "comment_token_token", + &support::DebugSyntaxResult(self.comment_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerMustacheComment").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerMustacheComment) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerMustacheComment) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerMustacheExpression { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_MUSTACHE_EXPRESSION as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_MUSTACHE_EXPRESSION + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerMustacheExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerMustacheExpression") + .field( + "l_curly2_token_token", + &support::DebugSyntaxResult(self.l_curly2_token_token()), + ) + .field("path", &support::DebugSyntaxResult(self.path())) + .field("arguments", &self.arguments()) + .field( + "r_curly2_token_token", + &support::DebugSyntaxResult(self.r_curly2_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerMustacheExpression").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerMustacheExpression) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerMustacheExpression) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerNamedArgument { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_NAMED_ARGUMENT as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_NAMED_ARGUMENT + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerNamedArgument { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerNamedArgument") + .field( + "name_token_token", + &support::DebugSyntaxResult(self.name_token_token()), + ) + .field( + "eq_token_token", + &support::DebugSyntaxResult(self.eq_token_token()), + ) + .field("value", &support::DebugSyntaxResult(self.value())) + .finish() + } else { + f.debug_struct("GlimmerNamedArgument").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerNamedArgument) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerNamedArgument) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerNamedBlock { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_NAMED_BLOCK as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_NAMED_BLOCK + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerNamedBlock { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerNamedBlock") + .field("opening", &support::DebugSyntaxResult(self.opening())) + .field("children", &self.children()) + .field("closing", &support::DebugSyntaxResult(self.closing())) + .finish() + } else { + f.debug_struct("GlimmerNamedBlock").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerNamedBlock) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerNamedBlock) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerNamedBlockClosing { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_NAMED_BLOCK_CLOSING as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_NAMED_BLOCK_CLOSING + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerNamedBlockClosing { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerNamedBlockClosing") + .field( + "l_angle_token_token", + &support::DebugSyntaxResult(self.l_angle_token_token()), + ) + .field( + "slash_token_token", + &support::DebugSyntaxResult(self.slash_token_token()), + ) + .field( + "colon_token_token", + &support::DebugSyntaxResult(self.colon_token_token()), + ) + .field( + "name_token_token", + &support::DebugSyntaxResult(self.name_token_token()), + ) + .field( + "r_angle_token_token", + &support::DebugSyntaxResult(self.r_angle_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerNamedBlockClosing").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerNamedBlockClosing) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerNamedBlockClosing) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerNamedBlockOpening { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_NAMED_BLOCK_OPENING as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_NAMED_BLOCK_OPENING + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None } } - pub fn as_html_content(&self) -> Option<&HtmlContent> { - match &self { - Self::HtmlContent(item) => Some(item), - _ => None, + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerNamedBlockOpening { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerNamedBlockOpening") + .field( + "l_angle_token_token", + &support::DebugSyntaxResult(self.l_angle_token_token()), + ) + .field( + "colon_token_token", + &support::DebugSyntaxResult(self.colon_token_token()), + ) + .field( + "name_token_token", + &support::DebugSyntaxResult(self.name_token_token()), + ) + .field("attributes", &self.attributes()) + .field( + "r_angle_token_token", + &support::DebugSyntaxResult(self.r_angle_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerNamedBlockOpening").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerNamedBlockOpening) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerNamedBlockOpening) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerPath { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_PATH as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_PATH + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None } } - pub fn as_html_embedded_content(&self) -> Option<&HtmlEmbeddedContent> { - match &self { - Self::HtmlEmbeddedContent(item) => Some(item), - _ => None, - } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax } } -#[derive(Clone, PartialEq, Eq, Hash, Serialize)] -pub enum AnyHtmlElement { - AnyHtmlContent(AnyHtmlContent), - HtmlBogusElement(HtmlBogusElement), - HtmlCdataSection(HtmlCdataSection), - HtmlElement(HtmlElement), - HtmlSelfClosingElement(HtmlSelfClosingElement), +impl std::fmt::Debug for GlimmerPath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerPath") + .field( + "at_token_token", + &support::DebugOptionalElement(self.at_token_token()), + ) + .field("segments", &self.segments()) + .finish() + } else { + f.debug_struct("GlimmerPath").finish() + }; + DEPTH.set(current_depth); + result + } } -impl AnyHtmlElement { - pub fn as_any_html_content(&self) -> Option<&AnyHtmlContent> { - match &self { - Self::AnyHtmlContent(item) => Some(item), - _ => None, - } +impl From for SyntaxNode { + fn from(n: GlimmerPath) -> Self { + n.syntax } - pub fn as_html_bogus_element(&self) -> Option<&HtmlBogusElement> { - match &self { - Self::HtmlBogusElement(item) => Some(item), - _ => None, - } +} +impl From for SyntaxElement { + fn from(n: GlimmerPath) -> Self { + n.syntax.into() } - pub fn as_html_cdata_section(&self) -> Option<&HtmlCdataSection> { - match &self { - Self::HtmlCdataSection(item) => Some(item), - _ => None, - } +} +impl AstNode for GlimmerPathSegment { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_PATH_SEGMENT as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_PATH_SEGMENT } - pub fn as_html_element(&self) -> Option<&HtmlElement> { - match &self { - Self::HtmlElement(item) => Some(item), - _ => None, + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None } } - pub fn as_html_self_closing_element(&self) -> Option<&HtmlSelfClosingElement> { - match &self { - Self::HtmlSelfClosingElement(item) => Some(item), - _ => None, - } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax } } -#[derive(Clone, PartialEq, Eq, Hash, Serialize)] -pub enum AnyHtmlTextExpression { - AnySvelteBlock(AnySvelteBlock), - HtmlBogusTextExpression(HtmlBogusTextExpression), - HtmlDoubleTextExpression(HtmlDoubleTextExpression), - HtmlSingleTextExpression(HtmlSingleTextExpression), +impl std::fmt::Debug for GlimmerPathSegment { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerPathSegment") + .field( + "value_token_token", + &support::DebugSyntaxResult(self.value_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerPathSegment").finish() + }; + DEPTH.set(current_depth); + result + } } -impl AnyHtmlTextExpression { - pub fn as_any_svelte_block(&self) -> Option<&AnySvelteBlock> { - match &self { - Self::AnySvelteBlock(item) => Some(item), - _ => None, - } +impl From for SyntaxNode { + fn from(n: GlimmerPathSegment) -> Self { + n.syntax } - pub fn as_html_bogus_text_expression(&self) -> Option<&HtmlBogusTextExpression> { - match &self { - Self::HtmlBogusTextExpression(item) => Some(item), - _ => None, - } +} +impl From for SyntaxElement { + fn from(n: GlimmerPathSegment) -> Self { + n.syntax.into() } - pub fn as_html_double_text_expression(&self) -> Option<&HtmlDoubleTextExpression> { - match &self { - Self::HtmlDoubleTextExpression(item) => Some(item), - _ => None, - } +} +impl AstNode for GlimmerPositionalArgument { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_POSITIONAL_ARGUMENT as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_POSITIONAL_ARGUMENT } - pub fn as_html_single_text_expression(&self) -> Option<&HtmlSingleTextExpression> { - match &self { - Self::HtmlSingleTextExpression(item) => Some(item), - _ => None, + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None } } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } } -#[derive(Clone, PartialEq, Eq, Hash, Serialize)] -pub enum AnySvelteBlock { - SvelteBogusBlock(SvelteBogusBlock), - SvelteDebugBlock(SvelteDebugBlock), +impl std::fmt::Debug for GlimmerPositionalArgument { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerPositionalArgument") + .field("value", &support::DebugSyntaxResult(self.value())) + .finish() + } else { + f.debug_struct("GlimmerPositionalArgument").finish() + }; + DEPTH.set(current_depth); + result + } } -impl AnySvelteBlock { - pub fn as_svelte_bogus_block(&self) -> Option<&SvelteBogusBlock> { - match &self { - Self::SvelteBogusBlock(item) => Some(item), - _ => None, - } +impl From for SyntaxNode { + fn from(n: GlimmerPositionalArgument) -> Self { + n.syntax } - pub fn as_svelte_debug_block(&self) -> Option<&SvelteDebugBlock> { - match &self { - Self::SvelteDebugBlock(item) => Some(item), - _ => None, +} +impl From for SyntaxElement { + fn from(n: GlimmerPositionalArgument) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerSplattribute { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_SPLATTRIBUTE as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_SPLATTRIBUTE + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None } } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } } -impl AstNode for AstroEmbeddedContent { +impl std::fmt::Debug for GlimmerSplattribute { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerSplattribute") + .field( + "dotdotdot_token_token", + &support::DebugSyntaxResult(self.dotdotdot_token_token()), + ) + .field( + "attributes_token_token", + &support::DebugSyntaxResult(self.attributes_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerSplattribute").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerSplattribute) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerSplattribute) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerStringLiteral { type Language = Language; const KIND_SET: SyntaxKindSet = - SyntaxKindSet::from_raw(RawSyntaxKind(ASTRO_EMBEDDED_CONTENT as u16)); + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_STRING_LITERAL as u16)); fn can_cast(kind: SyntaxKind) -> bool { - kind == ASTRO_EMBEDDED_CONTENT + kind == GLIMMER_STRING_LITERAL } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -1144,41 +3206,97 @@ impl AstNode for AstroEmbeddedContent { self.syntax } } -impl std::fmt::Debug for AstroEmbeddedContent { +impl std::fmt::Debug for GlimmerStringLiteral { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; let current_depth = DEPTH.get(); let result = if current_depth < 16 { DEPTH.set(current_depth + 1); - f.debug_struct("AstroEmbeddedContent") + f.debug_struct("GlimmerStringLiteral") .field( - "content_token", - &support::DebugOptionalElement(self.content_token()), + "value_token_token", + &support::DebugSyntaxResult(self.value_token_token()), ) .finish() } else { - f.debug_struct("AstroEmbeddedContent").finish() + f.debug_struct("GlimmerStringLiteral").finish() }; DEPTH.set(current_depth); result } } -impl From for SyntaxNode { - fn from(n: AstroEmbeddedContent) -> Self { +impl From for SyntaxNode { + fn from(n: GlimmerStringLiteral) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerStringLiteral) -> Self { + n.syntax.into() + } +} +impl AstNode for GlimmerSubexpression { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_SUBEXPRESSION as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_SUBEXPRESSION + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerSubexpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("GlimmerSubexpression") + .field( + "l_paren_token_token", + &support::DebugSyntaxResult(self.l_paren_token_token()), + ) + .field("path", &support::DebugSyntaxResult(self.path())) + .field("arguments", &self.arguments()) + .field( + "r_paren_token_token", + &support::DebugSyntaxResult(self.r_paren_token_token()), + ) + .finish() + } else { + f.debug_struct("GlimmerSubexpression").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: GlimmerSubexpression) -> Self { n.syntax } } -impl From for SyntaxElement { - fn from(n: AstroEmbeddedContent) -> Self { +impl From for SyntaxElement { + fn from(n: GlimmerSubexpression) -> Self { n.syntax.into() } } -impl AstNode for AstroFrontmatterElement { +impl AstNode for GlimmerTripleStashExpression { type Language = Language; const KIND_SET: SyntaxKindSet = - SyntaxKindSet::from_raw(RawSyntaxKind(ASTRO_FRONTMATTER_ELEMENT as u16)); + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_TRIPLE_STASH_EXPRESSION as u16)); fn can_cast(kind: SyntaxKind) -> bool { - kind == ASTRO_FRONTMATTER_ELEMENT + kind == GLIMMER_TRIPLE_STASH_EXPRESSION } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -1194,37 +3312,38 @@ impl AstNode for AstroFrontmatterElement { self.syntax } } -impl std::fmt::Debug for AstroFrontmatterElement { +impl std::fmt::Debug for GlimmerTripleStashExpression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; let current_depth = DEPTH.get(); let result = if current_depth < 16 { DEPTH.set(current_depth + 1); - f.debug_struct("AstroFrontmatterElement") + f.debug_struct("GlimmerTripleStashExpression") .field( - "l_fence_token", - &support::DebugSyntaxResult(self.l_fence_token()), + "l_curly3_token_token", + &support::DebugSyntaxResult(self.l_curly3_token_token()), ) - .field("content", &support::DebugSyntaxResult(self.content())) + .field("path", &support::DebugSyntaxResult(self.path())) + .field("arguments", &self.arguments()) .field( - "r_fence_token", - &support::DebugSyntaxResult(self.r_fence_token()), + "r_curly3_token_token", + &support::DebugSyntaxResult(self.r_curly3_token_token()), ) .finish() } else { - f.debug_struct("AstroFrontmatterElement").finish() + f.debug_struct("GlimmerTripleStashExpression").finish() }; DEPTH.set(current_depth); result } } -impl From for SyntaxNode { - fn from(n: AstroFrontmatterElement) -> Self { +impl From for SyntaxNode { + fn from(n: GlimmerTripleStashExpression) -> Self { n.syntax } } -impl From for SyntaxElement { - fn from(n: AstroFrontmatterElement) -> Self { +impl From for SyntaxElement { + fn from(n: GlimmerTripleStashExpression) -> Self { n.syntax.into() } } @@ -2333,6 +4452,283 @@ impl From for SyntaxElement { node.into() } } +impl From for AnyGlimmerArgument { + fn from(node: GlimmerNamedArgument) -> Self { + Self::GlimmerNamedArgument(node) + } +} +impl From for AnyGlimmerArgument { + fn from(node: GlimmerPositionalArgument) -> Self { + Self::GlimmerPositionalArgument(node) + } +} +impl AstNode for AnyGlimmerArgument { + type Language = Language; + const KIND_SET: SyntaxKindSet = + GlimmerNamedArgument::KIND_SET.union(GlimmerPositionalArgument::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, GLIMMER_NAMED_ARGUMENT | GLIMMER_POSITIONAL_ARGUMENT) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + GLIMMER_NAMED_ARGUMENT => Self::GlimmerNamedArgument(GlimmerNamedArgument { syntax }), + GLIMMER_POSITIONAL_ARGUMENT => { + Self::GlimmerPositionalArgument(GlimmerPositionalArgument { syntax }) + } + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Self::GlimmerNamedArgument(it) => &it.syntax, + Self::GlimmerPositionalArgument(it) => &it.syntax, + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + Self::GlimmerNamedArgument(it) => it.syntax, + Self::GlimmerPositionalArgument(it) => it.syntax, + } + } +} +impl std::fmt::Debug for AnyGlimmerArgument { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::GlimmerNamedArgument(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerPositionalArgument(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnyGlimmerArgument) -> Self { + match n { + AnyGlimmerArgument::GlimmerNamedArgument(it) => it.into(), + AnyGlimmerArgument::GlimmerPositionalArgument(it) => it.into(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnyGlimmerArgument) -> Self { + let node: SyntaxNode = n.into(); + node.into() + } +} +impl From for AnyGlimmerArgumentValue { + fn from(node: GlimmerLiteral) -> Self { + Self::GlimmerLiteral(node) + } +} +impl From for AnyGlimmerArgumentValue { + fn from(node: GlimmerPath) -> Self { + Self::GlimmerPath(node) + } +} +impl From for AnyGlimmerArgumentValue { + fn from(node: GlimmerStringLiteral) -> Self { + Self::GlimmerStringLiteral(node) + } +} +impl From for AnyGlimmerArgumentValue { + fn from(node: GlimmerSubexpression) -> Self { + Self::GlimmerSubexpression(node) + } +} +impl AstNode for AnyGlimmerArgumentValue { + type Language = Language; + const KIND_SET: SyntaxKindSet = GlimmerLiteral::KIND_SET + .union(GlimmerPath::KIND_SET) + .union(GlimmerStringLiteral::KIND_SET) + .union(GlimmerSubexpression::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + matches!( + kind, + GLIMMER_LITERAL | GLIMMER_PATH | GLIMMER_STRING_LITERAL | GLIMMER_SUBEXPRESSION + ) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + GLIMMER_LITERAL => Self::GlimmerLiteral(GlimmerLiteral { syntax }), + GLIMMER_PATH => Self::GlimmerPath(GlimmerPath { syntax }), + GLIMMER_STRING_LITERAL => Self::GlimmerStringLiteral(GlimmerStringLiteral { syntax }), + GLIMMER_SUBEXPRESSION => Self::GlimmerSubexpression(GlimmerSubexpression { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Self::GlimmerLiteral(it) => &it.syntax, + Self::GlimmerPath(it) => &it.syntax, + Self::GlimmerStringLiteral(it) => &it.syntax, + Self::GlimmerSubexpression(it) => &it.syntax, + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + Self::GlimmerLiteral(it) => it.syntax, + Self::GlimmerPath(it) => it.syntax, + Self::GlimmerStringLiteral(it) => it.syntax, + Self::GlimmerSubexpression(it) => it.syntax, + } + } +} +impl std::fmt::Debug for AnyGlimmerArgumentValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::GlimmerLiteral(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerPath(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerStringLiteral(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerSubexpression(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnyGlimmerArgumentValue) -> Self { + match n { + AnyGlimmerArgumentValue::GlimmerLiteral(it) => it.into(), + AnyGlimmerArgumentValue::GlimmerPath(it) => it.into(), + AnyGlimmerArgumentValue::GlimmerStringLiteral(it) => it.into(), + AnyGlimmerArgumentValue::GlimmerSubexpression(it) => it.into(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnyGlimmerArgumentValue) -> Self { + let node: SyntaxNode = n.into(); + node.into() + } +} +impl From for AnyGlimmerExpression { + fn from(node: GlimmerBlockHelper) -> Self { + Self::GlimmerBlockHelper(node) + } +} +impl From for AnyGlimmerExpression { + fn from(node: GlimmerBogusExpression) -> Self { + Self::GlimmerBogusExpression(node) + } +} +impl From for AnyGlimmerExpression { + fn from(node: GlimmerMustacheComment) -> Self { + Self::GlimmerMustacheComment(node) + } +} +impl From for AnyGlimmerExpression { + fn from(node: GlimmerMustacheExpression) -> Self { + Self::GlimmerMustacheExpression(node) + } +} +impl From for AnyGlimmerExpression { + fn from(node: GlimmerNamedBlock) -> Self { + Self::GlimmerNamedBlock(node) + } +} +impl From for AnyGlimmerExpression { + fn from(node: GlimmerTripleStashExpression) -> Self { + Self::GlimmerTripleStashExpression(node) + } +} +impl AstNode for AnyGlimmerExpression { + type Language = Language; + const KIND_SET: SyntaxKindSet = GlimmerBlockHelper::KIND_SET + .union(GlimmerBogusExpression::KIND_SET) + .union(GlimmerMustacheComment::KIND_SET) + .union(GlimmerMustacheExpression::KIND_SET) + .union(GlimmerNamedBlock::KIND_SET) + .union(GlimmerTripleStashExpression::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + matches!( + kind, + GLIMMER_BLOCK_HELPER + | GLIMMER_BOGUS_EXPRESSION + | GLIMMER_MUSTACHE_COMMENT + | GLIMMER_MUSTACHE_EXPRESSION + | GLIMMER_NAMED_BLOCK + | GLIMMER_TRIPLE_STASH_EXPRESSION + ) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + GLIMMER_BLOCK_HELPER => Self::GlimmerBlockHelper(GlimmerBlockHelper { syntax }), + GLIMMER_BOGUS_EXPRESSION => { + Self::GlimmerBogusExpression(GlimmerBogusExpression { syntax }) + } + GLIMMER_MUSTACHE_COMMENT => { + Self::GlimmerMustacheComment(GlimmerMustacheComment { syntax }) + } + GLIMMER_MUSTACHE_EXPRESSION => { + Self::GlimmerMustacheExpression(GlimmerMustacheExpression { syntax }) + } + GLIMMER_NAMED_BLOCK => Self::GlimmerNamedBlock(GlimmerNamedBlock { syntax }), + GLIMMER_TRIPLE_STASH_EXPRESSION => { + Self::GlimmerTripleStashExpression(GlimmerTripleStashExpression { syntax }) + } + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Self::GlimmerBlockHelper(it) => &it.syntax, + Self::GlimmerBogusExpression(it) => &it.syntax, + Self::GlimmerMustacheComment(it) => &it.syntax, + Self::GlimmerMustacheExpression(it) => &it.syntax, + Self::GlimmerNamedBlock(it) => &it.syntax, + Self::GlimmerTripleStashExpression(it) => &it.syntax, + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + Self::GlimmerBlockHelper(it) => it.syntax, + Self::GlimmerBogusExpression(it) => it.syntax, + Self::GlimmerMustacheComment(it) => it.syntax, + Self::GlimmerMustacheExpression(it) => it.syntax, + Self::GlimmerNamedBlock(it) => it.syntax, + Self::GlimmerTripleStashExpression(it) => it.syntax, + } + } +} +impl std::fmt::Debug for AnyGlimmerExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::GlimmerBlockHelper(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerBogusExpression(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerMustacheComment(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerMustacheExpression(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerNamedBlock(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerTripleStashExpression(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnyGlimmerExpression) -> Self { + match n { + AnyGlimmerExpression::GlimmerBlockHelper(it) => it.into(), + AnyGlimmerExpression::GlimmerBogusExpression(it) => it.into(), + AnyGlimmerExpression::GlimmerMustacheComment(it) => it.into(), + AnyGlimmerExpression::GlimmerMustacheExpression(it) => it.into(), + AnyGlimmerExpression::GlimmerNamedBlock(it) => it.into(), + AnyGlimmerExpression::GlimmerTripleStashExpression(it) => it.into(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnyGlimmerExpression) -> Self { + let node: SyntaxNode = n.into(); + node.into() + } +} +impl From for AnyHtmlAttribute { + fn from(node: GlimmerElementModifier) -> Self { + Self::GlimmerElementModifier(node) + } +} +impl From for AnyHtmlAttribute { + fn from(node: GlimmerSplattribute) -> Self { + Self::GlimmerSplattribute(node) + } +} impl From for AnyHtmlAttribute { fn from(node: HtmlAttribute) -> Self { Self::HtmlAttribute(node) @@ -2355,14 +4751,18 @@ impl From for AnyHtmlAttribute { } impl AstNode for AnyHtmlAttribute { type Language = Language; - const KIND_SET: SyntaxKindSet = HtmlAttribute::KIND_SET + const KIND_SET: SyntaxKindSet = GlimmerElementModifier::KIND_SET + .union(GlimmerSplattribute::KIND_SET) + .union(HtmlAttribute::KIND_SET) .union(HtmlBogusAttribute::KIND_SET) .union(HtmlDoubleTextExpression::KIND_SET) .union(HtmlSingleTextExpression::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - HTML_ATTRIBUTE + GLIMMER_ELEMENT_MODIFIER + | GLIMMER_SPLATTRIBUTE + | HTML_ATTRIBUTE | HTML_BOGUS_ATTRIBUTE | HTML_DOUBLE_TEXT_EXPRESSION | HTML_SINGLE_TEXT_EXPRESSION @@ -2370,6 +4770,10 @@ impl AstNode for AnyHtmlAttribute { } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { + GLIMMER_ELEMENT_MODIFIER => { + Self::GlimmerElementModifier(GlimmerElementModifier { syntax }) + } + GLIMMER_SPLATTRIBUTE => Self::GlimmerSplattribute(GlimmerSplattribute { syntax }), HTML_ATTRIBUTE => Self::HtmlAttribute(HtmlAttribute { syntax }), HTML_BOGUS_ATTRIBUTE => Self::HtmlBogusAttribute(HtmlBogusAttribute { syntax }), HTML_DOUBLE_TEXT_EXPRESSION => { @@ -2384,6 +4788,8 @@ impl AstNode for AnyHtmlAttribute { } fn syntax(&self) -> &SyntaxNode { match self { + Self::GlimmerElementModifier(it) => &it.syntax, + Self::GlimmerSplattribute(it) => &it.syntax, Self::HtmlAttribute(it) => &it.syntax, Self::HtmlBogusAttribute(it) => &it.syntax, Self::HtmlDoubleTextExpression(it) => &it.syntax, @@ -2392,6 +4798,8 @@ impl AstNode for AnyHtmlAttribute { } fn into_syntax(self) -> SyntaxNode { match self { + Self::GlimmerElementModifier(it) => it.syntax, + Self::GlimmerSplattribute(it) => it.syntax, Self::HtmlAttribute(it) => it.syntax, Self::HtmlBogusAttribute(it) => it.syntax, Self::HtmlDoubleTextExpression(it) => it.syntax, @@ -2402,6 +4810,8 @@ impl AstNode for AnyHtmlAttribute { impl std::fmt::Debug for AnyHtmlAttribute { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Self::GlimmerElementModifier(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerSplattribute(it) => std::fmt::Debug::fmt(it, f), 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), @@ -2412,6 +4822,8 @@ impl std::fmt::Debug for AnyHtmlAttribute { impl From for SyntaxNode { fn from(n: AnyHtmlAttribute) -> Self { match n { + AnyHtmlAttribute::GlimmerElementModifier(it) => it.into(), + AnyHtmlAttribute::GlimmerSplattribute(it) => it.into(), AnyHtmlAttribute::HtmlAttribute(it) => it.into(), AnyHtmlAttribute::HtmlBogusAttribute(it) => it.into(), AnyHtmlAttribute::HtmlDoubleTextExpression(it) => it.into(), @@ -2499,12 +4911,14 @@ impl From for AnyHtmlContent { } impl AstNode for AnyHtmlContent { type Language = Language; - const KIND_SET: SyntaxKindSet = AnyHtmlTextExpression::KIND_SET + const KIND_SET: SyntaxKindSet = AnyGlimmerExpression::KIND_SET + .union(AnyHtmlTextExpression::KIND_SET) .union(HtmlContent::KIND_SET) .union(HtmlEmbeddedContent::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { match kind { HTML_CONTENT | HTML_EMBEDDED_CONTENT => true, + k if AnyGlimmerExpression::can_cast(k) => true, k if AnyHtmlTextExpression::can_cast(k) => true, _ => false, } @@ -2514,6 +4928,12 @@ impl AstNode for AnyHtmlContent { HTML_CONTENT => Self::HtmlContent(HtmlContent { syntax }), HTML_EMBEDDED_CONTENT => Self::HtmlEmbeddedContent(HtmlEmbeddedContent { syntax }), _ => { + let syntax = match AnyGlimmerExpression::try_cast(syntax) { + Ok(any_glimmer_expression) => { + return Some(Self::AnyGlimmerExpression(any_glimmer_expression)); + } + Err(syntax) => syntax, + }; if let Some(any_html_text_expression) = AnyHtmlTextExpression::cast(syntax) { return Some(Self::AnyHtmlTextExpression(any_html_text_expression)); } @@ -2526,6 +4946,7 @@ impl AstNode for AnyHtmlContent { match self { Self::HtmlContent(it) => &it.syntax, Self::HtmlEmbeddedContent(it) => &it.syntax, + Self::AnyGlimmerExpression(it) => it.syntax(), Self::AnyHtmlTextExpression(it) => it.syntax(), } } @@ -2533,6 +4954,7 @@ impl AstNode for AnyHtmlContent { match self { Self::HtmlContent(it) => it.syntax, Self::HtmlEmbeddedContent(it) => it.syntax, + Self::AnyGlimmerExpression(it) => it.into_syntax(), Self::AnyHtmlTextExpression(it) => it.into_syntax(), } } @@ -2540,6 +4962,7 @@ impl AstNode for AnyHtmlContent { impl std::fmt::Debug for AnyHtmlContent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Self::AnyGlimmerExpression(it) => std::fmt::Debug::fmt(it, f), Self::AnyHtmlTextExpression(it) => std::fmt::Debug::fmt(it, f), Self::HtmlContent(it) => std::fmt::Debug::fmt(it, f), Self::HtmlEmbeddedContent(it) => std::fmt::Debug::fmt(it, f), @@ -2549,6 +4972,7 @@ impl std::fmt::Debug for AnyHtmlContent { impl From for SyntaxNode { fn from(n: AnyHtmlContent) -> Self { match n { + AnyHtmlContent::AnyGlimmerExpression(it) => it.into(), AnyHtmlContent::AnyHtmlTextExpression(it) => it.into(), AnyHtmlContent::HtmlContent(it) => it.into(), AnyHtmlContent::HtmlEmbeddedContent(it) => it.into(), @@ -2561,6 +4985,16 @@ impl From for SyntaxElement { node.into() } } +impl From for AnyHtmlElement { + fn from(node: GlimmerMustacheComment) -> Self { + Self::GlimmerMustacheComment(node) + } +} +impl From for AnyHtmlElement { + fn from(node: GlimmerTripleStashExpression) -> Self { + Self::GlimmerTripleStashExpression(node) + } +} impl From for AnyHtmlElement { fn from(node: HtmlBogusElement) -> Self { Self::HtmlBogusElement(node) @@ -2584,21 +5018,32 @@ impl From for AnyHtmlElement { impl AstNode for AnyHtmlElement { type Language = Language; const KIND_SET: SyntaxKindSet = AnyHtmlContent::KIND_SET + .union(GlimmerMustacheComment::KIND_SET) + .union(GlimmerTripleStashExpression::KIND_SET) .union(HtmlBogusElement::KIND_SET) .union(HtmlCdataSection::KIND_SET) .union(HtmlElement::KIND_SET) .union(HtmlSelfClosingElement::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { match kind { - HTML_BOGUS_ELEMENT | HTML_CDATA_SECTION | HTML_ELEMENT | HTML_SELF_CLOSING_ELEMENT => { - true - } + GLIMMER_MUSTACHE_COMMENT + | GLIMMER_TRIPLE_STASH_EXPRESSION + | HTML_BOGUS_ELEMENT + | HTML_CDATA_SECTION + | HTML_ELEMENT + | HTML_SELF_CLOSING_ELEMENT => true, k if AnyHtmlContent::can_cast(k) => true, _ => false, } } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { + GLIMMER_MUSTACHE_COMMENT => { + Self::GlimmerMustacheComment(GlimmerMustacheComment { syntax }) + } + GLIMMER_TRIPLE_STASH_EXPRESSION => { + Self::GlimmerTripleStashExpression(GlimmerTripleStashExpression { syntax }) + } HTML_BOGUS_ELEMENT => Self::HtmlBogusElement(HtmlBogusElement { syntax }), HTML_CDATA_SECTION => Self::HtmlCdataSection(HtmlCdataSection { syntax }), HTML_ELEMENT => Self::HtmlElement(HtmlElement { syntax }), @@ -2616,6 +5061,8 @@ impl AstNode for AnyHtmlElement { } fn syntax(&self) -> &SyntaxNode { match self { + Self::GlimmerMustacheComment(it) => &it.syntax, + Self::GlimmerTripleStashExpression(it) => &it.syntax, Self::HtmlBogusElement(it) => &it.syntax, Self::HtmlCdataSection(it) => &it.syntax, Self::HtmlElement(it) => &it.syntax, @@ -2625,6 +5072,8 @@ impl AstNode for AnyHtmlElement { } fn into_syntax(self) -> SyntaxNode { match self { + Self::GlimmerMustacheComment(it) => it.syntax, + Self::GlimmerTripleStashExpression(it) => it.syntax, Self::HtmlBogusElement(it) => it.syntax, Self::HtmlCdataSection(it) => it.syntax, Self::HtmlElement(it) => it.syntax, @@ -2637,6 +5086,8 @@ impl std::fmt::Debug for AnyHtmlElement { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::AnyHtmlContent(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerMustacheComment(it) => std::fmt::Debug::fmt(it, f), + Self::GlimmerTripleStashExpression(it) => std::fmt::Debug::fmt(it, f), Self::HtmlBogusElement(it) => std::fmt::Debug::fmt(it, f), Self::HtmlCdataSection(it) => std::fmt::Debug::fmt(it, f), Self::HtmlElement(it) => std::fmt::Debug::fmt(it, f), @@ -2648,6 +5099,8 @@ impl From for SyntaxNode { fn from(n: AnyHtmlElement) -> Self { match n { AnyHtmlElement::AnyHtmlContent(it) => it.into(), + AnyHtmlElement::GlimmerMustacheComment(it) => it.into(), + AnyHtmlElement::GlimmerTripleStashExpression(it) => it.into(), AnyHtmlElement::HtmlBogusElement(it) => it.into(), AnyHtmlElement::HtmlCdataSection(it) => it.into(), AnyHtmlElement::HtmlElement(it) => it.into(), @@ -2814,47 +5267,162 @@ impl From for SyntaxElement { node.into() } } -impl std::fmt::Display for AnyAstroFrontmatterElement { +impl std::fmt::Display for AnyAstroFrontmatterElement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AnyGlimmerArgument { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AnyGlimmerArgumentValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AnyGlimmerExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AnyHtmlAttribute { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AnyHtmlAttributeInitializer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AnyHtmlContent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AnyHtmlElement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AnyHtmlTextExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AnySvelteBlock { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AstroEmbeddedContent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for AstroFrontmatterElement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerBlockHelper { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerBlockHelperClosing { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerBlockHelperOpening { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerBlockParam { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerBlockParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerElementModifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerLiteral { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerMustacheComment { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerMustacheExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerNamedArgument { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerNamedBlock { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for AnyHtmlAttribute { +impl std::fmt::Display for GlimmerNamedBlockClosing { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for AnyHtmlAttributeInitializer { +impl std::fmt::Display for GlimmerNamedBlockOpening { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for AnyHtmlContent { +impl std::fmt::Display for GlimmerPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for AnyHtmlElement { +impl std::fmt::Display for GlimmerPathSegment { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for AnyHtmlTextExpression { +impl std::fmt::Display for GlimmerPositionalArgument { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for AnySvelteBlock { +impl std::fmt::Display for GlimmerSplattribute { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for AstroEmbeddedContent { +impl std::fmt::Display for GlimmerStringLiteral { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for AstroFrontmatterElement { +impl std::fmt::Display for GlimmerSubexpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for GlimmerTripleStashExpression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } @@ -3011,6 +5579,62 @@ impl From for SyntaxElement { } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub struct GlimmerBogusExpression { + syntax: SyntaxNode, +} +impl GlimmerBogusExpression { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn items(&self) -> SyntaxElementChildren { + support::elements(&self.syntax) + } +} +impl AstNode for GlimmerBogusExpression { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_BOGUS_EXPRESSION as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_BOGUS_EXPRESSION + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for GlimmerBogusExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GlimmerBogusExpression") + .field("items", &DebugSyntaxElementChildren(self.items())) + .finish() + } +} +impl From for SyntaxNode { + fn from(n: GlimmerBogusExpression) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: GlimmerBogusExpression) -> Self { + n.syntax.into() + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub struct HtmlBogus { syntax: SyntaxNode, } @@ -3290,7 +5914,253 @@ impl From for SyntaxElement { n.syntax.into() } } -biome_rowan::declare_node_union! { pub AnyHtmlBogusNode = AstroBogusFrontmatter | HtmlBogus | HtmlBogusAttribute | HtmlBogusElement | HtmlBogusTextExpression | SvelteBogusBlock } +biome_rowan::declare_node_union! { pub AnyHtmlBogusNode = AstroBogusFrontmatter | GlimmerBogusExpression | HtmlBogus | HtmlBogusAttribute | HtmlBogusElement | HtmlBogusTextExpression | SvelteBogusBlock } +#[derive(Clone, Eq, PartialEq, Hash)] +pub struct GlimmerArgumentList { + syntax_list: SyntaxList, +} +impl GlimmerArgumentList { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { + syntax_list: syntax.into_list(), + } + } +} +impl AstNode for GlimmerArgumentList { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_ARGUMENT_LIST as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_ARGUMENT_LIST + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { + syntax_list: syntax.into_list(), + }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + self.syntax_list.node() + } + fn into_syntax(self) -> SyntaxNode { + self.syntax_list.into_node() + } +} +impl Serialize for GlimmerArgumentList { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.len()))?; + for e in self.iter() { + seq.serialize_element(&e)?; + } + seq.end() + } +} +impl AstNodeList for GlimmerArgumentList { + type Language = Language; + type Node = AnyGlimmerArgument; + fn syntax_list(&self) -> &SyntaxList { + &self.syntax_list + } + fn into_syntax_list(self) -> SyntaxList { + self.syntax_list + } +} +impl Debug for GlimmerArgumentList { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("GlimmerArgumentList ")?; + f.debug_list().entries(self.iter()).finish() + } +} +impl IntoIterator for &GlimmerArgumentList { + type Item = AnyGlimmerArgument; + type IntoIter = AstNodeListIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} +impl IntoIterator for GlimmerArgumentList { + type Item = AnyGlimmerArgument; + type IntoIter = AstNodeListIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} +#[derive(Clone, Eq, PartialEq, Hash)] +pub struct GlimmerBlockParamList { + syntax_list: SyntaxList, +} +impl GlimmerBlockParamList { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { + syntax_list: syntax.into_list(), + } + } +} +impl AstNode for GlimmerBlockParamList { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_BLOCK_PARAM_LIST as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_BLOCK_PARAM_LIST + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { + syntax_list: syntax.into_list(), + }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + self.syntax_list.node() + } + fn into_syntax(self) -> SyntaxNode { + self.syntax_list.into_node() + } +} +impl Serialize for GlimmerBlockParamList { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.len()))?; + for e in self.iter() { + seq.serialize_element(&e)?; + } + seq.end() + } +} +impl AstNodeList for GlimmerBlockParamList { + type Language = Language; + type Node = GlimmerBlockParam; + fn syntax_list(&self) -> &SyntaxList { + &self.syntax_list + } + fn into_syntax_list(self) -> SyntaxList { + self.syntax_list + } +} +impl Debug for GlimmerBlockParamList { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("GlimmerBlockParamList ")?; + f.debug_list().entries(self.iter()).finish() + } +} +impl IntoIterator for &GlimmerBlockParamList { + type Item = GlimmerBlockParam; + type IntoIter = AstNodeListIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} +impl IntoIterator for GlimmerBlockParamList { + type Item = GlimmerBlockParam; + type IntoIter = AstNodeListIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} +#[derive(Clone, Eq, PartialEq, Hash)] +pub struct GlimmerPathSegmentList { + syntax_list: SyntaxList, +} +impl GlimmerPathSegmentList { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { + syntax_list: syntax.into_list(), + } + } +} +impl AstNode for GlimmerPathSegmentList { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(GLIMMER_PATH_SEGMENT_LIST as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == GLIMMER_PATH_SEGMENT_LIST + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { + syntax_list: syntax.into_list(), + }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + self.syntax_list.node() + } + fn into_syntax(self) -> SyntaxNode { + self.syntax_list.into_node() + } +} +impl Serialize for GlimmerPathSegmentList { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.len()))?; + for e in self.iter() { + seq.serialize_element(&e)?; + } + seq.end() + } +} +impl AstSeparatedList for GlimmerPathSegmentList { + type Language = Language; + type Node = GlimmerPathSegment; + fn syntax_list(&self) -> &SyntaxList { + &self.syntax_list + } + fn into_syntax_list(self) -> SyntaxList { + self.syntax_list + } +} +impl Debug for GlimmerPathSegmentList { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("GlimmerPathSegmentList ")?; + f.debug_list().entries(self.elements()).finish() + } +} +impl IntoIterator for GlimmerPathSegmentList { + type Item = SyntaxResult; + type IntoIter = AstSeparatedListNodesIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} +impl IntoIterator for &GlimmerPathSegmentList { + type Item = SyntaxResult; + type IntoIter = AstSeparatedListNodesIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} #[derive(Clone, Eq, PartialEq, Hash)] pub struct HtmlAttributeList { syntax_list: SyntaxList, diff --git a/crates/biome_html_syntax/src/generated/nodes_mut.rs b/crates/biome_html_syntax/src/generated/nodes_mut.rs index e313d156b95e..4510e97a3dcc 100644 --- a/crates/biome_html_syntax/src/generated/nodes_mut.rs +++ b/crates/biome_html_syntax/src/generated/nodes_mut.rs @@ -31,6 +31,400 @@ impl AstroFrontmatterElement { ) } } +impl GlimmerBlockHelper { + pub fn with_opening(self, element: GlimmerBlockHelperOpening) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_children(self, element: HtmlElementList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_closing(self, element: GlimmerBlockHelperClosing) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl GlimmerBlockHelperClosing { + pub fn with_l_curly2_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_slash_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } + pub fn with_helper(self, element: GlimmerPath) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_r_curly2_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into()))), + ) + } +} +impl GlimmerBlockHelperOpening { + pub fn with_l_curly2_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_hash_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } + pub fn with_helper(self, element: GlimmerPath) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_arguments(self, element: GlimmerArgumentList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_block_params(self, element: Option) -> Self { + Self::unwrap_cast(self.syntax.splice_slots( + 4usize..=4usize, + once(element.map(|element| element.into_syntax().into())), + )) + } + pub fn with_r_curly2_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(5usize..=5usize, once(Some(element.into()))), + ) + } +} +impl GlimmerBlockParam { + pub fn with_name_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } +} +impl GlimmerBlockParams { + pub fn with_as_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_l_pipe_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } + pub fn with_params(self, element: GlimmerBlockParamList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_r_pipe_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into()))), + ) + } +} +impl GlimmerElementModifier { + pub fn with_l_curly2_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_path(self, element: GlimmerPath) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_arguments(self, element: GlimmerArgumentList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_r_curly2_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into()))), + ) + } +} +impl GlimmerLiteral { + pub fn with_value_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } +} +impl GlimmerMustacheComment { + pub fn with_comment_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } +} +impl GlimmerMustacheExpression { + pub fn with_l_curly2_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_path(self, element: GlimmerPath) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_arguments(self, element: GlimmerArgumentList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_r_curly2_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into()))), + ) + } +} +impl GlimmerNamedArgument { + pub fn with_name_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_eq_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: AnyGlimmerArgumentValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl GlimmerNamedBlock { + pub fn with_opening(self, element: GlimmerNamedBlockOpening) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_children(self, element: HtmlElementList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_closing(self, element: GlimmerNamedBlockClosing) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl GlimmerNamedBlockClosing { + pub fn with_l_angle_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_slash_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } + pub fn with_colon_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into()))), + ) + } + pub fn with_name_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into()))), + ) + } + pub fn with_r_angle_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(4usize..=4usize, once(Some(element.into()))), + ) + } +} +impl GlimmerNamedBlockOpening { + pub fn with_l_angle_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_colon_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } + pub fn with_name_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into()))), + ) + } + pub fn with_attributes(self, element: HtmlAttributeList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_r_angle_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(4usize..=4usize, once(Some(element.into()))), + ) + } +} +impl GlimmerPath { + pub fn with_at_token_token(self, element: Option) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(element.map(|element| element.into()))), + ) + } + pub fn with_segments(self, element: GlimmerPathSegmentList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl GlimmerPathSegment { + pub fn with_value_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } +} +impl GlimmerPositionalArgument { + pub fn with_value(self, element: AnyGlimmerArgumentValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl GlimmerSplattribute { + pub fn with_dotdotdot_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_attributes_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } +} +impl GlimmerStringLiteral { + pub fn with_value_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } +} +impl GlimmerSubexpression { + pub fn with_l_paren_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_path(self, element: GlimmerPath) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_arguments(self, element: GlimmerArgumentList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_r_paren_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into()))), + ) + } +} +impl GlimmerTripleStashExpression { + pub fn with_l_curly3_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_path(self, element: GlimmerPath) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_arguments(self, element: GlimmerArgumentList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_r_curly3_token_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into()))), + ) + } +} impl HtmlAttribute { pub fn with_name(self, element: HtmlAttributeName) -> Self { Self::unwrap_cast( diff --git a/crates/biome_js_analyze/src/lint/complexity/no_static_only_class.rs b/crates/biome_js_analyze/src/lint/complexity/no_static_only_class.rs index 96506645b38f..ce1d71f49a4a 100644 --- a/crates/biome_js_analyze/src/lint/complexity/no_static_only_class.rs +++ b/crates/biome_js_analyze/src/lint/complexity/no_static_only_class.rs @@ -162,6 +162,7 @@ impl Rule for NoStaticOnlyClass { .filter_map(|member| match member { AnyJsClassMember::JsBogusMember(_) | AnyJsClassMember::JsMetavariable(_) + | AnyJsClassMember::JsGlimmerTemplate(_) | AnyJsClassMember::JsEmptyClassMember(_) => None, AnyJsClassMember::JsConstructorClassMember(_) => Some(false), // See GH#4482: Constructors are not regarded as static AnyJsClassMember::TsConstructorSignatureClassMember(_) => Some(false), // See GH#4482: Constructors are not regarded as static diff --git a/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs b/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs index d57aa1da8eee..f2638b3bc871 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs @@ -226,6 +226,7 @@ fn is_valid_constructor(expression: AnyJsExpression) -> Option { | AnyJsExpression::JsBinaryExpression(_) | AnyJsExpression::JsBogusExpression(_) | AnyJsExpression::JsMetavariable(_) + | AnyJsExpression::JsGlimmerTemplate(_) | AnyJsExpression::JsInstanceofExpression(_) | AnyJsExpression::JsObjectExpression(_) | AnyJsExpression::JsPostUpdateExpression(_) diff --git a/crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs b/crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs index 90d28f18a956..a09309aed478 100644 --- a/crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs +++ b/crates/biome_js_analyze/src/lint/nursery/no_unused_expressions.rs @@ -259,6 +259,7 @@ fn is_disallowed(expr: &AnyJsExpression) -> SyntaxResult { | AnyJsExpression::JsComputedMemberExpression(_) | AnyJsExpression::JsConditionalExpression(_) | AnyJsExpression::JsFunctionExpression(_) + | AnyJsExpression::JsGlimmerTemplate(_) | AnyJsExpression::JsIdentifierExpression(_) | AnyJsExpression::JsImportMetaExpression(_) | AnyJsExpression::JsInExpression(_) diff --git a/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs b/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs index 27bf311096c4..b656ffc18066 100644 --- a/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs +++ b/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs @@ -1155,6 +1155,7 @@ fn selector_from_class_member(member: &AnyJsClassMember) -> Option { | AnyJsClassMember::JsConstructorClassMember(_) | AnyJsClassMember::TsConstructorSignatureClassMember(_) | AnyJsClassMember::JsEmptyClassMember(_) + | AnyJsClassMember::JsGlimmerTemplate(_) | AnyJsClassMember::JsStaticInitializationBlockClassMember(_) => return None, AnyJsClassMember::TsIndexSignatureClassMember(member) => { (Kind::ClassProperty, (&member.modifiers()).into()) diff --git a/crates/biome_js_factory/src/generated/node_factory.rs b/crates/biome_js_factory/src/generated/node_factory.rs index b510b6e9a91c..8acb9560381f 100644 --- a/crates/biome_js_factory/src/generated/node_factory.rs +++ b/crates/biome_js_factory/src/generated/node_factory.rs @@ -1895,6 +1895,12 @@ impl JsGetterObjectMemberBuilder { )) } } +pub fn js_glimmer_template(template_token_token: SyntaxToken) -> JsGlimmerTemplate { + JsGlimmerTemplate::unwrap_cast(SyntaxNode::new_detached( + JsSyntaxKind::JS_GLIMMER_TEMPLATE, + [Some(SyntaxElement::Token(template_token_token))], + )) +} pub fn js_identifier_assignment(name_token: SyntaxToken) -> JsIdentifierAssignment { JsIdentifierAssignment::unwrap_cast(SyntaxNode::new_detached( JsSyntaxKind::JS_IDENTIFIER_ASSIGNMENT, diff --git a/crates/biome_js_factory/src/generated/syntax_factory.rs b/crates/biome_js_factory/src/generated/syntax_factory.rs index 97832980c67f..4c4b7d2dcc50 100644 --- a/crates/biome_js_factory/src/generated/syntax_factory.rs +++ b/crates/biome_js_factory/src/generated/syntax_factory.rs @@ -2655,6 +2655,25 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.into_node(JS_GETTER_OBJECT_MEMBER, children) } + JS_GLIMMER_TEMPLATE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == GLIMMER_TEMPLATE + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + JS_GLIMMER_TEMPLATE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(JS_GLIMMER_TEMPLATE, children) + } JS_IDENTIFIER_ASSIGNMENT => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); diff --git a/crates/biome_js_formatter/src/generated.rs b/crates/biome_js_formatter/src/generated.rs index f57505f1dfe0..eba9ccf34777 100644 --- a/crates/biome_js_formatter/src/generated.rs +++ b/crates/biome_js_formatter/src/generated.rs @@ -2263,6 +2263,73 @@ impl IntoFormat for biome_js_syntax::JsGetterObjectMember { ) } } +impl FormatRule + for crate::js::auxiliary::glimmer_template::FormatJsGlimmerTemplate +{ + type Context = JsFormatContext; + /// Formats a `JsGlimmerTemplate` node using this formatting rule. + /// + /// # Examples + /// + /// ``` + /// // Given a `template` of type `biome_js_syntax::JsGlimmerTemplate` + /// // and a mutable `formatter` of type `JsFormatter`: + /// // let result = crate::js::auxiliary::glimmer_template::FormatJsGlimmerTemplate::default() + /// // .fmt(&template, &mut formatter); + /// // assert!(result.is_ok()); + /// ``` + #[inline(always)] + fn fmt( + &self, + node: &biome_js_syntax::JsGlimmerTemplate, + f: &mut JsFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_js_syntax::JsGlimmerTemplate { + type Format<'a> = FormatRefWithRule< + 'a, + biome_js_syntax::JsGlimmerTemplate, + crate::js::auxiliary::glimmer_template::FormatJsGlimmerTemplate, + >; + /// Format a borrowed `JsGlimmerTemplate` with the default Glimmer template formatter. + /// + /// # Examples + /// + /// ``` + /// // Given a `JsGlimmerTemplate` value `template`: + /// let formatted = template.format(); + /// ``` + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::js::auxiliary::glimmer_template::FormatJsGlimmerTemplate::default(), + ) + } +} +impl IntoFormat for biome_js_syntax::JsGlimmerTemplate { + type Format = FormatOwnedWithRule< + biome_js_syntax::JsGlimmerTemplate, + crate::js::auxiliary::glimmer_template::FormatJsGlimmerTemplate, + >; + /// Converts the Glimmer template node into an owned formatter that applies the Glimmer template formatting rule. + /// + /// # Examples + /// + /// ``` + /// use biome_js_syntax::JsGlimmerTemplate; + /// + /// let node = JsGlimmerTemplate::default(); + /// let owned_formatter = node.into_format(); + /// ``` + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::js::auxiliary::glimmer_template::FormatJsGlimmerTemplate::default(), + ) + } +} impl FormatRule for crate::js::assignments::identifier_assignment::FormatJsIdentifierAssignment { diff --git a/crates/biome_js_formatter/src/js/any/class_member.rs b/crates/biome_js_formatter/src/js/any/class_member.rs index e3ab803ed1fb..2439167b002c 100644 --- a/crates/biome_js_formatter/src/js/any/class_member.rs +++ b/crates/biome_js_formatter/src/js/any/class_member.rs @@ -12,6 +12,7 @@ impl FormatRule for FormatAnyJsClassMember { AnyJsClassMember::JsConstructorClassMember(node) => node.format().fmt(f), AnyJsClassMember::JsEmptyClassMember(node) => node.format().fmt(f), AnyJsClassMember::JsGetterClassMember(node) => node.format().fmt(f), + AnyJsClassMember::JsGlimmerTemplate(node) => node.format().fmt(f), AnyJsClassMember::JsMetavariable(node) => node.format().fmt(f), AnyJsClassMember::JsMethodClassMember(node) => node.format().fmt(f), AnyJsClassMember::JsPropertyClassMember(node) => node.format().fmt(f), diff --git a/crates/biome_js_formatter/src/js/any/expression.rs b/crates/biome_js_formatter/src/js/any/expression.rs index c1eceec24086..bdf6cb56e707 100644 --- a/crates/biome_js_formatter/src/js/any/expression.rs +++ b/crates/biome_js_formatter/src/js/any/expression.rs @@ -20,6 +20,7 @@ impl FormatRule for FormatAnyJsExpression { AnyJsExpression::JsComputedMemberExpression(node) => node.format().fmt(f), AnyJsExpression::JsConditionalExpression(node) => node.format().fmt(f), AnyJsExpression::JsFunctionExpression(node) => node.format().fmt(f), + AnyJsExpression::JsGlimmerTemplate(node) => node.format().fmt(f), AnyJsExpression::JsIdentifierExpression(node) => node.format().fmt(f), AnyJsExpression::JsImportCallExpression(node) => node.format().fmt(f), AnyJsExpression::JsImportMetaExpression(node) => node.format().fmt(f), diff --git a/crates/biome_js_formatter/src/js/any/statement.rs b/crates/biome_js_formatter/src/js/any/statement.rs index 3f6387aa1abf..ff8a8f8c4dbc 100644 --- a/crates/biome_js_formatter/src/js/any/statement.rs +++ b/crates/biome_js_formatter/src/js/any/statement.rs @@ -21,6 +21,7 @@ impl FormatRule for FormatAnyJsStatement { AnyJsStatement::JsForOfStatement(node) => node.format().fmt(f), AnyJsStatement::JsForStatement(node) => node.format().fmt(f), AnyJsStatement::JsFunctionDeclaration(node) => node.format().fmt(f), + AnyJsStatement::JsGlimmerTemplate(node) => node.format().fmt(f), AnyJsStatement::JsIfStatement(node) => node.format().fmt(f), AnyJsStatement::JsLabeledStatement(node) => node.format().fmt(f), AnyJsStatement::JsMetavariable(node) => node.format().fmt(f), diff --git a/crates/biome_js_formatter/src/js/auxiliary/glimmer_template.rs b/crates/biome_js_formatter/src/js/auxiliary/glimmer_template.rs new file mode 100644 index 000000000000..3c501c56b1b6 --- /dev/null +++ b/crates/biome_js_formatter/src/js/auxiliary/glimmer_template.rs @@ -0,0 +1,19 @@ +use crate::prelude::*; +use biome_formatter::write; +use biome_js_syntax::{JsGlimmerTemplate, JsGlimmerTemplateFields}; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatJsGlimmerTemplate; + +impl FormatNodeRule for FormatJsGlimmerTemplate { + /// Formats a Glimmer template by writing its template token verbatim. + /// + /// This is a pass-through formatter that preserves the original template content. + fn fmt_fields(&self, node: &JsGlimmerTemplate, f: &mut JsFormatter) -> FormatResult<()> { + let JsGlimmerTemplateFields { + template_token_token, + } = node.as_fields(); + + write![f, [template_token_token.format()]] + } +} diff --git a/crates/biome_js_formatter/src/js/auxiliary/mod.rs b/crates/biome_js_formatter/src/js/auxiliary/mod.rs index 9d978e673507..04b9b20799af 100644 --- a/crates/biome_js_formatter/src/js/auxiliary/mod.rs +++ b/crates/biome_js_formatter/src/js/auxiliary/mod.rs @@ -11,6 +11,7 @@ pub(crate) mod else_clause; pub(crate) mod expression_snipped; pub(crate) mod finally_clause; pub(crate) mod function_body; +pub(crate) mod glimmer_template; pub(crate) mod initializer_clause; pub(crate) mod label; pub(crate) mod metavariable; diff --git a/crates/biome_js_formatter/src/js/classes/property_class_member.rs b/crates/biome_js_formatter/src/js/classes/property_class_member.rs index 4932bd9ee95d..b1eb93d4bc9a 100644 --- a/crates/biome_js_formatter/src/js/classes/property_class_member.rs +++ b/crates/biome_js_formatter/src/js/classes/property_class_member.rs @@ -134,6 +134,7 @@ fn needs_semicolon(property: &AnyJsPropertyClassMember) -> SyntaxResult { | AnyJsClassMember::TsGetterSignatureClassMember(_) | AnyJsClassMember::TsSetterSignatureClassMember(_) | AnyJsClassMember::JsSetterClassMember(_) + | AnyJsClassMember::JsGlimmerTemplate(_) | AnyJsClassMember::JsMetavariable(_) => false, // Computed members may be misinterpreted as array accessors/array types @@ -170,6 +171,7 @@ fn has_modifiers(member: &AnyJsClassMember) -> bool { constructor.modifiers().is_empty() } AnyJsClassMember::JsEmptyClassMember(_) => true, + AnyJsClassMember::JsGlimmerTemplate(_) => true, AnyJsClassMember::JsGetterClassMember(getter) => getter.modifiers().is_empty(), AnyJsClassMember::JsMethodClassMember(method) => method.modifiers().is_empty(), AnyJsClassMember::JsPropertyClassMember(property) => property.modifiers().is_empty(), diff --git a/crates/biome_js_formatter/src/utils/format_node_without_comments.rs b/crates/biome_js_formatter/src/utils/format_node_without_comments.rs index adb96cb172b2..1dc0ad7a596c 100644 --- a/crates/biome_js_formatter/src/utils/format_node_without_comments.rs +++ b/crates/biome_js_formatter/src/utils/format_node_without_comments.rs @@ -93,6 +93,7 @@ impl FormatRule for FormatAnyJsExpressionWithoutComments { AnyJsExpression::JsFunctionExpression(node) => { FormatJsFunctionExpression::default().fmt_node(node, f) } + AnyJsExpression::JsGlimmerTemplate(node) => node.format().fmt(f), AnyJsExpression::JsMetavariable(node) => FormatJsMetavariable.fmt_node(node, f), AnyJsExpression::JsIdentifierExpression(node) => { FormatJsIdentifierExpression.fmt_node(node, f) diff --git a/crates/biome_js_parser/src/lexer/mod.rs b/crates/biome_js_parser/src/lexer/mod.rs index 40ea38cae8b0..1b243609c437 100644 --- a/crates/biome_js_parser/src/lexer/mod.rs +++ b/crates/biome_js_parser/src/lexer/mod.rs @@ -132,6 +132,9 @@ pub(crate) struct JsLexer<'src> { diagnostics: Vec, options: JsParserOptions, + + /// The file source type (for determining if we're in .gjs/.gts files) + source_type: JsFileSource, } impl<'src> Lexer<'src> for JsLexer<'src> { @@ -311,6 +314,7 @@ impl<'src> JsLexer<'src> { position: 0, diagnostics: vec![], options: JsParserOptions::default(), + source_type: JsFileSource::default(), } } @@ -318,6 +322,13 @@ impl<'src> JsLexer<'src> { Self { options, ..self } } + pub(crate) fn with_source_type(self, source_type: JsFileSource) -> Self { + Self { + source_type, + ..self + } + } + fn re_lex_binary_operator(&mut self) -> JsSyntaxKind { if self.current_byte() == Some(b'>') { match self.next_byte() { @@ -1727,6 +1738,93 @@ impl<'src> JsLexer<'src> { } } + /// Attempts to lex a Glimmer template block ``. + /// Returns Some(GLIMMER_TEMPLATE) if a template was found, None otherwise. + /// + /// IMPORTANT: This function uses lookahead to check if we have a valid `" + let closing_tag = b""; + let mut found_closing = false; + + while self.position < self.source.len() { + if let Some(b'<') = self.current_byte() { + // Check if this is "" + let end_pos = self.position + closing_tag.len(); + if end_pos <= self.source.len() + && &self.source.as_bytes()[self.position..end_pos] == closing_tag + { + // Found closing tag, consume it + self.advance(closing_tag.len()); + found_closing = true; + break; + } + } + self.next_byte(); + } + + if !found_closing { + // Unclosed template - create diagnostic + let err = ParseDiagnostic::new("Unclosed `` tag"); + self.push_diagnostic(err); + } + + Some(GLIMMER_TEMPLATE) + } + #[inline] fn resolve_minus(&mut self) -> JsSyntaxKind { match self.next_byte() { @@ -1744,6 +1842,13 @@ impl<'src> JsLexer<'src> { #[inline] fn resolve_less_than(&mut self) -> JsSyntaxKind { + // Check for Glimmer template in .gjs/.gts files + if self.source_type.as_embedding_kind().is_glimmer() + && let Some(template_kind) = self.try_lex_glimmer_template() + { + return template_kind; + } + match self.next_byte() { Some(b'<') => { if let Some(b'=') = self.next_byte() { diff --git a/crates/biome_js_parser/src/options.rs b/crates/biome_js_parser/src/options.rs index 47dcadeaf81a..083dcbcc5e67 100644 --- a/crates/biome_js_parser/src/options.rs +++ b/crates/biome_js_parser/src/options.rs @@ -1,3 +1,5 @@ +use biome_js_syntax::JsFileSource; + /// Options to pass to the JavaScript parser #[derive(Debug, Clone, Copy, Default)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] @@ -46,3 +48,28 @@ impl JsParserOptions { self.parse_class_parameter_decorators } } + +impl From<&JsFileSource> for JsParserOptions { + /// Derive parser options from the file source type. + /// + /// This allows parser configuration to be automatically determined based on + /// file characteristics (language, variant, embedding kind, etc.) rather than + /// requiring explicit option passing. + /// + /// Currently returns default options for all file types, but provides a + /// centralized place to configure file-type-specific parsing behavior in the future. + /// For example, Glimmer template parsing (.gjs/.gts files) is handled at the + /// lexer level by checking the embedding kind. + fn from(_file_source: &JsFileSource) -> Self { + // File-type-specific options could be configured here based on: + // - _file_source.language() - JavaScript vs TypeScript + // - _file_source.variant() - Standard vs JSX + // - _file_source.module_kind() - Script vs Module + // - _file_source.as_embedding_kind() - Astro, Vue, Svelte, Glimmer, etc. + // + // For now, Glimmer-specific behavior (template lexing) is handled in the lexer + // by checking _file_source.as_embedding_kind().is_glimmer() + + Self::default() + } +} diff --git a/crates/biome_js_parser/src/parse.rs b/crates/biome_js_parser/src/parse.rs index d2c78d6e9f5f..9c1164dadd8d 100644 --- a/crates/biome_js_parser/src/parse.rs +++ b/crates/biome_js_parser/src/parse.rs @@ -45,7 +45,7 @@ impl Parse { /// The syntax node represented by this Parse result /// /// ``` - /// use biome_js_parser::{JsParserOptions, parse_script}; + /// use biome_js_parser::parse_script; /// use biome_js_syntax::{JsIfStatement, JsSyntaxKind}; /// use biome_rowan::{AstNode, AstNodeList}; /// @@ -54,8 +54,7 @@ impl Parse { /// if (a > 5) { /// /* something */ /// } - /// ", - /// JsParserOptions::default() + /// " /// ); /// /// // The first stmt in the root syntax node (Script) is the if statement. @@ -142,9 +141,8 @@ impl From for AnyParse { fn parse_common( text: &str, source_type: JsFileSource, - options: JsParserOptions, ) -> (Vec>, Vec, Vec) { - let mut parser = JsParser::new(text, source_type, options); + let mut parser = JsParser::new(text, source_type); syntax::program::parse(&mut parser); let (events, trivia, errors) = parser.finish(); @@ -156,11 +154,11 @@ fn parse_common( /// Or turned into a typed [`JsScript`](JsScript) with [`tree`](Parse::tree). /// /// ``` -/// use biome_js_parser::{JsParserOptions, parse_script}; +/// use biome_js_parser::parse_script; /// use biome_js_syntax::{JsSyntaxToken, JsFileSource, JsSyntaxList, JsComputedMemberExpression}; /// use biome_rowan::{AstNode, Direction}; /// -/// let parse = parse_script("foo.bar[2]", JsParserOptions::default()); +/// let parse = parse_script("foo.bar[2]"); /// // Parse returns a JS Root which contains two lists, the directives and the statements, let's get the statements /// let stmt = parse.syntax().children().nth(1).unwrap(); /// // The untyped syntax node of `foo.bar[2]`, the root node is `Script`. @@ -183,11 +181,13 @@ fn parse_common( /// /// assert_eq!(&tokens, &vec!["foo", ".", "bar", "[", "2", "]"]); /// ``` -pub fn parse_script(text: &str, options: JsParserOptions) -> Parse { +/// Parses the provided string as an ECMAScript script. +/// +/// Parser options are automatically derived from the source type. +pub fn parse_script(text: &str) -> Parse { parse( text, JsFileSource::js_module().with_module_kind(ModuleKind::Script), - options, ) .cast::() .unwrap() @@ -199,14 +199,14 @@ pub fn parse_script(text: &str, options: JsParserOptions) -> Parse { /// /// Check the diagnostics emitted by the code /// ``` -/// use biome_js_parser::{JsParserOptions, parse_module}; +/// use biome_js_parser::parse_module; /// let source = r#" /// import { someModule } from "./someModule.js"; /// /// someModule(); /// "#; /// -/// let parse = parse_module(source, JsParserOptions::default()); +/// let parse = parse_module(source); /// /// // Retrieve the diagnostics emitted /// assert_eq!(parse.diagnostics().len(), 0); @@ -214,7 +214,7 @@ pub fn parse_script(text: &str, options: JsParserOptions) -> Parse { /// /// Retrieve the emitted AST and check its kind: /// ``` -/// use biome_js_parser::{JsParserOptions, parse_module}; +/// use biome_js_parser::parse_module; /// use biome_js_syntax::JsSyntaxKind; /// use biome_rowan::AstNode; /// let source = r#" @@ -222,15 +222,18 @@ pub fn parse_script(text: &str, options: JsParserOptions) -> Parse { /// /// someModule(); /// "#; -/// let parse = parse_module(source, JsParserOptions::default()); +/// let parse = parse_module(source); /// /// let tree = parse.tree(); /// /// assert_eq!(tree.syntax().kind(), JsSyntaxKind::JS_MODULE); /// ``` /// -pub fn parse_module(text: &str, options: JsParserOptions) -> Parse { - parse(text, JsFileSource::js_module(), options) +/// Parses the provided string as an ECMAScript module. +/// +/// Parser options are automatically derived from the source type. +pub fn parse_module(text: &str) -> Parse { + parse(text, JsFileSource::js_module()) .cast::() .unwrap() } @@ -240,27 +243,62 @@ pub fn parse_module(text: &str, options: JsParserOptions) -> Parse { /// ### Examples /// /// ``` -/// use biome_js_parser::{JsParserOptions, parse}; +/// use biome_js_parser::parse; /// use biome_js_syntax::{LanguageVariant, LanguageVersion, ModuleKind, JsFileSource}; /// // parse source text as TypeScript /// let mut module = JsFileSource::ts(); -/// let mut parsed = parse("type F = {}", module, JsParserOptions::default()); +/// let mut parsed = parse("type F = {}", module); /// assert_eq!(parsed.diagnostics().len(), 0); /// // parse source text as JSX /// module = JsFileSource::jsx(); -/// parsed = parse("", module, JsParserOptions::default()); +/// parsed = parse("", module); /// assert_eq!(parsed.diagnostics().len(), 0); /// // parse source text with granular control /// module = JsFileSource::default() /// .with_version(LanguageVersion::ESNext) /// .with_module_kind(ModuleKind::Module) /// .with_variant(LanguageVariant::Jsx); -/// parsed = parse("foo[bar]", module, JsParserOptions::default()); +/// parsed = parse("foo[bar]", module); /// assert_eq!(parsed.diagnostics().len(), 0); /// ``` -pub fn parse(text: &str, source_type: JsFileSource, options: JsParserOptions) -> Parse { +/// Parses the provided string as an ECMAScript program. +/// +/// Parser options are automatically derived from the `source_type` based on +/// file characteristics (language, variant, embedding kind, etc.). +pub fn parse(text: &str, source_type: JsFileSource) -> Parse { let mut cache = NodeCache::default(); - parse_js_with_cache(text, source_type, options, &mut cache) + parse_js_with_cache(text, source_type, &mut cache) +} + +/// Parses with explicitly provided options (for testing). +/// +/// This is primarily used by the test harness to apply custom parsing options +/// from test configuration files. Regular code should use `parse` which derives +/// options from the source type. +pub fn parse_with_options( + text: &str, + source_type: JsFileSource, + options: JsParserOptions, +) -> Parse { + let mut cache = NodeCache::default(); + let (events, errors, tokens) = parse_common_with_options(text, source_type, options); + let mut tree_sink = JsLosslessTreeSink::with_cache(text, &tokens, &mut cache); + biome_parser::event::process(&mut tree_sink, events, errors); + let (green, parse_errors) = tree_sink.finish(); + Parse::new(green, parse_errors) +} + +fn parse_common_with_options( + text: &str, + source_type: JsFileSource, + options: JsParserOptions, +) -> (Vec>, Vec, Vec) { + let mut parser = parser::JsParser::with_options(text, source_type, options); + syntax::program::parse(&mut parser); + + let (events, trivia, errors) = parser.finish(); + + (events, errors, trivia) } /// Parses the provided string as a EcmaScript program using the provided syntax features and node cache. @@ -268,7 +306,7 @@ pub fn parse(text: &str, source_type: JsFileSource, options: JsParserOptions) -> /// ### Examples /// /// ``` -/// use biome_js_parser::{JsParserOptions, parse_js_with_cache}; +/// use biome_js_parser::parse_js_with_cache; /// use biome_js_syntax::JsFileSource; /// use biome_rowan::NodeCache; /// @@ -276,20 +314,22 @@ pub fn parse(text: &str, source_type: JsFileSource, options: JsParserOptions) -> /// let mut cache = NodeCache::default(); /// let mut source = "function f() { return 2 }"; /// -/// let parsed = parse_js_with_cache(source, source_type, JsParserOptions::default(), &mut cache); +/// let parsed = parse_js_with_cache(source, source_type, &mut cache); /// assert_eq!(parsed.diagnostics().len(), 0); /// /// source = "function bar() { return 3 }"; -/// let parsed = parse_js_with_cache(source, source_type, JsParserOptions::default(), &mut cache); +/// let parsed = parse_js_with_cache(source, source_type, &mut cache); /// assert_eq!(parsed.diagnostics().len(), 0); /// ``` +/// Parses the provided string using a node cache for improved performance. +/// +/// Parser options are automatically derived from the `source_type`. pub fn parse_js_with_cache( text: &str, source_type: JsFileSource, - options: JsParserOptions, cache: &mut NodeCache, ) -> Parse { - let (events, errors, tokens) = parse_common(text, source_type, options); + let (events, errors, tokens) = parse_common(text, source_type); let mut tree_sink = JsLosslessTreeSink::with_cache(text, &tokens, cache); biome_parser::event::process(&mut tree_sink, events, errors); let (green, parse_errors) = tree_sink.finish(); @@ -400,7 +440,7 @@ pub fn parse_js_with_offset_and_cache( options: JsParserOptions, cache: &mut NodeCache, ) -> JsOffsetParse { - let (events, errors, tokens) = parse_common(text, source_type, options); + let (events, errors, tokens) = parse_common_with_options(text, source_type, options); let mut tree_sink = crate::JsOffsetLosslessTreeSink::with_cache(text, &tokens, cache, base_offset); biome_parser::event::process(&mut tree_sink, events, errors); @@ -489,7 +529,6 @@ mod tests { let normal_parse = parse_js_with_cache( js_code, JsFileSource::js_module(), - JsParserOptions::default(), &mut biome_rowan::NodeCache::default(), ); diff --git a/crates/biome_js_parser/src/parser.rs b/crates/biome_js_parser/src/parser.rs index 33a4df78c1e3..0e060088238a 100644 --- a/crates/biome_js_parser/src/parser.rs +++ b/crates/biome_js_parser/src/parser.rs @@ -40,8 +40,32 @@ pub struct JsParser<'source> { impl<'source> JsParser<'source> { /// Creates a new parser that parses the `source`. - pub fn new(source: &'source str, source_type: JsFileSource, options: JsParserOptions) -> Self { - let source = JsTokenSource::from_str(source, options); + /// + /// Parser options are automatically derived from the `source_type` based on + /// file characteristics (language, variant, embedding kind, etc.). + pub fn new(source: &'source str, source_type: JsFileSource) -> Self { + let options = JsParserOptions::from(&source_type); + let source = JsTokenSource::from_str(source, source_type); + + JsParser { + state: JsParserState::new(&source_type), + source_type, + context: ParserContext::default(), + source, + options, + } + } + + /// Creates a new parser with explicit options (for testing). + /// + /// This is primarily used by the test harness. Regular code should use `new` + /// which derives options from the source type. + pub(crate) fn with_options( + source: &'source str, + source_type: JsFileSource, + options: JsParserOptions, + ) -> Self { + let source = JsTokenSource::from_str(source, source_type); JsParser { state: JsParserState::new(&source_type), @@ -226,7 +250,7 @@ mod tests { expected = "Marker must either be `completed` or `abandoned` to avoid that children are implicitly attached to a marker's parent." )] fn uncompleted_markers_panic() { - let mut parser = JsParser::new( + let mut parser = JsParser::with_options( "'use strict'", JsFileSource::default(), JsParserOptions::default(), @@ -238,7 +262,7 @@ mod tests { #[test] fn completed_marker_doesnt_panic() { - let mut p = JsParser::new( + let mut p = JsParser::with_options( "'use strict'", JsFileSource::default(), JsParserOptions::default(), @@ -251,7 +275,7 @@ mod tests { #[test] fn abandoned_marker_doesnt_panic() { - let mut p = JsParser::new( + let mut p = JsParser::with_options( "'use strict'", JsFileSource::default(), JsParserOptions::default(), diff --git a/crates/biome_js_parser/src/syntax/class.rs b/crates/biome_js_parser/src/syntax/class.rs index 2c337db6db53..5a6b5838938d 100644 --- a/crates/biome_js_parser/src/syntax/class.rs +++ b/crates/biome_js_parser/src/syntax/class.rs @@ -535,6 +535,12 @@ fn parse_class_member(p: &mut JsParser, inside_abstract_class: bool) -> ParsedSy return Present(member_marker.complete(p, JS_EMPTY_CLASS_MEMBER)); } + // Glimmer templates in class bodies + if p.at(GLIMMER_TEMPLATE) { + p.bump(GLIMMER_TEMPLATE); + return Present(member_marker.complete(p, JS_GLIMMER_TEMPLATE)); + } + let mut modifiers = parse_class_member_modifiers(p, false); if is_at_static_initialization_block_class_member(p) { diff --git a/crates/biome_js_parser/src/syntax/expr.rs b/crates/biome_js_parser/src/syntax/expr.rs index 5b23ac83dc3c..dfdc98a783bd 100644 --- a/crates/biome_js_parser/src/syntax/expr.rs +++ b/crates/biome_js_parser/src/syntax/expr.rs @@ -1249,7 +1249,8 @@ pub(crate) fn is_nth_at_expression(p: &mut JsParser, n: usize) -> bool { | JS_NUMBER_LITERAL | JS_BIGINT_LITERAL | JS_STRING_LITERAL - | NULL_KW => true, + | NULL_KW + | GLIMMER_TEMPLATE => true, t => t.is_contextual_keyword() || t.is_future_reserved_keyword(), } } @@ -1392,6 +1393,9 @@ fn parse_primary_expression(p: &mut JsParser, context: ExpressionContext) -> Par // let a = b; T![<] if Jsx.is_supported(p) => return parse_jsx_tag_expression(p), + // Glimmer templates in .gjs/.gts files + GLIMMER_TEMPLATE => return parse_glimmer_template(p), + // test_err js primary_expr_invalid_recovery // let a = \; foo(); t if t.is_contextual_keyword() || t.is_future_reserved_keyword() => { @@ -2168,3 +2172,14 @@ fn parse_import_call_expression( args.complete(p, JS_CALL_ARGUMENTS); marker.complete(p, JS_IMPORT_CALL_EXPRESSION) } + +/// Parses a Glimmer template block `` in .gjs/.gts files +pub(crate) fn parse_glimmer_template(p: &mut JsParser) -> ParsedSyntax { + if !p.at(GLIMMER_TEMPLATE) { + return Absent; + } + + let m = p.start(); + p.bump(GLIMMER_TEMPLATE); + Present(m.complete(p, JS_GLIMMER_TEMPLATE)) +} diff --git a/crates/biome_js_parser/src/syntax/stmt.rs b/crates/biome_js_parser/src/syntax/stmt.rs index a73bb0e31e08..c8abd0c22bbe 100644 --- a/crates/biome_js_parser/src/syntax/stmt.rs +++ b/crates/biome_js_parser/src/syntax/stmt.rs @@ -373,6 +373,12 @@ pub(crate) fn parse_statement(p: &mut JsParser, context: StatementContext) -> Pa }, ) } + // Glimmer templates at top level in .gjs/.gts files + GLIMMER_TEMPLATE => { + let m = p.start(); + p.bump(GLIMMER_TEMPLATE); + Present(m.complete(p, JS_GLIMMER_TEMPLATE)) + } _ if is_at_expression(p) || is_at_metavariable(p) => parse_expression_statement(p), _ => Absent, } diff --git a/crates/biome_js_parser/src/token_source.rs b/crates/biome_js_parser/src/token_source.rs index f282a4f0eed7..e4037159e8d6 100644 --- a/crates/biome_js_parser/src/token_source.rs +++ b/crates/biome_js_parser/src/token_source.rs @@ -25,9 +25,21 @@ impl<'l> JsTokenSource<'l> { } } - /// Creates a new token source for the given string - pub fn from_str(source: &'l str, options: JsParserOptions) -> Self { - let lexer = JsLexer::from_str(source).with_options(options); + /// Creates a new token source for the given string. + /// + /// Parser options are automatically derived from the `source_type` using + /// `From<&JsFileSource> for JsParserOptions`, ensuring consistent configuration + /// based on file characteristics. + pub fn from_str( + source: &'l str, + source_type: biome_js_syntax::JsFileSource, + ) -> Self { + // Derive parser options from file source type + let options = JsParserOptions::from(&source_type); + + let lexer = JsLexer::from_str(source) + .with_options(options) + .with_source_type(source_type); let buffered = BufferedLexer::new(lexer); let mut source = JsTokenSource::new(buffered); diff --git a/crates/biome_js_parser/tests/js_test_suite/error/glimmer/glimmer_incomplete_less_than.gjs b/crates/biome_js_parser/tests/js_test_suite/error/glimmer/glimmer_incomplete_less_than.gjs new file mode 100644 index 000000000000..11eb9e05c1fb --- /dev/null +++ b/crates/biome_js_parser/tests/js_test_suite/error/glimmer/glimmer_incomplete_less_than.gjs @@ -0,0 +1,3 @@ +// Test bare < at EOF +// Should handle EOF gracefully after less-than +const x = < diff --git a/crates/biome_js_parser/tests/js_test_suite/error/glimmer/glimmer_incomplete_less_than.gjs.snap b/crates/biome_js_parser/tests/js_test_suite/error/glimmer/glimmer_incomplete_less_than.gjs.snap new file mode 100644 index 000000000000..9ea45ccbe8ba --- /dev/null +++ b/crates/biome_js_parser/tests/js_test_suite/error/glimmer/glimmer_incomplete_less_than.gjs.snap @@ -0,0 +1,92 @@ +--- +source: crates/biome_js_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```js +// Test bare < at EOF +// Should handle EOF gracefully after less-than +const x = < + +``` + + +## AST + +``` +JsModule { + bom_token: missing (optional), + interpreter_token: missing (optional), + directives: JsDirectiveList [], + items: JsModuleItemList [ + JsVariableStatement { + declaration: JsVariableDeclaration { + await_token: missing (optional), + kind: CONST_KW@0..76 "const" [Comments("// Test bare < at EOF"), Newline("\n"), Comments("// Should handle EOF ..."), Newline("\n")] [Whitespace(" ")], + declarators: JsVariableDeclaratorList [ + JsVariableDeclarator { + id: JsIdentifierBinding { + name_token: IDENT@76..78 "x" [] [Whitespace(" ")], + }, + variable_annotation: missing (optional), + initializer: JsInitializerClause { + eq_token: EQ@78..80 "=" [] [Whitespace(" ")], + expression: JsBogusExpression { + items: [ + L_ANGLE@80..81 "<" [] [], + ], + }, + }, + }, + ], + }, + semicolon_token: missing (optional), + }, + ], + eof_token: EOF@81..82 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: JS_MODULE@0..82 + 0: (empty) + 1: (empty) + 2: JS_DIRECTIVE_LIST@0..0 + 3: JS_MODULE_ITEM_LIST@0..81 + 0: JS_VARIABLE_STATEMENT@0..81 + 0: JS_VARIABLE_DECLARATION@0..81 + 0: (empty) + 1: CONST_KW@0..76 "const" [Comments("// Test bare < at EOF"), Newline("\n"), Comments("// Should handle EOF ..."), Newline("\n")] [Whitespace(" ")] + 2: JS_VARIABLE_DECLARATOR_LIST@76..81 + 0: JS_VARIABLE_DECLARATOR@76..81 + 0: JS_IDENTIFIER_BINDING@76..78 + 0: IDENT@76..78 "x" [] [Whitespace(" ")] + 1: (empty) + 2: JS_INITIALIZER_CLAUSE@78..81 + 0: EQ@78..80 "=" [] [Whitespace(" ")] + 1: JS_BOGUS_EXPRESSION@80..81 + 0: L_ANGLE@80..81 "<" [] [] + 1: (empty) + 4: EOF@81..82 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +glimmer_incomplete_less_than.gjs:3:11 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × type assertion are a TypeScript only feature. Convert your file to a TypeScript file or remove the syntax. + + 1 │ // Test bare < at EOF + 2 │ // Should handle EOF gracefully after less-than + > 3 │ const x = < + │ ^ + 4 │ + + i TypeScript only syntax + +``` diff --git a/crates/biome_js_parser/tests/js_test_suite/error/glimmer/glimmer_incomplete_templat.gjs b/crates/biome_js_parser/tests/js_test_suite/error/glimmer/glimmer_incomplete_templat.gjs new file mode 100644 index 000000000000..f1f4078fed94 --- /dev/null +++ b/crates/biome_js_parser/tests/js_test_suite/error/glimmer/glimmer_incomplete_templat.gjs @@ -0,0 +1,3 @@ +// Test incomplete "templat" at EOF +// This tests lexer backtracking at EOF boundary +const x = 3 │ const x = ) is forbidden in .gjs files +// Only