use alloc::{boxed::Box, vec::Vec};
use vize_l0::Span;
use vize_l2::lang::js::{JsxFile, JsxNode};
use vize_l2::resolution::BindingId;
mod build;
pub use build::build_jsx_decisions;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JsxDecisionKind<'a> {
OriginalExpression,
Root,
Element,
Opening {
self_closing: bool,
},
Closing,
Intrinsic(&'a str),
Component(&'a str),
Member,
Property(&'a str),
StaticAttribute {
name: &'a str,
value: Option<&'a str>,
},
ExpressionAttribute {
name: &'a str,
},
AttributeName(&'a str),
AttributeString(&'a str),
Text(&'a str),
EmptyContainer,
ExpressionContainer,
Read {
name: &'a str,
binding: BindingId,
},
Number(u64),
String(&'a str),
Boolean(bool),
Null,
Empty,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JsxIssueKind {
InvalidRecord,
Expression,
Fragment,
DirectiveOrSlot,
SpreadAttribute,
SpreadChild,
Attribute,
UnresolvedComponent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct JsxIssue {
pub kind: JsxIssueKind,
pub span: Span,
}
pub struct NativeJsxAnalysis<'a> {
owner: JsxFile<'a>,
decisions: Vec<JsxDecisionKind<'a>>,
}
impl<'a> NativeJsxAnalysis<'a> {
#[must_use]
pub fn owner(&self) -> &JsxFile<'a> {
&self.owner
}
#[must_use]
pub fn decision_for<'f>(&'f self, node: JsxNode<'f, 'a>) -> Option<JsxDecision<'f, 'a>> {
if !core::ptr::eq(node.owner(), &self.owner) {
return None;
}
Some(JsxDecision {
node,
kind: *self.decisions.get(node.index())?,
})
}
pub fn decisions(&self) -> impl Iterator<Item = JsxDecision<'_, 'a>> {
self.decisions
.iter()
.enumerate()
.filter_map(|(index, kind)| {
Some(JsxDecision {
node: self.owner.node(index)?,
kind: *kind,
})
})
}
}
#[derive(Clone, Copy)]
pub struct JsxDecision<'owner, 'a> {
node: JsxNode<'owner, 'a>,
kind: JsxDecisionKind<'a>,
}
impl<'owner, 'a> JsxDecision<'owner, 'a> {
#[must_use]
pub fn node(self) -> JsxNode<'owner, 'a> {
self.node
}
#[must_use]
pub fn kind(self) -> JsxDecisionKind<'a> {
self.kind
}
}
pub struct RejectedJsxAnalysis<'a> {
owner: JsxFile<'a>,
issues: Vec<JsxIssue>,
}
impl<'a> RejectedJsxAnalysis<'a> {
#[must_use]
pub fn owner(&self) -> &JsxFile<'a> {
&self.owner
}
#[must_use]
pub fn issues(&self) -> &[JsxIssue] {
&self.issues
}
}
type BuildResult<'a> = Result<NativeJsxAnalysis<'a>, Box<RejectedJsxAnalysis<'a>>>;