tauri_typegen/analysis/
ast_cache.rs1use std::collections::HashMap;
2use std::path::PathBuf;
3use syn::File as SynFile;
4use walkdir::WalkDir;
5
6#[derive(Debug, Clone)]
8pub struct ParsedFile {
9 pub ast: SynFile,
11 pub path: PathBuf,
13 }
16
17impl ParsedFile {
18 pub fn new(ast: SynFile, path: PathBuf) -> Self {
19 Self { ast, path }
20 }
21}
22
23#[derive(Debug, Default)]
25pub struct AstCache {
26 cache: HashMap<PathBuf, ParsedFile>,
27}
28
29impl AstCache {
30 pub fn new() -> Self {
31 Self {
32 cache: HashMap::new(),
33 }
34 }
35
36 pub fn parse_and_cache_all_files(
38 &mut self,
39 project_path: &str,
40 verbose: bool,
41 ) -> Result<(), Box<dyn std::error::Error>> {
42 if verbose {
43 println!("🔄 Parsing and caching all Rust files in: {}", project_path);
44 }
45
46 for entry in WalkDir::new(project_path) {
47 let entry = entry?;
48 let path = entry.path();
49
50 if path.is_file() && path.extension().is_some_and(|ext| ext == "rs") {
51 if path.to_string_lossy().contains("/target/")
53 || path.to_string_lossy().contains("/.git/")
54 {
55 continue;
56 }
57
58 if verbose {
59 println!("📄 Parsing file: {}", path.display());
60 }
61
62 let content = std::fs::read_to_string(path)?;
63 match syn::parse_file(&content) {
64 Ok(ast) => {
65 let parsed_file = ParsedFile::new(ast, path.to_path_buf());
66 self.cache.insert(path.to_path_buf(), parsed_file);
67 if verbose {
68 println!("✅ Successfully parsed: {}", path.display());
69 }
70 }
71 Err(e) => {
72 eprintln!("❌ Failed to parse {}: {}", path.display(), e);
73 }
75 }
76 }
77 }
78
79 if verbose {
80 println!("📊 Cached {} Rust files", self.cache.len());
81 }
82 Ok(())
83 }
84
85 pub fn get(&self, path: &PathBuf) -> Option<&ParsedFile> {
87 self.cache.get(path)
88 }
89
90 pub fn get_cloned(&self, path: &PathBuf) -> Option<ParsedFile> {
92 self.cache.get(path).cloned()
93 }
94
95 pub fn keys(&self) -> std::collections::hash_map::Keys<'_, PathBuf, ParsedFile> {
97 self.cache.keys()
98 }
99
100 pub fn iter(&self) -> std::collections::hash_map::Iter<'_, PathBuf, ParsedFile> {
102 self.cache.iter()
103 }
104
105 pub fn contains(&self, path: &PathBuf) -> bool {
107 self.cache.contains_key(path)
108 }
109
110 pub fn len(&self) -> usize {
112 self.cache.len()
113 }
114
115 pub fn is_empty(&self) -> bool {
117 self.cache.is_empty()
118 }
119
120 pub fn clear(&mut self) {
122 self.cache.clear();
123 }
124
125 pub fn insert(&mut self, path: PathBuf, parsed_file: ParsedFile) -> Option<ParsedFile> {
127 self.cache.insert(path, parsed_file)
128 }
129
130 pub fn parse_and_cache_file(
132 &mut self,
133 file_path: &std::path::Path,
134 ) -> Result<(), Box<dyn std::error::Error>> {
135 let content = std::fs::read_to_string(file_path)?;
136 let ast = syn::parse_file(&content)?;
137 let parsed_file = ParsedFile::new(ast, file_path.to_path_buf());
138 self.cache.insert(file_path.to_path_buf(), parsed_file);
139 Ok(())
140 }
141}