turbovault_tools/
export_tools.rs1use std::sync::Arc;
4use turbovault_core::prelude::*;
5use turbovault_export::{
6 AnalysisReportExporter, BrokenLinkRecord, BrokenLinksExporter, HealthReportExporter,
7 VaultStatsExporter, VaultStatsRecord, create_health_report,
8};
9use turbovault_parser::to_plain_text;
10use turbovault_vault::VaultManager;
11
12pub struct ExportTools {
14 pub manager: Arc<VaultManager>,
15}
16
17impl ExportTools {
18 pub fn new(manager: Arc<VaultManager>) -> Self {
20 Self { manager }
21 }
22
23 pub async fn export_health_report(&self, format: &str) -> Result<String> {
25 let graph = self.manager.link_graph();
26 let graph_read = graph.read().await;
27
28 let stats = graph_read.stats();
29
30 let total_notes = stats.total_files;
32 let total_links = stats.total_links;
33 let broken_links = 0; let orphaned_notes = stats.orphaned_files;
35
36 let health_score = if broken_links == 0 && orphaned_notes == 0 {
38 100
39 } else if broken_links == 0 {
40 80
41 } else {
42 70
43 };
44
45 let report = create_health_report(
46 "default",
47 health_score,
48 total_notes,
49 total_links,
50 broken_links,
51 orphaned_notes,
52 );
53
54 match format {
55 "json" => HealthReportExporter::to_json(&report),
56 "csv" => HealthReportExporter::to_csv(&report),
57 _ => Err(Error::config_error(
58 "Invalid export format. Use 'json' or 'csv'".to_string(),
59 )),
60 }
61 }
62
63 pub async fn export_broken_links(&self, format: &str) -> Result<String> {
65 let links: Vec<BrokenLinkRecord> = vec![];
67
68 match format {
69 "json" => BrokenLinksExporter::to_json(&links),
70 "csv" => BrokenLinksExporter::to_csv(&links),
71 _ => Err(Error::config_error(
72 "Invalid export format. Use 'json' or 'csv'".to_string(),
73 )),
74 }
75 }
76
77 pub async fn export_vault_stats(&self, format: &str) -> Result<String> {
79 let graph = self.manager.link_graph();
80 let graph_read = graph.read().await;
81 let stats = graph_read.stats();
82
83 let files = self.manager.scan_vault().await?;
85 let mut total_words = 0usize;
86 let mut total_readable_chars = 0usize;
87 let mut note_count = 0usize;
88
89 for file_path in &files {
90 if !file_path.to_string_lossy().to_lowercase().ends_with(".md") {
91 continue;
92 }
93 if let Ok(vault_file) = self.manager.parse_file(file_path).await {
94 let plain_text = to_plain_text(&vault_file.content);
95 total_words += plain_text.split_whitespace().count();
96 total_readable_chars += plain_text.chars().count();
97 note_count += 1;
98 }
99 }
100
101 let avg_words_per_note = if note_count > 0 {
102 total_words as f64 / note_count as f64
103 } else {
104 0.0
105 };
106
107 let stats_record = VaultStatsRecord {
108 timestamp: chrono::Utc::now().to_rfc3339(),
109 vault_name: "default".to_string(),
110 total_files: stats.total_files,
111 total_links: stats.total_links,
112 orphaned_files: stats.orphaned_files,
113 average_links_per_file: stats.average_links_per_file,
114 total_words,
115 total_readable_chars,
116 avg_words_per_note,
117 };
118
119 match format {
120 "json" => VaultStatsExporter::to_json(&stats_record),
121 "csv" => VaultStatsExporter::to_csv(&stats_record),
122 _ => Err(Error::config_error(
123 "Invalid export format. Use 'json' or 'csv'".to_string(),
124 )),
125 }
126 }
127
128 pub async fn export_analysis_report(&self, format: &str) -> Result<String> {
130 let graph = self.manager.link_graph();
131 let graph_read = graph.read().await;
132 let stats = graph_read.stats();
133
134 let total_notes = stats.total_files;
135 let total_links = stats.total_links;
136 let broken_links = 0;
137 let orphaned_notes = stats.orphaned_files;
138
139 let health_score = if broken_links == 0 && orphaned_notes == 0 {
140 100
141 } else if broken_links == 0 {
142 80
143 } else {
144 70
145 };
146
147 let health = create_health_report(
148 "default",
149 health_score,
150 total_notes,
151 total_links,
152 broken_links,
153 orphaned_notes,
154 );
155
156 let analysis_report = turbovault_export::AnalysisReport {
157 timestamp: chrono::Utc::now().to_rfc3339(),
158 vault_name: "default".to_string(),
159 health,
160 broken_links_count: broken_links,
161 orphaned_notes_count: orphaned_notes,
162 recommendations: vec![
163 "Ensure all notes are linked for better connectivity".to_string(),
164 "Review and fix broken links regularly".to_string(),
165 ],
166 };
167
168 match format {
169 "json" => AnalysisReportExporter::to_json(&analysis_report),
170 "csv" => AnalysisReportExporter::to_csv(&analysis_report),
171 _ => Err(Error::config_error(
172 "Invalid export format. Use 'json' or 'csv'".to_string(),
173 )),
174 }
175 }
176}