vize_canon 0.153.0

Canon - The standard of correctness for Vize type checking
Documentation
use oxc_allocator::Allocator as OxcAllocator;
use oxc_parser::Parser as OxcParser;
use oxc_span::SourceType;
use vize_carton::{String, ToCompactString, profile};

#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct ScriptParseDiagnostic {
    pub message: String,
    pub start: u32,
    pub end: u32,
}

pub(crate) fn collect_script_parse_diagnostics(
    source: &str,
    source_offset: u32,
) -> Vec<ScriptParseDiagnostic> {
    let allocator = OxcAllocator::default();
    let source_type = SourceType::from_path("script.ts").unwrap_or_default();
    let parsed = profile!(
        "canon.script.parse_errors",
        OxcParser::new(&allocator, source, source_type).parse()
    );

    let mut diagnostics: Vec<ScriptParseDiagnostic> = parsed
        .errors
        .iter()
        .map(|error| {
            let (local_start, local_end) = diagnostic_span(error, source.len());
            ScriptParseDiagnostic {
                message: error.to_compact_string(),
                start: source_offset + local_start,
                end: source_offset + local_end,
            }
        })
        .collect();

    if parsed.panicked && diagnostics.is_empty() {
        let fallback_end = source_offset + (source.len() as u32).max(1);
        diagnostics.push(ScriptParseDiagnostic {
            message: "Parser panicked while parsing script".into(),
            start: source_offset,
            end: fallback_end,
        });
    }

    diagnostics
}

fn diagnostic_span(error: &oxc_diagnostics::OxcDiagnostic, source_len: usize) -> (u32, u32) {
    let fallback_end = source_len.max(1);
    let Some(label) = error.labels.as_ref().and_then(|labels| {
        labels
            .iter()
            .find(|label| label.primary())
            .or_else(|| labels.first())
    }) else {
        return (0, fallback_end as u32);
    };

    let start = label.offset().min(source_len);
    let end = start.saturating_add(label.len().max(1)).min(fallback_end);
    (start as u32, end.max(start + 1) as u32)
}