From 54ccf6306e643a651c25f5ba162c00e34e14cbd7 Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 19 Sep 2024 00:10:35 +0300 Subject: [PATCH 01/10] refactor(utils): improve docs of `CheckerState` and add some test cases --- crates/metassr-bundler/src/lib.rs | 4 +- crates/metassr-utils/src/checker.rs | 142 +++++++++++++++++++++++++--- 2 files changed, 132 insertions(+), 14 deletions(-) diff --git a/crates/metassr-bundler/src/lib.rs b/crates/metassr-bundler/src/lib.rs index c4b6051..5406c49 100644 --- a/crates/metassr-bundler/src/lib.rs +++ b/crates/metassr-bundler/src/lib.rs @@ -13,7 +13,7 @@ use tracing::error; lazy_static! { /// A detector for if the bundling script `./bundle.js` is loaded or not. It is used to solve multiple loading script error in metacall. - static ref IS_BUNDLING_SCRIPT_LOADED: Mutex = Mutex::new(CheckerState::new()); + static ref IS_BUNDLING_SCRIPT_LOADED: Mutex = Mutex::new(CheckerState::default()); /// A simple checker to check if the bundling function is done or not. It is used to block the program until bundling done. static ref IS_COMPLIATION_WAIT: Arc = Arc::new(CompilationWait::default()); @@ -30,7 +30,7 @@ struct CompilationWait { impl Default for CompilationWait { fn default() -> Self { Self { - checker: Mutex::new(CheckerState::with(false)), + checker: Mutex::new(CheckerState::default()), cond: Condvar::new(), } } diff --git a/crates/metassr-utils/src/checker.rs b/crates/metassr-utils/src/checker.rs index fc4561c..b45cf66 100644 --- a/crates/metassr-utils/src/checker.rs +++ b/crates/metassr-utils/src/checker.rs @@ -1,30 +1,148 @@ -/// A simple checker state +/// `CheckerState` is a simple structure that represents a boolean state. +/// It allows for easy manipulation of the state with utility methods to set it to `true` or `false`. +/// +/// This can be useful in situations where you need a simple flag to represent a state in an application. +/// +/// # Example +/// +/// ```rust +/// use metassr_utils::checker::CheckerState; +/// +/// let mut state = CheckerState::default(); +/// assert!(!state.is_true()); // Initially false by default +/// +/// state.make_true(); +/// assert!(state.is_true()); // Now true +/// +/// state.make_false(); +/// assert!(!state.is_true()); // Back to false +/// ``` #[derive(Debug)] -pub struct CheckerState(bool); -impl CheckerState { - pub fn new() -> Self { - Self(false) - } +pub struct CheckerState(bool); // A tuple struct that holds a boolean value - pub fn with(state: bool) -> Self { - Self(state) +impl CheckerState { + /// Creates a new `CheckerState` with the specified boolean value. + /// + /// # Example + /// + /// ```rust + /// use metassr_utils::checker::CheckerState; + /// + /// let state = CheckerState::new(true); + /// assert_eq!(state.is_true(), true); + /// ``` + pub fn new(state: bool) -> Self { + Self(state) // Allows for custom initialization with `true` or `false` } + /// Sets the internal state to `true`. + /// + /// # Example + /// + /// ```rust + /// use metassr_utils::checker::CheckerState; + /// + /// let mut state = CheckerState::default(); + /// state.make_true(); + /// assert_eq!(state.is_true(), true); + /// ``` pub fn make_true(&mut self) { - self.0 = true + self.0 = true; // Mutate the internal state to true } + /// Sets the internal state to `false`. + /// + /// # Example + /// + /// ```rust + /// use metassr_utils::checker::CheckerState; + /// + /// let mut state = CheckerState::new(true); + /// state.make_false(); + /// assert_eq!(state.is_true(), false); + /// ``` pub fn make_false(&mut self) { - self.0 = false + self.0 = false; // Mutate the internal state to false } + /// Returns `true` if the internal state is true, otherwise returns `false`. + /// + /// # Example + /// + /// ```rust + /// use metassr_utils::checker::CheckerState; + /// + /// let state = CheckerState::new(true); + /// assert_eq!(state.is_true(), true); + /// ``` pub fn is_true(&self) -> bool { - self.0 + self.0 // Return the current state } } impl Default for CheckerState { + /// The default implementation for `CheckerState`, which initializes the state to `false`. + /// + /// # Example + /// + /// ```rust + /// use metassr_utils::checker::CheckerState; + /// + /// let state = CheckerState::default(); + /// assert_eq!(state.is_true(), false); + /// ``` fn default() -> Self { - Self::new() + Self::new(false) // By default, new CheckerState is false + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Test case for creating a new `CheckerState` using `new()` + #[test] + fn test_new_checker_state() { + let state = CheckerState::default(); + assert!(!state.is_true(), "Expected state to be false"); + } + + /// Test case for creating a `CheckerState` with a specific boolean value + #[test] + fn test_with_checker_state() { + let state_true = CheckerState::new(true); + let state_false = CheckerState::new(false); + + assert!(state_true.is_true(), "Expected state to be true"); + assert!(!state_false.is_true(), "Expected state to be false"); + } + + /// Test case for the `make_true()` method + #[test] + fn test_make_true() { + let mut state = CheckerState::new(false); + state.make_true(); + assert!( + state.is_true(), + "Expected state to be true after calling make_true()" + ); + } + + /// Test case for the `make_false()` method + #[test] + fn test_make_false() { + let mut state = CheckerState::new(true); + state.make_false(); + assert!( + !state.is_true(), + "Expected state to be false after calling make_false()" + ); + } + + /// Test case for the default implementation + #[test] + fn test_default_checker_state() { + let state: CheckerState = Default::default(); + assert!(!state.is_true(), "Expected default state to be false"); } } From f19343ab0f317e4a9bcf295d782c855707b822c7 Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 19 Sep 2024 00:37:46 +0300 Subject: [PATCH 02/10] refactor(utils): improve `rand::Rand` improve its documentation and test cases --- crates/metassr-utils/src/rand.rs | 83 +++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/crates/metassr-utils/src/rand.rs b/crates/metassr-utils/src/rand.rs index 8659ad4..1030827 100644 --- a/crates/metassr-utils/src/rand.rs +++ b/crates/metassr-utils/src/rand.rs @@ -3,34 +3,93 @@ use std::{ hash::{BuildHasher, Hasher}, }; -/// A very simple random implementation for specific purposes (Just get a random value). - +/// `Rand` is a simple structure that generates a random 64-bit integer value. +/// It uses the `RandomState` from the standard library's hash map as a source of randomness. +/// +/// This is useful for situations where you need a random integer in your application. +/// The random value is generated when the `Rand` object is instantiated. +/// +/// # Example +/// +/// ```rust +/// use metassr_utils::rand::Rand; +/// let rand = Rand::new(); +/// println!("Generated random value: {}", rand.val()); +/// ``` pub struct Rand(i64); impl Rand { + /// Creates a new `Rand` instance, generating a random i64 value using `RandomState`. + /// + /// The generated value is always non-negative. + /// + /// # Example + /// + /// ```rust + /// use metassr_utils::rand::Rand; + /// + /// let random = Rand::new(); + /// assert!(random.val() >= 0, "Random value should be non-negative"); + /// ``` pub fn new() -> Self { - let val = RandomState::new().build_hasher().finish() as i64; - Self(val.abs()) + let val = RandomState::new().build_hasher().finish() as i64; // Generate a random value + Self(val.abs()) // Ensure the value is non-negative } + + /// Returns the generated random value. + /// + /// # Example + /// + /// ```rust + /// use metassr_utils::rand::Rand; + /// + /// let random = Rand::new(); + /// println!("Generated value: {}", random.val()); + /// ``` pub fn val(&self) -> i64 { - self.0 + self.0 // Return the stored random value } } #[cfg(test)] mod tests { - use crate::rand::Rand; + use super::*; + + /// Test case to verify that `Rand::new()` generates a non-negative value. + #[test] + fn test_random_value_is_non_negative() { + let random = Rand::new(); + assert!(random.val() >= 0, "Expected non-negative random value, got {}", random.val()); + } + + /// Test case to ensure random values are distinct in multiple instantiations. + #[test] + fn test_random_values_are_distinct() { + let mut values: Vec = vec![]; + + // Generate 10 random values and check for uniqueness + for _ in 0..10 { + let val = Rand::new().val(); + assert!(!values.contains(&val), "Random value repeated: {}", val); + values.push(val); + } + + println!("Generated random values: {:?}", values); + } + /// Test case to verify multiple random values over several iterations #[test] - fn random_value() { + fn test_random_value_repetition_over_iterations() { + let iterations = 100; let mut values: Vec = vec![]; - for _ in 1..10 { + + // Generate a large number of random values to verify low repetition rate + for _ in 0..iterations { let val = Rand::new().val(); - if values.contains(&val) { - panic!("a random value repeated"); - } + assert!(!values.contains(&val), "Repeated random value: {}", val); values.push(val); } - println!("{values:?}") + + println!("Generated {} random values: {:?}", iterations, values); } } From c701d046fa1b06f00e33917d116e8a8b92ffb642 Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 19 Sep 2024 00:38:28 +0300 Subject: [PATCH 03/10] refactor(utils): improve cache directory improve its documentation and test cases --- crates/metassr-utils/src/cache_dir.rs | 197 +++++++++++++++++++++++--- 1 file changed, 179 insertions(+), 18 deletions(-) diff --git a/crates/metassr-utils/src/cache_dir.rs b/crates/metassr-utils/src/cache_dir.rs index 51b956c..4252375 100644 --- a/crates/metassr-utils/src/cache_dir.rs +++ b/crates/metassr-utils/src/cache_dir.rs @@ -8,7 +8,23 @@ use std::{ }; use walkdir::WalkDir; -/// A simple cache directory. +/// `CacheDir` represents a simple directory-based cache system. +/// It stores file entries in a specified directory and tracks files +/// that are currently in the cache's scope. +/// +/// This is useful for caching purposes where files are written and +/// retrieved based on a pathname, making it easier to manage multiple +/// cached files in a structured directory. +/// +/// # Example +/// +/// ```no_run +/// use metassr_utils::cache_dir::CacheDir; +/// +/// let mut cache = CacheDir::new(".cache").unwrap(); +/// cache.insert("example.txt", "Cache data".as_bytes()).unwrap(); +/// println!("{:?}", cache.entries_in_scope()); +/// ``` #[derive(Debug, Clone)] pub struct CacheDir { @@ -17,6 +33,25 @@ pub struct CacheDir { } impl CacheDir { + /// Creates a new `CacheDir` at the specified path. + /// + /// If the directory does not exist, it will be created. + /// + /// # Arguments + /// + /// * `path` - A reference to the directory where the cache will be stored. + /// + /// # Errors + /// + /// Returns an error if the directory cannot be created or accessed. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::cache_dir::CacheDir; + /// + /// let cache = CacheDir::new(".cache").unwrap(); + /// ``` pub fn new + ?Sized>(path: &S) -> Result { let dir_path = PathBuf::from(path); @@ -30,12 +65,33 @@ impl CacheDir { }) } + /// Inserts a file into the cache. + /// + /// This method writes a file to the cache directory if it doesn't already exist. + /// If the file exists and the content differs, it will be replaced with the new content. + /// + /// # Arguments + /// + /// * `pathname` - The relative path where the file should be stored. + /// * `buf` - The content to be written to the file. + /// + /// # Returns + /// + /// The `PathBuf` of the written file. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::cache_dir::CacheDir; + /// + /// let mut cache = CacheDir::new(".cache").unwrap(); + /// cache.insert("data.txt", "Some data".as_bytes()).unwrap(); + /// ``` pub fn insert(&mut self, pathname: &str, buf: &[u8]) -> Result { - let id = pathname; let pathname = format!("{}/{}", self.dir_path.to_str().unwrap(), pathname); let path = Path::new(&pathname); - // Create fille path if it isn't exist + // Create file path if it doesn't exist if !path.exists() { let parent = path.parent().unwrap(); fs::create_dir_all(parent)?; @@ -46,6 +102,7 @@ impl CacheDir { let mut file = File::options().read(true).write(true).open(path)?; let mut current_buf = Vec::new(); + // Check if the file buffer is changed or not to rewrite it file.read_to_end(&mut current_buf)?; if current_buf != buf { let mut file = File::create(path)?; @@ -53,26 +110,55 @@ impl CacheDir { } } - // Replace the file if its content was changed - - // Adding the new filepath + // Add the new file path to the cache entries self.entries_in_scope - .insert(id.to_string(), path.canonicalize()?.as_path().into()); + .insert(pathname.clone(), path.canonicalize()?); Ok(path.to_path_buf()) } + /// Returns the path to the cache directory. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::cache_dir::CacheDir; + /// + /// let cache = CacheDir::new(".cache").unwrap(); + /// println!("Cache directory: {:?}", cache.dir_path()); + /// ``` pub fn dir_path(&self) -> PathBuf { self.dir_path.clone() } + /// Returns the current entries in scope. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::cache_dir::CacheDir; + /// + /// let cache = CacheDir::new(".cache").unwrap(); + /// println!("Entries in scope: {:?}", cache.entries_in_scope()); + /// ``` pub fn entries_in_scope(&self) -> HashMap { self.entries_in_scope.clone() } + + /// Returns all file entries in the cache directory. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::cache_dir::CacheDir; + /// + /// let cache = CacheDir::new(".cache").unwrap(); + /// println!("All entries: {:?}", cache.all_entries()); + /// ``` pub fn all_entries(&self) -> Vec { WalkDir::new(&self.dir_path) .into_iter() .filter_map(|e| { - // Check if the entry is a js/ts file. + // Check if the entry is a file e.ok().and_then(|e| match e.path().is_file() { true => Some(e.into_path()), false => None, @@ -84,19 +170,94 @@ impl CacheDir { #[cfg(test)] mod tests { - use super::CacheDir; + use super::*; + use crate::rand::Rand; + use std::fs; + use std::path::PathBuf; + + /// Helper function to create a `CacheDir` with a random name + fn create_temp_cache_dir() -> Result { + let dir_path = PathBuf::from(format!(".cache-{}", Rand::new().val())); + CacheDir::new(&dir_path) + } + /// Test case to verify that a new cache directory can be created and deleted. #[test] - fn create_new_tmpfile() { - let mut cache = CacheDir::new(".cache-metassr").unwrap(); - cache - .insert("pages/home.jsx", "hello world".as_bytes()) - .map_err(|e| println!("{e}")) - .unwrap(); + fn test_create_and_delete_temp_cache_dir() { + let mut cache = create_temp_cache_dir().unwrap(); + let test_file_path = cache.insert("test_file.txt", b"Hello, world!").unwrap(); + + assert!(test_file_path.exists(), "Inserted file should exist"); + + // Cleanup + fs::remove_file(test_file_path).unwrap(); + fs::remove_dir_all(cache.dir_path()).unwrap(); + } + + /// Test case to verify that a new file can be inserted into the cache. + #[test] + fn test_insert_new_file() { + let mut cache = create_temp_cache_dir().unwrap(); + let file_path = cache + .insert("test_file.txt", b"Hello, world!") + .expect("File should be inserted into the cache"); + assert!(file_path.exists(), "Inserted file should exist"); + + // Cleanup + // let file_path = result.unwrap(); + fs::remove_file(file_path).unwrap(); + fs::remove_dir_all(cache.dir_path()).unwrap(); + } + + /// Test case to check the scope of entries in the cache. + #[test] + fn test_entries_in_scope() { + let mut cache = create_temp_cache_dir().unwrap(); + cache.insert("test_file1.txt", b"Data 1").unwrap(); + cache.insert("test_file2.txt", b"Data 2").unwrap(); + let entries = cache.entries_in_scope(); + assert_eq!(entries.len(), 2, "There should be two entries in scope"); + + // Cleanup + for path in entries.values() { + fs::remove_file(path).unwrap(); + } + fs::remove_dir_all(cache.dir_path()).unwrap(); + } + + /// Test case to retrieve all entries in the cache. + #[test] + fn test_all_entries() { + let mut cache = create_temp_cache_dir().unwrap(); + cache.insert("test_file1.txt", b"Data 1").unwrap(); + cache.insert("test_file2.txt", b"Data 2").unwrap(); + let entries = cache.all_entries(); + assert_eq!(entries.len(), 2, "Cache should contain two entries"); + + // Cleanup + for path in entries { + fs::remove_file(path).unwrap(); + } + fs::remove_dir_all(cache.dir_path()).unwrap(); + } + + /// Test case to verify file replacement when content changes. + #[test] + fn test_insert_file_content_change() { + let mut cache = create_temp_cache_dir().unwrap(); cache - .insert("styles/index.jsx", "hello world".as_bytes()) - .map_err(|e| println!("{e}")) + .insert("replace_file.txt", b"Original content") .unwrap(); - println!("{:?}", cache.entries_in_scope()); + + let path = cache.insert("replace_file.txt", b"New content").unwrap(); + + let mut file = File::open(&path).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + assert_eq!(content, "New content", "File content should be updated"); + + // Cleanup + fs::remove_file(path).unwrap(); + fs::remove_dir_all(cache.dir_path()).unwrap(); } } From 827cafaebd548a68e64150e62e057491a32d8c6a Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 19 Sep 2024 00:42:06 +0300 Subject: [PATCH 04/10] refactor(utils): improve directories analyzer - move `src_analyzer.rs` and `dist_analyzer.rs` to `analyzer` module. - improve their documentation. - add more test-cases. --- crates/metassr-build/src/client/mod.rs | 6 +- crates/metassr-build/src/server/manifest.rs | 4 +- crates/metassr-build/src/server/mod.rs | 8 +- .../src/server/pages_generator.rs | 6 +- .../metassr-build/src/server/renderer/html.rs | 2 +- .../metassr-build/src/server/renderer/page.rs | 2 +- crates/metassr-build/src/server/targets.rs | 2 +- crates/metassr-server/src/handler.rs | 6 +- crates/metassr-utils/src/analyzer/dist_dir.rs | 421 ++++++++++++++++++ .../src/{traits.rs => analyzer/mod.rs} | 6 +- crates/metassr-utils/src/analyzer/src_dir.rs | 223 ++++++++++ crates/metassr-utils/src/dist_analyzer.rs | 122 ----- crates/metassr-utils/src/lib.rs | 4 +- crates/metassr-utils/src/src_analyzer.rs | 122 ----- 14 files changed, 672 insertions(+), 262 deletions(-) create mode 100644 crates/metassr-utils/src/analyzer/dist_dir.rs rename crates/metassr-utils/src/{traits.rs => analyzer/mod.rs} (56%) create mode 100644 crates/metassr-utils/src/analyzer/src_dir.rs delete mode 100644 crates/metassr-utils/src/dist_analyzer.rs delete mode 100644 crates/metassr-utils/src/src_analyzer.rs diff --git a/crates/metassr-build/src/client/mod.rs b/crates/metassr-build/src/client/mod.rs index 6fcfbcf..0e1f5bb 100644 --- a/crates/metassr-build/src/client/mod.rs +++ b/crates/metassr-build/src/client/mod.rs @@ -5,7 +5,11 @@ use hydrator::Hydrator; use metassr_bundler::WebBundler; use metassr_utils::{ - cache_dir::CacheDir, src_analyzer::special_entries, src_analyzer::SourceDir, traits::AnalyzeDir, + analyzer::{ + src_dir::{special_entries, SourceDir}, + DirectoryAnalyzer, + }, + cache_dir::CacheDir, }; use std::{ collections::HashMap, diff --git a/crates/metassr-build/src/server/manifest.rs b/crates/metassr-build/src/server/manifest.rs index e108c5a..53fcf38 100644 --- a/crates/metassr-build/src/server/manifest.rs +++ b/crates/metassr-build/src/server/manifest.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Result}; use metassr_utils::{ + analyzer::dist_dir::{DistDirContainer, PageEntry}, cache_dir::CacheDir, - dist_analyzer::{DistDirContainer, PageEntry}, }; use serde::{Deserialize, Serialize}; use serde_json::to_string_pretty; @@ -121,7 +121,7 @@ impl ManifestGenerator { pub fn generate + ?Sized>(&self, head: &H) -> Result { let global = GlobalEntry::new(head, &self.cache.dir_path())?; let mut manifest = Manifest::new(global); - + for (path, &id) in self.targets.iter() { let route = match path .strip_prefix(self.cache.dir_path().join("pages"))? diff --git a/crates/metassr-build/src/server/mod.rs b/crates/metassr-build/src/server/mod.rs index 06f9fa0..45d7a65 100644 --- a/crates/metassr-build/src/server/mod.rs +++ b/crates/metassr-build/src/server/mod.rs @@ -11,10 +11,12 @@ use manifest::ManifestGenerator; use metassr_bundler::WebBundler; use metassr_utils::{ + analyzer::{ + dist_dir::DistDir, + src_dir::{special_entries, SourceDir}, + DirectoryAnalyzer, + }, cache_dir::CacheDir, - dist_analyzer::DistDir, - src_analyzer::{special_entries, SourceDir}, - traits::AnalyzeDir, }; use pages_generator::PagesGenerator; use renderer::head::HeadRenderer; diff --git a/crates/metassr-build/src/server/pages_generator.rs b/crates/metassr-build/src/server/pages_generator.rs index b8fe4ea..a98e9b1 100644 --- a/crates/metassr-build/src/server/pages_generator.rs +++ b/crates/metassr-build/src/server/pages_generator.rs @@ -6,9 +6,11 @@ use std::{ use anyhow::{anyhow, Result}; use metassr_utils::{ + analyzer::{ + dist_dir::{DistDir, DistDirContainer}, + DirectoryAnalyzer, + }, cache_dir::CacheDir, - dist_analyzer::{DistDir, DistDirContainer}, - traits::AnalyzeDir, }; use crate::traits::Exec; diff --git a/crates/metassr-build/src/server/renderer/html.rs b/crates/metassr-build/src/server/renderer/html.rs index e96d88d..dd16f68 100644 --- a/crates/metassr-build/src/server/renderer/html.rs +++ b/crates/metassr-build/src/server/renderer/html.rs @@ -6,7 +6,7 @@ use html_generator::{ html_props::HtmlProps, template::HtmlTemplate, }; -use metassr_utils::dist_analyzer::PageEntry; +use metassr_utils::analyzer::dist_dir::PageEntry; pub struct HtmlRenderer<'a> { head: String, diff --git a/crates/metassr-build/src/server/renderer/page.rs b/crates/metassr-build/src/server/renderer/page.rs index a57f559..d2ba4b5 100644 --- a/crates/metassr-build/src/server/renderer/page.rs +++ b/crates/metassr-build/src/server/renderer/page.rs @@ -1,7 +1,7 @@ use std::ffi::OsStr; use anyhow::Result; -use metassr_utils::{cache_dir::CacheDir, dist_analyzer::PageEntry}; +use metassr_utils::{analyzer::dist_dir::PageEntry, cache_dir::CacheDir}; use crate::{ server::{manifest::Manifest, render_exec::RenderExec}, diff --git a/crates/metassr-build/src/server/targets.rs b/crates/metassr-build/src/server/targets.rs index 8e1ce14..60eb020 100644 --- a/crates/metassr-build/src/server/targets.rs +++ b/crates/metassr-build/src/server/targets.rs @@ -4,7 +4,7 @@ use std::{ }; use anyhow::Result; -use metassr_utils::{cache_dir::CacheDir, src_analyzer::PagesEntriesType}; +use metassr_utils::{analyzer::src_dir::PagesEntriesType, cache_dir::CacheDir}; use crate::{traits::Generate, utils::setup_page_path}; diff --git a/crates/metassr-server/src/handler.rs b/crates/metassr-server/src/handler.rs index 7e5b975..5ca2a71 100644 --- a/crates/metassr-server/src/handler.rs +++ b/crates/metassr-server/src/handler.rs @@ -5,9 +5,9 @@ use axum::{ routing::get, }; use metassr_build::server::renderer::page::PageRenderer; -use metassr_utils::{ - dist_analyzer::{DistDir, PageEntry}, - traits::AnalyzeDir, +use metassr_utils::analyzer::{ + dist_dir::{DistDir, PageEntry}, + DirectoryAnalyzer, }; use std::{collections::HashMap, fs::read_to_string, path::PathBuf}; diff --git a/crates/metassr-utils/src/analyzer/dist_dir.rs b/crates/metassr-utils/src/analyzer/dist_dir.rs new file mode 100644 index 0000000..1bc97b5 --- /dev/null +++ b/crates/metassr-utils/src/analyzer/dist_dir.rs @@ -0,0 +1,421 @@ +use super::DirectoryAnalyzer; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashMap, + ffi::OsStr, + marker::Sized, + path::{Path, PathBuf}, +}; +use walkdir::WalkDir; + +/// `DistDirContainer` is a structure that holds the analyzing results for the `dist/` directory. +/// It contains a `HashMap` where the keys are page names (directories) and the values are `PageEntry` structures. +/// +/// # Example +/// +/// ```no_run +/// use metassr_utils::analyzer::dist_dir::{DistDirContainer, PageEntry}; +/// use std::{collections::HashMap, path::PathBuf}; +/// +/// let mut container = DistDirContainer { +/// pages: HashMap::new(), +/// }; +/// +/// let page_entry = PageEntry::new(PathBuf::from("/dist/pages/home.js")); +/// container.pages.insert("home".to_string(), page_entry); +/// +/// println!("{:?}", container.pages.get("home")); +/// ``` +#[derive(Debug)] +pub struct DistDirContainer { + pub pages: HashMap, // Maps page paths to page entries +} + +/// `PageEntry` represents the details for each page found in the `dist/` directory. +/// It includes the paths for JavaScript and CSS files (scripts and styles). +/// +/// # Example +/// +/// ```no_run +/// use metassr_utils::analyzer::dist_dir::PageEntry; +/// use std::path::PathBuf; +/// +/// let mut page_entry = PageEntry::new(PathBuf::from("/dist/pages/home")); +/// +/// page_entry.push_script(&PathBuf::from("/dist/pages/home/main.js")); +/// page_entry.push_style(&PathBuf::from("/dist/pages/home/main.css")); +/// +/// println!("{:?}", page_entry); +/// ``` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PageEntry { + pub scripts: Vec, // List of paths to JavaScript files for the page + pub styles: Vec, // List of paths to CSS files for the page + pub path: PathBuf, // The actual path of the page (directory) +} + +impl PageEntry { + /// Creates a new `PageEntry` given the path to a page. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::analyzer::dist_dir::PageEntry; + /// use std::path::PathBuf; + /// + /// let page_entry = PageEntry::new(PathBuf::from("/dist/pages/home")); + /// println!("{:?}", page_entry.path); + /// ``` + pub fn new(path: PathBuf) -> Self { + Self { + scripts: vec![], // Initialize with an empty list of scripts + styles: vec![], // Initialize with an empty list of styles + path, // Set the path of the page + } + } + + /// Adds a script (JavaScript file) to the `scripts` list for the page. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::analyzer::dist_dir::PageEntry; + /// use std::path::PathBuf; + /// + /// let mut page_entry = PageEntry::new(PathBuf::from("/dist/pages/home")); + /// page_entry.push_script(&PathBuf::from("/dist/pages/home/main.js")); + /// println!("{:?}", page_entry.scripts); + /// ``` + pub fn push_script(&mut self, path: &Path) { + self.scripts.push(path.to_path_buf()); + } + + /// Adds a style (CSS file) to the `styles` list for the page. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::analyzer::dist_dir::PageEntry; + /// use std::path::PathBuf; + /// + /// let mut page_entry = PageEntry::new(PathBuf::from("/dist/pages/home")); + /// page_entry.push_style(&PathBuf::from("/dist/pages/home/style.css")); + /// println!("{:?}", page_entry.styles); + /// ``` + pub fn push_style(&mut self, path: &Path) { + self.styles.push(path.to_path_buf()); + } +} + +/// `DistDir` is responsible for analyzing the `dist/` directory, +/// which is typically a folder generated by a bundler like `rspack` that contains JavaScript and CSS files. +/// It extracts and organizes the page structure based on the files inside the directory. +/// +/// # Example +/// +/// ```no_run +/// use metassr_utils::analyzer::{dist_dir::DistDir, DirectoryAnalyzer}; +/// +/// let dist_dir = DistDir::new("path/to/dist").unwrap(); +/// let analysis_result = dist_dir.analyze().unwrap(); +/// +/// for (page, entry) in analysis_result.pages { +/// println!("Page: {}, Scripts: {:?}, Styles: {:?}", page, entry.scripts, entry.styles); +/// } +/// ``` +#[derive(Debug)] +pub struct DistDir(PathBuf); // Contains the path to the `dist/` directory + +impl DistDir { + /// Creates a new `DistDir` object given a path to the `dist/` directory. + /// Returns an error if the provided path does not exist. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::analyzer::dist_dir::DistDir; + /// + /// let dist_dir = DistDir::new("path/to/dist"); + /// match dist_dir { + /// Ok(dir) => println!("Dist directory found!"), + /// Err(e) => println!("Error: {}", e), + /// } + /// ``` + pub fn new(path: &S) -> Result + where + S: AsRef + ?Sized, // Accepts types that can be referenced as `OsStr` + { + let path = PathBuf::from(path); + + // Check if the path exists, and return an error if not foundd + if !path.exists() { + return Err(anyhow!("Dist directory not found: {path:#?}")); + } + + Ok(Self(path)) + } +} + +/// `AnalyzeDir` trait is implemented for `DistDir`. +/// This implementation allows analyzing the directory and extracting its structure. +/// +/// # Example +/// +/// ```no_run +/// use metassr_utils::analyzer::{dist_dir::DistDir, DirectoryAnalyzer}; +/// +/// let dist_dir = DistDir::new("/path/to/dist").unwrap(); +/// let result = dist_dir.analyze().unwrap(); +/// for (page, entry) in result.pages { +/// println!("Page: {}, Scripts: {:?}, Styles: {:?}", page, entry.scripts, entry.styles); +/// } +/// ``` +impl DirectoryAnalyzer for DistDir { + type Output = DistDirContainer; // The output of the analysis is a `DistDirContainer` + + /// Analyzes the `dist/` directory to find and organize JavaScript and CSS files + /// inside the `pages/` subdirectory, if it exists. + /// + /// # Example + /// + /// ```no_run + /// use metassr_utils::analyzer::{dist_dir::DistDir, DirectoryAnalyzer}; + /// + /// let dist_dir = DistDir::new("path/to/dist").unwrap(); + /// let analysis_result = dist_dir.analyze().unwrap(); + /// + /// for (page, entry) in analysis_result.pages { + /// println!("Page: {}, Scripts: {:?}, Styles: {:?}", page, entry.scripts, entry.styles); + /// } + /// ``` + fn analyze(&self) -> Result { + let pages_path = self.0.join("pages"); // Define the path to the `pages` directory inside `dist` + let mut pages: HashMap = HashMap::new(); // Create a `HashMap` to store pages + + // Traverse the `pages` directory recursively and filter out files based on extensions (js, css) + for entry in WalkDir::new(pages_path.clone()) + .into_iter() + .filter_map(|e| { + let exts = ["js", "css"]; + match e.ok() { + Some(e) + if e.path().is_file() + && exts.contains(&e.path().extension().unwrap().to_str().unwrap()) => + { + Some(e) // Include files that are either JS or CSS + } + _ => None, + } + }) + { + let path = entry.path(); // Get the path of the current file + let parent = path.parent().unwrap(); // Get the parent directory of the file (the page directory) + + // Strip the `pages_path` prefix from the parent directory path to get a relative path + let parent_stripped = match parent.strip_prefix(pages_path.clone()).unwrap() { + p if p == Path::new("") => "#root", // If no parent, set the root identifier + p => p.to_str().unwrap(), // Otherwise, use the relative path as the identifier + }; + + let ext = path.extension().unwrap().to_str().unwrap(); // Get the file extension (js or css) + + // If the page does not already exist in the `pages` map, insert a new `PageEntry` + if !pages.contains_key(parent_stripped) { + pages.insert( + parent_stripped.to_owned(), + PageEntry::new(parent.to_path_buf().canonicalize().unwrap()), // Add canonicalized parent path + ); + }; + + let page_entry = pages.get_mut(parent_stripped).unwrap(); // Get the `PageEntry` for the current page + + // Depending on the file extension, add the file to either `scripts` or `styles` + match ext { + "js" => (*page_entry).push_script(path), + "css" => (*page_entry).push_style(path), + _ => (), + } + } + + // Return the analyzed pages in a `DistDirContainer` + Ok(Self::Output { pages }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::rand::Rand; + use std::fs; + /// Helper function to create a temporary directory structure for testing + fn setup_test_dist_dir() -> PathBuf { + let tmp_dir = std::env::temp_dir() + .join(&Rand::new().val().to_string()) + .join("test-dist"); + let pages_dir = tmp_dir.join("pages"); + + // Clear any previous test data + if pages_dir.exists() { + fs::remove_dir_all(&pages_dir).unwrap(); + } + + fs::create_dir_all(&pages_dir).unwrap(); + + // Create some test files + fs::write(pages_dir.join("index.js"), "// JavaScript file").unwrap(); + fs::write(pages_dir.join("style.css"), "/* CSS file */").unwrap(); + fs::create_dir(pages_dir.join("subdir")).unwrap(); + fs::write( + pages_dir.join("subdir").join("script.js"), + "// Subdir JS file", + ) + .unwrap(); + fs::write( + pages_dir.join("subdir").join("substyle.css"), + "/* Subdir CSS file */", + ) + .unwrap(); + dbg!(&tmp_dir.canonicalize(), &pages_dir.canonicalize()); + tmp_dir + } + + /// Clean up the test directory after tests + fn cleanup_test_dist_dir(test_dir: PathBuf) { + if test_dir.exists() { + fs::remove_dir_all(test_dir).unwrap(); + } + } + + #[test] + fn test_analyze_valid_dist_dir() { + let test_dir = setup_test_dist_dir(); + let dist_dir = DistDir::new(&test_dir).unwrap(); + + let result = dist_dir.analyze().unwrap(); + let pages = result.pages; + + // Ensure correct number of pages + assert_eq!( + pages.len(), + 2, + "Expected 2 page entries, found {}", + pages.len() + ); + + // Validate root page + let root_page = pages.get("#root").expect("Root page should exist"); + assert_eq!(root_page.scripts.len(), 1, "Expected 1 script in root page"); + assert_eq!(root_page.styles.len(), 1, "Expected 1 style in root page"); + + // Validate subdir page + let subdir_page = pages.get("subdir").expect("Subdir page should exist"); + assert_eq!( + subdir_page.scripts.len(), + 1, + "Expected 1 script in subdir page" + ); + assert_eq!( + subdir_page.styles.len(), + 1, + "Expected 1 style in subdir page" + ); + + cleanup_test_dist_dir(test_dir); + } + + #[test] + fn test_dist_dir_not_found() { + let invalid_path = std::env::temp_dir().join("invalid-dist"); + let result = DistDir::new(&invalid_path); + + assert!( + result.is_err(), + "Expected error when dist directory is not found" + ); + if let Err(err) = result { + assert!( + err.to_string().contains("Dist directory not found"), + "Unexpected error message: {}", + err + ); + } + } + + #[test] + fn test_empty_dist_dir() { + let test_dir = std::env::temp_dir().join("empty-test-dist"); + fs::create_dir_all(test_dir.join("pages")).unwrap(); // Create empty pages directory + + let dist_dir = DistDir::new(&test_dir).unwrap(); + let result = dist_dir.analyze().unwrap(); + + assert!( + result.pages.is_empty(), + "Expected no page entries in an empty dist directory" + ); + + cleanup_test_dist_dir(test_dir); + } + + #[test] + fn test_analyze_unsupported_file_extensions() { + let test_dir = setup_test_dist_dir(); + + // Create a file with an unsupported extension + fs::write( + test_dir.join("pages").join("unsupported.txt"), + "Unsupported file", + ) + .unwrap(); + + let dist_dir = DistDir::new(&test_dir).unwrap(); + let result = dist_dir.analyze().unwrap(); + + // Ensure the unsupported file is ignored + assert_eq!( + result.pages.len(), + 2, + "Expected 2 page entries, found {}", + result.pages.len() + ); + + cleanup_test_dist_dir(test_dir); + } + + #[test] + fn test_analyze_dist_dir_with_only_scripts() { + let test_dir = std::env::temp_dir().join("script-only-test-dist"); + let pages_dir = test_dir.join("pages"); + + fs::create_dir_all(&pages_dir).unwrap(); + fs::write(pages_dir.join("script.js"), "// JavaScript file").unwrap(); + + let dist_dir = DistDir::new(&test_dir).unwrap(); + let result = dist_dir.analyze().unwrap(); + + let root_page = result.pages.get("#root").expect("Root page should exist"); + assert_eq!(root_page.scripts.len(), 1, "Expected 1 script file"); + assert!(root_page.styles.is_empty(), "Expected no styles"); + + cleanup_test_dist_dir(test_dir); + } + + #[test] + fn test_analyze_dist_dir_with_only_styles() { + let test_dir = std::env::temp_dir().join("style-only-test-dist"); + let pages_dir = test_dir.join("pages"); + + fs::create_dir_all(&pages_dir).unwrap(); + fs::write(pages_dir.join("style.css"), "/* CSS file */").unwrap(); + + let dist_dir = DistDir::new(&test_dir).unwrap(); + let result = dist_dir.analyze().unwrap(); + + let root_page = result.pages.get("#root").expect("Root page should exist"); + assert_eq!(root_page.styles.len(), 1, "Expected 1 style file"); + assert!(root_page.scripts.is_empty(), "Expected no scripts"); + + cleanup_test_dist_dir(test_dir); + } +} diff --git a/crates/metassr-utils/src/traits.rs b/crates/metassr-utils/src/analyzer/mod.rs similarity index 56% rename from crates/metassr-utils/src/traits.rs rename to crates/metassr-utils/src/analyzer/mod.rs index a83786c..7f5bf65 100644 --- a/crates/metassr-utils/src/traits.rs +++ b/crates/metassr-utils/src/analyzer/mod.rs @@ -1,5 +1,9 @@ +pub mod dist_dir; +pub mod src_dir; + + use anyhow::Result; -pub trait AnalyzeDir { +pub trait DirectoryAnalyzer { type Output; fn analyze(&self) -> Result; } diff --git a/crates/metassr-utils/src/analyzer/src_dir.rs b/crates/metassr-utils/src/analyzer/src_dir.rs new file mode 100644 index 0000000..2ef30bc --- /dev/null +++ b/crates/metassr-utils/src/analyzer/src_dir.rs @@ -0,0 +1,223 @@ +use super::DirectoryAnalyzer; +use anyhow::{anyhow, Result}; +use std::{collections::HashMap, ffi::OsStr, marker::Sized, path::PathBuf}; +use walkdir::WalkDir; + +/// Wrappers for special entries that collected by the source analyzer +pub mod special_entries { + use std::path::PathBuf; + + /// Represents a special entry for the `_app.[js, jsx, ts, tsx]` file. + #[derive(Debug, Clone)] + pub struct App(pub PathBuf); + + /// Represents a special entry for the `_head.[js, jsx, ts, tsx]` file. + #[derive(Debug, Clone)] + pub struct Head(pub PathBuf); +} + +pub type PagesEntriesType = HashMap; +pub type SpecialEntriesType = (Option, Option); + +/// A container holding the results of analyzing a source directory. +/// +/// This struct holds the pages and special entries found in the source directory. +#[derive(Debug, Clone)] +pub struct SourceDirContainer { + pub pages: PagesEntriesType, + pub specials: SpecialEntriesType, +} + +impl SourceDirContainer { + /// Creates a new `SourceDirContainer` with the given pages and special entries. + /// + /// # Parameters + /// + /// - `pages`: A `HashMap` where keys are routes and values are paths to page files. + /// - `specials`: A tuple containing optional special entries (`App` and `Head`). + pub fn new(pages: PagesEntriesType, specials: SpecialEntriesType) -> Self { + Self { pages, specials } + } + + /// Retrieves the special entries from the container. + /// + /// # Returns + /// + /// Returns a `Result` containing a tuple of `App` and `Head` if both are present, + /// or an error if one or both are missing. + pub fn specials(&self) -> Result<(special_entries::App, special_entries::Head)> { + let (app, head) = self.specials.clone(); + if let (Some(app), Some(head)) = (app.clone(), head.clone()) { + return Ok((app, head)); + } + let mut not_found = vec![]; + if app.is_none() { + not_found.push("_app.[js,jsx,ts,tsx]") + } + if head.is_none() { + not_found.push("_head.[js,jsx,ts,tsx]") + } + Err(anyhow!( + "Couldn't find: {}. Create the files that have not been found.", + not_found.join(", ") + )) + } + + /// Retrieves the pages entries from the container. + /// + /// # Returns + /// + /// Returns a `HashMap` where keys are routes and values are paths to page files. + pub fn pages(&self) -> PagesEntriesType { + self.pages.clone() + } +} + +/// A directory analyzer for a source directory. +/// +/// This struct provides functionality to analyze a directory and extract pages and special entries. +#[derive(Debug)] +pub struct SourceDir(PathBuf); + +impl SourceDir { + /// Creates a new `SourceDir` instance. + /// + /// # Parameters + /// + /// - `path`: The path to the source directory. + pub fn new(path: &S) -> Self + where + S: AsRef + ?Sized, + { + Self(PathBuf::from(path)) + } +} + +impl DirectoryAnalyzer for SourceDir { + type Output = SourceDirContainer; + + /// Analyzes the source directory and extracts pages and special entries. + /// + /// # Returns + /// + /// Returns a `Result` containing a `SourceDirContainer` with pages and special entries. + fn analyze(&self) -> Result { + let src = self.0.to_str().unwrap(); + + let list_of_specials = ["_app", "_head"]; + let mut pages: HashMap = HashMap::new(); + let mut specials: SpecialEntriesType = (None, None); + + for entry in WalkDir::new(src) + .into_iter() + .filter_map(|e| match e.ok() { + Some(e) if e.path().is_file() => Some(e), + _ => None, + }) + .skip_while(|e| { + // Check if the entry is a js/ts file. + let exts: Vec<&str> = vec!["js", "jsx", "tsx", "ts"]; + !exts.contains(&e.path().extension().unwrap().to_str().unwrap()) + }) + { + let path = entry.path(); + let stem = path.file_stem().unwrap().to_str().unwrap(); + let stripped = path.strip_prefix(src)?; + + match stripped.iter().next() { + Some(_) if list_of_specials.contains(&stem) => match stem { + "_app" => specials.0 = Some(special_entries::App(path.to_path_buf())), + "_head" => specials.1 = Some(special_entries::Head(path.to_path_buf())), + _ => (), + }, + + Some(p) if p == OsStr::new("pages") => { + let route = path + .strip_prefix([src, "/pages"].concat())? + .to_str() + .unwrap(); + pages.insert(route.to_owned(), path.to_path_buf()); + } + + _ => (), + } + } + + let container = SourceDirContainer::new(pages, specials); + + // Return an error if specials not found. + if let Err(err) = container.specials() { + return Err(anyhow!(err)); + } + + Ok(container) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::rand::Rand; + use std::fs; + use std::path::PathBuf; + + /// Helper function to create a temporary source directory with a random name. + fn create_temp_source_dir() -> Result { + let dir_path = PathBuf::from(format!("src-{}", Rand::new().val())); + fs::create_dir_all(&dir_path)?; + Ok(SourceDir::new(&dir_path)) + } + + /// Test case to verify the creation and analysis of a source directory. + #[test] + fn test_create_and_analyze_source_dir() { + let source_dir = create_temp_source_dir().unwrap(); + let pages = vec!["page1.jsx", "page2.tsx"]; + let specials = vec!["_app.jsx", "_head.tsx"]; + + for page in pages.iter() { + let path = source_dir.0.join("pages").join(page); + fs::create_dir_all(path.parent().unwrap()).unwrap(); + fs::write(&path, b"dummy content").unwrap(); + } + + for special in specials.iter() { + let path = source_dir.0.join(special); + fs::write(&path, b"dummy content").unwrap(); + } + + let result = source_dir.analyze().unwrap(); + assert_eq!(result.pages().len(), pages.len()); + assert!(result.specials().is_ok()); + + // Cleanup + for page in pages.iter() { + let path = source_dir.0.join("pages").join(page); + fs::remove_file(&path).unwrap(); + } + for special in specials.iter() { + let path = source_dir.0.join(special); + fs::remove_file(&path).unwrap(); + } + fs::remove_dir_all(source_dir.0).unwrap(); + } + + /// Test case to verify handling of missing special entries. + #[test] + fn test_missing_special_entries() { + let source_dir = create_temp_source_dir().unwrap(); + let page_path = source_dir.0.join("pages/page1.jsx"); + fs::create_dir_all(page_path.parent().unwrap()).unwrap(); + fs::write(&page_path, b"dummy content").unwrap(); + + let result = source_dir.analyze(); + assert!( + result.is_err(), + "Should return an error due to missing special entries" + ); + + // Cleanup + fs::remove_file(&page_path).unwrap(); + fs::remove_dir_all(source_dir.0).unwrap(); + } +} diff --git a/crates/metassr-utils/src/dist_analyzer.rs b/crates/metassr-utils/src/dist_analyzer.rs deleted file mode 100644 index 5bd244c..0000000 --- a/crates/metassr-utils/src/dist_analyzer.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::traits::AnalyzeDir; -use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; -use std::{ - collections::HashMap, - ffi::OsStr, - marker::Sized, - path::{Path, PathBuf}, -}; -use walkdir::WalkDir; -/// A container contains analyzing result for `dist/` directory. -#[derive(Debug)] -pub struct DistDirContainer { - pub pages: HashMap, -} - -/// The page entry, where each pages details stored. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PageEntry { - pub scripts: Vec, - pub styles: Vec, - pub path: PathBuf, -} - -impl PageEntry { - pub fn new(path: PathBuf) -> Self { - Self { - scripts: vec![], - styles: vec![], - path, - } - } - pub fn push_script(&mut self, path: &Path) { - self.scripts.push(path.to_path_buf()); - } - pub fn push_style(&mut self, path: &Path) { - self.styles.push(path.to_path_buf()); - } -} - -/// A simple analyzer for `dist/` directory to extract script files and style files, a bundled files generated using `rspack`. -#[derive(Debug)] -pub struct DistDir(PathBuf); - -impl DistDir { - pub fn new(path: &S) -> Result - where - S: AsRef + ?Sized, - { - let path = PathBuf::from(path); - if !path.exists() { - return Err(anyhow!("Dist directory not found: {path:#?}")); - } - - Ok(Self(path)) - } -} - -impl AnalyzeDir for DistDir { - type Output = DistDirContainer; - fn analyze(&self) -> Result { - let pages_path = self.0.join("pages"); - let mut pages: HashMap = HashMap::new(); - - for entry in WalkDir::new(pages_path.clone()) - .into_iter() - .filter_map(|e| { - let exts = ["js", "css"]; - match e.ok() { - Some(e) - if e.path().is_file() - && exts.contains(&e.path().extension().unwrap().to_str().unwrap()) => - { - Some(e) - } - _ => None, - } - }) - { - let path = entry.path(); - let parent = path.parent().unwrap(); - - let parent_stripped = match parent.strip_prefix(pages_path.clone()).unwrap() { - p if p == Path::new("") => "#root", - p => p.to_str().unwrap(), - }; - let ext = path.extension().unwrap().to_str().unwrap(); - // let stem = path.file_stem().unwrap().to_str().unwrap(); - // let stripped = path.strip_prefix(src)?; - if !pages.contains_key(parent_stripped) { - pages.insert( - parent_stripped.to_owned(), - PageEntry::new(parent.to_path_buf().canonicalize().unwrap()), - ); - }; - - let page = pages.get_mut(parent_stripped).unwrap(); - match ext { - "js" => (*page).push_script(path), - "css" => { - (*page).push_style(path); - } - _ => (), - } - } - - Ok(Self::Output { pages }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - dbg!(&DistDir::new("../../tests/web-app/dist") - .unwrap() - .analyze() - .unwrap()); - } -} diff --git a/crates/metassr-utils/src/lib.rs b/crates/metassr-utils/src/lib.rs index dc81d5e..7024b87 100644 --- a/crates/metassr-utils/src/lib.rs +++ b/crates/metassr-utils/src/lib.rs @@ -1,6 +1,4 @@ +pub mod analyzer; pub mod cache_dir; pub mod checker; -pub mod dist_analyzer; pub mod rand; -pub mod src_analyzer; -pub mod traits; diff --git a/crates/metassr-utils/src/src_analyzer.rs b/crates/metassr-utils/src/src_analyzer.rs deleted file mode 100644 index ec9e264..0000000 --- a/crates/metassr-utils/src/src_analyzer.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::traits::AnalyzeDir; -use anyhow::{anyhow, Result}; -use std::{collections::HashMap, ffi::OsStr, marker::Sized, path::PathBuf}; -use walkdir::WalkDir; - -pub mod special_entries { - use std::path::PathBuf; - - #[derive(Debug, Clone)] - pub struct Head(pub PathBuf); - #[derive(Debug, Clone)] - pub struct App(pub PathBuf); -} - -pub type PagesEntriesType = HashMap; -pub type SpecialEntriesType = (Option, Option); -#[derive(Debug, Clone)] - -pub struct SourceDirContainer { - pub pages: PagesEntriesType, - pub specials: SpecialEntriesType, -} - -impl SourceDirContainer { - pub fn new(pages: PagesEntriesType, specials: SpecialEntriesType) -> Self { - Self { pages, specials } - } - - pub fn specials(&self) -> Result<(special_entries::App, special_entries::Head)> { - let (app, head) = self.specials.clone(); - if let (Some(app), Some(head)) = (app.clone(), head.clone()) { - return Ok((app, head)); - } - let mut not_found = vec![]; - if app.is_none() { - not_found.push("_app.[js,jsx,ts,tsx]") - } - if head.is_none() { - not_found.push("_head.[js,jsx,ts,tsx]") - } - Err(anyhow!( - "Couldn't found: {}. Create the files that have not been found.", - not_found.join(", ") - )) - } - - pub fn pages(&self) -> PagesEntriesType { - self.pages.clone() - } -} - -#[derive(Debug)] -pub struct SourceDir(PathBuf); - -impl SourceDir { - pub fn new(path: &S) -> Self - where - S: AsRef + ?Sized, - { - Self(PathBuf::from(path)) - } -} - -impl AnalyzeDir for SourceDir { - type Output = SourceDirContainer; - fn analyze(&self) -> Result { - let src = self.0.to_str().unwrap(); - - let list_of_specials = ["_app", "_head"]; - let mut pages: HashMap = HashMap::new(); - let mut specials: SpecialEntriesType = (None, None); - - for entry in WalkDir::new(src) - .into_iter() - .filter_map(|e| match e.ok() { - Some(e) if e.path().is_file() => Some(e), - _ => None, - }) - .skip_while(|e| { - // Check if the entry is a js/ts file. - let exts: Vec<&str> = vec!["js", "jsx", "tsx", "ts"]; - !exts.contains(&e.path().extension().unwrap().to_str().unwrap()) - }) - { - let path = entry.path(); - let stem = path.file_stem().unwrap().to_str().unwrap(); - let stripped = path.strip_prefix(src)?; - - match stripped.iter().next() { - Some(_) if list_of_specials.contains(&stem) => { - match stem { - "_app" => specials.0 = Some(special_entries::App(path.to_path_buf())), - "_head" => specials.1 = Some(special_entries::Head(path.to_path_buf())), - _ => (), - } - } - - Some(p) if p == OsStr::new("pages") => { - let route = path - .strip_prefix([src, "/pages"].concat())? - .to_str() - .unwrap(); - pages.insert(route.to_owned(), path.to_path_buf()); - } - - _ => (), - } - } - - Ok(SourceDirContainer::new(pages, specials)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - dbg!(&SourceDir::new("../../tests/web-app/src").analyze().unwrap()); - } -} From b57f1b984f5f3053702940c9da3053be584ead5b Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 19 Sep 2024 01:08:03 +0300 Subject: [PATCH 05/10] docs(utils): improve documentation of `metassr-utils` crate - add `README.md` for `metassr-utils` - add documenation for`metassr-utils` crate - improve documenation of each module in the crate --- crates/metassr-utils/README.md | 9 ++++ crates/metassr-utils/src/analyzer/dist_dir.rs | 2 +- crates/metassr-utils/src/analyzer/mod.rs | 20 +++++++- crates/metassr-utils/src/lib.rs | 51 +++++++++++++++++++ crates/metassr-utils/src/rand.rs | 2 +- 5 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 crates/metassr-utils/README.md diff --git a/crates/metassr-utils/README.md b/crates/metassr-utils/README.md new file mode 100644 index 0000000..fd07a70 --- /dev/null +++ b/crates/metassr-utils/README.md @@ -0,0 +1,9 @@ +# MetaSSR Utilities +This module contains utility components that are designed to assist with the functionality of the MetaSSR framework. +These utilities serve different purposes, including directory analysis, caching, state checking, and random value generation. +## Available Modules +- [`analyzer`]: Provides functionalities to analyze directories (e.g., source and distribution directories) and extract specific files based on criteria. +- [`cache_dir`]: Offers caching utilities for managing and organizing cached files within a directory. +- [`checker`]: A simple utility to track and manage a boolean state. +- [`rand`]: A random number generator utility based on hashing for generating pseudo-random values. + diff --git a/crates/metassr-utils/src/analyzer/dist_dir.rs b/crates/metassr-utils/src/analyzer/dist_dir.rs index 1bc97b5..2ba869c 100644 --- a/crates/metassr-utils/src/analyzer/dist_dir.rs +++ b/crates/metassr-utils/src/analyzer/dist_dir.rs @@ -128,7 +128,7 @@ impl PageEntry { pub struct DistDir(PathBuf); // Contains the path to the `dist/` directory impl DistDir { - /// Creates a new `DistDir` object given a path to the `dist/` directory. + /// Creates a new `DistDir` struct given a path to the `dist/` directory. /// Returns an error if the provided path does not exist. /// /// # Example diff --git a/crates/metassr-utils/src/analyzer/mod.rs b/crates/metassr-utils/src/analyzer/mod.rs index 7f5bf65..6febb09 100644 --- a/crates/metassr-utils/src/analyzer/mod.rs +++ b/crates/metassr-utils/src/analyzer/mod.rs @@ -1,9 +1,25 @@ +use anyhow::Result; + +/// Analyzes the `dist/` directory for scripts and style files. The `dist/` directory +/// contains bundled and compiled assets like JavaScript and CSS files. pub mod dist_dir; -pub mod src_dir; +/// Analyzes the `src/` directory for source code files. The `src/` directory typically +/// contains raw, uncompiled TypeScript or JavaScript modules used in a project. +pub mod src_dir; -use anyhow::Result; +/// A trait for analyzing directories to extract and process files. +/// +/// Implement this trait for any directory that needs to be analyzed. The trait defines +/// an associated `Output` type and a required `analyze` method to return a result of that type. pub trait DirectoryAnalyzer { + /// The output type returned by the `analyze` function. type Output; + + /// Analyzes the directory and returns the result of the analysis. + /// + /// # Errors + /// If the directory or its contents cannot be analyzed (e.g., due to a missing directory, + /// unreadable files, or unexpected formats), the function returns an error. fn analyze(&self) -> Result; } diff --git a/crates/metassr-utils/src/lib.rs b/crates/metassr-utils/src/lib.rs index 7024b87..1cd065b 100644 --- a/crates/metassr-utils/src/lib.rs +++ b/crates/metassr-utils/src/lib.rs @@ -1,4 +1,55 @@ +#![doc = include_str!("../README.md")] + +/// This module provides directory analyzers for extracting useful files from directories like `src/` and `dist/`. pub mod analyzer; + +/// This module provides utilities for managing cache directories, creating files, and handling their contents. +/// +/// This is useful for caching purposes where files are written and +/// retrieved based on a pathname, making it easier to manage multiple +/// cached files in a structured directory. +/// +/// # Example +/// +/// ```no_run +/// use metassr_utils::cache_dir::CacheDir; +/// +/// let mut cache = CacheDir::new(".cache").unwrap(); +/// cache.insert("example.txt", "Cache data".as_bytes()).unwrap(); +/// println!("{:?}", cache.entries_in_scope()); +/// ``` pub mod cache_dir; + +/// This module contains a simple utility for managing a boolean state that can be toggled on or off. +/// It allows for easy manipulation of the state with utility methods to set it to `true` or `false`. +/// +/// This can be useful in situations where you need a simple flag to represent a state in an application. +/// +/// # Example +/// +/// ```rust +/// use metassr_utils::checker::CheckerState; +/// +/// let mut state = CheckerState::default(); +/// assert!(!state.is_true()); // Initially false by default +/// +/// state.make_true(); +/// assert!(state.is_true()); // Now true +/// +/// state.make_false(); +/// assert!(!state.is_true()); // Back to false +/// ``` pub mod checker; + +/// This module offers a utility to generate random numbers based on hash values for purposes such as creating random directory names. +/// This is useful for situations where you need a random integer in your application. +/// The random value is generated when the `Rand` struct is instantiated. +/// +/// # Example +/// +/// ```rust +/// use metassr_utils::rand::Rand; +/// let rand = Rand::new(); +/// println!("Generated random value: {}", rand.val()); +/// ``` pub mod rand; diff --git a/crates/metassr-utils/src/rand.rs b/crates/metassr-utils/src/rand.rs index 1030827..2bb1fd7 100644 --- a/crates/metassr-utils/src/rand.rs +++ b/crates/metassr-utils/src/rand.rs @@ -7,7 +7,7 @@ use std::{ /// It uses the `RandomState` from the standard library's hash map as a source of randomness. /// /// This is useful for situations where you need a random integer in your application. -/// The random value is generated when the `Rand` object is instantiated. +/// The random value is generated when the `Rand` struct is instantiated. /// /// # Example /// From 782e4d849c3610eb0c6d58cd76264f27cba93f90 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 20 Sep 2024 14:55:32 +0300 Subject: [PATCH 06/10] feat(utils): implement some traits for Rand struct - implement `std::fmt::Display` - implement `std::cmp::PartialEq` and `std::cmp::PartialOrd` - implement `std::cmp::PartialEq` and `std::cmp::PartialOrd` --- crates/metassr-utils/src/rand.rs | 96 +++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 14 deletions(-) diff --git a/crates/metassr-utils/src/rand.rs b/crates/metassr-utils/src/rand.rs index 2bb1fd7..1174667 100644 --- a/crates/metassr-utils/src/rand.rs +++ b/crates/metassr-utils/src/rand.rs @@ -1,33 +1,35 @@ use std::{ collections::hash_map::RandomState, + fmt::Display, hash::{BuildHasher, Hasher}, }; /// `Rand` is a simple structure that generates a random 64-bit integer value. /// It uses the `RandomState` from the standard library's hash map as a source of randomness. -/// +/// /// This is useful for situations where you need a random integer in your application. /// The random value is generated when the `Rand` struct is instantiated. /// /// # Example -/// +/// /// ```rust /// use metassr_utils::rand::Rand; /// let rand = Rand::new(); /// println!("Generated random value: {}", rand.val()); /// ``` +#[derive(Debug)] pub struct Rand(i64); impl Rand { /// Creates a new `Rand` instance, generating a random i64 value using `RandomState`. - /// + /// /// The generated value is always non-negative. /// /// # Example - /// + /// /// ```rust /// use metassr_utils::rand::Rand; - /// + /// /// let random = Rand::new(); /// assert!(random.val() >= 0, "Random value should be non-negative"); /// ``` @@ -39,10 +41,10 @@ impl Rand { /// Returns the generated random value. /// /// # Example - /// + /// /// ```rust /// use metassr_utils::rand::Rand; - /// + /// /// let random = Rand::new(); /// println!("Generated value: {}", random.val()); /// ``` @@ -51,6 +53,68 @@ impl Rand { } } +impl Display for Rand { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}", self.0)) + } +} + +impl PartialEq for Rand { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + fn ne(&self, other: &Self) -> bool { + self.0 != other.0 + } +} + +impl PartialOrd for Rand { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } + fn ge(&self, other: &Self) -> bool { + self.0 >= other.0 + } + fn gt(&self, other: &Self) -> bool { + self.0 > other.0 + } + + fn le(&self, other: &Self) -> bool { + self.0 <= other.0 + } + fn lt(&self, other: &Self) -> bool { + self.0 < other.0 + } +} + +impl PartialEq for Rand { + fn eq(&self, other: &i64) -> bool { + &self.0 == other + } + fn ne(&self, other: &i64) -> bool { + &self.0 != other + } +} + +impl PartialOrd for Rand { + fn partial_cmp(&self, other: &i64) -> Option { + self.0.partial_cmp(other) + } + fn ge(&self, other: &i64) -> bool { + &self.0 >= other + } + fn gt(&self, other: &i64) -> bool { + &self.0 > other + } + + fn le(&self, other: &i64) -> bool { + &self.0 <= other + } + fn lt(&self, other: &i64) -> bool { + &self.0 < other + } +} + #[cfg(test)] mod tests { use super::*; @@ -59,21 +123,25 @@ mod tests { #[test] fn test_random_value_is_non_negative() { let random = Rand::new(); - assert!(random.val() >= 0, "Expected non-negative random value, got {}", random.val()); + assert!( + random >= 0, + "Expected non-negative random value, got {}", + random + ); } /// Test case to ensure random values are distinct in multiple instantiations. #[test] fn test_random_values_are_distinct() { - let mut values: Vec = vec![]; - + let mut values: Vec = vec![]; + // Generate 10 random values and check for uniqueness for _ in 0..10 { - let val = Rand::new().val(); + let val = Rand::new(); assert!(!values.contains(&val), "Random value repeated: {}", val); values.push(val); } - + println!("Generated random values: {:?}", values); } @@ -81,11 +149,11 @@ mod tests { #[test] fn test_random_value_repetition_over_iterations() { let iterations = 100; - let mut values: Vec = vec![]; + let mut values: Vec = vec![]; // Generate a large number of random values to verify low repetition rate for _ in 0..iterations { - let val = Rand::new().val(); + let val = Rand::new(); assert!(!values.contains(&val), "Repeated random value: {}", val); values.push(val); } From 9d94e896966f4425d9f6c57f9865c881fb618962 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 20 Sep 2024 15:20:15 +0300 Subject: [PATCH 07/10] docs(utils): improve formatting --- crates/metassr-utils/src/analyzer/mod.rs | 2 +- crates/metassr-utils/src/analyzer/src_dir.rs | 10 +++++----- crates/metassr-utils/src/cache_dir.rs | 20 ++++++++++---------- crates/metassr-utils/src/checker.rs | 12 ++++++------ crates/metassr-utils/src/lib.rs | 6 +++--- crates/metassr-utils/src/rand.rs | 6 +++--- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/crates/metassr-utils/src/analyzer/mod.rs b/crates/metassr-utils/src/analyzer/mod.rs index 6febb09..c0fba6c 100644 --- a/crates/metassr-utils/src/analyzer/mod.rs +++ b/crates/metassr-utils/src/analyzer/mod.rs @@ -18,7 +18,7 @@ pub trait DirectoryAnalyzer { /// Analyzes the directory and returns the result of the analysis. /// - /// # Errors + /// **Errors** /// If the directory or its contents cannot be analyzed (e.g., due to a missing directory, /// unreadable files, or unexpected formats), the function returns an error. fn analyze(&self) -> Result; diff --git a/crates/metassr-utils/src/analyzer/src_dir.rs b/crates/metassr-utils/src/analyzer/src_dir.rs index 2ef30bc..c5e73fa 100644 --- a/crates/metassr-utils/src/analyzer/src_dir.rs +++ b/crates/metassr-utils/src/analyzer/src_dir.rs @@ -31,7 +31,7 @@ pub struct SourceDirContainer { impl SourceDirContainer { /// Creates a new `SourceDirContainer` with the given pages and special entries. /// - /// # Parameters + /// **Parameters** /// /// - `pages`: A `HashMap` where keys are routes and values are paths to page files. /// - `specials`: A tuple containing optional special entries (`App` and `Head`). @@ -41,7 +41,7 @@ impl SourceDirContainer { /// Retrieves the special entries from the container. /// - /// # Returns + /// **Returns** /// /// Returns a `Result` containing a tuple of `App` and `Head` if both are present, /// or an error if one or both are missing. @@ -65,7 +65,7 @@ impl SourceDirContainer { /// Retrieves the pages entries from the container. /// - /// # Returns + /// **Returns** /// /// Returns a `HashMap` where keys are routes and values are paths to page files. pub fn pages(&self) -> PagesEntriesType { @@ -82,7 +82,7 @@ pub struct SourceDir(PathBuf); impl SourceDir { /// Creates a new `SourceDir` instance. /// - /// # Parameters + /// **Parameters** /// /// - `path`: The path to the source directory. pub fn new(path: &S) -> Self @@ -98,7 +98,7 @@ impl DirectoryAnalyzer for SourceDir { /// Analyzes the source directory and extracts pages and special entries. /// - /// # Returns + /// **Returns** /// /// Returns a `Result` containing a `SourceDirContainer` with pages and special entries. fn analyze(&self) -> Result { diff --git a/crates/metassr-utils/src/cache_dir.rs b/crates/metassr-utils/src/cache_dir.rs index 4252375..fbdd9fc 100644 --- a/crates/metassr-utils/src/cache_dir.rs +++ b/crates/metassr-utils/src/cache_dir.rs @@ -16,7 +16,7 @@ use walkdir::WalkDir; /// retrieved based on a pathname, making it easier to manage multiple /// cached files in a structured directory. /// -/// # Example +/// **Example** /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; @@ -37,15 +37,15 @@ impl CacheDir { /// /// If the directory does not exist, it will be created. /// - /// # Arguments + /// **Arguments** /// /// * `path` - A reference to the directory where the cache will be stored. /// - /// # Errors + /// **Errors** /// /// Returns an error if the directory cannot be created or accessed. /// - /// # Example + /// **Example** /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; @@ -70,16 +70,16 @@ impl CacheDir { /// This method writes a file to the cache directory if it doesn't already exist. /// If the file exists and the content differs, it will be replaced with the new content. /// - /// # Arguments + /// **Arguments** /// /// * `pathname` - The relative path where the file should be stored. /// * `buf` - The content to be written to the file. /// - /// # Returns + /// **Returns** /// /// The `PathBuf` of the written file. /// - /// # Example + /// **Example** /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; @@ -118,7 +118,7 @@ impl CacheDir { /// Returns the path to the cache directory. /// - /// # Example + /// **Example** /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; @@ -132,7 +132,7 @@ impl CacheDir { /// Returns the current entries in scope. /// - /// # Example + /// **Example** /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; @@ -146,7 +146,7 @@ impl CacheDir { /// Returns all file entries in the cache directory. /// - /// # Example + /// **Example** /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; diff --git a/crates/metassr-utils/src/checker.rs b/crates/metassr-utils/src/checker.rs index b45cf66..d829197 100644 --- a/crates/metassr-utils/src/checker.rs +++ b/crates/metassr-utils/src/checker.rs @@ -3,7 +3,7 @@ /// /// This can be useful in situations where you need a simple flag to represent a state in an application. /// -/// # Example +/// **Example** /// /// ```rust /// use metassr_utils::checker::CheckerState; @@ -23,7 +23,7 @@ pub struct CheckerState(bool); // A tuple struct that holds a boolean value impl CheckerState { /// Creates a new `CheckerState` with the specified boolean value. /// - /// # Example + /// **Example** /// /// ```rust /// use metassr_utils::checker::CheckerState; @@ -37,7 +37,7 @@ impl CheckerState { /// Sets the internal state to `true`. /// - /// # Example + /// **Example** /// /// ```rust /// use metassr_utils::checker::CheckerState; @@ -52,7 +52,7 @@ impl CheckerState { /// Sets the internal state to `false`. /// - /// # Example + /// **Example** /// /// ```rust /// use metassr_utils::checker::CheckerState; @@ -67,7 +67,7 @@ impl CheckerState { /// Returns `true` if the internal state is true, otherwise returns `false`. /// - /// # Example + /// **Example** /// /// ```rust /// use metassr_utils::checker::CheckerState; @@ -83,7 +83,7 @@ impl CheckerState { impl Default for CheckerState { /// The default implementation for `CheckerState`, which initializes the state to `false`. /// - /// # Example + /// **Example** /// /// ```rust /// use metassr_utils::checker::CheckerState; diff --git a/crates/metassr-utils/src/lib.rs b/crates/metassr-utils/src/lib.rs index 1cd065b..de1661f 100644 --- a/crates/metassr-utils/src/lib.rs +++ b/crates/metassr-utils/src/lib.rs @@ -9,7 +9,7 @@ pub mod analyzer; /// retrieved based on a pathname, making it easier to manage multiple /// cached files in a structured directory. /// -/// # Example +/// **Example** /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; @@ -25,7 +25,7 @@ pub mod cache_dir; /// /// This can be useful in situations where you need a simple flag to represent a state in an application. /// -/// # Example +/// **Example** /// /// ```rust /// use metassr_utils::checker::CheckerState; @@ -45,7 +45,7 @@ pub mod checker; /// This is useful for situations where you need a random integer in your application. /// The random value is generated when the `Rand` struct is instantiated. /// -/// # Example +/// **Example** /// /// ```rust /// use metassr_utils::rand::Rand; diff --git a/crates/metassr-utils/src/rand.rs b/crates/metassr-utils/src/rand.rs index 1174667..198fc65 100644 --- a/crates/metassr-utils/src/rand.rs +++ b/crates/metassr-utils/src/rand.rs @@ -10,7 +10,7 @@ use std::{ /// This is useful for situations where you need a random integer in your application. /// The random value is generated when the `Rand` struct is instantiated. /// -/// # Example +/// **Example** /// /// ```rust /// use metassr_utils::rand::Rand; @@ -25,7 +25,7 @@ impl Rand { /// /// The generated value is always non-negative. /// - /// # Example + /// **Example** /// /// ```rust /// use metassr_utils::rand::Rand; @@ -40,7 +40,7 @@ impl Rand { /// Returns the generated random value. /// - /// # Example + /// **Example** /// /// ```rust /// use metassr_utils::rand::Rand; From 306ffd7bba7ab8de7f892d4ab322eb364b8193cf Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 20 Sep 2024 15:35:59 +0300 Subject: [PATCH 08/10] refactor: move `metassr_utils::analyzer` to a standalone crate --- Cargo.lock | 25 ++++++++++++++----- Cargo.toml | 6 +++-- crates/metassr-build/Cargo.toml | 1 + crates/metassr-build/src/client/mod.rs | 11 ++++---- crates/metassr-build/src/server/manifest.rs | 8 +++--- crates/metassr-build/src/server/mod.rs | 13 +++++----- .../src/server/pages_generator.rs | 10 +++----- .../metassr-build/src/server/renderer/html.rs | 2 +- .../metassr-build/src/server/renderer/page.rs | 4 ++- crates/metassr-build/src/server/targets.rs | 4 ++- crates/metassr-fs-analyzer/Cargo.toml | 13 ++++++++++ .../src}/dist_dir.rs | 20 +++++++-------- .../mod.rs => metassr-fs-analyzer/src/lib.rs} | 2 ++ .../src}/src_dir.rs | 2 +- crates/metassr-server/Cargo.toml | 1 + crates/metassr-server/src/handler.rs | 2 +- crates/metassr-utils/src/lib.rs | 5 +--- 17 files changed, 79 insertions(+), 50 deletions(-) create mode 100644 crates/metassr-fs-analyzer/Cargo.toml rename crates/{metassr-utils/src/analyzer => metassr-fs-analyzer/src}/dist_dir.rs (95%) rename crates/{metassr-utils/src/analyzer/mod.rs => metassr-fs-analyzer/src/lib.rs} (90%) rename crates/{metassr-utils/src/analyzer => metassr-fs-analyzer/src}/src_dir.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index 8cceaa3..f9c9205 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,9 +92,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "async-trait" @@ -582,6 +582,7 @@ dependencies = [ "metassr-build", "metassr-bundler", "metassr-create", + "metassr-fs-analyzer", "metassr-server", "metassr-utils", "nu-ansi-term 0.50.0", @@ -605,6 +606,7 @@ dependencies = [ "lazy_static", "metacall", "metassr-bundler", + "metassr-fs-analyzer", "metassr-utils", "serde", "serde_json", @@ -648,6 +650,16 @@ dependencies = [ "walkdir", ] +[[package]] +name = "metassr-fs-analyzer" +version = "0.0.1-alpha" +dependencies = [ + "anyhow", + "metassr-utils", + "serde", + "walkdir", +] + [[package]] name = "metassr-server" version = "0.0.1-alpha" @@ -656,6 +668,7 @@ dependencies = [ "axum", "chrono", "metassr-build", + "metassr-fs-analyzer", "metassr-utils", "serde_json", "tokio", @@ -936,18 +949,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.207" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.207" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 30c5232..82364ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" authors = ["Mohamed Emad (hulxxv@gmail.com)"] description = "Another SSR framework but built with MetaCall!" - [dependencies] anyhow = "1.0.82" chrono = "0.4.38" @@ -32,6 +31,7 @@ tower-layer = "0.3.3" tower-service = "0.3.3" metassr-create = { path = "crates/metassr-create" } metassr-bundler = { path = "crates/metassr-bundler" } +metassr-fs-analyzer = { path = "crates/metassr-fs-analyzer" } [workspace] members = [ @@ -41,7 +41,9 @@ members = [ "crates/metassr-utils", "crates/html-generator", "metassr-cli", - "crates/metassr-create", "crates/metassr-bundler", + "crates/metassr-create", + "crates/metassr-bundler", + "crates/metassr-fs-analyzer", ] [[bin]] diff --git a/crates/metassr-build/Cargo.toml b/crates/metassr-build/Cargo.toml index 34c7965..6adf3fc 100644 --- a/crates/metassr-build/Cargo.toml +++ b/crates/metassr-build/Cargo.toml @@ -14,3 +14,4 @@ html-generator = { path = "../html-generator" } lazy_static = "1.5.0" serde = { version = "1.0.207", features = ["derive"] } metassr-bundler = { path = "../metassr-bundler" } +metassr-fs-analyzer = { path = "../metassr-fs-analyzer" } diff --git a/crates/metassr-build/src/client/mod.rs b/crates/metassr-build/src/client/mod.rs index 0e1f5bb..de95904 100644 --- a/crates/metassr-build/src/client/mod.rs +++ b/crates/metassr-build/src/client/mod.rs @@ -4,13 +4,12 @@ use anyhow::{anyhow, Result}; use hydrator::Hydrator; use metassr_bundler::WebBundler; -use metassr_utils::{ - analyzer::{ - src_dir::{special_entries, SourceDir}, - DirectoryAnalyzer, - }, - cache_dir::CacheDir, +use metassr_fs_analyzer::{ + src_dir::{special_entries, SourceDir}, + DirectoryAnalyzer, }; +use metassr_utils::cache_dir::CacheDir; + use std::{ collections::HashMap, ffi::OsStr, diff --git a/crates/metassr-build/src/server/manifest.rs b/crates/metassr-build/src/server/manifest.rs index 53fcf38..b1585d7 100644 --- a/crates/metassr-build/src/server/manifest.rs +++ b/crates/metassr-build/src/server/manifest.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; -use metassr_utils::{ - analyzer::dist_dir::{DistDirContainer, PageEntry}, - cache_dir::CacheDir, -}; + +use metassr_fs_analyzer::dist_dir::{DistDirContainer, PageEntry}; +use metassr_utils::cache_dir::CacheDir; + use serde::{Deserialize, Serialize}; use serde_json::to_string_pretty; use std::{ diff --git a/crates/metassr-build/src/server/mod.rs b/crates/metassr-build/src/server/mod.rs index 45d7a65..77b4cf7 100644 --- a/crates/metassr-build/src/server/mod.rs +++ b/crates/metassr-build/src/server/mod.rs @@ -10,14 +10,13 @@ use crate::traits::Build; use manifest::ManifestGenerator; use metassr_bundler::WebBundler; -use metassr_utils::{ - analyzer::{ - dist_dir::DistDir, - src_dir::{special_entries, SourceDir}, - DirectoryAnalyzer, - }, - cache_dir::CacheDir, +use metassr_fs_analyzer::{ + dist_dir::DistDir, + src_dir::{special_entries, SourceDir}, + DirectoryAnalyzer, }; +use metassr_utils::cache_dir::CacheDir; + use pages_generator::PagesGenerator; use renderer::head::HeadRenderer; diff --git a/crates/metassr-build/src/server/pages_generator.rs b/crates/metassr-build/src/server/pages_generator.rs index a98e9b1..6deeefe 100644 --- a/crates/metassr-build/src/server/pages_generator.rs +++ b/crates/metassr-build/src/server/pages_generator.rs @@ -5,13 +5,11 @@ use std::{ }; use anyhow::{anyhow, Result}; -use metassr_utils::{ - analyzer::{ - dist_dir::{DistDir, DistDirContainer}, - DirectoryAnalyzer, - }, - cache_dir::CacheDir, +use metassr_fs_analyzer::{ + dist_dir::{DistDir, DistDirContainer}, + DirectoryAnalyzer, }; +use metassr_utils::cache_dir::CacheDir; use crate::traits::Exec; diff --git a/crates/metassr-build/src/server/renderer/html.rs b/crates/metassr-build/src/server/renderer/html.rs index dd16f68..b04d102 100644 --- a/crates/metassr-build/src/server/renderer/html.rs +++ b/crates/metassr-build/src/server/renderer/html.rs @@ -6,7 +6,7 @@ use html_generator::{ html_props::HtmlProps, template::HtmlTemplate, }; -use metassr_utils::analyzer::dist_dir::PageEntry; +use metassr_fs_analyzer::dist_dir::PageEntry; pub struct HtmlRenderer<'a> { head: String, diff --git a/crates/metassr-build/src/server/renderer/page.rs b/crates/metassr-build/src/server/renderer/page.rs index d2ba4b5..321f94c 100644 --- a/crates/metassr-build/src/server/renderer/page.rs +++ b/crates/metassr-build/src/server/renderer/page.rs @@ -1,7 +1,9 @@ use std::ffi::OsStr; use anyhow::Result; -use metassr_utils::{analyzer::dist_dir::PageEntry, cache_dir::CacheDir}; + +use metassr_fs_analyzer::dist_dir::PageEntry; +use metassr_utils::cache_dir::CacheDir; use crate::{ server::{manifest::Manifest, render_exec::RenderExec}, diff --git a/crates/metassr-build/src/server/targets.rs b/crates/metassr-build/src/server/targets.rs index 60eb020..014dd01 100644 --- a/crates/metassr-build/src/server/targets.rs +++ b/crates/metassr-build/src/server/targets.rs @@ -4,7 +4,9 @@ use std::{ }; use anyhow::Result; -use metassr_utils::{analyzer::src_dir::PagesEntriesType, cache_dir::CacheDir}; + +use metassr_fs_analyzer::src_dir::PagesEntriesType; +use metassr_utils::cache_dir::CacheDir; use crate::{traits::Generate, utils::setup_page_path}; diff --git a/crates/metassr-fs-analyzer/Cargo.toml b/crates/metassr-fs-analyzer/Cargo.toml new file mode 100644 index 0000000..8776fb3 --- /dev/null +++ b/crates/metassr-fs-analyzer/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "metassr-fs-analyzer" +description = "This module provides directory analyzers for MetaSSR web applications." +version = "0.0.1-alpha" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.89" +metassr-utils = { version = "0.0.1-alpha", path = "../metassr-utils" } +serde = "1.0.210" +walkdir = "2.5.0" diff --git a/crates/metassr-utils/src/analyzer/dist_dir.rs b/crates/metassr-fs-analyzer/src/dist_dir.rs similarity index 95% rename from crates/metassr-utils/src/analyzer/dist_dir.rs rename to crates/metassr-fs-analyzer/src/dist_dir.rs index 2ba869c..cfee74a 100644 --- a/crates/metassr-utils/src/analyzer/dist_dir.rs +++ b/crates/metassr-fs-analyzer/src/dist_dir.rs @@ -15,7 +15,7 @@ use walkdir::WalkDir; /// # Example /// /// ```no_run -/// use metassr_utils::analyzer::dist_dir::{DistDirContainer, PageEntry}; +/// use metassr_fs_analyzer::dist_dir::{DistDirContainer, PageEntry}; /// use std::{collections::HashMap, path::PathBuf}; /// /// let mut container = DistDirContainer { @@ -38,7 +38,7 @@ pub struct DistDirContainer { /// # Example /// /// ```no_run -/// use metassr_utils::analyzer::dist_dir::PageEntry; +/// use metassr_fs_analyzer::dist_dir::PageEntry; /// use std::path::PathBuf; /// /// let mut page_entry = PageEntry::new(PathBuf::from("/dist/pages/home")); @@ -61,7 +61,7 @@ impl PageEntry { /// # Example /// /// ```no_run - /// use metassr_utils::analyzer::dist_dir::PageEntry; + /// use metassr_fs_analyzer::dist_dir::PageEntry; /// use std::path::PathBuf; /// /// let page_entry = PageEntry::new(PathBuf::from("/dist/pages/home")); @@ -80,7 +80,7 @@ impl PageEntry { /// # Example /// /// ```no_run - /// use metassr_utils::analyzer::dist_dir::PageEntry; + /// use metassr_fs_analyzer::dist_dir::PageEntry; /// use std::path::PathBuf; /// /// let mut page_entry = PageEntry::new(PathBuf::from("/dist/pages/home")); @@ -96,7 +96,7 @@ impl PageEntry { /// # Example /// /// ```no_run - /// use metassr_utils::analyzer::dist_dir::PageEntry; + /// use metassr_fs_analyzer::dist_dir::PageEntry; /// use std::path::PathBuf; /// /// let mut page_entry = PageEntry::new(PathBuf::from("/dist/pages/home")); @@ -115,7 +115,7 @@ impl PageEntry { /// # Example /// /// ```no_run -/// use metassr_utils::analyzer::{dist_dir::DistDir, DirectoryAnalyzer}; +/// use metassr_fs_analyzer::{dist_dir::DistDir, DirectoryAnalyzer}; /// /// let dist_dir = DistDir::new("path/to/dist").unwrap(); /// let analysis_result = dist_dir.analyze().unwrap(); @@ -134,7 +134,7 @@ impl DistDir { /// # Example /// /// ```no_run - /// use metassr_utils::analyzer::dist_dir::DistDir; + /// use metassr_fs_analyzer::dist_dir::DistDir; /// /// let dist_dir = DistDir::new("path/to/dist"); /// match dist_dir { @@ -163,7 +163,7 @@ impl DistDir { /// # Example /// /// ```no_run -/// use metassr_utils::analyzer::{dist_dir::DistDir, DirectoryAnalyzer}; +/// use metassr_fs_analyzer::{dist_dir::DistDir, DirectoryAnalyzer}; /// /// let dist_dir = DistDir::new("/path/to/dist").unwrap(); /// let result = dist_dir.analyze().unwrap(); @@ -180,7 +180,7 @@ impl DirectoryAnalyzer for DistDir { /// # Example /// /// ```no_run - /// use metassr_utils::analyzer::{dist_dir::DistDir, DirectoryAnalyzer}; + /// use metassr_fs_analyzer::{dist_dir::DistDir, DirectoryAnalyzer}; /// /// let dist_dir = DistDir::new("path/to/dist").unwrap(); /// let analysis_result = dist_dir.analyze().unwrap(); @@ -246,7 +246,7 @@ impl DirectoryAnalyzer for DistDir { #[cfg(test)] mod tests { use super::*; - use crate::rand::Rand; + use metassr_utils::rand::Rand; use std::fs; /// Helper function to create a temporary directory structure for testing fn setup_test_dist_dir() -> PathBuf { diff --git a/crates/metassr-utils/src/analyzer/mod.rs b/crates/metassr-fs-analyzer/src/lib.rs similarity index 90% rename from crates/metassr-utils/src/analyzer/mod.rs rename to crates/metassr-fs-analyzer/src/lib.rs index c0fba6c..07003ae 100644 --- a/crates/metassr-utils/src/analyzer/mod.rs +++ b/crates/metassr-fs-analyzer/src/lib.rs @@ -1,3 +1,5 @@ +//! This module provides directory analyzers for extracting useful files from directories like `src/` and `dist/`. + use anyhow::Result; /// Analyzes the `dist/` directory for scripts and style files. The `dist/` directory diff --git a/crates/metassr-utils/src/analyzer/src_dir.rs b/crates/metassr-fs-analyzer/src/src_dir.rs similarity index 99% rename from crates/metassr-utils/src/analyzer/src_dir.rs rename to crates/metassr-fs-analyzer/src/src_dir.rs index c5e73fa..4f7ddb7 100644 --- a/crates/metassr-utils/src/analyzer/src_dir.rs +++ b/crates/metassr-fs-analyzer/src/src_dir.rs @@ -157,7 +157,7 @@ impl DirectoryAnalyzer for SourceDir { #[cfg(test)] mod tests { use super::*; - use crate::rand::Rand; + use metassr_utils::rand::Rand; use std::fs; use std::path::PathBuf; diff --git a/crates/metassr-server/Cargo.toml b/crates/metassr-server/Cargo.toml index 9497639..0d6384f 100644 --- a/crates/metassr-server/Cargo.toml +++ b/crates/metassr-server/Cargo.toml @@ -10,6 +10,7 @@ anyhow = "1.0.82" axum = "0.7.5" chrono = "0.4.38" metassr-build = { path = "../metassr-build" } +metassr-fs-analyzer = { path = "../metassr-fs-analyzer" } metassr-utils = { path = "../metassr-utils" } serde_json = "1.0.122" tokio = { version = "1.36.0", features = ["full"] } diff --git a/crates/metassr-server/src/handler.rs b/crates/metassr-server/src/handler.rs index 5ca2a71..46f8bf6 100644 --- a/crates/metassr-server/src/handler.rs +++ b/crates/metassr-server/src/handler.rs @@ -5,7 +5,7 @@ use axum::{ routing::get, }; use metassr_build::server::renderer::page::PageRenderer; -use metassr_utils::analyzer::{ +use metassr_fs_analyzer::{ dist_dir::{DistDir, PageEntry}, DirectoryAnalyzer, }; diff --git a/crates/metassr-utils/src/lib.rs b/crates/metassr-utils/src/lib.rs index de1661f..03228f7 100644 --- a/crates/metassr-utils/src/lib.rs +++ b/crates/metassr-utils/src/lib.rs @@ -1,10 +1,7 @@ #![doc = include_str!("../README.md")] -/// This module provides directory analyzers for extracting useful files from directories like `src/` and `dist/`. -pub mod analyzer; - /// This module provides utilities for managing cache directories, creating files, and handling their contents. -/// +/// /// This is useful for caching purposes where files are written and /// retrieved based on a pathname, making it easier to manage multiple /// cached files in a structured directory. From 648981a0b9028d3531c6b5ca6d3ef9221dfa8e71 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 20 Sep 2024 17:14:05 +0300 Subject: [PATCH 09/10] fix(utils): wrong pathname is registered in the cache --- crates/metassr-utils/src/cache_dir.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/metassr-utils/src/cache_dir.rs b/crates/metassr-utils/src/cache_dir.rs index fbdd9fc..38b0e7c 100644 --- a/crates/metassr-utils/src/cache_dir.rs +++ b/crates/metassr-utils/src/cache_dir.rs @@ -88,8 +88,10 @@ impl CacheDir { /// cache.insert("data.txt", "Some data".as_bytes()).unwrap(); /// ``` pub fn insert(&mut self, pathname: &str, buf: &[u8]) -> Result { - let pathname = format!("{}/{}", self.dir_path.to_str().unwrap(), pathname); - let path = Path::new(&pathname); + + // Set the path + let path = format!("{}/{}", self.dir_path.to_str().unwrap(), pathname); + let path = Path::new(&path); // Create file path if it doesn't exist if !path.exists() { @@ -112,7 +114,8 @@ impl CacheDir { // Add the new file path to the cache entries self.entries_in_scope - .insert(pathname.clone(), path.canonicalize()?); + .insert(pathname.to_string(), path.canonicalize()?); + Ok(path.to_path_buf()) } From b4ccf02219c258d69dad7b656bb6585ceff6966b Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 20 Sep 2024 17:48:47 +0300 Subject: [PATCH 10/10] refactor(utils): return `&Path` instead of `PathBuf` clone from `CacheDir.dir_path()` and rename it to `CacheDir.path()` --- crates/metassr-build/src/client/mod.rs | 2 +- crates/metassr-build/src/server/manifest.rs | 5 ++- .../src/server/pages_generator.rs | 2 +- .../metassr-build/src/server/renderer/head.rs | 4 +- crates/metassr-utils/src/cache_dir.rs | 42 +++++++++---------- 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/crates/metassr-build/src/client/mod.rs b/crates/metassr-build/src/client/mod.rs index de95904..482db39 100644 --- a/crates/metassr-build/src/client/mod.rs +++ b/crates/metassr-build/src/client/mod.rs @@ -37,7 +37,7 @@ impl ClientBuilder { return Err(anyhow!("src directory not found.")); } if !dist_path.exists() { - fs::create_dir(dist_path.clone())?; + fs::create_dir(&dist_path)?; } Ok(Self { src_path, diff --git a/crates/metassr-build/src/server/manifest.rs b/crates/metassr-build/src/server/manifest.rs index b1585d7..c8effd0 100644 --- a/crates/metassr-build/src/server/manifest.rs +++ b/crates/metassr-build/src/server/manifest.rs @@ -119,12 +119,13 @@ impl ManifestGenerator { } } pub fn generate + ?Sized>(&self, head: &H) -> Result { - let global = GlobalEntry::new(head, &self.cache.dir_path())?; + let cache_path = self.cache.path(); + let global = GlobalEntry::new(head, cache_path)?; let mut manifest = Manifest::new(global); for (path, &id) in self.targets.iter() { let route = match path - .strip_prefix(self.cache.dir_path().join("pages"))? + .strip_prefix(cache_path.join("pages"))? .parent() .unwrap() { diff --git a/crates/metassr-build/src/server/pages_generator.rs b/crates/metassr-build/src/server/pages_generator.rs index 6deeefe..f5a5ec4 100644 --- a/crates/metassr-build/src/server/pages_generator.rs +++ b/crates/metassr-build/src/server/pages_generator.rs @@ -34,7 +34,7 @@ impl PagesGenerator { ) -> Result { let dist = DistDir::new(dist_path)?.analyze()?; let head = HeadRenderer::new(&head_path, cache_dir.clone()).render(true)?; - let cache = cache_dir.dir_path(); + let cache = cache_dir.path().to_path_buf(); let output = MultiRenderExec::new(targets.ready_for_exec())?.exec()?; diff --git a/crates/metassr-build/src/server/renderer/head.rs b/crates/metassr-build/src/server/renderer/head.rs index dd6b5ea..63f5e9f 100644 --- a/crates/metassr-build/src/server/renderer/head.rs +++ b/crates/metassr-build/src/server/renderer/head.rs @@ -35,7 +35,7 @@ impl HeadRenderer { let _ = loaders::from_single_file( "node", - format!("{}/head.js", self.cache_dir.dir_path().display()), + format!("{}/head.js", self.cache_dir.path().display()), ); guard.make_true() } @@ -48,7 +48,7 @@ impl HeadRenderer { } fn bundle(&mut self) -> Result<()> { - if let Err(e) = WebBundler::new(&self.bundling_target()?, &self.cache_dir.dir_path()).exec() + if let Err(e) = WebBundler::new(&self.bundling_target()?, &self.cache_dir.path()).exec() { return Err(anyhow!("Cannot bundling head: {e}")); } diff --git a/crates/metassr-utils/src/cache_dir.rs b/crates/metassr-utils/src/cache_dir.rs index 38b0e7c..0159efa 100644 --- a/crates/metassr-utils/src/cache_dir.rs +++ b/crates/metassr-utils/src/cache_dir.rs @@ -28,7 +28,7 @@ use walkdir::WalkDir; #[derive(Debug, Clone)] pub struct CacheDir { - dir_path: PathBuf, + path: PathBuf, entries_in_scope: HashMap, } @@ -53,14 +53,14 @@ impl CacheDir { /// let cache = CacheDir::new(".cache").unwrap(); /// ``` pub fn new + ?Sized>(path: &S) -> Result { - let dir_path = PathBuf::from(path); + let path = PathBuf::from(path); - if !dir_path.exists() { - fs::create_dir(dir_path.clone())?; + if !path.exists() { + fs::create_dir(path.clone())?; } Ok(Self { - dir_path, + path, entries_in_scope: HashMap::new(), }) } @@ -83,14 +83,14 @@ impl CacheDir { /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; - /// + /// /// let mut cache = CacheDir::new(".cache").unwrap(); /// cache.insert("data.txt", "Some data".as_bytes()).unwrap(); /// ``` pub fn insert(&mut self, pathname: &str, buf: &[u8]) -> Result { // Set the path - let path = format!("{}/{}", self.dir_path.to_str().unwrap(), pathname); + let path = format!("{}/{}", self.path.to_str().unwrap(), pathname); let path = Path::new(&path); // Create file path if it doesn't exist @@ -125,12 +125,12 @@ impl CacheDir { /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; - /// + /// /// let cache = CacheDir::new(".cache").unwrap(); - /// println!("Cache directory: {:?}", cache.dir_path()); + /// println!("Cache directory: {:?}", cache.path()); /// ``` - pub fn dir_path(&self) -> PathBuf { - self.dir_path.clone() + pub fn path(&self) -> &Path { + self.path.as_path() } /// Returns the current entries in scope. @@ -139,7 +139,7 @@ impl CacheDir { /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; - /// + /// /// let cache = CacheDir::new(".cache").unwrap(); /// println!("Entries in scope: {:?}", cache.entries_in_scope()); /// ``` @@ -153,12 +153,12 @@ impl CacheDir { /// /// ```no_run /// use metassr_utils::cache_dir::CacheDir; - /// + /// /// let cache = CacheDir::new(".cache").unwrap(); /// println!("All entries: {:?}", cache.all_entries()); /// ``` pub fn all_entries(&self) -> Vec { - WalkDir::new(&self.dir_path) + WalkDir::new(&self.path) .into_iter() .filter_map(|e| { // Check if the entry is a file @@ -180,8 +180,8 @@ mod tests { /// Helper function to create a `CacheDir` with a random name fn create_temp_cache_dir() -> Result { - let dir_path = PathBuf::from(format!(".cache-{}", Rand::new().val())); - CacheDir::new(&dir_path) + let path = PathBuf::from(format!(".cache-{}", Rand::new().val())); + CacheDir::new(&path) } /// Test case to verify that a new cache directory can be created and deleted. @@ -194,7 +194,7 @@ mod tests { // Cleanup fs::remove_file(test_file_path).unwrap(); - fs::remove_dir_all(cache.dir_path()).unwrap(); + fs::remove_dir_all(cache.path()).unwrap(); } /// Test case to verify that a new file can be inserted into the cache. @@ -209,7 +209,7 @@ mod tests { // Cleanup // let file_path = result.unwrap(); fs::remove_file(file_path).unwrap(); - fs::remove_dir_all(cache.dir_path()).unwrap(); + fs::remove_dir_all(cache.path()).unwrap(); } /// Test case to check the scope of entries in the cache. @@ -225,7 +225,7 @@ mod tests { for path in entries.values() { fs::remove_file(path).unwrap(); } - fs::remove_dir_all(cache.dir_path()).unwrap(); + fs::remove_dir_all(cache.path()).unwrap(); } /// Test case to retrieve all entries in the cache. @@ -241,7 +241,7 @@ mod tests { for path in entries { fs::remove_file(path).unwrap(); } - fs::remove_dir_all(cache.dir_path()).unwrap(); + fs::remove_dir_all(cache.path()).unwrap(); } /// Test case to verify file replacement when content changes. @@ -261,6 +261,6 @@ mod tests { // Cleanup fs::remove_file(path).unwrap(); - fs::remove_dir_all(cache.dir_path()).unwrap(); + fs::remove_dir_all(cache.path()).unwrap(); } }