1use super::generated::*;
2use crate::common::*;
3use crate::swc::ast as swc_ast;
4use crate::swc::common::comments::SingleThreadedCommentsMapInner;
5use crate::swc::parser::token::TokenAndSpan;
6
7pub enum NodeOrToken<'a> {
8 Node(Node<'a>),
9 Token(&'a TokenAndSpan),
10}
11
12impl<'a> NodeOrToken<'a> {
13 pub fn unwrap_token(&self) -> &'a TokenAndSpan {
14 match self {
15 NodeOrToken::Token(token) => token,
16 NodeOrToken::Node(node) => panic!("Expected to unwrap a token, but it was a node of kind {}.", node.kind()),
17 }
18 }
19
20 pub fn unwrap_node(&self) -> &Node<'a> {
21 match self {
22 NodeOrToken::Node(node) => node,
23 NodeOrToken::Token(token) => panic!("Expected to unwrap a node, but it was a token with text '{:?}'.", token.token),
24 }
25 }
26}
27
28impl<'a> SourceRanged for NodeOrToken<'a> {
29 fn start(&self) -> SourcePos {
30 match self {
31 NodeOrToken::Node(node) => node.start(),
32 NodeOrToken::Token(token) => token.start(),
33 }
34 }
35
36 fn end(&self) -> SourcePos {
37 match self {
38 NodeOrToken::Node(node) => node.end(),
39 NodeOrToken::Token(token) => token.end(),
40 }
41 }
42}
43
44macro_rules! implement_root_node {
45 ($name:ty) => {
46 impl<'a> RootNode<'a> for $name {
47 fn maybe_text_info(&self) -> Option<&'a SourceTextInfo> {
48 self.text_info
49 }
50
51 fn maybe_token_container(&self) -> Option<&'a TokenContainer<'a>> {
52 self.tokens
53 }
54
55 fn maybe_comment_container(&self) -> Option<&'a CommentContainer<'a>> {
56 self.comments
57 }
58 }
59 };
60}
61
62implement_root_node!(Module<'a>);
63implement_root_node!(&Module<'a>);
64implement_root_node!(Script<'a>);
65implement_root_node!(&Script<'a>);
66
67#[derive(Clone, Copy)]
69pub enum Program<'a> {
70 Module(&'a Module<'a>),
71 Script(&'a Script<'a>),
72}
73
74impl<'a> SourceRanged for Program<'a> {
75 fn start(&self) -> SourcePos {
76 match self {
77 Program::Module(node) => node.start(),
78 Program::Script(node) => node.start(),
79 }
80 }
81
82 fn end(&self) -> SourcePos {
83 match self {
84 Program::Module(node) => node.end(),
85 Program::Script(node) => node.end(),
86 }
87 }
88}
89
90impl<'a> NodeTrait<'a> for Program<'a> {
91 fn parent(&self) -> Option<Node<'a>> {
92 None
93 }
94
95 fn children(&self) -> Vec<Node<'a>> {
96 match self {
97 Program::Module(node) => node.children(),
98 Program::Script(node) => node.children(),
99 }
100 }
101
102 fn as_node(&self) -> Node<'a> {
103 match self {
104 Program::Module(node) => node.as_node(),
105 Program::Script(node) => node.as_node(),
106 }
107 }
108
109 fn kind(&self) -> NodeKind {
110 match self {
111 Program::Module(node) => node.kind(),
112 Program::Script(node) => node.kind(),
113 }
114 }
115}
116
117impl<'a> From<&Program<'a>> for Node<'a> {
118 fn from(node: &Program<'a>) -> Node<'a> {
119 match node {
120 Program::Module(node) => (*node).into(),
121 Program::Script(node) => (*node).into(),
122 }
123 }
124}
125
126impl<'a> From<Program<'a>> for Node<'a> {
127 fn from(node: Program<'a>) -> Node<'a> {
128 match node {
129 Program::Module(node) => node.into(),
130 Program::Script(node) => node.into(),
131 }
132 }
133}
134
135impl<'a> RootNode<'a> for Program<'a> {
136 fn maybe_text_info(&self) -> Option<&'a SourceTextInfo> {
137 match self {
138 Program::Module(module) => module.text_info,
139 Program::Script(script) => script.text_info,
140 }
141 }
142
143 fn maybe_token_container(&self) -> Option<&'a TokenContainer<'a>> {
144 match self {
145 Program::Module(module) => module.tokens,
146 Program::Script(script) => script.tokens,
147 }
148 }
149
150 fn maybe_comment_container(&self) -> Option<&'a CommentContainer<'a>> {
151 match self {
152 Program::Module(module) => module.comments,
153 Program::Script(script) => script.comments,
154 }
155 }
156}
157
158pub trait NodeTrait<'a>: SourceRanged + Sized {
159 fn parent(&self) -> Option<Node<'a>>;
160 fn children(&self) -> Vec<Node<'a>>;
161 fn as_node(&self) -> Node<'a>;
162 fn kind(&self) -> NodeKind;
163
164 fn ancestors(&self) -> AncestorIterator<'a> {
165 AncestorIterator::new(self.as_node())
166 }
167
168 fn start_line(&self) -> usize {
169 self.start_line_fast(self.program())
170 }
171
172 fn end_line(&self) -> usize {
173 self.end_line_fast(self.program())
174 }
175
176 fn start_column(&self) -> usize {
177 self.start_column_fast(self.program())
178 }
179
180 fn end_column(&self) -> usize {
181 self.end_column_fast(self.program())
182 }
183
184 fn char_width(&self) -> usize {
185 self.char_width_fast(self.program())
186 }
187
188 fn child_index(&self) -> usize {
189 if let Some(parent) = self.parent() {
190 let start_pos = self.start();
191 for (i, child) in parent.children().iter().enumerate() {
192 if child.start() == start_pos {
193 return i;
194 }
195 }
196 panic!("Could not find the child index for some reason.");
197 } else {
198 0
199 }
200 }
201
202 fn previous_sibling(&self) -> Option<Node<'a>> {
203 if let Some(parent) = self.parent() {
204 let child_index = self.child_index();
205 if child_index > 0 {
206 Some(parent.children().remove(child_index - 1))
207 } else {
208 None
209 }
210 } else {
211 None
212 }
213 }
214
215 fn previous_siblings(&self) -> Vec<Node<'a>> {
217 if let Some(parent) = self.parent() {
218 let child_index = self.child_index();
219 if child_index > 0 {
220 let mut parent_children = parent.children();
221 parent_children.drain(child_index..);
222 parent_children
223 } else {
224 Vec::new()
225 }
226 } else {
227 Vec::new()
228 }
229 }
230
231 fn next_sibling(&self) -> Option<Node<'a>> {
233 if let Some(parent) = self.parent() {
234 let next_index = self.child_index() + 1;
235 let mut parent_children = parent.children();
236 if next_index < parent_children.len() {
237 Some(parent_children.remove(next_index))
238 } else {
239 None
240 }
241 } else {
242 None
243 }
244 }
245
246 fn next_siblings(&self) -> Vec<Node<'a>> {
247 if let Some(parent) = self.parent() {
248 let next_index = self.child_index() + 1;
249 let mut parent_children = parent.children();
250 if next_index < parent_children.len() {
251 parent_children.drain(0..next_index);
252 parent_children
253 } else {
254 Vec::new()
255 }
256 } else {
257 Vec::new()
258 }
259 }
260
261 fn tokens(&self) -> &'a [TokenAndSpan] {
262 self.tokens_fast(self.program())
263 }
264
265 fn children_with_tokens(&self) -> Vec<NodeOrToken<'a>> {
266 self.children_with_tokens_fast(self.program())
267 }
268
269 fn children_with_tokens_fast(&self, program: impl RootNode<'a>) -> Vec<NodeOrToken<'a>> {
270 let children = self.children();
271 let tokens = self.tokens_fast(program);
272 let mut result = Vec::new();
273 let mut tokens_index = 0;
274
275 for child in children {
276 let child_range = child.range();
277
278 for token in &tokens[tokens_index..] {
280 if token.start() < child_range.start {
281 result.push(NodeOrToken::Token(token));
282 tokens_index += 1;
283 } else {
284 break;
285 }
286 }
287
288 result.push(NodeOrToken::Node(child));
290
291 for token in &tokens[tokens_index..] {
293 if token.end() <= child_range.end {
294 tokens_index += 1;
295 } else {
296 break;
297 }
298 }
299 }
300
301 for token in &tokens[tokens_index..] {
303 result.push(NodeOrToken::Token(token));
304 }
305
306 result
307 }
308
309 fn leading_comments(&self) -> CommentsIterator<'a> {
310 self.leading_comments_fast(self.program())
311 }
312
313 fn trailing_comments(&self) -> CommentsIterator<'a> {
314 self.trailing_comments_fast(self.program())
315 }
316
317 fn program(&self) -> Program<'a> {
319 let mut current: Node<'a> = self.as_node();
320 while let Some(parent) = current.parent() {
321 current = parent;
322 }
323
324 match current {
326 Node::Module(module) => Program::Module(module),
327 Node::Script(script) => Program::Script(script),
328 _ => panic!("Expected the root node to be a Module or Script, but it was a {}.", current.kind()),
329 }
330 }
331
332 fn module(&self) -> &Module<'a> {
334 match self.program() {
335 Program::Module(module) => module,
336 Program::Script(_) => {
337 panic!("The root node was a Script and not a Module. Use .script() or .program() instead.")
338 }
339 }
340 }
341
342 fn script(&self) -> &Script<'a> {
344 match self.program() {
345 Program::Script(script) => script,
346 Program::Module(_) => {
347 panic!("The root node was a Module and not a Script. Use .module() or .program() instead.")
348 }
349 }
350 }
351
352 fn text(&self) -> &'a str {
353 self.text_fast(self.program())
354 }
355
356 fn previous_token(&self) -> Option<&'a TokenAndSpan> {
357 self.previous_token_fast(self.program())
358 }
359
360 fn next_token(&self) -> Option<&'a TokenAndSpan> {
361 self.next_token_fast(self.program())
362 }
363
364 fn previous_tokens(&self) -> &'a [TokenAndSpan] {
366 self.previous_tokens_fast(self.program())
367 }
368
369 fn next_tokens(&self) -> &'a [TokenAndSpan] {
371 self.next_tokens_fast(self.program())
372 }
373}
374
375pub trait CastableNode<'a> {
376 fn to(node: &Node<'a>) -> Option<&'a Self>;
377 fn kind() -> NodeKind;
378}
379
380#[derive(Clone, Copy)]
381pub struct Comments<'a> {
382 pub leading: &'a SingleThreadedCommentsMapInner,
383 pub trailing: &'a SingleThreadedCommentsMapInner,
384}
385
386#[derive(Clone, Copy)]
387pub enum ProgramRef<'a> {
388 Module(&'a swc_ast::Module),
389 Script(&'a swc_ast::Script),
390}
391
392impl<'a> From<&'a swc_ast::Program> for ProgramRef<'a> {
393 fn from(program: &'a swc_ast::Program) -> Self {
394 use swc_ast::Program;
395
396 match program {
397 Program::Module(module) => ProgramRef::Module(module),
398 Program::Script(script) => ProgramRef::Script(script),
399 }
400 }
401}
402
403impl<'a> From<&'a swc_ast::Module> for ProgramRef<'a> {
404 fn from(module: &'a swc_ast::Module) -> Self {
405 ProgramRef::Module(module)
406 }
407}
408
409impl<'a> From<&'a swc_ast::Script> for ProgramRef<'a> {
410 fn from(script: &'a swc_ast::Script) -> Self {
411 ProgramRef::Script(script)
412 }
413}
414
415impl<'a> SourceRanged for ProgramRef<'a> {
416 fn start(&self) -> SourcePos {
417 match self {
418 ProgramRef::Module(node) => node.range().start,
419 ProgramRef::Script(node) => node.range().start,
420 }
421 }
422
423 fn end(&self) -> SourcePos {
424 match self {
425 ProgramRef::Module(node) => node.range().end,
426 ProgramRef::Script(node) => node.range().end,
427 }
428 }
429}
430
431#[derive(Clone, Copy)]
432pub struct ProgramInfo<'a> {
433 pub program: ProgramRef<'a>,
434 pub text_info: Option<&'a SourceTextInfo>,
435 pub tokens: Option<&'a [TokenAndSpan]>,
436 pub comments: Option<Comments<'a>>,
437}
438
439#[derive(Clone, Copy)]
440pub struct ModuleInfo<'a> {
441 pub module: &'a swc_ast::Module,
442 pub text_info: Option<&'a SourceTextInfo>,
443 pub tokens: Option<&'a [TokenAndSpan]>,
444 pub comments: Option<Comments<'a>>,
445}
446
447#[derive(Clone, Copy)]
448pub struct ScriptInfo<'a> {
449 pub script: &'a swc_ast::Script,
450 pub text_info: Option<&'a SourceTextInfo>,
451 pub tokens: Option<&'a [TokenAndSpan]>,
452 pub comments: Option<Comments<'a>>,
453}
454
455#[derive(Clone)]
456pub struct AncestorIterator<'a> {
457 current: Node<'a>,
458}
459
460impl<'a> AncestorIterator<'a> {
461 pub fn new(node: Node<'a>) -> AncestorIterator<'a> {
462 AncestorIterator { current: node }
463 }
464}
465
466impl<'a> Iterator for AncestorIterator<'a> {
467 type Item = Node<'a>;
468
469 fn next(&mut self) -> Option<Node<'a>> {
470 let parent = self.current.parent();
471 if let Some(parent) = parent {
472 self.current = parent;
473 }
474 parent
475 }
476}
477
478pub trait TokenExt {
479 fn token_index<'a, N: RootNode<'a>>(&self, root_node: N) -> usize;
480}
481
482impl TokenExt for TokenAndSpan {
483 fn token_index<'a, N: RootNode<'a>>(&self, root_node: N) -> usize {
484 root_node.token_container().get_token_index_at_start(self.start()).unwrap()
485 }
486}
487
488#[cfg(test)]
489mod test {
490 use super::super::test_helpers::run_test;
491 use crate::common::*;
492 use crate::view::*;
493
494 #[test]
495 fn it_should_get_children() {
496 run_test("class Test { a: string; b: number; }", |program| {
497 let class_decl = program.children()[0].expect::<ClassDecl>();
498 let children = class_decl.class.children();
499 assert_eq!(children.len(), 2);
500 assert_eq!(children[0].text(), "a: string;");
501 assert_eq!(children[1].text(), "b: number;");
502 });
503 }
504
505 #[test]
506 fn it_should_get_all_comments() {
507 run_test(
508 r#"
509/// <reference path="foo" />
510const a = 42;
511
512/*
513 * block comment
514 */
515let b = true;
516
517// line comment
518let c = "";
519
520function foo(name: /* inline comment */ string) {
521 console.log(`hello, ${name}`); // greeting!
522}
523
524// trailing comment
525"#,
526 |program| {
527 assert_eq!(program.maybe_comment_container().unwrap().all_comments().count(), 6);
528 },
529 );
530 }
531}