From 6ae7a434c49008dbe725a8cba4ae09a81757424e Mon Sep 17 00:00:00 2001 From: Gato Date: Fri, 19 Jun 2026 14:13:30 +0200 Subject: [PATCH] =?UTF-8?q?refactor:=20migration=20Clean=20Architecture=20?= =?UTF-8?q?=E2=80=94=20module=20commands=20avec=20render=20et=20watch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- src-tauri/src/application/file_service.rs | 1 - src-tauri/src/application/render_service.rs | 2 - src-tauri/src/commands/mod.rs | 2 + src-tauri/src/commands/render.rs | 101 ++++++++++ .../src/{watcher.rs => commands/watch.rs} | 0 src-tauri/src/core.rs | 176 ------------------ .../src/infrastructure/file_repository.rs | 73 ++++++++ src-tauri/src/lib.rs | 30 +-- 8 files changed, 183 insertions(+), 202 deletions(-) create mode 100644 src-tauri/src/commands/mod.rs create mode 100644 src-tauri/src/commands/render.rs rename src-tauri/src/{watcher.rs => commands/watch.rs} (100%) delete mode 100644 src-tauri/src/core.rs diff --git a/src-tauri/src/application/file_service.rs b/src-tauri/src/application/file_service.rs index e4382d2..4016771 100644 --- a/src-tauri/src/application/file_service.rs +++ b/src-tauri/src/application/file_service.rs @@ -1,7 +1,6 @@ use crate::infrastructure::file_repository; use std::path::Path; -#[allow(dead_code)] pub fn list_markdown_files(dir: &str) -> Result, String> { let path = Path::new(dir); if !path.is_dir() { diff --git a/src-tauri/src/application/render_service.rs b/src-tauri/src/application/render_service.rs index 820accb..aba0613 100644 --- a/src-tauri/src/application/render_service.rs +++ b/src-tauri/src/application/render_service.rs @@ -1,12 +1,10 @@ use crate::domain::MarkdownRenderer; use crate::infrastructure::file_repository; -#[allow(dead_code)] pub fn render_string(renderer: &dyn MarkdownRenderer, content: &str) -> String { renderer.render(content) } -#[allow(dead_code)] pub fn render_file(renderer: &dyn MarkdownRenderer, path: &str) -> Result { let content = file_repository::read_file(path)?; Ok(renderer.render(&content)) diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs new file mode 100644 index 0000000..bf80f3e --- /dev/null +++ b/src-tauri/src/commands/mod.rs @@ -0,0 +1,2 @@ +pub mod render; +pub mod watch; diff --git a/src-tauri/src/commands/render.rs b/src-tauri/src/commands/render.rs new file mode 100644 index 0000000..5cbee7e --- /dev/null +++ b/src-tauri/src/commands/render.rs @@ -0,0 +1,101 @@ +use crate::application::{file_service, render_service}; +use crate::infrastructure::comrak_renderer::{ComrakPreviewRenderer, ComrakRenderer}; + +#[tauri::command] +pub fn render_markdown(content: String) -> String { + let renderer = ComrakPreviewRenderer { + theme: "base16-ocean.dark".to_string(), + }; + render_service::render_string(&renderer, &content) +} + +#[tauri::command] +pub fn convert_file(path: String) -> Result { + let renderer = ComrakRenderer { + theme: "InspiredGitHub".to_string(), + }; + render_service::render_file(&renderer, &path) +} + +#[tauri::command] +pub fn list_md_files(dir: String) -> Result, String> { + file_service::list_markdown_files(&dir) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + + fn tmpdir(name: &str) -> std::path::PathBuf { + std::env::temp_dir().join(name) + } + + #[test] + fn render_markdown_heading() { + let html = render_markdown("# Hello\n".to_string()); + assert!(html.contains("

")); + assert!(html.contains("Hello")); + } + + #[test] + fn render_markdown_code_block() { + let html = render_markdown("```rust\nfn main() {}\n```\n".to_string()); + assert!(html.contains("")); + } + + #[test] + fn render_markdown_empty() { + let html = render_markdown(String::new()); + assert!(!html.contains("

