refactor: migration Clean Architecture — module commands avec render et watch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
use crate::infrastructure::file_repository;
|
use crate::infrastructure::file_repository;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn list_markdown_files(dir: &str) -> Result<Vec<String>, String> {
|
pub fn list_markdown_files(dir: &str) -> Result<Vec<String>, String> {
|
||||||
let path = Path::new(dir);
|
let path = Path::new(dir);
|
||||||
if !path.is_dir() {
|
if !path.is_dir() {
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
use crate::domain::MarkdownRenderer;
|
use crate::domain::MarkdownRenderer;
|
||||||
use crate::infrastructure::file_repository;
|
use crate::infrastructure::file_repository;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn render_string(renderer: &dyn MarkdownRenderer, content: &str) -> String {
|
pub fn render_string(renderer: &dyn MarkdownRenderer, content: &str) -> String {
|
||||||
renderer.render(content)
|
renderer.render(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn render_file(renderer: &dyn MarkdownRenderer, path: &str) -> Result<String, String> {
|
pub fn render_file(renderer: &dyn MarkdownRenderer, path: &str) -> Result<String, String> {
|
||||||
let content = file_repository::read_file(path)?;
|
let content = file_repository::read_file(path)?;
|
||||||
Ok(renderer.render(&content))
|
Ok(renderer.render(&content))
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod render;
|
||||||
|
pub mod watch;
|
||||||
@@ -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<String, String> {
|
||||||
|
let renderer = ComrakRenderer {
|
||||||
|
theme: "InspiredGitHub".to_string(),
|
||||||
|
};
|
||||||
|
render_service::render_file(&renderer, &path)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn list_md_files(dir: String) -> Result<Vec<String>, 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("<h1>"));
|
||||||
|
assert!(html.contains("Hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_markdown_code_block() {
|
||||||
|
let html = render_markdown("```rust\nfn main() {}\n```\n".to_string());
|
||||||
|
assert!(html.contains("<code") || html.contains("<pre>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_markdown_empty() {
|
||||||
|
let html = render_markdown(String::new());
|
||||||
|
assert!(!html.contains("<h1>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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("<h1>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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("<table>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<String, String> {
|
|
||||||
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<String>) -> std::io::Result<()> {
|
|
||||||
file_repository::collect_md_files(dir, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_md_files(dir: String) -> Result<Vec<String>, 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("<h1>"));
|
|
||||||
assert!(html.contains("Hello"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn render_markdown_code_block() {
|
|
||||||
let html = render_markdown("```rust\nfn main() {}\n```\n".to_string());
|
|
||||||
assert!(html.contains("<code") || html.contains("<pre>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn render_markdown_empty() {
|
|
||||||
let html = render_markdown(String::new());
|
|
||||||
assert!(!html.contains("<h1>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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("<h1>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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("<table>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,3 +23,76 @@ pub fn collect_md_files(dir: &Path, result: &mut Vec<String>) -> std::io::Result
|
|||||||
pub fn read_file(path: &str) -> Result<String, String> {
|
pub fn read_file(path: &str) -> Result<String, String> {
|
||||||
fs::read_to_string(path).map_err(|e| e.to_string())
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+7
-23
@@ -1,38 +1,22 @@
|
|||||||
mod application;
|
mod application;
|
||||||
mod core;
|
mod commands;
|
||||||
mod domain;
|
mod domain;
|
||||||
mod infrastructure;
|
mod infrastructure;
|
||||||
mod watcher;
|
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
fn render_markdown(content: String) -> String {
|
|
||||||
core::render_markdown(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
fn convert_file(path: String) -> Result<String, String> {
|
|
||||||
core::convert_file(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
fn list_md_files(dir: String) -> Result<Vec<String>, String> {
|
|
||||||
core::list_md_files(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_fs::init())
|
.plugin(tauri_plugin_fs::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
.manage(watcher::WatcherState(Mutex::new(None)))
|
.manage(commands::watch::WatcherState(Mutex::new(None)))
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
render_markdown,
|
commands::render::render_markdown,
|
||||||
convert_file,
|
commands::render::convert_file,
|
||||||
list_md_files,
|
commands::render::list_md_files,
|
||||||
watcher::start_watch,
|
commands::watch::start_watch,
|
||||||
watcher::stop_watch,
|
commands::watch::stop_watch,
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("Erreur lors du démarrage de l'application Tauri");
|
.expect("Erreur lors du démarrage de l'application Tauri");
|
||||||
|
|||||||
Reference in New Issue
Block a user