tsv_svelte 0.8.0

Svelte formatter and parser compatible with Svelte's parse() — part of tsv
Documentation
// Style tag parsing

use crate::ast::*;
use crate::lexer::TokenKind;
use tsv_lang::{Error, Span};

use super::find_raw_text_close;
use super::parser_impl::SvelteParser;

impl<'a, 'arena> SvelteParser<'a, 'arena> {
    pub(crate) fn parse_style_tag(&mut self) -> Result<Style<'arena>, Error> {
        let start = self.current_start();

        // Expect <
        self.expect(TokenKind::LeftAngle)?;

        // Expect identifier "style"
        if !self.check(TokenKind::Identifier) || self.current_value() != "style" {
            return Err(self.error_expected_found("'style'"));
        }
        self.advance()?;

        // Parse attributes (e.g., lang="scss")
        // Use literal parsing - style attributes don't have expression syntax
        let attributes = self.parse_attributes_literal()?;

        // Verify we're at > and save position for content start
        if !self.check(TokenKind::RightAngle) {
            return Err(self.error_expected_found("'>'"));
        }

        // Content starts right after the >
        let content_start = self.current_end();

        // Find closing </style> tag (raw scan, `/<\/style\s*>/`; see
        // `find_raw_text_close` for the shared string-context limitation).
        let content_end = find_raw_text_close(self.source, content_start, b"style")
            .ok_or_else(|| self.error_msg_at("Unterminated style tag", start))?;

        // Reposition the lexer to the closing `</style>` tag (resumes at `<`) and
        // consume it; `find_raw_text_close` already guaranteed it exists.
        self.advance_to_position(content_end)?;
        let end = self.parse_closing_tag("style")?;

        // Parse CSS content (shares the document's bump arena)
        let css_content = &self.source[content_start..content_end];
        let css_stylesheet = tsv_css::__private::parse_embedded(
            css_content,
            content_start,
            self.island_nesting(),
            self.arena,
        )?;

        Ok(Style {
            span: Span {
                start: start as u32,
                end,
            },
            content_span: Span {
                start: content_start as u32,
                end: content_end as u32,
            },
            attributes: attributes.into_bump_slice(),
            css_stylesheet,
        })
    }
}