mod analysis;
mod tracker;
use vize_carton::lsp::VueReactiveType;
use vize_carton::{CompactString, FxHashSet, SmallVec};
pub use tracker::ReactivityTracker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ReactiveBindingId(u32);
impl ReactiveBindingId {
pub fn new(id: u32) -> Self {
Self(id)
}
pub fn as_u32(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ReactiveOrigin {
Ref,
ShallowRef,
Reactive,
ShallowReactive,
Readonly,
ShallowReadonly,
Computed,
ToRef,
ToRefs,
Inject,
Props,
PiniaStore,
ComposableReturn { composable_name: CompactString },
Derived { source: ReactiveBindingId },
Unknown,
}
impl ReactiveOrigin {
pub fn reactive_type(&self) -> VueReactiveType {
match self {
Self::Ref | Self::ToRef | Self::Computed => VueReactiveType::Ref,
Self::ShallowRef => VueReactiveType::ShallowRef,
Self::Reactive | Self::ToRefs | Self::Props | Self::PiniaStore => {
VueReactiveType::Reactive
}
Self::ShallowReactive => VueReactiveType::ShallowReactive,
Self::Readonly => VueReactiveType::Readonly,
Self::ShallowReadonly => VueReactiveType::ShallowReadonly,
Self::Inject | Self::ComposableReturn { .. } | Self::Unknown => {
VueReactiveType::Reactive
}
Self::Derived { .. } => VueReactiveType::Reactive,
}
}
pub fn is_deep(&self) -> bool {
!matches!(
self,
Self::ShallowRef | Self::ShallowReactive | Self::ShallowReadonly
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BindingState {
Active,
ReactivityLost,
Moved,
Escaped,
Reassigned,
}
#[derive(Debug, Clone)]
pub struct ReactiveBinding {
pub id: ReactiveBindingId,
pub name: CompactString,
pub origin: ReactiveOrigin,
pub state: BindingState,
pub is_mutable: bool,
pub start: u32,
pub end: u32,
pub scope_depth: u32,
pub value_accessed: bool,
pub derived_bindings: SmallVec<[ReactiveBindingId; 4]>,
pub use_sites: SmallVec<[UseSite; 8]>,
}
impl ReactiveBinding {
pub fn loses_reactivity_on_destructure(&self) -> bool {
self.origin
.reactive_type()
.loses_reactivity_on_destructure()
}
pub fn loses_reactivity_on_spread(&self) -> bool {
self.origin.reactive_type().loses_reactivity_on_spread()
}
pub fn is_ref_type(&self) -> bool {
self.origin.reactive_type().is_ref()
}
}
#[derive(Debug, Clone)]
pub struct UseSite {
pub kind: UseSiteKind,
pub start: u32,
pub end: u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UseSiteKind {
Read,
PropertyAccess { property: CompactString },
ValueAccess,
Destructure { extracted_props: Vec<CompactString> },
Spread,
FunctionArg {
fn_name: CompactString,
arg_index: usize,
},
Return,
Assignment { target: CompactString },
TemplateExpression,
Reassignment,
ClosureCapture { closure_start: u32 },
ExternalEscape { target: CompactString },
}
#[derive(Debug, Clone)]
pub struct ReactivityViolation {
pub binding_id: ReactiveBindingId,
pub kind: ViolationKind,
pub start: u32,
pub end: u32,
pub message: CompactString,
pub suggestion: Option<CompactString>,
pub severity: ViolationSeverity,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ViolationKind {
DestructuringLoss { extracted_props: Vec<CompactString> },
SpreadLoss,
Reassignment,
MissingValueAccess,
ScopeEscape { escape_target: CompactString },
UnsafeClosureCapture,
ExternalMutation,
WrongUnwrapContext,
PiniaDestructure,
PropsDestructure,
InjectDestructure,
ToRefsOnNonReactive,
DoubleUnwrap,
ReactiveConst,
ShallowDeepMismatch,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ViolationSeverity {
Error,
Warning,
Info,
Hint,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub(crate) struct ReactiveScope {
pub depth: u32,
pub bindings: FxHashSet<ReactiveBindingId>,
pub is_setup_scope: bool,
pub is_async: bool,
pub parent_scope: Option<u32>,
}