use super::nodes::comment_ast::{
LazyJsdocBlock, LazyJsdocBorrowsTagBody, LazyJsdocDescriptionLine, LazyJsdocGenericTagBody,
LazyJsdocIdentifier, LazyJsdocInlineTag, LazyJsdocNamepathSource, LazyJsdocParameterName,
LazyJsdocRawTagBody, LazyJsdocTag, LazyJsdocTagBody, LazyJsdocTagName, LazyJsdocTagNameValue,
LazyJsdocText, LazyJsdocTypeLine, LazyJsdocTypeSource,
};
use super::nodes::type_node::{
LazyTypeAny, LazyTypeAsserts, LazyTypeAssertsPlain, LazyTypeCallSignature, LazyTypeConditional,
LazyTypeConstructorSignature, LazyTypeFunction, LazyTypeGeneric, LazyTypeImport,
LazyTypeIndexSignature, LazyTypeIndexedAccessIndex, LazyTypeInfer, LazyTypeIntersection,
LazyTypeJsdocObjectField, LazyTypeKeyOf, LazyTypeKeyValue, LazyTypeMappedType,
LazyTypeMethodSignature, LazyTypeName, LazyTypeNamePath, LazyTypeNode, LazyTypeNotNullable,
LazyTypeNull, LazyTypeNullable, LazyTypeNumber, LazyTypeObject, LazyTypeObjectField,
LazyTypeOptional, LazyTypeParameterList, LazyTypeParenthesis, LazyTypePredicate,
LazyTypeProperty, LazyTypeReadonlyArray, LazyTypeReadonlyProperty, LazyTypeSpecialNamePath,
LazyTypeStringValue, LazyTypeSymbol, LazyTypeTemplateLiteral, LazyTypeTuple, LazyTypeTypeOf,
LazyTypeTypeParameter, LazyTypeUndefined, LazyTypeUnion, LazyTypeUniqueSymbol, LazyTypeUnknown,
LazyTypeVariadic,
};
pub trait LazyJsdocVisitor<'a> {
fn visit_block(&mut self, block: LazyJsdocBlock<'a>) {
self.visit_block_default(block);
}
fn visit_block_default(&mut self, block: LazyJsdocBlock<'a>) {
for line in block.description_lines() {
self.visit_description_line(line);
}
for tag in block.tags() {
self.visit_tag(tag);
}
for inline in block.inline_tags() {
self.visit_inline_tag(inline);
}
}
fn visit_description_line(&mut self, _node: LazyJsdocDescriptionLine<'a>) {}
fn visit_tag(&mut self, tag: LazyJsdocTag<'a>) {
self.visit_tag_default(tag);
}
fn visit_tag_default(&mut self, tag: LazyJsdocTag<'a>) {
self.visit_tag_name(tag.tag());
if let Some(rt) = tag.raw_type() {
self.visit_type_source(rt);
}
if let Some(name) = tag.name() {
self.visit_tag_name_value(name);
}
if let Some(pt) = tag.parsed_type() {
self.visit_type_node(pt);
}
if let Some(body) = tag.body() {
self.visit_tag_body(body);
}
for line in tag.type_lines() {
self.visit_type_line(line);
}
for line in tag.description_lines() {
self.visit_description_line(line);
}
for inline in tag.inline_tags() {
self.visit_inline_tag(inline);
}
}
fn visit_tag_body(&mut self, body: LazyJsdocTagBody<'a>) {
match body {
LazyJsdocTagBody::Generic(b) => self.visit_generic_tag_body(b),
LazyJsdocTagBody::Borrows(b) => self.visit_borrows_tag_body(b),
LazyJsdocTagBody::Raw(b) => self.visit_raw_tag_body(b),
}
}
fn visit_tag_name(&mut self, _node: LazyJsdocTagName<'a>) {}
fn visit_tag_name_value(&mut self, _node: LazyJsdocTagNameValue<'a>) {}
fn visit_type_source(&mut self, _node: LazyJsdocTypeSource<'a>) {}
fn visit_type_line(&mut self, _node: LazyJsdocTypeLine<'a>) {}
fn visit_inline_tag(&mut self, _node: LazyJsdocInlineTag<'a>) {}
fn visit_generic_tag_body(&mut self, _node: LazyJsdocGenericTagBody<'a>) {}
fn visit_borrows_tag_body(&mut self, _node: LazyJsdocBorrowsTagBody<'a>) {}
fn visit_raw_tag_body(&mut self, _node: LazyJsdocRawTagBody<'a>) {}
fn visit_parameter_name(&mut self, _node: LazyJsdocParameterName<'a>) {}
fn visit_namepath_source(&mut self, _node: LazyJsdocNamepathSource<'a>) {}
fn visit_identifier(&mut self, _node: LazyJsdocIdentifier<'a>) {}
fn visit_text(&mut self, _node: LazyJsdocText<'a>) {}
fn visit_type_node(&mut self, node: LazyTypeNode<'a>) {
match node {
LazyTypeNode::Name(n) => self.visit_type_name(n),
LazyTypeNode::Number(n) => self.visit_type_number(n),
LazyTypeNode::StringValue(n) => self.visit_type_string_value(n),
LazyTypeNode::Property(n) => self.visit_type_property(n),
LazyTypeNode::SpecialNamePath(n) => self.visit_type_special_name_path(n),
LazyTypeNode::Union(n) => self.visit_type_union(n),
LazyTypeNode::Intersection(n) => self.visit_type_intersection(n),
LazyTypeNode::Generic(n) => self.visit_type_generic(n),
LazyTypeNode::Function(n) => self.visit_type_function(n),
LazyTypeNode::Object(n) => self.visit_type_object(n),
LazyTypeNode::Tuple(n) => self.visit_type_tuple(n),
LazyTypeNode::Parenthesis(n) => self.visit_type_parenthesis(n),
LazyTypeNode::NamePath(n) => self.visit_type_name_path(n),
LazyTypeNode::Nullable(n) => self.visit_type_nullable(n),
LazyTypeNode::NotNullable(n) => self.visit_type_not_nullable(n),
LazyTypeNode::Optional(n) => self.visit_type_optional(n),
LazyTypeNode::Variadic(n) => self.visit_type_variadic(n),
LazyTypeNode::Conditional(n) => self.visit_type_conditional(n),
LazyTypeNode::Infer(n) => self.visit_type_infer(n),
LazyTypeNode::KeyOf(n) => self.visit_type_key_of(n),
LazyTypeNode::TypeOf(n) => self.visit_type_type_of(n),
LazyTypeNode::Import(n) => self.visit_type_import(n),
LazyTypeNode::Predicate(n) => self.visit_type_predicate(n),
LazyTypeNode::Asserts(n) => self.visit_type_asserts(n),
LazyTypeNode::AssertsPlain(n) => self.visit_type_asserts_plain(n),
LazyTypeNode::ReadonlyArray(n) => self.visit_type_readonly_array(n),
LazyTypeNode::ObjectField(n) => self.visit_type_object_field(n),
LazyTypeNode::JsdocObjectField(n) => self.visit_type_jsdoc_object_field(n),
LazyTypeNode::IndexedAccessIndex(n) => self.visit_type_indexed_access_index(n),
LazyTypeNode::CallSignature(n) => self.visit_type_call_signature(n),
LazyTypeNode::ConstructorSignature(n) => self.visit_type_constructor_signature(n),
LazyTypeNode::TypeParameter(n) => self.visit_type_type_parameter(n),
LazyTypeNode::ParameterList(n) => self.visit_type_parameter_list(n),
LazyTypeNode::ReadonlyProperty(n) => self.visit_type_readonly_property(n),
LazyTypeNode::KeyValue(n) => self.visit_type_key_value(n),
LazyTypeNode::IndexSignature(n) => self.visit_type_index_signature(n),
LazyTypeNode::MappedType(n) => self.visit_type_mapped_type(n),
LazyTypeNode::MethodSignature(n) => self.visit_type_method_signature(n),
LazyTypeNode::TemplateLiteral(n) => self.visit_type_template_literal(n),
LazyTypeNode::Symbol(n) => self.visit_type_symbol(n),
LazyTypeNode::Null(n) => self.visit_type_null(n),
LazyTypeNode::Undefined(n) => self.visit_type_undefined(n),
LazyTypeNode::Any(n) => self.visit_type_any(n),
LazyTypeNode::Unknown(n) => self.visit_type_unknown(n),
LazyTypeNode::UniqueSymbol(n) => self.visit_type_unique_symbol(n),
}
}
fn visit_type_name(&mut self, _node: LazyTypeName<'a>) {}
fn visit_type_number(&mut self, _node: LazyTypeNumber<'a>) {}
fn visit_type_string_value(&mut self, _node: LazyTypeStringValue<'a>) {}
fn visit_type_property(&mut self, _node: LazyTypeProperty<'a>) {}
fn visit_type_special_name_path(&mut self, _node: LazyTypeSpecialNamePath<'a>) {}
fn visit_type_union(&mut self, node: LazyTypeUnion<'a>) {
self.visit_type_union_default(node);
}
fn visit_type_union_default(&mut self, node: LazyTypeUnion<'a>) {
for el in node.elements() {
self.visit_type_node(el);
}
}
fn visit_type_intersection(&mut self, node: LazyTypeIntersection<'a>) {
self.visit_type_intersection_default(node);
}
fn visit_type_intersection_default(&mut self, node: LazyTypeIntersection<'a>) {
for el in node.elements() {
self.visit_type_node(el);
}
}
fn visit_type_generic(&mut self, node: LazyTypeGeneric<'a>) {
self.visit_type_generic_default(node);
}
fn visit_type_generic_default(&mut self, node: LazyTypeGeneric<'a>) {
if let Some(l) = node.left() {
self.visit_type_node(l);
}
for el in node.elements() {
self.visit_type_node(el);
}
}
fn visit_type_function(&mut self, node: LazyTypeFunction<'a>) {
self.visit_type_function_default(node);
}
fn visit_type_function_default(&mut self, node: LazyTypeFunction<'a>) {
if let Some(params) = node.parameters() {
self.visit_type_parameter_list(params);
}
if let Some(ret) = node.return_type() {
self.visit_type_node(ret);
}
if let Some(tp) = node.type_parameters() {
self.visit_type_parameter_list(tp);
}
}
fn visit_type_object(&mut self, node: LazyTypeObject<'a>) {
self.visit_type_object_default(node);
}
fn visit_type_object_default(&mut self, node: LazyTypeObject<'a>) {
for el in node.elements() {
self.visit_type_node(el);
}
}
fn visit_type_tuple(&mut self, node: LazyTypeTuple<'a>) {
self.visit_type_tuple_default(node);
}
fn visit_type_tuple_default(&mut self, node: LazyTypeTuple<'a>) {
for el in node.elements() {
self.visit_type_node(el);
}
}
fn visit_type_parenthesis(&mut self, node: LazyTypeParenthesis<'a>) {
self.visit_type_parenthesis_default(node);
}
fn visit_type_parenthesis_default(&mut self, node: LazyTypeParenthesis<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_name_path(&mut self, node: LazyTypeNamePath<'a>) {
self.visit_type_name_path_default(node);
}
fn visit_type_name_path_default(&mut self, node: LazyTypeNamePath<'a>) {
if let Some(l) = node.left() {
self.visit_type_node(l);
}
if let Some(r) = node.right() {
self.visit_type_node(r);
}
}
fn visit_type_nullable(&mut self, node: LazyTypeNullable<'a>) {
self.visit_type_nullable_default(node);
}
fn visit_type_nullable_default(&mut self, node: LazyTypeNullable<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_not_nullable(&mut self, node: LazyTypeNotNullable<'a>) {
self.visit_type_not_nullable_default(node);
}
fn visit_type_not_nullable_default(&mut self, node: LazyTypeNotNullable<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_optional(&mut self, node: LazyTypeOptional<'a>) {
self.visit_type_optional_default(node);
}
fn visit_type_optional_default(&mut self, node: LazyTypeOptional<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_variadic(&mut self, node: LazyTypeVariadic<'a>) {
self.visit_type_variadic_default(node);
}
fn visit_type_variadic_default(&mut self, node: LazyTypeVariadic<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_conditional(&mut self, node: LazyTypeConditional<'a>) {
self.visit_type_conditional_default(node);
}
fn visit_type_conditional_default(&mut self, node: LazyTypeConditional<'a>) {
if let Some(t) = node.check_type() {
self.visit_type_node(t);
}
if let Some(t) = node.extends_type() {
self.visit_type_node(t);
}
if let Some(t) = node.true_type() {
self.visit_type_node(t);
}
if let Some(t) = node.false_type() {
self.visit_type_node(t);
}
}
fn visit_type_infer(&mut self, node: LazyTypeInfer<'a>) {
self.visit_type_infer_default(node);
}
fn visit_type_infer_default(&mut self, node: LazyTypeInfer<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_key_of(&mut self, node: LazyTypeKeyOf<'a>) {
self.visit_type_key_of_default(node);
}
fn visit_type_key_of_default(&mut self, node: LazyTypeKeyOf<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_type_of(&mut self, node: LazyTypeTypeOf<'a>) {
self.visit_type_type_of_default(node);
}
fn visit_type_type_of_default(&mut self, node: LazyTypeTypeOf<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_import(&mut self, node: LazyTypeImport<'a>) {
self.visit_type_import_default(node);
}
fn visit_type_import_default(&mut self, node: LazyTypeImport<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_predicate(&mut self, node: LazyTypePredicate<'a>) {
self.visit_type_predicate_default(node);
}
fn visit_type_predicate_default(&mut self, node: LazyTypePredicate<'a>) {
if let Some(l) = node.left() {
self.visit_type_node(l);
}
if let Some(r) = node.right() {
self.visit_type_node(r);
}
}
fn visit_type_asserts(&mut self, node: LazyTypeAsserts<'a>) {
self.visit_type_asserts_default(node);
}
fn visit_type_asserts_default(&mut self, node: LazyTypeAsserts<'a>) {
if let Some(l) = node.left() {
self.visit_type_node(l);
}
if let Some(r) = node.right() {
self.visit_type_node(r);
}
}
fn visit_type_asserts_plain(&mut self, node: LazyTypeAssertsPlain<'a>) {
self.visit_type_asserts_plain_default(node);
}
fn visit_type_asserts_plain_default(&mut self, node: LazyTypeAssertsPlain<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_readonly_array(&mut self, node: LazyTypeReadonlyArray<'a>) {
self.visit_type_readonly_array_default(node);
}
fn visit_type_readonly_array_default(&mut self, node: LazyTypeReadonlyArray<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_object_field(&mut self, node: LazyTypeObjectField<'a>) {
self.visit_type_object_field_default(node);
}
fn visit_type_object_field_default(&mut self, node: LazyTypeObjectField<'a>) {
if let Some(k) = node.key() {
self.visit_type_node(k);
}
if let Some(r) = node.right() {
self.visit_type_node(r);
}
}
fn visit_type_jsdoc_object_field(&mut self, node: LazyTypeJsdocObjectField<'a>) {
self.visit_type_jsdoc_object_field_default(node);
}
fn visit_type_jsdoc_object_field_default(&mut self, node: LazyTypeJsdocObjectField<'a>) {
if let Some(k) = node.key() {
self.visit_type_node(k);
}
if let Some(r) = node.right() {
self.visit_type_node(r);
}
}
fn visit_type_indexed_access_index(&mut self, node: LazyTypeIndexedAccessIndex<'a>) {
self.visit_type_indexed_access_index_default(node);
}
fn visit_type_indexed_access_index_default(&mut self, node: LazyTypeIndexedAccessIndex<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_call_signature(&mut self, node: LazyTypeCallSignature<'a>) {
self.visit_type_call_signature_default(node);
}
fn visit_type_call_signature_default(&mut self, node: LazyTypeCallSignature<'a>) {
if let Some(params) = node.parameters() {
self.visit_type_parameter_list(params);
}
if let Some(ret) = node.return_type() {
self.visit_type_node(ret);
}
if let Some(tp) = node.type_parameters() {
self.visit_type_parameter_list(tp);
}
}
fn visit_type_constructor_signature(&mut self, node: LazyTypeConstructorSignature<'a>) {
self.visit_type_constructor_signature_default(node);
}
fn visit_type_constructor_signature_default(&mut self, node: LazyTypeConstructorSignature<'a>) {
if let Some(params) = node.parameters() {
self.visit_type_parameter_list(params);
}
if let Some(ret) = node.return_type() {
self.visit_type_node(ret);
}
if let Some(tp) = node.type_parameters() {
self.visit_type_parameter_list(tp);
}
}
fn visit_type_type_parameter(&mut self, node: LazyTypeTypeParameter<'a>) {
self.visit_type_type_parameter_default(node);
}
fn visit_type_type_parameter_default(&mut self, node: LazyTypeTypeParameter<'a>) {
for el in node.elements() {
self.visit_type_node(el);
}
}
fn visit_type_parameter_list(&mut self, node: LazyTypeParameterList<'a>) {
self.visit_type_parameter_list_default(node);
}
fn visit_type_parameter_list_default(&mut self, node: LazyTypeParameterList<'a>) {
for el in node.elements() {
self.visit_type_node(el);
}
}
fn visit_type_readonly_property(&mut self, node: LazyTypeReadonlyProperty<'a>) {
self.visit_type_readonly_property_default(node);
}
fn visit_type_readonly_property_default(&mut self, node: LazyTypeReadonlyProperty<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_key_value(&mut self, node: LazyTypeKeyValue<'a>) {
self.visit_type_key_value_default(node);
}
fn visit_type_key_value_default(&mut self, node: LazyTypeKeyValue<'a>) {
if let Some(r) = node.right() {
self.visit_type_node(r);
}
}
fn visit_type_index_signature(&mut self, node: LazyTypeIndexSignature<'a>) {
self.visit_type_index_signature_default(node);
}
fn visit_type_index_signature_default(&mut self, node: LazyTypeIndexSignature<'a>) {
if let Some(r) = node.right() {
self.visit_type_node(r);
}
}
fn visit_type_mapped_type(&mut self, node: LazyTypeMappedType<'a>) {
self.visit_type_mapped_type_default(node);
}
fn visit_type_mapped_type_default(&mut self, node: LazyTypeMappedType<'a>) {
if let Some(r) = node.right() {
self.visit_type_node(r);
}
}
fn visit_type_method_signature(&mut self, _node: LazyTypeMethodSignature<'a>) {}
fn visit_type_template_literal(&mut self, _node: LazyTypeTemplateLiteral<'a>) {}
fn visit_type_symbol(&mut self, node: LazyTypeSymbol<'a>) {
self.visit_type_symbol_default(node);
}
fn visit_type_symbol_default(&mut self, node: LazyTypeSymbol<'a>) {
if let Some(el) = node.element() {
self.visit_type_node(el);
}
}
fn visit_type_null(&mut self, _node: LazyTypeNull<'a>) {}
fn visit_type_undefined(&mut self, _node: LazyTypeUndefined<'a>) {}
fn visit_type_any(&mut self, _node: LazyTypeAny<'a>) {}
fn visit_type_unknown(&mut self, _node: LazyTypeUnknown<'a>) {}
fn visit_type_unique_symbol(&mut self, _node: LazyTypeUniqueSymbol<'a>) {}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::decoder::source_file::LazySourceFile;
use crate::format::kind::Kind;
use crate::writer::BinaryWriter;
use crate::writer::nodes::comment_ast::{
JSDOC_BLOCK_TAGS_SLOT, write_jsdoc_block, write_jsdoc_tag, write_jsdoc_tag_name,
write_jsdoc_tag_name_value,
};
use crate::writer::nodes::type_node::TYPE_LIST_PARENT_SLOT;
use crate::writer::nodes::type_node::write_type_name;
use oxc_allocator::Allocator;
use oxc_span::Span;
use std::collections::HashMap;
struct CountVisitor {
counts: HashMap<Kind, usize>,
}
impl CountVisitor {
fn bump(&mut self, kind: Kind) {
*self.counts.entry(kind).or_insert(0) += 1;
}
}
impl<'a> LazyJsdocVisitor<'a> for CountVisitor {
fn visit_block(&mut self, b: LazyJsdocBlock<'a>) {
self.bump(Kind::JsdocBlock);
self.visit_block_default(b);
}
fn visit_tag(&mut self, t: LazyJsdocTag<'a>) {
self.bump(Kind::JsdocTag);
self.visit_tag_default(t);
}
fn visit_tag_name(&mut self, _n: LazyJsdocTagName<'a>) {
self.bump(Kind::JsdocTagName);
}
fn visit_tag_name_value(&mut self, _n: LazyJsdocTagNameValue<'a>) {
self.bump(Kind::JsdocTagNameValue);
}
fn visit_type_name(&mut self, _n: LazyTypeName<'a>) {
self.bump(Kind::TypeName);
}
}
fn build_single_tag_buffer<'a>(arena: &'a Allocator) -> Vec<u8> {
let mut writer = BinaryWriter::new(arena);
let _ = writer.append_source_text("/** @param {string} id */");
let empty = writer.intern_string("");
let star = writer.intern_string("*");
let space = writer.intern_string(" ");
let close = writer.intern_string("*/");
let nl = writer.intern_string("\n");
let tag_name_str = writer.intern_string_payload("param");
let type_name_str = writer.intern_string_payload("string");
let param_name_str = writer.intern_string_payload("id");
let (block, block_ext) = write_jsdoc_block(
&mut writer,
Span::new(0, 25),
0,
None,
star,
space,
close,
nl,
empty,
nl,
empty,
0b010, None, );
let mut tags_list = writer.begin_node_list_at(block_ext, JSDOC_BLOCK_TAGS_SLOT);
let (tag, _tag_ext) = write_jsdoc_tag(
&mut writer,
Span::new(4, 23),
block.as_u32(),
false,
None,
None,
None,
0b0000_1101,
None, );
writer.record_list_child(&mut tags_list, tag.as_u32());
writer.finalize_node_list(tags_list);
let _ = write_jsdoc_tag_name(&mut writer, Span::new(4, 9), tag.as_u32(), tag_name_str);
let _ = write_jsdoc_tag_name_value(
&mut writer,
Span::new(20, 22),
tag.as_u32(),
param_name_str,
);
let _ = write_type_name(&mut writer, Span::new(11, 17), tag.as_u32(), type_name_str);
writer.push_root(block.as_u32(), 0, 0);
writer.finish()
}
#[test]
fn visitor_walks_block_and_children() {
let arena = Allocator::default();
let bytes = build_single_tag_buffer(&arena);
let sf = LazySourceFile::new(&bytes).unwrap();
let mut v = CountVisitor {
counts: HashMap::new(),
};
for opt in sf.asts() {
if let Some(block) = opt {
v.visit_block(block);
}
}
assert_eq!(v.counts.get(&Kind::JsdocBlock).copied(), Some(1));
assert_eq!(v.counts.get(&Kind::JsdocTag).copied(), Some(1));
assert_eq!(v.counts.get(&Kind::JsdocTagName).copied(), Some(1));
assert_eq!(v.counts.get(&Kind::JsdocTagNameValue).copied(), Some(1));
assert_eq!(v.counts.get(&Kind::TypeName).copied(), Some(1));
}
struct NoopVisitor;
impl<'a> LazyJsdocVisitor<'a> for NoopVisitor {}
#[test]
fn empty_visitor_traverses_without_panic() {
let arena = Allocator::default();
let bytes = build_single_tag_buffer(&arena);
let sf = LazySourceFile::new(&bytes).unwrap();
let mut v = NoopVisitor;
for opt in sf.asts() {
if let Some(block) = opt {
v.visit_block(block);
}
}
}
#[test]
fn visit_type_node_dispatches_each_variant() {
let arena = Allocator::default();
let mut writer = BinaryWriter::new(&arena);
let s = writer.intern_string_payload("Foo");
use crate::writer::nodes::type_node::{write_type_name, write_type_union};
let (union_idx, union_ext) = write_type_union(&mut writer, Span::new(0, 10), 0);
let union = union_idx.as_u32();
let mut list = writer.begin_node_list_at(union_ext, TYPE_LIST_PARENT_SLOT);
let n1 = write_type_name(&mut writer, Span::new(0, 3), union, s);
writer.record_list_child(&mut list, n1.as_u32());
let n2 = write_type_name(&mut writer, Span::new(4, 7), union, s);
writer.record_list_child(&mut list, n2.as_u32());
writer.finalize_node_list(list);
writer.push_root(union, 0, 0);
let bytes = writer.finish();
let sf = LazySourceFile::new(&bytes).unwrap();
use crate::decoder::nodes::type_node::LazyTypeNode;
struct TypeVisitor {
saw_union: bool,
type_name_count: usize,
}
impl<'a> LazyJsdocVisitor<'a> for TypeVisitor {
fn visit_type_union(&mut self, n: LazyTypeUnion<'a>) {
self.saw_union = true;
self.visit_type_union_default(n);
}
fn visit_type_name(&mut self, _n: LazyTypeName<'a>) {
self.type_name_count += 1;
}
}
let mut v = TypeVisitor {
saw_union: false,
type_name_count: 0,
};
let root = LazyTypeNode::from_index(&sf, union, 0).expect("union root");
v.visit_type_node(root);
assert!(v.saw_union);
assert_eq!(v.type_name_count, 2);
}
}