use std::borrow::Cow;
use rustc_hash::FxHashMap;
use oxc_index::IndexVec;
use oxc_span::Span;
use oxc_str::Ident;
use oxc_syntax::{
class::{ClassId, ElementId, ElementKind},
node::NodeId,
};
#[derive(Debug)]
pub struct Element<'a> {
pub name: Cow<'a, str>,
pub span: Span,
pub is_private: bool,
pub r#static: bool,
pub kind: ElementKind,
}
impl<'a> Element<'a> {
pub fn new(
name: Cow<'a, str>,
span: Span,
r#static: bool,
is_private: bool,
kind: ElementKind,
) -> Self {
Self { name, span, is_private, r#static, kind }
}
}
#[derive(Debug)]
pub struct PrivateIdentifierReference<'a> {
pub id: NodeId,
pub name: Ident<'a>,
pub span: Span,
pub element_ids: Vec<ElementId>,
}
impl<'a> PrivateIdentifierReference<'a> {
pub fn new(id: NodeId, name: Ident<'a>, span: Span, element_ids: Vec<ElementId>) -> Self {
Self { id, name, span, element_ids }
}
}
#[derive(Debug, Default)]
pub struct ClassTable<'a> {
pub parent_ids: FxHashMap<ClassId, ClassId>,
pub declarations: IndexVec<ClassId, NodeId>,
pub elements: IndexVec<ClassId, IndexVec<ElementId, Element<'a>>>,
pub private_identifier_references: IndexVec<ClassId, Vec<PrivateIdentifierReference<'a>>>,
}
impl<'a> ClassTable<'a> {
pub fn ancestors(&self, class_id: ClassId) -> impl Iterator<Item = ClassId> + '_ {
std::iter::successors(Some(class_id), |class_id| self.parent_ids.get(class_id).copied())
}
pub fn len(&self) -> usize {
self.declarations.raw.len()
}
pub fn iter_enumerated(&self) -> impl Iterator<Item = (ClassId, &NodeId)> + '_ {
self.declarations.iter_enumerated()
}
pub fn iter_private_identifiers(
&self,
class_id: ClassId,
) -> impl Iterator<Item = &PrivateIdentifierReference<'_>> + '_ {
self.private_identifier_references[class_id].iter()
}
pub fn get_node_id(&self, class_id: ClassId) -> NodeId {
self.declarations[class_id]
}
pub fn get_element_ids(
&self,
class_id: ClassId,
name: Ident<'_>,
is_private: bool,
) -> Vec<ElementId> {
let mut element_ids = vec![];
for (element_id, element) in self.elements[class_id].iter_enumerated() {
if element.name == name && element.is_private == is_private {
element_ids.push(element_id);
if element.kind.intersects(ElementKind::Accessor | ElementKind::Property) {
break;
}
if element_ids.len() == 2 {
break;
}
}
}
element_ids
}
pub fn has_private_definition(&self, class_id: ClassId, name: Ident<'_>) -> bool {
self.elements[class_id].iter().any(|p| p.is_private && p.name == name)
}
pub fn declare_class(&mut self, parent_id: Option<ClassId>, node_id: NodeId) -> ClassId {
let class_id = self.declarations.push(node_id);
if let Some(parent_id) = parent_id {
self.parent_ids.insert(class_id, parent_id);
}
self.elements.push(IndexVec::default());
self.private_identifier_references.push(Vec::new());
class_id
}
pub fn add_element(&mut self, class_id: ClassId, element: Element<'a>) {
self.elements[class_id].push(element);
}
pub fn add_private_identifier_reference(
&mut self,
class_id: ClassId,
private_identifier_reference: PrivateIdentifierReference<'a>,
) {
self.private_identifier_references[class_id].push(private_identifier_reference);
}
}