use alloc::vec::Vec;
use vize_l0::{Span, id::NodeId, side_table::SideTable};
use vize_l2::{
expr::JsExpr,
op::{BindingOp, Op},
};
pub(super) mod build;
mod context;
pub mod control;
mod dependencies;
pub(in crate::decision) mod file;
mod for_head;
mod handler;
pub mod vue;
pub use context::ContextOnly;
pub use dependencies::DomDependency;
pub use file::{DomFileExpression, NativeFileAnalysis, build_dom_file_decisions};
pub use for_head::DomFileForHead;
pub use handler::DomFileHandler;
pub trait DomExpressionFacts {
fn is_context_only(&self, expression: &JsExpr<'_>) -> bool;
}
pub struct LiteralExpressions;
impl DomExpressionFacts for LiteralExpressions {
fn is_context_only(&self, _: &JsExpr<'_>) -> bool {
false
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DomUnsupported {
Operation,
Namespace,
ElementRole,
SpecialAttribute,
Binding,
BindingName,
BindingModifiers,
MissingValue,
DuplicateProperty,
Expression,
ConditionalShape,
ConditionalCondition,
ConditionalRoot,
FileExpression,
FileHandler,
FileForHead,
ForCollectionAccess,
ForCollectionRuntime,
ForShape,
ForBody,
HandlerSyntax,
HandlerAccess,
FileScope,
FileBinding,
VueReadAccess,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DomRejection {
pub node: NodeId,
pub span: Span,
pub reason: DomUnsupported,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DomRootKind {
Empty,
Direct,
Fragment { single_non_comment: bool },
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DomText {
pub nodes: Vec<NodeId>,
pub dynamic: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DomChild {
Text(DomText),
Node(NodeId),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DomChildren {
Empty,
Text(DomText),
Array(Vec<DomChild>),
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct DomChanges {
pub text: bool,
pub class: bool,
pub style: bool,
pub properties: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PropertyRole {
Property,
Class,
Style,
Event,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValueKind {
LiteralConstant,
ContextDependent,
FileDependent,
}
impl ValueKind {
#[must_use]
pub const fn is_dynamic(self) -> bool {
matches!(self, Self::ContextDependent | Self::FileDependent)
}
}
#[derive(Debug)]
pub struct DomNode<'owner, 'arena> {
pub(super) op: &'owner Op<'arena>,
pub block_eligible: bool,
pub children: DomChildren,
pub changes: DomChanges,
pub dynamic_property_bindings: Vec<NodeId>,
}
impl<'owner, 'arena> DomNode<'owner, 'arena> {
#[must_use]
pub fn op(&self) -> &'owner Op<'arena> {
self.op
}
}
#[derive(Debug)]
pub struct DomBinding<'owner, 'arena> {
pub(super) binding: &'owner BindingOp<'arena>,
pub role: PropertyRole,
pub value: ValueKind,
}
impl<'owner, 'arena> DomBinding<'owner, 'arena> {
#[must_use]
pub fn binding(&self) -> &'owner BindingOp<'arena> {
self.binding
}
}
#[derive(Debug)]
pub struct DomRoot {
pub kind: DomRootKind,
pub children: Vec<DomChild>,
}
#[derive(Debug)]
pub struct DomFacts<'owner, 'arena> {
pub(super) root: DomRoot,
pub(super) nodes: SideTable<DomNode<'owner, 'arena>>,
pub(super) bindings: SideTable<DomBinding<'owner, 'arena>>,
pub(super) controls: SideTable<control::DomConditional<'owner, 'arena>>,
pub(super) dependencies: Vec<DomDependency>,
pub(super) file_expressions: SideTable<DomFileExpression<'owner, 'arena>>,
pub(super) file_handlers: SideTable<DomFileHandler<'owner, 'arena>>,
pub(super) file_for_heads: SideTable<DomFileForHead<'owner, 'arena>>,
pub(super) vue_expressions: SideTable<vue::VueRenderExpression<'owner, 'arena>>,
pub(super) unsupported: Vec<DomRejection>,
}
impl<'owner, 'arena> DomFacts<'owner, 'arena> {
#[must_use]
pub fn root(&self) -> &DomRoot {
&self.root
}
#[must_use]
pub fn node(&self, id: NodeId) -> Option<&DomNode<'owner, 'arena>> {
self.nodes.get(id)
}
#[must_use]
pub fn binding(&self, id: NodeId) -> Option<&DomBinding<'owner, 'arena>> {
self.bindings.get(id)
}
#[must_use]
pub fn conditional(&self, id: NodeId) -> Option<&control::DomConditional<'owner, 'arena>> {
self.controls.get(id)
}
#[must_use]
pub fn dependencies(&self) -> &[DomDependency] {
&self.dependencies
}
#[must_use]
pub fn file_expression(&self, id: NodeId) -> Option<&DomFileExpression<'owner, 'arena>> {
self.file_expressions.get(id)
}
#[must_use]
pub fn file_handler(&self, id: NodeId) -> Option<&DomFileHandler<'owner, 'arena>> {
self.file_handlers.get(id)
}
#[must_use]
pub fn file_for_head(&self, id: NodeId) -> Option<&DomFileForHead<'owner, 'arena>> {
self.file_for_heads.get(id)
}
#[must_use]
pub fn unsupported(&self) -> &[DomRejection] {
&self.unsupported
}
}