1use crate::{
2 block::{parse_statements_and_declarations, statements_and_declarations_to_string},
3 derive_ASTNode, BlockLike, BlockLikeMut, LocalToStringInformation, ParseOptions, ParseResult,
4 StatementOrDeclaration, VisitOptions,
5};
6
7use super::{ASTNode, Span, TSXToken, TokenReader};
8
9#[derive(Debug, Clone)]
10#[apply(derive_ASTNode)]
11pub struct Module {
12 pub hashbang_comment: Option<String>,
13 pub items: Vec<StatementOrDeclaration>,
14 pub span: Span,
15}
16
17impl PartialEq for Module {
18 fn eq(&self, other: &Self) -> bool {
19 self.items == other.items
20 }
21}
22
23impl ASTNode for Module {
24 fn to_string_from_buffer<T: source_map::ToString>(
25 &self,
26 buf: &mut T,
27 options: &crate::ToStringOptions,
28 local: crate::LocalToStringInformation,
29 ) {
30 if let Some(ref hashbang_comment) = self.hashbang_comment {
31 buf.push_str("#!");
32 buf.push_str(hashbang_comment);
33 buf.push_new_line();
34 }
35 statements_and_declarations_to_string(&self.items, buf, options, local);
36 }
37
38 fn get_position(&self) -> Span {
39 self.span
40 }
41
42 fn from_reader(
43 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
44 state: &mut crate::ParsingState,
45 options: &ParseOptions,
46 ) -> ParseResult<Self> {
47 let start = reader.peek().map(|t| t.1 .0).unwrap_or_default();
48 let span = Span { start, source: (), end: start + state.length_of_source };
49 let hashbang_comment = if let Some(crate::Token(TSXToken::HashBangComment(_), _)) =
50 reader.peek()
51 {
52 let Some(crate::Token(TSXToken::HashBangComment(hashbang_comment), _)) = reader.next()
53 else {
54 unreachable!()
55 };
56 Some(hashbang_comment)
57 } else {
58 None
59 };
60 parse_statements_and_declarations(reader, state, options).map(|items| Module {
61 hashbang_comment,
62 items,
63 span,
64 })
65 }
66}
67
68impl Module {
69 pub fn to_string_with_source_map(
70 &self,
71 options: &crate::ToStringOptions,
72 this: source_map::SourceId,
73 fs: &impl source_map::FileSystem,
74 ) -> (String, Option<source_map::SourceMap>) {
75 let mut buf = source_map::StringWithOptionalSourceMap::new(true);
76 self.to_string_from_buffer(
77 &mut buf,
78 options,
79 LocalToStringInformation { depth: 0, under: this, should_try_pretty_print: true },
80 );
81 buf.build(fs)
82 }
83
84 }
95
96impl Module {
97 pub fn visit<TData>(
98 &self,
99 visitors: &mut (impl crate::VisitorReceiver<TData> + ?Sized),
100 data: &mut TData,
101 options: &VisitOptions,
102 source: source_map::SourceId,
103 ) {
104 use crate::visiting::Visitable;
105 let mut chain = crate::Chain::new_with_initial(crate::ChainVariable::Module(source));
106 let mut chain = temporary_annex::Annex::new(&mut chain);
107
108 {
109 visitors.visit_block(&crate::block::BlockLike { items: &self.items }, data, &chain);
110 }
111
112 let iter = self.items.iter();
113 if options.reverse_statements {
114 iter.for_each(|item| item.visit(visitors, data, options, &mut chain));
115 } else {
116 iter.rev().for_each(|item| item.visit(visitors, data, options, &mut chain));
117 }
118 }
119
120 pub fn visit_mut<TData>(
121 &mut self,
122 visitors: &mut (impl crate::VisitorMutReceiver<TData> + ?Sized),
123 data: &mut TData,
124 options: &VisitOptions,
125 source: source_map::SourceId,
126 ) {
127 use crate::visiting::Visitable;
128 let mut chain = crate::Chain::new_with_initial(crate::ChainVariable::Module(source));
129 let mut chain = temporary_annex::Annex::new(&mut chain);
130
131 {
132 visitors.visit_block_mut(
133 &mut crate::block::BlockLikeMut { items: &mut self.items },
134 data,
135 &chain,
136 );
137 }
138
139 let iter_mut = self.items.iter_mut();
140 if options.reverse_statements {
141 iter_mut.for_each(|item| item.visit_mut(visitors, data, options, &mut chain));
142 } else {
143 iter_mut.rev().for_each(|item| item.visit_mut(visitors, data, options, &mut chain));
144 }
145 }
146}
147
148impl<'a> From<&'a Module> for BlockLike<'a> {
149 fn from(module: &'a Module) -> Self {
150 BlockLike { items: &module.items }
151 }
152}
153
154impl<'a> From<&'a mut Module> for BlockLikeMut<'a> {
155 fn from(module: &'a mut Module) -> Self {
156 BlockLikeMut { items: &mut module.items }
157 }
158}