")); + } + + #[test] + fn convert_file_success() { + let dir = tmpdir("pena_convert_success"); + fs::create_dir_all(&dir).unwrap(); + let file = dir.join("test.md"); + fs::write(&file, "# Title\n\nParagraph.").unwrap(); + let result = convert_file(file.to_string_lossy().to_string()); + fs::remove_dir_all(&dir).unwrap(); + assert!(result.is_ok()); + assert!(result.unwrap().contains("

")); + } + + #[test] + fn convert_file_with_table() { + let dir = tmpdir("pena_convert_table"); + fs::create_dir_all(&dir).unwrap(); + let file = dir.join("table.md"); + fs::write(&file, "| A | B |\n|---|---|\n| 1 | 2 |").unwrap(); + let result = convert_file(file.to_string_lossy().to_string()); + fs::remove_dir_all(&dir).unwrap(); + assert!(result.is_ok()); + assert!(result.unwrap().contains("")); + } + + #[test] + fn convert_file_not_found() { + let result = convert_file("/nonexistent/path/does/not/exist.md".to_string()); + assert!(result.is_err()); + } + + #[test] + fn list_md_files_sorted() { + let dir = tmpdir("pena_list_sorted"); + fs::create_dir_all(&dir).unwrap(); + fs::write(dir.join("z.md"), "").unwrap(); + fs::write(dir.join("a.md"), "").unwrap(); + fs::write(dir.join("m.md"), "").unwrap(); + let result = list_md_files(dir.to_string_lossy().to_string()).unwrap(); + fs::remove_dir_all(&dir).unwrap(); + assert_eq!(result.len(), 3); + assert!(result[0] < result[1] && result[1] < result[2]); + } + + #[test] + fn list_md_files_not_a_dir() { + let result = list_md_files("/nonexistent/does/not/exist".to_string()); + assert!(result.is_err()); + } +} diff --git a/src-tauri/src/watcher.rs b/src-tauri/src/commands/watch.rs similarity index 100% rename from src-tauri/src/watcher.rs rename to src-tauri/src/commands/watch.rs diff --git a/src-tauri/src/core.rs b/src-tauri/src/core.rs deleted file mode 100644 index 9c450fc..0000000 --- a/src-tauri/src/core.rs +++ /dev/null @@ -1,176 +0,0 @@ -use crate::domain::MarkdownRenderer; -use crate::infrastructure::comrak_renderer::{ComrakPreviewRenderer, ComrakRenderer}; -use crate::infrastructure::file_repository; -use std::path::Path; - -pub fn render_markdown(content: String) -> String { - ComrakPreviewRenderer { - theme: "base16-ocean.dark".to_string(), - } - .render(&content) -} - -pub fn convert_file(path: String) -> Result { - let content = file_repository::read_file(&path)?; - Ok(ComrakRenderer { - theme: "InspiredGitHub".to_string(), - } - .render(&content)) -} - -pub(crate) fn collect_md_files(dir: &Path, result: &mut Vec) -> std::io::Result<()> { - file_repository::collect_md_files(dir, result) -} - -pub fn list_md_files(dir: String) -> Result, String> { - let path = Path::new(&dir); - if !path.is_dir() { - return Err(format!("{dir} n'est pas un dossier")); - } - let mut files = Vec::new(); - collect_md_files(path, &mut files).map_err(|e| e.to_string())?; - files.sort(); - Ok(files) -} - -#[cfg(test)] -mod tests { - use super::*; - use std::fs; - use std::path::PathBuf; - - fn tmpdir(name: &str) -> PathBuf { - std::env::temp_dir().join(name) - } - - #[test] - fn render_markdown_heading() { - let html = render_markdown("# Hello\n".to_string()); - assert!(html.contains("

")); - assert!(html.contains("Hello")); - } - - #[test] - fn render_markdown_code_block() { - let html = render_markdown("```rust\nfn main() {}\n```\n".to_string()); - assert!(html.contains("")); - } - - #[test] - fn render_markdown_empty() { - let html = render_markdown(String::new()); - assert!(!html.contains("

")); - } - - #[test] - fn convert_file_success() { - let dir = tmpdir("pena_convert_success"); - fs::create_dir_all(&dir).unwrap(); - let file = dir.join("test.md"); - fs::write(&file, "# Title\n\nParagraph.").unwrap(); - let result = convert_file(file.to_string_lossy().to_string()); - fs::remove_dir_all(&dir).unwrap(); - assert!(result.is_ok()); - assert!(result.unwrap().contains("

