use super::JsxFile;
use crate::file::{Reference, ScopeId, ScriptUnitId};
use crate::resolution::SyntaxKind;
use core::ops::Range;
use vize_l0::Span;
pub(super) struct Record<'a> {
pub kind: SyntaxKind<'a>,
pub span: Span,
pub unit: ScriptUnitId,
pub scope: ScopeId,
pub parent: Option<usize>,
pub subtree_end: usize,
pub references: Range<usize>,
}
#[derive(Clone, Copy)]
pub struct JsxNode<'f, 'a> {
owner: &'f JsxFile<'a>,
index: usize,
}
impl<'f, 'a> JsxNode<'f, 'a> {
pub(super) fn new(owner: &'f JsxFile<'a>, index: usize) -> Self {
Self { owner, index }
}
fn record(self) -> Option<&'f Record<'a>> {
self.owner.records.get(self.index)
}
#[must_use]
pub fn owner(self) -> &'f JsxFile<'a> {
self.owner
}
#[must_use]
pub fn index(self) -> usize {
self.index
}
#[must_use]
pub fn kind(self) -> Option<SyntaxKind<'a>> {
Some(self.record()?.kind)
}
#[must_use]
pub fn span(self) -> Option<Span> {
Some(self.record()?.span)
}
#[must_use]
pub fn unit(self) -> Option<ScriptUnitId> {
Some(self.record()?.unit)
}
#[must_use]
pub fn scope(self) -> Option<ScopeId> {
Some(self.record()?.scope)
}
#[must_use]
pub fn parent(self) -> Option<Self> {
self.owner.node(self.record()?.parent?)
}
#[must_use]
pub fn source(self) -> Option<&'a str> {
let span = self.record()?.span;
self.owner
.file
.artifact()
.source()
.get(span.start as usize..span.end as usize)
}
#[must_use]
pub fn references(self) -> Option<&'f [Reference]> {
self.owner
.file
.references()
.get(self.record()?.references.clone())
}
#[must_use]
pub fn children(self) -> JsxChildren<'f, 'a> {
JsxChildren {
owner: self.owner,
next: self.index + 1,
end: self.record().map_or(self.index + 1, |row| row.subtree_end),
}
}
pub fn subtree(self) -> impl ExactSizeIterator<Item = Self> {
let end = self.record().map_or(self.index, |row| row.subtree_end);
(self.index..end).map(move |index| Self::new(self.owner, index))
}
#[must_use]
pub fn same_owner(self, other: JsxNode<'_, '_>) -> bool {
core::ptr::eq(self.owner, other.owner)
}
}
pub struct JsxChildren<'f, 'a> {
owner: &'f JsxFile<'a>,
next: usize,
end: usize,
}
impl<'f, 'a> Iterator for JsxChildren<'f, 'a> {
type Item = JsxNode<'f, 'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.next >= self.end {
return None;
}
let node = self.owner.node(self.next)?;
self.next = node.record()?.subtree_end;
Some(node)
}
}