svelte-compiler 0.1.4

Core compiler API for the Rust Svelte toolchain
Documentation
use std::rc::Rc;

use oxc_ast::ast::Statement;
use oxc_span::SourceType as OxcSourceType;

use svelte_syntax::JsProgram;

#[derive(Debug)]
pub(crate) struct SvelteOxcParser<'src> {
    source: &'src str,
    is_ts: bool,
}

impl<'src> SvelteOxcParser<'src> {
    pub(crate) fn new(source: &'src str) -> Self {
        Self {
            source,
            is_ts: false,
        }
    }

    pub(crate) fn with_typescript(mut self, is_ts: bool) -> Self {
        self.is_ts = is_ts;
        self
    }

    pub(crate) fn parse_program_for_compile(&self) -> Option<Rc<JsProgram>> {
        let source_type = source_type(self.is_ts);
        let parsed = Rc::new(JsProgram::parse(self.source, source_type));
        parsed.errors().is_empty().then_some(parsed)
    }

    pub(crate) fn parse_import_ranges_for_compile(&self) -> Option<Vec<(usize, usize)>> {
        let parsed = JsProgram::parse(self.source, source_type(self.is_ts));
        if !parsed.errors().is_empty() {
            return None;
        }

        let mut ranges = Vec::with_capacity(parsed.program().body.len());
        for statement in parsed.program().body.iter() {
            let Statement::ImportDeclaration(declaration) = statement else {
                return None;
            };
            ranges.push((
                declaration.span.start as usize,
                declaration.span.end as usize,
            ));
        }

        Some(ranges)
    }
}

fn source_type(is_ts: bool) -> OxcSourceType {
    if is_ts {
        OxcSourceType::ts().with_module(true)
    } else {
        OxcSourceType::mjs()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    fn program_body_len(program: &JsProgram) -> usize {
        program.program().body.len()
    }

    #[test]
    fn parses_program_with_rune_call_in_js_mode() {
        let source = "let playbackRate = $state(0.5);";
        let program = SvelteOxcParser::new(source)
            .parse_program_for_compile()
            .expect("program should parse");

        assert_eq!(program_body_len(&program), 1);
    }

    #[test]
    fn parses_program_with_dollar_dollar_props_in_js_mode() {
        let source = "let x = $$props;";
        let program = SvelteOxcParser::new(source)
            .parse_program_for_compile()
            .expect("program should parse");

        assert_eq!(program_body_len(&program), 1);
    }
}