diff --git a/.changeset/cruel-candles-grab.md b/.changeset/cruel-candles-grab.md new file mode 100644 index 000000000000..9ff0a60dfc64 --- /dev/null +++ b/.changeset/cruel-candles-grab.md @@ -0,0 +1,5 @@ +--- +"@biomejs/biome": patch +--- + +Added proper parsing and formatting for Svelte directives when the `html.experimentalFullSupportEnabled` is set to `true`. diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index d51efb4aa9e7..000000000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(cargo clippy:*)", - "Bash(cargo t:*)", - "Bash(cargo clean:*)" - ], - "deny": [], - "ask": [] - } -} diff --git a/.github/workflows/benchmark_html.yml b/.github/workflows/benchmark_html.yml new file mode 100644 index 000000000000..560a110c6445 --- /dev/null +++ b/.github/workflows/benchmark_html.yml @@ -0,0 +1,79 @@ +name: Benchmarks HTML +on: + workflow_dispatch: + merge_group: + pull_request: + types: [ opened, synchronize ] + branches: + - main + - next + paths: + - 'Cargo.lock' + - 'crates/biome_html_analyze/**/*.rs' + - 'crates/biome_html_formatter/**/*.rs' + - 'crates/biome_html_parser/**/*.rs' + - 'crates/biome_html_*/**/*.rs' + - 'crates/biome_formatter/**/*.rs' + - 'crates/biome_rowan/**/*.rs' + - 'crates/biome_parser/**/*.rs' + push: + branches: + - main + - next + paths: + - 'Cargo.lock' + - 'crates/biome_html_analyze/**/*.rs' + - 'crates/biome_html_formatter/**/*.rs' + - 'crates/biome_html_parser/**/*.rs' + - 'crates/biome_html_*/**/*.rs' + - 'crates/biome_formatter/**/*.rs' + - 'crates/biome_rowan/**/*.rs' + - 'crates/biome_parser/**/*.rs' + +env: + RUST_LOG: info + +jobs: + bench: + permissions: + contents: read + pull-requests: write + name: Bench + runs-on: depot-ubuntu-24.04-arm-16 + strategy: + matrix: + package: + - biome_html_parser + - biome_html_formatter + - biome_html_analyze + + steps: + + - name: Checkout PR Branch + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Install toolchain + uses: moonrepo/setup-rust@ede6de059f8046a5e236c94046823e2af11ca670 # v1.2.2 + with: + channel: stable + cache-target: release + bins: cargo-codspeed + cache-base: main + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Compile + timeout-minutes: 20 + run: cargo codspeed build -p ${{ matrix.package }} + env: + CARGO_BUILD_JOBS: 3 # Default is 4 (equals to the vCPU count of the runner), which leads OOM on cargo build + + - name: Run the benchmarks + uses: CodSpeedHQ/action@972e3437949c89e1357ebd1a2dbc852fcbc57245 # v4.5.1 + timeout-minutes: 50 + with: + mode: simulation + run: cargo codspeed run + token: ${{ secrets.CODSPEED_TOKEN }} diff --git a/.gitignore b/.gitignore index 0a4510a85a43..783a210e9e57 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ Profile-*.json **/build .pnpm-debug.log .vercel +.claude/settings.local.json # https://github.com/nnethercote/dhat-rs output file dhat-heap.json diff --git a/Cargo.lock b/Cargo.lock index 248e832d137d..92cc9c9c96c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -780,10 +780,13 @@ dependencies = [ "biome_suppression", "biome_test_utils", "camino", + "codspeed-criterion-compat", "insta", + "mimalloc", "schemars", "serde", "tests_macros", + "tikv-jemallocator", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index bf9e2aee520a..33385f130fb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ anyhow = "1.0.100" biome_analyze = { path = "./crates/biome_analyze", version = "0.5.7" } biome_aria = { path = "./crates/biome_aria", version = "0.5.7" } biome_aria_metadata = { path = "./crates/biome_aria_metadata", version = "0.5.7" } +biome_bench_utils = { path = "./crates/biome_bench_utils" } # not publish biome_cli = { path = "./crates/biome_cli" } biome_configuration = { path = "./crates/biome_configuration" } diff --git a/crates/biome_html_analyze/Cargo.toml b/crates/biome_html_analyze/Cargo.toml index 459e75925ba2..86c46ab076d3 100644 --- a/crates/biome_html_analyze/Cargo.toml +++ b/crates/biome_html_analyze/Cargo.toml @@ -10,6 +10,10 @@ license.workspace = true keywords.workspace = true categories.workspace = true +[[bench]] +harness = false +name = "html_analyzer" + [dependencies] biome_analyze = { workspace = true } biome_aria_metadata = { workspace = true } @@ -30,9 +34,16 @@ serde = { workspace = true, features = ["derive"] } biome_html_parser = { path = "../biome_html_parser" } biome_test_utils = { path = "../biome_test_utils" } camino = { workspace = true } +criterion = { package = "codspeed-criterion-compat", version = "=3.0.5" } insta = { workspace = true, features = ["glob"] } tests_macros = { path = "../tests_macros" } +[target.'cfg(all(target_family="unix", not(all(target_arch = "aarch64", target_env = "musl"))))'.dev-dependencies] +tikv-jemallocator = { workspace = true } + +[target.'cfg(target_os = "windows")'.dev-dependencies] +mimalloc = { workspace = true } + [features] schema = ["schemars"] diff --git a/crates/biome_html_analyze/benches/html_analyzer.rs b/crates/biome_html_analyze/benches/html_analyzer.rs new file mode 100644 index 000000000000..7cb476aa2c20 --- /dev/null +++ b/crates/biome_html_analyze/benches/html_analyzer.rs @@ -0,0 +1,86 @@ +use biome_analyze::options::JsxRuntime; +use biome_analyze::{ + AnalysisFilter, AnalyzerConfiguration, AnalyzerOptions, ControlFlow, Never, + RuleCategoriesBuilder, +}; +use biome_html_parser::{HtmlParseOptions, parse_html}; +use biome_html_syntax::HtmlFileSource; +use biome_test_utils::BenchCase; +use criterion::{BenchmarkId, Criterion, black_box, criterion_group, criterion_main}; +use std::collections::HashMap; + +#[cfg(target_os = "windows")] +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + +#[cfg(all( + any(target_os = "macos", target_os = "linux"), + not(target_env = "musl"), +))] +#[global_allocator] +static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + +// Jemallocator does not work on aarch64 with musl, so we'll use the system allocator instead +#[cfg(all(target_env = "musl", target_os = "linux", target_arch = "aarch64"))] +#[global_allocator] +static GLOBAL: std::alloc::System = std::alloc::System; +fn bench_analyzer(criterion: &mut Criterion) { + let mut all_suites = HashMap::new(); + all_suites.insert("html", include_str!("libs-html.txt")); + let mut libs = vec![]; + libs.extend(all_suites.values().flat_map(|suite| suite.lines())); + + let mut group = criterion.benchmark_group("html_analyzer"); + + for lib in libs { + let test_case = BenchCase::try_from(lib); + + match test_case { + Ok(test_case) => { + let code = test_case.code(); + let file_source = HtmlFileSource::html(); + group.throughput(criterion::Throughput::Bytes(code.len() as u64)); + group.bench_with_input( + BenchmarkId::from_parameter(test_case.filename()), + code, + |b, _| { + let parse = parse_html(code, HtmlParseOptions::from(&file_source)); + + let filter = AnalysisFilter { + categories: RuleCategoriesBuilder::default() + .with_syntax() + .with_lint() + .with_assist() + .build(), + ..AnalysisFilter::default() + }; + let options = AnalyzerOptions::default().with_configuration( + AnalyzerConfiguration::default() + .with_jsx_runtime(JsxRuntime::default()), + ); + + b.iter(|| { + biome_html_analyze::analyze( + &parse.tree(), + filter, + &options, + file_source, + |event| { + black_box(event.diagnostic()); + black_box(event.actions()); + ControlFlow::::Continue(()) + }, + ); + }); + }, + ); + } + Err(e) => println!("{e:?}"), + } + } + + group.finish(); +} + +criterion_group!(html_analyzer, bench_analyzer); +criterion_main!(html_analyzer); diff --git a/crates/biome_html_analyze/benches/libs-html.txt b/crates/biome_html_analyze/benches/libs-html.txt new file mode 100644 index 000000000000..405364bb3395 --- /dev/null +++ b/crates/biome_html_analyze/benches/libs-html.txt @@ -0,0 +1 @@ +https://raw.githubusercontent.com/dyc3/opentogethertube/e6b44c716289a8babb2f70624e452542e45c2a1b/client/index.html diff --git a/crates/biome_html_factory/src/generated/node_factory.rs b/crates/biome_html_factory/src/generated/node_factory.rs index 0ec38def2148..46587e785628 100644 --- a/crates/biome_html_factory/src/generated/node_factory.rs +++ b/crates/biome_html_factory/src/generated/node_factory.rs @@ -347,6 +347,18 @@ pub fn html_text_expression(html_literal_token: SyntaxToken) -> HtmlTextExpressi [Some(SyntaxElement::Token(html_literal_token))], )) } +pub fn svelte_animate_directive( + animate_token: SyntaxToken, + value: SvelteDirectiveValue, +) -> SvelteAnimateDirective { + SvelteAnimateDirective::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_ANIMATE_DIRECTIVE, + [ + Some(SyntaxElement::Token(animate_token)), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} pub fn svelte_attach_attribute( sv_curly_at_token: SyntaxToken, attach_token: SyntaxToken, @@ -503,6 +515,30 @@ pub fn svelte_await_then_clause( ], )) } +pub fn svelte_bind_directive( + bind_token: SyntaxToken, + value: SvelteDirectiveValue, +) -> SvelteBindDirective { + SvelteBindDirective::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_BIND_DIRECTIVE, + [ + Some(SyntaxElement::Token(bind_token)), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} +pub fn svelte_class_directive( + class_token: SyntaxToken, + value: SvelteDirectiveValue, +) -> SvelteClassDirective { + SvelteClassDirective::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_CLASS_DIRECTIVE, + [ + Some(SyntaxElement::Token(class_token)), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} pub fn svelte_const_block( sv_curly_at_token: SyntaxToken, const_token: SyntaxToken, @@ -549,6 +585,54 @@ pub fn svelte_debug_block( ], )) } +pub fn svelte_directive_modifier( + bitwise_or_token: SyntaxToken, + name: SvelteName, +) -> SvelteDirectiveModifier { + SvelteDirectiveModifier::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_DIRECTIVE_MODIFIER, + [ + Some(SyntaxElement::Token(bitwise_or_token)), + Some(SyntaxElement::Node(name.into_syntax())), + ], + )) +} +pub fn svelte_directive_value( + colon_token: SyntaxToken, + property: AnySvelteBindingProperty, + modifiers: SvelteDirectiveModifierList, +) -> SvelteDirectiveValueBuilder { + SvelteDirectiveValueBuilder { + colon_token, + property, + modifiers, + initializer: None, + } +} +pub struct SvelteDirectiveValueBuilder { + colon_token: SyntaxToken, + property: AnySvelteBindingProperty, + modifiers: SvelteDirectiveModifierList, + initializer: Option, +} +impl SvelteDirectiveValueBuilder { + pub fn with_initializer(mut self, initializer: HtmlAttributeInitializerClause) -> Self { + self.initializer = Some(initializer); + self + } + pub fn build(self) -> SvelteDirectiveValue { + SvelteDirectiveValue::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_DIRECTIVE_VALUE, + [ + Some(SyntaxElement::Token(self.colon_token)), + Some(SyntaxElement::Node(self.property.into_syntax())), + Some(SyntaxElement::Node(self.modifiers.into_syntax())), + self.initializer + .map(|token| SyntaxElement::Node(token.into_syntax())), + ], + )) + } +} pub fn svelte_each_as_keyed_item( as_token: SyntaxToken, name: AnySvelteEachName, @@ -842,6 +926,18 @@ pub fn svelte_if_opening_block( ], )) } +pub fn svelte_in_directive( + in_token: SyntaxToken, + value: SvelteDirectiveValue, +) -> SvelteInDirective { + SvelteInDirective::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_IN_DIRECTIVE, + [ + Some(SyntaxElement::Token(in_token)), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} pub fn svelte_key_block( opening_block: SvelteKeyOpeningBlock, children: HtmlElementList, @@ -886,12 +982,30 @@ pub fn svelte_key_opening_block( ], )) } +pub fn svelte_literal(value_token: SyntaxToken) -> SvelteLiteral { + SvelteLiteral::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_LITERAL, + [Some(SyntaxElement::Token(value_token))], + )) +} pub fn svelte_name(ident_token: SyntaxToken) -> SvelteName { SvelteName::unwrap_cast(SyntaxNode::new_detached( HtmlSyntaxKind::SVELTE_NAME, [Some(SyntaxElement::Token(ident_token))], )) } +pub fn svelte_out_directive( + out_token: SyntaxToken, + value: SvelteDirectiveValue, +) -> SvelteOutDirective { + SvelteOutDirective::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_OUT_DIRECTIVE, + [ + Some(SyntaxElement::Token(out_token)), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} pub fn svelte_render_block( sv_curly_at_token: SyntaxToken, render_token: SyntaxToken, @@ -975,6 +1089,42 @@ pub fn svelte_square_destructured_name( ], )) } +pub fn svelte_style_directive( + style_token: SyntaxToken, + value: SvelteDirectiveValue, +) -> SvelteStyleDirective { + SvelteStyleDirective::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_STYLE_DIRECTIVE, + [ + Some(SyntaxElement::Token(style_token)), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} +pub fn svelte_transition_directive( + transition_token: SyntaxToken, + value: SvelteDirectiveValue, +) -> SvelteTransitionDirective { + SvelteTransitionDirective::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_TRANSITION_DIRECTIVE, + [ + Some(SyntaxElement::Token(transition_token)), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} +pub fn svelte_use_directive( + use_token: SyntaxToken, + value: SvelteDirectiveValue, +) -> SvelteUseDirective { + SvelteUseDirective::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_USE_DIRECTIVE, + [ + Some(SyntaxElement::Token(use_token)), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} pub fn vue_directive(name_token: SyntaxToken, modifiers: VueModifierList) -> VueDirectiveBuilder { VueDirectiveBuilder { name_token, @@ -1238,6 +1388,18 @@ where }), )) } +pub fn svelte_directive_modifier_list(items: I) -> SvelteDirectiveModifierList +where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, +{ + SvelteDirectiveModifierList::unwrap_cast(SyntaxNode::new_detached( + HtmlSyntaxKind::SVELTE_DIRECTIVE_MODIFIER_LIST, + items + .into_iter() + .map(|item| Some(item.into_syntax().into())), + )) +} pub fn svelte_else_if_clause_list(items: I) -> SvelteElseIfClauseList where I: IntoIterator, diff --git a/crates/biome_html_factory/src/generated/syntax_factory.rs b/crates/biome_html_factory/src/generated/syntax_factory.rs index ebb239184a3e..daa1c90a6e2d 100644 --- a/crates/biome_html_factory/src/generated/syntax_factory.rs +++ b/crates/biome_html_factory/src/generated/syntax_factory.rs @@ -616,6 +616,32 @@ impl SyntaxFactory for HtmlSyntaxFactory { } slots.into_node(HTML_TEXT_EXPRESSION, children) } + SVELTE_ANIMATE_DIRECTIVE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T![animate] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteDirectiveValue::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_ANIMATE_DIRECTIVE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_ANIMATE_DIRECTIVE, children) + } SVELTE_ATTACH_ATTRIBUTE => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); @@ -929,6 +955,58 @@ impl SyntaxFactory for HtmlSyntaxFactory { } slots.into_node(SVELTE_AWAIT_THEN_CLAUSE, children) } + SVELTE_BIND_DIRECTIVE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T![bind] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteDirectiveValue::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_BIND_DIRECTIVE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_BIND_DIRECTIVE, children) + } + SVELTE_CLASS_DIRECTIVE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T![class] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteDirectiveValue::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_CLASS_DIRECTIVE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_CLASS_DIRECTIVE, children) + } SVELTE_CONST_BLOCK => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); @@ -1042,6 +1120,72 @@ impl SyntaxFactory for HtmlSyntaxFactory { } slots.into_node(SVELTE_DEBUG_BLOCK, children) } + SVELTE_DIRECTIVE_MODIFIER => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T ! [|] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteName::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_DIRECTIVE_MODIFIER.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_DIRECTIVE_MODIFIER, children) + } + SVELTE_DIRECTIVE_VALUE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T ! [:] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && AnySvelteBindingProperty::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteDirectiveModifierList::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && HtmlAttributeInitializerClause::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_DIRECTIVE_VALUE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_DIRECTIVE_VALUE, children) + } SVELTE_EACH_AS_KEYED_ITEM => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); @@ -1534,6 +1678,32 @@ impl SyntaxFactory for HtmlSyntaxFactory { } slots.into_node(SVELTE_IF_OPENING_BLOCK, children) } + SVELTE_IN_DIRECTIVE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T![in] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteDirectiveValue::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_IN_DIRECTIVE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_IN_DIRECTIVE, children) + } SVELTE_KEY_BLOCK => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); @@ -1640,6 +1810,25 @@ impl SyntaxFactory for HtmlSyntaxFactory { } slots.into_node(SVELTE_KEY_OPENING_BLOCK, children) } + SVELTE_LITERAL => { + 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() == HTML_LITERAL + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_LITERAL.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_LITERAL, children) + } SVELTE_NAME => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); @@ -1659,6 +1848,32 @@ impl SyntaxFactory for HtmlSyntaxFactory { } slots.into_node(SVELTE_NAME, children) } + SVELTE_OUT_DIRECTIVE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T![out] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteDirectiveValue::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_OUT_DIRECTIVE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_OUT_DIRECTIVE, children) + } SVELTE_RENDER_BLOCK => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); @@ -1864,6 +2079,84 @@ impl SyntaxFactory for HtmlSyntaxFactory { } slots.into_node(SVELTE_SQUARE_DESTRUCTURED_NAME, children) } + SVELTE_STYLE_DIRECTIVE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T![style] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteDirectiveValue::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_STYLE_DIRECTIVE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_STYLE_DIRECTIVE, children) + } + SVELTE_TRANSITION_DIRECTIVE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T![transition] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteDirectiveValue::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_TRANSITION_DIRECTIVE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_TRANSITION_DIRECTIVE, children) + } + SVELTE_USE_DIRECTIVE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == T![use] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && SvelteDirectiveValue::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SVELTE_USE_DIRECTIVE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SVELTE_USE_DIRECTIVE, children) + } VUE_DIRECTIVE => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); @@ -2144,6 +2437,9 @@ impl SyntaxFactory for HtmlSyntaxFactory { T ! [,], false, ), + SVELTE_DIRECTIVE_MODIFIER_LIST => { + Self::make_node_list_syntax(kind, children, SvelteDirectiveModifier::can_cast) + } SVELTE_ELSE_IF_CLAUSE_LIST => { Self::make_node_list_syntax(kind, children, SvelteElseIfClause::can_cast) } diff --git a/crates/biome_html_formatter/src/generated.rs b/crates/biome_html_formatter/src/generated.rs index 7c04d55cb955..bd41ed902bdb 100644 --- a/crates/biome_html_formatter/src/generated.rs +++ b/crates/biome_html_formatter/src/generated.rs @@ -716,6 +716,44 @@ impl IntoFormat for biome_html_syntax::HtmlTextExpression { ) } } +impl FormatRule + for crate::svelte::auxiliary::animate_directive::FormatSvelteAnimateDirective +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteAnimateDirective, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteAnimateDirective { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteAnimateDirective, + crate::svelte::auxiliary::animate_directive::FormatSvelteAnimateDirective, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::auxiliary::animate_directive::FormatSvelteAnimateDirective::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteAnimateDirective { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteAnimateDirective, + crate::svelte::auxiliary::animate_directive::FormatSvelteAnimateDirective, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::auxiliary::animate_directive::FormatSvelteAnimateDirective::default(), + ) + } +} impl FormatRule for crate::svelte::auxiliary::attach_attribute::FormatSvelteAttachAttribute { @@ -1020,6 +1058,82 @@ impl IntoFormat for biome_html_syntax::SvelteAwaitThenClause ) } } +impl FormatRule + for crate::svelte::auxiliary::bind_directive::FormatSvelteBindDirective +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteBindDirective, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteBindDirective { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteBindDirective, + crate::svelte::auxiliary::bind_directive::FormatSvelteBindDirective, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::auxiliary::bind_directive::FormatSvelteBindDirective::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteBindDirective { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteBindDirective, + crate::svelte::auxiliary::bind_directive::FormatSvelteBindDirective, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::auxiliary::bind_directive::FormatSvelteBindDirective::default(), + ) + } +} +impl FormatRule + for crate::svelte::auxiliary::class_directive::FormatSvelteClassDirective +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteClassDirective, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteClassDirective { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteClassDirective, + crate::svelte::auxiliary::class_directive::FormatSvelteClassDirective, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::auxiliary::class_directive::FormatSvelteClassDirective::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteClassDirective { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteClassDirective, + crate::svelte::auxiliary::class_directive::FormatSvelteClassDirective, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::auxiliary::class_directive::FormatSvelteClassDirective::default(), + ) + } +} impl FormatRule for crate::svelte::auxiliary::const_block::FormatSvelteConstBlock { @@ -1128,6 +1242,82 @@ impl IntoFormat for biome_html_syntax::SvelteDebugBlock { ) } } +impl FormatRule + for crate::svelte::auxiliary::directive_modifier::FormatSvelteDirectiveModifier +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteDirectiveModifier, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteDirectiveModifier { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteDirectiveModifier, + crate::svelte::auxiliary::directive_modifier::FormatSvelteDirectiveModifier, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::auxiliary::directive_modifier::FormatSvelteDirectiveModifier::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteDirectiveModifier { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteDirectiveModifier, + crate::svelte::auxiliary::directive_modifier::FormatSvelteDirectiveModifier, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::auxiliary::directive_modifier::FormatSvelteDirectiveModifier::default(), + ) + } +} +impl FormatRule + for crate::svelte::value::directive_value::FormatSvelteDirectiveValue +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteDirectiveValue, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteDirectiveValue { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteDirectiveValue, + crate::svelte::value::directive_value::FormatSvelteDirectiveValue, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::value::directive_value::FormatSvelteDirectiveValue::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteDirectiveValue { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteDirectiveValue, + crate::svelte::value::directive_value::FormatSvelteDirectiveValue, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::value::directive_value::FormatSvelteDirectiveValue::default(), + ) + } +} impl FormatRule for crate::svelte::auxiliary::each_as_keyed_item::FormatSvelteEachAsKeyedItem { @@ -1622,6 +1812,44 @@ impl IntoFormat for biome_html_syntax::SvelteIfOpeningBlock { ) } } +impl FormatRule + for crate::svelte::auxiliary::in_directive::FormatSvelteInDirective +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteInDirective, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteInDirective { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteInDirective, + crate::svelte::auxiliary::in_directive::FormatSvelteInDirective, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::auxiliary::in_directive::FormatSvelteInDirective::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteInDirective { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteInDirective, + crate::svelte::auxiliary::in_directive::FormatSvelteInDirective, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::auxiliary::in_directive::FormatSvelteInDirective::default(), + ) + } +} impl FormatRule for crate::svelte::auxiliary::key_block::FormatSvelteKeyBlock { @@ -1736,6 +1964,44 @@ impl IntoFormat for biome_html_syntax::SvelteKeyOpeningBlock ) } } +impl FormatRule + for crate::svelte::auxiliary::literal::FormatSvelteLiteral +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteLiteral, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteLiteral { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteLiteral, + crate::svelte::auxiliary::literal::FormatSvelteLiteral, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::auxiliary::literal::FormatSvelteLiteral::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteLiteral { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteLiteral, + crate::svelte::auxiliary::literal::FormatSvelteLiteral, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::auxiliary::literal::FormatSvelteLiteral::default(), + ) + } +} impl FormatRule for crate::svelte::auxiliary::name::FormatSvelteName { @@ -1770,6 +2036,44 @@ impl IntoFormat for biome_html_syntax::SvelteName { ) } } +impl FormatRule + for crate::svelte::auxiliary::out_directive::FormatSvelteOutDirective +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteOutDirective, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteOutDirective { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteOutDirective, + crate::svelte::auxiliary::out_directive::FormatSvelteOutDirective, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::auxiliary::out_directive::FormatSvelteOutDirective::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteOutDirective { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteOutDirective, + crate::svelte::auxiliary::out_directive::FormatSvelteOutDirective, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::auxiliary::out_directive::FormatSvelteOutDirective::default(), + ) + } +} impl FormatRule for crate::svelte::auxiliary::render_block::FormatSvelteRenderBlock { @@ -1980,6 +2284,114 @@ impl IntoFormat for biome_html_syntax::SvelteSquareDestructur FormatOwnedWithRule :: new (self , crate :: svelte :: auxiliary :: square_destructured_name :: FormatSvelteSquareDestructuredName :: default ()) } } +impl FormatRule + for crate::svelte::auxiliary::style_directive::FormatSvelteStyleDirective +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteStyleDirective, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteStyleDirective { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteStyleDirective, + crate::svelte::auxiliary::style_directive::FormatSvelteStyleDirective, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::auxiliary::style_directive::FormatSvelteStyleDirective::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteStyleDirective { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteStyleDirective, + crate::svelte::auxiliary::style_directive::FormatSvelteStyleDirective, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::auxiliary::style_directive::FormatSvelteStyleDirective::default(), + ) + } +} +impl FormatRule + for crate::svelte::auxiliary::transition_directive::FormatSvelteTransitionDirective +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteTransitionDirective, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteTransitionDirective { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteTransitionDirective, + crate::svelte::auxiliary::transition_directive::FormatSvelteTransitionDirective, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule :: new (self , crate :: svelte :: auxiliary :: transition_directive :: FormatSvelteTransitionDirective :: default ()) + } +} +impl IntoFormat for biome_html_syntax::SvelteTransitionDirective { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteTransitionDirective, + crate::svelte::auxiliary::transition_directive::FormatSvelteTransitionDirective, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule :: new (self , crate :: svelte :: auxiliary :: transition_directive :: FormatSvelteTransitionDirective :: default ()) + } +} +impl FormatRule + for crate::svelte::auxiliary::use_directive::FormatSvelteUseDirective +{ + type Context = HtmlFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_html_syntax::SvelteUseDirective, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_html_syntax::SvelteUseDirective { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteUseDirective, + crate::svelte::auxiliary::use_directive::FormatSvelteUseDirective, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::auxiliary::use_directive::FormatSvelteUseDirective::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::SvelteUseDirective { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteUseDirective, + crate::svelte::auxiliary::use_directive::FormatSvelteUseDirective, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::auxiliary::use_directive::FormatSvelteUseDirective::default(), + ) + } +} impl FormatRule for crate::vue::auxiliary::directive::FormatVueDirective { @@ -2378,6 +2790,25 @@ impl IntoFormat for biome_html_syntax::SvelteBindingList { ) } } +impl AsFormat for biome_html_syntax::SvelteDirectiveModifierList { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::SvelteDirectiveModifierList, + crate::svelte::lists::directive_modifier_list::FormatSvelteDirectiveModifierList, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule :: new (self , crate :: svelte :: lists :: directive_modifier_list :: FormatSvelteDirectiveModifierList :: default ()) + } +} +impl IntoFormat for biome_html_syntax::SvelteDirectiveModifierList { + type Format = FormatOwnedWithRule< + biome_html_syntax::SvelteDirectiveModifierList, + crate::svelte::lists::directive_modifier_list::FormatSvelteDirectiveModifierList, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule :: new (self , crate :: svelte :: lists :: directive_modifier_list :: FormatSvelteDirectiveModifierList :: default ()) + } +} impl AsFormat for biome_html_syntax::SvelteElseIfClauseList { type Format<'a> = FormatRefWithRule< 'a, @@ -2914,6 +3345,31 @@ impl IntoFormat for biome_html_syntax::AnySvelteBindingAssign FormatOwnedWithRule :: new (self , crate :: svelte :: any :: binding_assignment_binding :: FormatAnySvelteBindingAssignmentBinding :: default ()) } } +impl AsFormat for biome_html_syntax::AnySvelteBindingProperty { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::AnySvelteBindingProperty, + crate::svelte::any::binding_property::FormatAnySvelteBindingProperty, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::any::binding_property::FormatAnySvelteBindingProperty::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::AnySvelteBindingProperty { + type Format = FormatOwnedWithRule< + biome_html_syntax::AnySvelteBindingProperty, + crate::svelte::any::binding_property::FormatAnySvelteBindingProperty, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::any::binding_property::FormatAnySvelteBindingProperty::default(), + ) + } +} impl AsFormat for biome_html_syntax::AnySvelteBlock { type Format<'a> = FormatRefWithRule< 'a, @@ -2989,6 +3445,31 @@ impl IntoFormat for biome_html_syntax::AnySvelteDestructuredN ) } } +impl AsFormat for biome_html_syntax::AnySvelteDirective { + type Format<'a> = FormatRefWithRule< + 'a, + biome_html_syntax::AnySvelteDirective, + crate::svelte::any::directive::FormatAnySvelteDirective, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::svelte::any::directive::FormatAnySvelteDirective::default(), + ) + } +} +impl IntoFormat for biome_html_syntax::AnySvelteDirective { + type Format = FormatOwnedWithRule< + biome_html_syntax::AnySvelteDirective, + crate::svelte::any::directive::FormatAnySvelteDirective, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::svelte::any::directive::FormatAnySvelteDirective::default(), + ) + } +} impl AsFormat for biome_html_syntax::AnySvelteEachName { type Format<'a> = FormatRefWithRule< 'a, diff --git a/crates/biome_html_formatter/src/html/any/attribute.rs b/crates/biome_html_formatter/src/html/any/attribute.rs index 561f0dcb2765..b7f2a967d2e3 100644 --- a/crates/biome_html_formatter/src/html/any/attribute.rs +++ b/crates/biome_html_formatter/src/html/any/attribute.rs @@ -8,6 +8,7 @@ impl FormatRule for FormatAnyHtmlAttribute { type Context = HtmlFormatContext; fn fmt(&self, node: &AnyHtmlAttribute, f: &mut HtmlFormatter) -> FormatResult<()> { match node { + AnyHtmlAttribute::AnySvelteDirective(node) => node.format().fmt(f), AnyHtmlAttribute::AnyVueDirective(node) => node.format().fmt(f), AnyHtmlAttribute::HtmlAttribute(node) => node.format().fmt(f), AnyHtmlAttribute::HtmlBogusAttribute(node) => node.format().fmt(f), diff --git a/crates/biome_html_formatter/src/html/any/attribute_initializer.rs b/crates/biome_html_formatter/src/html/any/attribute_initializer.rs index 79709c0a9cbe..159713337422 100644 --- a/crates/biome_html_formatter/src/html/any/attribute_initializer.rs +++ b/crates/biome_html_formatter/src/html/any/attribute_initializer.rs @@ -1,15 +1,32 @@ //! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. use crate::prelude::*; +use biome_formatter::FormatRuleWithOptions; use biome_html_syntax::AnyHtmlAttributeInitializer; #[derive(Debug, Clone, Default)] -pub(crate) struct FormatAnyHtmlAttributeInitializer; +pub(crate) struct FormatAnyHtmlAttributeInitializer { + compact: bool, +} + impl FormatRule for FormatAnyHtmlAttributeInitializer { type Context = HtmlFormatContext; fn fmt(&self, node: &AnyHtmlAttributeInitializer, f: &mut HtmlFormatter) -> FormatResult<()> { match node { - AnyHtmlAttributeInitializer::HtmlSingleTextExpression(node) => node.format().fmt(f), - AnyHtmlAttributeInitializer::HtmlString(node) => node.format().fmt(f), + AnyHtmlAttributeInitializer::HtmlSingleTextExpression(node) => { + node.format().with_options(self.compact).fmt(f) + } + AnyHtmlAttributeInitializer::HtmlString(node) => { + node.format().with_options(self.compact).fmt(f) + } } } } + +impl FormatRuleWithOptions for FormatAnyHtmlAttributeInitializer { + type Options = bool; + + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options; + self + } +} diff --git a/crates/biome_html_formatter/src/html/auxiliary/attribute.rs b/crates/biome_html_formatter/src/html/auxiliary/attribute.rs index 94fc9dbc2db0..d620e90ab3fc 100644 --- a/crates/biome_html_formatter/src/html/auxiliary/attribute.rs +++ b/crates/biome_html_formatter/src/html/auxiliary/attribute.rs @@ -1,3 +1,4 @@ +use crate::html::auxiliary::attribute_initializer_clause::CompactKind; use crate::{ html::auxiliary::{ attribute_initializer_clause::FormatHtmlAttributeInitializerClauseOptions, @@ -5,8 +6,11 @@ use crate::{ }, prelude::*, }; -use biome_formatter::{FormatRuleWithOptions, write}; -use biome_html_syntax::{HtmlAttribute, HtmlAttributeFields, HtmlTagName}; +use biome_formatter::{FormatContext, FormatRuleWithOptions, write}; +use biome_html_syntax::{ + AnyHtmlAttributeInitializer, HtmlAttribute, HtmlAttributeFields, HtmlTagName, +}; +use std::fmt::Debug; #[derive(Debug, Clone, Default)] pub(crate) struct FormatHtmlAttribute { @@ -15,6 +19,10 @@ pub(crate) struct FormatHtmlAttribute { /// The name of the tag this attribute belongs to. pub tag_name: Option, + + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: bool, } pub(crate) struct FormatHtmlAttributeOptions { @@ -23,6 +31,10 @@ pub(crate) struct FormatHtmlAttributeOptions { /// The name of the tag this attribute belongs to. pub tag_name: Option, + + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: bool, } impl FormatRuleWithOptions for FormatHtmlAttribute { @@ -31,37 +43,118 @@ impl FormatRuleWithOptions for FormatHtmlAttribute { fn with_options(mut self, options: Self::Options) -> Self { self.is_canonical_html_element = options.is_canonical_html_element; self.tag_name = options.tag_name; + self.compact = options.compact; self } } +/// Whether the formatter can write `x={x}` in `{x}` +/// The initializer must be a text expression, and the two values must match. +fn can_compact(node: &HtmlAttribute, f: &mut HtmlFormatter) -> bool { + if f.context().options().file_source().is_svelte() { + let name = node.name().ok().and_then(|name| name.token_text_trimmed()); + + let initializer_value = node.initializer().and_then(|init| init.value().ok()); + + let Some(AnyHtmlAttributeInitializer::HtmlSingleTextExpression(initializer_value)) = + initializer_value + else { + return false; + }; + + let initializer_value = initializer_value + .expression() + .ok() + .and_then(|expression| expression.string_value()); + + if let (Some(name), Some(initializer_value)) = (name, initializer_value) { + return initializer_value.text() == name.text(); + } + } + + false +} + impl FormatNodeRule for FormatHtmlAttribute { fn fmt_fields(&self, node: &HtmlAttribute, f: &mut HtmlFormatter) -> FormatResult<()> { let HtmlAttributeFields { name, initializer } = node.as_fields(); - write!( - f, - [name.format()?.with_options(FormatHtmlAttributeNameOptions { - is_canonical_html_element: self.is_canonical_html_element, - tag_name: self.tag_name.clone(), - }),] - )?; - - if let Some(initializer) = initializer.as_ref() { + if self.compact { + let name = name.clone()?; write!( f, - [initializer - .format() - .with_options(FormatHtmlAttributeInitializerClauseOptions { - tag_name: self - .tag_name - .as_ref() - .and_then(|name| name.token_text_trimmed()), - attribute_name: name.ok().and_then(|name| name.token_text_trimmed()), - })] + [name.format().with_options(FormatHtmlAttributeNameOptions { + compact: true, + tag_name: None, + is_canonical_html_element: self.is_canonical_html_element, + })] + )?; + if let Some(initializer) = initializer { + write!( + f, + [initializer.format().with_options( + FormatHtmlAttributeInitializerClauseOptions { + compact: CompactKind::Remove, + tag_name: None, + attribute_name: None, + } + )] + )?; + } + Ok(()) + } else if can_compact(node, f) { + let name = name.clone()?; + write!( + f, + [name.format().with_options(FormatHtmlAttributeNameOptions { + compact: true, + tag_name: None, + is_canonical_html_element: self.is_canonical_html_element, + })] + )?; + if let Some(initializer) = initializer.as_ref() { + write!( + f, + [initializer.format().with_options( + FormatHtmlAttributeInitializerClauseOptions { + tag_name: self + .tag_name + .as_ref() + .and_then(|name| name.token_text_trimmed()), + attribute_name: name.token_text_trimmed(), + compact: CompactKind::Curly + } + )] + )?; + } + Ok(()) + } else { + write!( + f, + [name.format()?.with_options(FormatHtmlAttributeNameOptions { + is_canonical_html_element: self.is_canonical_html_element, + tag_name: self.tag_name.clone(), + compact: false + }),] )?; - } - Ok(()) + if let Some(initializer) = initializer.as_ref() { + write!( + f, + [initializer.format().with_options( + FormatHtmlAttributeInitializerClauseOptions { + tag_name: self + .tag_name + .as_ref() + .and_then(|name| name.token_text_trimmed()), + attribute_name: name.ok().and_then(|name| name.token_text_trimmed()), + compact: CompactKind::None + } + )] + )?; + } + + Ok(()) + } } } diff --git a/crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs b/crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs index 9eaafe4fc462..8e5aa39278d1 100644 --- a/crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs +++ b/crates/biome_html_formatter/src/html/auxiliary/attribute_initializer_clause.rs @@ -2,7 +2,10 @@ use std::fmt::Debug; use crate::prelude::*; use biome_formatter::{CstFormatContext, FormatRuleWithOptions, write}; -use biome_html_syntax::{HtmlAttributeInitializerClause, HtmlAttributeInitializerClauseFields}; +use biome_html_syntax::{ + AnyHtmlAttributeInitializer, HtmlAttributeInitializerClause, + HtmlAttributeInitializerClauseFields, +}; use biome_rowan::TokenText; #[derive(Debug, Clone, Default)] @@ -12,6 +15,10 @@ pub(crate) struct FormatHtmlAttributeInitializerClause { /// The name of the attribute this initializer clause belongs to. pub attribute_name: Option, + + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: CompactKind, } pub(crate) struct FormatHtmlAttributeInitializerClauseOptions { @@ -20,6 +27,27 @@ pub(crate) struct FormatHtmlAttributeInitializerClauseOptions { /// The name of the attribute this initializer clause belongs to. pub attribute_name: Option, + + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: CompactKind, +} + +#[derive(Debug, Clone, Default)] +pub(crate) enum CompactKind { + /// No special formatting + #[default] + None, + /// Removes everything + Remove, + /// Removes the `=` and keeps the `{ expression }` + Curly, +} + +impl CompactKind { + const fn is_curly(&self) -> bool { + matches!(self, Self::Curly) + } } impl FormatRuleWithOptions @@ -30,6 +58,7 @@ impl FormatRuleWithOptions fn with_options(mut self, options: Self::Options) -> Self { self.tag_name = options.tag_name; self.attribute_name = options.attribute_name; + self.compact = options.compact; self } } @@ -42,68 +71,93 @@ impl FormatNodeRule for FormatHtmlAttributeIniti ) -> FormatResult<()> { let HtmlAttributeInitializerClauseFields { eq_token, value } = node.as_fields(); - // We currently only have special formatting for when the value is a string. - if let Some(html_string) = value.as_ref()?.as_html_string() - && !f.context().comments().is_suppressed(html_string.syntax()) - { - match (self.tag_name.as_deref(), self.attribute_name.as_deref()) { - // Prettier 3.7 handles allow attribute on iframes specially by splitting the - // value on semicolons and formatting it like a list, breaking if its too long, or leaving it on one line if it fits in the line width. - // It also trims whitespace around each item, and removes empty items. - // - // Before: - // ```html - // - // ``` - // - // After: - // ```html - // - // ``` - (Some("iframe"), Some("allow")) => { - let content = html_string.inner_string_text()?; - let value_token = html_string.value_token()?; + match self.compact { + CompactKind::None | CompactKind::Curly => { + // We currently only have special formatting for when the value is a string. + let eq_token = eq_token?; + let fmt_eq_token = format_with(|f| { + if self.compact.is_curly() + && value.as_ref().is_ok_and(|v| { + matches!(v, AnyHtmlAttributeInitializer::HtmlSingleTextExpression(_)) + }) + { + format_removed(&eq_token).fmt(f) + } else { + write!(f, [eq_token.format()]) + } + }); + if let Some(html_string) = value.as_ref()?.as_html_string() + && !f.context().comments().is_suppressed(html_string.syntax()) + { + match (self.tag_name.as_deref(), self.attribute_name.as_deref()) { + // Prettier 3.7 handles allow attribute on iframes specially by splitting the + // value on semicolons and formatting it like a list, breaking if its too long, or leaving it on one line if it fits in the line width. + // It also trims whitespace around each item, and removes empty items. + // + // Before: + // ```html + // + // ``` + // + // After: + // ```html + // + // ``` + (Some("iframe"), Some("allow")) => { + let content = html_string.inner_string_text()?; + let value_token = html_string.value_token()?; + + struct JoinWithSemicolon; + impl Format for JoinWithSemicolon { + fn fmt(&self, f: &mut HtmlFormatter) -> FormatResult<()> { + write!(f, [token(";"), soft_line_break_or_space()]) + } + } - struct JoinWithSemicolon; - impl Format for JoinWithSemicolon { - fn fmt(&self, f: &mut HtmlFormatter) -> FormatResult<()> { - write!(f, [token(";"), soft_line_break_or_space()]) + write!( + f, + [ + fmt_eq_token, + format_removed(&value_token), + token("\""), + group(&soft_block_indent(&format_with(|f| { + let items = content + .split(';') + .map(TokenText::trim_token) + .filter(|s| !s.is_empty()) + .collect::>(); + f.join_with(JoinWithSemicolon) + .entries(items.into_iter().map(|item| { + located_token_text( + &value_token, + item.source_range(value_token.text_range()), + ) + })) + .finish()?; + write!(f, [if_group_breaks(&token(";"))])?; + Ok(()) + }))), + token("\"") + ] + ) + } + _ => { + write!(f, [fmt_eq_token, value.format()]) } } - - write!( - f, - [ - eq_token.format(), - format_removed(&value_token), - token("\""), - group(&soft_block_indent(&format_with(|f| { - let items = content - .split(';') - .map(TokenText::trim_token) - .filter(|s| !s.is_empty()) - .collect::>(); - f.join_with(JoinWithSemicolon) - .entries(items.into_iter().map(|item| { - located_token_text( - &value_token, - item.source_range(value_token.text_range()), - ) - })) - .finish()?; - write!(f, [if_group_breaks(&token(";"))])?; - Ok(()) - }))), - token("\"") - ] - ) - } - _ => { - write!(f, [eq_token.format(), value.format()]) + } else { + write!(f, [fmt_eq_token, value.format()]) } } - } else { - write!(f, [eq_token.format(), value.format()]) + CompactKind::Remove => { + let eq_token = eq_token.clone()?; + let value = value.clone()?; + write!( + f, + [format_removed(&eq_token), value.format().with_options(true),] + )?; + Ok(()) + } } } } diff --git a/crates/biome_html_formatter/src/html/auxiliary/attribute_name.rs b/crates/biome_html_formatter/src/html/auxiliary/attribute_name.rs index 5624625fddb3..387071a16f2c 100644 --- a/crates/biome_html_formatter/src/html/auxiliary/attribute_name.rs +++ b/crates/biome_html_formatter/src/html/auxiliary/attribute_name.rs @@ -12,6 +12,10 @@ pub(crate) struct FormatHtmlAttributeName { /// The name of the tag this attribute belongs to. pub tag_name: Option, + + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: bool, } pub(crate) struct FormatHtmlAttributeNameOptions { @@ -20,6 +24,10 @@ pub(crate) struct FormatHtmlAttributeNameOptions { /// The name of the tag this attribute belongs to. pub tag_name: Option, + + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: bool, } impl FormatRuleWithOptions for FormatHtmlAttributeName { @@ -28,6 +36,7 @@ impl FormatRuleWithOptions for FormatHtmlAttributeName { fn with_options(mut self, options: Self::Options) -> Self { self.is_canonical_html_element = options.is_canonical_html_element; self.tag_name = options.tag_name; + self.compact = options.compact; self } } @@ -35,17 +44,22 @@ impl FormatNodeRule for FormatHtmlAttributeName { fn fmt_fields(&self, node: &HtmlAttributeName, f: &mut HtmlFormatter) -> FormatResult<()> { let HtmlAttributeNameFields { value_token } = node.as_fields(); - let should_lowercase = self.is_canonical_html_element - && if let Some(tag_name) = &self.tag_name { - is_canonical_html_attribute(tag_name, node) - } else { - false - }; - - if should_lowercase { - write!(f, [FormatTokenAsLowercase::from(value_token?)]) + if self.compact { + let value_token = value_token?; + format_removed(&value_token).fmt(f) } else { - write!(f, [value_token.format()]) + let should_lowercase = self.is_canonical_html_element + && if let Some(tag_name) = &self.tag_name { + is_canonical_html_attribute(tag_name, node) + } else { + false + }; + + if should_lowercase { + write!(f, [FormatTokenAsLowercase::from(value_token?)]) + } else { + write!(f, [value_token.format()]) + } } } } diff --git a/crates/biome_html_formatter/src/html/auxiliary/single_text_expression.rs b/crates/biome_html_formatter/src/html/auxiliary/single_text_expression.rs index ff5335797265..1d83a0170b53 100644 --- a/crates/biome_html_formatter/src/html/auxiliary/single_text_expression.rs +++ b/crates/biome_html_formatter/src/html/auxiliary/single_text_expression.rs @@ -1,9 +1,11 @@ use crate::prelude::*; -use biome_formatter::write; +use biome_formatter::{FormatRuleWithOptions, write}; use biome_html_syntax::{HtmlSingleTextExpression, HtmlSingleTextExpressionFields}; #[derive(Debug, Clone, Default)] -pub(crate) struct FormatHtmlSingleTextExpression; +pub(crate) struct FormatHtmlSingleTextExpression { + compact: bool, +} impl FormatNodeRule for FormatHtmlSingleTextExpression { fn fmt_fields( &self, @@ -16,13 +18,30 @@ impl FormatNodeRule for FormatHtmlSingleTextExpression r_curly_token, } = node.as_fields(); - write!( - f, - [ - l_curly_token.format(), - expression.format(), - r_curly_token.format() - ] - ) + if self.compact { + let l_curly_token = l_curly_token?; + let r_curly_token = r_curly_token.clone()?; + let expression = expression.clone()?; + format_removed(&l_curly_token).fmt(f)?; + format_removed(&r_curly_token).fmt(f)?; + expression.format().with_options(self.compact).fmt(f) + } else { + write!( + f, + [ + l_curly_token.format(), + expression.format(), + r_curly_token.format() + ] + ) + } + } +} + +impl FormatRuleWithOptions for FormatHtmlSingleTextExpression { + type Options = bool; + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options; + self } } diff --git a/crates/biome_html_formatter/src/html/auxiliary/string.rs b/crates/biome_html_formatter/src/html/auxiliary/string.rs index 7838d254aab1..9c378dd257f9 100644 --- a/crates/biome_html_formatter/src/html/auxiliary/string.rs +++ b/crates/biome_html_formatter/src/html/auxiliary/string.rs @@ -1,12 +1,19 @@ use crate::prelude::*; -use biome_formatter::{format_args, write}; +use biome_formatter::{FormatRuleWithOptions, format_args, write}; use biome_html_syntax::{HtmlString, HtmlStringFields}; #[derive(Debug, Clone, Default)] -pub(crate) struct FormatHtmlString; +pub(crate) struct FormatHtmlString { + compact: bool, +} impl FormatNodeRule for FormatHtmlString { fn fmt_fields(&self, node: &HtmlString, f: &mut HtmlFormatter) -> FormatResult<()> { let HtmlStringFields { value_token } = node.as_fields(); + if self.compact { + let value_token = value_token.clone()?; + return format_removed(&value_token).fmt(f); + } + // Prettier always uses double quotes for HTML strings, regardless of configuration. // Unless the string contains a double quote, in which case it uses single quotes. if let Ok(value) = value_token.as_ref() { @@ -49,3 +56,11 @@ impl FormatNodeRule for FormatHtmlString { write!(f, [value_token.format()]) } } + +impl FormatRuleWithOptions for FormatHtmlString { + type Options = bool; + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options; + self + } +} diff --git a/crates/biome_html_formatter/src/html/auxiliary/text_expression.rs b/crates/biome_html_formatter/src/html/auxiliary/text_expression.rs index f472c503408b..5390186f3346 100644 --- a/crates/biome_html_formatter/src/html/auxiliary/text_expression.rs +++ b/crates/biome_html_formatter/src/html/auxiliary/text_expression.rs @@ -1,17 +1,23 @@ use crate::prelude::*; -use biome_formatter::CstFormatContext; use biome_formatter::write; +use biome_formatter::{CstFormatContext, FormatRuleWithOptions}; use biome_html_syntax::HtmlTextExpression; #[derive(Debug, Clone, Default)] -pub(crate) struct FormatHtmlTextExpression; +pub(crate) struct FormatHtmlTextExpression { + compact: bool, +} impl FormatNodeRule for FormatHtmlTextExpression { fn fmt_fields(&self, node: &HtmlTextExpression, f: &mut HtmlFormatter) -> FormatResult<()> { if f.context().comments().is_suppressed(node.syntax()) { return write!(f, [format_suppressed_node(node.syntax())]); } - let token = node.html_literal_token()?; + + if self.compact { + return format_removed(&token).fmt(f); + } + let token_text = token.text(); let trimmed_text = token_text.trim_start().trim_end(); @@ -24,3 +30,11 @@ impl FormatNodeRule for FormatHtmlTextExpression { ) } } + +impl FormatRuleWithOptions for FormatHtmlTextExpression { + type Options = bool; + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options; + self + } +} diff --git a/crates/biome_html_formatter/src/html/lists/attribute_list.rs b/crates/biome_html_formatter/src/html/lists/attribute_list.rs index 611abde8975a..cb7994bc8086 100644 --- a/crates/biome_html_formatter/src/html/lists/attribute_list.rs +++ b/crates/biome_html_formatter/src/html/lists/attribute_list.rs @@ -58,6 +58,7 @@ impl FormatRule for FormatHtmlAttributeList { is_canonical_html_element: self .is_canonical_html_element, tag_name: self.tag_name.clone(), + compact: false, }) .fmt(f), AnyHtmlAttribute::HtmlDoubleTextExpression(attr) => { @@ -73,6 +74,9 @@ impl FormatRule for FormatHtmlAttributeList { attr.format().fmt(f) } AnyHtmlAttribute::AnyVueDirective(attr) => attr.format().fmt(f), + AnyHtmlAttribute::AnySvelteDirective(attr) => { + attr.format().fmt(f) + } }) })) .finish()?; diff --git a/crates/biome_html_formatter/src/svelte/any/binding_property.rs b/crates/biome_html_formatter/src/svelte/any/binding_property.rs new file mode 100644 index 000000000000..a440cc278bb5 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/any/binding_property.rs @@ -0,0 +1,33 @@ +//! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. + +use crate::prelude::*; +use biome_formatter::FormatRuleWithOptions; +use biome_html_syntax::AnySvelteBindingProperty; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatAnySvelteBindingProperty { + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: bool, +} +impl FormatRule for FormatAnySvelteBindingProperty { + type Context = HtmlFormatContext; + fn fmt(&self, node: &AnySvelteBindingProperty, f: &mut HtmlFormatter) -> FormatResult<()> { + match node { + AnySvelteBindingProperty::SvelteLiteral(node) => { + node.format().with_options(self.compact).fmt(f) + } + AnySvelteBindingProperty::SvelteName(node) => { + node.format().with_options(self.compact).fmt(f) + } + } + } +} + +impl FormatRuleWithOptions for FormatAnySvelteBindingProperty { + type Options = bool; + + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options; + self + } +} diff --git a/crates/biome_html_formatter/src/svelte/any/directive.rs b/crates/biome_html_formatter/src/svelte/any/directive.rs new file mode 100644 index 000000000000..33d9e4c61db4 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/any/directive.rs @@ -0,0 +1,21 @@ +//! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. + +use crate::prelude::*; +use biome_html_syntax::AnySvelteDirective; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatAnySvelteDirective; +impl FormatRule for FormatAnySvelteDirective { + type Context = HtmlFormatContext; + fn fmt(&self, node: &AnySvelteDirective, f: &mut HtmlFormatter) -> FormatResult<()> { + match node { + AnySvelteDirective::SvelteAnimateDirective(node) => node.format().fmt(f), + AnySvelteDirective::SvelteBindDirective(node) => node.format().fmt(f), + AnySvelteDirective::SvelteClassDirective(node) => node.format().fmt(f), + AnySvelteDirective::SvelteInDirective(node) => node.format().fmt(f), + AnySvelteDirective::SvelteOutDirective(node) => node.format().fmt(f), + AnySvelteDirective::SvelteStyleDirective(node) => node.format().fmt(f), + AnySvelteDirective::SvelteTransitionDirective(node) => node.format().fmt(f), + AnySvelteDirective::SvelteUseDirective(node) => node.format().fmt(f), + } + } +} diff --git a/crates/biome_html_formatter/src/svelte/any/mod.rs b/crates/biome_html_formatter/src/svelte/any/mod.rs index d7b5b49cf264..841a221935a8 100644 --- a/crates/biome_html_formatter/src/svelte/any/mod.rs +++ b/crates/biome_html_formatter/src/svelte/any/mod.rs @@ -2,7 +2,9 @@ pub(crate) mod await_clauses; pub(crate) mod binding_assignment_binding; +pub(crate) mod binding_property; pub(crate) mod block; pub(crate) mod block_item; pub(crate) mod destructured_name; +pub(crate) mod directive; pub(crate) mod each_name; diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/animate_directive.rs b/crates/biome_html_formatter/src/svelte/auxiliary/animate_directive.rs new file mode 100644 index 000000000000..59498de53abb --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/animate_directive.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; +use crate::utils::svelte_directive::FmtSvelteDirective; +use biome_html_syntax::SvelteAnimateDirective; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteAnimateDirective; +impl FormatNodeRule for FormatSvelteAnimateDirective { + fn fmt_fields(&self, node: &SvelteAnimateDirective, f: &mut HtmlFormatter) -> FormatResult<()> { + FmtSvelteDirective::from(node).fmt(f) + } +} diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/bind_directive.rs b/crates/biome_html_formatter/src/svelte/auxiliary/bind_directive.rs new file mode 100644 index 000000000000..012eaf60f0a3 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/bind_directive.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; +use crate::utils::svelte_directive::FmtSvelteDirective; +use biome_html_syntax::SvelteBindDirective; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteBindDirective; +impl FormatNodeRule for FormatSvelteBindDirective { + fn fmt_fields(&self, node: &SvelteBindDirective, f: &mut HtmlFormatter) -> FormatResult<()> { + FmtSvelteDirective::from(node).fmt(f) + } +} diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/class_directive.rs b/crates/biome_html_formatter/src/svelte/auxiliary/class_directive.rs new file mode 100644 index 000000000000..640644007bae --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/class_directive.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; +use crate::utils::svelte_directive::FmtSvelteDirective; +use biome_html_syntax::SvelteClassDirective; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteClassDirective; +impl FormatNodeRule for FormatSvelteClassDirective { + fn fmt_fields(&self, node: &SvelteClassDirective, f: &mut HtmlFormatter) -> FormatResult<()> { + FmtSvelteDirective::from(node).fmt(f) + } +} diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/directive_modifier.rs b/crates/biome_html_formatter/src/svelte/auxiliary/directive_modifier.rs new file mode 100644 index 000000000000..e7ffdcb6d270 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/directive_modifier.rs @@ -0,0 +1,44 @@ +use crate::prelude::*; +use biome_formatter::{FormatRuleWithOptions, write}; +use biome_html_syntax::{SvelteDirectiveModifier, SvelteDirectiveModifierFields}; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteDirectiveModifier { + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: bool, +} + +impl FormatNodeRule for FormatSvelteDirectiveModifier { + fn fmt_fields( + &self, + node: &SvelteDirectiveModifier, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + let SvelteDirectiveModifierFields { + bitwise_or_token, + name, + } = node.as_fields(); + if self.compact { + let bitwise_or_token = bitwise_or_token?; + let name = name?; + write!( + f, + [ + format_removed(&bitwise_or_token), + name.format().with_options(true) + ] + ) + } else { + write!(f, [bitwise_or_token.format(), name.format()]) + } + } +} + +impl FormatRuleWithOptions for FormatSvelteDirectiveModifier { + type Options = bool; + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options; + self + } +} diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/in_directive.rs b/crates/biome_html_formatter/src/svelte/auxiliary/in_directive.rs new file mode 100644 index 000000000000..88c7a22276e7 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/in_directive.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; +use crate::utils::svelte_directive::FmtSvelteDirective; +use biome_html_syntax::SvelteInDirective; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteInDirective; +impl FormatNodeRule for FormatSvelteInDirective { + fn fmt_fields(&self, node: &SvelteInDirective, f: &mut HtmlFormatter) -> FormatResult<()> { + FmtSvelteDirective::from(node).fmt(f) + } +} diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/literal.rs b/crates/biome_html_formatter/src/svelte/auxiliary/literal.rs new file mode 100644 index 000000000000..71ded6c61e6a --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/literal.rs @@ -0,0 +1,29 @@ +use crate::prelude::*; +use biome_formatter::{FormatRuleWithOptions, write}; +use biome_html_syntax::SvelteLiteral; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteLiteral { + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: bool, +} +impl FormatNodeRule for FormatSvelteLiteral { + fn fmt_fields(&self, node: &SvelteLiteral, f: &mut HtmlFormatter) -> FormatResult<()> { + if self.compact { + let value_token = node.value_token()?; + format_removed(&value_token).fmt(f) + } else { + write!(f, [node.value_token().format()]) + } + } +} + +impl FormatRuleWithOptions for FormatSvelteLiteral { + type Options = bool; + + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options; + self + } +} diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/mod.rs b/crates/biome_html_formatter/src/svelte/auxiliary/mod.rs index 3d1687d26060..b32959ab555c 100644 --- a/crates/biome_html_formatter/src/svelte/auxiliary/mod.rs +++ b/crates/biome_html_formatter/src/svelte/auxiliary/mod.rs @@ -1,5 +1,6 @@ //! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. +pub(crate) mod animate_directive; pub(crate) mod attach_attribute; pub(crate) mod await_block; pub(crate) mod await_catch_block; @@ -8,9 +9,12 @@ pub(crate) mod await_closing_block; pub(crate) mod await_opening_block; pub(crate) mod await_then_block; pub(crate) mod await_then_clause; +pub(crate) mod bind_directive; +pub(crate) mod class_directive; pub(crate) mod const_block; pub(crate) mod curly_destructured_name; pub(crate) mod debug_block; +pub(crate) mod directive_modifier; pub(crate) mod each_as_keyed_item; pub(crate) mod each_block; pub(crate) mod each_closing_block; @@ -24,13 +28,19 @@ pub(crate) mod html_block; pub(crate) mod if_block; pub(crate) mod if_closing_block; pub(crate) mod if_opening_block; +pub(crate) mod in_directive; pub(crate) mod key_block; pub(crate) mod key_closing_block; pub(crate) mod key_opening_block; +pub(crate) mod literal; pub(crate) mod name; +pub(crate) mod out_directive; pub(crate) mod render_block; pub(crate) mod rest_binding; pub(crate) mod snippet_block; pub(crate) mod snippet_closing_block; pub(crate) mod snippet_opening_block; pub(crate) mod square_destructured_name; +pub(crate) mod style_directive; +pub(crate) mod transition_directive; +pub(crate) mod use_directive; diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/name.rs b/crates/biome_html_formatter/src/svelte/auxiliary/name.rs index 7140c93c3cf4..e1192a93aeba 100644 --- a/crates/biome_html_formatter/src/svelte/auxiliary/name.rs +++ b/crates/biome_html_formatter/src/svelte/auxiliary/name.rs @@ -1,12 +1,30 @@ use crate::prelude::*; -use biome_formatter::write; +use biome_formatter::{FormatRuleWithOptions, write}; use biome_html_syntax::{SvelteName, SvelteNameFields}; #[derive(Debug, Clone, Default)] -pub(crate) struct FormatSvelteName; +pub(crate) struct FormatSvelteName { + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: bool, +} impl FormatNodeRule for FormatSvelteName { fn fmt_fields(&self, node: &SvelteName, f: &mut HtmlFormatter) -> FormatResult<()> { let SvelteNameFields { ident_token } = node.as_fields(); - write!(f, [ident_token.format()]) + if self.compact { + let ident_token = ident_token?; + format_removed(&ident_token).fmt(f) + } else { + write!(f, [ident_token.format()]) + } + } +} + +impl FormatRuleWithOptions for FormatSvelteName { + type Options = bool; + + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options; + self } } diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/out_directive.rs b/crates/biome_html_formatter/src/svelte/auxiliary/out_directive.rs new file mode 100644 index 000000000000..47d32cd46cb0 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/out_directive.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; +use crate::utils::svelte_directive::FmtSvelteDirective; +use biome_html_syntax::SvelteOutDirective; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteOutDirective; +impl FormatNodeRule for FormatSvelteOutDirective { + fn fmt_fields(&self, node: &SvelteOutDirective, f: &mut HtmlFormatter) -> FormatResult<()> { + FmtSvelteDirective::from(node).fmt(f) + } +} diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/style_directive.rs b/crates/biome_html_formatter/src/svelte/auxiliary/style_directive.rs new file mode 100644 index 000000000000..528cb05299c2 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/style_directive.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; +use crate::utils::svelte_directive::FmtSvelteDirective; +use biome_html_syntax::SvelteStyleDirective; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteStyleDirective; +impl FormatNodeRule for FormatSvelteStyleDirective { + fn fmt_fields(&self, node: &SvelteStyleDirective, f: &mut HtmlFormatter) -> FormatResult<()> { + FmtSvelteDirective::from(node).fmt(f) + } +} diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/transition_directive.rs b/crates/biome_html_formatter/src/svelte/auxiliary/transition_directive.rs new file mode 100644 index 000000000000..b1764b14cf57 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/transition_directive.rs @@ -0,0 +1,15 @@ +use crate::prelude::*; +use crate::utils::svelte_directive::FmtSvelteDirective; +use biome_html_syntax::SvelteTransitionDirective; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteTransitionDirective; +impl FormatNodeRule for FormatSvelteTransitionDirective { + fn fmt_fields( + &self, + node: &SvelteTransitionDirective, + f: &mut HtmlFormatter, + ) -> FormatResult<()> { + FmtSvelteDirective::from(node).fmt(f) + } +} diff --git a/crates/biome_html_formatter/src/svelte/auxiliary/use_directive.rs b/crates/biome_html_formatter/src/svelte/auxiliary/use_directive.rs new file mode 100644 index 000000000000..d659bd5d5a65 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/auxiliary/use_directive.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; +use crate::utils::svelte_directive::FmtSvelteDirective; +use biome_html_syntax::SvelteUseDirective; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteUseDirective; +impl FormatNodeRule for FormatSvelteUseDirective { + fn fmt_fields(&self, node: &SvelteUseDirective, f: &mut HtmlFormatter) -> FormatResult<()> { + FmtSvelteDirective::from(node).fmt(f) + } +} diff --git a/crates/biome_html_formatter/src/svelte/lists/directive_modifier_list.rs b/crates/biome_html_formatter/src/svelte/lists/directive_modifier_list.rs new file mode 100644 index 000000000000..e32646b1fbdb --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/lists/directive_modifier_list.rs @@ -0,0 +1,28 @@ +use crate::prelude::*; +use biome_formatter::FormatRuleWithOptions; +use biome_html_syntax::SvelteDirectiveModifierList; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteDirectiveModifierList { + /// Whether it should be formatted in compact mode. In compact mode, all tokens and children + /// are removed + pub compact: bool, +} +impl FormatRule for FormatSvelteDirectiveModifierList { + type Context = HtmlFormatContext; + fn fmt(&self, node: &SvelteDirectiveModifierList, f: &mut HtmlFormatter) -> FormatResult<()> { + let mut joiner = f.join(); + for entry in node.iter() { + joiner.entry(&entry.format().with_options(self.compact)); + } + + joiner.finish() + } +} + +impl FormatRuleWithOptions for FormatSvelteDirectiveModifierList { + type Options = bool; + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options; + self + } +} diff --git a/crates/biome_html_formatter/src/svelte/lists/mod.rs b/crates/biome_html_formatter/src/svelte/lists/mod.rs index e9fb2ee2abf8..523f26c71537 100644 --- a/crates/biome_html_formatter/src/svelte/lists/mod.rs +++ b/crates/biome_html_formatter/src/svelte/lists/mod.rs @@ -3,4 +3,5 @@ pub(crate) mod await_clauses_list; pub(crate) mod binding_assignment_binding_list; pub(crate) mod binding_list; +pub(crate) mod directive_modifier_list; pub(crate) mod else_if_clause_list; diff --git a/crates/biome_html_formatter/src/svelte/mod.rs b/crates/biome_html_formatter/src/svelte/mod.rs index 54da8fe0418f..f9caa8bedcd1 100644 --- a/crates/biome_html_formatter/src/svelte/mod.rs +++ b/crates/biome_html_formatter/src/svelte/mod.rs @@ -4,3 +4,4 @@ pub(crate) mod any; pub(crate) mod auxiliary; pub(crate) mod bogus; pub(crate) mod lists; +pub(crate) mod value; diff --git a/crates/biome_html_formatter/src/svelte/value/directive_value.rs b/crates/biome_html_formatter/src/svelte/value/directive_value.rs new file mode 100644 index 000000000000..75a9015002c8 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/value/directive_value.rs @@ -0,0 +1,105 @@ +use crate::html::auxiliary::attribute_initializer_clause::{ + CompactKind, FormatHtmlAttributeInitializerClauseOptions, +}; +use crate::prelude::*; +use biome_formatter::{FormatRuleWithOptions, write}; +use biome_html_syntax::{ + AnySvelteBindingProperty, SvelteDirectiveValue, SvelteDirectiveValueFields, +}; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteDirectiveValue { + compact: bool, +} +impl FormatNodeRule for FormatSvelteDirectiveValue { + fn fmt_fields(&self, node: &SvelteDirectiveValue, f: &mut HtmlFormatter) -> FormatResult<()> { + if !self.fmt_compact(node, f)? { + let SvelteDirectiveValueFields { + property, + colon_token, + modifiers, + initializer, + } = node.as_fields(); + + write!( + f, + [colon_token.format(), property.format(), modifiers.format()] + )?; + + if let Some(initializer) = initializer { + write!(f, [initializer.format()])?; + } + } + + Ok(()) + } +} + +impl FormatSvelteDirectiveValue { + fn fmt_compact( + &self, + node: &SvelteDirectiveValue, + f: &mut HtmlFormatter, + ) -> FormatResult { + let SvelteDirectiveValueFields { + property, + colon_token, + modifiers, + initializer, + } = node.as_fields(); + if self.compact { + let property = property.clone()?; + let binding_value = match &property { + AnySvelteBindingProperty::SvelteLiteral(literal) => literal.value_token(), + AnySvelteBindingProperty::SvelteName(name) => name.ident_token(), + }?; + + let Some(initializer) = initializer.clone() else { + return Ok(false); + }; + let Some(initializer_value) = initializer.value().ok().and_then(|v| v.string_value()) + else { + return Ok(false); + }; + + if initializer_value.text() != binding_value.text_trimmed() { + return Ok(false); + } + + write!( + f, + [ + colon_token.format(), + text(initializer_value.text(), initializer.range().start()), + initializer.format().with_options( + FormatHtmlAttributeInitializerClauseOptions { + compact: CompactKind::Remove, + attribute_name: None, + tag_name: None + } + ), + property.format().with_options(true), + modifiers.format().with_options(true) + ] + )?; + + return Ok(true); + } + + Ok(false) + } +} + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatSvelteDirectiveValueOptions { + pub(crate) compact: bool, +} + +impl FormatRuleWithOptions for FormatSvelteDirectiveValue { + type Options = FormatSvelteDirectiveValueOptions; + + fn with_options(mut self, options: Self::Options) -> Self { + self.compact = options.compact; + self + } +} diff --git a/crates/biome_html_formatter/src/svelte/value/mod.rs b/crates/biome_html_formatter/src/svelte/value/mod.rs new file mode 100644 index 000000000000..68f363ad2d66 --- /dev/null +++ b/crates/biome_html_formatter/src/svelte/value/mod.rs @@ -0,0 +1,3 @@ +//! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. + +pub(crate) mod directive_value; diff --git a/crates/biome_html_formatter/src/utils/mod.rs b/crates/biome_html_formatter/src/utils/mod.rs index 13f1b5cdbe17..e171aa598ae0 100644 --- a/crates/biome_html_formatter/src/utils/mod.rs +++ b/crates/biome_html_formatter/src/utils/mod.rs @@ -1,3 +1,4 @@ pub mod children; pub mod formatters; pub mod metadata; +pub(crate) mod svelte_directive; diff --git a/crates/biome_html_formatter/src/utils/svelte_directive.rs b/crates/biome_html_formatter/src/utils/svelte_directive.rs new file mode 100644 index 000000000000..de43cbc48689 --- /dev/null +++ b/crates/biome_html_formatter/src/utils/svelte_directive.rs @@ -0,0 +1,123 @@ +use crate::AsFormat; +use crate::prelude::HtmlFormatContext; +use crate::svelte::value::directive_value::FormatSvelteDirectiveValueOptions; +use biome_formatter::Buffer; +use biome_formatter::formatter::Formatter; +use biome_formatter::write; +use biome_formatter::{Format, FormatResult}; +use biome_html_syntax::{ + HtmlSyntaxNode, HtmlSyntaxToken, SvelteAnimateDirective, SvelteBindDirective, + SvelteClassDirective, SvelteDirectiveValue, SvelteInDirective, SvelteOutDirective, + SvelteStyleDirective, SvelteTransitionDirective, SvelteUseDirective, +}; +use biome_rowan::{AstNode, SyntaxResult}; + +pub(crate) struct FmtSvelteDirective<'a> { + _node: &'a HtmlSyntaxNode, + token: SyntaxResult, + value: SyntaxResult, + allows_compact: bool, +} + +impl<'a> From<&'a SvelteAnimateDirective> for FmtSvelteDirective<'a> { + fn from(value: &'a SvelteAnimateDirective) -> Self { + Self { + token: value.animate_token(), + value: value.value(), + _node: value.syntax(), + allows_compact: false, + } + } +} + +impl<'a> From<&'a SvelteInDirective> for FmtSvelteDirective<'a> { + fn from(value: &'a SvelteInDirective) -> Self { + Self { + token: value.in_token(), + value: value.value(), + _node: value.syntax(), + allows_compact: false, + } + } +} + +impl<'a> From<&'a SvelteOutDirective> for FmtSvelteDirective<'a> { + fn from(value: &'a SvelteOutDirective) -> Self { + Self { + token: value.out_token(), + value: value.value(), + _node: value.syntax(), + allows_compact: false, + } + } +} + +impl<'a> From<&'a SvelteBindDirective> for FmtSvelteDirective<'a> { + fn from(value: &'a SvelteBindDirective) -> Self { + Self { + token: value.bind_token(), + value: value.value(), + _node: value.syntax(), + allows_compact: true, + } + } +} + +impl<'a> From<&'a SvelteTransitionDirective> for FmtSvelteDirective<'a> { + fn from(value: &'a SvelteTransitionDirective) -> Self { + Self { + token: value.transition_token(), + value: value.value(), + _node: value.syntax(), + allows_compact: false, + } + } +} + +impl<'a> From<&'a SvelteClassDirective> for FmtSvelteDirective<'a> { + fn from(value: &'a SvelteClassDirective) -> Self { + Self { + token: value.class_token(), + value: value.value(), + _node: value.syntax(), + allows_compact: false, + } + } +} +impl<'a> From<&'a SvelteStyleDirective> for FmtSvelteDirective<'a> { + fn from(value: &'a SvelteStyleDirective) -> Self { + Self { + token: value.style_token(), + value: value.value(), + _node: value.syntax(), + allows_compact: false, + } + } +} + +impl<'a> From<&'a SvelteUseDirective> for FmtSvelteDirective<'a> { + fn from(value: &'a SvelteUseDirective) -> Self { + Self { + token: value.use_token(), + value: value.value(), + _node: value.syntax(), + allows_compact: false, + } + } +} + +impl<'a> Format for FmtSvelteDirective<'a> { + fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { + write!( + f, + [ + self.token.format(), + self.value + .format()? + .with_options(FormatSvelteDirectiveValueOptions { + compact: self.allows_compact + }) + ] + ) + } +} diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/compat_binding.svelte b/crates/biome_html_formatter/tests/specs/html/svelte/compat_binding.svelte new file mode 100644 index 000000000000..175c25eedb7a --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/compat_binding.svelte @@ -0,0 +1,3 @@ +
+
+
diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/compat_binding.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/compat_binding.svelte.snap new file mode 100644 index 000000000000..6be2a3515aa4 --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/compat_binding.svelte.snap @@ -0,0 +1,39 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: svelte/compat_binding.svelte +--- +# Input + +```svelte +
+
+
+ +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Attribute Position: Auto +Bracket same line: false +Whitespace sensitivity: css +Indent script and style: false +Self close void elements: never +Trailing newline: true +----- + +```svelte +
+
+
+ +``` diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_bind_basic.svelte b/crates/biome_html_formatter/tests/specs/html/svelte/directive_bind_basic.svelte new file mode 100644 index 000000000000..56aeb620b97f --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_bind_basic.svelte @@ -0,0 +1,2 @@ + + diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_bind_basic.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/directive_bind_basic.svelte.snap new file mode 100644 index 000000000000..87c65816c246 --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_bind_basic.svelte.snap @@ -0,0 +1,37 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: svelte/directive_bind_basic.svelte +--- +# Input + +```svelte + + + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Attribute Position: Auto +Bracket same line: false +Whitespace sensitivity: css +Indent script and style: false +Self close void elements: never +Trailing newline: true +----- + +```svelte + + + +``` diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_class_basic.svelte b/crates/biome_html_formatter/tests/specs/html/svelte/directive_class_basic.svelte new file mode 100644 index 000000000000..958eaaa91fe1 --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_class_basic.svelte @@ -0,0 +1,3 @@ +
Toggle class
+
Shorthand class
+

Multiple classes

diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_class_basic.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/directive_class_basic.svelte.snap new file mode 100644 index 000000000000..84e3bb8f9e3c --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_class_basic.svelte.snap @@ -0,0 +1,39 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: svelte/directive_class_basic.svelte +--- +# Input + +```svelte +
Toggle class
+
Shorthand class
+

Multiple classes

+ +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Attribute Position: Auto +Bracket same line: false +Whitespace sensitivity: css +Indent script and style: false +Self close void elements: never +Trailing newline: true +----- + +```svelte +
Toggle class
+
Shorthand class
+

Multiple classes

+ +``` diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_multiple.svelte b/crates/biome_html_formatter/tests/specs/html/svelte/directive_multiple.svelte new file mode 100644 index 000000000000..d01be0ab81dd --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_multiple.svelte @@ -0,0 +1,2 @@ + +
Multiple directives
diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_multiple.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/directive_multiple.svelte.snap new file mode 100644 index 000000000000..6981118cff85 --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_multiple.svelte.snap @@ -0,0 +1,43 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: svelte/directive_multiple.svelte +--- +# Input + +```svelte + +
Multiple directives
+ +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Attribute Position: Auto +Bracket same line: false +Whitespace sensitivity: css +Indent script and style: false +Self close void elements: never +Trailing newline: true +----- + +```svelte + +
+ Multiple directives +
+ +``` diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_style_important.svelte b/crates/biome_html_formatter/tests/specs/html/svelte/directive_style_important.svelte new file mode 100644 index 000000000000..4a0a93e46f49 --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_style_important.svelte @@ -0,0 +1,3 @@ +
Normal style
+
Important style
+

Multiple styles

diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_style_important.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/directive_style_important.svelte.snap new file mode 100644 index 000000000000..b6956f9868ff --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_style_important.svelte.snap @@ -0,0 +1,41 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: svelte/directive_style_important.svelte +--- +# Input + +```svelte +
Normal style
+
Important style
+

Multiple styles

+ +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Attribute Position: Auto +Bracket same line: false +Whitespace sensitivity: css +Indent script and style: false +Self close void elements: never +Trailing newline: true +----- + +```svelte +
Normal style
+
Important style
+

+ Multiple styles +

+ +``` diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_transition_modifiers.svelte b/crates/biome_html_formatter/tests/specs/html/svelte/directive_transition_modifiers.svelte new file mode 100644 index 000000000000..4454278503cd --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_transition_modifiers.svelte @@ -0,0 +1,3 @@ +
Content
+

Global transition

+Complex diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_transition_modifiers.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/directive_transition_modifiers.svelte.snap new file mode 100644 index 000000000000..152cdc7a3d63 --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_transition_modifiers.svelte.snap @@ -0,0 +1,39 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: svelte/directive_transition_modifiers.svelte +--- +# Input + +```svelte +
Content
+

Global transition

+Complex + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Attribute Position: Auto +Bracket same line: false +Whitespace sensitivity: css +Indent script and style: false +Self close void elements: never +Trailing newline: true +----- + +```svelte +
Content
+

Global transition

+Complex + +``` diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_use_basic.svelte b/crates/biome_html_formatter/tests/specs/html/svelte/directive_use_basic.svelte new file mode 100644 index 000000000000..cf00110a770c --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_use_basic.svelte @@ -0,0 +1,2 @@ +
Click outside handler
+ diff --git a/crates/biome_html_formatter/tests/specs/html/svelte/directive_use_basic.svelte.snap b/crates/biome_html_formatter/tests/specs/html/svelte/directive_use_basic.svelte.snap new file mode 100644 index 000000000000..0d2456f37e44 --- /dev/null +++ b/crates/biome_html_formatter/tests/specs/html/svelte/directive_use_basic.svelte.snap @@ -0,0 +1,37 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: svelte/directive_use_basic.svelte +--- +# Input + +```svelte +
Click outside handler
+ + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Attribute Position: Auto +Bracket same line: false +Whitespace sensitivity: css +Indent script and style: false +Self close void elements: never +Trailing newline: true +----- + +```svelte +
Click outside handler
+ + +``` diff --git a/crates/biome_html_parser/src/lexer/mod.rs b/crates/biome_html_parser/src/lexer/mod.rs index 2d7b6680e7c1..14a8401f9dd8 100644 --- a/crates/biome_html_parser/src/lexer/mod.rs +++ b/crates/biome_html_parser/src/lexer/mod.rs @@ -5,16 +5,16 @@ use crate::token_source::{ TextExpressionKind, }; use biome_html_syntax::HtmlSyntaxKind::{ - AS_KW, ATTACH_KW, AWAIT_KW, CATCH_KW, COMMENT, CONST_KW, DEBUG_KW, DOCTYPE_KW, EACH_KW, - ELSE_KW, EOF, ERROR_TOKEN, HTML_KW, HTML_LITERAL, HTML_STRING_LITERAL, IDENT, IF_KW, KEY_KW, - NEWLINE, RENDER_KW, SNIPPET_KW, THEN_KW, TOMBSTONE, UNICODE_BOM, WHITESPACE, + ANIMATE_KW, AS_KW, ATTACH_KW, AWAIT_KW, BIND_KW, CATCH_KW, CLASS_KW, COMMENT, CONST_KW, + DEBUG_KW, DOCTYPE_KW, EACH_KW, ELSE_KW, EOF, ERROR_TOKEN, HTML_KW, HTML_LITERAL, + HTML_STRING_LITERAL, IDENT, IF_KW, IN_KW, KEY_KW, NEWLINE, OUT_KW, RENDER_KW, SNIPPET_KW, + STYLE_KW, THEN_KW, TOMBSTONE, TRANSITION_KW, UNICODE_BOM, USE_KW, WHITESPACE, }; use biome_html_syntax::{HtmlSyntaxKind, T, TextLen, TextSize}; use biome_parser::diagnostic::ParseDiagnostic; use biome_parser::lexer::{Lexer, LexerCheckpoint, LexerWithCheckpoint, ReLexer, TokenFlags}; use biome_rowan::SyntaxKind; -use biome_unicode_table::Dispatch::{BSL, QOT, UNI}; -use biome_unicode_table::lookup_byte; +use biome_unicode_table::{Dispatch::*, lookup_byte}; use std::ops::{Add, AddAssign}; pub(crate) struct HtmlLexer<'src> { @@ -61,29 +61,31 @@ impl<'src> HtmlLexer<'src> { /// Consume a token in the [HtmlLexContext::InsideTag] context. fn consume_token_inside_tag(&mut self, current: u8) -> HtmlSyntaxKind { - match current { - b'\n' | b'\r' | b'\t' | b' ' => self.consume_newline_or_whitespaces(), - b'<' => self.consume_l_angle(), - b'>' => self.consume_byte(T![>]), - b'/' => self.consume_byte(T![/]), - b'=' => self.consume_byte(T![=]), - b'!' => self.consume_byte(T![!]), - b'{' if self.at_svelte_opening_block() => self.consume_svelte_opening_block(), - b'{' => { + let dispatched = lookup_byte(current); + + match dispatched { + WHS => self.consume_newline_or_whitespaces(), + LSS => self.consume_l_angle(), + MOR => self.consume_byte(T![>]), + SLH => self.consume_byte(T![/]), + EQL => self.consume_byte(T![=]), + EXL => self.consume_byte(T![!]), + BEO if self.at_svelte_opening_block() => self.consume_svelte_opening_block(), + BEO => { if self.at_opening_double_text_expression() { self.consume_l_double_text_expression() } else { self.consume_byte(T!['{']) } } - b'}' => { + BEC => { if self.at_closing_double_text_expression() { self.consume_r_double_text_expression() } else { self.consume_byte(T!['}']) } } - b'\'' | b'"' => self.consume_string_literal(current), + QOT => self.consume_string_literal(current), _ if self.current_kind == T![<] && is_tag_name_byte(current) => { // tag names must immediately follow a `<` // https://html.spec.whatwg.org/multipage/syntax.html#start-tags @@ -92,7 +94,7 @@ impl<'src> HtmlLexer<'src> { _ if self.current_kind != T![<] && is_attribute_name_byte(current) => { self.consume_identifier(current, IdentifierContext::None) } - _ if is_at_start_identifier(current) => self + IDT => self .consume_language_identifier(current) .unwrap_or_else(|| self.consume_unexpected_character()), _ => { @@ -109,21 +111,23 @@ impl<'src> HtmlLexer<'src> { /// Consume a token in the [HtmlLexContext::InsideTagVue] context. fn consume_token_inside_tag_vue(&mut self, current: u8) -> HtmlSyntaxKind { - match current { - b'\n' | b'\r' | b'\t' | b' ' => self.consume_newline_or_whitespaces(), - b'<' => self.consume_l_angle(), - b'>' => self.consume_byte(T![>]), - b'/' => self.consume_byte(T![/]), - b'=' => self.consume_byte(T![=]), - b'!' => self.consume_byte(T![!]), - b'{' => { + let dispatched = lookup_byte(current); + + match dispatched { + WHS => self.consume_newline_or_whitespaces(), + LSS => self.consume_l_angle(), + MOR => self.consume_byte(T![>]), + SLH => self.consume_byte(T![/]), + EQL => self.consume_byte(T![=]), + EXL => self.consume_byte(T![!]), + BEO => { if self.at_opening_double_text_expression() { self.consume_l_double_text_expression() } else { self.consume_byte(T!['{']) } } - b'}' => { + BEC => { if self.at_closing_double_text_expression() { self.consume_r_double_text_expression() } else { @@ -132,14 +136,14 @@ impl<'src> HtmlLexer<'src> { } // these are used in Vue directives - b':' => self.consume_byte(T![:]), - b'@' => self.consume_byte(T![@]), - b'.' => self.consume_byte(T![.]), - b'[' => self.consume_byte(T!['[']), - b']' => self.consume_byte(T![']']), - b'#' => self.consume_byte(T![#]), - - b'\'' | b'"' => self.consume_string_literal(current), + COL => self.consume_byte(T![:]), + AT_ => self.consume_byte(T![@]), + PRD => self.consume_byte(T![.]), + BTO => self.consume_byte(T!['[']), + BTC => self.consume_byte(T![']']), + HAS => self.consume_byte(T![#]), + + QOT => self.consume_string_literal(current), _ if self.current_kind == T![<] && is_tag_name_byte(current) => { // tag names must immediately follow a `<` // https://html.spec.whatwg.org/multipage/syntax.html#start-tags @@ -157,30 +161,32 @@ impl<'src> HtmlLexer<'src> { /// Consume a token in the [HtmlLexContext::Regular] context. fn consume_token(&mut self, current: u8) -> HtmlSyntaxKind { - match current { - b'\n' | b'\r' | b'\t' | b' ' => self.consume_newline_or_whitespaces(), - b'!' if self.current() == T![<] => self.consume_byte(T![!]), - b'/' if self.current() == T![<] => self.consume_byte(T![/]), - b',' if self.current() == T![<] => self.consume_byte(T![,]), - b'-' if self.at_frontmatter_edge() => self.consume_frontmatter_edge(), - b'{' if self.at_svelte_opening_block() => self.consume_svelte_opening_block(), - b'[' => self.consume_byte(T!['[']), - b']' => self.consume_byte(T![']']), - b'{' => { + let dispatched = lookup_byte(current); + + match dispatched { + WHS => self.consume_newline_or_whitespaces(), + EXL if self.current() == T![<] => self.consume_byte(T![!]), + SLH if self.current() == T![<] => self.consume_byte(T![/]), + COM if self.current() == T![<] => self.consume_byte(T![,]), + MIN if self.at_frontmatter_edge() => self.consume_frontmatter_edge(), + BEO if self.at_svelte_opening_block() => self.consume_svelte_opening_block(), + BTO => self.consume_byte(T!['[']), + BTC => self.consume_byte(T![']']), + BEO => { if self.at_opening_double_text_expression() { self.consume_l_double_text_expression() } else { self.consume_byte(T!['{']) } } - b'}' => { + BEC => { if self.at_closing_double_text_expression() { self.consume_r_double_text_expression() } else { self.consume_byte(T!['}']) } } - b'<' => { + LSS => { // if this truly is the start of a tag, it *must* be immediately followed by a tag name. Whitespace is not allowed. // https://html.spec.whatwg.org/multipage/syntax.html#start-tags if self @@ -199,7 +205,7 @@ impl<'src> HtmlLexer<'src> { self.consume_byte(HTML_LITERAL) } } - _ if is_at_start_identifier(current) => self + IDT => self .consume_language_identifier(current) .unwrap_or_else(|| self.consume_html_text(current)), _ => { @@ -216,25 +222,29 @@ impl<'src> HtmlLexer<'src> { /// Consume a token in the [HtmlLexContext::AttributeValue] context. fn consume_token_attribute_value(&mut self, current: u8) -> HtmlSyntaxKind { - match current { - b'\n' | b'\r' | b'\t' | b' ' => self.consume_newline_or_whitespaces(), - b'<' => self.consume_byte(T![<]), - b'>' => self.consume_byte(T![>]), - b'{' => self.consume_byte(T!['{']), - b'}' => self.consume_byte(T!['}']), - b'\'' | b'"' => self.consume_string_literal(current), + let dispatched = lookup_byte(current); + + match dispatched { + WHS => self.consume_newline_or_whitespaces(), + LSS => self.consume_byte(T![<]), + MOR => self.consume_byte(T![>]), + BEO => self.consume_byte(T!['{']), + BEC => self.consume_byte(T!['}']), + QOT => self.consume_string_literal(current), _ => self.consume_unquoted_string_literal(), } } /// Consume a token in the [HtmlLexContext::Doctype] context. fn consume_token_doctype(&mut self, current: u8) -> HtmlSyntaxKind { - match current { - b'\n' | b'\r' | b'\t' | b' ' => self.consume_newline_or_whitespaces(), - b'<' => self.consume_byte(T![<]), - b'>' => self.consume_byte(T![>]), - b'!' => self.consume_byte(T![!]), - b'\'' | b'"' => self.consume_string_literal(current), + let dispatched = lookup_byte(current); + + match dispatched { + WHS => self.consume_newline_or_whitespaces(), + LSS => self.consume_byte(T![<]), + MOR => self.consume_byte(T![>]), + EXL => self.consume_byte(T![!]), + QOT => self.consume_string_literal(current), _ if is_tag_name_byte(current) || is_attribute_name_byte(current) => { self.consume_identifier(current, IdentifierContext::Doctype) } @@ -291,19 +301,19 @@ impl<'src> HtmlLexer<'src> { /// Consumes tokens within a double text expression ('{{...}}') until the closing /// delimiter is reached. Returns HTML_LITERAL for the expression content. fn consume_double_text_expression(&mut self, current: u8) -> HtmlSyntaxKind { - match current { - b'}' if self.at_closing_double_text_expression() => { + let dispatched = lookup_byte(current); + + match dispatched { + BEC if self.at_closing_double_text_expression() => { self.consume_r_double_text_expression() } - b'<' => self.consume_byte(T![<]), + LSS => self.consume_byte(T![<]), _ => { while let Some(current) = self.current_byte() { - match current { - b'}' if self.at_closing_double_text_expression() => break, - _ => { - self.advance(1); - } + if current == b'}' && self.at_closing_double_text_expression() { + break; } + self.advance(1); } HTML_LITERAL } @@ -431,9 +441,11 @@ impl<'src> HtmlLexer<'src> { /// Consume a token in the [HtmlLexContext::CdataSection] context. fn consume_inside_cdata(&mut self, current: u8) -> HtmlSyntaxKind { - match current { - b'<' if self.at_start_cdata() => self.consume_cdata_start(), - b']' if self.at_end_cdata() => self.consume_cdata_end(), + let dispatched = lookup_byte(current); + + match dispatched { + LSS if self.at_start_cdata() => self.consume_cdata_start(), + BTC if self.at_end_cdata() => self.consume_cdata_end(), _ => { while let Some(char) = self.current_byte() { if self.at_end_cdata() { @@ -453,11 +465,13 @@ impl<'src> HtmlLexer<'src> { current: u8, context: HtmlLexContext, ) -> HtmlSyntaxKind { - match current { - b'\n' | b'\r' | b'\t' | b' ' => self.consume_newline_or_whitespaces(), - b'<' if self.at_start_cdata() => self.consume_cdata_start(), - b'<' => self.consume_byte(T![<]), - b'-' => { + let dispatched = lookup_byte(current); + + match dispatched { + WHS => self.consume_newline_or_whitespaces(), + LSS if self.at_start_cdata() => self.consume_cdata_start(), + LSS => self.consume_byte(T![<]), + MIN => { debug_assert!(self.at_frontmatter_edge()); self.advance(3); T![---] @@ -469,24 +483,41 @@ impl<'src> HtmlLexer<'src> { } fn consume_svelte(&mut self, current: u8) -> HtmlSyntaxKind { - match current { - b'\n' | b'\r' | b'\t' | b' ' => self.consume_newline_or_whitespaces(), - b'}' => self.consume_byte(T!['}']), - b'.' if self.is_at_three_dots() => self.consume_dot3(), - b',' => self.consume_byte(T![,]), - b'(' => self.consume_byte(T!['(']), - b')' => self.consume_byte(T![')']), - b'{' if self.at_svelte_opening_block() => self.consume_svelte_opening_block(), - b'{' => self.consume_byte(T!['{']), - b'[' => self.consume_byte(T!['[']), - b']' => self.consume_byte(T![']']), - _ if is_at_start_identifier(current) => self + let dispatched = lookup_byte(current); + + match dispatched { + WHS => self.consume_newline_or_whitespaces(), + BEC => self.consume_byte(T!['}']), + PRD if self.is_at_three_dots() => self.consume_dot3(), + COM => self.consume_byte(T![,]), + PNO => self.consume_byte(T!['(']), + PNC => self.consume_byte(T![')']), + BEO if self.at_svelte_opening_block() => self.consume_svelte_opening_block(), + BEO => self.consume_byte(T!['{']), + BTO => self.consume_byte(T!['[']), + BTC => self.consume_byte(T![']']), + COL => self.consume_byte(T![:]), + EQL => self.consume_byte(T![=]), + PIP => self.consume_byte(T![|]), + IDT => self .consume_language_identifier(current) .unwrap_or_else(|| self.consume_svelte_identifier(current)), _ => self.consume_single_text_expression(), } } + fn consume_svelte_literal(&mut self) -> HtmlSyntaxKind { + while let Some(current) = self.current_byte() { + let dispatched = lookup_byte(current); + if dispatched == WHS || dispatched == EQL || dispatched == MOR { + break; + } + self.advance(1); + } + + HTML_LITERAL + } + /// Consumes a Svelte identifier (alphanumeric + underscore only) fn consume_svelte_identifier(&mut self, first: u8) -> HtmlSyntaxKind { self.assert_current_char_boundary(); @@ -568,6 +599,15 @@ impl<'src> HtmlLexer<'src> { b"then" => THEN_KW, b"catch" => CATCH_KW, b"snippet" => SNIPPET_KW, + b"bind" => BIND_KW, + b"transition" => TRANSITION_KW, + b"animate" => ANIMATE_KW, + b"in" => IN_KW, + b"out" => OUT_KW, + b"use" => USE_KW, + b"style" => STYLE_KW, + b"class" => CLASS_KW, + _ => { self.position = starting_position; return None; @@ -979,15 +1019,17 @@ impl<'src> HtmlLexer<'src> { let mut closing_expression = None; let mut was_escaped = false; - match current { - b'{' => { + let dispatched = lookup_byte(current); + + match dispatched { + BEO => { if self.at_opening_double_text_expression() { self.consume_l_double_text_expression() } else { self.consume_byte(T!['{']) } } - b'}' => { + BEC => { if self.at_closing_double_text_expression() { self.consume_r_double_text_expression() } else { @@ -996,20 +1038,22 @@ impl<'src> HtmlLexer<'src> { } _ => { while let Some(current) = self.current_byte() { - match current { - b'{' => { + let dispatched = lookup_byte(current); + + match dispatched { + BEO => { if was_escaped { self.advance(1); } else { break; } } - b'\\' => { + BSL => { was_escaped = true; whitespace_started = None; self.advance(1); } - b'}' => { + BEC => { if was_escaped { self.advance(1); } else { @@ -1023,10 +1067,10 @@ impl<'src> HtmlLexer<'src> { } } - b'<' => { + LSS => { break; } - b'\n' | b'\r' => { + WHS if current == b'\n' || current == b'\r' => { if whitespace_started.is_none() { whitespace_started = Some(self.checkpoint()); } @@ -1037,7 +1081,7 @@ impl<'src> HtmlLexer<'src> { } self.advance(1); } - b' ' | b'\t' => { + WHS => { if was_escaped { was_escaped = false; } @@ -1114,6 +1158,7 @@ impl<'src> Lexer<'src> for HtmlLexer<'src> { self.consume_astro_frontmatter(current, context) } HtmlLexContext::Svelte => self.consume_svelte(current), + HtmlLexContext::SvelteBindingLiteral => self.consume_svelte_literal(), }, None => EOF, } @@ -1190,6 +1235,7 @@ impl<'src> ReLexer<'src> for HtmlLexer<'src> { Some(current) => match context { HtmlReLexContext::Svelte => self.consume_svelte(current), HtmlReLexContext::HtmlText => self.consume_html_text(current), + HtmlReLexContext::InsideTag => self.consume_token_inside_tag(current), }, None => EOF, }; diff --git a/crates/biome_html_parser/src/syntax/mod.rs b/crates/biome_html_parser/src/syntax/mod.rs index 1da85f760bda..e44de56f0c38 100644 --- a/crates/biome_html_parser/src/syntax/mod.rs +++ b/crates/biome_html_parser/src/syntax/mod.rs @@ -8,7 +8,8 @@ use crate::syntax::HtmlSyntaxFeatures::{DoubleTextExpressions, SingleTextExpress use crate::syntax::astro::parse_astro_fence; use crate::syntax::parse_error::*; use crate::syntax::svelte::{ - is_at_svelte_keyword, parse_attach_attribute, parse_svelte_at_block, parse_svelte_hash_block, + is_at_svelte_directive_start, is_at_svelte_keyword, parse_attach_attribute, + parse_svelte_at_block, parse_svelte_directive, parse_svelte_hash_block, }; use crate::syntax::vue::{ parse_vue_directive, parse_vue_v_bind_shorthand_directive, parse_vue_v_on_shorthand_directive, @@ -393,17 +394,22 @@ fn parse_attribute(p: &mut HtmlParser) -> ParsedSyntax { T!['{'] => SingleTextExpressions.parse_exclusive_syntax( p, |p| parse_single_text_expression(p, HtmlLexContext::InsideTag), - |p: &HtmlParser<'_>, m: &CompletedMarker| disabled_svelte_prop(p, m.range(p)), + |p: &HtmlParser<'_>, m: &CompletedMarker| disabled_svelte(p, m.range(p)), ), T!["{@"] => SingleTextExpressions.parse_exclusive_syntax( p, |p| parse_attach_attribute(p), - |p: &HtmlParser<'_>, m: &CompletedMarker| disabled_svelte_prop(p, m.range(p)), + |p: &HtmlParser<'_>, m: &CompletedMarker| disabled_svelte(p, m.range(p)), ), _ if p.cur_text().starts_with("v-") => { HtmlSyntaxFeatures::Vue .parse_exclusive_syntax(p, parse_vue_directive, |p, m| disabled_vue(p, m.range(p))) } + _ if is_at_svelte_directive_start(p) => { + SingleTextExpressions.parse_exclusive_syntax(p, parse_svelte_directive, |p, m| { + disabled_svelte(p, m.range(p)) + }) + } _ => { let m = p.start(); parse_literal(p, HTML_ATTRIBUTE_NAME).or_add_diagnostic(p, expected_attribute); diff --git a/crates/biome_html_parser/src/syntax/parse_error.rs b/crates/biome_html_parser/src/syntax/parse_error.rs index eda64a77cb7b..c27824a84c14 100644 --- a/crates/biome_html_parser/src/syntax/parse_error.rs +++ b/crates/biome_html_parser/src/syntax/parse_error.rs @@ -13,7 +13,7 @@ pub(crate) fn disabled_interpolation(p: &HtmlParser, range: TextRange) -> ParseD p.err_builder("Text expressions aren't supported.", range).with_hint(markup!("Remove it or enable the parsing using the ""html.parser.interpolation"" option.")) } -pub(crate) fn disabled_svelte_prop(p: &HtmlParser, range: TextRange) -> ParseDiagnostic { +pub(crate) fn disabled_svelte(p: &HtmlParser, range: TextRange) -> ParseDiagnostic { p.err_builder("This looks like Svelte syntax, but this is not a Svelte file.", range).with_hint(markup!("Remove it or rename this file to have the "".svelte"" file extension.")) } @@ -106,12 +106,7 @@ pub(crate) fn expected_svelte_closing_block(p: &HtmlParser, range: TextRange) -> } pub(crate) fn expected_name(p: &HtmlParser, range: TextRange) -> ParseDiagnostic { - expected_node( - "Expected a name or a closing block, instead found none.", - range, - p, - ) - .into_diagnostic(p) + expect_one_of(&["name", "closing block"], range).into_diagnostic(p) } pub(crate) fn disabled_vue(p: &HtmlParser, range: TextRange) -> ParseDiagnostic { @@ -126,3 +121,16 @@ pub(crate) fn expected_expression(p: &HtmlParser, range: TextRange) -> ParseDiag p.err_builder("Expected an expression, instead none was found.", range) .into_diagnostic(p) } + +pub(crate) fn expected_svelte_property(p: &HtmlParser, range: TextRange) -> ParseDiagnostic { + p.err_builder("Expected a property, instead none was found.", range) + .into_diagnostic(p) +} + +pub(crate) fn expected_valid_directive(p: &HtmlParser, range: TextRange) -> ParseDiagnostic { + p.err_builder( + "Expected a valid directive, which should be followed by ':' and a value.", + range, + ) + .into_diagnostic(p) +} diff --git a/crates/biome_html_parser/src/syntax/svelte.rs b/crates/biome_html_parser/src/syntax/svelte.rs index 6d5ee1f922b0..b25f0822f107 100644 --- a/crates/biome_html_parser/src/syntax/svelte.rs +++ b/crates/biome_html_parser/src/syntax/svelte.rs @@ -1,23 +1,29 @@ use crate::parser::HtmlParser; use crate::syntax::parse_error::{ expected_child_or_block, expected_expression, expected_name, expected_svelte_closing_block, - expected_text_expression, + expected_svelte_property, expected_text_expression, expected_valid_directive, +}; +use crate::syntax::{ + parse_attribute_initializer, parse_html_element, parse_single_text_expression_content, }; -use crate::syntax::{parse_html_element, parse_single_text_expression_content}; use crate::token_source::{HtmlLexContext, HtmlReLexContext, RestrictedExpressionStopAt}; use biome_html_syntax::HtmlSyntaxKind::{ - EOF, HTML_BOGUS_ELEMENT, HTML_ELEMENT_LIST, HTML_LITERAL, IDENT, SVELTE_ATTACH_ATTRIBUTE, - SVELTE_AWAIT_BLOCK, SVELTE_AWAIT_CATCH_BLOCK, SVELTE_AWAIT_CATCH_CLAUSE, - SVELTE_AWAIT_CLAUSES_LIST, SVELTE_AWAIT_CLOSING_BLOCK, SVELTE_AWAIT_OPENING_BLOCK, - SVELTE_AWAIT_THEN_BLOCK, SVELTE_AWAIT_THEN_CLAUSE, SVELTE_BINDING_ASSIGNMENT_BINDING_LIST, - SVELTE_BINDING_LIST, SVELTE_BOGUS_BLOCK, SVELTE_CONST_BLOCK, SVELTE_CURLY_DESTRUCTURED_NAME, - SVELTE_DEBUG_BLOCK, SVELTE_EACH_AS_KEYED_ITEM, SVELTE_EACH_BLOCK, SVELTE_EACH_CLOSING_BLOCK, - SVELTE_EACH_INDEX, SVELTE_EACH_KEY, SVELTE_EACH_KEYED_ITEM, SVELTE_EACH_OPENING_BLOCK, - SVELTE_ELSE_CLAUSE, SVELTE_ELSE_IF_CLAUSE, SVELTE_ELSE_IF_CLAUSE_LIST, SVELTE_HTML_BLOCK, - SVELTE_IF_BLOCK, SVELTE_IF_CLOSING_BLOCK, SVELTE_IF_OPENING_BLOCK, SVELTE_KEY_BLOCK, - SVELTE_KEY_CLOSING_BLOCK, SVELTE_KEY_OPENING_BLOCK, SVELTE_NAME, SVELTE_RENDER_BLOCK, - SVELTE_REST_BINDING, SVELTE_SNIPPET_BLOCK, SVELTE_SNIPPET_CLOSING_BLOCK, - SVELTE_SNIPPET_OPENING_BLOCK, SVELTE_SQUARE_DESTRUCTURED_NAME, + EOF, HTML_BOGUS_ELEMENT, HTML_ELEMENT_LIST, HTML_LITERAL, IDENT, SVELTE_ANIMATE_DIRECTIVE, + SVELTE_ATTACH_ATTRIBUTE, SVELTE_AWAIT_BLOCK, SVELTE_AWAIT_CATCH_BLOCK, + SVELTE_AWAIT_CATCH_CLAUSE, SVELTE_AWAIT_CLAUSES_LIST, SVELTE_AWAIT_CLOSING_BLOCK, + SVELTE_AWAIT_OPENING_BLOCK, SVELTE_AWAIT_THEN_BLOCK, SVELTE_AWAIT_THEN_CLAUSE, + SVELTE_BIND_DIRECTIVE, SVELTE_BINDING_ASSIGNMENT_BINDING_LIST, SVELTE_BINDING_LIST, + SVELTE_BOGUS_BLOCK, SVELTE_CLASS_DIRECTIVE, SVELTE_CONST_BLOCK, SVELTE_CURLY_DESTRUCTURED_NAME, + SVELTE_DEBUG_BLOCK, SVELTE_DIRECTIVE_MODIFIER, SVELTE_DIRECTIVE_MODIFIER_LIST, + SVELTE_DIRECTIVE_VALUE, SVELTE_EACH_AS_KEYED_ITEM, SVELTE_EACH_BLOCK, + SVELTE_EACH_CLOSING_BLOCK, SVELTE_EACH_INDEX, SVELTE_EACH_KEY, SVELTE_EACH_KEYED_ITEM, + SVELTE_EACH_OPENING_BLOCK, SVELTE_ELSE_CLAUSE, SVELTE_ELSE_IF_CLAUSE, + SVELTE_ELSE_IF_CLAUSE_LIST, SVELTE_HTML_BLOCK, SVELTE_IF_BLOCK, SVELTE_IF_CLOSING_BLOCK, + SVELTE_IF_OPENING_BLOCK, SVELTE_IN_DIRECTIVE, SVELTE_KEY_BLOCK, SVELTE_KEY_CLOSING_BLOCK, + SVELTE_KEY_OPENING_BLOCK, SVELTE_LITERAL, SVELTE_NAME, SVELTE_OUT_DIRECTIVE, + SVELTE_RENDER_BLOCK, SVELTE_REST_BINDING, SVELTE_SNIPPET_BLOCK, SVELTE_SNIPPET_CLOSING_BLOCK, + SVELTE_SNIPPET_OPENING_BLOCK, SVELTE_SQUARE_DESTRUCTURED_NAME, SVELTE_STYLE_DIRECTIVE, + SVELTE_TRANSITION_DIRECTIVE, SVELTE_USE_DIRECTIVE, }; use biome_html_syntax::{HtmlSyntaxKind, T}; use biome_parser::parse_lists::{ParseNodeList, ParseSeparatedList}; @@ -932,6 +938,12 @@ fn parse_name(p: &mut HtmlParser) -> ParsedSyntax { Present(m.complete(p, SVELTE_NAME)) } +fn parse_binding_literal(p: &mut HtmlParser) -> ParsedSyntax { + let m = p.start(); + p.bump_with_context(HTML_LITERAL, HtmlLexContext::InsideTag); + Present(m.complete(p, SVELTE_LITERAL)) +} + /// Parses `...rest` fn parse_rest_name(p: &mut HtmlParser) -> ParsedSyntax { if !p.at(T![...]) { @@ -1072,6 +1084,129 @@ impl ParseSeparatedList for SvelteBindingAssignmentBindingList { } } +// #region Directives parsing functions + +pub(crate) fn parse_svelte_directive(p: &mut HtmlParser) -> ParsedSyntax { + if !is_at_svelte_directive_start(p) { + return Absent; + } + + // relex token so we acknowledge the keyword + p.re_lex(HtmlReLexContext::Svelte); + + match p.cur() { + T![bind] => parse_directive(p, T![bind], SVELTE_BIND_DIRECTIVE, HtmlLexContext::Svelte), + T![transition] => parse_directive( + p, + T![transition], + SVELTE_TRANSITION_DIRECTIVE, + HtmlLexContext::Svelte, + ), + T![in] => parse_directive(p, T![in], SVELTE_IN_DIRECTIVE, HtmlLexContext::Svelte), + T![out] => parse_directive(p, T![out], SVELTE_OUT_DIRECTIVE, HtmlLexContext::Svelte), + T![class] => parse_directive( + p, + T![class], + SVELTE_CLASS_DIRECTIVE, + HtmlLexContext::SvelteBindingLiteral, + ), + T![style] => parse_directive( + p, + T![style], + SVELTE_STYLE_DIRECTIVE, + HtmlLexContext::SvelteBindingLiteral, + ), + T![use] => parse_directive(p, T![use], SVELTE_USE_DIRECTIVE, HtmlLexContext::Svelte), + T![animate] => parse_directive( + p, + T![animate], + SVELTE_ANIMATE_DIRECTIVE, + HtmlLexContext::Svelte, + ), + _ => Absent, + } +} + +fn parse_directive_value(p: &mut HtmlParser, context_after_colon: HtmlLexContext) -> ParsedSyntax { + if !p.at(T![:]) { + return Absent; + } + + let m = p.start(); + + p.bump_with_context(T![:], context_after_colon); + if p.cur_text().is_empty() { + p.error(p.err_builder("The directive can't be empty.", p.cur_range())) + } else if context_after_colon == HtmlLexContext::SvelteBindingLiteral { + parse_binding_literal(p).or_add_diagnostic(p, expected_svelte_property); + } else { + parse_name(p).or_add_diagnostic(p, expected_name); + } + + ModifiersList.parse_list(p); + + if p.at(T![=]) { + parse_attribute_initializer(p).ok(); + } else { + p.re_lex(HtmlReLexContext::InsideTag); + } + + Present(m.complete(p, SVELTE_DIRECTIVE_VALUE)) +} + +/// Parses a general directive. `token` is the keyword to parse, and `node_kind` is the kind of the node to emit. +fn parse_directive( + p: &mut HtmlParser, + token: HtmlSyntaxKind, + node_kind: HtmlSyntaxKind, + context_after_colon: HtmlLexContext, +) -> ParsedSyntax { + if !p.at(token) { + return Absent; + } + + let m = p.start(); + p.bump_with_context(token, HtmlLexContext::Svelte); + + parse_directive_value(p, context_after_colon).or_add_diagnostic(p, expected_valid_directive); + + Present(m.complete(p, node_kind)) +} + +struct ModifiersList; + +impl ParseNodeList for ModifiersList { + type Kind = HtmlSyntaxKind; + type Parser<'source> = HtmlParser<'source>; + const LIST_KIND: Self::Kind = SVELTE_DIRECTIVE_MODIFIER_LIST; + + fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax { + let m = p.start(); + p.expect_with_context(T![|], HtmlLexContext::Svelte); + parse_name(p).or_add_diagnostic(p, |p, range| { + p.err_builder("Expected a valid Svelte modifier name", range) + }); + Present(m.complete(p, SVELTE_DIRECTIVE_MODIFIER)) + } + + fn is_at_list_end(&self, p: &mut Self::Parser<'_>) -> bool { + !p.at(T![|]) + } + + fn recover( + &mut self, + p: &mut Self::Parser<'_>, + parsed_element: ParsedSyntax, + ) -> RecoveryResult { + parsed_element.or_recover_with_token_set( + p, + &ParseRecoveryTokenSet::new(SVELTE_BOGUS_BLOCK, BLOCK_RECOVER), + expected_name, + ) + } +} +// #endregion + // #region Check functions pub(crate) fn is_at_svelte_keyword(p: &HtmlParser) -> bool { @@ -1090,6 +1225,12 @@ pub(crate) fn is_at_svelte_keyword(p: &HtmlParser) -> bool { | T![catch] | T![then] | T![snippet] + | T![class] + | T![in] + | T![out] + | T![transition] + | T![animate] + | T![bind] ) } @@ -1101,4 +1242,16 @@ fn is_at_then_or_catch_block(p: &mut HtmlParser) -> bool { p.at(T!["{:"]) && (p.nth_at(1, T![then]) || p.nth_at(1, T![catch])) } +pub(crate) fn is_at_svelte_directive_start(p: &HtmlParser) -> bool { + let text = p.cur_text(); + text.starts_with("bind:") + || text.starts_with("transition:") + || text.starts_with("in:") + || text.starts_with("out:") + || text.starts_with("animate:") + || text.starts_with("use:") + || text.starts_with("style:") + || text.starts_with("class:") +} + // #endregion diff --git a/crates/biome_html_parser/src/token_source.rs b/crates/biome_html_parser/src/token_source.rs index 5b6d7ad23ebb..0ba9d639298a 100644 --- a/crates/biome_html_parser/src/token_source.rs +++ b/crates/biome_html_parser/src/token_source.rs @@ -40,6 +40,9 @@ pub(crate) enum HtmlLexContext { /// Outside of this context, the lexer doesn't yield any particular keywords. Svelte, + /// The binding properties in Svelte are special and require a special lexing. They accept everything until `=` is found. + SvelteBindingLiteral, + /// Lex tokens inside text expressions. In the following examples, `foo` is the text expression: /// - `{{ foo }}` /// - `attr={ foo }` @@ -139,6 +142,8 @@ pub(crate) enum HtmlReLexContext { Svelte, /// Relex tokens using `HtmlLexer::consume_html_text` HtmlText, + /// Relex tokens as if the parser was inside a tag. + InsideTag, } pub(crate) type HtmlTokenSourceCheckpoint = TokenSourceCheckpoint; diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/debug-trailing-comma.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/debug-trailing-comma.svelte.snap index 97e5bfbdde78..8cd332c8d57e 100644 --- a/crates/biome_html_parser/tests/html_specs/error/svelte/debug-trailing-comma.svelte.snap +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/debug-trailing-comma.svelte.snap @@ -61,16 +61,15 @@ HtmlRoot { ``` debug-trailing-comma.svelte:1:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Expected a Expected a name or a closing block, instead found none. but instead found '}'. + × Unexpected value or character. > 1 │ {@debug something,} │ ^ 2 │ - i Expected a Expected a name or a closing block, instead found none. here. + i Expected one of: - > 1 │ {@debug something,} - │ ^ - 2 │ + - name + - closing block ``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/debug.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/debug.svelte.snap index c0a03871dab4..fe5ffaf259e7 100644 --- a/crates/biome_html_parser/tests/html_specs/error/svelte/debug.svelte.snap +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/debug.svelte.snap @@ -87,7 +87,7 @@ HtmlRoot { ``` debug.svelte:2:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Expected a Expected a name or a closing block, instead found none. but instead found '{@'. + × Unexpected value or character. 1 │ {@debug > 2 │ {@debug something} @@ -95,12 +95,9 @@ debug.svelte:2:1 parse ━━━━━━━━━━━━━━━━━━━ 3 │ {@debug debug} 4 │ - i Expected a Expected a name or a closing block, instead found none. here. + i Expected one of: - 1 │ {@debug - > 2 │ {@debug something} - │ ^^ - 3 │ {@debug debug} - 4 │ + - name + - closing block ``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_invalid_params.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_invalid_params.svelte new file mode 100644 index 000000000000..5814aa8f528d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_invalid_params.svelte @@ -0,0 +1,3 @@ +{#each list as item (item)} +
  • {item}
  • +{/each} diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_invalid_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_invalid_params.svelte.snap new file mode 100644 index 000000000000..2db27be6f103 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_invalid_params.svelte.snap @@ -0,0 +1,211 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +{#each list as item (item)} +
  • {item}
  • +{/each} + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + SvelteEachBlock { + opening_block: SvelteEachOpeningBlock { + sv_curly_hash_token: SV_CURLY_HASH@0..2 "{#" [] [], + each_token: EACH_KW@2..6 "each" [] [], + list: HtmlTextExpression { + html_literal_token: HTML_LITERAL@6..12 " list " [] [], + }, + item: SvelteEachAsKeyedItem { + as_token: AS_KW@12..15 "as" [] [Whitespace(" ")], + name: SvelteName { + ident_token: IDENT@15..20 "item" [] [Whitespace(" ")], + }, + index: missing (optional), + key: SvelteEachKey { + l_paren_token: L_PAREN@20..21 "(" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@21..25 "item" [] [], + }, + r_paren_token: R_PAREN@25..26 ")" [] [], + }, + }, + r_curly_token: R_CURLY@26..27 "}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlBogusAttribute { + items: [ + ANIMATE_KW@34..41 "animate" [] [], + HtmlBogus { + items: [ + COLON@41..42 ":" [] [], + SvelteName { + ident_token: IDENT@42..46 "flip" [] [], + }, + SvelteDirectiveModifierList [], + HtmlBogus { + items: [ + EQ@46..47 "=" [] [], + HtmlBogusTextExpression { + items: [ + L_CURLY@47..48 "{" [] [], + L_CURLY@48..50 "{" [] [Whitespace(" ")], + HTML_LITERAL@50..59 "delay: }>" [] [], + L_CURLY@59..60 "{" [] [], + HTML_LITERAL@60..65 "item}" [] [], + ], + }, + ], + }, + ], + }, + ], + }, + ], + r_angle_token: missing (required), + }, + children: HtmlElementList [], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@65..66 "<" [] [], + slash_token: SLASH@66..67 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@67..69 "li" [] [], + }, + r_angle_token: R_ANGLE@69..70 ">" [] [], + }, + }, + ], + else_clause: missing (optional), + closing_block: SvelteEachClosingBlock { + sv_curly_slash_token: SV_CURLY_SLASH@70..73 "{/" [Newline("\n")] [], + each_token: EACH_KW@73..77 "each" [] [], + r_curly_token: R_CURLY@77..78 "}" [] [], + }, + }, + ], + eof_token: EOF@78..79 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..79 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..78 + 0: SVELTE_EACH_BLOCK@0..78 + 0: SVELTE_EACH_OPENING_BLOCK@0..27 + 0: SV_CURLY_HASH@0..2 "{#" [] [] + 1: EACH_KW@2..6 "each" [] [] + 2: HTML_TEXT_EXPRESSION@6..12 + 0: HTML_LITERAL@6..12 " list " [] [] + 3: SVELTE_EACH_AS_KEYED_ITEM@12..26 + 0: AS_KW@12..15 "as" [] [Whitespace(" ")] + 1: SVELTE_NAME@15..20 + 0: IDENT@15..20 "item" [] [Whitespace(" ")] + 2: (empty) + 3: SVELTE_EACH_KEY@20..26 + 0: L_PAREN@20..21 "(" [] [] + 1: HTML_TEXT_EXPRESSION@21..25 + 0: HTML_LITERAL@21..25 "item" [] [] + 2: R_PAREN@25..26 ")" [] [] + 4: R_CURLY@26..27 "}" [] [] + 1: HTML_ELEMENT_LIST@27..70 + 0: HTML_ELEMENT@27..70 + 0: HTML_OPENING_ELEMENT@27..65 + 0: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@31..34 + 0: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@34..65 + 0: HTML_BOGUS_ATTRIBUTE@34..65 + 0: ANIMATE_KW@34..41 "animate" [] [] + 1: HTML_BOGUS@41..65 + 0: COLON@41..42 ":" [] [] + 1: SVELTE_NAME@42..46 + 0: IDENT@42..46 "flip" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@46..46 + 3: HTML_BOGUS@46..65 + 0: EQ@46..47 "=" [] [] + 1: HTML_BOGUS_TEXT_EXPRESSION@47..65 + 0: L_CURLY@47..48 "{" [] [] + 1: L_CURLY@48..50 "{" [] [Whitespace(" ")] + 2: HTML_LITERAL@50..59 "delay: }>" [] [] + 3: L_CURLY@59..60 "{" [] [] + 4: HTML_LITERAL@60..65 "item}" [] [] + 3: (empty) + 1: HTML_ELEMENT_LIST@65..65 + 2: HTML_CLOSING_ELEMENT@65..70 + 0: L_ANGLE@65..66 "<" [] [] + 1: SLASH@66..67 "/" [] [] + 2: HTML_TAG_NAME@67..69 + 0: HTML_LITERAL@67..69 "li" [] [] + 3: R_ANGLE@69..70 ">" [] [] + 2: (empty) + 3: SVELTE_EACH_CLOSING_BLOCK@70..78 + 0: SV_CURLY_SLASH@70..73 "{/" [Newline("\n")] [] + 1: EACH_KW@73..77 "each" [] [] + 2: R_CURLY@77..78 "}" [] [] + 4: EOF@78..79 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +animate_invalid_params.svelte:2:20 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Found a text expression that doesn't have the closing expression: + + 1 │ {#each list as item (item)} + > 2 │
  • {item}
  • + │ ^^^^^^^^^^^^^^^^^^ + 3 │ {/each} + 4 │ + + i This is where the opening expression was found: + + 1 │ {#each list as item (item)} + > 2 │
  • {item}
  • + │ ^ + 3 │ {/each} + 4 │ + +animate_invalid_params.svelte:2:38 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + 1 │ {#each list as item (item)} + > 2 │
  • {item}
  • + │ ^ + 3 │ {/each} + 4 │ + + i Expected an attribute here. + + 1 │ {#each list as item (item)} + > 2 │
  • {item}
  • + │ ^ + 3 │ {/each} + 4 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_missing_name.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_missing_name.svelte new file mode 100644 index 000000000000..c3ea3f4787f5 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_missing_name.svelte @@ -0,0 +1,3 @@ +{#each list as item (item)} +
  • {item}
  • +{/each} diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_missing_name.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_missing_name.svelte.snap new file mode 100644 index 000000000000..62bd1615ae8b --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/animate_missing_name.svelte.snap @@ -0,0 +1,177 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +{#each list as item (item)} +
  • {item}
  • +{/each} + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + SvelteEachBlock { + opening_block: SvelteEachOpeningBlock { + sv_curly_hash_token: SV_CURLY_HASH@0..2 "{#" [] [], + each_token: EACH_KW@2..6 "each" [] [], + list: HtmlTextExpression { + html_literal_token: HTML_LITERAL@6..12 " list " [] [], + }, + item: SvelteEachAsKeyedItem { + as_token: AS_KW@12..15 "as" [] [Whitespace(" ")], + name: SvelteName { + ident_token: IDENT@15..20 "item" [] [Whitespace(" ")], + }, + index: missing (optional), + key: SvelteEachKey { + l_paren_token: L_PAREN@20..21 "(" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@21..25 "item" [] [], + }, + r_paren_token: R_PAREN@25..26 ")" [] [], + }, + }, + r_curly_token: R_CURLY@26..27 "}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteAnimateDirective { + animate_token: ANIMATE_KW@34..41 "animate" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@41..42 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@42..43 ">" [] [], + }, + children: HtmlElementList [ + HtmlSingleTextExpression { + l_curly_token: L_CURLY@43..44 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@44..48 "item" [] [], + }, + r_curly_token: R_CURLY@48..49 "}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@49..50 "<" [] [], + slash_token: SLASH@50..51 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@51..53 "li" [] [], + }, + r_angle_token: R_ANGLE@53..54 ">" [] [], + }, + }, + ], + else_clause: missing (optional), + closing_block: SvelteEachClosingBlock { + sv_curly_slash_token: SV_CURLY_SLASH@54..57 "{/" [Newline("\n")] [], + each_token: EACH_KW@57..61 "each" [] [], + r_curly_token: R_CURLY@61..62 "}" [] [], + }, + }, + ], + eof_token: EOF@62..63 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..63 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..62 + 0: SVELTE_EACH_BLOCK@0..62 + 0: SVELTE_EACH_OPENING_BLOCK@0..27 + 0: SV_CURLY_HASH@0..2 "{#" [] [] + 1: EACH_KW@2..6 "each" [] [] + 2: HTML_TEXT_EXPRESSION@6..12 + 0: HTML_LITERAL@6..12 " list " [] [] + 3: SVELTE_EACH_AS_KEYED_ITEM@12..26 + 0: AS_KW@12..15 "as" [] [Whitespace(" ")] + 1: SVELTE_NAME@15..20 + 0: IDENT@15..20 "item" [] [Whitespace(" ")] + 2: (empty) + 3: SVELTE_EACH_KEY@20..26 + 0: L_PAREN@20..21 "(" [] [] + 1: HTML_TEXT_EXPRESSION@21..25 + 0: HTML_LITERAL@21..25 "item" [] [] + 2: R_PAREN@25..26 ")" [] [] + 4: R_CURLY@26..27 "}" [] [] + 1: HTML_ELEMENT_LIST@27..54 + 0: HTML_ELEMENT@27..54 + 0: HTML_OPENING_ELEMENT@27..43 + 0: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@31..34 + 0: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@34..42 + 0: SVELTE_ANIMATE_DIRECTIVE@34..42 + 0: ANIMATE_KW@34..41 "animate" [] [] + 1: SVELTE_DIRECTIVE_VALUE@41..42 + 0: COLON@41..42 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@42..42 + 3: (empty) + 3: R_ANGLE@42..43 ">" [] [] + 1: HTML_ELEMENT_LIST@43..49 + 0: HTML_SINGLE_TEXT_EXPRESSION@43..49 + 0: L_CURLY@43..44 "{" [] [] + 1: HTML_TEXT_EXPRESSION@44..48 + 0: HTML_LITERAL@44..48 "item" [] [] + 2: R_CURLY@48..49 "}" [] [] + 2: HTML_CLOSING_ELEMENT@49..54 + 0: L_ANGLE@49..50 "<" [] [] + 1: SLASH@50..51 "/" [] [] + 2: HTML_TAG_NAME@51..53 + 0: HTML_LITERAL@51..53 "li" [] [] + 3: R_ANGLE@53..54 ">" [] [] + 2: (empty) + 3: SVELTE_EACH_CLOSING_BLOCK@54..62 + 0: SV_CURLY_SLASH@54..57 "{/" [Newline("\n")] [] + 1: EACH_KW@57..61 "each" [] [] + 2: R_CURLY@61..62 "}" [] [] + 4: EOF@62..63 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +animate_missing_name.svelte:2:15 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + 1 │ {#each list as item (item)} + > 2 │
  • {item}
  • + │ ^^^^^^^^^^^^ + > 3 │ {/each} + > 4 │ + │ + + i Expected one of: + + - name + - closing block + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_incomplete_expression.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_incomplete_expression.svelte new file mode 100644 index 000000000000..15bc418d980d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_incomplete_expression.svelte @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_incomplete_expression.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_incomplete_expression.svelte.snap new file mode 100644 index 000000000000..d5475af946f1 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_incomplete_expression.svelte.snap @@ -0,0 +1,123 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlBogusAttribute { + items: [ + BIND_KW@7..11 "bind" [] [], + HtmlBogus { + items: [ + COLON@11..12 ":" [] [], + SvelteName { + ident_token: IDENT@12..17 "value" [] [], + }, + SvelteDirectiveModifierList [], + HtmlBogus { + items: [ + EQ@17..18 "=" [] [], + HtmlBogusTextExpression { + items: [ + L_CURLY@18..20 "{" [] [Whitespace(" ")], + HTML_LITERAL@20..22 "/>" [] [], + ], + }, + ], + }, + ], + }, + ], + }, + ], + slash_token: missing (optional), + r_angle_token: missing (required), + }, + ], + eof_token: EOF@22..23 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..23 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..22 + 0: HTML_SELF_CLOSING_ELEMENT@0..22 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..22 + 0: HTML_BOGUS_ATTRIBUTE@7..22 + 0: BIND_KW@7..11 "bind" [] [] + 1: HTML_BOGUS@11..22 + 0: COLON@11..12 ":" [] [] + 1: SVELTE_NAME@12..17 + 0: IDENT@12..17 "value" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@17..17 + 3: HTML_BOGUS@17..22 + 0: EQ@17..18 "=" [] [] + 1: HTML_BOGUS_TEXT_EXPRESSION@18..22 + 0: L_CURLY@18..20 "{" [] [Whitespace(" ")] + 1: HTML_LITERAL@20..22 "/>" [] [] + 3: (empty) + 4: (empty) + 4: EOF@22..23 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +bind_incomplete_expression.svelte:1:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Found a text expression that doesn't have the closing expression: + + > 1 │ + │ ^^^^ + 2 │ + + i This is where the opening expression was found: + + > 1 │ + │ ^ + 2 │ + +bind_incomplete_expression.svelte:2:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `>` but instead the file ends + + 1 │ + > 2 │ + │ + + i the file ends here + + 1 │ + > 2 │ + │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_invalid_syntax.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_invalid_syntax.svelte new file mode 100644 index 000000000000..d1ac5156012f --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_invalid_syntax.svelte @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_invalid_syntax.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_invalid_syntax.svelte.snap new file mode 100644 index 000000000000..996b16e24d65 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_invalid_syntax.svelte.snap @@ -0,0 +1,97 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@7..11 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@11..12 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@12..20 ":{name}" [] [Whitespace(" ")], + }, + initializer: missing (optional), + }, + ], + slash_token: SLASH@20..21 "/" [] [], + r_angle_token: R_ANGLE@21..22 ">" [] [], + }, + ], + eof_token: EOF@22..23 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..23 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..22 + 0: HTML_SELF_CLOSING_ELEMENT@0..22 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..20 + 0: SVELTE_BIND_DIRECTIVE@7..12 + 0: BIND_KW@7..11 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@11..12 + 0: COLON@11..12 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@12..12 + 3: (empty) + 1: HTML_ATTRIBUTE@12..20 + 0: HTML_ATTRIBUTE_NAME@12..20 + 0: HTML_LITERAL@12..20 ":{name}" [] [Whitespace(" ")] + 1: (empty) + 3: SLASH@20..21 "/" [] [] + 4: R_ANGLE@21..22 ">" [] [] + 4: EOF@22..23 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +bind_invalid_syntax.svelte:1:13 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + > 1 │ + │ ^ + 2 │ + + i Expected one of: + + - name + - closing block + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_missing_property.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_missing_property.svelte new file mode 100644 index 000000000000..988e60778421 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_missing_property.svelte @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_missing_property.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_missing_property.svelte.snap new file mode 100644 index 000000000000..7e1886e380ae --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/bind_missing_property.svelte.snap @@ -0,0 +1,102 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@7..11 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@11..12 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@12..13 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@13..14 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@14..18 "name" [] [], + }, + r_curly_token: R_CURLY@18..20 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@20..21 "/" [] [], + r_angle_token: R_ANGLE@21..22 ">" [] [], + }, + ], + eof_token: EOF@22..23 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..23 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..22 + 0: HTML_SELF_CLOSING_ELEMENT@0..22 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..20 + 0: SVELTE_BIND_DIRECTIVE@7..20 + 0: BIND_KW@7..11 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@11..20 + 0: COLON@11..12 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@12..12 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@12..20 + 0: EQ@12..13 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@13..20 + 0: L_CURLY@13..14 "{" [] [] + 1: HTML_TEXT_EXPRESSION@14..18 + 0: HTML_LITERAL@14..18 "name" [] [] + 2: R_CURLY@18..20 "}" [] [Whitespace(" ")] + 3: SLASH@20..21 "/" [] [] + 4: R_ANGLE@21..22 ">" [] [] + 4: EOF@22..23 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +bind_missing_property.svelte:1:13 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + > 1 │ + │ ^ + 2 │ + + i Expected one of: + + - name + - closing block + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_invalid_expression.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_invalid_expression.svelte new file mode 100644 index 000000000000..ac69e6093b97 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_invalid_expression.svelte @@ -0,0 +1 @@ +
    Invalid
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_invalid_expression.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_invalid_expression.svelte.snap new file mode 100644 index 000000000000..9887568df285 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_invalid_expression.svelte.snap @@ -0,0 +1,140 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Invalid
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlBogusAttribute { + items: [ + CLASS_KW@5..10 "class" [] [], + HtmlBogus { + items: [ + COLON@10..11 ":" [] [], + SvelteLiteral { + value_token: HTML_LITERAL@11..17 "active" [] [], + }, + SvelteDirectiveModifierList [], + HtmlBogus { + items: [ + EQ@17..18 "=" [] [], + HtmlBogusTextExpression { + items: [ + L_CURLY@18..19 "{" [] [], + HTML_LITERAL@19..27 ">Invalid" [] [], + ], + }, + ], + }, + ], + }, + ], + }, + ], + r_angle_token: missing (required), + }, + children: HtmlElementList [], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@27..28 "<" [] [], + slash_token: SLASH@28..29 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@29..32 "div" [] [], + }, + r_angle_token: R_ANGLE@32..33 ">" [] [], + }, + }, + ], + eof_token: EOF@33..34 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..34 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..33 + 0: HTML_ELEMENT@0..33 + 0: HTML_OPENING_ELEMENT@0..27 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..27 + 0: HTML_BOGUS_ATTRIBUTE@5..27 + 0: CLASS_KW@5..10 "class" [] [] + 1: HTML_BOGUS@10..27 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..17 + 0: HTML_LITERAL@11..17 "active" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@17..17 + 3: HTML_BOGUS@17..27 + 0: EQ@17..18 "=" [] [] + 1: HTML_BOGUS_TEXT_EXPRESSION@18..27 + 0: L_CURLY@18..19 "{" [] [] + 1: HTML_LITERAL@19..27 ">Invalid" [] [] + 3: (empty) + 1: HTML_ELEMENT_LIST@27..27 + 2: HTML_CLOSING_ELEMENT@27..33 + 0: L_ANGLE@27..28 "<" [] [] + 1: SLASH@28..29 "/" [] [] + 2: HTML_TAG_NAME@29..32 + 0: HTML_LITERAL@29..32 "div" [] [] + 3: R_ANGLE@32..33 ">" [] [] + 4: EOF@33..34 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +class_invalid_expression.svelte:1:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Found a text expression that doesn't have the closing expression: + + > 1 │
    Invalid
    + │ ^^^^^^^^^ + 2 │ + + i This is where the opening expression was found: + + > 1 │
    Invalid
    + │ ^ + 2 │ + +class_invalid_expression.svelte:1:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + > 1 │
    Invalid
    + │ ^ + 2 │ + + i Expected an attribute here. + + > 1 │
    Invalid
    + │ ^ + 2 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_missing_name.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_missing_name.svelte new file mode 100644 index 000000000000..78822147e2ab --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_missing_name.svelte @@ -0,0 +1 @@ +
    Invalid
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_missing_name.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_missing_name.svelte.snap new file mode 100644 index 000000000000..ab4bdca86e72 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/class_missing_name.svelte.snap @@ -0,0 +1,128 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Invalid
    + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlBogusElement { + items: [ + HtmlBogus { + items: [ + L_ANGLE@0..1 "<" [] [], + HtmlTagName { + value_token: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")], + }, + HtmlBogus { + items: [ + SvelteClassDirective { + class_token: CLASS_KW@5..10 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + HtmlBogusElement { + items: [ + EQ@11..12 "=" [] [], + L_CURLY@12..13 "{" [] [], + HTML_LITERAL@13..30 "isActive}>Invalid" [] [], + ], + }, + ], + }, + ], + }, + HtmlElementList [], + HtmlClosingElement { + l_angle_token: L_ANGLE@30..31 "<" [] [], + slash_token: SLASH@31..32 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@32..35 "div" [] [], + }, + r_angle_token: R_ANGLE@35..36 ">" [] [], + }, + ], + }, + ], + eof_token: EOF@36..37 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..37 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..36 + 0: HTML_BOGUS_ELEMENT@0..36 + 0: HTML_BOGUS@0..30 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_BOGUS@5..30 + 0: SVELTE_CLASS_DIRECTIVE@5..11 + 0: CLASS_KW@5..10 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..11 + 0: COLON@10..11 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@11..11 + 3: (empty) + 1: HTML_BOGUS_ELEMENT@11..30 + 0: EQ@11..12 "=" [] [] + 1: L_CURLY@12..13 "{" [] [] + 2: HTML_LITERAL@13..30 "isActive}>Invalid" [] [] + 1: HTML_ELEMENT_LIST@30..30 + 2: HTML_CLOSING_ELEMENT@30..36 + 0: L_ANGLE@30..31 "<" [] [] + 1: SLASH@31..32 "/" [] [] + 2: HTML_TAG_NAME@32..35 + 0: HTML_LITERAL@32..35 "div" [] [] + 3: R_ANGLE@35..36 ">" [] [] + 4: EOF@36..37 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +class_missing_name.svelte:1:12 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × The directive can't be empty. + + > 1 │
    Invalid
    + │ + 2 │ + +class_missing_name.svelte:1:31 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + > 1 │
    Invalid
    + │ ^ + 2 │ + + i Expected an attribute here. + + > 1 │
    Invalid
    + │ ^ + 2 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_invalid_params.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_invalid_params.svelte new file mode 100644 index 000000000000..8b9f38ceeeb0 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_invalid_params.svelte @@ -0,0 +1 @@ +
    Incomplete
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_invalid_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_invalid_params.svelte.snap new file mode 100644 index 000000000000..153fb134f30e --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_invalid_params.svelte.snap @@ -0,0 +1,142 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Incomplete
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlBogusAttribute { + items: [ + IN_KW@5..7 "in" [] [], + HtmlBogus { + items: [ + COLON@7..8 ":" [] [], + SvelteName { + ident_token: IDENT@8..11 "fly" [] [], + }, + SvelteDirectiveModifierList [], + HtmlBogus { + items: [ + EQ@11..12 "=" [] [], + HtmlBogusTextExpression { + items: [ + L_CURLY@12..13 "{" [] [], + L_CURLY@13..15 "{" [] [Whitespace(" ")], + HTML_LITERAL@15..29 "y: >Incomplete" [] [], + ], + }, + ], + }, + ], + }, + ], + }, + ], + r_angle_token: missing (required), + }, + children: HtmlElementList [], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@29..30 "<" [] [], + slash_token: SLASH@30..31 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@31..34 "div" [] [], + }, + r_angle_token: R_ANGLE@34..35 ">" [] [], + }, + }, + ], + eof_token: EOF@35..36 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..36 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..35 + 0: HTML_ELEMENT@0..35 + 0: HTML_OPENING_ELEMENT@0..29 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..29 + 0: HTML_BOGUS_ATTRIBUTE@5..29 + 0: IN_KW@5..7 "in" [] [] + 1: HTML_BOGUS@7..29 + 0: COLON@7..8 ":" [] [] + 1: SVELTE_NAME@8..11 + 0: IDENT@8..11 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@11..11 + 3: HTML_BOGUS@11..29 + 0: EQ@11..12 "=" [] [] + 1: HTML_BOGUS_TEXT_EXPRESSION@12..29 + 0: L_CURLY@12..13 "{" [] [] + 1: L_CURLY@13..15 "{" [] [Whitespace(" ")] + 2: HTML_LITERAL@15..29 "y: >Incomplete" [] [] + 3: (empty) + 1: HTML_ELEMENT_LIST@29..29 + 2: HTML_CLOSING_ELEMENT@29..35 + 0: L_ANGLE@29..30 "<" [] [] + 1: SLASH@30..31 "/" [] [] + 2: HTML_TAG_NAME@31..34 + 0: HTML_LITERAL@31..34 "div" [] [] + 3: R_ANGLE@34..35 ">" [] [] + 4: EOF@35..36 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +in_invalid_params.svelte:1:13 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Found a text expression that doesn't have the closing expression: + + > 1 │
    Incomplete
    + │ ^^^^^^^^^^^^^^^^^ + 2 │ + + i This is where the opening expression was found: + + > 1 │
    Incomplete
    + │ ^ + 2 │ + +in_invalid_params.svelte:1:30 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + > 1 │
    Incomplete
    + │ ^ + 2 │ + + i Expected an attribute here. + + > 1 │
    Incomplete
    + │ ^ + 2 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_missing_name.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_missing_name.svelte new file mode 100644 index 000000000000..04a3a26bac27 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_missing_name.svelte @@ -0,0 +1 @@ +
    Invalid
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_missing_name.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_missing_name.svelte.snap new file mode 100644 index 000000000000..ad23ee9c043b --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/in_missing_name.svelte.snap @@ -0,0 +1,111 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Invalid
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@5..7 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@7..8 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@8..9 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@9..16 "Invalid" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@16..17 "<" [] [], + slash_token: SLASH@17..18 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@18..21 "div" [] [], + }, + r_angle_token: R_ANGLE@21..22 ">" [] [], + }, + }, + ], + eof_token: EOF@22..23 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..23 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..22 + 0: HTML_ELEMENT@0..22 + 0: HTML_OPENING_ELEMENT@0..9 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..8 + 0: SVELTE_IN_DIRECTIVE@5..8 + 0: IN_KW@5..7 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@7..8 + 0: COLON@7..8 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@8..8 + 3: (empty) + 3: R_ANGLE@8..9 ">" [] [] + 1: HTML_ELEMENT_LIST@9..16 + 0: HTML_CONTENT@9..16 + 0: HTML_LITERAL@9..16 "Invalid" [] [] + 2: HTML_CLOSING_ELEMENT@16..22 + 0: L_ANGLE@16..17 "<" [] [] + 1: SLASH@17..18 "/" [] [] + 2: HTML_TAG_NAME@18..21 + 0: HTML_LITERAL@18..21 "div" [] [] + 3: R_ANGLE@21..22 ">" [] [] + 4: EOF@22..23 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +in_missing_name.svelte:1:9 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + > 1 │
    Invalid
    + │ ^^^^^^^^^^^^^^ + > 2 │ + │ + + i Expected one of: + + - name + - closing block + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_invalid_params.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_invalid_params.svelte new file mode 100644 index 000000000000..87f16f96be39 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_invalid_params.svelte @@ -0,0 +1 @@ +
    Incomplete
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_invalid_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_invalid_params.svelte.snap new file mode 100644 index 000000000000..129d5b2b27f1 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_invalid_params.svelte.snap @@ -0,0 +1,142 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Incomplete
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlBogusAttribute { + items: [ + OUT_KW@5..8 "out" [] [], + HtmlBogus { + items: [ + COLON@8..9 ":" [] [], + SvelteName { + ident_token: IDENT@9..13 "fade" [] [], + }, + SvelteDirectiveModifierList [], + HtmlBogus { + items: [ + EQ@13..14 "=" [] [], + HtmlBogusTextExpression { + items: [ + L_CURLY@14..15 "{" [] [], + L_CURLY@15..17 "{" [] [Whitespace(" ")], + HTML_LITERAL@17..38 "duration: >Incomplete" [] [], + ], + }, + ], + }, + ], + }, + ], + }, + ], + r_angle_token: missing (required), + }, + children: HtmlElementList [], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@38..39 "<" [] [], + slash_token: SLASH@39..40 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@40..43 "div" [] [], + }, + r_angle_token: R_ANGLE@43..44 ">" [] [], + }, + }, + ], + eof_token: EOF@44..45 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..45 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..44 + 0: HTML_ELEMENT@0..44 + 0: HTML_OPENING_ELEMENT@0..38 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..38 + 0: HTML_BOGUS_ATTRIBUTE@5..38 + 0: OUT_KW@5..8 "out" [] [] + 1: HTML_BOGUS@8..38 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..13 + 0: IDENT@9..13 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@13..13 + 3: HTML_BOGUS@13..38 + 0: EQ@13..14 "=" [] [] + 1: HTML_BOGUS_TEXT_EXPRESSION@14..38 + 0: L_CURLY@14..15 "{" [] [] + 1: L_CURLY@15..17 "{" [] [Whitespace(" ")] + 2: HTML_LITERAL@17..38 "duration: >Incomplete" [] [] + 3: (empty) + 1: HTML_ELEMENT_LIST@38..38 + 2: HTML_CLOSING_ELEMENT@38..44 + 0: L_ANGLE@38..39 "<" [] [] + 1: SLASH@39..40 "/" [] [] + 2: HTML_TAG_NAME@40..43 + 0: HTML_LITERAL@40..43 "div" [] [] + 3: R_ANGLE@43..44 ">" [] [] + 4: EOF@44..45 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +out_invalid_params.svelte:1:15 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Found a text expression that doesn't have the closing expression: + + > 1 │
    Incomplete
    + │ ^^^^^^^^^^^^^^^^^^^^^^^^ + 2 │ + + i This is where the opening expression was found: + + > 1 │
    Incomplete
    + │ ^ + 2 │ + +out_invalid_params.svelte:1:39 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + > 1 │
    Incomplete
    + │ ^ + 2 │ + + i Expected an attribute here. + + > 1 │
    Incomplete
    + │ ^ + 2 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_missing_name.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_missing_name.svelte new file mode 100644 index 000000000000..db69e76e1dd4 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_missing_name.svelte @@ -0,0 +1 @@ +
    Invalid
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_missing_name.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_missing_name.svelte.snap new file mode 100644 index 000000000000..d3f3d91198d0 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/out_missing_name.svelte.snap @@ -0,0 +1,111 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Invalid
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteOutDirective { + out_token: OUT_KW@5..8 "out" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@9..10 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@10..17 "Invalid" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@17..18 "<" [] [], + slash_token: SLASH@18..19 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@19..22 "div" [] [], + }, + r_angle_token: R_ANGLE@22..23 ">" [] [], + }, + }, + ], + eof_token: EOF@23..24 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..24 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..23 + 0: HTML_ELEMENT@0..23 + 0: HTML_OPENING_ELEMENT@0..10 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..9 + 0: SVELTE_OUT_DIRECTIVE@5..9 + 0: OUT_KW@5..8 "out" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..9 + 0: COLON@8..9 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@9..9 + 3: (empty) + 3: R_ANGLE@9..10 ">" [] [] + 1: HTML_ELEMENT_LIST@10..17 + 0: HTML_CONTENT@10..17 + 0: HTML_LITERAL@10..17 "Invalid" [] [] + 2: HTML_CLOSING_ELEMENT@17..23 + 0: L_ANGLE@17..18 "<" [] [] + 1: SLASH@18..19 "/" [] [] + 2: HTML_TAG_NAME@19..22 + 0: HTML_LITERAL@19..22 "div" [] [] + 3: R_ANGLE@22..23 ">" [] [] + 4: EOF@23..24 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +out_missing_name.svelte:1:10 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + > 1 │
    Invalid
    + │ ^^^^^^^^^^^^^^ + > 2 │ + │ + + i Expected one of: + + - name + - closing block + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_incomplete_expression.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_incomplete_expression.svelte new file mode 100644 index 000000000000..3f3b538f2500 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_incomplete_expression.svelte @@ -0,0 +1 @@ +
    Incomplete
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_incomplete_expression.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_incomplete_expression.svelte.snap new file mode 100644 index 000000000000..cd1fe7d0a149 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_incomplete_expression.svelte.snap @@ -0,0 +1,140 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Incomplete
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlBogusAttribute { + items: [ + STYLE_KW@5..10 "style" [] [], + HtmlBogus { + items: [ + COLON@10..11 ":" [] [], + SvelteLiteral { + value_token: HTML_LITERAL@11..16 "color" [] [], + }, + SvelteDirectiveModifierList [], + HtmlBogus { + items: [ + EQ@16..17 "=" [] [], + HtmlBogusTextExpression { + items: [ + L_CURLY@17..18 "{" [] [], + HTML_LITERAL@18..29 ">Incomplete" [] [], + ], + }, + ], + }, + ], + }, + ], + }, + ], + r_angle_token: missing (required), + }, + children: HtmlElementList [], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@29..30 "<" [] [], + slash_token: SLASH@30..31 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@31..34 "div" [] [], + }, + r_angle_token: R_ANGLE@34..35 ">" [] [], + }, + }, + ], + eof_token: EOF@35..36 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..36 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..35 + 0: HTML_ELEMENT@0..35 + 0: HTML_OPENING_ELEMENT@0..29 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..29 + 0: HTML_BOGUS_ATTRIBUTE@5..29 + 0: STYLE_KW@5..10 "style" [] [] + 1: HTML_BOGUS@10..29 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..16 + 0: HTML_LITERAL@11..16 "color" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..16 + 3: HTML_BOGUS@16..29 + 0: EQ@16..17 "=" [] [] + 1: HTML_BOGUS_TEXT_EXPRESSION@17..29 + 0: L_CURLY@17..18 "{" [] [] + 1: HTML_LITERAL@18..29 ">Incomplete" [] [] + 3: (empty) + 1: HTML_ELEMENT_LIST@29..29 + 2: HTML_CLOSING_ELEMENT@29..35 + 0: L_ANGLE@29..30 "<" [] [] + 1: SLASH@30..31 "/" [] [] + 2: HTML_TAG_NAME@31..34 + 0: HTML_LITERAL@31..34 "div" [] [] + 3: R_ANGLE@34..35 ">" [] [] + 4: EOF@35..36 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +style_incomplete_expression.svelte:1:18 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Found a text expression that doesn't have the closing expression: + + > 1 │
    Incomplete
    + │ ^^^^^^^^^^^^ + 2 │ + + i This is where the opening expression was found: + + > 1 │
    Incomplete
    + │ ^ + 2 │ + +style_incomplete_expression.svelte:1:30 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + > 1 │
    Incomplete
    + │ ^ + 2 │ + + i Expected an attribute here. + + > 1 │
    Incomplete
    + │ ^ + 2 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_missing_property.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_missing_property.svelte new file mode 100644 index 000000000000..886f69906376 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_missing_property.svelte @@ -0,0 +1 @@ +
    Invalid
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_missing_property.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_missing_property.svelte.snap new file mode 100644 index 000000000000..244cc879d3db --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/style_missing_property.svelte.snap @@ -0,0 +1,126 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Invalid
    + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlBogusElement { + items: [ + HtmlBogus { + items: [ + L_ANGLE@0..1 "<" [] [], + HtmlTagName { + value_token: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")], + }, + HtmlBogus { + items: [ + SvelteStyleDirective { + style_token: STYLE_KW@5..10 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + HtmlBogusElement { + items: [ + EQ@11..12 "=" [] [], + HTML_LITERAL@12..25 "\"red\">Invalid" [] [], + ], + }, + ], + }, + ], + }, + HtmlElementList [], + HtmlClosingElement { + l_angle_token: L_ANGLE@25..26 "<" [] [], + slash_token: SLASH@26..27 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@27..30 "div" [] [], + }, + r_angle_token: R_ANGLE@30..31 ">" [] [], + }, + ], + }, + ], + eof_token: EOF@31..32 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..32 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..31 + 0: HTML_BOGUS_ELEMENT@0..31 + 0: HTML_BOGUS@0..25 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_BOGUS@5..25 + 0: SVELTE_STYLE_DIRECTIVE@5..11 + 0: STYLE_KW@5..10 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..11 + 0: COLON@10..11 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@11..11 + 3: (empty) + 1: HTML_BOGUS_ELEMENT@11..25 + 0: EQ@11..12 "=" [] [] + 1: HTML_LITERAL@12..25 "\"red\">Invalid" [] [] + 1: HTML_ELEMENT_LIST@25..25 + 2: HTML_CLOSING_ELEMENT@25..31 + 0: L_ANGLE@25..26 "<" [] [] + 1: SLASH@26..27 "/" [] [] + 2: HTML_TAG_NAME@27..30 + 0: HTML_LITERAL@27..30 "div" [] [] + 3: R_ANGLE@30..31 ">" [] [] + 4: EOF@31..32 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +style_missing_property.svelte:1:12 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × The directive can't be empty. + + > 1 │
    Invalid
    + │ + 2 │ + +style_missing_property.svelte:1:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + > 1 │
    Invalid
    + │ ^ + 2 │ + + i Expected an attribute here. + + > 1 │
    Invalid
    + │ ^ + 2 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_incomplete_params.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_incomplete_params.svelte new file mode 100644 index 000000000000..80a7d9ccecbc --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_incomplete_params.svelte @@ -0,0 +1 @@ +
    Incomplete
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_incomplete_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_incomplete_params.svelte.snap new file mode 100644 index 000000000000..4c24b191fe38 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_incomplete_params.svelte.snap @@ -0,0 +1,142 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Incomplete
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlBogusAttribute { + items: [ + TRANSITION_KW@5..15 "transition" [] [], + HtmlBogus { + items: [ + COLON@15..16 ":" [] [], + SvelteName { + ident_token: IDENT@16..20 "fade" [] [], + }, + SvelteDirectiveModifierList [], + HtmlBogus { + items: [ + EQ@20..21 "=" [] [], + HtmlBogusTextExpression { + items: [ + L_CURLY@21..22 "{" [] [], + L_CURLY@22..24 "{" [] [Whitespace(" ")], + HTML_LITERAL@24..45 "duration: >Incomplete" [] [], + ], + }, + ], + }, + ], + }, + ], + }, + ], + r_angle_token: missing (required), + }, + children: HtmlElementList [], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@45..46 "<" [] [], + slash_token: SLASH@46..47 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@47..50 "div" [] [], + }, + r_angle_token: R_ANGLE@50..51 ">" [] [], + }, + }, + ], + eof_token: EOF@51..52 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..52 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..51 + 0: HTML_ELEMENT@0..51 + 0: HTML_OPENING_ELEMENT@0..45 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..45 + 0: HTML_BOGUS_ATTRIBUTE@5..45 + 0: TRANSITION_KW@5..15 "transition" [] [] + 1: HTML_BOGUS@15..45 + 0: COLON@15..16 ":" [] [] + 1: SVELTE_NAME@16..20 + 0: IDENT@16..20 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@20..20 + 3: HTML_BOGUS@20..45 + 0: EQ@20..21 "=" [] [] + 1: HTML_BOGUS_TEXT_EXPRESSION@21..45 + 0: L_CURLY@21..22 "{" [] [] + 1: L_CURLY@22..24 "{" [] [Whitespace(" ")] + 2: HTML_LITERAL@24..45 "duration: >Incomplete" [] [] + 3: (empty) + 1: HTML_ELEMENT_LIST@45..45 + 2: HTML_CLOSING_ELEMENT@45..51 + 0: L_ANGLE@45..46 "<" [] [] + 1: SLASH@46..47 "/" [] [] + 2: HTML_TAG_NAME@47..50 + 0: HTML_LITERAL@47..50 "div" [] [] + 3: R_ANGLE@50..51 ">" [] [] + 4: EOF@51..52 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +transition_incomplete_params.svelte:1:22 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Found a text expression that doesn't have the closing expression: + + > 1 │
    Incomplete
    + │ ^^^^^^^^^^^^^^^^^^^^^^^^ + 2 │ + + i This is where the opening expression was found: + + > 1 │
    Incomplete
    + │ ^ + 2 │ + +transition_incomplete_params.svelte:1:46 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + > 1 │
    Incomplete
    + │ ^ + 2 │ + + i Expected an attribute here. + + > 1 │
    Incomplete
    + │ ^ + 2 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_missing_name.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_missing_name.svelte new file mode 100644 index 000000000000..bee9a8c44436 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_missing_name.svelte @@ -0,0 +1 @@ +
    Invalid
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_missing_name.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_missing_name.svelte.snap new file mode 100644 index 000000000000..b36ba933b56d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_missing_name.svelte.snap @@ -0,0 +1,111 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Invalid
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@5..15 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@15..16 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@16..17 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@17..24 "Invalid" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@24..25 "<" [] [], + slash_token: SLASH@25..26 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@26..29 "div" [] [], + }, + r_angle_token: R_ANGLE@29..30 ">" [] [], + }, + }, + ], + eof_token: EOF@30..31 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..31 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..30 + 0: HTML_ELEMENT@0..30 + 0: HTML_OPENING_ELEMENT@0..17 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..16 + 0: SVELTE_TRANSITION_DIRECTIVE@5..16 + 0: TRANSITION_KW@5..15 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@15..16 + 0: COLON@15..16 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..16 + 3: (empty) + 3: R_ANGLE@16..17 ">" [] [] + 1: HTML_ELEMENT_LIST@17..24 + 0: HTML_CONTENT@17..24 + 0: HTML_LITERAL@17..24 "Invalid" [] [] + 2: HTML_CLOSING_ELEMENT@24..30 + 0: L_ANGLE@24..25 "<" [] [] + 1: SLASH@25..26 "/" [] [] + 2: HTML_TAG_NAME@26..29 + 0: HTML_LITERAL@26..29 "div" [] [] + 3: R_ANGLE@29..30 ">" [] [] + 4: EOF@30..31 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +transition_missing_name.svelte:1:17 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + > 1 │
    Invalid
    + │ ^^^^^^^^^^^^^^ + > 2 │ + │ + + i Expected one of: + + - name + - closing block + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_modifier_only.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_modifier_only.svelte new file mode 100644 index 000000000000..32dac664edeb --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_modifier_only.svelte @@ -0,0 +1 @@ +
    Missing name
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_modifier_only.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_modifier_only.svelte.snap new file mode 100644 index 000000000000..bce0ca95ceed --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/transition_modifier_only.svelte.snap @@ -0,0 +1,121 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Missing name
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@5..15 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@15..16 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@16..17 "|" [] [], + name: SvelteName { + ident_token: IDENT@17..23 "global" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@23..24 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@24..36 "Missing name" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@36..37 "<" [] [], + slash_token: SLASH@37..38 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@38..41 "div" [] [], + }, + r_angle_token: R_ANGLE@41..42 ">" [] [], + }, + }, + ], + eof_token: EOF@42..43 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..43 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..42 + 0: HTML_ELEMENT@0..42 + 0: HTML_OPENING_ELEMENT@0..24 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..23 + 0: SVELTE_TRANSITION_DIRECTIVE@5..23 + 0: TRANSITION_KW@5..15 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@15..23 + 0: COLON@15..16 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..23 + 0: SVELTE_DIRECTIVE_MODIFIER@16..23 + 0: PIPE@16..17 "|" [] [] + 1: SVELTE_NAME@17..23 + 0: IDENT@17..23 "global" [] [] + 3: (empty) + 3: R_ANGLE@23..24 ">" [] [] + 1: HTML_ELEMENT_LIST@24..36 + 0: HTML_CONTENT@24..36 + 0: HTML_LITERAL@24..36 "Missing name" [] [] + 2: HTML_CLOSING_ELEMENT@36..42 + 0: L_ANGLE@36..37 "<" [] [] + 1: SLASH@37..38 "/" [] [] + 2: HTML_TAG_NAME@38..41 + 0: HTML_LITERAL@38..41 "div" [] [] + 3: R_ANGLE@41..42 ">" [] [] + 4: EOF@42..43 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +transition_modifier_only.svelte:1:17 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + > 1 │
    Missing name
    + │ ^ + 2 │ + + i Expected one of: + + - name + - closing block + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_invalid_expression.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_invalid_expression.svelte new file mode 100644 index 000000000000..71b56bf49e76 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_invalid_expression.svelte @@ -0,0 +1 @@ +
    Invalid
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_invalid_expression.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_invalid_expression.svelte.snap new file mode 100644 index 000000000000..0bdf9b02a599 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_invalid_expression.svelte.snap @@ -0,0 +1,140 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Invalid
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlBogusAttribute { + items: [ + USE_KW@5..8 "use" [] [], + HtmlBogus { + items: [ + COLON@8..9 ":" [] [], + SvelteName { + ident_token: IDENT@9..16 "tooltip" [] [], + }, + SvelteDirectiveModifierList [], + HtmlBogus { + items: [ + EQ@16..17 "=" [] [], + HtmlBogusTextExpression { + items: [ + L_CURLY@17..18 "{" [] [], + HTML_LITERAL@18..26 ">Invalid" [] [], + ], + }, + ], + }, + ], + }, + ], + }, + ], + r_angle_token: missing (required), + }, + children: HtmlElementList [], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@26..27 "<" [] [], + slash_token: SLASH@27..28 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@28..31 "div" [] [], + }, + r_angle_token: R_ANGLE@31..32 ">" [] [], + }, + }, + ], + eof_token: EOF@32..33 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..33 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..32 + 0: HTML_ELEMENT@0..32 + 0: HTML_OPENING_ELEMENT@0..26 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..26 + 0: HTML_BOGUS_ATTRIBUTE@5..26 + 0: USE_KW@5..8 "use" [] [] + 1: HTML_BOGUS@8..26 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..16 + 0: IDENT@9..16 "tooltip" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..16 + 3: HTML_BOGUS@16..26 + 0: EQ@16..17 "=" [] [] + 1: HTML_BOGUS_TEXT_EXPRESSION@17..26 + 0: L_CURLY@17..18 "{" [] [] + 1: HTML_LITERAL@18..26 ">Invalid" [] [] + 3: (empty) + 1: HTML_ELEMENT_LIST@26..26 + 2: HTML_CLOSING_ELEMENT@26..32 + 0: L_ANGLE@26..27 "<" [] [] + 1: SLASH@27..28 "/" [] [] + 2: HTML_TAG_NAME@28..31 + 0: HTML_LITERAL@28..31 "div" [] [] + 3: R_ANGLE@31..32 ">" [] [] + 4: EOF@32..33 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +use_invalid_expression.svelte:1:18 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Found a text expression that doesn't have the closing expression: + + > 1 │
    Invalid
    + │ ^^^^^^^^^ + 2 │ + + i This is where the opening expression was found: + + > 1 │
    Invalid
    + │ ^ + 2 │ + +use_invalid_expression.svelte:1:27 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an attribute but instead found '<'. + + > 1 │
    Invalid
    + │ ^ + 2 │ + + i Expected an attribute here. + + > 1 │
    Invalid
    + │ ^ + 2 │ + +``` diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_missing_name.svelte b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_missing_name.svelte new file mode 100644 index 000000000000..33610c5175d0 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_missing_name.svelte @@ -0,0 +1 @@ +
    Hover me
    diff --git a/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_missing_name.svelte.snap b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_missing_name.svelte.snap new file mode 100644 index 000000000000..04f2272346f5 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/error/svelte/directives/use_missing_name.svelte.snap @@ -0,0 +1,111 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Hover me
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteUseDirective { + use_token: USE_KW@5..8 "use" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: missing (required), + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@9..10 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@10..18 "Hover me" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@18..19 "<" [] [], + slash_token: SLASH@19..20 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@20..23 "div" [] [], + }, + r_angle_token: R_ANGLE@23..24 ">" [] [], + }, + }, + ], + eof_token: EOF@24..25 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..25 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..24 + 0: HTML_ELEMENT@0..24 + 0: HTML_OPENING_ELEMENT@0..10 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..9 + 0: SVELTE_USE_DIRECTIVE@5..9 + 0: USE_KW@5..8 "use" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..9 + 0: COLON@8..9 ":" [] [] + 1: (empty) + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@9..9 + 3: (empty) + 3: R_ANGLE@9..10 ">" [] [] + 1: HTML_ELEMENT_LIST@10..18 + 0: HTML_CONTENT@10..18 + 0: HTML_LITERAL@10..18 "Hover me" [] [] + 2: HTML_CLOSING_ELEMENT@18..24 + 0: L_ANGLE@18..19 "<" [] [] + 1: SLASH@19..20 "/" [] [] + 2: HTML_TAG_NAME@20..23 + 0: HTML_LITERAL@20..23 "div" [] [] + 3: R_ANGLE@23..24 ">" [] [] + 4: EOF@24..25 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +use_missing_name.svelte:1:10 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + > 1 │
    Hover me
    + │ ^^^^^^^^^^^^^^^ + > 2 │ + │ + + i Expected one of: + + - name + - closing block + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_basic.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_basic.svelte new file mode 100644 index 000000000000..c6c32f9028eb --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_basic.svelte @@ -0,0 +1,3 @@ +{#each list as item (item)} +
  • {item}
  • +{/each} diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_basic.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_basic.svelte.snap new file mode 100644 index 000000000000..a3a3c2b6aabd --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_basic.svelte.snap @@ -0,0 +1,159 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +{#each list as item (item)} +
  • {item}
  • +{/each} + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + SvelteEachBlock { + opening_block: SvelteEachOpeningBlock { + sv_curly_hash_token: SV_CURLY_HASH@0..2 "{#" [] [], + each_token: EACH_KW@2..6 "each" [] [], + list: HtmlTextExpression { + html_literal_token: HTML_LITERAL@6..12 " list " [] [], + }, + item: SvelteEachAsKeyedItem { + as_token: AS_KW@12..15 "as" [] [Whitespace(" ")], + name: SvelteName { + ident_token: IDENT@15..20 "item" [] [Whitespace(" ")], + }, + index: missing (optional), + key: SvelteEachKey { + l_paren_token: L_PAREN@20..21 "(" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@21..25 "item" [] [], + }, + r_paren_token: R_PAREN@25..26 ")" [] [], + }, + }, + r_curly_token: R_CURLY@26..27 "}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteAnimateDirective { + animate_token: ANIMATE_KW@34..41 "animate" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@41..42 ":" [] [], + property: SvelteName { + ident_token: IDENT@42..46 "flip" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@46..47 ">" [] [], + }, + children: HtmlElementList [ + HtmlSingleTextExpression { + l_curly_token: L_CURLY@47..48 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@48..52 "item" [] [], + }, + r_curly_token: R_CURLY@52..53 "}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@53..54 "<" [] [], + slash_token: SLASH@54..55 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@55..57 "li" [] [], + }, + r_angle_token: R_ANGLE@57..58 ">" [] [], + }, + }, + ], + else_clause: missing (optional), + closing_block: SvelteEachClosingBlock { + sv_curly_slash_token: SV_CURLY_SLASH@58..61 "{/" [Newline("\n")] [], + each_token: EACH_KW@61..65 "each" [] [], + r_curly_token: R_CURLY@65..66 "}" [] [], + }, + }, + ], + eof_token: EOF@66..67 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..67 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..66 + 0: SVELTE_EACH_BLOCK@0..66 + 0: SVELTE_EACH_OPENING_BLOCK@0..27 + 0: SV_CURLY_HASH@0..2 "{#" [] [] + 1: EACH_KW@2..6 "each" [] [] + 2: HTML_TEXT_EXPRESSION@6..12 + 0: HTML_LITERAL@6..12 " list " [] [] + 3: SVELTE_EACH_AS_KEYED_ITEM@12..26 + 0: AS_KW@12..15 "as" [] [Whitespace(" ")] + 1: SVELTE_NAME@15..20 + 0: IDENT@15..20 "item" [] [Whitespace(" ")] + 2: (empty) + 3: SVELTE_EACH_KEY@20..26 + 0: L_PAREN@20..21 "(" [] [] + 1: HTML_TEXT_EXPRESSION@21..25 + 0: HTML_LITERAL@21..25 "item" [] [] + 2: R_PAREN@25..26 ")" [] [] + 4: R_CURLY@26..27 "}" [] [] + 1: HTML_ELEMENT_LIST@27..58 + 0: HTML_ELEMENT@27..58 + 0: HTML_OPENING_ELEMENT@27..47 + 0: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@31..34 + 0: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@34..46 + 0: SVELTE_ANIMATE_DIRECTIVE@34..46 + 0: ANIMATE_KW@34..41 "animate" [] [] + 1: SVELTE_DIRECTIVE_VALUE@41..46 + 0: COLON@41..42 ":" [] [] + 1: SVELTE_NAME@42..46 + 0: IDENT@42..46 "flip" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@46..46 + 3: (empty) + 3: R_ANGLE@46..47 ">" [] [] + 1: HTML_ELEMENT_LIST@47..53 + 0: HTML_SINGLE_TEXT_EXPRESSION@47..53 + 0: L_CURLY@47..48 "{" [] [] + 1: HTML_TEXT_EXPRESSION@48..52 + 0: HTML_LITERAL@48..52 "item" [] [] + 2: R_CURLY@52..53 "}" [] [] + 2: HTML_CLOSING_ELEMENT@53..58 + 0: L_ANGLE@53..54 "<" [] [] + 1: SLASH@54..55 "/" [] [] + 2: HTML_TAG_NAME@55..57 + 0: HTML_LITERAL@55..57 "li" [] [] + 3: R_ANGLE@57..58 ">" [] [] + 2: (empty) + 3: SVELTE_EACH_CLOSING_BLOCK@58..66 + 0: SV_CURLY_SLASH@58..61 "{/" [Newline("\n")] [] + 1: EACH_KW@61..65 "each" [] [] + 2: R_CURLY@65..66 "}" [] [] + 4: EOF@66..67 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_custom.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_custom.svelte new file mode 100644 index 000000000000..4df1829fdfbf --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_custom.svelte @@ -0,0 +1,3 @@ +{#each list as item (item)} +
  • {item}
  • +{/each} diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_custom.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_custom.svelte.snap new file mode 100644 index 000000000000..9dfc1755c81d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_custom.svelte.snap @@ -0,0 +1,174 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +{#each list as item (item)} +
  • {item}
  • +{/each} + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + SvelteEachBlock { + opening_block: SvelteEachOpeningBlock { + sv_curly_hash_token: SV_CURLY_HASH@0..2 "{#" [] [], + each_token: EACH_KW@2..6 "each" [] [], + list: HtmlTextExpression { + html_literal_token: HTML_LITERAL@6..12 " list " [] [], + }, + item: SvelteEachAsKeyedItem { + as_token: AS_KW@12..15 "as" [] [Whitespace(" ")], + name: SvelteName { + ident_token: IDENT@15..20 "item" [] [Whitespace(" ")], + }, + index: missing (optional), + key: SvelteEachKey { + l_paren_token: L_PAREN@20..21 "(" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@21..25 "item" [] [], + }, + r_paren_token: R_PAREN@25..26 ")" [] [], + }, + }, + r_curly_token: R_CURLY@26..27 "}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteAnimateDirective { + animate_token: ANIMATE_KW@34..41 "animate" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@41..42 ":" [] [], + property: SvelteName { + ident_token: IDENT@42..47 "whizz" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@47..48 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@48..49 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@49..66 "{ duration: 400 }" [] [], + }, + r_curly_token: R_CURLY@66..67 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@67..68 ">" [] [], + }, + children: HtmlElementList [ + HtmlSingleTextExpression { + l_curly_token: L_CURLY@68..69 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@69..73 "item" [] [], + }, + r_curly_token: R_CURLY@73..74 "}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@74..75 "<" [] [], + slash_token: SLASH@75..76 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@76..78 "li" [] [], + }, + r_angle_token: R_ANGLE@78..79 ">" [] [], + }, + }, + ], + else_clause: missing (optional), + closing_block: SvelteEachClosingBlock { + sv_curly_slash_token: SV_CURLY_SLASH@79..82 "{/" [Newline("\n")] [], + each_token: EACH_KW@82..86 "each" [] [], + r_curly_token: R_CURLY@86..87 "}" [] [], + }, + }, + ], + eof_token: EOF@87..88 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..88 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..87 + 0: SVELTE_EACH_BLOCK@0..87 + 0: SVELTE_EACH_OPENING_BLOCK@0..27 + 0: SV_CURLY_HASH@0..2 "{#" [] [] + 1: EACH_KW@2..6 "each" [] [] + 2: HTML_TEXT_EXPRESSION@6..12 + 0: HTML_LITERAL@6..12 " list " [] [] + 3: SVELTE_EACH_AS_KEYED_ITEM@12..26 + 0: AS_KW@12..15 "as" [] [Whitespace(" ")] + 1: SVELTE_NAME@15..20 + 0: IDENT@15..20 "item" [] [Whitespace(" ")] + 2: (empty) + 3: SVELTE_EACH_KEY@20..26 + 0: L_PAREN@20..21 "(" [] [] + 1: HTML_TEXT_EXPRESSION@21..25 + 0: HTML_LITERAL@21..25 "item" [] [] + 2: R_PAREN@25..26 ")" [] [] + 4: R_CURLY@26..27 "}" [] [] + 1: HTML_ELEMENT_LIST@27..79 + 0: HTML_ELEMENT@27..79 + 0: HTML_OPENING_ELEMENT@27..68 + 0: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@31..34 + 0: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@34..67 + 0: SVELTE_ANIMATE_DIRECTIVE@34..67 + 0: ANIMATE_KW@34..41 "animate" [] [] + 1: SVELTE_DIRECTIVE_VALUE@41..67 + 0: COLON@41..42 ":" [] [] + 1: SVELTE_NAME@42..47 + 0: IDENT@42..47 "whizz" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@47..47 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@47..67 + 0: EQ@47..48 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@48..67 + 0: L_CURLY@48..49 "{" [] [] + 1: HTML_TEXT_EXPRESSION@49..66 + 0: HTML_LITERAL@49..66 "{ duration: 400 }" [] [] + 2: R_CURLY@66..67 "}" [] [] + 3: R_ANGLE@67..68 ">" [] [] + 1: HTML_ELEMENT_LIST@68..74 + 0: HTML_SINGLE_TEXT_EXPRESSION@68..74 + 0: L_CURLY@68..69 "{" [] [] + 1: HTML_TEXT_EXPRESSION@69..73 + 0: HTML_LITERAL@69..73 "item" [] [] + 2: R_CURLY@73..74 "}" [] [] + 2: HTML_CLOSING_ELEMENT@74..79 + 0: L_ANGLE@74..75 "<" [] [] + 1: SLASH@75..76 "/" [] [] + 2: HTML_TAG_NAME@76..78 + 0: HTML_LITERAL@76..78 "li" [] [] + 3: R_ANGLE@78..79 ">" [] [] + 2: (empty) + 3: SVELTE_EACH_CLOSING_BLOCK@79..87 + 0: SV_CURLY_SLASH@79..82 "{/" [Newline("\n")] [] + 1: EACH_KW@82..86 "each" [] [] + 2: R_CURLY@86..87 "}" [] [] + 4: EOF@87..88 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_in_each.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_in_each.svelte new file mode 100644 index 000000000000..fddb2fd6527f --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_in_each.svelte @@ -0,0 +1,6 @@ +{#each todos.filter(t => !t.done) as todo (todo.id)} +
    + + {todo.text} +
    +{/each} diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_in_each.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_in_each.svelte.snap new file mode 100644 index 000000000000..8b7394dcc61a --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_in_each.svelte.snap @@ -0,0 +1,246 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +{#each todos.filter(t => !t.done) as todo (todo.id)} +
    + + {todo.text} +
    +{/each} + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + SvelteEachBlock { + opening_block: SvelteEachOpeningBlock { + sv_curly_hash_token: SV_CURLY_HASH@0..2 "{#" [] [], + each_token: EACH_KW@2..6 "each" [] [], + list: HtmlTextExpression { + html_literal_token: HTML_LITERAL@6..34 " todos.filter(t => !t.done) " [] [], + }, + item: SvelteEachAsKeyedItem { + as_token: AS_KW@34..37 "as" [] [Whitespace(" ")], + name: SvelteName { + ident_token: IDENT@37..42 "todo" [] [Whitespace(" ")], + }, + index: missing (optional), + key: SvelteEachKey { + l_paren_token: L_PAREN@42..43 "(" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@43..50 "todo.id" [] [], + }, + r_paren_token: R_PAREN@50..51 ")" [] [], + }, + }, + r_curly_token: R_CURLY@51..52 "}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@52..56 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@56..60 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteAnimateDirective { + animate_token: ANIMATE_KW@60..67 "animate" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@67..68 ":" [] [], + property: SvelteName { + ident_token: IDENT@68..72 "flip" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@72..73 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@73..74 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@74..91 "{ duration: 200 }" [] [], + }, + r_curly_token: R_CURLY@91..92 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@92..93 ">" [] [], + }, + children: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@93..99 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@99..105 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@105..109 "type" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@109..110 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@110..121 "\"checkbox\"" [] [Whitespace(" ")], + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@121..125 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@125..126 ":" [] [], + property: SvelteName { + ident_token: IDENT@126..133 "checked" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@133..134 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@134..135 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@135..144 "todo.done" [] [], + }, + r_curly_token: R_CURLY@144..146 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@146..147 "/" [] [], + r_angle_token: R_ANGLE@147..148 ">" [] [], + }, + HtmlSingleTextExpression { + l_curly_token: L_CURLY@148..154 "{" [Newline("\n"), Whitespace(" ")] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@154..163 "todo.text" [] [], + }, + r_curly_token: R_CURLY@163..164 "}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@164..168 "<" [Newline("\n"), Whitespace(" ")] [], + slash_token: SLASH@168..169 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@169..172 "div" [] [], + }, + r_angle_token: R_ANGLE@172..173 ">" [] [], + }, + }, + ], + else_clause: missing (optional), + closing_block: SvelteEachClosingBlock { + sv_curly_slash_token: SV_CURLY_SLASH@173..176 "{/" [Newline("\n")] [], + each_token: EACH_KW@176..180 "each" [] [], + r_curly_token: R_CURLY@180..181 "}" [] [], + }, + }, + ], + eof_token: EOF@181..182 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..182 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..181 + 0: SVELTE_EACH_BLOCK@0..181 + 0: SVELTE_EACH_OPENING_BLOCK@0..52 + 0: SV_CURLY_HASH@0..2 "{#" [] [] + 1: EACH_KW@2..6 "each" [] [] + 2: HTML_TEXT_EXPRESSION@6..34 + 0: HTML_LITERAL@6..34 " todos.filter(t => !t.done) " [] [] + 3: SVELTE_EACH_AS_KEYED_ITEM@34..51 + 0: AS_KW@34..37 "as" [] [Whitespace(" ")] + 1: SVELTE_NAME@37..42 + 0: IDENT@37..42 "todo" [] [Whitespace(" ")] + 2: (empty) + 3: SVELTE_EACH_KEY@42..51 + 0: L_PAREN@42..43 "(" [] [] + 1: HTML_TEXT_EXPRESSION@43..50 + 0: HTML_LITERAL@43..50 "todo.id" [] [] + 2: R_PAREN@50..51 ")" [] [] + 4: R_CURLY@51..52 "}" [] [] + 1: HTML_ELEMENT_LIST@52..173 + 0: HTML_ELEMENT@52..173 + 0: HTML_OPENING_ELEMENT@52..93 + 0: L_ANGLE@52..56 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@56..60 + 0: HTML_LITERAL@56..60 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@60..92 + 0: SVELTE_ANIMATE_DIRECTIVE@60..92 + 0: ANIMATE_KW@60..67 "animate" [] [] + 1: SVELTE_DIRECTIVE_VALUE@67..92 + 0: COLON@67..68 ":" [] [] + 1: SVELTE_NAME@68..72 + 0: IDENT@68..72 "flip" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@72..72 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@72..92 + 0: EQ@72..73 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@73..92 + 0: L_CURLY@73..74 "{" [] [] + 1: HTML_TEXT_EXPRESSION@74..91 + 0: HTML_LITERAL@74..91 "{ duration: 200 }" [] [] + 2: R_CURLY@91..92 "}" [] [] + 3: R_ANGLE@92..93 ">" [] [] + 1: HTML_ELEMENT_LIST@93..164 + 0: HTML_SELF_CLOSING_ELEMENT@93..148 + 0: L_ANGLE@93..99 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@99..105 + 0: HTML_LITERAL@99..105 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@105..146 + 0: HTML_ATTRIBUTE@105..121 + 0: HTML_ATTRIBUTE_NAME@105..109 + 0: HTML_LITERAL@105..109 "type" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@109..121 + 0: EQ@109..110 "=" [] [] + 1: HTML_STRING@110..121 + 0: HTML_STRING_LITERAL@110..121 "\"checkbox\"" [] [Whitespace(" ")] + 1: SVELTE_BIND_DIRECTIVE@121..146 + 0: BIND_KW@121..125 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@125..146 + 0: COLON@125..126 ":" [] [] + 1: SVELTE_NAME@126..133 + 0: IDENT@126..133 "checked" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@133..133 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@133..146 + 0: EQ@133..134 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@134..146 + 0: L_CURLY@134..135 "{" [] [] + 1: HTML_TEXT_EXPRESSION@135..144 + 0: HTML_LITERAL@135..144 "todo.done" [] [] + 2: R_CURLY@144..146 "}" [] [Whitespace(" ")] + 3: SLASH@146..147 "/" [] [] + 4: R_ANGLE@147..148 ">" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@148..164 + 0: L_CURLY@148..154 "{" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TEXT_EXPRESSION@154..163 + 0: HTML_LITERAL@154..163 "todo.text" [] [] + 2: R_CURLY@163..164 "}" [] [] + 2: HTML_CLOSING_ELEMENT@164..173 + 0: L_ANGLE@164..168 "<" [Newline("\n"), Whitespace(" ")] [] + 1: SLASH@168..169 "/" [] [] + 2: HTML_TAG_NAME@169..172 + 0: HTML_LITERAL@169..172 "div" [] [] + 3: R_ANGLE@172..173 ">" [] [] + 2: (empty) + 3: SVELTE_EACH_CLOSING_BLOCK@173..181 + 0: SV_CURLY_SLASH@173..176 "{/" [Newline("\n")] [] + 1: EACH_KW@176..180 "each" [] [] + 2: R_CURLY@180..181 "}" [] [] + 4: EOF@181..182 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_with_params.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_with_params.svelte new file mode 100644 index 000000000000..109d8c10cc56 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_with_params.svelte @@ -0,0 +1,6 @@ +{#each list as item (item)} +
  • {item}
  • +{/each} +{#each items as item (item.id)} +
    {item.name}
    +{/each} diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_with_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_with_params.svelte.snap new file mode 100644 index 000000000000..795ad032102c --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/animate_with_params.svelte.snap @@ -0,0 +1,313 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +{#each list as item (item)} +
  • {item}
  • +{/each} +{#each items as item (item.id)} +
    {item.name}
    +{/each} + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + SvelteEachBlock { + opening_block: SvelteEachOpeningBlock { + sv_curly_hash_token: SV_CURLY_HASH@0..2 "{#" [] [], + each_token: EACH_KW@2..6 "each" [] [], + list: HtmlTextExpression { + html_literal_token: HTML_LITERAL@6..12 " list " [] [], + }, + item: SvelteEachAsKeyedItem { + as_token: AS_KW@12..15 "as" [] [Whitespace(" ")], + name: SvelteName { + ident_token: IDENT@15..20 "item" [] [Whitespace(" ")], + }, + index: missing (optional), + key: SvelteEachKey { + l_paren_token: L_PAREN@20..21 "(" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@21..25 "item" [] [], + }, + r_paren_token: R_PAREN@25..26 ")" [] [], + }, + }, + r_curly_token: R_CURLY@26..27 "}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteAnimateDirective { + animate_token: ANIMATE_KW@34..41 "animate" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@41..42 ":" [] [], + property: SvelteName { + ident_token: IDENT@42..46 "flip" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@46..47 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@47..48 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@48..62 "{ delay: 500 }" [] [], + }, + r_curly_token: R_CURLY@62..63 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@63..64 ">" [] [], + }, + children: HtmlElementList [ + HtmlSingleTextExpression { + l_curly_token: L_CURLY@64..65 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@65..69 "item" [] [], + }, + r_curly_token: R_CURLY@69..70 "}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@70..71 "<" [] [], + slash_token: SLASH@71..72 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@72..74 "li" [] [], + }, + r_angle_token: R_ANGLE@74..75 ">" [] [], + }, + }, + ], + else_clause: missing (optional), + closing_block: SvelteEachClosingBlock { + sv_curly_slash_token: SV_CURLY_SLASH@75..78 "{/" [Newline("\n")] [], + each_token: EACH_KW@78..82 "each" [] [], + r_curly_token: R_CURLY@82..83 "}" [] [], + }, + }, + SvelteEachBlock { + opening_block: SvelteEachOpeningBlock { + sv_curly_hash_token: SV_CURLY_HASH@83..86 "{#" [Newline("\n")] [], + each_token: EACH_KW@86..90 "each" [] [], + list: HtmlTextExpression { + html_literal_token: HTML_LITERAL@90..97 " items " [] [], + }, + item: SvelteEachAsKeyedItem { + as_token: AS_KW@97..100 "as" [] [Whitespace(" ")], + name: SvelteName { + ident_token: IDENT@100..105 "item" [] [Whitespace(" ")], + }, + index: missing (optional), + key: SvelteEachKey { + l_paren_token: L_PAREN@105..106 "(" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@106..113 "item.id" [] [], + }, + r_paren_token: R_PAREN@113..114 ")" [] [], + }, + }, + r_curly_token: R_CURLY@114..115 "}" [] [], + }, + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@115..119 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@119..123 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteAnimateDirective { + animate_token: ANIMATE_KW@123..130 "animate" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@130..131 ":" [] [], + property: SvelteName { + ident_token: IDENT@131..135 "flip" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@135..136 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@136..137 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@137..172 "{ duration: 300, easing: cubicOut }" [] [], + }, + r_curly_token: R_CURLY@172..173 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@173..174 ">" [] [], + }, + children: HtmlElementList [ + HtmlSingleTextExpression { + l_curly_token: L_CURLY@174..175 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@175..184 "item.name" [] [], + }, + r_curly_token: R_CURLY@184..185 "}" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@185..186 "<" [] [], + slash_token: SLASH@186..187 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@187..190 "div" [] [], + }, + r_angle_token: R_ANGLE@190..191 ">" [] [], + }, + }, + ], + else_clause: missing (optional), + closing_block: SvelteEachClosingBlock { + sv_curly_slash_token: SV_CURLY_SLASH@191..194 "{/" [Newline("\n")] [], + each_token: EACH_KW@194..198 "each" [] [], + r_curly_token: R_CURLY@198..199 "}" [] [], + }, + }, + ], + eof_token: EOF@199..200 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..200 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..199 + 0: SVELTE_EACH_BLOCK@0..83 + 0: SVELTE_EACH_OPENING_BLOCK@0..27 + 0: SV_CURLY_HASH@0..2 "{#" [] [] + 1: EACH_KW@2..6 "each" [] [] + 2: HTML_TEXT_EXPRESSION@6..12 + 0: HTML_LITERAL@6..12 " list " [] [] + 3: SVELTE_EACH_AS_KEYED_ITEM@12..26 + 0: AS_KW@12..15 "as" [] [Whitespace(" ")] + 1: SVELTE_NAME@15..20 + 0: IDENT@15..20 "item" [] [Whitespace(" ")] + 2: (empty) + 3: SVELTE_EACH_KEY@20..26 + 0: L_PAREN@20..21 "(" [] [] + 1: HTML_TEXT_EXPRESSION@21..25 + 0: HTML_LITERAL@21..25 "item" [] [] + 2: R_PAREN@25..26 ")" [] [] + 4: R_CURLY@26..27 "}" [] [] + 1: HTML_ELEMENT_LIST@27..75 + 0: HTML_ELEMENT@27..75 + 0: HTML_OPENING_ELEMENT@27..64 + 0: L_ANGLE@27..31 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@31..34 + 0: HTML_LITERAL@31..34 "li" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@34..63 + 0: SVELTE_ANIMATE_DIRECTIVE@34..63 + 0: ANIMATE_KW@34..41 "animate" [] [] + 1: SVELTE_DIRECTIVE_VALUE@41..63 + 0: COLON@41..42 ":" [] [] + 1: SVELTE_NAME@42..46 + 0: IDENT@42..46 "flip" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@46..46 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@46..63 + 0: EQ@46..47 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@47..63 + 0: L_CURLY@47..48 "{" [] [] + 1: HTML_TEXT_EXPRESSION@48..62 + 0: HTML_LITERAL@48..62 "{ delay: 500 }" [] [] + 2: R_CURLY@62..63 "}" [] [] + 3: R_ANGLE@63..64 ">" [] [] + 1: HTML_ELEMENT_LIST@64..70 + 0: HTML_SINGLE_TEXT_EXPRESSION@64..70 + 0: L_CURLY@64..65 "{" [] [] + 1: HTML_TEXT_EXPRESSION@65..69 + 0: HTML_LITERAL@65..69 "item" [] [] + 2: R_CURLY@69..70 "}" [] [] + 2: HTML_CLOSING_ELEMENT@70..75 + 0: L_ANGLE@70..71 "<" [] [] + 1: SLASH@71..72 "/" [] [] + 2: HTML_TAG_NAME@72..74 + 0: HTML_LITERAL@72..74 "li" [] [] + 3: R_ANGLE@74..75 ">" [] [] + 2: (empty) + 3: SVELTE_EACH_CLOSING_BLOCK@75..83 + 0: SV_CURLY_SLASH@75..78 "{/" [Newline("\n")] [] + 1: EACH_KW@78..82 "each" [] [] + 2: R_CURLY@82..83 "}" [] [] + 1: SVELTE_EACH_BLOCK@83..199 + 0: SVELTE_EACH_OPENING_BLOCK@83..115 + 0: SV_CURLY_HASH@83..86 "{#" [Newline("\n")] [] + 1: EACH_KW@86..90 "each" [] [] + 2: HTML_TEXT_EXPRESSION@90..97 + 0: HTML_LITERAL@90..97 " items " [] [] + 3: SVELTE_EACH_AS_KEYED_ITEM@97..114 + 0: AS_KW@97..100 "as" [] [Whitespace(" ")] + 1: SVELTE_NAME@100..105 + 0: IDENT@100..105 "item" [] [Whitespace(" ")] + 2: (empty) + 3: SVELTE_EACH_KEY@105..114 + 0: L_PAREN@105..106 "(" [] [] + 1: HTML_TEXT_EXPRESSION@106..113 + 0: HTML_LITERAL@106..113 "item.id" [] [] + 2: R_PAREN@113..114 ")" [] [] + 4: R_CURLY@114..115 "}" [] [] + 1: HTML_ELEMENT_LIST@115..191 + 0: HTML_ELEMENT@115..191 + 0: HTML_OPENING_ELEMENT@115..174 + 0: L_ANGLE@115..119 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@119..123 + 0: HTML_LITERAL@119..123 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@123..173 + 0: SVELTE_ANIMATE_DIRECTIVE@123..173 + 0: ANIMATE_KW@123..130 "animate" [] [] + 1: SVELTE_DIRECTIVE_VALUE@130..173 + 0: COLON@130..131 ":" [] [] + 1: SVELTE_NAME@131..135 + 0: IDENT@131..135 "flip" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@135..135 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@135..173 + 0: EQ@135..136 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@136..173 + 0: L_CURLY@136..137 "{" [] [] + 1: HTML_TEXT_EXPRESSION@137..172 + 0: HTML_LITERAL@137..172 "{ duration: 300, easing: cubicOut }" [] [] + 2: R_CURLY@172..173 "}" [] [] + 3: R_ANGLE@173..174 ">" [] [] + 1: HTML_ELEMENT_LIST@174..185 + 0: HTML_SINGLE_TEXT_EXPRESSION@174..185 + 0: L_CURLY@174..175 "{" [] [] + 1: HTML_TEXT_EXPRESSION@175..184 + 0: HTML_LITERAL@175..184 "item.name" [] [] + 2: R_CURLY@184..185 "}" [] [] + 2: HTML_CLOSING_ELEMENT@185..191 + 0: L_ANGLE@185..186 "<" [] [] + 1: SLASH@186..187 "/" [] [] + 2: HTML_TAG_NAME@187..190 + 0: HTML_LITERAL@187..190 "div" [] [] + 3: R_ANGLE@190..191 ">" [] [] + 2: (empty) + 3: SVELTE_EACH_CLOSING_BLOCK@191..199 + 0: SV_CURLY_SLASH@191..194 "{/" [Newline("\n")] [] + 1: EACH_KW@194..198 "each" [] [] + 2: R_CURLY@198..199 "}" [] [] + 4: EOF@199..200 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_checked.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_checked.svelte new file mode 100644 index 000000000000..4979cbaf6c4c --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_checked.svelte @@ -0,0 +1,2 @@ + + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_checked.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_checked.svelte.snap new file mode 100644 index 000000000000..e9db0090c144 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_checked.svelte.snap @@ -0,0 +1,175 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@7..11 "type" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@11..12 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@12..23 "\"checkbox\"" [] [Whitespace(" ")], + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@23..27 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@27..28 ":" [] [], + property: SvelteName { + ident_token: IDENT@28..35 "checked" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@35..36 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@36..37 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@37..46 "isChecked" [] [], + }, + r_curly_token: R_CURLY@46..48 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@48..49 "/" [] [], + r_angle_token: R_ANGLE@49..50 ">" [] [], + }, + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@50..52 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@52..58 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@58..62 "type" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@62..63 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@63..74 "\"checkbox\"" [] [Whitespace(" ")], + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@74..78 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@78..79 ":" [] [], + property: SvelteName { + ident_token: IDENT@79..92 "indeterminate" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@92..93 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@93..94 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@94..109 "isIndeterminate" [] [], + }, + r_curly_token: R_CURLY@109..111 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@111..112 "/" [] [], + r_angle_token: R_ANGLE@112..113 ">" [] [], + }, + ], + eof_token: EOF@113..114 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..114 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..113 + 0: HTML_SELF_CLOSING_ELEMENT@0..50 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..48 + 0: HTML_ATTRIBUTE@7..23 + 0: HTML_ATTRIBUTE_NAME@7..11 + 0: HTML_LITERAL@7..11 "type" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@11..23 + 0: EQ@11..12 "=" [] [] + 1: HTML_STRING@12..23 + 0: HTML_STRING_LITERAL@12..23 "\"checkbox\"" [] [Whitespace(" ")] + 1: SVELTE_BIND_DIRECTIVE@23..48 + 0: BIND_KW@23..27 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@27..48 + 0: COLON@27..28 ":" [] [] + 1: SVELTE_NAME@28..35 + 0: IDENT@28..35 "checked" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@35..35 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@35..48 + 0: EQ@35..36 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@36..48 + 0: L_CURLY@36..37 "{" [] [] + 1: HTML_TEXT_EXPRESSION@37..46 + 0: HTML_LITERAL@37..46 "isChecked" [] [] + 2: R_CURLY@46..48 "}" [] [Whitespace(" ")] + 3: SLASH@48..49 "/" [] [] + 4: R_ANGLE@49..50 ">" [] [] + 1: HTML_SELF_CLOSING_ELEMENT@50..113 + 0: L_ANGLE@50..52 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@52..58 + 0: HTML_LITERAL@52..58 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@58..111 + 0: HTML_ATTRIBUTE@58..74 + 0: HTML_ATTRIBUTE_NAME@58..62 + 0: HTML_LITERAL@58..62 "type" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@62..74 + 0: EQ@62..63 "=" [] [] + 1: HTML_STRING@63..74 + 0: HTML_STRING_LITERAL@63..74 "\"checkbox\"" [] [Whitespace(" ")] + 1: SVELTE_BIND_DIRECTIVE@74..111 + 0: BIND_KW@74..78 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@78..111 + 0: COLON@78..79 ":" [] [] + 1: SVELTE_NAME@79..92 + 0: IDENT@79..92 "indeterminate" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@92..92 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@92..111 + 0: EQ@92..93 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@93..111 + 0: L_CURLY@93..94 "{" [] [] + 1: HTML_TEXT_EXPRESSION@94..109 + 0: HTML_LITERAL@94..109 "isIndeterminate" [] [] + 2: R_CURLY@109..111 "}" [] [Whitespace(" ")] + 3: SLASH@111..112 "/" [] [] + 4: R_ANGLE@112..113 ">" [] [] + 4: EOF@113..114 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_files.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_files.svelte new file mode 100644 index 000000000000..cd6563a6442f --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_files.svelte @@ -0,0 +1,2 @@ + + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_files.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_files.svelte.snap new file mode 100644 index 000000000000..8b9ddc0a6f0b --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_files.svelte.snap @@ -0,0 +1,185 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@7..11 "type" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@11..12 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@12..19 "\"file\"" [] [Whitespace(" ")], + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@19..23 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@23..24 ":" [] [], + property: SvelteName { + ident_token: IDENT@24..29 "files" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@29..30 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@30..31 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@31..39 "fileList" [] [], + }, + r_curly_token: R_CURLY@39..41 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@41..42 "/" [] [], + r_angle_token: R_ANGLE@42..43 ">" [] [], + }, + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@43..45 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@45..51 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@51..55 "type" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@55..56 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@56..63 "\"file\"" [] [Whitespace(" ")], + }, + }, + }, + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@63..72 "multiple" [] [Whitespace(" ")], + }, + initializer: missing (optional), + }, + SvelteBindDirective { + bind_token: BIND_KW@72..76 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@76..77 ":" [] [], + property: SvelteName { + ident_token: IDENT@77..82 "files" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@82..83 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@83..84 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@84..89 "files" [] [], + }, + r_curly_token: R_CURLY@89..91 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@91..92 "/" [] [], + 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: HTML_SELF_CLOSING_ELEMENT@0..43 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..41 + 0: HTML_ATTRIBUTE@7..19 + 0: HTML_ATTRIBUTE_NAME@7..11 + 0: HTML_LITERAL@7..11 "type" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@11..19 + 0: EQ@11..12 "=" [] [] + 1: HTML_STRING@12..19 + 0: HTML_STRING_LITERAL@12..19 "\"file\"" [] [Whitespace(" ")] + 1: SVELTE_BIND_DIRECTIVE@19..41 + 0: BIND_KW@19..23 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@23..41 + 0: COLON@23..24 ":" [] [] + 1: SVELTE_NAME@24..29 + 0: IDENT@24..29 "files" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@29..29 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@29..41 + 0: EQ@29..30 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@30..41 + 0: L_CURLY@30..31 "{" [] [] + 1: HTML_TEXT_EXPRESSION@31..39 + 0: HTML_LITERAL@31..39 "fileList" [] [] + 2: R_CURLY@39..41 "}" [] [Whitespace(" ")] + 3: SLASH@41..42 "/" [] [] + 4: R_ANGLE@42..43 ">" [] [] + 1: HTML_SELF_CLOSING_ELEMENT@43..93 + 0: L_ANGLE@43..45 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@45..51 + 0: HTML_LITERAL@45..51 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@51..91 + 0: HTML_ATTRIBUTE@51..63 + 0: HTML_ATTRIBUTE_NAME@51..55 + 0: HTML_LITERAL@51..55 "type" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@55..63 + 0: EQ@55..56 "=" [] [] + 1: HTML_STRING@56..63 + 0: HTML_STRING_LITERAL@56..63 "\"file\"" [] [Whitespace(" ")] + 1: HTML_ATTRIBUTE@63..72 + 0: HTML_ATTRIBUTE_NAME@63..72 + 0: HTML_LITERAL@63..72 "multiple" [] [Whitespace(" ")] + 1: (empty) + 2: SVELTE_BIND_DIRECTIVE@72..91 + 0: BIND_KW@72..76 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@76..91 + 0: COLON@76..77 ":" [] [] + 1: SVELTE_NAME@77..82 + 0: IDENT@77..82 "files" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@82..82 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@82..91 + 0: EQ@82..83 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@83..91 + 0: L_CURLY@83..84 "{" [] [] + 1: HTML_TEXT_EXPRESSION@84..89 + 0: HTML_LITERAL@84..89 "files" [] [] + 2: R_CURLY@89..91 "}" [] [Whitespace(" ")] + 3: SLASH@91..92 "/" [] [] + 4: R_ANGLE@92..93 ">" [] [] + 4: EOF@93..94 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_function.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_function.svelte new file mode 100644 index 000000000000..8baf952ffbd2 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_function.svelte @@ -0,0 +1,2 @@ + + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_function.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_function.svelte.snap new file mode 100644 index 000000000000..951fb5468cac --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_function.svelte.snap @@ -0,0 +1,139 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@7..11 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@11..12 ":" [] [], + property: SvelteName { + ident_token: IDENT@12..17 "value" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@17..18 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@18..19 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@19..27 "get, set" [] [], + }, + r_curly_token: R_CURLY@27..29 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@29..30 "/" [] [], + r_angle_token: R_ANGLE@30..31 ">" [] [], + }, + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@31..33 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@33..39 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@39..43 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@43..44 ":" [] [], + property: SvelteName { + ident_token: IDENT@44..49 "value" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@49..50 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@50..51 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@51..63 "null, setter" [] [], + }, + r_curly_token: R_CURLY@63..65 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@65..66 "/" [] [], + r_angle_token: R_ANGLE@66..67 ">" [] [], + }, + ], + eof_token: EOF@67..68 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..68 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..67 + 0: HTML_SELF_CLOSING_ELEMENT@0..31 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..29 + 0: SVELTE_BIND_DIRECTIVE@7..29 + 0: BIND_KW@7..11 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@11..29 + 0: COLON@11..12 ":" [] [] + 1: SVELTE_NAME@12..17 + 0: IDENT@12..17 "value" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@17..17 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@17..29 + 0: EQ@17..18 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@18..29 + 0: L_CURLY@18..19 "{" [] [] + 1: HTML_TEXT_EXPRESSION@19..27 + 0: HTML_LITERAL@19..27 "get, set" [] [] + 2: R_CURLY@27..29 "}" [] [Whitespace(" ")] + 3: SLASH@29..30 "/" [] [] + 4: R_ANGLE@30..31 ">" [] [] + 1: HTML_SELF_CLOSING_ELEMENT@31..67 + 0: L_ANGLE@31..33 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@33..39 + 0: HTML_LITERAL@33..39 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@39..65 + 0: SVELTE_BIND_DIRECTIVE@39..65 + 0: BIND_KW@39..43 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@43..65 + 0: COLON@43..44 ":" [] [] + 1: SVELTE_NAME@44..49 + 0: IDENT@44..49 "value" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@49..49 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@49..65 + 0: EQ@49..50 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@50..65 + 0: L_CURLY@50..51 "{" [] [] + 1: HTML_TEXT_EXPRESSION@51..63 + 0: HTML_LITERAL@51..63 "null, setter" [] [] + 2: R_CURLY@63..65 "}" [] [Whitespace(" ")] + 3: SLASH@65..66 "/" [] [] + 4: R_ANGLE@66..67 ">" [] [] + 4: EOF@67..68 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_group.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_group.svelte new file mode 100644 index 000000000000..e8f9d63eb96a --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_group.svelte @@ -0,0 +1,3 @@ + + + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_group.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_group.svelte.snap new file mode 100644 index 000000000000..ca3cfaf6d247 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_group.svelte.snap @@ -0,0 +1,299 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@7..11 "type" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@11..12 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@12..20 "\"radio\"" [] [Whitespace(" ")], + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@20..24 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@24..25 ":" [] [], + property: SvelteName { + ident_token: IDENT@25..30 "group" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@30..31 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@31..32 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@32..40 "selected" [] [], + }, + r_curly_token: R_CURLY@40..42 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@42..47 "value" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@47..48 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@48..52 "\"a\"" [] [Whitespace(" ")], + }, + }, + }, + ], + slash_token: SLASH@52..53 "/" [] [], + r_angle_token: R_ANGLE@53..54 ">" [] [], + }, + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@54..56 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@56..62 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@62..66 "type" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@66..67 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@67..75 "\"radio\"" [] [Whitespace(" ")], + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@75..79 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@79..80 ":" [] [], + property: SvelteName { + ident_token: IDENT@80..85 "group" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@85..86 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@86..87 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@87..95 "selected" [] [], + }, + r_curly_token: R_CURLY@95..97 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@97..102 "value" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@102..103 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@103..107 "\"b\"" [] [Whitespace(" ")], + }, + }, + }, + ], + slash_token: SLASH@107..108 "/" [] [], + r_angle_token: R_ANGLE@108..109 ">" [] [], + }, + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@109..111 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@111..117 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@117..121 "type" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@121..122 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@122..133 "\"checkbox\"" [] [Whitespace(" ")], + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@133..137 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@137..138 ":" [] [], + property: SvelteName { + ident_token: IDENT@138..143 "group" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@143..144 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@144..145 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@145..153 "flavours" [] [], + }, + r_curly_token: R_CURLY@153..155 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@155..160 "value" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@160..161 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@161..168 "\"mint\"" [] [Whitespace(" ")], + }, + }, + }, + ], + slash_token: SLASH@168..169 "/" [] [], + r_angle_token: R_ANGLE@169..170 ">" [] [], + }, + ], + eof_token: EOF@170..171 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..171 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..170 + 0: HTML_SELF_CLOSING_ELEMENT@0..54 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..52 + 0: HTML_ATTRIBUTE@7..20 + 0: HTML_ATTRIBUTE_NAME@7..11 + 0: HTML_LITERAL@7..11 "type" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@11..20 + 0: EQ@11..12 "=" [] [] + 1: HTML_STRING@12..20 + 0: HTML_STRING_LITERAL@12..20 "\"radio\"" [] [Whitespace(" ")] + 1: SVELTE_BIND_DIRECTIVE@20..42 + 0: BIND_KW@20..24 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@24..42 + 0: COLON@24..25 ":" [] [] + 1: SVELTE_NAME@25..30 + 0: IDENT@25..30 "group" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@30..30 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@30..42 + 0: EQ@30..31 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@31..42 + 0: L_CURLY@31..32 "{" [] [] + 1: HTML_TEXT_EXPRESSION@32..40 + 0: HTML_LITERAL@32..40 "selected" [] [] + 2: R_CURLY@40..42 "}" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE@42..52 + 0: HTML_ATTRIBUTE_NAME@42..47 + 0: HTML_LITERAL@42..47 "value" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@47..52 + 0: EQ@47..48 "=" [] [] + 1: HTML_STRING@48..52 + 0: HTML_STRING_LITERAL@48..52 "\"a\"" [] [Whitespace(" ")] + 3: SLASH@52..53 "/" [] [] + 4: R_ANGLE@53..54 ">" [] [] + 1: HTML_SELF_CLOSING_ELEMENT@54..109 + 0: L_ANGLE@54..56 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@56..62 + 0: HTML_LITERAL@56..62 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@62..107 + 0: HTML_ATTRIBUTE@62..75 + 0: HTML_ATTRIBUTE_NAME@62..66 + 0: HTML_LITERAL@62..66 "type" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@66..75 + 0: EQ@66..67 "=" [] [] + 1: HTML_STRING@67..75 + 0: HTML_STRING_LITERAL@67..75 "\"radio\"" [] [Whitespace(" ")] + 1: SVELTE_BIND_DIRECTIVE@75..97 + 0: BIND_KW@75..79 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@79..97 + 0: COLON@79..80 ":" [] [] + 1: SVELTE_NAME@80..85 + 0: IDENT@80..85 "group" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@85..85 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@85..97 + 0: EQ@85..86 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@86..97 + 0: L_CURLY@86..87 "{" [] [] + 1: HTML_TEXT_EXPRESSION@87..95 + 0: HTML_LITERAL@87..95 "selected" [] [] + 2: R_CURLY@95..97 "}" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE@97..107 + 0: HTML_ATTRIBUTE_NAME@97..102 + 0: HTML_LITERAL@97..102 "value" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@102..107 + 0: EQ@102..103 "=" [] [] + 1: HTML_STRING@103..107 + 0: HTML_STRING_LITERAL@103..107 "\"b\"" [] [Whitespace(" ")] + 3: SLASH@107..108 "/" [] [] + 4: R_ANGLE@108..109 ">" [] [] + 2: HTML_SELF_CLOSING_ELEMENT@109..170 + 0: L_ANGLE@109..111 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@111..117 + 0: HTML_LITERAL@111..117 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@117..168 + 0: HTML_ATTRIBUTE@117..133 + 0: HTML_ATTRIBUTE_NAME@117..121 + 0: HTML_LITERAL@117..121 "type" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@121..133 + 0: EQ@121..122 "=" [] [] + 1: HTML_STRING@122..133 + 0: HTML_STRING_LITERAL@122..133 "\"checkbox\"" [] [Whitespace(" ")] + 1: SVELTE_BIND_DIRECTIVE@133..155 + 0: BIND_KW@133..137 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@137..155 + 0: COLON@137..138 ":" [] [] + 1: SVELTE_NAME@138..143 + 0: IDENT@138..143 "group" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@143..143 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@143..155 + 0: EQ@143..144 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@144..155 + 0: L_CURLY@144..145 "{" [] [] + 1: HTML_TEXT_EXPRESSION@145..153 + 0: HTML_LITERAL@145..153 "flavours" [] [] + 2: R_CURLY@153..155 "}" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE@155..168 + 0: HTML_ATTRIBUTE_NAME@155..160 + 0: HTML_LITERAL@155..160 "value" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@160..168 + 0: EQ@160..161 "=" [] [] + 1: HTML_STRING@161..168 + 0: HTML_STRING_LITERAL@161..168 "\"mint\"" [] [Whitespace(" ")] + 3: SLASH@168..169 "/" [] [] + 4: R_ANGLE@169..170 ">" [] [] + 4: EOF@170..171 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_missing_colon.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_missing_colon.svelte new file mode 100644 index 000000000000..cc5e066271a5 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_missing_colon.svelte @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_missing_colon.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_missing_colon.svelte.snap new file mode 100644 index 000000000000..4a1e4948df4f --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_missing_colon.svelte.snap @@ -0,0 +1,88 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@7..12 "bind" [] [Whitespace(" ")], + }, + initializer: missing (optional), + }, + HtmlAttribute { + name: HtmlAttributeName { + value_token: HTML_LITERAL@12..17 "value" [] [], + }, + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@17..18 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@18..19 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@19..23 "name" [] [], + }, + r_curly_token: R_CURLY@23..25 "}" [] [Whitespace(" ")], + }, + }, + }, + ], + slash_token: SLASH@25..26 "/" [] [], + r_angle_token: R_ANGLE@26..27 ">" [] [], + }, + ], + eof_token: EOF@27..28 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..28 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..27 + 0: HTML_SELF_CLOSING_ELEMENT@0..27 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..25 + 0: HTML_ATTRIBUTE@7..12 + 0: HTML_ATTRIBUTE_NAME@7..12 + 0: HTML_LITERAL@7..12 "bind" [] [Whitespace(" ")] + 1: (empty) + 1: HTML_ATTRIBUTE@12..25 + 0: HTML_ATTRIBUTE_NAME@12..17 + 0: HTML_LITERAL@12..17 "value" [] [] + 1: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@17..25 + 0: EQ@17..18 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@18..25 + 0: L_CURLY@18..19 "{" [] [] + 1: HTML_TEXT_EXPRESSION@19..23 + 0: HTML_LITERAL@19..23 "name" [] [] + 2: R_CURLY@23..25 "}" [] [Whitespace(" ")] + 3: SLASH@25..26 "/" [] [] + 4: R_ANGLE@26..27 ">" [] [] + 4: EOF@27..28 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_multiple_props.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_multiple_props.svelte new file mode 100644 index 000000000000..89c705d3196c --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_multiple_props.svelte @@ -0,0 +1,2 @@ + + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_multiple_props.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_multiple_props.svelte.snap new file mode 100644 index 000000000000..79b1b31f82ec --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_multiple_props.svelte.snap @@ -0,0 +1,292 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@7..11 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@11..12 ":" [] [], + property: SvelteName { + ident_token: IDENT@12..17 "value" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@17..18 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@18..19 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@19..23 "text" [] [], + }, + r_curly_token: R_CURLY@23..25 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@25..29 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@29..30 ":" [] [], + property: SvelteName { + ident_token: IDENT@30..44 "selectionStart" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@44..45 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@45..46 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@46..51 "start" [] [], + }, + r_curly_token: R_CURLY@51..53 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@53..57 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@57..58 ":" [] [], + property: SvelteName { + ident_token: IDENT@58..70 "selectionEnd" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@70..71 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@71..72 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@72..75 "end" [] [], + }, + r_curly_token: R_CURLY@75..77 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@77..78 "/" [] [], + r_angle_token: R_ANGLE@78..79 ">" [] [], + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@79..81 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@81..87 "video" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@87..91 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@91..92 ":" [] [], + property: SvelteName { + ident_token: IDENT@92..103 "currentTime" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@103..104 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@104..105 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@105..109 "time" [] [], + }, + r_curly_token: R_CURLY@109..111 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@111..115 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@115..116 ":" [] [], + property: SvelteName { + ident_token: IDENT@116..122 "paused" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@122..123 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@123..124 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@124..132 "isPaused" [] [], + }, + r_curly_token: R_CURLY@132..134 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteBindDirective { + bind_token: BIND_KW@134..138 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@138..139 ":" [] [], + property: SvelteName { + ident_token: IDENT@139..145 "volume" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@145..146 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@146..147 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@147..153 "volume" [] [], + }, + r_curly_token: R_CURLY@153..154 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@154..155 ">" [] [], + }, + children: HtmlElementList [], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@155..156 "<" [] [], + slash_token: SLASH@156..157 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@157..162 "video" [] [], + }, + r_angle_token: R_ANGLE@162..163 ">" [] [], + }, + }, + ], + eof_token: EOF@163..164 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..164 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..163 + 0: HTML_SELF_CLOSING_ELEMENT@0..79 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..77 + 0: SVELTE_BIND_DIRECTIVE@7..25 + 0: BIND_KW@7..11 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@11..25 + 0: COLON@11..12 ":" [] [] + 1: SVELTE_NAME@12..17 + 0: IDENT@12..17 "value" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@17..17 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@17..25 + 0: EQ@17..18 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@18..25 + 0: L_CURLY@18..19 "{" [] [] + 1: HTML_TEXT_EXPRESSION@19..23 + 0: HTML_LITERAL@19..23 "text" [] [] + 2: R_CURLY@23..25 "}" [] [Whitespace(" ")] + 1: SVELTE_BIND_DIRECTIVE@25..53 + 0: BIND_KW@25..29 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@29..53 + 0: COLON@29..30 ":" [] [] + 1: SVELTE_NAME@30..44 + 0: IDENT@30..44 "selectionStart" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@44..44 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@44..53 + 0: EQ@44..45 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@45..53 + 0: L_CURLY@45..46 "{" [] [] + 1: HTML_TEXT_EXPRESSION@46..51 + 0: HTML_LITERAL@46..51 "start" [] [] + 2: R_CURLY@51..53 "}" [] [Whitespace(" ")] + 2: SVELTE_BIND_DIRECTIVE@53..77 + 0: BIND_KW@53..57 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@57..77 + 0: COLON@57..58 ":" [] [] + 1: SVELTE_NAME@58..70 + 0: IDENT@58..70 "selectionEnd" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@70..70 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@70..77 + 0: EQ@70..71 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@71..77 + 0: L_CURLY@71..72 "{" [] [] + 1: HTML_TEXT_EXPRESSION@72..75 + 0: HTML_LITERAL@72..75 "end" [] [] + 2: R_CURLY@75..77 "}" [] [Whitespace(" ")] + 3: SLASH@77..78 "/" [] [] + 4: R_ANGLE@78..79 ">" [] [] + 1: HTML_ELEMENT@79..163 + 0: HTML_OPENING_ELEMENT@79..155 + 0: L_ANGLE@79..81 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@81..87 + 0: HTML_LITERAL@81..87 "video" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@87..154 + 0: SVELTE_BIND_DIRECTIVE@87..111 + 0: BIND_KW@87..91 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@91..111 + 0: COLON@91..92 ":" [] [] + 1: SVELTE_NAME@92..103 + 0: IDENT@92..103 "currentTime" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@103..103 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@103..111 + 0: EQ@103..104 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@104..111 + 0: L_CURLY@104..105 "{" [] [] + 1: HTML_TEXT_EXPRESSION@105..109 + 0: HTML_LITERAL@105..109 "time" [] [] + 2: R_CURLY@109..111 "}" [] [Whitespace(" ")] + 1: SVELTE_BIND_DIRECTIVE@111..134 + 0: BIND_KW@111..115 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@115..134 + 0: COLON@115..116 ":" [] [] + 1: SVELTE_NAME@116..122 + 0: IDENT@116..122 "paused" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@122..122 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@122..134 + 0: EQ@122..123 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@123..134 + 0: L_CURLY@123..124 "{" [] [] + 1: HTML_TEXT_EXPRESSION@124..132 + 0: HTML_LITERAL@124..132 "isPaused" [] [] + 2: R_CURLY@132..134 "}" [] [Whitespace(" ")] + 2: SVELTE_BIND_DIRECTIVE@134..154 + 0: BIND_KW@134..138 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@138..154 + 0: COLON@138..139 ":" [] [] + 1: SVELTE_NAME@139..145 + 0: IDENT@139..145 "volume" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@145..145 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@145..154 + 0: EQ@145..146 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@146..154 + 0: L_CURLY@146..147 "{" [] [] + 1: HTML_TEXT_EXPRESSION@147..153 + 0: HTML_LITERAL@147..153 "volume" [] [] + 2: R_CURLY@153..154 "}" [] [] + 3: R_ANGLE@154..155 ">" [] [] + 1: HTML_ELEMENT_LIST@155..155 + 2: HTML_CLOSING_ELEMENT@155..163 + 0: L_ANGLE@155..156 "<" [] [] + 1: SLASH@156..157 "/" [] [] + 2: HTML_TAG_NAME@157..162 + 0: HTML_LITERAL@157..162 "video" [] [] + 3: R_ANGLE@162..163 ">" [] [] + 4: EOF@163..164 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_shorthand.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_shorthand.svelte new file mode 100644 index 000000000000..3bc42f797c5e --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_shorthand.svelte @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_shorthand.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_shorthand.svelte.snap new file mode 100644 index 000000000000..f7dab9cf68dc --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_shorthand.svelte.snap @@ -0,0 +1,72 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@7..11 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@11..12 ":" [] [], + property: SvelteName { + ident_token: IDENT@12..18 "value" [] [Whitespace(" ")], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + slash_token: SLASH@18..19 "/" [] [], + r_angle_token: R_ANGLE@19..20 ">" [] [], + }, + ], + eof_token: EOF@20..21 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..21 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..20 + 0: HTML_SELF_CLOSING_ELEMENT@0..20 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..18 + 0: SVELTE_BIND_DIRECTIVE@7..18 + 0: BIND_KW@7..11 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@11..18 + 0: COLON@11..12 ":" [] [] + 1: SVELTE_NAME@12..18 + 0: IDENT@12..18 "value" [] [Whitespace(" ")] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@18..18 + 3: (empty) + 3: SLASH@18..19 "/" [] [] + 4: R_ANGLE@19..20 ">" [] [] + 4: EOF@20..21 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_this.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_this.svelte new file mode 100644 index 000000000000..04af913ba221 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_this.svelte @@ -0,0 +1,2 @@ +
    content
    + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_this.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_this.svelte.snap new file mode 100644 index 000000000000..6bf7c300824c --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_this.svelte.snap @@ -0,0 +1,179 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@5..9 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@9..10 ":" [] [], + property: SvelteName { + ident_token: IDENT@10..14 "this" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@14..15 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@15..16 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@16..20 "node" [] [], + }, + r_curly_token: R_CURLY@20..21 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@21..22 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@22..29 "content" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@29..30 "<" [] [], + slash_token: SLASH@30..31 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@31..34 "div" [] [], + }, + r_angle_token: R_ANGLE@34..35 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@35..37 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@37..44 "canvas" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@44..48 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@48..49 ":" [] [], + property: SvelteName { + ident_token: IDENT@49..53 "this" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@53..54 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@54..55 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@55..61 "canvas" [] [], + }, + r_curly_token: R_CURLY@61..62 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@62..63 ">" [] [], + }, + children: HtmlElementList [], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@63..64 "<" [] [], + slash_token: SLASH@64..65 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@65..71 "canvas" [] [], + }, + r_angle_token: R_ANGLE@71..72 ">" [] [], + }, + }, + ], + eof_token: EOF@72..73 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..73 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..72 + 0: HTML_ELEMENT@0..35 + 0: HTML_OPENING_ELEMENT@0..22 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..21 + 0: SVELTE_BIND_DIRECTIVE@5..21 + 0: BIND_KW@5..9 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@9..21 + 0: COLON@9..10 ":" [] [] + 1: SVELTE_NAME@10..14 + 0: IDENT@10..14 "this" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@14..14 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@14..21 + 0: EQ@14..15 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@15..21 + 0: L_CURLY@15..16 "{" [] [] + 1: HTML_TEXT_EXPRESSION@16..20 + 0: HTML_LITERAL@16..20 "node" [] [] + 2: R_CURLY@20..21 "}" [] [] + 3: R_ANGLE@21..22 ">" [] [] + 1: HTML_ELEMENT_LIST@22..29 + 0: HTML_CONTENT@22..29 + 0: HTML_LITERAL@22..29 "content" [] [] + 2: HTML_CLOSING_ELEMENT@29..35 + 0: L_ANGLE@29..30 "<" [] [] + 1: SLASH@30..31 "/" [] [] + 2: HTML_TAG_NAME@31..34 + 0: HTML_LITERAL@31..34 "div" [] [] + 3: R_ANGLE@34..35 ">" [] [] + 1: HTML_ELEMENT@35..72 + 0: HTML_OPENING_ELEMENT@35..63 + 0: L_ANGLE@35..37 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@37..44 + 0: HTML_LITERAL@37..44 "canvas" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@44..62 + 0: SVELTE_BIND_DIRECTIVE@44..62 + 0: BIND_KW@44..48 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@48..62 + 0: COLON@48..49 ":" [] [] + 1: SVELTE_NAME@49..53 + 0: IDENT@49..53 "this" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@53..53 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@53..62 + 0: EQ@53..54 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@54..62 + 0: L_CURLY@54..55 "{" [] [] + 1: HTML_TEXT_EXPRESSION@55..61 + 0: HTML_LITERAL@55..61 "canvas" [] [] + 2: R_CURLY@61..62 "}" [] [] + 3: R_ANGLE@62..63 ">" [] [] + 1: HTML_ELEMENT_LIST@63..63 + 2: HTML_CLOSING_ELEMENT@63..72 + 0: L_ANGLE@63..64 "<" [] [] + 1: SLASH@64..65 "/" [] [] + 2: HTML_TAG_NAME@65..71 + 0: HTML_LITERAL@65..71 "canvas" [] [] + 3: R_ANGLE@71..72 ">" [] [] + 4: EOF@72..73 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_value_basic.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_value_basic.svelte new file mode 100644 index 000000000000..3b7e08921efe --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_value_basic.svelte @@ -0,0 +1 @@ + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_value_basic.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_value_basic.svelte.snap new file mode 100644 index 000000000000..b03987535090 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/bind_value_basic.svelte.snap @@ -0,0 +1,87 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte + + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + HtmlSelfClosingElement { + l_angle_token: L_ANGLE@0..1 "<" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteBindDirective { + bind_token: BIND_KW@7..11 "bind" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@11..12 ":" [] [], + property: SvelteName { + ident_token: IDENT@12..17 "value" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@17..18 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@18..19 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@19..23 "name" [] [], + }, + r_curly_token: R_CURLY@23..25 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + ], + slash_token: SLASH@25..26 "/" [] [], + r_angle_token: R_ANGLE@26..27 ">" [] [], + }, + ], + eof_token: EOF@27..28 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..28 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..27 + 0: HTML_SELF_CLOSING_ELEMENT@0..27 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..7 + 0: HTML_LITERAL@1..7 "input" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@7..25 + 0: SVELTE_BIND_DIRECTIVE@7..25 + 0: BIND_KW@7..11 "bind" [] [] + 1: SVELTE_DIRECTIVE_VALUE@11..25 + 0: COLON@11..12 ":" [] [] + 1: SVELTE_NAME@12..17 + 0: IDENT@12..17 "value" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@17..17 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@17..25 + 0: EQ@17..18 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@18..25 + 0: L_CURLY@18..19 "{" [] [] + 1: HTML_TEXT_EXPRESSION@19..23 + 0: HTML_LITERAL@19..23 "name" [] [] + 2: R_CURLY@23..25 "}" [] [Whitespace(" ")] + 3: SLASH@25..26 "/" [] [] + 4: R_ANGLE@26..27 ">" [] [] + 4: EOF@27..28 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_basic.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_basic.svelte new file mode 100644 index 000000000000..0a7f5e5a0a62 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_basic.svelte @@ -0,0 +1,2 @@ +
    Toggle active
    + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_basic.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_basic.svelte.snap new file mode 100644 index 000000000000..fcd1da3dcdf0 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_basic.svelte.snap @@ -0,0 +1,185 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Toggle active
    + + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteClassDirective { + class_token: CLASS_KW@5..10 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..17 "active" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@17..18 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@18..19 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@19..27 "isActive" [] [], + }, + r_curly_token: R_CURLY@27..28 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@28..29 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@29..42 "Toggle active" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@42..43 "<" [] [], + slash_token: SLASH@43..44 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@44..47 "div" [] [], + }, + r_angle_token: R_ANGLE@47..48 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@48..50 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@50..57 "button" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteClassDirective { + class_token: CLASS_KW@57..62 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@62..63 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@63..71 "disabled" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@71..72 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@72..73 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@73..83 "!canSubmit" [] [], + }, + r_curly_token: R_CURLY@83..84 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@84..85 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@85..91 "Submit" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@91..92 "<" [] [], + slash_token: SLASH@92..93 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@93..99 "button" [] [], + }, + r_angle_token: R_ANGLE@99..100 ">" [] [], + }, + }, + ], + eof_token: EOF@100..101 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..101 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..100 + 0: HTML_ELEMENT@0..48 + 0: HTML_OPENING_ELEMENT@0..29 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..28 + 0: SVELTE_CLASS_DIRECTIVE@5..28 + 0: CLASS_KW@5..10 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..28 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..17 + 0: HTML_LITERAL@11..17 "active" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@17..17 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@17..28 + 0: EQ@17..18 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@18..28 + 0: L_CURLY@18..19 "{" [] [] + 1: HTML_TEXT_EXPRESSION@19..27 + 0: HTML_LITERAL@19..27 "isActive" [] [] + 2: R_CURLY@27..28 "}" [] [] + 3: R_ANGLE@28..29 ">" [] [] + 1: HTML_ELEMENT_LIST@29..42 + 0: HTML_CONTENT@29..42 + 0: HTML_LITERAL@29..42 "Toggle active" [] [] + 2: HTML_CLOSING_ELEMENT@42..48 + 0: L_ANGLE@42..43 "<" [] [] + 1: SLASH@43..44 "/" [] [] + 2: HTML_TAG_NAME@44..47 + 0: HTML_LITERAL@44..47 "div" [] [] + 3: R_ANGLE@47..48 ">" [] [] + 1: HTML_ELEMENT@48..100 + 0: HTML_OPENING_ELEMENT@48..85 + 0: L_ANGLE@48..50 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@50..57 + 0: HTML_LITERAL@50..57 "button" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@57..84 + 0: SVELTE_CLASS_DIRECTIVE@57..84 + 0: CLASS_KW@57..62 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@62..84 + 0: COLON@62..63 ":" [] [] + 1: SVELTE_LITERAL@63..71 + 0: HTML_LITERAL@63..71 "disabled" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@71..71 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@71..84 + 0: EQ@71..72 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@72..84 + 0: L_CURLY@72..73 "{" [] [] + 1: HTML_TEXT_EXPRESSION@73..83 + 0: HTML_LITERAL@73..83 "!canSubmit" [] [] + 2: R_CURLY@83..84 "}" [] [] + 3: R_ANGLE@84..85 ">" [] [] + 1: HTML_ELEMENT_LIST@85..91 + 0: HTML_CONTENT@85..91 + 0: HTML_LITERAL@85..91 "Submit" [] [] + 2: HTML_CLOSING_ELEMENT@91..100 + 0: L_ANGLE@91..92 "<" [] [] + 1: SLASH@92..93 "/" [] [] + 2: HTML_TAG_NAME@93..99 + 0: HTML_LITERAL@93..99 "button" [] [] + 3: R_ANGLE@99..100 ">" [] [] + 4: EOF@100..101 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_kebab_case.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_kebab_case.svelte new file mode 100644 index 000000000000..2e9c3f63a160 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_kebab_case.svelte @@ -0,0 +1,2 @@ +
    Kebab case
    +
    Multiple kebab
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_kebab_case.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_kebab_case.svelte.snap new file mode 100644 index 000000000000..8b8497f086a8 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_kebab_case.svelte.snap @@ -0,0 +1,219 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Kebab case
    +
    Multiple kebab
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteClassDirective { + class_token: CLASS_KW@5..10 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..20 "is-active" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@20..21 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@21..22 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@22..28 "active" [] [], + }, + r_curly_token: R_CURLY@28..29 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@29..30 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@30..40 "Kebab case" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@40..41 "<" [] [], + slash_token: SLASH@41..42 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@42..45 "div" [] [], + }, + r_angle_token: R_ANGLE@45..46 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@46..48 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@48..52 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteClassDirective { + class_token: CLASS_KW@52..57 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@57..58 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@58..67 "has-error" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@67..68 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@68..69 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@69..74 "error" [] [], + }, + r_curly_token: R_CURLY@74..76 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteClassDirective { + class_token: CLASS_KW@76..81 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@81..82 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@82..92 "is-loading" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@92..93 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@93..94 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@94..101 "loading" [] [], + }, + r_curly_token: R_CURLY@101..102 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@102..103 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@103..117 "Multiple kebab" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@117..118 "<" [] [], + slash_token: SLASH@118..119 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@119..122 "div" [] [], + }, + r_angle_token: R_ANGLE@122..123 ">" [] [], + }, + }, + ], + eof_token: EOF@123..124 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..124 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..123 + 0: HTML_ELEMENT@0..46 + 0: HTML_OPENING_ELEMENT@0..30 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..29 + 0: SVELTE_CLASS_DIRECTIVE@5..29 + 0: CLASS_KW@5..10 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..29 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..20 + 0: HTML_LITERAL@11..20 "is-active" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@20..20 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@20..29 + 0: EQ@20..21 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@21..29 + 0: L_CURLY@21..22 "{" [] [] + 1: HTML_TEXT_EXPRESSION@22..28 + 0: HTML_LITERAL@22..28 "active" [] [] + 2: R_CURLY@28..29 "}" [] [] + 3: R_ANGLE@29..30 ">" [] [] + 1: HTML_ELEMENT_LIST@30..40 + 0: HTML_CONTENT@30..40 + 0: HTML_LITERAL@30..40 "Kebab case" [] [] + 2: HTML_CLOSING_ELEMENT@40..46 + 0: L_ANGLE@40..41 "<" [] [] + 1: SLASH@41..42 "/" [] [] + 2: HTML_TAG_NAME@42..45 + 0: HTML_LITERAL@42..45 "div" [] [] + 3: R_ANGLE@45..46 ">" [] [] + 1: HTML_ELEMENT@46..123 + 0: HTML_OPENING_ELEMENT@46..103 + 0: L_ANGLE@46..48 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@48..52 + 0: HTML_LITERAL@48..52 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@52..102 + 0: SVELTE_CLASS_DIRECTIVE@52..76 + 0: CLASS_KW@52..57 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@57..76 + 0: COLON@57..58 ":" [] [] + 1: SVELTE_LITERAL@58..67 + 0: HTML_LITERAL@58..67 "has-error" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@67..67 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@67..76 + 0: EQ@67..68 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@68..76 + 0: L_CURLY@68..69 "{" [] [] + 1: HTML_TEXT_EXPRESSION@69..74 + 0: HTML_LITERAL@69..74 "error" [] [] + 2: R_CURLY@74..76 "}" [] [Whitespace(" ")] + 1: SVELTE_CLASS_DIRECTIVE@76..102 + 0: CLASS_KW@76..81 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@81..102 + 0: COLON@81..82 ":" [] [] + 1: SVELTE_LITERAL@82..92 + 0: HTML_LITERAL@82..92 "is-loading" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@92..92 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@92..102 + 0: EQ@92..93 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@93..102 + 0: L_CURLY@93..94 "{" [] [] + 1: HTML_TEXT_EXPRESSION@94..101 + 0: HTML_LITERAL@94..101 "loading" [] [] + 2: R_CURLY@101..102 "}" [] [] + 3: R_ANGLE@102..103 ">" [] [] + 1: HTML_ELEMENT_LIST@103..117 + 0: HTML_CONTENT@103..117 + 0: HTML_LITERAL@103..117 "Multiple kebab" [] [] + 2: HTML_CLOSING_ELEMENT@117..123 + 0: L_ANGLE@117..118 "<" [] [] + 1: SLASH@118..119 "/" [] [] + 2: HTML_TAG_NAME@119..122 + 0: HTML_LITERAL@119..122 "div" [] [] + 3: R_ANGLE@122..123 ">" [] [] + 4: EOF@123..124 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_multiple.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_multiple.svelte new file mode 100644 index 000000000000..64e887309012 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_multiple.svelte @@ -0,0 +1,3 @@ +
    + Multiple classes +
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_multiple.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_multiple.svelte.snap new file mode 100644 index 000000000000..fb67344e9696 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_multiple.svelte.snap @@ -0,0 +1,165 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    + Multiple classes +
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteClassDirective { + class_token: CLASS_KW@5..10 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..15 "foo" [] [Whitespace(" ")], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + SvelteClassDirective { + class_token: CLASS_KW@15..20 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@20..21 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@21..24 "bar" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@24..25 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@25..26 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@26..31 "isBaz" [] [], + }, + r_curly_token: R_CURLY@31..33 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteClassDirective { + class_token: CLASS_KW@33..38 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@38..39 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@39..42 "baz" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@42..43 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@43..44 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@44..49 "isBaz" [] [], + }, + r_curly_token: R_CURLY@49..50 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@50..51 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@51..70 "Multiple classes" [Newline("\n"), Whitespace(" ")] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@70..72 "<" [Newline("\n")] [], + slash_token: SLASH@72..73 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@73..76 "div" [] [], + }, + r_angle_token: R_ANGLE@76..77 ">" [] [], + }, + }, + ], + eof_token: EOF@77..78 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..78 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..77 + 0: HTML_ELEMENT@0..77 + 0: HTML_OPENING_ELEMENT@0..51 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..50 + 0: SVELTE_CLASS_DIRECTIVE@5..15 + 0: CLASS_KW@5..10 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..15 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..15 + 0: HTML_LITERAL@11..15 "foo" [] [Whitespace(" ")] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@15..15 + 3: (empty) + 1: SVELTE_CLASS_DIRECTIVE@15..33 + 0: CLASS_KW@15..20 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@20..33 + 0: COLON@20..21 ":" [] [] + 1: SVELTE_LITERAL@21..24 + 0: HTML_LITERAL@21..24 "bar" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@24..24 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@24..33 + 0: EQ@24..25 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@25..33 + 0: L_CURLY@25..26 "{" [] [] + 1: HTML_TEXT_EXPRESSION@26..31 + 0: HTML_LITERAL@26..31 "isBaz" [] [] + 2: R_CURLY@31..33 "}" [] [Whitespace(" ")] + 2: SVELTE_CLASS_DIRECTIVE@33..50 + 0: CLASS_KW@33..38 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@38..50 + 0: COLON@38..39 ":" [] [] + 1: SVELTE_LITERAL@39..42 + 0: HTML_LITERAL@39..42 "baz" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@42..42 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@42..50 + 0: EQ@42..43 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@43..50 + 0: L_CURLY@43..44 "{" [] [] + 1: HTML_TEXT_EXPRESSION@44..49 + 0: HTML_LITERAL@44..49 "isBaz" [] [] + 2: R_CURLY@49..50 "}" [] [] + 3: R_ANGLE@50..51 ">" [] [] + 1: HTML_ELEMENT_LIST@51..70 + 0: HTML_CONTENT@51..70 + 0: HTML_LITERAL@51..70 "Multiple classes" [Newline("\n"), Whitespace(" ")] [] + 2: HTML_CLOSING_ELEMENT@70..77 + 0: L_ANGLE@70..72 "<" [Newline("\n")] [] + 1: SLASH@72..73 "/" [] [] + 2: HTML_TAG_NAME@73..76 + 0: HTML_LITERAL@73..76 "div" [] [] + 3: R_ANGLE@76..77 ">" [] [] + 4: EOF@77..78 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_shorthand.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_shorthand.svelte new file mode 100644 index 000000000000..fda548427958 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_shorthand.svelte @@ -0,0 +1,2 @@ +
    Shorthand
    +
    Multiple shorthand
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_shorthand.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_shorthand.svelte.snap new file mode 100644 index 000000000000..6c0f1ddac3f7 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_shorthand.svelte.snap @@ -0,0 +1,189 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Shorthand
    +
    Multiple shorthand
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteClassDirective { + class_token: CLASS_KW@5..10 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..17 "active" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@17..18 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@18..27 "Shorthand" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@27..28 "<" [] [], + slash_token: SLASH@28..29 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@29..32 "div" [] [], + }, + r_angle_token: R_ANGLE@32..33 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@33..35 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@35..39 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteClassDirective { + class_token: CLASS_KW@39..44 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@44..45 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@45..50 "cool" [] [Whitespace(" ")], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + SvelteClassDirective { + class_token: CLASS_KW@50..55 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@55..56 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@56..60 "lame" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@60..61 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@61..62 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@62..67 "!cool" [] [], + }, + r_curly_token: R_CURLY@67..68 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@68..69 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@69..87 "Multiple shorthand" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@87..88 "<" [] [], + 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: HTML_ELEMENT@0..33 + 0: HTML_OPENING_ELEMENT@0..18 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..17 + 0: SVELTE_CLASS_DIRECTIVE@5..17 + 0: CLASS_KW@5..10 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..17 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..17 + 0: HTML_LITERAL@11..17 "active" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@17..17 + 3: (empty) + 3: R_ANGLE@17..18 ">" [] [] + 1: HTML_ELEMENT_LIST@18..27 + 0: HTML_CONTENT@18..27 + 0: HTML_LITERAL@18..27 "Shorthand" [] [] + 2: HTML_CLOSING_ELEMENT@27..33 + 0: L_ANGLE@27..28 "<" [] [] + 1: SLASH@28..29 "/" [] [] + 2: HTML_TAG_NAME@29..32 + 0: HTML_LITERAL@29..32 "div" [] [] + 3: R_ANGLE@32..33 ">" [] [] + 1: HTML_ELEMENT@33..93 + 0: HTML_OPENING_ELEMENT@33..69 + 0: L_ANGLE@33..35 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@35..39 + 0: HTML_LITERAL@35..39 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@39..68 + 0: SVELTE_CLASS_DIRECTIVE@39..50 + 0: CLASS_KW@39..44 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@44..50 + 0: COLON@44..45 ":" [] [] + 1: SVELTE_LITERAL@45..50 + 0: HTML_LITERAL@45..50 "cool" [] [Whitespace(" ")] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@50..50 + 3: (empty) + 1: SVELTE_CLASS_DIRECTIVE@50..68 + 0: CLASS_KW@50..55 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@55..68 + 0: COLON@55..56 ":" [] [] + 1: SVELTE_LITERAL@56..60 + 0: HTML_LITERAL@56..60 "lame" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@60..60 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@60..68 + 0: EQ@60..61 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@61..68 + 0: L_CURLY@61..62 "{" [] [] + 1: HTML_TEXT_EXPRESSION@62..67 + 0: HTML_LITERAL@62..67 "!cool" [] [] + 2: R_CURLY@67..68 "}" [] [] + 3: R_ANGLE@68..69 ">" [] [] + 1: HTML_ELEMENT_LIST@69..87 + 0: HTML_CONTENT@69..87 + 0: HTML_LITERAL@69..87 "Multiple shorthand" [] [] + 2: HTML_CLOSING_ELEMENT@87..93 + 0: L_ANGLE@87..88 "<" [] [] + 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/html_specs/ok/svelte/directives/class_with_expression.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_with_expression.svelte new file mode 100644 index 000000000000..31ae5207229d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_with_expression.svelte @@ -0,0 +1,2 @@ +
    Item
    + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_with_expression.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_with_expression.svelte.snap new file mode 100644 index 000000000000..a28db9c20011 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/class_with_expression.svelte.snap @@ -0,0 +1,185 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Item
    + + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteClassDirective { + class_token: CLASS_KW@5..10 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..19 "selected" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@19..20 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@20..21 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@21..43 "item.id === selectedId" [] [], + }, + r_curly_token: R_CURLY@43..44 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@44..45 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@45..49 "Item" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@49..50 "<" [] [], + slash_token: SLASH@50..51 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@51..54 "div" [] [], + }, + r_angle_token: R_ANGLE@54..55 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@55..57 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@57..64 "button" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteClassDirective { + class_token: CLASS_KW@64..69 "class" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@69..70 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@70..77 "primary" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@77..78 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@78..79 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@79..97 "type === 'primary'" [] [], + }, + r_curly_token: R_CURLY@97..98 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@98..99 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@99..105 "Button" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@105..106 "<" [] [], + slash_token: SLASH@106..107 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@107..113 "button" [] [], + }, + r_angle_token: R_ANGLE@113..114 ">" [] [], + }, + }, + ], + eof_token: EOF@114..115 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..115 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..114 + 0: HTML_ELEMENT@0..55 + 0: HTML_OPENING_ELEMENT@0..45 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..44 + 0: SVELTE_CLASS_DIRECTIVE@5..44 + 0: CLASS_KW@5..10 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..44 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..19 + 0: HTML_LITERAL@11..19 "selected" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@19..19 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@19..44 + 0: EQ@19..20 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@20..44 + 0: L_CURLY@20..21 "{" [] [] + 1: HTML_TEXT_EXPRESSION@21..43 + 0: HTML_LITERAL@21..43 "item.id === selectedId" [] [] + 2: R_CURLY@43..44 "}" [] [] + 3: R_ANGLE@44..45 ">" [] [] + 1: HTML_ELEMENT_LIST@45..49 + 0: HTML_CONTENT@45..49 + 0: HTML_LITERAL@45..49 "Item" [] [] + 2: HTML_CLOSING_ELEMENT@49..55 + 0: L_ANGLE@49..50 "<" [] [] + 1: SLASH@50..51 "/" [] [] + 2: HTML_TAG_NAME@51..54 + 0: HTML_LITERAL@51..54 "div" [] [] + 3: R_ANGLE@54..55 ">" [] [] + 1: HTML_ELEMENT@55..114 + 0: HTML_OPENING_ELEMENT@55..99 + 0: L_ANGLE@55..57 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@57..64 + 0: HTML_LITERAL@57..64 "button" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@64..98 + 0: SVELTE_CLASS_DIRECTIVE@64..98 + 0: CLASS_KW@64..69 "class" [] [] + 1: SVELTE_DIRECTIVE_VALUE@69..98 + 0: COLON@69..70 ":" [] [] + 1: SVELTE_LITERAL@70..77 + 0: HTML_LITERAL@70..77 "primary" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@77..77 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@77..98 + 0: EQ@77..78 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@78..98 + 0: L_CURLY@78..79 "{" [] [] + 1: HTML_TEXT_EXPRESSION@79..97 + 0: HTML_LITERAL@79..97 "type === 'primary'" [] [] + 2: R_CURLY@97..98 "}" [] [] + 3: R_ANGLE@98..99 ">" [] [] + 1: HTML_ELEMENT_LIST@99..105 + 0: HTML_CONTENT@99..105 + 0: HTML_LITERAL@99..105 "Button" [] [] + 2: HTML_CLOSING_ELEMENT@105..114 + 0: L_ANGLE@105..106 "<" [] [] + 1: SLASH@106..107 "/" [] [] + 2: HTML_TAG_NAME@107..113 + 0: HTML_LITERAL@107..113 "button" [] [] + 3: R_ANGLE@113..114 ">" [] [] + 4: EOF@114..115 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_basic.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_basic.svelte new file mode 100644 index 000000000000..338a1a5e1259 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_basic.svelte @@ -0,0 +1 @@ +
    Flies in
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_basic.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_basic.svelte.snap new file mode 100644 index 000000000000..87e2e14dee6b --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_basic.svelte.snap @@ -0,0 +1,95 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Flies in
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@5..7 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@7..8 ":" [] [], + property: SvelteName { + ident_token: IDENT@8..11 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@11..12 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@12..20 "Flies in" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@20..21 "<" [] [], + slash_token: SLASH@21..22 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@22..25 "div" [] [], + }, + r_angle_token: R_ANGLE@25..26 ">" [] [], + }, + }, + ], + eof_token: EOF@26..27 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..27 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..26 + 0: HTML_ELEMENT@0..26 + 0: HTML_OPENING_ELEMENT@0..12 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..11 + 0: SVELTE_IN_DIRECTIVE@5..11 + 0: IN_KW@5..7 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@7..11 + 0: COLON@7..8 ":" [] [] + 1: SVELTE_NAME@8..11 + 0: IDENT@8..11 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@11..11 + 3: (empty) + 3: R_ANGLE@11..12 ">" [] [] + 1: HTML_ELEMENT_LIST@12..20 + 0: HTML_CONTENT@12..20 + 0: HTML_LITERAL@12..20 "Flies in" [] [] + 2: HTML_CLOSING_ELEMENT@20..26 + 0: L_ANGLE@20..21 "<" [] [] + 1: SLASH@21..22 "/" [] [] + 2: HTML_TAG_NAME@22..25 + 0: HTML_LITERAL@22..25 "div" [] [] + 3: R_ANGLE@25..26 ">" [] [] + 4: EOF@26..27 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_global_modifier.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_global_modifier.svelte new file mode 100644 index 000000000000..249689e8fef7 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_global_modifier.svelte @@ -0,0 +1 @@ +
    Global in transition
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_global_modifier.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_global_modifier.svelte.snap new file mode 100644 index 000000000000..9c40fe9df642 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_global_modifier.svelte.snap @@ -0,0 +1,106 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Global in transition
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@5..7 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@7..8 ":" [] [], + property: SvelteName { + ident_token: IDENT@8..11 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@11..12 "|" [] [], + name: SvelteName { + ident_token: IDENT@12..18 "global" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@18..19 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@19..39 "Global in transition" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@39..40 "<" [] [], + slash_token: SLASH@40..41 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@41..44 "div" [] [], + }, + r_angle_token: R_ANGLE@44..45 ">" [] [], + }, + }, + ], + eof_token: EOF@45..46 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..46 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..45 + 0: HTML_ELEMENT@0..45 + 0: HTML_OPENING_ELEMENT@0..19 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..18 + 0: SVELTE_IN_DIRECTIVE@5..18 + 0: IN_KW@5..7 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@7..18 + 0: COLON@7..8 ":" [] [] + 1: SVELTE_NAME@8..11 + 0: IDENT@8..11 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@11..18 + 0: SVELTE_DIRECTIVE_MODIFIER@11..18 + 0: PIPE@11..12 "|" [] [] + 1: SVELTE_NAME@12..18 + 0: IDENT@12..18 "global" [] [] + 3: (empty) + 3: R_ANGLE@18..19 ">" [] [] + 1: HTML_ELEMENT_LIST@19..39 + 0: HTML_CONTENT@19..39 + 0: HTML_LITERAL@19..39 "Global in transition" [] [] + 2: HTML_CLOSING_ELEMENT@39..45 + 0: L_ANGLE@39..40 "<" [] [] + 1: SLASH@40..41 "/" [] [] + 2: HTML_TAG_NAME@41..44 + 0: HTML_LITERAL@41..44 "div" [] [] + 3: R_ANGLE@44..45 ">" [] [] + 4: EOF@45..46 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_local_modifier.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_local_modifier.svelte new file mode 100644 index 000000000000..75f1d5d32f76 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_local_modifier.svelte @@ -0,0 +1 @@ +
    Local in transition
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_local_modifier.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_local_modifier.svelte.snap new file mode 100644 index 000000000000..743bcadbe01d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_local_modifier.svelte.snap @@ -0,0 +1,106 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Local in transition
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@5..7 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@7..8 ":" [] [], + property: SvelteName { + ident_token: IDENT@8..11 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@11..12 "|" [] [], + name: SvelteName { + ident_token: IDENT@12..17 "local" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@17..18 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@18..37 "Local in transition" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@37..38 "<" [] [], + slash_token: SLASH@38..39 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@39..42 "div" [] [], + }, + r_angle_token: R_ANGLE@42..43 ">" [] [], + }, + }, + ], + eof_token: EOF@43..44 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..44 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..43 + 0: HTML_ELEMENT@0..43 + 0: HTML_OPENING_ELEMENT@0..18 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..17 + 0: SVELTE_IN_DIRECTIVE@5..17 + 0: IN_KW@5..7 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@7..17 + 0: COLON@7..8 ":" [] [] + 1: SVELTE_NAME@8..11 + 0: IDENT@8..11 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@11..17 + 0: SVELTE_DIRECTIVE_MODIFIER@11..17 + 0: PIPE@11..12 "|" [] [] + 1: SVELTE_NAME@12..17 + 0: IDENT@12..17 "local" [] [] + 3: (empty) + 3: R_ANGLE@17..18 ">" [] [] + 1: HTML_ELEMENT_LIST@18..37 + 0: HTML_CONTENT@18..37 + 0: HTML_LITERAL@18..37 "Local in transition" [] [] + 2: HTML_CLOSING_ELEMENT@37..43 + 0: L_ANGLE@37..38 "<" [] [] + 1: SLASH@38..39 "/" [] [] + 2: HTML_TAG_NAME@39..42 + 0: HTML_LITERAL@39..42 "div" [] [] + 3: R_ANGLE@42..43 ">" [] [] + 4: EOF@43..44 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_modifier_with_params.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_modifier_with_params.svelte new file mode 100644 index 000000000000..26ed25c5a658 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_modifier_with_params.svelte @@ -0,0 +1 @@ +
    Global with params
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_modifier_with_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_modifier_with_params.svelte.snap new file mode 100644 index 000000000000..2d7149ef2fe7 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_modifier_with_params.svelte.snap @@ -0,0 +1,121 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Global with params
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@5..7 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@7..8 ":" [] [], + property: SvelteName { + ident_token: IDENT@8..11 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@11..12 "|" [] [], + name: SvelteName { + ident_token: IDENT@12..18 "global" [] [], + }, + }, + ], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@18..19 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@19..20 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@20..30 "{ y: 200 }" [] [], + }, + r_curly_token: R_CURLY@30..31 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@31..32 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@32..50 "Global with params" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@50..51 "<" [] [], + slash_token: SLASH@51..52 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@52..55 "div" [] [], + }, + r_angle_token: R_ANGLE@55..56 ">" [] [], + }, + }, + ], + eof_token: EOF@56..57 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..57 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..56 + 0: HTML_ELEMENT@0..56 + 0: HTML_OPENING_ELEMENT@0..32 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..31 + 0: SVELTE_IN_DIRECTIVE@5..31 + 0: IN_KW@5..7 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@7..31 + 0: COLON@7..8 ":" [] [] + 1: SVELTE_NAME@8..11 + 0: IDENT@8..11 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@11..18 + 0: SVELTE_DIRECTIVE_MODIFIER@11..18 + 0: PIPE@11..12 "|" [] [] + 1: SVELTE_NAME@12..18 + 0: IDENT@12..18 "global" [] [] + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@18..31 + 0: EQ@18..19 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@19..31 + 0: L_CURLY@19..20 "{" [] [] + 1: HTML_TEXT_EXPRESSION@20..30 + 0: HTML_LITERAL@20..30 "{ y: 200 }" [] [] + 2: R_CURLY@30..31 "}" [] [] + 3: R_ANGLE@31..32 ">" [] [] + 1: HTML_ELEMENT_LIST@32..50 + 0: HTML_CONTENT@32..50 + 0: HTML_LITERAL@32..50 "Global with params" [] [] + 2: HTML_CLOSING_ELEMENT@50..56 + 0: L_ANGLE@50..51 "<" [] [] + 1: SLASH@51..52 "/" [] [] + 2: HTML_TAG_NAME@52..55 + 0: HTML_LITERAL@52..55 "div" [] [] + 3: R_ANGLE@55..56 ">" [] [] + 4: EOF@56..57 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_multiple_modifiers.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_multiple_modifiers.svelte new file mode 100644 index 000000000000..821a261e7a55 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_multiple_modifiers.svelte @@ -0,0 +1 @@ +
    Multiple modifiers
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_multiple_modifiers.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_multiple_modifiers.svelte.snap new file mode 100644 index 000000000000..a54337a7873a --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_multiple_modifiers.svelte.snap @@ -0,0 +1,116 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Multiple modifiers
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@5..7 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@7..8 ":" [] [], + property: SvelteName { + ident_token: IDENT@8..11 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@11..12 "|" [] [], + name: SvelteName { + ident_token: IDENT@12..18 "global" [] [], + }, + }, + SvelteDirectiveModifier { + bitwise_or_token: PIPE@18..19 "|" [] [], + name: SvelteName { + ident_token: IDENT@19..24 "local" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@24..25 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@25..43 "Multiple modifiers" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@43..44 "<" [] [], + slash_token: SLASH@44..45 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@45..48 "div" [] [], + }, + r_angle_token: R_ANGLE@48..49 ">" [] [], + }, + }, + ], + eof_token: EOF@49..50 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..50 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..49 + 0: HTML_ELEMENT@0..49 + 0: HTML_OPENING_ELEMENT@0..25 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..24 + 0: SVELTE_IN_DIRECTIVE@5..24 + 0: IN_KW@5..7 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@7..24 + 0: COLON@7..8 ":" [] [] + 1: SVELTE_NAME@8..11 + 0: IDENT@8..11 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@11..24 + 0: SVELTE_DIRECTIVE_MODIFIER@11..18 + 0: PIPE@11..12 "|" [] [] + 1: SVELTE_NAME@12..18 + 0: IDENT@12..18 "global" [] [] + 1: SVELTE_DIRECTIVE_MODIFIER@18..24 + 0: PIPE@18..19 "|" [] [] + 1: SVELTE_NAME@19..24 + 0: IDENT@19..24 "local" [] [] + 3: (empty) + 3: R_ANGLE@24..25 ">" [] [] + 1: HTML_ELEMENT_LIST@25..43 + 0: HTML_CONTENT@25..43 + 0: HTML_LITERAL@25..43 "Multiple modifiers" [] [] + 2: HTML_CLOSING_ELEMENT@43..49 + 0: L_ANGLE@43..44 "<" [] [] + 1: SLASH@44..45 "/" [] [] + 2: HTML_TAG_NAME@45..48 + 0: HTML_LITERAL@45..48 "div" [] [] + 3: R_ANGLE@48..49 ">" [] [] + 4: EOF@49..50 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_with_params.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_with_params.svelte new file mode 100644 index 000000000000..ccc1b34dbc7f --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_with_params.svelte @@ -0,0 +1,2 @@ +
    Flies from below
    +

    Slow fade in

    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_with_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_with_params.svelte.snap new file mode 100644 index 000000000000..d43c5741b0da --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/in_with_params.svelte.snap @@ -0,0 +1,185 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Flies from below
    +

    Slow fade in

    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@5..7 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@7..8 ":" [] [], + property: SvelteName { + ident_token: IDENT@8..11 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@11..12 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@12..13 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@13..23 "{ y: 200 }" [] [], + }, + r_curly_token: R_CURLY@23..24 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@24..25 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@25..41 "Flies from below" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@41..42 "<" [] [], + slash_token: SLASH@42..43 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@43..46 "div" [] [], + }, + r_angle_token: R_ANGLE@46..47 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@47..49 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@49..51 "p" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@51..53 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@53..54 ":" [] [], + property: SvelteName { + ident_token: IDENT@54..58 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@58..59 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@59..60 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@60..77 "{ duration: 500 }" [] [], + }, + r_curly_token: R_CURLY@77..78 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@78..79 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@79..91 "Slow fade in" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@91..92 "<" [] [], + slash_token: SLASH@92..93 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@93..94 "p" [] [], + }, + r_angle_token: R_ANGLE@94..95 ">" [] [], + }, + }, + ], + eof_token: EOF@95..96 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..96 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..95 + 0: HTML_ELEMENT@0..47 + 0: HTML_OPENING_ELEMENT@0..25 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..24 + 0: SVELTE_IN_DIRECTIVE@5..24 + 0: IN_KW@5..7 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@7..24 + 0: COLON@7..8 ":" [] [] + 1: SVELTE_NAME@8..11 + 0: IDENT@8..11 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@11..11 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@11..24 + 0: EQ@11..12 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@12..24 + 0: L_CURLY@12..13 "{" [] [] + 1: HTML_TEXT_EXPRESSION@13..23 + 0: HTML_LITERAL@13..23 "{ y: 200 }" [] [] + 2: R_CURLY@23..24 "}" [] [] + 3: R_ANGLE@24..25 ">" [] [] + 1: HTML_ELEMENT_LIST@25..41 + 0: HTML_CONTENT@25..41 + 0: HTML_LITERAL@25..41 "Flies from below" [] [] + 2: HTML_CLOSING_ELEMENT@41..47 + 0: L_ANGLE@41..42 "<" [] [] + 1: SLASH@42..43 "/" [] [] + 2: HTML_TAG_NAME@43..46 + 0: HTML_LITERAL@43..46 "div" [] [] + 3: R_ANGLE@46..47 ">" [] [] + 1: HTML_ELEMENT@47..95 + 0: HTML_OPENING_ELEMENT@47..79 + 0: L_ANGLE@47..49 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@49..51 + 0: HTML_LITERAL@49..51 "p" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@51..78 + 0: SVELTE_IN_DIRECTIVE@51..78 + 0: IN_KW@51..53 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@53..78 + 0: COLON@53..54 ":" [] [] + 1: SVELTE_NAME@54..58 + 0: IDENT@54..58 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@58..58 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@58..78 + 0: EQ@58..59 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@59..78 + 0: L_CURLY@59..60 "{" [] [] + 1: HTML_TEXT_EXPRESSION@60..77 + 0: HTML_LITERAL@60..77 "{ duration: 500 }" [] [] + 2: R_CURLY@77..78 "}" [] [] + 3: R_ANGLE@78..79 ">" [] [] + 1: HTML_ELEMENT_LIST@79..91 + 0: HTML_CONTENT@79..91 + 0: HTML_LITERAL@79..91 "Slow fade in" [] [] + 2: HTML_CLOSING_ELEMENT@91..95 + 0: L_ANGLE@91..92 "<" [] [] + 1: SLASH@92..93 "/" [] [] + 2: HTML_TAG_NAME@93..94 + 0: HTML_LITERAL@93..94 "p" [] [] + 3: R_ANGLE@94..95 ">" [] [] + 4: EOF@95..96 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_basic.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_basic.svelte new file mode 100644 index 000000000000..85bb8326b436 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_basic.svelte @@ -0,0 +1 @@ +
    Fades out
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_basic.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_basic.svelte.snap new file mode 100644 index 000000000000..0b666b6f44bc --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_basic.svelte.snap @@ -0,0 +1,95 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Fades out
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteOutDirective { + out_token: OUT_KW@5..8 "out" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: SvelteName { + ident_token: IDENT@9..13 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@13..14 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@14..23 "Fades out" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@23..24 "<" [] [], + slash_token: SLASH@24..25 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@25..28 "div" [] [], + }, + r_angle_token: R_ANGLE@28..29 ">" [] [], + }, + }, + ], + eof_token: EOF@29..30 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..30 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..29 + 0: HTML_ELEMENT@0..29 + 0: HTML_OPENING_ELEMENT@0..14 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..13 + 0: SVELTE_OUT_DIRECTIVE@5..13 + 0: OUT_KW@5..8 "out" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..13 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..13 + 0: IDENT@9..13 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@13..13 + 3: (empty) + 3: R_ANGLE@13..14 ">" [] [] + 1: HTML_ELEMENT_LIST@14..23 + 0: HTML_CONTENT@14..23 + 0: HTML_LITERAL@14..23 "Fades out" [] [] + 2: HTML_CLOSING_ELEMENT@23..29 + 0: L_ANGLE@23..24 "<" [] [] + 1: SLASH@24..25 "/" [] [] + 2: HTML_TAG_NAME@25..28 + 0: HTML_LITERAL@25..28 "div" [] [] + 3: R_ANGLE@28..29 ">" [] [] + 4: EOF@29..30 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_combined_with_in.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_combined_with_in.svelte new file mode 100644 index 000000000000..34c9f36edb68 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_combined_with_in.svelte @@ -0,0 +1,8 @@ +{#if visible} +
    + flies in, fades out +
    +
    + With modifiers +
    +{/if} diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_combined_with_in.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_combined_with_in.svelte.snap new file mode 100644 index 000000000000..faa7911e6a89 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_combined_with_in.svelte.snap @@ -0,0 +1,299 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +{#if visible} +
    + flies in, fades out +
    +
    + With modifiers +
    +{/if} + +``` + + +## AST + +``` +HtmlRoot { + bom_token: missing (optional), + frontmatter: missing (optional), + directive: missing (optional), + html: HtmlElementList [ + SvelteIfBlock { + opening_block: SvelteIfOpeningBlock { + sv_curly_hash_token: SV_CURLY_HASH@0..2 "{#" [] [], + if_token: IF_KW@2..4 "if" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@4..12 " visible" [] [], + }, + r_curly_token: R_CURLY@12..13 "}" [] [], + children: HtmlElementList [ + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@13..17 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@17..21 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@21..23 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@23..24 ":" [] [], + property: SvelteName { + ident_token: IDENT@24..27 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@27..28 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@28..29 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@29..39 "{ y: 200 }" [] [], + }, + r_curly_token: R_CURLY@39..41 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteOutDirective { + out_token: OUT_KW@41..44 "out" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@44..45 ":" [] [], + property: SvelteName { + ident_token: IDENT@45..49 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@49..50 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@50..74 "flies in, fades out" [Newline("\n"), Whitespace(" ")] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@74..78 "<" [Newline("\n"), Whitespace(" ")] [], + slash_token: SLASH@78..79 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@79..82 "div" [] [], + }, + r_angle_token: R_ANGLE@82..83 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@83..87 "<" [Newline("\n"), Whitespace(" ")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@87..91 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteInDirective { + in_token: IN_KW@91..93 "in" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@93..94 ":" [] [], + property: SvelteName { + ident_token: IDENT@94..97 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@97..98 "|" [] [], + name: SvelteName { + ident_token: IDENT@98..104 "global" [] [], + }, + }, + ], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@104..105 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@105..106 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@106..116 "{ y: 200 }" [] [], + }, + r_curly_token: R_CURLY@116..118 "}" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteOutDirective { + out_token: OUT_KW@118..121 "out" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@121..122 ":" [] [], + property: SvelteName { + ident_token: IDENT@122..126 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@126..127 "|" [] [], + name: SvelteName { + ident_token: IDENT@127..132 "local" [] [], + }, + }, + ], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@132..133 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@133..134 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@134..151 "{ duration: 300 }" [] [], + }, + r_curly_token: R_CURLY@151..152 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@152..153 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@153..172 "With modifiers" [Newline("\n"), Whitespace(" ")] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@172..176 "<" [Newline("\n"), Whitespace(" ")] [], + slash_token: SLASH@176..177 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@177..180 "div" [] [], + }, + r_angle_token: R_ANGLE@180..181 ">" [] [], + }, + }, + ], + }, + else_if_clauses: SvelteElseIfClauseList [], + else_clause: missing (optional), + closing_block: SvelteIfClosingBlock { + sv_curly_slash_token: SV_CURLY_SLASH@181..184 "{/" [Newline("\n")] [], + if_token: IF_KW@184..186 "if" [] [], + r_curly_token: R_CURLY@186..187 "}" [] [], + }, + }, + ], + eof_token: EOF@187..188 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..188 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..187 + 0: SVELTE_IF_BLOCK@0..187 + 0: SVELTE_IF_OPENING_BLOCK@0..181 + 0: SV_CURLY_HASH@0..2 "{#" [] [] + 1: IF_KW@2..4 "if" [] [] + 2: HTML_TEXT_EXPRESSION@4..12 + 0: HTML_LITERAL@4..12 " visible" [] [] + 3: R_CURLY@12..13 "}" [] [] + 4: HTML_ELEMENT_LIST@13..181 + 0: HTML_ELEMENT@13..83 + 0: HTML_OPENING_ELEMENT@13..50 + 0: L_ANGLE@13..17 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@17..21 + 0: HTML_LITERAL@17..21 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@21..49 + 0: SVELTE_IN_DIRECTIVE@21..41 + 0: IN_KW@21..23 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@23..41 + 0: COLON@23..24 ":" [] [] + 1: SVELTE_NAME@24..27 + 0: IDENT@24..27 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@27..27 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@27..41 + 0: EQ@27..28 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@28..41 + 0: L_CURLY@28..29 "{" [] [] + 1: HTML_TEXT_EXPRESSION@29..39 + 0: HTML_LITERAL@29..39 "{ y: 200 }" [] [] + 2: R_CURLY@39..41 "}" [] [Whitespace(" ")] + 1: SVELTE_OUT_DIRECTIVE@41..49 + 0: OUT_KW@41..44 "out" [] [] + 1: SVELTE_DIRECTIVE_VALUE@44..49 + 0: COLON@44..45 ":" [] [] + 1: SVELTE_NAME@45..49 + 0: IDENT@45..49 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@49..49 + 3: (empty) + 3: R_ANGLE@49..50 ">" [] [] + 1: HTML_ELEMENT_LIST@50..74 + 0: HTML_CONTENT@50..74 + 0: HTML_LITERAL@50..74 "flies in, fades out" [Newline("\n"), Whitespace(" ")] [] + 2: HTML_CLOSING_ELEMENT@74..83 + 0: L_ANGLE@74..78 "<" [Newline("\n"), Whitespace(" ")] [] + 1: SLASH@78..79 "/" [] [] + 2: HTML_TAG_NAME@79..82 + 0: HTML_LITERAL@79..82 "div" [] [] + 3: R_ANGLE@82..83 ">" [] [] + 1: HTML_ELEMENT@83..181 + 0: HTML_OPENING_ELEMENT@83..153 + 0: L_ANGLE@83..87 "<" [Newline("\n"), Whitespace(" ")] [] + 1: HTML_TAG_NAME@87..91 + 0: HTML_LITERAL@87..91 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@91..152 + 0: SVELTE_IN_DIRECTIVE@91..118 + 0: IN_KW@91..93 "in" [] [] + 1: SVELTE_DIRECTIVE_VALUE@93..118 + 0: COLON@93..94 ":" [] [] + 1: SVELTE_NAME@94..97 + 0: IDENT@94..97 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@97..104 + 0: SVELTE_DIRECTIVE_MODIFIER@97..104 + 0: PIPE@97..98 "|" [] [] + 1: SVELTE_NAME@98..104 + 0: IDENT@98..104 "global" [] [] + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@104..118 + 0: EQ@104..105 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@105..118 + 0: L_CURLY@105..106 "{" [] [] + 1: HTML_TEXT_EXPRESSION@106..116 + 0: HTML_LITERAL@106..116 "{ y: 200 }" [] [] + 2: R_CURLY@116..118 "}" [] [Whitespace(" ")] + 1: SVELTE_OUT_DIRECTIVE@118..152 + 0: OUT_KW@118..121 "out" [] [] + 1: SVELTE_DIRECTIVE_VALUE@121..152 + 0: COLON@121..122 ":" [] [] + 1: SVELTE_NAME@122..126 + 0: IDENT@122..126 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@126..132 + 0: SVELTE_DIRECTIVE_MODIFIER@126..132 + 0: PIPE@126..127 "|" [] [] + 1: SVELTE_NAME@127..132 + 0: IDENT@127..132 "local" [] [] + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@132..152 + 0: EQ@132..133 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@133..152 + 0: L_CURLY@133..134 "{" [] [] + 1: HTML_TEXT_EXPRESSION@134..151 + 0: HTML_LITERAL@134..151 "{ duration: 300 }" [] [] + 2: R_CURLY@151..152 "}" [] [] + 3: R_ANGLE@152..153 ">" [] [] + 1: HTML_ELEMENT_LIST@153..172 + 0: HTML_CONTENT@153..172 + 0: HTML_LITERAL@153..172 "With modifiers" [Newline("\n"), Whitespace(" ")] [] + 2: HTML_CLOSING_ELEMENT@172..181 + 0: L_ANGLE@172..176 "<" [Newline("\n"), Whitespace(" ")] [] + 1: SLASH@176..177 "/" [] [] + 2: HTML_TAG_NAME@177..180 + 0: HTML_LITERAL@177..180 "div" [] [] + 3: R_ANGLE@180..181 ">" [] [] + 1: SVELTE_ELSE_IF_CLAUSE_LIST@181..181 + 2: (empty) + 3: SVELTE_IF_CLOSING_BLOCK@181..187 + 0: SV_CURLY_SLASH@181..184 "{/" [Newline("\n")] [] + 1: IF_KW@184..186 "if" [] [] + 2: R_CURLY@186..187 "}" [] [] + 4: EOF@187..188 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_global_modifier.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_global_modifier.svelte new file mode 100644 index 000000000000..56cdebce64b7 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_global_modifier.svelte @@ -0,0 +1 @@ +
    Global out transition
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_global_modifier.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_global_modifier.svelte.snap new file mode 100644 index 000000000000..ddaae2ee22bf --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_global_modifier.svelte.snap @@ -0,0 +1,106 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Global out transition
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteOutDirective { + out_token: OUT_KW@5..8 "out" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: SvelteName { + ident_token: IDENT@9..13 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@13..14 "|" [] [], + name: SvelteName { + ident_token: IDENT@14..20 "global" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@20..21 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@21..42 "Global out transition" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@42..43 "<" [] [], + slash_token: SLASH@43..44 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@44..47 "div" [] [], + }, + r_angle_token: R_ANGLE@47..48 ">" [] [], + }, + }, + ], + eof_token: EOF@48..49 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..49 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..48 + 0: HTML_ELEMENT@0..48 + 0: HTML_OPENING_ELEMENT@0..21 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..20 + 0: SVELTE_OUT_DIRECTIVE@5..20 + 0: OUT_KW@5..8 "out" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..20 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..13 + 0: IDENT@9..13 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@13..20 + 0: SVELTE_DIRECTIVE_MODIFIER@13..20 + 0: PIPE@13..14 "|" [] [] + 1: SVELTE_NAME@14..20 + 0: IDENT@14..20 "global" [] [] + 3: (empty) + 3: R_ANGLE@20..21 ">" [] [] + 1: HTML_ELEMENT_LIST@21..42 + 0: HTML_CONTENT@21..42 + 0: HTML_LITERAL@21..42 "Global out transition" [] [] + 2: HTML_CLOSING_ELEMENT@42..48 + 0: L_ANGLE@42..43 "<" [] [] + 1: SLASH@43..44 "/" [] [] + 2: HTML_TAG_NAME@44..47 + 0: HTML_LITERAL@44..47 "div" [] [] + 3: R_ANGLE@47..48 ">" [] [] + 4: EOF@48..49 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_local_modifier.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_local_modifier.svelte new file mode 100644 index 000000000000..a4160fec17c5 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_local_modifier.svelte @@ -0,0 +1 @@ +
    Local out transition
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_local_modifier.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_local_modifier.svelte.snap new file mode 100644 index 000000000000..042f54f41ea2 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_local_modifier.svelte.snap @@ -0,0 +1,106 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Local out transition
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteOutDirective { + out_token: OUT_KW@5..8 "out" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: SvelteName { + ident_token: IDENT@9..13 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@13..14 "|" [] [], + name: SvelteName { + ident_token: IDENT@14..19 "local" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@19..20 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@20..40 "Local out transition" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@40..41 "<" [] [], + slash_token: SLASH@41..42 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@42..45 "div" [] [], + }, + r_angle_token: R_ANGLE@45..46 ">" [] [], + }, + }, + ], + eof_token: EOF@46..47 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..47 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..46 + 0: HTML_ELEMENT@0..46 + 0: HTML_OPENING_ELEMENT@0..20 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..19 + 0: SVELTE_OUT_DIRECTIVE@5..19 + 0: OUT_KW@5..8 "out" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..19 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..13 + 0: IDENT@9..13 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@13..19 + 0: SVELTE_DIRECTIVE_MODIFIER@13..19 + 0: PIPE@13..14 "|" [] [] + 1: SVELTE_NAME@14..19 + 0: IDENT@14..19 "local" [] [] + 3: (empty) + 3: R_ANGLE@19..20 ">" [] [] + 1: HTML_ELEMENT_LIST@20..40 + 0: HTML_CONTENT@20..40 + 0: HTML_LITERAL@20..40 "Local out transition" [] [] + 2: HTML_CLOSING_ELEMENT@40..46 + 0: L_ANGLE@40..41 "<" [] [] + 1: SLASH@41..42 "/" [] [] + 2: HTML_TAG_NAME@42..45 + 0: HTML_LITERAL@42..45 "div" [] [] + 3: R_ANGLE@45..46 ">" [] [] + 4: EOF@46..47 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_multiple_modifiers.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_multiple_modifiers.svelte new file mode 100644 index 000000000000..06219b0739ad --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_multiple_modifiers.svelte @@ -0,0 +1 @@ +
    Multiple modifiers
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_multiple_modifiers.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_multiple_modifiers.svelte.snap new file mode 100644 index 000000000000..c386d86bc1ac --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_multiple_modifiers.svelte.snap @@ -0,0 +1,116 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Multiple modifiers
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteOutDirective { + out_token: OUT_KW@5..8 "out" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: SvelteName { + ident_token: IDENT@9..13 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@13..14 "|" [] [], + name: SvelteName { + ident_token: IDENT@14..20 "global" [] [], + }, + }, + SvelteDirectiveModifier { + bitwise_or_token: PIPE@20..21 "|" [] [], + name: SvelteName { + ident_token: IDENT@21..26 "local" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@26..27 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@27..45 "Multiple modifiers" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@45..46 "<" [] [], + slash_token: SLASH@46..47 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@47..50 "div" [] [], + }, + r_angle_token: R_ANGLE@50..51 ">" [] [], + }, + }, + ], + eof_token: EOF@51..52 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..52 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..51 + 0: HTML_ELEMENT@0..51 + 0: HTML_OPENING_ELEMENT@0..27 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..26 + 0: SVELTE_OUT_DIRECTIVE@5..26 + 0: OUT_KW@5..8 "out" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..26 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..13 + 0: IDENT@9..13 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@13..26 + 0: SVELTE_DIRECTIVE_MODIFIER@13..20 + 0: PIPE@13..14 "|" [] [] + 1: SVELTE_NAME@14..20 + 0: IDENT@14..20 "global" [] [] + 1: SVELTE_DIRECTIVE_MODIFIER@20..26 + 0: PIPE@20..21 "|" [] [] + 1: SVELTE_NAME@21..26 + 0: IDENT@21..26 "local" [] [] + 3: (empty) + 3: R_ANGLE@26..27 ">" [] [] + 1: HTML_ELEMENT_LIST@27..45 + 0: HTML_CONTENT@27..45 + 0: HTML_LITERAL@27..45 "Multiple modifiers" [] [] + 2: HTML_CLOSING_ELEMENT@45..51 + 0: L_ANGLE@45..46 "<" [] [] + 1: SLASH@46..47 "/" [] [] + 2: HTML_TAG_NAME@47..50 + 0: HTML_LITERAL@47..50 "div" [] [] + 3: R_ANGLE@50..51 ">" [] [] + 4: EOF@51..52 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_with_params.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_with_params.svelte new file mode 100644 index 000000000000..40c4cdfb9730 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_with_params.svelte @@ -0,0 +1,2 @@ +
    Slow fade out
    +

    Flies up

    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_with_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_with_params.svelte.snap new file mode 100644 index 000000000000..0e0b77f2a1d5 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/out_with_params.svelte.snap @@ -0,0 +1,185 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Slow fade out
    +

    Flies up

    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteOutDirective { + out_token: OUT_KW@5..8 "out" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: SvelteName { + ident_token: IDENT@9..13 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@13..14 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@14..15 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@15..32 "{ duration: 300 }" [] [], + }, + r_curly_token: R_CURLY@32..33 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@33..34 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@34..47 "Slow fade out" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@47..48 "<" [] [], + slash_token: SLASH@48..49 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@49..52 "div" [] [], + }, + r_angle_token: R_ANGLE@52..53 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@53..55 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@55..57 "p" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteOutDirective { + out_token: OUT_KW@57..60 "out" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@60..61 ":" [] [], + property: SvelteName { + ident_token: IDENT@61..64 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@64..65 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@65..66 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@66..77 "{ y: -200 }" [] [], + }, + r_curly_token: R_CURLY@77..78 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@78..79 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@79..87 "Flies up" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@87..88 "<" [] [], + slash_token: SLASH@88..89 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@89..90 "p" [] [], + }, + r_angle_token: R_ANGLE@90..91 ">" [] [], + }, + }, + ], + eof_token: EOF@91..92 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..92 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..91 + 0: HTML_ELEMENT@0..53 + 0: HTML_OPENING_ELEMENT@0..34 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..33 + 0: SVELTE_OUT_DIRECTIVE@5..33 + 0: OUT_KW@5..8 "out" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..33 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..13 + 0: IDENT@9..13 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@13..13 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@13..33 + 0: EQ@13..14 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@14..33 + 0: L_CURLY@14..15 "{" [] [] + 1: HTML_TEXT_EXPRESSION@15..32 + 0: HTML_LITERAL@15..32 "{ duration: 300 }" [] [] + 2: R_CURLY@32..33 "}" [] [] + 3: R_ANGLE@33..34 ">" [] [] + 1: HTML_ELEMENT_LIST@34..47 + 0: HTML_CONTENT@34..47 + 0: HTML_LITERAL@34..47 "Slow fade out" [] [] + 2: HTML_CLOSING_ELEMENT@47..53 + 0: L_ANGLE@47..48 "<" [] [] + 1: SLASH@48..49 "/" [] [] + 2: HTML_TAG_NAME@49..52 + 0: HTML_LITERAL@49..52 "div" [] [] + 3: R_ANGLE@52..53 ">" [] [] + 1: HTML_ELEMENT@53..91 + 0: HTML_OPENING_ELEMENT@53..79 + 0: L_ANGLE@53..55 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@55..57 + 0: HTML_LITERAL@55..57 "p" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@57..78 + 0: SVELTE_OUT_DIRECTIVE@57..78 + 0: OUT_KW@57..60 "out" [] [] + 1: SVELTE_DIRECTIVE_VALUE@60..78 + 0: COLON@60..61 ":" [] [] + 1: SVELTE_NAME@61..64 + 0: IDENT@61..64 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@64..64 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@64..78 + 0: EQ@64..65 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@65..78 + 0: L_CURLY@65..66 "{" [] [] + 1: HTML_TEXT_EXPRESSION@66..77 + 0: HTML_LITERAL@66..77 "{ y: -200 }" [] [] + 2: R_CURLY@77..78 "}" [] [] + 3: R_ANGLE@78..79 ">" [] [] + 1: HTML_ELEMENT_LIST@79..87 + 0: HTML_CONTENT@79..87 + 0: HTML_LITERAL@79..87 "Flies up" [] [] + 2: HTML_CLOSING_ELEMENT@87..91 + 0: L_ANGLE@87..88 "<" [] [] + 1: SLASH@88..89 "/" [] [] + 2: HTML_TAG_NAME@89..90 + 0: HTML_LITERAL@89..90 "p" [] [] + 3: R_ANGLE@90..91 ">" [] [] + 4: EOF@91..92 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_basic.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_basic.svelte new file mode 100644 index 000000000000..928860843f99 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_basic.svelte @@ -0,0 +1,2 @@ +
    Red text
    +

    Large text

    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_basic.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_basic.svelte.snap new file mode 100644 index 000000000000..3528bcf732d7 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_basic.svelte.snap @@ -0,0 +1,171 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Red text
    +

    Large text

    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@5..10 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..16 "color" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@16..17 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@17..22 "\"red\"" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@22..23 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@23..31 "Red text" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@31..32 "<" [] [], + slash_token: SLASH@32..33 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@33..36 "div" [] [], + }, + r_angle_token: R_ANGLE@36..37 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@37..39 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@39..41 "p" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@41..46 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@46..47 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@47..56 "font-size" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@56..57 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@57..63 "\"20px\"" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@63..64 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@64..74 "Large text" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@74..75 "<" [] [], + slash_token: SLASH@75..76 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@76..77 "p" [] [], + }, + r_angle_token: R_ANGLE@77..78 ">" [] [], + }, + }, + ], + eof_token: EOF@78..79 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..79 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..78 + 0: HTML_ELEMENT@0..37 + 0: HTML_OPENING_ELEMENT@0..23 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..22 + 0: SVELTE_STYLE_DIRECTIVE@5..22 + 0: STYLE_KW@5..10 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..22 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..16 + 0: HTML_LITERAL@11..16 "color" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..16 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@16..22 + 0: EQ@16..17 "=" [] [] + 1: HTML_STRING@17..22 + 0: HTML_STRING_LITERAL@17..22 "\"red\"" [] [] + 3: R_ANGLE@22..23 ">" [] [] + 1: HTML_ELEMENT_LIST@23..31 + 0: HTML_CONTENT@23..31 + 0: HTML_LITERAL@23..31 "Red text" [] [] + 2: HTML_CLOSING_ELEMENT@31..37 + 0: L_ANGLE@31..32 "<" [] [] + 1: SLASH@32..33 "/" [] [] + 2: HTML_TAG_NAME@33..36 + 0: HTML_LITERAL@33..36 "div" [] [] + 3: R_ANGLE@36..37 ">" [] [] + 1: HTML_ELEMENT@37..78 + 0: HTML_OPENING_ELEMENT@37..64 + 0: L_ANGLE@37..39 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@39..41 + 0: HTML_LITERAL@39..41 "p" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@41..63 + 0: SVELTE_STYLE_DIRECTIVE@41..63 + 0: STYLE_KW@41..46 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@46..63 + 0: COLON@46..47 ":" [] [] + 1: SVELTE_LITERAL@47..56 + 0: HTML_LITERAL@47..56 "font-size" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@56..56 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@56..63 + 0: EQ@56..57 "=" [] [] + 1: HTML_STRING@57..63 + 0: HTML_STRING_LITERAL@57..63 "\"20px\"" [] [] + 3: R_ANGLE@63..64 ">" [] [] + 1: HTML_ELEMENT_LIST@64..74 + 0: HTML_CONTENT@64..74 + 0: HTML_LITERAL@64..74 "Large text" [] [] + 2: HTML_CLOSING_ELEMENT@74..78 + 0: L_ANGLE@74..75 "<" [] [] + 1: SLASH@75..76 "/" [] [] + 2: HTML_TAG_NAME@76..77 + 0: HTML_LITERAL@76..77 "p" [] [] + 3: R_ANGLE@77..78 ">" [] [] + 4: EOF@78..79 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_modifier.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_modifier.svelte new file mode 100644 index 000000000000..b5934c0cb80b --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_modifier.svelte @@ -0,0 +1 @@ +
    Important red
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_modifier.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_modifier.svelte.snap new file mode 100644 index 000000000000..5399d3e4ef73 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_modifier.svelte.snap @@ -0,0 +1,103 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Important red
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@5..10 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..26 "color|important" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@26..27 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@27..32 "\"red\"" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@32..33 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@33..46 "Important red" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@46..47 "<" [] [], + slash_token: SLASH@47..48 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@48..51 "div" [] [], + }, + r_angle_token: R_ANGLE@51..52 ">" [] [], + }, + }, + ], + eof_token: EOF@52..53 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..53 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..52 + 0: HTML_ELEMENT@0..52 + 0: HTML_OPENING_ELEMENT@0..33 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..32 + 0: SVELTE_STYLE_DIRECTIVE@5..32 + 0: STYLE_KW@5..10 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..32 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..26 + 0: HTML_LITERAL@11..26 "color|important" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@26..26 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@26..32 + 0: EQ@26..27 "=" [] [] + 1: HTML_STRING@27..32 + 0: HTML_STRING_LITERAL@27..32 "\"red\"" [] [] + 3: R_ANGLE@32..33 ">" [] [] + 1: HTML_ELEMENT_LIST@33..46 + 0: HTML_CONTENT@33..46 + 0: HTML_LITERAL@33..46 "Important red" [] [] + 2: HTML_CLOSING_ELEMENT@46..52 + 0: L_ANGLE@46..47 "<" [] [] + 1: SLASH@47..48 "/" [] [] + 2: HTML_TAG_NAME@48..51 + 0: HTML_LITERAL@48..51 "div" [] [] + 3: R_ANGLE@51..52 ">" [] [] + 4: EOF@52..53 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_with_expression.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_with_expression.svelte new file mode 100644 index 000000000000..c6adf388818b --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_with_expression.svelte @@ -0,0 +1 @@ +
    Important dynamic
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_with_expression.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_with_expression.svelte.snap new file mode 100644 index 000000000000..86b03a73ef37 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_important_with_expression.svelte.snap @@ -0,0 +1,110 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Important dynamic
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@5..10 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..26 "color|important" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@26..27 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@27..28 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@28..35 "myColor" [] [], + }, + r_curly_token: R_CURLY@35..36 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@36..37 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@37..54 "Important dynamic" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@54..55 "<" [] [], + slash_token: SLASH@55..56 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@56..59 "div" [] [], + }, + r_angle_token: R_ANGLE@59..60 ">" [] [], + }, + }, + ], + eof_token: EOF@60..61 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..61 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..60 + 0: HTML_ELEMENT@0..60 + 0: HTML_OPENING_ELEMENT@0..37 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..36 + 0: SVELTE_STYLE_DIRECTIVE@5..36 + 0: STYLE_KW@5..10 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..36 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..26 + 0: HTML_LITERAL@11..26 "color|important" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@26..26 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@26..36 + 0: EQ@26..27 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@27..36 + 0: L_CURLY@27..28 "{" [] [] + 1: HTML_TEXT_EXPRESSION@28..35 + 0: HTML_LITERAL@28..35 "myColor" [] [] + 2: R_CURLY@35..36 "}" [] [] + 3: R_ANGLE@36..37 ">" [] [] + 1: HTML_ELEMENT_LIST@37..54 + 0: HTML_CONTENT@37..54 + 0: HTML_LITERAL@37..54 "Important dynamic" [] [] + 2: HTML_CLOSING_ELEMENT@54..60 + 0: L_ANGLE@54..55 "<" [] [] + 1: SLASH@55..56 "/" [] [] + 2: HTML_TAG_NAME@56..59 + 0: HTML_LITERAL@56..59 "div" [] [] + 3: R_ANGLE@59..60 ">" [] [] + 4: EOF@60..61 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_kebab_case.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_kebab_case.svelte new file mode 100644 index 000000000000..bdf3250d60ef --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_kebab_case.svelte @@ -0,0 +1,2 @@ +
    Blue background
    +
    Kebab case props
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_kebab_case.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_kebab_case.svelte.snap new file mode 100644 index 000000000000..31a90dc27509 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_kebab_case.svelte.snap @@ -0,0 +1,198 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Blue background
    +
    Kebab case props
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@5..10 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..27 "background-color" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@27..28 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@28..34 "\"blue\"" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@34..35 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@35..50 "Blue background" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@50..51 "<" [] [], + slash_token: SLASH@51..52 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@52..55 "div" [] [], + }, + r_angle_token: R_ANGLE@55..56 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@56..58 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@58..62 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@62..67 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@67..68 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@68..77 "font-size" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@77..78 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@78..85 "\"16px\"" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteStyleDirective { + style_token: STYLE_KW@85..90 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@90..91 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@91..102 "line-height" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@102..103 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@103..108 "\"1.5\"" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@108..109 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@109..125 "Kebab case props" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@125..126 "<" [] [], + slash_token: SLASH@126..127 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@127..130 "div" [] [], + }, + r_angle_token: R_ANGLE@130..131 ">" [] [], + }, + }, + ], + eof_token: EOF@131..132 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..132 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..131 + 0: HTML_ELEMENT@0..56 + 0: HTML_OPENING_ELEMENT@0..35 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..34 + 0: SVELTE_STYLE_DIRECTIVE@5..34 + 0: STYLE_KW@5..10 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..34 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..27 + 0: HTML_LITERAL@11..27 "background-color" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@27..27 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@27..34 + 0: EQ@27..28 "=" [] [] + 1: HTML_STRING@28..34 + 0: HTML_STRING_LITERAL@28..34 "\"blue\"" [] [] + 3: R_ANGLE@34..35 ">" [] [] + 1: HTML_ELEMENT_LIST@35..50 + 0: HTML_CONTENT@35..50 + 0: HTML_LITERAL@35..50 "Blue background" [] [] + 2: HTML_CLOSING_ELEMENT@50..56 + 0: L_ANGLE@50..51 "<" [] [] + 1: SLASH@51..52 "/" [] [] + 2: HTML_TAG_NAME@52..55 + 0: HTML_LITERAL@52..55 "div" [] [] + 3: R_ANGLE@55..56 ">" [] [] + 1: HTML_ELEMENT@56..131 + 0: HTML_OPENING_ELEMENT@56..109 + 0: L_ANGLE@56..58 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@58..62 + 0: HTML_LITERAL@58..62 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@62..108 + 0: SVELTE_STYLE_DIRECTIVE@62..85 + 0: STYLE_KW@62..67 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@67..85 + 0: COLON@67..68 ":" [] [] + 1: SVELTE_LITERAL@68..77 + 0: HTML_LITERAL@68..77 "font-size" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@77..77 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@77..85 + 0: EQ@77..78 "=" [] [] + 1: HTML_STRING@78..85 + 0: HTML_STRING_LITERAL@78..85 "\"16px\"" [] [Whitespace(" ")] + 1: SVELTE_STYLE_DIRECTIVE@85..108 + 0: STYLE_KW@85..90 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@90..108 + 0: COLON@90..91 ":" [] [] + 1: SVELTE_LITERAL@91..102 + 0: HTML_LITERAL@91..102 "line-height" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@102..102 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@102..108 + 0: EQ@102..103 "=" [] [] + 1: HTML_STRING@103..108 + 0: HTML_STRING_LITERAL@103..108 "\"1.5\"" [] [] + 3: R_ANGLE@108..109 ">" [] [] + 1: HTML_ELEMENT_LIST@109..125 + 0: HTML_CONTENT@109..125 + 0: HTML_LITERAL@109..125 "Kebab case props" [] [] + 2: HTML_CLOSING_ELEMENT@125..131 + 0: L_ANGLE@125..126 "<" [] [] + 1: SLASH@126..127 "/" [] [] + 2: HTML_TAG_NAME@127..130 + 0: HTML_LITERAL@127..130 "div" [] [] + 3: R_ANGLE@130..131 ">" [] [] + 4: EOF@131..132 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple.svelte new file mode 100644 index 000000000000..3d1f98b1b22c --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple.svelte @@ -0,0 +1,3 @@ +
    + Multiple styles +
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple.svelte.snap new file mode 100644 index 000000000000..c70c3621bc12 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple.svelte.snap @@ -0,0 +1,159 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    + Multiple styles +
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@5..10 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..16 "color" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@16..17 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@17..23 "\"red\"" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteStyleDirective { + style_token: STYLE_KW@23..28 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@28..29 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@29..34 "width" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@34..35 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@35..43 "\"100px\"" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteStyleDirective { + style_token: STYLE_KW@43..48 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@48..49 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@49..55 "height" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@55..56 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@56..62 "\"50px\"" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@62..63 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@63..81 "Multiple styles" [Newline("\n"), Whitespace(" ")] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@81..83 "<" [Newline("\n")] [], + slash_token: SLASH@83..84 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@84..87 "div" [] [], + }, + r_angle_token: R_ANGLE@87..88 ">" [] [], + }, + }, + ], + eof_token: EOF@88..89 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..89 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..88 + 0: HTML_ELEMENT@0..88 + 0: HTML_OPENING_ELEMENT@0..63 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..62 + 0: SVELTE_STYLE_DIRECTIVE@5..23 + 0: STYLE_KW@5..10 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..23 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..16 + 0: HTML_LITERAL@11..16 "color" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..16 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@16..23 + 0: EQ@16..17 "=" [] [] + 1: HTML_STRING@17..23 + 0: HTML_STRING_LITERAL@17..23 "\"red\"" [] [Whitespace(" ")] + 1: SVELTE_STYLE_DIRECTIVE@23..43 + 0: STYLE_KW@23..28 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@28..43 + 0: COLON@28..29 ":" [] [] + 1: SVELTE_LITERAL@29..34 + 0: HTML_LITERAL@29..34 "width" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@34..34 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@34..43 + 0: EQ@34..35 "=" [] [] + 1: HTML_STRING@35..43 + 0: HTML_STRING_LITERAL@35..43 "\"100px\"" [] [Whitespace(" ")] + 2: SVELTE_STYLE_DIRECTIVE@43..62 + 0: STYLE_KW@43..48 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@48..62 + 0: COLON@48..49 ":" [] [] + 1: SVELTE_LITERAL@49..55 + 0: HTML_LITERAL@49..55 "height" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@55..55 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@55..62 + 0: EQ@55..56 "=" [] [] + 1: HTML_STRING@56..62 + 0: HTML_STRING_LITERAL@56..62 "\"50px\"" [] [] + 3: R_ANGLE@62..63 ">" [] [] + 1: HTML_ELEMENT_LIST@63..81 + 0: HTML_CONTENT@63..81 + 0: HTML_LITERAL@63..81 "Multiple styles" [Newline("\n"), Whitespace(" ")] [] + 2: HTML_CLOSING_ELEMENT@81..88 + 0: L_ANGLE@81..83 "<" [Newline("\n")] [] + 1: SLASH@83..84 "/" [] [] + 2: HTML_TAG_NAME@84..87 + 0: HTML_LITERAL@84..87 "div" [] [] + 3: R_ANGLE@87..88 ">" [] [] + 4: EOF@88..89 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple_with_important.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple_with_important.svelte new file mode 100644 index 000000000000..64ff6adc322d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple_with_important.svelte @@ -0,0 +1,3 @@ +
    + Mixed important +
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple_with_important.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple_with_important.svelte.snap new file mode 100644 index 000000000000..f81e487b80aa --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_multiple_with_important.svelte.snap @@ -0,0 +1,166 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    + Mixed important +
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@5..10 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..26 "color|important" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@26..27 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@27..33 "\"red\"" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteStyleDirective { + style_token: STYLE_KW@33..38 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@38..39 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@39..44 "width" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@44..45 "=" [] [], + value: HtmlString { + value_token: HTML_STRING_LITERAL@45..53 "\"100px\"" [] [Whitespace(" ")], + }, + }, + }, + }, + SvelteStyleDirective { + style_token: STYLE_KW@53..58 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@58..59 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@59..85 "background-color|important" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@85..86 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@86..87 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@87..89 "bg" [] [], + }, + r_curly_token: R_CURLY@89..90 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@90..91 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@91..109 "Mixed important" [Newline("\n"), Whitespace(" ")] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@109..111 "<" [Newline("\n")] [], + slash_token: SLASH@111..112 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@112..115 "div" [] [], + }, + r_angle_token: R_ANGLE@115..116 ">" [] [], + }, + }, + ], + eof_token: EOF@116..117 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..117 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..116 + 0: HTML_ELEMENT@0..116 + 0: HTML_OPENING_ELEMENT@0..91 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..90 + 0: SVELTE_STYLE_DIRECTIVE@5..33 + 0: STYLE_KW@5..10 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..33 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..26 + 0: HTML_LITERAL@11..26 "color|important" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@26..26 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@26..33 + 0: EQ@26..27 "=" [] [] + 1: HTML_STRING@27..33 + 0: HTML_STRING_LITERAL@27..33 "\"red\"" [] [Whitespace(" ")] + 1: SVELTE_STYLE_DIRECTIVE@33..53 + 0: STYLE_KW@33..38 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@38..53 + 0: COLON@38..39 ":" [] [] + 1: SVELTE_LITERAL@39..44 + 0: HTML_LITERAL@39..44 "width" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@44..44 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@44..53 + 0: EQ@44..45 "=" [] [] + 1: HTML_STRING@45..53 + 0: HTML_STRING_LITERAL@45..53 "\"100px\"" [] [Whitespace(" ")] + 2: SVELTE_STYLE_DIRECTIVE@53..90 + 0: STYLE_KW@53..58 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@58..90 + 0: COLON@58..59 ":" [] [] + 1: SVELTE_LITERAL@59..85 + 0: HTML_LITERAL@59..85 "background-color|important" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@85..85 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@85..90 + 0: EQ@85..86 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@86..90 + 0: L_CURLY@86..87 "{" [] [] + 1: HTML_TEXT_EXPRESSION@87..89 + 0: HTML_LITERAL@87..89 "bg" [] [] + 2: R_CURLY@89..90 "}" [] [] + 3: R_ANGLE@90..91 ">" [] [] + 1: HTML_ELEMENT_LIST@91..109 + 0: HTML_CONTENT@91..109 + 0: HTML_LITERAL@91..109 "Mixed important" [Newline("\n"), Whitespace(" ")] [] + 2: HTML_CLOSING_ELEMENT@109..116 + 0: L_ANGLE@109..111 "<" [Newline("\n")] [] + 1: SLASH@111..112 "/" [] [] + 2: HTML_TAG_NAME@112..115 + 0: HTML_LITERAL@112..115 "div" [] [] + 3: R_ANGLE@115..116 ">" [] [] + 4: EOF@116..117 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_shorthand.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_shorthand.svelte new file mode 100644 index 000000000000..c9cc2e2a03b1 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_shorthand.svelte @@ -0,0 +1,2 @@ +
    Shorthand
    +

    Multiple shorthand

    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_shorthand.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_shorthand.svelte.snap new file mode 100644 index 000000000000..4b1307918310 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_shorthand.svelte.snap @@ -0,0 +1,174 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Shorthand
    +

    Multiple shorthand

    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@5..10 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..16 "color" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@16..17 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@17..26 "Shorthand" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@26..27 "<" [] [], + slash_token: SLASH@27..28 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@28..31 "div" [] [], + }, + r_angle_token: R_ANGLE@31..32 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@32..34 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@34..36 "p" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@36..41 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@41..42 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@42..48 "width" [] [Whitespace(" ")], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + SvelteStyleDirective { + style_token: STYLE_KW@48..53 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@53..54 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@54..60 "height" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@60..61 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@61..79 "Multiple shorthand" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@79..80 "<" [] [], + slash_token: SLASH@80..81 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@81..82 "p" [] [], + }, + r_angle_token: R_ANGLE@82..83 ">" [] [], + }, + }, + ], + eof_token: EOF@83..84 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..84 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..83 + 0: HTML_ELEMENT@0..32 + 0: HTML_OPENING_ELEMENT@0..17 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..16 + 0: SVELTE_STYLE_DIRECTIVE@5..16 + 0: STYLE_KW@5..10 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..16 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..16 + 0: HTML_LITERAL@11..16 "color" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..16 + 3: (empty) + 3: R_ANGLE@16..17 ">" [] [] + 1: HTML_ELEMENT_LIST@17..26 + 0: HTML_CONTENT@17..26 + 0: HTML_LITERAL@17..26 "Shorthand" [] [] + 2: HTML_CLOSING_ELEMENT@26..32 + 0: L_ANGLE@26..27 "<" [] [] + 1: SLASH@27..28 "/" [] [] + 2: HTML_TAG_NAME@28..31 + 0: HTML_LITERAL@28..31 "div" [] [] + 3: R_ANGLE@31..32 ">" [] [] + 1: HTML_ELEMENT@32..83 + 0: HTML_OPENING_ELEMENT@32..61 + 0: L_ANGLE@32..34 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@34..36 + 0: HTML_LITERAL@34..36 "p" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@36..60 + 0: SVELTE_STYLE_DIRECTIVE@36..48 + 0: STYLE_KW@36..41 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@41..48 + 0: COLON@41..42 ":" [] [] + 1: SVELTE_LITERAL@42..48 + 0: HTML_LITERAL@42..48 "width" [] [Whitespace(" ")] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@48..48 + 3: (empty) + 1: SVELTE_STYLE_DIRECTIVE@48..60 + 0: STYLE_KW@48..53 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@53..60 + 0: COLON@53..54 ":" [] [] + 1: SVELTE_LITERAL@54..60 + 0: HTML_LITERAL@54..60 "height" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@60..60 + 3: (empty) + 3: R_ANGLE@60..61 ">" [] [] + 1: HTML_ELEMENT_LIST@61..79 + 0: HTML_CONTENT@61..79 + 0: HTML_LITERAL@61..79 "Multiple shorthand" [] [] + 2: HTML_CLOSING_ELEMENT@79..83 + 0: L_ANGLE@79..80 "<" [] [] + 1: SLASH@80..81 "/" [] [] + 2: HTML_TAG_NAME@81..82 + 0: HTML_LITERAL@81..82 "p" [] [] + 3: R_ANGLE@82..83 ">" [] [] + 4: EOF@83..84 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_with_expression.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_with_expression.svelte new file mode 100644 index 000000000000..8410ee34ca2c --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_with_expression.svelte @@ -0,0 +1,2 @@ +
    Dynamic color
    +

    Dynamic width

    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_with_expression.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_with_expression.svelte.snap new file mode 100644 index 000000000000..950cb610eaea --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/style_with_expression.svelte.snap @@ -0,0 +1,185 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Dynamic color
    +

    Dynamic width

    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@5..10 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@10..11 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@11..16 "color" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@16..17 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@17..18 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@18..25 "myColor" [] [], + }, + r_curly_token: R_CURLY@25..26 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@26..27 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@27..40 "Dynamic color" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@40..41 "<" [] [], + slash_token: SLASH@41..42 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@42..45 "div" [] [], + }, + r_angle_token: R_ANGLE@45..46 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@46..48 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@48..50 "p" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteStyleDirective { + style_token: STYLE_KW@50..55 "style" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@55..56 ":" [] [], + property: SvelteLiteral { + value_token: HTML_LITERAL@56..61 "width" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@61..62 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@62..63 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@63..75 "width + 'px'" [] [], + }, + r_curly_token: R_CURLY@75..76 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@76..77 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@77..90 "Dynamic width" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@90..91 "<" [] [], + slash_token: SLASH@91..92 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@92..93 "p" [] [], + }, + r_angle_token: R_ANGLE@93..94 ">" [] [], + }, + }, + ], + eof_token: EOF@94..95 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..95 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..94 + 0: HTML_ELEMENT@0..46 + 0: HTML_OPENING_ELEMENT@0..27 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..26 + 0: SVELTE_STYLE_DIRECTIVE@5..26 + 0: STYLE_KW@5..10 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@10..26 + 0: COLON@10..11 ":" [] [] + 1: SVELTE_LITERAL@11..16 + 0: HTML_LITERAL@11..16 "color" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..16 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@16..26 + 0: EQ@16..17 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@17..26 + 0: L_CURLY@17..18 "{" [] [] + 1: HTML_TEXT_EXPRESSION@18..25 + 0: HTML_LITERAL@18..25 "myColor" [] [] + 2: R_CURLY@25..26 "}" [] [] + 3: R_ANGLE@26..27 ">" [] [] + 1: HTML_ELEMENT_LIST@27..40 + 0: HTML_CONTENT@27..40 + 0: HTML_LITERAL@27..40 "Dynamic color" [] [] + 2: HTML_CLOSING_ELEMENT@40..46 + 0: L_ANGLE@40..41 "<" [] [] + 1: SLASH@41..42 "/" [] [] + 2: HTML_TAG_NAME@42..45 + 0: HTML_LITERAL@42..45 "div" [] [] + 3: R_ANGLE@45..46 ">" [] [] + 1: HTML_ELEMENT@46..94 + 0: HTML_OPENING_ELEMENT@46..77 + 0: L_ANGLE@46..48 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@48..50 + 0: HTML_LITERAL@48..50 "p" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@50..76 + 0: SVELTE_STYLE_DIRECTIVE@50..76 + 0: STYLE_KW@50..55 "style" [] [] + 1: SVELTE_DIRECTIVE_VALUE@55..76 + 0: COLON@55..56 ":" [] [] + 1: SVELTE_LITERAL@56..61 + 0: HTML_LITERAL@56..61 "width" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@61..61 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@61..76 + 0: EQ@61..62 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@62..76 + 0: L_CURLY@62..63 "{" [] [] + 1: HTML_TEXT_EXPRESSION@63..75 + 0: HTML_LITERAL@63..75 "width + 'px'" [] [] + 2: R_CURLY@75..76 "}" [] [] + 3: R_ANGLE@76..77 ">" [] [] + 1: HTML_ELEMENT_LIST@77..90 + 0: HTML_CONTENT@77..90 + 0: HTML_LITERAL@77..90 "Dynamic width" [] [] + 2: HTML_CLOSING_ELEMENT@90..94 + 0: L_ANGLE@90..91 "<" [] [] + 1: SLASH@91..92 "/" [] [] + 2: HTML_TAG_NAME@92..93 + 0: HTML_LITERAL@92..93 "p" [] [] + 3: R_ANGLE@93..94 ">" [] [] + 4: EOF@94..95 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_basic.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_basic.svelte new file mode 100644 index 000000000000..ab88fdec0c41 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_basic.svelte @@ -0,0 +1 @@ +
    Fades in and out
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_basic.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_basic.svelte.snap new file mode 100644 index 000000000000..711ef2ae69a9 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_basic.svelte.snap @@ -0,0 +1,95 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Fades in and out
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@5..15 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@15..16 ":" [] [], + property: SvelteName { + ident_token: IDENT@16..20 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@20..21 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@21..37 "Fades in and out" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@37..38 "<" [] [], + slash_token: SLASH@38..39 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@39..42 "div" [] [], + }, + r_angle_token: R_ANGLE@42..43 ">" [] [], + }, + }, + ], + eof_token: EOF@43..44 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..44 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..43 + 0: HTML_ELEMENT@0..43 + 0: HTML_OPENING_ELEMENT@0..21 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..20 + 0: SVELTE_TRANSITION_DIRECTIVE@5..20 + 0: TRANSITION_KW@5..15 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@15..20 + 0: COLON@15..16 ":" [] [] + 1: SVELTE_NAME@16..20 + 0: IDENT@16..20 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@20..20 + 3: (empty) + 3: R_ANGLE@20..21 ">" [] [] + 1: HTML_ELEMENT_LIST@21..37 + 0: HTML_CONTENT@21..37 + 0: HTML_LITERAL@21..37 "Fades in and out" [] [] + 2: HTML_CLOSING_ELEMENT@37..43 + 0: L_ANGLE@37..38 "<" [] [] + 1: SLASH@38..39 "/" [] [] + 2: HTML_TAG_NAME@39..42 + 0: HTML_LITERAL@39..42 "div" [] [] + 3: R_ANGLE@42..43 ">" [] [] + 4: EOF@43..44 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_complex_params.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_complex_params.svelte new file mode 100644 index 000000000000..12d8816f3086 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_complex_params.svelte @@ -0,0 +1,3 @@ +
    + Complex parameters +
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_complex_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_complex_params.svelte.snap new file mode 100644 index 000000000000..ef79709ce152 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_complex_params.svelte.snap @@ -0,0 +1,112 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    + Complex parameters +
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@5..15 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@15..16 ":" [] [], + property: SvelteName { + ident_token: IDENT@16..22 "custom" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@22..23 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@23..24 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@24..85 "{ delay: 100, duration: 400, easing: cubicOut, opacity: 0.5 }" [] [], + }, + r_curly_token: R_CURLY@85..86 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@86..87 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@87..108 "Complex parameters" [Newline("\n"), Whitespace(" ")] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@108..110 "<" [Newline("\n")] [], + slash_token: SLASH@110..111 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@111..114 "div" [] [], + }, + r_angle_token: R_ANGLE@114..115 ">" [] [], + }, + }, + ], + eof_token: EOF@115..116 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..116 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..115 + 0: HTML_ELEMENT@0..115 + 0: HTML_OPENING_ELEMENT@0..87 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..86 + 0: SVELTE_TRANSITION_DIRECTIVE@5..86 + 0: TRANSITION_KW@5..15 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@15..86 + 0: COLON@15..16 ":" [] [] + 1: SVELTE_NAME@16..22 + 0: IDENT@16..22 "custom" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@22..22 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@22..86 + 0: EQ@22..23 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@23..86 + 0: L_CURLY@23..24 "{" [] [] + 1: HTML_TEXT_EXPRESSION@24..85 + 0: HTML_LITERAL@24..85 "{ delay: 100, duration: 400, easing: cubicOut, opacity: 0.5 }" [] [] + 2: R_CURLY@85..86 "}" [] [] + 3: R_ANGLE@86..87 ">" [] [] + 1: HTML_ELEMENT_LIST@87..108 + 0: HTML_CONTENT@87..108 + 0: HTML_LITERAL@87..108 "Complex parameters" [Newline("\n"), Whitespace(" ")] [] + 2: HTML_CLOSING_ELEMENT@108..115 + 0: L_ANGLE@108..110 "<" [Newline("\n")] [] + 1: SLASH@110..111 "/" [] [] + 2: HTML_TAG_NAME@111..114 + 0: HTML_LITERAL@111..114 "div" [] [] + 3: R_ANGLE@114..115 ">" [] [] + 4: EOF@115..116 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_global_modifier.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_global_modifier.svelte new file mode 100644 index 000000000000..6922e6507121 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_global_modifier.svelte @@ -0,0 +1 @@ +

    Fades when x or y change

    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_global_modifier.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_global_modifier.svelte.snap new file mode 100644 index 000000000000..9727e5cdaeaa --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_global_modifier.svelte.snap @@ -0,0 +1,106 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +

    Fades when x or y change

    + +``` + + +## 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..3 "p" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@3..13 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@13..14 ":" [] [], + property: SvelteName { + ident_token: IDENT@14..18 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@18..19 "|" [] [], + name: SvelteName { + ident_token: IDENT@19..25 "global" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@25..26 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@26..50 "Fades when x or y change" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@50..51 "<" [] [], + slash_token: SLASH@51..52 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@52..53 "p" [] [], + }, + r_angle_token: R_ANGLE@53..54 ">" [] [], + }, + }, + ], + eof_token: EOF@54..55 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..55 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..54 + 0: HTML_ELEMENT@0..54 + 0: HTML_OPENING_ELEMENT@0..26 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..3 + 0: HTML_LITERAL@1..3 "p" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@3..25 + 0: SVELTE_TRANSITION_DIRECTIVE@3..25 + 0: TRANSITION_KW@3..13 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@13..25 + 0: COLON@13..14 ":" [] [] + 1: SVELTE_NAME@14..18 + 0: IDENT@14..18 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@18..25 + 0: SVELTE_DIRECTIVE_MODIFIER@18..25 + 0: PIPE@18..19 "|" [] [] + 1: SVELTE_NAME@19..25 + 0: IDENT@19..25 "global" [] [] + 3: (empty) + 3: R_ANGLE@25..26 ">" [] [] + 1: HTML_ELEMENT_LIST@26..50 + 0: HTML_CONTENT@26..50 + 0: HTML_LITERAL@26..50 "Fades when x or y change" [] [] + 2: HTML_CLOSING_ELEMENT@50..54 + 0: L_ANGLE@50..51 "<" [] [] + 1: SLASH@51..52 "/" [] [] + 2: HTML_TAG_NAME@52..53 + 0: HTML_LITERAL@52..53 "p" [] [] + 3: R_ANGLE@53..54 ">" [] [] + 4: EOF@54..55 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_local_modifier.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_local_modifier.svelte new file mode 100644 index 000000000000..e51dcefb621a --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_local_modifier.svelte @@ -0,0 +1 @@ +

    Fades only when y changes

    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_local_modifier.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_local_modifier.svelte.snap new file mode 100644 index 000000000000..ee9d11526212 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_local_modifier.svelte.snap @@ -0,0 +1,106 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +

    Fades only when y changes

    + +``` + + +## 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..3 "p" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@3..13 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@13..14 ":" [] [], + property: SvelteName { + ident_token: IDENT@14..18 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@18..19 "|" [] [], + name: SvelteName { + ident_token: IDENT@19..24 "local" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@24..25 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@25..50 "Fades only when y changes" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@50..51 "<" [] [], + slash_token: SLASH@51..52 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@52..53 "p" [] [], + }, + r_angle_token: R_ANGLE@53..54 ">" [] [], + }, + }, + ], + eof_token: EOF@54..55 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..55 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..54 + 0: HTML_ELEMENT@0..54 + 0: HTML_OPENING_ELEMENT@0..25 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..3 + 0: HTML_LITERAL@1..3 "p" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@3..24 + 0: SVELTE_TRANSITION_DIRECTIVE@3..24 + 0: TRANSITION_KW@3..13 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@13..24 + 0: COLON@13..14 ":" [] [] + 1: SVELTE_NAME@14..18 + 0: IDENT@14..18 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@18..24 + 0: SVELTE_DIRECTIVE_MODIFIER@18..24 + 0: PIPE@18..19 "|" [] [] + 1: SVELTE_NAME@19..24 + 0: IDENT@19..24 "local" [] [] + 3: (empty) + 3: R_ANGLE@24..25 ">" [] [] + 1: HTML_ELEMENT_LIST@25..50 + 0: HTML_CONTENT@25..50 + 0: HTML_LITERAL@25..50 "Fades only when y changes" [] [] + 2: HTML_CLOSING_ELEMENT@50..54 + 0: L_ANGLE@50..51 "<" [] [] + 1: SLASH@51..52 "/" [] [] + 2: HTML_TAG_NAME@52..53 + 0: HTML_LITERAL@52..53 "p" [] [] + 3: R_ANGLE@53..54 ">" [] [] + 4: EOF@54..55 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_modifier_with_params.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_modifier_with_params.svelte new file mode 100644 index 000000000000..822de1bbb6ae --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_modifier_with_params.svelte @@ -0,0 +1,2 @@ +
    Global with params
    +

    Local with params

    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_modifier_with_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_modifier_with_params.svelte.snap new file mode 100644 index 000000000000..01258d41a2e8 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_modifier_with_params.svelte.snap @@ -0,0 +1,207 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Global with params
    +

    Local with params

    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@5..15 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@15..16 ":" [] [], + property: SvelteName { + ident_token: IDENT@16..20 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@20..21 "|" [] [], + name: SvelteName { + ident_token: IDENT@21..27 "global" [] [], + }, + }, + ], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@27..28 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@28..29 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@29..46 "{ duration: 200 }" [] [], + }, + r_curly_token: R_CURLY@46..47 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@47..48 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@48..66 "Global with params" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@66..67 "<" [] [], + slash_token: SLASH@67..68 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@68..71 "div" [] [], + }, + r_angle_token: R_ANGLE@71..72 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@72..74 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@74..76 "p" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@76..86 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@86..87 ":" [] [], + property: SvelteName { + ident_token: IDENT@87..90 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@90..91 "|" [] [], + name: SvelteName { + ident_token: IDENT@91..96 "local" [] [], + }, + }, + ], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@96..97 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@97..98 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@98..108 "{ y: 200 }" [] [], + }, + r_curly_token: R_CURLY@108..109 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@109..110 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@110..127 "Local with params" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@127..128 "<" [] [], + slash_token: SLASH@128..129 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@129..130 "p" [] [], + }, + r_angle_token: R_ANGLE@130..131 ">" [] [], + }, + }, + ], + eof_token: EOF@131..132 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..132 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..131 + 0: HTML_ELEMENT@0..72 + 0: HTML_OPENING_ELEMENT@0..48 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..47 + 0: SVELTE_TRANSITION_DIRECTIVE@5..47 + 0: TRANSITION_KW@5..15 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@15..47 + 0: COLON@15..16 ":" [] [] + 1: SVELTE_NAME@16..20 + 0: IDENT@16..20 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@20..27 + 0: SVELTE_DIRECTIVE_MODIFIER@20..27 + 0: PIPE@20..21 "|" [] [] + 1: SVELTE_NAME@21..27 + 0: IDENT@21..27 "global" [] [] + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@27..47 + 0: EQ@27..28 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@28..47 + 0: L_CURLY@28..29 "{" [] [] + 1: HTML_TEXT_EXPRESSION@29..46 + 0: HTML_LITERAL@29..46 "{ duration: 200 }" [] [] + 2: R_CURLY@46..47 "}" [] [] + 3: R_ANGLE@47..48 ">" [] [] + 1: HTML_ELEMENT_LIST@48..66 + 0: HTML_CONTENT@48..66 + 0: HTML_LITERAL@48..66 "Global with params" [] [] + 2: HTML_CLOSING_ELEMENT@66..72 + 0: L_ANGLE@66..67 "<" [] [] + 1: SLASH@67..68 "/" [] [] + 2: HTML_TAG_NAME@68..71 + 0: HTML_LITERAL@68..71 "div" [] [] + 3: R_ANGLE@71..72 ">" [] [] + 1: HTML_ELEMENT@72..131 + 0: HTML_OPENING_ELEMENT@72..110 + 0: L_ANGLE@72..74 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@74..76 + 0: HTML_LITERAL@74..76 "p" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@76..109 + 0: SVELTE_TRANSITION_DIRECTIVE@76..109 + 0: TRANSITION_KW@76..86 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@86..109 + 0: COLON@86..87 ":" [] [] + 1: SVELTE_NAME@87..90 + 0: IDENT@87..90 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@90..96 + 0: SVELTE_DIRECTIVE_MODIFIER@90..96 + 0: PIPE@90..91 "|" [] [] + 1: SVELTE_NAME@91..96 + 0: IDENT@91..96 "local" [] [] + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@96..109 + 0: EQ@96..97 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@97..109 + 0: L_CURLY@97..98 "{" [] [] + 1: HTML_TEXT_EXPRESSION@98..108 + 0: HTML_LITERAL@98..108 "{ y: 200 }" [] [] + 2: R_CURLY@108..109 "}" [] [] + 3: R_ANGLE@109..110 ">" [] [] + 1: HTML_ELEMENT_LIST@110..127 + 0: HTML_CONTENT@110..127 + 0: HTML_LITERAL@110..127 "Local with params" [] [] + 2: HTML_CLOSING_ELEMENT@127..131 + 0: L_ANGLE@127..128 "<" [] [] + 1: SLASH@128..129 "/" [] [] + 2: HTML_TAG_NAME@129..130 + 0: HTML_LITERAL@129..130 "p" [] [] + 3: R_ANGLE@130..131 ">" [] [] + 4: EOF@131..132 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_multiple_modifiers.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_multiple_modifiers.svelte new file mode 100644 index 000000000000..ebb6d8aa8460 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_multiple_modifiers.svelte @@ -0,0 +1 @@ +
    Multiple modifiers
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_multiple_modifiers.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_multiple_modifiers.svelte.snap new file mode 100644 index 000000000000..10cc5412cfe7 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_multiple_modifiers.svelte.snap @@ -0,0 +1,116 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Multiple modifiers
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@5..15 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@15..16 ":" [] [], + property: SvelteName { + ident_token: IDENT@16..20 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [ + SvelteDirectiveModifier { + bitwise_or_token: PIPE@20..21 "|" [] [], + name: SvelteName { + ident_token: IDENT@21..27 "global" [] [], + }, + }, + SvelteDirectiveModifier { + bitwise_or_token: PIPE@27..28 "|" [] [], + name: SvelteName { + ident_token: IDENT@28..33 "local" [] [], + }, + }, + ], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@33..34 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@34..52 "Multiple modifiers" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@52..53 "<" [] [], + slash_token: SLASH@53..54 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@54..57 "div" [] [], + }, + r_angle_token: R_ANGLE@57..58 ">" [] [], + }, + }, + ], + eof_token: EOF@58..59 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..59 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..58 + 0: HTML_ELEMENT@0..58 + 0: HTML_OPENING_ELEMENT@0..34 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..33 + 0: SVELTE_TRANSITION_DIRECTIVE@5..33 + 0: TRANSITION_KW@5..15 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@15..33 + 0: COLON@15..16 ":" [] [] + 1: SVELTE_NAME@16..20 + 0: IDENT@16..20 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@20..33 + 0: SVELTE_DIRECTIVE_MODIFIER@20..27 + 0: PIPE@20..21 "|" [] [] + 1: SVELTE_NAME@21..27 + 0: IDENT@21..27 "global" [] [] + 1: SVELTE_DIRECTIVE_MODIFIER@27..33 + 0: PIPE@27..28 "|" [] [] + 1: SVELTE_NAME@28..33 + 0: IDENT@28..33 "local" [] [] + 3: (empty) + 3: R_ANGLE@33..34 ">" [] [] + 1: HTML_ELEMENT_LIST@34..52 + 0: HTML_CONTENT@34..52 + 0: HTML_LITERAL@34..52 "Multiple modifiers" [] [] + 2: HTML_CLOSING_ELEMENT@52..58 + 0: L_ANGLE@52..53 "<" [] [] + 1: SLASH@53..54 "/" [] [] + 2: HTML_TAG_NAME@54..57 + 0: HTML_LITERAL@54..57 "div" [] [] + 3: R_ANGLE@57..58 ">" [] [] + 4: EOF@58..59 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_shorthand.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_shorthand.svelte new file mode 100644 index 000000000000..b9e67a212251 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_shorthand.svelte @@ -0,0 +1 @@ +
    Shorthand transition
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_shorthand.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_shorthand.svelte.snap new file mode 100644 index 000000000000..37d35e9f91f8 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_shorthand.svelte.snap @@ -0,0 +1,95 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Shorthand transition
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@5..15 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@15..16 ":" [] [], + property: SvelteName { + ident_token: IDENT@16..20 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@20..21 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@21..41 "Shorthand transition" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@41..42 "<" [] [], + slash_token: SLASH@42..43 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@43..46 "div" [] [], + }, + r_angle_token: R_ANGLE@46..47 ">" [] [], + }, + }, + ], + eof_token: EOF@47..48 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..48 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..47 + 0: HTML_ELEMENT@0..47 + 0: HTML_OPENING_ELEMENT@0..21 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..20 + 0: SVELTE_TRANSITION_DIRECTIVE@5..20 + 0: TRANSITION_KW@5..15 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@15..20 + 0: COLON@15..16 ":" [] [] + 1: SVELTE_NAME@16..20 + 0: IDENT@16..20 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@20..20 + 3: (empty) + 3: R_ANGLE@20..21 ">" [] [] + 1: HTML_ELEMENT_LIST@21..41 + 0: HTML_CONTENT@21..41 + 0: HTML_LITERAL@21..41 "Shorthand transition" [] [] + 2: HTML_CLOSING_ELEMENT@41..47 + 0: L_ANGLE@41..42 "<" [] [] + 1: SLASH@42..43 "/" [] [] + 2: HTML_TAG_NAME@43..46 + 0: HTML_LITERAL@43..46 "div" [] [] + 3: R_ANGLE@46..47 ">" [] [] + 4: EOF@47..48 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_with_params.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_with_params.svelte new file mode 100644 index 000000000000..ccdec0b1c181 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_with_params.svelte @@ -0,0 +1,2 @@ +
    Slow fade
    +

    Flies in

    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_with_params.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_with_params.svelte.snap new file mode 100644 index 000000000000..1d02f4ddeb2b --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/transition_with_params.svelte.snap @@ -0,0 +1,185 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Slow fade
    +

    Flies in

    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@5..15 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@15..16 ":" [] [], + property: SvelteName { + ident_token: IDENT@16..20 "fade" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@20..21 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@21..22 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@22..39 "{ duration: 200 }" [] [], + }, + r_curly_token: R_CURLY@39..40 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@40..41 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@41..50 "Slow fade" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@50..51 "<" [] [], + slash_token: SLASH@51..52 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@52..55 "div" [] [], + }, + r_angle_token: R_ANGLE@55..56 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@56..58 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@58..60 "p" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteTransitionDirective { + transition_token: TRANSITION_KW@60..70 "transition" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@70..71 ":" [] [], + property: SvelteName { + ident_token: IDENT@71..74 "fly" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@74..75 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@75..76 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@76..102 "{ y: 200, duration: 2000 }" [] [], + }, + r_curly_token: R_CURLY@102..103 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@103..104 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@104..112 "Flies in" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@112..113 "<" [] [], + slash_token: SLASH@113..114 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@114..115 "p" [] [], + }, + r_angle_token: R_ANGLE@115..116 ">" [] [], + }, + }, + ], + eof_token: EOF@116..117 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..117 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..116 + 0: HTML_ELEMENT@0..56 + 0: HTML_OPENING_ELEMENT@0..41 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..40 + 0: SVELTE_TRANSITION_DIRECTIVE@5..40 + 0: TRANSITION_KW@5..15 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@15..40 + 0: COLON@15..16 ":" [] [] + 1: SVELTE_NAME@16..20 + 0: IDENT@16..20 "fade" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@20..20 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@20..40 + 0: EQ@20..21 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@21..40 + 0: L_CURLY@21..22 "{" [] [] + 1: HTML_TEXT_EXPRESSION@22..39 + 0: HTML_LITERAL@22..39 "{ duration: 200 }" [] [] + 2: R_CURLY@39..40 "}" [] [] + 3: R_ANGLE@40..41 ">" [] [] + 1: HTML_ELEMENT_LIST@41..50 + 0: HTML_CONTENT@41..50 + 0: HTML_LITERAL@41..50 "Slow fade" [] [] + 2: HTML_CLOSING_ELEMENT@50..56 + 0: L_ANGLE@50..51 "<" [] [] + 1: SLASH@51..52 "/" [] [] + 2: HTML_TAG_NAME@52..55 + 0: HTML_LITERAL@52..55 "div" [] [] + 3: R_ANGLE@55..56 ">" [] [] + 1: HTML_ELEMENT@56..116 + 0: HTML_OPENING_ELEMENT@56..104 + 0: L_ANGLE@56..58 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@58..60 + 0: HTML_LITERAL@58..60 "p" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@60..103 + 0: SVELTE_TRANSITION_DIRECTIVE@60..103 + 0: TRANSITION_KW@60..70 "transition" [] [] + 1: SVELTE_DIRECTIVE_VALUE@70..103 + 0: COLON@70..71 ":" [] [] + 1: SVELTE_NAME@71..74 + 0: IDENT@71..74 "fly" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@74..74 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@74..103 + 0: EQ@74..75 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@75..103 + 0: L_CURLY@75..76 "{" [] [] + 1: HTML_TEXT_EXPRESSION@76..102 + 0: HTML_LITERAL@76..102 "{ y: 200, duration: 2000 }" [] [] + 2: R_CURLY@102..103 "}" [] [] + 3: R_ANGLE@103..104 ">" [] [] + 1: HTML_ELEMENT_LIST@104..112 + 0: HTML_CONTENT@104..112 + 0: HTML_LITERAL@104..112 "Flies in" [] [] + 2: HTML_CLOSING_ELEMENT@112..116 + 0: L_ANGLE@112..113 "<" [] [] + 1: SLASH@113..114 "/" [] [] + 2: HTML_TAG_NAME@114..115 + 0: HTML_LITERAL@114..115 "p" [] [] + 3: R_ANGLE@115..116 ">" [] [] + 4: EOF@116..117 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_basic.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_basic.svelte new file mode 100644 index 000000000000..a7c33e7f136e --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_basic.svelte @@ -0,0 +1 @@ +
    Hover me
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_basic.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_basic.svelte.snap new file mode 100644 index 000000000000..cee933d76c54 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_basic.svelte.snap @@ -0,0 +1,95 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Hover me
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteUseDirective { + use_token: USE_KW@5..8 "use" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: SvelteName { + ident_token: IDENT@9..16 "tooltip" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@16..17 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@17..25 "Hover me" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@25..26 "<" [] [], + slash_token: SLASH@26..27 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@27..30 "div" [] [], + }, + r_angle_token: R_ANGLE@30..31 ">" [] [], + }, + }, + ], + eof_token: EOF@31..32 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..32 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..31 + 0: HTML_ELEMENT@0..31 + 0: HTML_OPENING_ELEMENT@0..17 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..16 + 0: SVELTE_USE_DIRECTIVE@5..16 + 0: USE_KW@5..8 "use" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..16 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..16 + 0: IDENT@9..16 "tooltip" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..16 + 3: (empty) + 3: R_ANGLE@16..17 ">" [] [] + 1: HTML_ELEMENT_LIST@17..25 + 0: HTML_CONTENT@17..25 + 0: HTML_LITERAL@17..25 "Hover me" [] [] + 2: HTML_CLOSING_ELEMENT@25..31 + 0: L_ANGLE@25..26 "<" [] [] + 1: SLASH@26..27 "/" [] [] + 2: HTML_TAG_NAME@27..30 + 0: HTML_LITERAL@27..30 "div" [] [] + 3: R_ANGLE@30..31 ">" [] [] + 4: EOF@31..32 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_multiple.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_multiple.svelte new file mode 100644 index 000000000000..efd2e321b52d --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_multiple.svelte @@ -0,0 +1,3 @@ +
    + Multiple actions +
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_multiple.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_multiple.svelte.snap new file mode 100644 index 000000000000..c7e0178bdd3e --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_multiple.svelte.snap @@ -0,0 +1,150 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    + Multiple actions +
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteUseDirective { + use_token: USE_KW@5..8 "use" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: SvelteName { + ident_token: IDENT@9..17 "tooltip" [] [Whitespace(" ")], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + SvelteUseDirective { + use_token: USE_KW@17..20 "use" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@20..21 ":" [] [], + property: SvelteName { + ident_token: IDENT@21..34 "clickOutside" [] [Whitespace(" ")], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + SvelteUseDirective { + use_token: USE_KW@34..37 "use" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@37..38 ":" [] [], + property: SvelteName { + ident_token: IDENT@38..47 "draggable" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@47..48 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@48..49 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@49..60 "dragOptions" [] [], + }, + r_curly_token: R_CURLY@60..61 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@61..62 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@62..81 "Multiple actions" [Newline("\n"), Whitespace(" ")] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@81..83 "<" [Newline("\n")] [], + slash_token: SLASH@83..84 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@84..87 "div" [] [], + }, + r_angle_token: R_ANGLE@87..88 ">" [] [], + }, + }, + ], + eof_token: EOF@88..89 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..89 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..88 + 0: HTML_ELEMENT@0..88 + 0: HTML_OPENING_ELEMENT@0..62 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..61 + 0: SVELTE_USE_DIRECTIVE@5..17 + 0: USE_KW@5..8 "use" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..17 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..17 + 0: IDENT@9..17 "tooltip" [] [Whitespace(" ")] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@17..17 + 3: (empty) + 1: SVELTE_USE_DIRECTIVE@17..34 + 0: USE_KW@17..20 "use" [] [] + 1: SVELTE_DIRECTIVE_VALUE@20..34 + 0: COLON@20..21 ":" [] [] + 1: SVELTE_NAME@21..34 + 0: IDENT@21..34 "clickOutside" [] [Whitespace(" ")] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@34..34 + 3: (empty) + 2: SVELTE_USE_DIRECTIVE@34..61 + 0: USE_KW@34..37 "use" [] [] + 1: SVELTE_DIRECTIVE_VALUE@37..61 + 0: COLON@37..38 ":" [] [] + 1: SVELTE_NAME@38..47 + 0: IDENT@38..47 "draggable" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@47..47 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@47..61 + 0: EQ@47..48 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@48..61 + 0: L_CURLY@48..49 "{" [] [] + 1: HTML_TEXT_EXPRESSION@49..60 + 0: HTML_LITERAL@49..60 "dragOptions" [] [] + 2: R_CURLY@60..61 "}" [] [] + 3: R_ANGLE@61..62 ">" [] [] + 1: HTML_ELEMENT_LIST@62..81 + 0: HTML_CONTENT@62..81 + 0: HTML_LITERAL@62..81 "Multiple actions" [Newline("\n"), Whitespace(" ")] [] + 2: HTML_CLOSING_ELEMENT@81..88 + 0: L_ANGLE@81..83 "<" [Newline("\n")] [] + 1: SLASH@83..84 "/" [] [] + 2: HTML_TAG_NAME@84..87 + 0: HTML_LITERAL@84..87 "div" [] [] + 3: R_ANGLE@87..88 ">" [] [] + 4: EOF@88..89 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_shorthand.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_shorthand.svelte new file mode 100644 index 000000000000..ccd9124fec3a --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_shorthand.svelte @@ -0,0 +1 @@ +
    Click outside me
    diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_shorthand.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_shorthand.svelte.snap new file mode 100644 index 000000000000..7bacd7f6eced --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_shorthand.svelte.snap @@ -0,0 +1,95 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Click outside me
    + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteUseDirective { + use_token: USE_KW@5..8 "use" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: SvelteName { + ident_token: IDENT@9..21 "clickOutside" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: missing (optional), + }, + }, + ], + r_angle_token: R_ANGLE@21..22 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@22..38 "Click outside me" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@38..39 "<" [] [], + slash_token: SLASH@39..40 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@40..43 "div" [] [], + }, + r_angle_token: R_ANGLE@43..44 ">" [] [], + }, + }, + ], + eof_token: EOF@44..45 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..45 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..44 + 0: HTML_ELEMENT@0..44 + 0: HTML_OPENING_ELEMENT@0..22 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..21 + 0: SVELTE_USE_DIRECTIVE@5..21 + 0: USE_KW@5..8 "use" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..21 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..21 + 0: IDENT@9..21 "clickOutside" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@21..21 + 3: (empty) + 3: R_ANGLE@21..22 ">" [] [] + 1: HTML_ELEMENT_LIST@22..38 + 0: HTML_CONTENT@22..38 + 0: HTML_LITERAL@22..38 "Click outside me" [] [] + 2: HTML_CLOSING_ELEMENT@38..44 + 0: L_ANGLE@38..39 "<" [] [] + 1: SLASH@39..40 "/" [] [] + 2: HTML_TAG_NAME@40..43 + 0: HTML_LITERAL@40..43 "div" [] [] + 3: R_ANGLE@43..44 ">" [] [] + 4: EOF@44..45 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_with_param.svelte b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_with_param.svelte new file mode 100644 index 000000000000..3380ac10e9b7 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_with_param.svelte @@ -0,0 +1,2 @@ +
    Hover me
    + diff --git a/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_with_param.svelte.snap b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_with_param.svelte.snap new file mode 100644 index 000000000000..29b7b72b6f44 --- /dev/null +++ b/crates/biome_html_parser/tests/html_specs/ok/svelte/directives/use_with_param.svelte.snap @@ -0,0 +1,185 @@ +--- +source: crates/biome_html_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```svelte +
    Hover me
    + + +``` + + +## 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..5 "div" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteUseDirective { + use_token: USE_KW@5..8 "use" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@8..9 ":" [] [], + property: SvelteName { + ident_token: IDENT@9..16 "tooltip" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@16..17 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@17..18 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@18..25 "options" [] [], + }, + r_curly_token: R_CURLY@25..26 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@26..27 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@27..35 "Hover me" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@35..36 "<" [] [], + slash_token: SLASH@36..37 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@37..40 "div" [] [], + }, + r_angle_token: R_ANGLE@40..41 ">" [] [], + }, + }, + HtmlElement { + opening_element: HtmlOpeningElement { + l_angle_token: L_ANGLE@41..43 "<" [Newline("\n")] [], + name: HtmlTagName { + value_token: HTML_LITERAL@43..50 "button" [] [Whitespace(" ")], + }, + attributes: HtmlAttributeList [ + SvelteUseDirective { + use_token: USE_KW@50..53 "use" [] [], + value: SvelteDirectiveValue { + colon_token: COLON@53..54 ":" [] [], + property: SvelteName { + ident_token: IDENT@54..63 "longpress" [] [], + }, + modifiers: SvelteDirectiveModifierList [], + initializer: HtmlAttributeInitializerClause { + eq_token: EQ@63..64 "=" [] [], + value: HtmlSingleTextExpression { + l_curly_token: L_CURLY@64..65 "{" [] [], + expression: HtmlTextExpression { + html_literal_token: HTML_LITERAL@65..73 "duration" [] [], + }, + r_curly_token: R_CURLY@73..74 "}" [] [], + }, + }, + }, + }, + ], + r_angle_token: R_ANGLE@74..75 ">" [] [], + }, + children: HtmlElementList [ + HtmlContent { + value_token: HTML_LITERAL@75..83 "Press me" [] [], + }, + ], + closing_element: HtmlClosingElement { + l_angle_token: L_ANGLE@83..84 "<" [] [], + slash_token: SLASH@84..85 "/" [] [], + name: HtmlTagName { + value_token: HTML_LITERAL@85..91 "button" [] [], + }, + r_angle_token: R_ANGLE@91..92 ">" [] [], + }, + }, + ], + eof_token: EOF@92..93 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: HTML_ROOT@0..93 + 0: (empty) + 1: (empty) + 2: (empty) + 3: HTML_ELEMENT_LIST@0..92 + 0: HTML_ELEMENT@0..41 + 0: HTML_OPENING_ELEMENT@0..27 + 0: L_ANGLE@0..1 "<" [] [] + 1: HTML_TAG_NAME@1..5 + 0: HTML_LITERAL@1..5 "div" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@5..26 + 0: SVELTE_USE_DIRECTIVE@5..26 + 0: USE_KW@5..8 "use" [] [] + 1: SVELTE_DIRECTIVE_VALUE@8..26 + 0: COLON@8..9 ":" [] [] + 1: SVELTE_NAME@9..16 + 0: IDENT@9..16 "tooltip" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@16..16 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@16..26 + 0: EQ@16..17 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@17..26 + 0: L_CURLY@17..18 "{" [] [] + 1: HTML_TEXT_EXPRESSION@18..25 + 0: HTML_LITERAL@18..25 "options" [] [] + 2: R_CURLY@25..26 "}" [] [] + 3: R_ANGLE@26..27 ">" [] [] + 1: HTML_ELEMENT_LIST@27..35 + 0: HTML_CONTENT@27..35 + 0: HTML_LITERAL@27..35 "Hover me" [] [] + 2: HTML_CLOSING_ELEMENT@35..41 + 0: L_ANGLE@35..36 "<" [] [] + 1: SLASH@36..37 "/" [] [] + 2: HTML_TAG_NAME@37..40 + 0: HTML_LITERAL@37..40 "div" [] [] + 3: R_ANGLE@40..41 ">" [] [] + 1: HTML_ELEMENT@41..92 + 0: HTML_OPENING_ELEMENT@41..75 + 0: L_ANGLE@41..43 "<" [Newline("\n")] [] + 1: HTML_TAG_NAME@43..50 + 0: HTML_LITERAL@43..50 "button" [] [Whitespace(" ")] + 2: HTML_ATTRIBUTE_LIST@50..74 + 0: SVELTE_USE_DIRECTIVE@50..74 + 0: USE_KW@50..53 "use" [] [] + 1: SVELTE_DIRECTIVE_VALUE@53..74 + 0: COLON@53..54 ":" [] [] + 1: SVELTE_NAME@54..63 + 0: IDENT@54..63 "longpress" [] [] + 2: SVELTE_DIRECTIVE_MODIFIER_LIST@63..63 + 3: HTML_ATTRIBUTE_INITIALIZER_CLAUSE@63..74 + 0: EQ@63..64 "=" [] [] + 1: HTML_SINGLE_TEXT_EXPRESSION@64..74 + 0: L_CURLY@64..65 "{" [] [] + 1: HTML_TEXT_EXPRESSION@65..73 + 0: HTML_LITERAL@65..73 "duration" [] [] + 2: R_CURLY@73..74 "}" [] [] + 3: R_ANGLE@74..75 ">" [] [] + 1: HTML_ELEMENT_LIST@75..83 + 0: HTML_CONTENT@75..83 + 0: HTML_LITERAL@75..83 "Press me" [] [] + 2: HTML_CLOSING_ELEMENT@83..92 + 0: L_ANGLE@83..84 "<" [] [] + 1: SLASH@84..85 "/" [] [] + 2: HTML_TAG_NAME@85..91 + 0: HTML_LITERAL@85..91 "button" [] [] + 3: R_ANGLE@91..92 ">" [] [] + 4: EOF@92..93 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_html_parser/tests/quick_test.rs b/crates/biome_html_parser/tests/quick_test.rs index 4b8d6a99f5ce..d7c1b68dab45 100644 --- a/crates/biome_html_parser/tests/quick_test.rs +++ b/crates/biome_html_parser/tests/quick_test.rs @@ -4,7 +4,8 @@ use biome_test_utils::has_bogus_nodes_or_empty_slots; #[ignore] #[test] pub fn quick_test() { - let code = r#"{#each products as {id, ...title}}{/each} + let code = r#"

    Multiple shorthand

    + "#; diff --git a/crates/biome_html_syntax/src/attr_ext.rs b/crates/biome_html_syntax/src/attr_ext.rs index 03ac73ef25d3..5734ea10d26b 100644 --- a/crates/biome_html_syntax/src/attr_ext.rs +++ b/crates/biome_html_syntax/src/attr_ext.rs @@ -8,7 +8,7 @@ impl AnyHtmlAttributeInitializer { /// Returns the string value of the attribute, if available, without quotes. pub fn string_value(&self) -> Option { match self { - Self::HtmlSingleTextExpression(_) => None, + Self::HtmlSingleTextExpression(text) => text.expression().ok()?.string_value(), Self::HtmlString(string) => Some( string .value_token() diff --git a/crates/biome_html_syntax/src/generated/kind.rs b/crates/biome_html_syntax/src/generated/kind.rs index ca66aca4ff17..1ed89eb97344 100644 --- a/crates/biome_html_syntax/src/generated/kind.rs +++ b/crates/biome_html_syntax/src/generated/kind.rs @@ -39,6 +39,7 @@ pub enum HtmlSyntaxKind { L_PAREN, R_PAREN, DOT3, + PIPE, NULL_KW, TRUE_KW, FALSE_KW, @@ -57,6 +58,14 @@ pub enum HtmlSyntaxKind { AWAIT_KW, CATCH_KW, SNIPPET_KW, + BIND_KW, + TRANSITION_KW, + USE_KW, + ANIMATE_KW, + IN_KW, + OUT_KW, + STYLE_KW, + CLASS_KW, HTML_STRING_LITERAL, HTML_LITERAL, ERROR_TOKEN, @@ -124,6 +133,18 @@ pub enum HtmlSyntaxKind { SVELTE_SQUARE_DESTRUCTURED_NAME, SVELTE_BINDING_ASSIGNMENT_BINDING_LIST, SVELTE_REST_BINDING, + SVELTE_BIND_DIRECTIVE, + SVELTE_TRANSITION_DIRECTIVE, + SVELTE_IN_DIRECTIVE, + SVELTE_OUT_DIRECTIVE, + SVELTE_USE_DIRECTIVE, + SVELTE_ANIMATE_DIRECTIVE, + SVELTE_STYLE_DIRECTIVE, + SVELTE_CLASS_DIRECTIVE, + SVELTE_DIRECTIVE_VALUE, + SVELTE_DIRECTIVE_MODIFIER, + SVELTE_DIRECTIVE_MODIFIER_LIST, + SVELTE_LITERAL, VUE_DIRECTIVE, VUE_DIRECTIVE_ARGUMENT, VUE_V_BIND_SHORTHAND_DIRECTIVE, @@ -176,6 +197,7 @@ impl HtmlSyntaxKind { | L_PAREN | R_PAREN | DOT3 + | PIPE ) } pub const fn is_literal(self) -> bool { @@ -190,6 +212,7 @@ impl HtmlSyntaxKind { | SVELTE_ELSE_IF_CLAUSE_LIST | SVELTE_AWAIT_CLAUSES_LIST | SVELTE_BINDING_ASSIGNMENT_BINDING_LIST + | SVELTE_DIRECTIVE_MODIFIER_LIST | VUE_MODIFIER_LIST ) } @@ -213,6 +236,14 @@ impl HtmlSyntaxKind { "await" => AWAIT_KW, "catch" => CATCH_KW, "snippet" => SNIPPET_KW, + "bind" => BIND_KW, + "transition" => TRANSITION_KW, + "use" => USE_KW, + "animate" => ANIMATE_KW, + "in" => IN_KW, + "out" => OUT_KW, + "style" => STYLE_KW, + "class" => CLASS_KW, _ => return None, }; Some(kw) @@ -246,6 +277,7 @@ impl HtmlSyntaxKind { L_PAREN => "(", R_PAREN => ")", DOT3 => "...", + PIPE => "|", NULL_KW => "null", TRUE_KW => "true", FALSE_KW => "false", @@ -264,6 +296,14 @@ impl HtmlSyntaxKind { AWAIT_KW => "await", CATCH_KW => "catch", SNIPPET_KW => "snippet", + BIND_KW => "bind", + TRANSITION_KW => "transition", + USE_KW => "use", + ANIMATE_KW => "animate", + IN_KW => "in", + OUT_KW => "out", + STYLE_KW => "style", + CLASS_KW => "class", EOF => "EOF", HTML_STRING_LITERAL => "string literal", _ => return None, @@ -273,4 +313,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 } ; [:] => { $ crate :: HtmlSyntaxKind :: COLON } ; [@] => { $ crate :: HtmlSyntaxKind :: AT } ; [.] => { $ crate :: HtmlSyntaxKind :: DOT } ; ['['] => { $ crate :: HtmlSyntaxKind :: L_BRACKET } ; [']'] => { $ crate :: HtmlSyntaxKind :: R_BRACKET } ; [#] => { $ crate :: HtmlSyntaxKind :: HASH } ; ['('] => { $ crate :: HtmlSyntaxKind :: L_PAREN } ; [')'] => { $ crate :: HtmlSyntaxKind :: R_PAREN } ; [...] => { $ crate :: HtmlSyntaxKind :: DOT3 } ; [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 } ; [key] => { $ crate :: HtmlSyntaxKind :: KEY_KW } ; [render] => { $ crate :: HtmlSyntaxKind :: RENDER_KW } ; [const] => { $ crate :: HtmlSyntaxKind :: CONST_KW } ; [attach] => { $ crate :: HtmlSyntaxKind :: ATTACH_KW } ; [else] => { $ crate :: HtmlSyntaxKind :: ELSE_KW } ; [if] => { $ crate :: HtmlSyntaxKind :: IF_KW } ; [as] => { $ crate :: HtmlSyntaxKind :: AS_KW } ; [each] => { $ crate :: HtmlSyntaxKind :: EACH_KW } ; [then] => { $ crate :: HtmlSyntaxKind :: THEN_KW } ; [await] => { $ crate :: HtmlSyntaxKind :: AWAIT_KW } ; [catch] => { $ crate :: HtmlSyntaxKind :: CATCH_KW } ; [snippet] => { $ crate :: HtmlSyntaxKind :: SNIPPET_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 :: COLON } ; [@] => { $ crate :: HtmlSyntaxKind :: AT } ; [.] => { $ crate :: HtmlSyntaxKind :: DOT } ; ['['] => { $ crate :: HtmlSyntaxKind :: L_BRACKET } ; [']'] => { $ crate :: HtmlSyntaxKind :: R_BRACKET } ; [#] => { $ crate :: HtmlSyntaxKind :: HASH } ; ['('] => { $ crate :: HtmlSyntaxKind :: L_PAREN } ; [')'] => { $ crate :: HtmlSyntaxKind :: R_PAREN } ; [...] => { $ crate :: HtmlSyntaxKind :: DOT3 } ; [|] => { $ crate :: HtmlSyntaxKind :: PIPE } ; [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 } ; [key] => { $ crate :: HtmlSyntaxKind :: KEY_KW } ; [render] => { $ crate :: HtmlSyntaxKind :: RENDER_KW } ; [const] => { $ crate :: HtmlSyntaxKind :: CONST_KW } ; [attach] => { $ crate :: HtmlSyntaxKind :: ATTACH_KW } ; [else] => { $ crate :: HtmlSyntaxKind :: ELSE_KW } ; [if] => { $ crate :: HtmlSyntaxKind :: IF_KW } ; [as] => { $ crate :: HtmlSyntaxKind :: AS_KW } ; [each] => { $ crate :: HtmlSyntaxKind :: EACH_KW } ; [then] => { $ crate :: HtmlSyntaxKind :: THEN_KW } ; [await] => { $ crate :: HtmlSyntaxKind :: AWAIT_KW } ; [catch] => { $ crate :: HtmlSyntaxKind :: CATCH_KW } ; [snippet] => { $ crate :: HtmlSyntaxKind :: SNIPPET_KW } ; [bind] => { $ crate :: HtmlSyntaxKind :: BIND_KW } ; [transition] => { $ crate :: HtmlSyntaxKind :: TRANSITION_KW } ; [use] => { $ crate :: HtmlSyntaxKind :: USE_KW } ; [animate] => { $ crate :: HtmlSyntaxKind :: ANIMATE_KW } ; [in] => { $ crate :: HtmlSyntaxKind :: IN_KW } ; [out] => { $ crate :: HtmlSyntaxKind :: OUT_KW } ; [style] => { $ crate :: HtmlSyntaxKind :: STYLE_KW } ; [class] => { $ crate :: HtmlSyntaxKind :: CLASS_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 aeaa28ceff97..87099a4cdfd1 100644 --- a/crates/biome_html_syntax/src/generated/macros.rs +++ b/crates/biome_html_syntax/src/generated/macros.rs @@ -93,6 +93,10 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::HtmlTextExpression::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::SVELTE_ANIMATE_DIRECTIVE => { + let $pattern = unsafe { $crate::SvelteAnimateDirective::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::SVELTE_ATTACH_ATTRIBUTE => { let $pattern = unsafe { $crate::SvelteAttachAttribute::new_unchecked(node) }; $body @@ -125,6 +129,14 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::SvelteAwaitThenClause::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::SVELTE_BIND_DIRECTIVE => { + let $pattern = unsafe { $crate::SvelteBindDirective::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::SVELTE_CLASS_DIRECTIVE => { + let $pattern = unsafe { $crate::SvelteClassDirective::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::SVELTE_CONST_BLOCK => { let $pattern = unsafe { $crate::SvelteConstBlock::new_unchecked(node) }; $body @@ -138,6 +150,14 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::SvelteDebugBlock::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::SVELTE_DIRECTIVE_MODIFIER => { + let $pattern = unsafe { $crate::SvelteDirectiveModifier::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::SVELTE_DIRECTIVE_VALUE => { + let $pattern = unsafe { $crate::SvelteDirectiveValue::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::SVELTE_EACH_AS_KEYED_ITEM => { let $pattern = unsafe { $crate::SvelteEachAsKeyedItem::new_unchecked(node) }; $body @@ -190,6 +210,10 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::SvelteIfOpeningBlock::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::SVELTE_IN_DIRECTIVE => { + let $pattern = unsafe { $crate::SvelteInDirective::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::SVELTE_KEY_BLOCK => { let $pattern = unsafe { $crate::SvelteKeyBlock::new_unchecked(node) }; $body @@ -202,10 +226,18 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::SvelteKeyOpeningBlock::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::SVELTE_LITERAL => { + let $pattern = unsafe { $crate::SvelteLiteral::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::SVELTE_NAME => { let $pattern = unsafe { $crate::SvelteName::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::SVELTE_OUT_DIRECTIVE => { + let $pattern = unsafe { $crate::SvelteOutDirective::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::SVELTE_RENDER_BLOCK => { let $pattern = unsafe { $crate::SvelteRenderBlock::new_unchecked(node) }; $body @@ -233,6 +265,19 @@ macro_rules! map_syntax_node { unsafe { $crate::SvelteSquareDestructuredName::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::SVELTE_STYLE_DIRECTIVE => { + let $pattern = unsafe { $crate::SvelteStyleDirective::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::SVELTE_TRANSITION_DIRECTIVE => { + let $pattern = + unsafe { $crate::SvelteTransitionDirective::new_unchecked(node) }; + $body + } + $crate::HtmlSyntaxKind::SVELTE_USE_DIRECTIVE => { + let $pattern = unsafe { $crate::SvelteUseDirective::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::VUE_DIRECTIVE => { let $pattern = unsafe { $crate::VueDirective::new_unchecked(node) }; $body @@ -321,6 +366,11 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::SvelteBindingList::new_unchecked(node) }; $body } + $crate::HtmlSyntaxKind::SVELTE_DIRECTIVE_MODIFIER_LIST => { + let $pattern = + unsafe { $crate::SvelteDirectiveModifierList::new_unchecked(node) }; + $body + } $crate::HtmlSyntaxKind::SVELTE_ELSE_IF_CLAUSE_LIST => { let $pattern = unsafe { $crate::SvelteElseIfClauseList::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 ce428af4700c..bfd6abf11fd1 100644 --- a/crates/biome_html_syntax/src/generated/nodes.rs +++ b/crates/biome_html_syntax/src/generated/nodes.rs @@ -850,6 +850,46 @@ pub struct HtmlTextExpressionFields { pub html_literal_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteAnimateDirective { + pub(crate) syntax: SyntaxNode, +} +impl SvelteAnimateDirective { + #[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) -> SvelteAnimateDirectiveFields { + SvelteAnimateDirectiveFields { + animate_token: self.animate_token(), + value: self.value(), + } + } + pub fn animate_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for SvelteAnimateDirective { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteAnimateDirectiveFields { + pub animate_token: SyntaxResult, + pub value: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct SvelteAttachAttribute { pub(crate) syntax: SyntaxNode, } @@ -1245,6 +1285,86 @@ pub struct SvelteAwaitThenClauseFields { pub name: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteBindDirective { + pub(crate) syntax: SyntaxNode, +} +impl SvelteBindDirective { + #[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) -> SvelteBindDirectiveFields { + SvelteBindDirectiveFields { + bind_token: self.bind_token(), + value: self.value(), + } + } + pub fn bind_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for SvelteBindDirective { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteBindDirectiveFields { + pub bind_token: SyntaxResult, + pub value: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteClassDirective { + pub(crate) syntax: SyntaxNode, +} +impl SvelteClassDirective { + #[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) -> SvelteClassDirectiveFields { + SvelteClassDirectiveFields { + class_token: self.class_token(), + value: self.value(), + } + } + pub fn class_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for SvelteClassDirective { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteClassDirectiveFields { + pub class_token: SyntaxResult, + pub value: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct SvelteConstBlock { pub(crate) syntax: SyntaxNode, } @@ -1390,6 +1510,96 @@ pub struct SvelteDebugBlockFields { pub r_curly_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteDirectiveModifier { + pub(crate) syntax: SyntaxNode, +} +impl SvelteDirectiveModifier { + #[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) -> SvelteDirectiveModifierFields { + SvelteDirectiveModifierFields { + bitwise_or_token: self.bitwise_or_token(), + name: self.name(), + } + } + pub fn bitwise_or_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn name(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for SvelteDirectiveModifier { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteDirectiveModifierFields { + pub bitwise_or_token: SyntaxResult, + pub name: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteDirectiveValue { + pub(crate) syntax: SyntaxNode, +} +impl SvelteDirectiveValue { + #[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) -> SvelteDirectiveValueFields { + SvelteDirectiveValueFields { + colon_token: self.colon_token(), + property: self.property(), + modifiers: self.modifiers(), + initializer: self.initializer(), + } + } + pub fn colon_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn property(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } + pub fn modifiers(&self) -> SvelteDirectiveModifierList { + support::list(&self.syntax, 2usize) + } + pub fn initializer(&self) -> Option { + support::node(&self.syntax, 3usize) + } +} +impl Serialize for SvelteDirectiveValue { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteDirectiveValueFields { + pub colon_token: SyntaxResult, + pub property: SyntaxResult, + pub modifiers: SvelteDirectiveModifierList, + pub initializer: Option, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct SvelteEachAsKeyedItem { pub(crate) syntax: SyntaxNode, } @@ -2020,6 +2230,46 @@ pub struct SvelteIfOpeningBlockFields { pub children: HtmlElementList, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteInDirective { + pub(crate) syntax: SyntaxNode, +} +impl SvelteInDirective { + #[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) -> SvelteInDirectiveFields { + SvelteInDirectiveFields { + in_token: self.in_token(), + value: self.value(), + } + } + pub fn in_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for SvelteInDirective { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteInDirectiveFields { + pub in_token: SyntaxResult, + pub value: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct SvelteKeyBlock { pub(crate) syntax: SyntaxNode, } @@ -2160,6 +2410,41 @@ pub struct SvelteKeyOpeningBlockFields { pub r_curly_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteLiteral { + pub(crate) syntax: SyntaxNode, +} +impl SvelteLiteral { + #[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) -> SvelteLiteralFields { + SvelteLiteralFields { + value_token: self.value_token(), + } + } + pub fn value_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +impl Serialize for SvelteLiteral { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteLiteralFields { + pub value_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct SvelteName { pub(crate) syntax: SyntaxNode, } @@ -2195,6 +2480,46 @@ pub struct SvelteNameFields { pub ident_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteOutDirective { + pub(crate) syntax: SyntaxNode, +} +impl SvelteOutDirective { + #[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) -> SvelteOutDirectiveFields { + SvelteOutDirectiveFields { + out_token: self.out_token(), + value: self.value(), + } + } + pub fn out_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for SvelteOutDirective { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteOutDirectiveFields { + pub out_token: SyntaxResult, + pub value: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct SvelteRenderBlock { pub(crate) syntax: SyntaxNode, } @@ -2470,10 +2795,10 @@ pub struct SvelteSquareDestructuredNameFields { pub r_brack_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct VueDirective { +pub struct SvelteStyleDirective { pub(crate) syntax: SyntaxNode, } -impl VueDirective { +impl SvelteStyleDirective { #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] #[doc = r""] #[doc = r" # Safety"] @@ -2483,19 +2808,139 @@ impl VueDirective { pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { Self { syntax } } - pub fn as_fields(&self) -> VueDirectiveFields { - VueDirectiveFields { - name_token: self.name_token(), - arg: self.arg(), - modifiers: self.modifiers(), - initializer: self.initializer(), + pub fn as_fields(&self) -> SvelteStyleDirectiveFields { + SvelteStyleDirectiveFields { + style_token: self.style_token(), + value: self.value(), } } - pub fn name_token(&self) -> SyntaxResult { + pub fn style_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn arg(&self) -> Option { - support::node(&self.syntax, 1usize) + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for SvelteStyleDirective { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteStyleDirectiveFields { + pub style_token: SyntaxResult, + pub value: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteTransitionDirective { + pub(crate) syntax: SyntaxNode, +} +impl SvelteTransitionDirective { + #[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) -> SvelteTransitionDirectiveFields { + SvelteTransitionDirectiveFields { + transition_token: self.transition_token(), + value: self.value(), + } + } + pub fn transition_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for SvelteTransitionDirective { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteTransitionDirectiveFields { + pub transition_token: SyntaxResult, + pub value: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct SvelteUseDirective { + pub(crate) syntax: SyntaxNode, +} +impl SvelteUseDirective { + #[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) -> SvelteUseDirectiveFields { + SvelteUseDirectiveFields { + use_token: self.use_token(), + value: self.value(), + } + } + pub fn use_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn value(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for SvelteUseDirective { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct SvelteUseDirectiveFields { + pub use_token: SyntaxResult, + pub value: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct VueDirective { + pub(crate) syntax: SyntaxNode, +} +impl VueDirective { + #[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) -> VueDirectiveFields { + VueDirectiveFields { + name_token: self.name_token(), + arg: self.arg(), + modifiers: self.modifiers(), + initializer: self.initializer(), + } + } + pub fn name_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn arg(&self) -> Option { + support::node(&self.syntax, 1usize) } pub fn modifiers(&self) -> VueModifierList { support::list(&self.syntax, 2usize) @@ -2845,6 +3290,7 @@ impl AnyAstroFrontmatterElement { } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyHtmlAttribute { + AnySvelteDirective(AnySvelteDirective), AnyVueDirective(AnyVueDirective), HtmlAttribute(HtmlAttribute), HtmlBogusAttribute(HtmlBogusAttribute), @@ -2853,6 +3299,12 @@ pub enum AnyHtmlAttribute { SvelteAttachAttribute(SvelteAttachAttribute), } impl AnyHtmlAttribute { + pub fn as_any_svelte_directive(&self) -> Option<&AnySvelteDirective> { + match &self { + Self::AnySvelteDirective(item) => Some(item), + _ => None, + } + } pub fn as_any_vue_directive(&self) -> Option<&AnyVueDirective> { match &self { Self::AnyVueDirective(item) => Some(item), @@ -3054,6 +3506,25 @@ impl AnySvelteBindingAssignmentBinding { } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnySvelteBindingProperty { + SvelteLiteral(SvelteLiteral), + SvelteName(SvelteName), +} +impl AnySvelteBindingProperty { + pub fn as_svelte_literal(&self) -> Option<&SvelteLiteral> { + match &self { + Self::SvelteLiteral(item) => Some(item), + _ => None, + } + } + pub fn as_svelte_name(&self) -> Option<&SvelteName> { + match &self { + Self::SvelteName(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnySvelteBlock { SvelteAwaitBlock(SvelteAwaitBlock), SvelteBogusBlock(SvelteBogusBlock), @@ -3167,6 +3638,67 @@ impl AnySvelteDestructuredName { } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnySvelteDirective { + SvelteAnimateDirective(SvelteAnimateDirective), + SvelteBindDirective(SvelteBindDirective), + SvelteClassDirective(SvelteClassDirective), + SvelteInDirective(SvelteInDirective), + SvelteOutDirective(SvelteOutDirective), + SvelteStyleDirective(SvelteStyleDirective), + SvelteTransitionDirective(SvelteTransitionDirective), + SvelteUseDirective(SvelteUseDirective), +} +impl AnySvelteDirective { + pub fn as_svelte_animate_directive(&self) -> Option<&SvelteAnimateDirective> { + match &self { + Self::SvelteAnimateDirective(item) => Some(item), + _ => None, + } + } + pub fn as_svelte_bind_directive(&self) -> Option<&SvelteBindDirective> { + match &self { + Self::SvelteBindDirective(item) => Some(item), + _ => None, + } + } + pub fn as_svelte_class_directive(&self) -> Option<&SvelteClassDirective> { + match &self { + Self::SvelteClassDirective(item) => Some(item), + _ => None, + } + } + pub fn as_svelte_in_directive(&self) -> Option<&SvelteInDirective> { + match &self { + Self::SvelteInDirective(item) => Some(item), + _ => None, + } + } + pub fn as_svelte_out_directive(&self) -> Option<&SvelteOutDirective> { + match &self { + Self::SvelteOutDirective(item) => Some(item), + _ => None, + } + } + pub fn as_svelte_style_directive(&self) -> Option<&SvelteStyleDirective> { + match &self { + Self::SvelteStyleDirective(item) => Some(item), + _ => None, + } + } + pub fn as_svelte_transition_directive(&self) -> Option<&SvelteTransitionDirective> { + match &self { + Self::SvelteTransitionDirective(item) => Some(item), + _ => None, + } + } + pub fn as_svelte_use_directive(&self) -> Option<&SvelteUseDirective> { + match &self { + Self::SvelteUseDirective(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnySvelteEachName { AnySvelteDestructuredName(AnySvelteDestructuredName), HtmlTextExpression(HtmlTextExpression), @@ -4295,6 +4827,57 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for SvelteAnimateDirective { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_ANIMATE_DIRECTIVE as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_ANIMATE_DIRECTIVE + } + 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 SvelteAnimateDirective { + 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("SvelteAnimateDirective") + .field( + "animate_token", + &support::DebugSyntaxResult(self.animate_token()), + ) + .field("value", &support::DebugSyntaxResult(self.value())) + .finish() + } else { + f.debug_struct("SvelteAnimateDirective").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteAnimateDirective) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteAnimateDirective) -> Self { + n.syntax.into() + } +} impl AstNode for SvelteAttachAttribute { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -4751,12 +5334,12 @@ impl From for SyntaxElement { n.syntax.into() } } -impl AstNode for SvelteConstBlock { +impl AstNode for SvelteBindDirective { type Language = Language; const KIND_SET: SyntaxKindSet = - SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_CONST_BLOCK as u16)); + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_BIND_DIRECTIVE as u16)); fn can_cast(kind: SyntaxKind) -> bool { - kind == SVELTE_CONST_BLOCK + kind == SVELTE_BIND_DIRECTIVE } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -4772,50 +5355,39 @@ impl AstNode for SvelteConstBlock { self.syntax } } -impl std::fmt::Debug for SvelteConstBlock { +impl std::fmt::Debug for SvelteBindDirective { 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("SvelteConstBlock") - .field( - "sv_curly_at_token", - &support::DebugSyntaxResult(self.sv_curly_at_token()), - ) - .field( - "const_token", - &support::DebugSyntaxResult(self.const_token()), - ) - .field("expression", &support::DebugSyntaxResult(self.expression())) - .field( - "r_curly_token", - &support::DebugSyntaxResult(self.r_curly_token()), - ) + f.debug_struct("SvelteBindDirective") + .field("bind_token", &support::DebugSyntaxResult(self.bind_token())) + .field("value", &support::DebugSyntaxResult(self.value())) .finish() } else { - f.debug_struct("SvelteConstBlock").finish() + f.debug_struct("SvelteBindDirective").finish() }; DEPTH.set(current_depth); result } } -impl From for SyntaxNode { - fn from(n: SvelteConstBlock) -> Self { +impl From for SyntaxNode { + fn from(n: SvelteBindDirective) -> Self { n.syntax } } -impl From for SyntaxElement { - fn from(n: SvelteConstBlock) -> Self { +impl From for SyntaxElement { + fn from(n: SvelteBindDirective) -> Self { n.syntax.into() } } -impl AstNode for SvelteCurlyDestructuredName { +impl AstNode for SvelteClassDirective { type Language = Language; const KIND_SET: SyntaxKindSet = - SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_CURLY_DESTRUCTURED_NAME as u16)); + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_CLASS_DIRECTIVE as u16)); fn can_cast(kind: SyntaxKind) -> bool { - kind == SVELTE_CURLY_DESTRUCTURED_NAME + kind == SVELTE_CLASS_DIRECTIVE } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -4831,46 +5403,42 @@ impl AstNode for SvelteCurlyDestructuredName { self.syntax } } -impl std::fmt::Debug for SvelteCurlyDestructuredName { +impl std::fmt::Debug for SvelteClassDirective { 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("SvelteCurlyDestructuredName") - .field( - "l_curly_token", - &support::DebugSyntaxResult(self.l_curly_token()), - ) - .field("names", &self.names()) + f.debug_struct("SvelteClassDirective") .field( - "r_curly_token", - &support::DebugSyntaxResult(self.r_curly_token()), + "class_token", + &support::DebugSyntaxResult(self.class_token()), ) + .field("value", &support::DebugSyntaxResult(self.value())) .finish() } else { - f.debug_struct("SvelteCurlyDestructuredName").finish() + f.debug_struct("SvelteClassDirective").finish() }; DEPTH.set(current_depth); result } } -impl From for SyntaxNode { - fn from(n: SvelteCurlyDestructuredName) -> Self { +impl From for SyntaxNode { + fn from(n: SvelteClassDirective) -> Self { n.syntax } } -impl From for SyntaxElement { - fn from(n: SvelteCurlyDestructuredName) -> Self { +impl From for SyntaxElement { + fn from(n: SvelteClassDirective) -> Self { n.syntax.into() } } -impl AstNode for SvelteDebugBlock { +impl AstNode for SvelteConstBlock { type Language = Language; const KIND_SET: SyntaxKindSet = - SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_DEBUG_BLOCK as u16)); + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_CONST_BLOCK as u16)); fn can_cast(kind: SyntaxKind) -> bool { - kind == SVELTE_DEBUG_BLOCK + kind == SVELTE_CONST_BLOCK } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -4886,41 +5454,262 @@ impl AstNode for SvelteDebugBlock { self.syntax } } -impl std::fmt::Debug for SvelteDebugBlock { +impl std::fmt::Debug for SvelteConstBlock { 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("SvelteDebugBlock") + f.debug_struct("SvelteConstBlock") .field( "sv_curly_at_token", &support::DebugSyntaxResult(self.sv_curly_at_token()), ) .field( - "debug_token", - &support::DebugSyntaxResult(self.debug_token()), + "const_token", + &support::DebugSyntaxResult(self.const_token()), ) - .field("bindings", &self.bindings()) + .field("expression", &support::DebugSyntaxResult(self.expression())) .field( "r_curly_token", &support::DebugSyntaxResult(self.r_curly_token()), ) .finish() } else { - f.debug_struct("SvelteDebugBlock").finish() + f.debug_struct("SvelteConstBlock").finish() }; DEPTH.set(current_depth); result } } -impl From for SyntaxNode { - fn from(n: SvelteDebugBlock) -> Self { +impl From for SyntaxNode { + fn from(n: SvelteConstBlock) -> Self { n.syntax } } -impl From for SyntaxElement { - fn from(n: SvelteDebugBlock) -> Self { +impl From for SyntaxElement { + fn from(n: SvelteConstBlock) -> Self { + n.syntax.into() + } +} +impl AstNode for SvelteCurlyDestructuredName { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_CURLY_DESTRUCTURED_NAME as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_CURLY_DESTRUCTURED_NAME + } + 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 SvelteCurlyDestructuredName { + 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("SvelteCurlyDestructuredName") + .field( + "l_curly_token", + &support::DebugSyntaxResult(self.l_curly_token()), + ) + .field("names", &self.names()) + .field( + "r_curly_token", + &support::DebugSyntaxResult(self.r_curly_token()), + ) + .finish() + } else { + f.debug_struct("SvelteCurlyDestructuredName").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteCurlyDestructuredName) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteCurlyDestructuredName) -> Self { + n.syntax.into() + } +} +impl AstNode for SvelteDebugBlock { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_DEBUG_BLOCK as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_DEBUG_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 SvelteDebugBlock { + 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("SvelteDebugBlock") + .field( + "sv_curly_at_token", + &support::DebugSyntaxResult(self.sv_curly_at_token()), + ) + .field( + "debug_token", + &support::DebugSyntaxResult(self.debug_token()), + ) + .field("bindings", &self.bindings()) + .field( + "r_curly_token", + &support::DebugSyntaxResult(self.r_curly_token()), + ) + .finish() + } else { + f.debug_struct("SvelteDebugBlock").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteDebugBlock) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteDebugBlock) -> Self { + n.syntax.into() + } +} +impl AstNode for SvelteDirectiveModifier { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_DIRECTIVE_MODIFIER as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_DIRECTIVE_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 SvelteDirectiveModifier { + 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("SvelteDirectiveModifier") + .field( + "bitwise_or_token", + &support::DebugSyntaxResult(self.bitwise_or_token()), + ) + .field("name", &support::DebugSyntaxResult(self.name())) + .finish() + } else { + f.debug_struct("SvelteDirectiveModifier").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteDirectiveModifier) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteDirectiveModifier) -> Self { + n.syntax.into() + } +} +impl AstNode for SvelteDirectiveValue { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_DIRECTIVE_VALUE as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_DIRECTIVE_VALUE + } + 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 SvelteDirectiveValue { + 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("SvelteDirectiveValue") + .field( + "colon_token", + &support::DebugSyntaxResult(self.colon_token()), + ) + .field("property", &support::DebugSyntaxResult(self.property())) + .field("modifiers", &self.modifiers()) + .field( + "initializer", + &support::DebugOptionalElement(self.initializer()), + ) + .finish() + } else { + f.debug_struct("SvelteDirectiveValue").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteDirectiveValue) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteDirectiveValue) -> Self { n.syntax.into() } } @@ -5639,6 +6428,54 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for SvelteInDirective { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_IN_DIRECTIVE as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_IN_DIRECTIVE + } + 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 SvelteInDirective { + 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("SvelteInDirective") + .field("in_token", &support::DebugSyntaxResult(self.in_token())) + .field("value", &support::DebugSyntaxResult(self.value())) + .finish() + } else { + f.debug_struct("SvelteInDirective").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteInDirective) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteInDirective) -> Self { + n.syntax.into() + } +} impl AstNode for SvelteKeyBlock { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -5805,6 +6642,56 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for SvelteLiteral { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_LITERAL as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_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 SvelteLiteral { + 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("SvelteLiteral") + .field( + "value_token", + &support::DebugSyntaxResult(self.value_token()), + ) + .finish() + } else { + f.debug_struct("SvelteLiteral").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteLiteral) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteLiteral) -> Self { + n.syntax.into() + } +} impl AstNode for SvelteName { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -5855,6 +6742,54 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for SvelteOutDirective { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_OUT_DIRECTIVE as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_OUT_DIRECTIVE + } + 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 SvelteOutDirective { + 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("SvelteOutDirective") + .field("out_token", &support::DebugSyntaxResult(self.out_token())) + .field("value", &support::DebugSyntaxResult(self.value())) + .finish() + } else { + f.debug_struct("SvelteOutDirective").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteOutDirective) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteOutDirective) -> Self { + n.syntax.into() + } +} impl AstNode for SvelteRenderBlock { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -6072,17 +7007,183 @@ impl From for SyntaxNode { n.syntax } } -impl From for SyntaxElement { - fn from(n: SvelteSnippetClosingBlock) -> Self { +impl From for SyntaxElement { + fn from(n: SvelteSnippetClosingBlock) -> Self { + n.syntax.into() + } +} +impl AstNode for SvelteSnippetOpeningBlock { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_SNIPPET_OPENING_BLOCK as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_SNIPPET_OPENING_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 SvelteSnippetOpeningBlock { + 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("SvelteSnippetOpeningBlock") + .field( + "sv_curly_hash_token", + &support::DebugSyntaxResult(self.sv_curly_hash_token()), + ) + .field( + "snippet_token", + &support::DebugSyntaxResult(self.snippet_token()), + ) + .field("expression", &support::DebugSyntaxResult(self.expression())) + .field( + "r_curly_token", + &support::DebugSyntaxResult(self.r_curly_token()), + ) + .field("children", &self.children()) + .finish() + } else { + f.debug_struct("SvelteSnippetOpeningBlock").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteSnippetOpeningBlock) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteSnippetOpeningBlock) -> Self { + n.syntax.into() + } +} +impl AstNode for SvelteSquareDestructuredName { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_SQUARE_DESTRUCTURED_NAME as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_SQUARE_DESTRUCTURED_NAME + } + 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 SvelteSquareDestructuredName { + 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("SvelteSquareDestructuredName") + .field( + "l_brack_token", + &support::DebugSyntaxResult(self.l_brack_token()), + ) + .field("names", &self.names()) + .field( + "r_brack_token", + &support::DebugSyntaxResult(self.r_brack_token()), + ) + .finish() + } else { + f.debug_struct("SvelteSquareDestructuredName").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteSquareDestructuredName) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteSquareDestructuredName) -> Self { + n.syntax.into() + } +} +impl AstNode for SvelteStyleDirective { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_STYLE_DIRECTIVE as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_STYLE_DIRECTIVE + } + 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 SvelteStyleDirective { + 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("SvelteStyleDirective") + .field( + "style_token", + &support::DebugSyntaxResult(self.style_token()), + ) + .field("value", &support::DebugSyntaxResult(self.value())) + .finish() + } else { + f.debug_struct("SvelteStyleDirective").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: SvelteStyleDirective) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: SvelteStyleDirective) -> Self { n.syntax.into() } } -impl AstNode for SvelteSnippetOpeningBlock { +impl AstNode for SvelteTransitionDirective { type Language = Language; const KIND_SET: SyntaxKindSet = - SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_SNIPPET_OPENING_BLOCK as u16)); + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_TRANSITION_DIRECTIVE as u16)); fn can_cast(kind: SyntaxKind) -> bool { - kind == SVELTE_SNIPPET_OPENING_BLOCK + kind == SVELTE_TRANSITION_DIRECTIVE } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -6098,51 +7199,42 @@ impl AstNode for SvelteSnippetOpeningBlock { self.syntax } } -impl std::fmt::Debug for SvelteSnippetOpeningBlock { +impl std::fmt::Debug for SvelteTransitionDirective { 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("SvelteSnippetOpeningBlock") - .field( - "sv_curly_hash_token", - &support::DebugSyntaxResult(self.sv_curly_hash_token()), - ) - .field( - "snippet_token", - &support::DebugSyntaxResult(self.snippet_token()), - ) - .field("expression", &support::DebugSyntaxResult(self.expression())) + f.debug_struct("SvelteTransitionDirective") .field( - "r_curly_token", - &support::DebugSyntaxResult(self.r_curly_token()), + "transition_token", + &support::DebugSyntaxResult(self.transition_token()), ) - .field("children", &self.children()) + .field("value", &support::DebugSyntaxResult(self.value())) .finish() } else { - f.debug_struct("SvelteSnippetOpeningBlock").finish() + f.debug_struct("SvelteTransitionDirective").finish() }; DEPTH.set(current_depth); result } } -impl From for SyntaxNode { - fn from(n: SvelteSnippetOpeningBlock) -> Self { +impl From for SyntaxNode { + fn from(n: SvelteTransitionDirective) -> Self { n.syntax } } -impl From for SyntaxElement { - fn from(n: SvelteSnippetOpeningBlock) -> Self { +impl From for SyntaxElement { + fn from(n: SvelteTransitionDirective) -> Self { n.syntax.into() } } -impl AstNode for SvelteSquareDestructuredName { +impl AstNode for SvelteUseDirective { type Language = Language; const KIND_SET: SyntaxKindSet = - SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_SQUARE_DESTRUCTURED_NAME as u16)); + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_USE_DIRECTIVE as u16)); fn can_cast(kind: SyntaxKind) -> bool { - kind == SVELTE_SQUARE_DESTRUCTURED_NAME + kind == SVELTE_USE_DIRECTIVE } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -6158,37 +7250,30 @@ impl AstNode for SvelteSquareDestructuredName { self.syntax } } -impl std::fmt::Debug for SvelteSquareDestructuredName { +impl std::fmt::Debug for SvelteUseDirective { 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("SvelteSquareDestructuredName") - .field( - "l_brack_token", - &support::DebugSyntaxResult(self.l_brack_token()), - ) - .field("names", &self.names()) - .field( - "r_brack_token", - &support::DebugSyntaxResult(self.r_brack_token()), - ) + f.debug_struct("SvelteUseDirective") + .field("use_token", &support::DebugSyntaxResult(self.use_token())) + .field("value", &support::DebugSyntaxResult(self.value())) .finish() } else { - f.debug_struct("SvelteSquareDestructuredName").finish() + f.debug_struct("SvelteUseDirective").finish() }; DEPTH.set(current_depth); result } } -impl From for SyntaxNode { - fn from(n: SvelteSquareDestructuredName) -> Self { +impl From for SyntaxNode { + fn from(n: SvelteUseDirective) -> Self { n.syntax } } -impl From for SyntaxElement { - fn from(n: SvelteSquareDestructuredName) -> Self { +impl From for SyntaxElement { + fn from(n: SvelteUseDirective) -> Self { n.syntax.into() } } @@ -6698,7 +7783,8 @@ impl From for AnyHtmlAttribute { } impl AstNode for AnyHtmlAttribute { type Language = Language; - const KIND_SET: SyntaxKindSet = AnyVueDirective::KIND_SET + const KIND_SET: SyntaxKindSet = AnySvelteDirective::KIND_SET + .union(AnyVueDirective::KIND_SET) .union(HtmlAttribute::KIND_SET) .union(HtmlBogusAttribute::KIND_SET) .union(HtmlDoubleTextExpression::KIND_SET) @@ -6711,6 +7797,7 @@ impl AstNode for AnyHtmlAttribute { | HTML_DOUBLE_TEXT_EXPRESSION | HTML_SINGLE_TEXT_EXPRESSION | SVELTE_ATTACH_ATTRIBUTE => true, + k if AnySvelteDirective::can_cast(k) => true, k if AnyVueDirective::can_cast(k) => true, _ => false, } @@ -6729,6 +7816,12 @@ impl AstNode for AnyHtmlAttribute { Self::SvelteAttachAttribute(SvelteAttachAttribute { syntax }) } _ => { + let syntax = match AnySvelteDirective::try_cast(syntax) { + Ok(any_svelte_directive) => { + return Some(Self::AnySvelteDirective(any_svelte_directive)); + } + Err(syntax) => syntax, + }; if let Some(any_vue_directive) = AnyVueDirective::cast(syntax) { return Some(Self::AnyVueDirective(any_vue_directive)); } @@ -6744,6 +7837,7 @@ impl AstNode for AnyHtmlAttribute { Self::HtmlDoubleTextExpression(it) => it.syntax(), Self::HtmlSingleTextExpression(it) => it.syntax(), Self::SvelteAttachAttribute(it) => it.syntax(), + Self::AnySvelteDirective(it) => it.syntax(), Self::AnyVueDirective(it) => it.syntax(), } } @@ -6754,6 +7848,7 @@ impl AstNode for AnyHtmlAttribute { Self::HtmlDoubleTextExpression(it) => it.into_syntax(), Self::HtmlSingleTextExpression(it) => it.into_syntax(), Self::SvelteAttachAttribute(it) => it.into_syntax(), + Self::AnySvelteDirective(it) => it.into_syntax(), Self::AnyVueDirective(it) => it.into_syntax(), } } @@ -6761,6 +7856,7 @@ impl AstNode for AnyHtmlAttribute { impl std::fmt::Debug for AnyHtmlAttribute { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Self::AnySvelteDirective(it) => std::fmt::Debug::fmt(it, f), Self::AnyVueDirective(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), @@ -6773,6 +7869,7 @@ impl std::fmt::Debug for AnyHtmlAttribute { impl From for SyntaxNode { fn from(n: AnyHtmlAttribute) -> Self { match n { + AnyHtmlAttribute::AnySvelteDirective(it) => it.into_syntax(), AnyHtmlAttribute::AnyVueDirective(it) => it.into_syntax(), AnyHtmlAttribute::HtmlAttribute(it) => it.into_syntax(), AnyHtmlAttribute::HtmlBogusAttribute(it) => it.into_syntax(), @@ -7253,6 +8350,65 @@ impl From for SyntaxElement { node.into() } } +impl From for AnySvelteBindingProperty { + fn from(node: SvelteLiteral) -> Self { + Self::SvelteLiteral(node) + } +} +impl From for AnySvelteBindingProperty { + fn from(node: SvelteName) -> Self { + Self::SvelteName(node) + } +} +impl AstNode for AnySvelteBindingProperty { + type Language = Language; + const KIND_SET: SyntaxKindSet = SvelteLiteral::KIND_SET.union(SvelteName::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, SVELTE_LITERAL | SVELTE_NAME) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + SVELTE_LITERAL => Self::SvelteLiteral(SvelteLiteral { syntax }), + SVELTE_NAME => Self::SvelteName(SvelteName { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Self::SvelteLiteral(it) => it.syntax(), + Self::SvelteName(it) => it.syntax(), + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + Self::SvelteLiteral(it) => it.into_syntax(), + Self::SvelteName(it) => it.into_syntax(), + } + } +} +impl std::fmt::Debug for AnySvelteBindingProperty { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::SvelteLiteral(it) => std::fmt::Debug::fmt(it, f), + Self::SvelteName(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnySvelteBindingProperty) -> Self { + match n { + AnySvelteBindingProperty::SvelteLiteral(it) => it.into_syntax(), + AnySvelteBindingProperty::SvelteName(it) => it.into_syntax(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnySvelteBindingProperty) -> Self { + let node: SyntaxNode = n.into(); + node.into() + } +} impl From for AnySvelteBlock { fn from(node: SvelteAwaitBlock) -> Self { Self::SvelteAwaitBlock(node) @@ -7542,6 +8698,146 @@ impl From for SyntaxElement { node.into() } } +impl From for AnySvelteDirective { + fn from(node: SvelteAnimateDirective) -> Self { + Self::SvelteAnimateDirective(node) + } +} +impl From for AnySvelteDirective { + fn from(node: SvelteBindDirective) -> Self { + Self::SvelteBindDirective(node) + } +} +impl From for AnySvelteDirective { + fn from(node: SvelteClassDirective) -> Self { + Self::SvelteClassDirective(node) + } +} +impl From for AnySvelteDirective { + fn from(node: SvelteInDirective) -> Self { + Self::SvelteInDirective(node) + } +} +impl From for AnySvelteDirective { + fn from(node: SvelteOutDirective) -> Self { + Self::SvelteOutDirective(node) + } +} +impl From for AnySvelteDirective { + fn from(node: SvelteStyleDirective) -> Self { + Self::SvelteStyleDirective(node) + } +} +impl From for AnySvelteDirective { + fn from(node: SvelteTransitionDirective) -> Self { + Self::SvelteTransitionDirective(node) + } +} +impl From for AnySvelteDirective { + fn from(node: SvelteUseDirective) -> Self { + Self::SvelteUseDirective(node) + } +} +impl AstNode for AnySvelteDirective { + type Language = Language; + const KIND_SET: SyntaxKindSet = SvelteAnimateDirective::KIND_SET + .union(SvelteBindDirective::KIND_SET) + .union(SvelteClassDirective::KIND_SET) + .union(SvelteInDirective::KIND_SET) + .union(SvelteOutDirective::KIND_SET) + .union(SvelteStyleDirective::KIND_SET) + .union(SvelteTransitionDirective::KIND_SET) + .union(SvelteUseDirective::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + matches!( + kind, + SVELTE_ANIMATE_DIRECTIVE + | SVELTE_BIND_DIRECTIVE + | SVELTE_CLASS_DIRECTIVE + | SVELTE_IN_DIRECTIVE + | SVELTE_OUT_DIRECTIVE + | SVELTE_STYLE_DIRECTIVE + | SVELTE_TRANSITION_DIRECTIVE + | SVELTE_USE_DIRECTIVE + ) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + SVELTE_ANIMATE_DIRECTIVE => { + Self::SvelteAnimateDirective(SvelteAnimateDirective { syntax }) + } + SVELTE_BIND_DIRECTIVE => Self::SvelteBindDirective(SvelteBindDirective { syntax }), + SVELTE_CLASS_DIRECTIVE => Self::SvelteClassDirective(SvelteClassDirective { syntax }), + SVELTE_IN_DIRECTIVE => Self::SvelteInDirective(SvelteInDirective { syntax }), + SVELTE_OUT_DIRECTIVE => Self::SvelteOutDirective(SvelteOutDirective { syntax }), + SVELTE_STYLE_DIRECTIVE => Self::SvelteStyleDirective(SvelteStyleDirective { syntax }), + SVELTE_TRANSITION_DIRECTIVE => { + Self::SvelteTransitionDirective(SvelteTransitionDirective { syntax }) + } + SVELTE_USE_DIRECTIVE => Self::SvelteUseDirective(SvelteUseDirective { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Self::SvelteAnimateDirective(it) => it.syntax(), + Self::SvelteBindDirective(it) => it.syntax(), + Self::SvelteClassDirective(it) => it.syntax(), + Self::SvelteInDirective(it) => it.syntax(), + Self::SvelteOutDirective(it) => it.syntax(), + Self::SvelteStyleDirective(it) => it.syntax(), + Self::SvelteTransitionDirective(it) => it.syntax(), + Self::SvelteUseDirective(it) => it.syntax(), + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + Self::SvelteAnimateDirective(it) => it.into_syntax(), + Self::SvelteBindDirective(it) => it.into_syntax(), + Self::SvelteClassDirective(it) => it.into_syntax(), + Self::SvelteInDirective(it) => it.into_syntax(), + Self::SvelteOutDirective(it) => it.into_syntax(), + Self::SvelteStyleDirective(it) => it.into_syntax(), + Self::SvelteTransitionDirective(it) => it.into_syntax(), + Self::SvelteUseDirective(it) => it.into_syntax(), + } + } +} +impl std::fmt::Debug for AnySvelteDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::SvelteAnimateDirective(it) => std::fmt::Debug::fmt(it, f), + Self::SvelteBindDirective(it) => std::fmt::Debug::fmt(it, f), + Self::SvelteClassDirective(it) => std::fmt::Debug::fmt(it, f), + Self::SvelteInDirective(it) => std::fmt::Debug::fmt(it, f), + Self::SvelteOutDirective(it) => std::fmt::Debug::fmt(it, f), + Self::SvelteStyleDirective(it) => std::fmt::Debug::fmt(it, f), + Self::SvelteTransitionDirective(it) => std::fmt::Debug::fmt(it, f), + Self::SvelteUseDirective(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnySvelteDirective) -> Self { + match n { + AnySvelteDirective::SvelteAnimateDirective(it) => it.into_syntax(), + AnySvelteDirective::SvelteBindDirective(it) => it.into_syntax(), + AnySvelteDirective::SvelteClassDirective(it) => it.into_syntax(), + AnySvelteDirective::SvelteInDirective(it) => it.into_syntax(), + AnySvelteDirective::SvelteOutDirective(it) => it.into_syntax(), + AnySvelteDirective::SvelteStyleDirective(it) => it.into_syntax(), + AnySvelteDirective::SvelteTransitionDirective(it) => it.into_syntax(), + AnySvelteDirective::SvelteUseDirective(it) => it.into_syntax(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnySvelteDirective) -> Self { + let node: SyntaxNode = n.into(); + node.into() + } +} impl From for AnySvelteEachName { fn from(node: HtmlTextExpression) -> Self { Self::HtmlTextExpression(node) @@ -7841,6 +9137,11 @@ impl std::fmt::Display for AnySvelteBindingAssignmentBinding { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AnySvelteBindingProperty { + 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) @@ -7856,6 +9157,11 @@ impl std::fmt::Display for AnySvelteDestructuredName { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AnySvelteDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AnySvelteEachName { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -7966,6 +9272,11 @@ impl std::fmt::Display for HtmlTextExpression { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for SvelteAnimateDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for SvelteAttachAttribute { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -8006,6 +9317,16 @@ impl std::fmt::Display for SvelteAwaitThenClause { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for SvelteBindDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for SvelteClassDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for SvelteConstBlock { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -8021,6 +9342,16 @@ impl std::fmt::Display for SvelteDebugBlock { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for SvelteDirectiveModifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for SvelteDirectiveValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for SvelteEachAsKeyedItem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -8086,6 +9417,11 @@ impl std::fmt::Display for SvelteIfOpeningBlock { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for SvelteInDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for SvelteKeyBlock { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -8101,11 +9437,21 @@ impl std::fmt::Display for SvelteKeyOpeningBlock { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for SvelteLiteral { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for SvelteName { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for SvelteOutDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for SvelteRenderBlock { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -8136,6 +9482,21 @@ impl std::fmt::Display for SvelteSquareDestructuredName { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for SvelteStyleDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for SvelteTransitionDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for SvelteUseDirective { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for VueDirective { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -9036,6 +10397,88 @@ impl IntoIterator for &SvelteBindingList { } } #[derive(Clone, Eq, PartialEq, Hash)] +pub struct SvelteDirectiveModifierList { + syntax_list: SyntaxList, +} +impl SvelteDirectiveModifierList { + #[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 SvelteDirectiveModifierList { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SVELTE_DIRECTIVE_MODIFIER_LIST as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SVELTE_DIRECTIVE_MODIFIER_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 SvelteDirectiveModifierList { + 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 SvelteDirectiveModifierList { + type Language = Language; + type Node = SvelteDirectiveModifier; + fn syntax_list(&self) -> &SyntaxList { + &self.syntax_list + } + fn into_syntax_list(self) -> SyntaxList { + self.syntax_list + } +} +impl Debug for SvelteDirectiveModifierList { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("SvelteDirectiveModifierList ")?; + f.debug_list().entries(self.iter()).finish() + } +} +impl IntoIterator for &SvelteDirectiveModifierList { + type Item = SvelteDirectiveModifier; + type IntoIter = AstNodeListIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} +impl IntoIterator for SvelteDirectiveModifierList { + type Item = SvelteDirectiveModifier; + type IntoIter = AstNodeListIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} +#[derive(Clone, Eq, PartialEq, Hash)] pub struct SvelteElseIfClauseList { 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 306f699fdfb9..41202173dd73 100644 --- a/crates/biome_html_syntax/src/generated/nodes_mut.rs +++ b/crates/biome_html_syntax/src/generated/nodes_mut.rs @@ -353,6 +353,20 @@ impl HtmlTextExpression { ) } } +impl SvelteAnimateDirective { + pub fn with_animate_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: SvelteDirectiveValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} impl SvelteAttachAttribute { pub fn with_sv_curly_at_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( @@ -555,6 +569,34 @@ impl SvelteAwaitThenClause { ) } } +impl SvelteBindDirective { + pub fn with_bind_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: SvelteDirectiveValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl SvelteClassDirective { + pub fn with_class_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: SvelteDirectiveValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} impl SvelteConstBlock { pub fn with_sv_curly_at_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( @@ -627,6 +669,46 @@ impl SvelteDebugBlock { ) } } +impl SvelteDirectiveModifier { + pub fn with_bitwise_or_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_name(self, element: SvelteName) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl SvelteDirectiveValue { + pub fn with_colon_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_property(self, element: AnySvelteBindingProperty) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_modifiers(self, element: SvelteDirectiveModifierList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_initializer(self, element: Option) -> Self { + Self::unwrap_cast(self.syntax.splice_slots( + 3usize..=3usize, + once(element.map(|element| element.into_syntax().into())), + )) + } +} impl SvelteEachAsKeyedItem { pub fn with_as_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( @@ -941,6 +1023,20 @@ impl SvelteIfOpeningBlock { ) } } +impl SvelteInDirective { + pub fn with_in_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: SvelteDirectiveValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} impl SvelteKeyBlock { pub fn with_opening_block(self, element: SvelteKeyOpeningBlock) -> Self { Self::unwrap_cast( @@ -1007,6 +1103,14 @@ impl SvelteKeyOpeningBlock { ) } } +impl SvelteLiteral { + pub fn with_value_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } +} impl SvelteName { pub fn with_ident_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( @@ -1015,6 +1119,20 @@ impl SvelteName { ) } } +impl SvelteOutDirective { + pub fn with_out_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: SvelteDirectiveValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} impl SvelteRenderBlock { pub fn with_sv_curly_at_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( @@ -1141,6 +1259,48 @@ impl SvelteSquareDestructuredName { ) } } +impl SvelteStyleDirective { + pub fn with_style_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: SvelteDirectiveValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl SvelteTransitionDirective { + pub fn with_transition_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: SvelteDirectiveValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl SvelteUseDirective { + pub fn with_use_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: SvelteDirectiveValue) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} impl VueDirective { pub fn with_name_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( diff --git a/crates/biome_html_syntax/src/lib.rs b/crates/biome_html_syntax/src/lib.rs index 10972d592e8a..2ad781b975f0 100644 --- a/crates/biome_html_syntax/src/lib.rs +++ b/crates/biome_html_syntax/src/lib.rs @@ -10,6 +10,7 @@ mod script_type; pub mod static_value; mod string_ext; mod syntax_node; +mod text_ext; pub use biome_rowan::{TextLen, TextRange, TextSize, TokenAtOffset, TriviaPieceKind, WalkEvent}; pub use file_source::{HtmlFileSource, HtmlTextExpressions, HtmlVariant}; diff --git a/crates/biome_html_syntax/src/text_ext.rs b/crates/biome_html_syntax/src/text_ext.rs new file mode 100644 index 000000000000..f2fabc7fb47e --- /dev/null +++ b/crates/biome_html_syntax/src/text_ext.rs @@ -0,0 +1,11 @@ +use crate::HtmlTextExpression; +use biome_rowan::Text; + +impl HtmlTextExpression { + /// Returns the string value of the attribute, if available, without quotes. + pub fn string_value(&self) -> Option { + self.html_literal_token() + .ok() + .map(|token| token.token_text_trimmed().into()) + } +} diff --git a/xtask/codegen/html.ungram b/xtask/codegen/html.ungram index 2386061a9a7e..a3501b113584 100644 --- a/xtask/codegen/html.ungram +++ b/xtask/codegen/html.ungram @@ -165,6 +165,7 @@ AnyHtmlAttribute = | HtmlDoubleTextExpression | HtmlSingleTextExpression | SvelteAttachAttribute + | AnySvelteDirective | AnyVueDirective | HtmlBogusAttribute @@ -494,8 +495,90 @@ SvelteSnippetClosingBlock = 'snippet' '}' +AnySvelteDirective = + SvelteBindDirective + | SvelteTransitionDirective + | SvelteInDirective + | SvelteOutDirective + | SvelteUseDirective + | SvelteAnimateDirective + | SvelteStyleDirective + | SvelteClassDirective + +//
    +// ^^^^^^^^^^^^^^^^^^ +SvelteBindDirective = + 'bind' + value: SvelteDirectiveValue + +//
    +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +SvelteTransitionDirective = + 'transition' + value: SvelteDirectiveValue + +//
    +// ^^^^^^ +SvelteInDirective = + 'in' + value: SvelteDirectiveValue + +//
    +// ^^^^^^^ +SvelteOutDirective = + 'out' + value: SvelteDirectiveValue + +//
    +// ^^^^^^^ +SvelteUseDirective = + 'use' + value: SvelteDirectiveValue + +//
    +// ^^^^^^^^^^^ +SvelteAnimateDirective = + 'animate' + value: SvelteDirectiveValue + +//
    +// ^^^^^^^^^ +SvelteStyleDirective = + 'style' + value: SvelteDirectiveValue + +//
    +// ^^^^^^^^^ +SvelteClassDirective = + 'class' + value: SvelteDirectiveValue + +//
    +// ^^^^^^^^^^^^^^^^^^^^ +SvelteDirectiveValue = + ':' + property: AnySvelteBindingProperty + modifiers: SvelteDirectiveModifierList + initializer: HtmlAttributeInitializerClause? + +AnySvelteBindingProperty = + SvelteName + | SvelteLiteral + +SvelteDirectiveModifierList = SvelteDirectiveModifier* + +//
    +// ^^^^^^^^^^^^^^ +SvelteDirectiveModifier = + '|' + name: SvelteName + + + + // Keep it different just for svelte SvelteName = 'ident' +SvelteLiteral = value: 'html_literal' HtmlString = value: 'html_string_literal' HtmlTagName = value: 'html_literal' HtmlAttributeName = value: 'html_literal' diff --git a/xtask/codegen/src/html_kinds_src.rs b/xtask/codegen/src/html_kinds_src.rs index a5af91f966ff..9cfda838b619 100644 --- a/xtask/codegen/src/html_kinds_src.rs +++ b/xtask/codegen/src/html_kinds_src.rs @@ -29,6 +29,7 @@ pub const HTML_KINDS_SRC: KindsSrc = KindsSrc { ("(", "L_PAREN"), (")", "R_PAREN"), ("...", "DOT3"), + ("|", "PIPE"), ], keywords: &[ "null", @@ -53,6 +54,14 @@ pub const HTML_KINDS_SRC: KindsSrc = KindsSrc { "await", "catch", "snippet", + "bind", + "transition", + "use", + "animate", + "in", + "out", + "style", + "class", ], literals: &["HTML_STRING_LITERAL", "HTML_LITERAL"], tokens: &["ERROR_TOKEN", "NEWLINE", "WHITESPACE", "IDENT"], @@ -120,6 +129,18 @@ pub const HTML_KINDS_SRC: KindsSrc = KindsSrc { "SVELTE_SQUARE_DESTRUCTURED_NAME", "SVELTE_BINDING_ASSIGNMENT_BINDING_LIST", "SVELTE_REST_BINDING", + "SVELTE_BIND_DIRECTIVE", + "SVELTE_TRANSITION_DIRECTIVE", + "SVELTE_IN_DIRECTIVE", + "SVELTE_OUT_DIRECTIVE", + "SVELTE_USE_DIRECTIVE", + "SVELTE_ANIMATE_DIRECTIVE", + "SVELTE_STYLE_DIRECTIVE", + "SVELTE_CLASS_DIRECTIVE", + "SVELTE_DIRECTIVE_VALUE", + "SVELTE_DIRECTIVE_MODIFIER", + "SVELTE_DIRECTIVE_MODIFIER_LIST", + "SVELTE_LITERAL", // Vue nodes "VUE_DIRECTIVE", "VUE_DIRECTIVE_ARGUMENT",