svelte-syntax 0.1.5

Lightweight syntax-layer crate for the Rust Svelte toolchain
Documentation
use std::sync::Arc;

use oxc_ast::ast::{BindingPattern, Expression as OxcExpression, ObjectPropertyKind};
use oxc_span::GetSpan;

use crate::ast::modern::{Expression, JsNodeHandle};

pub(crate) fn split_debug_tag_arguments(expression: Expression) -> Box<[Expression]> {
    if let Some(OxcExpression::SequenceExpression(sequence)) = expression.oxc_expression() {
        let root = match &expression.node {
            Some(JsNodeHandle::Expression(root)) => Some(root.clone()),
            Some(JsNodeHandle::SequenceItem { root, .. }) => Some(root.clone()),
            _ => None,
        };

        if let Some(root) = root {
            return sequence
                .expressions
                .iter()
                .enumerate()
                .map(|(index, node)| {
                    let span = node.span();
                    Expression::from_sequence_item(
                        root.clone(),
                        index,
                        span.start as usize,
                        span.end as usize,
                    )
                })
                .collect::<Vec<_>>()
                .into_boxed_slice();
        }
    }

    vec![expression].into_boxed_slice()
}

pub(crate) fn invalid_binding_expression_error(
    expression: &Expression,
) -> Option<(usize, Arc<str>)> {
    if let Some(oxc) = expression.oxc_expression()
        && let Some(error) = invalid_binding_expression_error_oxc(oxc)
    {
        return Some(error);
    }

    invalid_binding_pattern_error(expression.oxc_pattern()?)
}

fn invalid_binding_expression_error_oxc(
    expression: &OxcExpression<'_>,
) -> Option<(usize, Arc<str>)> {
    match expression {
        OxcExpression::ObjectExpression(expression) => {
            for (index, property) in expression.properties.iter().enumerate() {
                if property.is_spread() && index + 1 < expression.properties.len() {
                    let start = property.span().end as usize;
                    return Some((
                        start,
                        Arc::from("Comma is not permitted after the rest element"),
                    ));
                }
                if let ObjectPropertyKind::ObjectProperty(property) = property
                    && let Some(error) = invalid_binding_expression_error_oxc(&property.value)
                {
                    return Some(error);
                }
            }
            None
        }
        OxcExpression::ArrayExpression(expression) => {
            for (index, element) in expression.elements.iter().enumerate() {
                if element.is_spread() && index + 1 < expression.elements.len() {
                    let start = element.span().end as usize;
                    return Some((
                        start,
                        Arc::from("Comma is not permitted after the rest element"),
                    ));
                }
            }
            None
        }
        _ => None,
    }
}

fn invalid_binding_pattern_error(pattern: &BindingPattern<'_>) -> Option<(usize, Arc<str>)> {
    match pattern {
        BindingPattern::ObjectPattern(pattern) => {
            for (index, property) in pattern.properties.iter().enumerate() {
                if let Some(error) = invalid_binding_pattern_error(&property.value) {
                    return Some(error);
                }
                if index + 1 < pattern.properties.len() && pattern.rest.is_some() {
                    let start = property.span.end as usize;
                    return Some((
                        start,
                        Arc::from("Comma is not permitted after the rest element"),
                    ));
                }
            }
            None
        }
        BindingPattern::ArrayPattern(pattern) => {
            if pattern.rest.is_some() && pattern.elements.iter().flatten().count() > 0 {
                let start = pattern
                    .elements
                    .iter()
                    .flatten()
                    .last()
                    .map(|element| element.span().end as usize)
                    .unwrap_or(pattern.span.start as usize);
                return Some((
                    start,
                    Arc::from("Comma is not permitted after the rest element"),
                ));
            }
            None
        }
        BindingPattern::AssignmentPattern(pattern) => invalid_binding_pattern_error(&pattern.left),
        BindingPattern::BindingIdentifier(_) => None,
    }
}