")); - } - - #[test] - fn convert_file_with_table() { - let dir = tmpdir("pena_convert_table"); - fs::create_dir_all(&dir).unwrap(); - let file = dir.join("table.md"); - fs::write(&file, "| A | B |\n|---|---|\n| 1 | 2 |").unwrap(); - let result = convert_file(file.to_string_lossy().to_string()); - fs::remove_dir_all(&dir).unwrap(); - assert!(result.is_ok()); - assert!(result.unwrap().contains("

")); - } - - #[test] - fn convert_file_not_found() { - let result = convert_file("/nonexistent/path/does/not/exist.md".to_string()); - assert!(result.is_err()); - } - - #[test] - fn collect_md_flat() { - let dir = tmpdir("pena_collect_flat"); - fs::create_dir_all(&dir).unwrap(); - fs::write(dir.join("a.md"), "").unwrap(); - fs::write(dir.join("b.md"), "").unwrap(); - fs::write(dir.join("c.txt"), "").unwrap(); - let mut result = Vec::new(); - collect_md_files(&dir, &mut result).unwrap(); - result.sort(); - fs::remove_dir_all(&dir).unwrap(); - assert_eq!(result.len(), 2); - assert!(result[0].ends_with("a.md")); - assert!(result[1].ends_with("b.md")); - } - - #[test] - fn collect_md_recursive() { - let dir = tmpdir("pena_collect_recursive"); - let sub = dir.join("docs"); - fs::create_dir_all(&sub).unwrap(); - fs::write(dir.join("Home.md"), "").unwrap(); - fs::write(sub.join("Page.md"), "").unwrap(); - let mut result = Vec::new(); - collect_md_files(&dir, &mut result).unwrap(); - fs::remove_dir_all(&dir).unwrap(); - assert_eq!(result.len(), 2); - } - - #[test] - fn collect_md_ignores_hidden_dir() { - let dir = tmpdir("pena_collect_hidden_dir"); - let hidden = dir.join(".hidden"); - fs::create_dir_all(&hidden).unwrap(); - fs::write(dir.join("visible.md"), "").unwrap(); - fs::write(hidden.join("secret.md"), "").unwrap(); - let mut result = Vec::new(); - collect_md_files(&dir, &mut result).unwrap(); - fs::remove_dir_all(&dir).unwrap(); - assert_eq!(result.len(), 1); - assert!(result[0].ends_with("visible.md")); - } - - #[test] - fn collect_md_ignores_hidden_file() { - let dir = tmpdir("pena_collect_hidden_file"); - fs::create_dir_all(&dir).unwrap(); - fs::write(dir.join("visible.md"), "").unwrap(); - fs::write(dir.join(".hidden.md"), "").unwrap(); - let mut result = Vec::new(); - collect_md_files(&dir, &mut result).unwrap(); - fs::remove_dir_all(&dir).unwrap(); - assert_eq!(result.len(), 1); - assert!(result[0].ends_with("visible.md")); - } - - #[test] - fn collect_md_nonexistent_dir() { - let mut result = Vec::new(); - let err = collect_md_files(Path::new("/nonexistent/path/for/pena"), &mut result); - assert!(err.is_err()); - } - - #[test] - fn list_md_files_sorted() { - let dir = tmpdir("pena_list_sorted"); - fs::create_dir_all(&dir).unwrap(); - fs::write(dir.join("z.md"), "").unwrap(); - fs::write(dir.join("a.md"), "").unwrap(); - fs::write(dir.join("m.md"), "").unwrap(); - let result = list_md_files(dir.to_string_lossy().to_string()).unwrap(); - fs::remove_dir_all(&dir).unwrap(); - assert_eq!(result.len(), 3); - assert!(result[0] < result[1] && result[1] < result[2]); - } - - #[test] - fn list_md_files_not_a_dir() { - let result = list_md_files("/nonexistent/does/not/exist".to_string()); - assert!(result.is_err()); - } -} diff --git a/src-tauri/src/infrastructure/file_repository.rs b/src-tauri/src/infrastructure/file_repository.rs index 2008cdb..b5384c1 100644 --- a/src-tauri/src/infrastructure/file_repository.rs +++ b/src-tauri/src/infrastructure/file_repository.rs @@ -23,3 +23,76 @@ pub fn collect_md_files(dir: &Path, result: &mut Vec) -> std::io::Result pub fn read_file(path: &str) -> Result { fs::read_to_string(path).map_err(|e| e.to_string()) } + +#[cfg(test)] +mod tests { + use super::*; + use std::path::PathBuf; + + fn tmpdir(name: &str) -> PathBuf { + std::env::temp_dir().join(name) + } + + #[test] + fn collect_md_flat() { + let dir = tmpdir("pena_collect_flat"); + fs::create_dir_all(&dir).unwrap(); + fs::write(dir.join("a.md"), "").unwrap(); + fs::write(dir.join("b.md"), "").unwrap(); + fs::write(dir.join("c.txt"), "").unwrap(); + let mut result = Vec::new(); + collect_md_files(&dir, &mut result).unwrap(); + result.sort(); + fs::remove_dir_all(&dir).unwrap(); + assert_eq!(result.len(), 2); + assert!(result[0].ends_with("a.md")); + assert!(result[1].ends_with("b.md")); + } + + #[test] + fn collect_md_recursive() { + let dir = tmpdir("pena_collect_recursive"); + let sub = dir.join("docs"); + fs::create_dir_all(&sub).unwrap(); + fs::write(dir.join("Home.md"), "").unwrap(); + fs::write(sub.join("Page.md"), "").unwrap(); + let mut result = Vec::new(); + collect_md_files(&dir, &mut result).unwrap(); + fs::remove_dir_all(&dir).unwrap(); + assert_eq!(result.len(), 2); + } + + #[test] + fn collect_md_ignores_hidden_dir() { + let dir = tmpdir("pena_collect_hidden_dir"); + let hidden = dir.join(".hidden"); + fs::create_dir_all(&hidden).unwrap(); + fs::write(dir.join("visible.md"), "").unwrap(); + fs::write(hidden.join("secret.md"), "").unwrap(); + let mut result = Vec::new(); + collect_md_files(&dir, &mut result).unwrap(); + fs::remove_dir_all(&dir).unwrap(); + assert_eq!(result.len(), 1); + assert!(result[0].ends_with("visible.md")); + } + + #[test] + fn collect_md_ignores_hidden_file() { + let dir = tmpdir("pena_collect_hidden_file"); + fs::create_dir_all(&dir).unwrap(); + fs::write(dir.join("visible.md"), "").unwrap(); + fs::write(dir.join(".hidden.md"), "").unwrap(); + let mut result = Vec::new(); + collect_md_files(&dir, &mut result).unwrap(); + fs::remove_dir_all(&dir).unwrap(); + assert_eq!(result.len(), 1); + assert!(result[0].ends_with("visible.md")); + } + + #[test] + fn collect_md_nonexistent_dir() { + let mut result = Vec::new(); + let err = collect_md_files(Path::new("/nonexistent/path/for/pena"), &mut result); + assert!(err.is_err()); + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 2970b74..6a0118e 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,38 +1,22 @@ mod application; -mod core; +mod commands; mod domain; mod infrastructure; -mod watcher; use std::sync::Mutex; -#[tauri::command] -fn render_markdown(content: String) -> String { - core::render_markdown(content) -} - -#[tauri::command] -fn convert_file(path: String) -> Result { - core::convert_file(path) -} - -#[tauri::command] -fn list_md_files(dir: String) -> Result, String> { - core::list_md_files(dir) -} - #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_dialog::init()) - .manage(watcher::WatcherState(Mutex::new(None))) + .manage(commands::watch::WatcherState(Mutex::new(None))) .invoke_handler(tauri::generate_handler![ - render_markdown, - convert_file, - list_md_files, - watcher::start_watch, - watcher::stop_watch, + commands::render::render_markdown, + commands::render::convert_file, + commands::render::list_md_files, + commands::watch::start_watch, + commands::watch::stop_watch, ]) .run(tauri::generate_context!()) .expect("Erreur lors du démarrage de l'application Tauri");