reinhardt_admin_cli/migrate_v2/rules/
watch_unwrap.rs1use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
9use syn::visit_mut::{self, VisitMut};
10
11use crate::migrate_v2::rewriter::FileRewriter;
12
13pub struct Rule;
15
16impl FileRewriter for Rule {
17 fn name(&self) -> &'static str {
18 "watch_unwrap"
19 }
20
21 fn rewrite(&self, mut file: syn::File) -> syn::File {
22 PageMacroBodyVisitor.visit_file_mut(&mut file);
23 file
24 }
25}
26
27struct PageMacroBodyVisitor;
28
29impl VisitMut for PageMacroBodyVisitor {
30 fn visit_macro_mut(&mut self, m: &mut syn::Macro) {
31 if m.path
32 .segments
33 .last()
34 .map(|s| s.ident == "page")
35 .unwrap_or(false)
36 {
37 m.tokens = unwrap_watch(m.tokens.clone());
38 }
39 visit_mut::visit_macro_mut(self, m);
40 }
41}
42
43fn unwrap_watch(input: TokenStream) -> TokenStream {
44 let mut out: Vec<TokenTree> = Vec::new();
45 let mut iter = input.into_iter().peekable();
46
47 while let Some(tt) = iter.next() {
48 match &tt {
49 TokenTree::Ident(id) if id == "watch" => {
51 if let Some(TokenTree::Group(g)) = iter.peek()
52 && g.delimiter() == Delimiter::Brace
53 {
54 let body = match iter.next() {
55 Some(TokenTree::Group(g)) => g.stream(),
56 _ => unreachable!("peek matched but next did not"),
57 };
58 out.extend(unwrap_watch(body));
59 continue;
60 }
61 out.push(tt);
62 }
63 TokenTree::Punct(p) if p.as_char() == '#' => {
67 let mut lookahead = iter.clone();
68 let reactive_with_brace = matches!(
69 (lookahead.next(), lookahead.next()),
70 (Some(TokenTree::Ident(id2)), Some(TokenTree::Group(g)))
71 if id2 == "reactive" && g.delimiter() == Delimiter::Brace
72 );
73 if reactive_with_brace {
74 let _ = iter.next(); let body = match iter.next() {
76 Some(TokenTree::Group(g)) => g.stream(),
77 _ => unreachable!("lookahead matched but next did not"),
78 };
79 out.extend(unwrap_watch(body));
80 continue;
81 }
82 out.push(tt);
83 }
84 TokenTree::Group(g) if g.delimiter() == Delimiter::Brace => {
86 let inner = unwrap_watch(g.stream());
87 out.push(TokenTree::Group(Group::new(Delimiter::Brace, inner)));
88 }
89 _ => out.push(tt),
90 }
91 }
92
93 out.into_iter().collect()
94}