use crate::utils::path_url::path_to_file_url;
use cow_utils::CowUtils;
use std::path::{Path, PathBuf};
pub struct DistPathResolver {
project_root: PathBuf,
dist_dir: PathBuf,
server_dir: String,
}
impl DistPathResolver {
pub fn new(project_root: PathBuf) -> Self {
let dist_dir = project_root.join("dist");
Self { project_root, dist_dir, server_dir: "server".to_string() }
}
pub fn get_dist_path(&self, component_id: &str) -> PathBuf {
let filename = format!("{}.js", component_id);
self.dist_dir.join(&self.server_dir).join(filename)
}
pub fn get_dist_url(&self, component_id: &str) -> String {
let path = self.get_dist_path(component_id);
path_to_file_url(&path)
}
pub fn file_path_to_component_id(&self, file_path: &Path) -> String {
let relative_path = if file_path.is_absolute() {
file_path.strip_prefix(&self.project_root).unwrap_or(file_path).to_path_buf()
} else {
file_path.to_path_buf()
};
let path_str = relative_path.to_string_lossy();
path_str
.cow_replace('\\', "/")
.trim_end_matches(".tsx")
.trim_end_matches(".ts")
.trim_end_matches(".jsx")
.trim_end_matches(".js")
.cow_replace(|c: char| !c.is_alphanumeric() && c != '/' && c != '-', "_")
.trim_start_matches("src/")
.to_string()
}
pub fn dist_file_exists(&self, component_id: &str) -> bool {
let path = self.get_dist_path(component_id);
path.exists()
}
pub fn get_dist_file_mtime(&self, component_id: &str) -> Option<std::time::SystemTime> {
let path = self.get_dist_path(component_id);
std::fs::metadata(&path).ok().and_then(|metadata| metadata.modified().ok())
}
pub fn is_dist_newer_than_source(&self, component_id: &str, source_path: &Path) -> bool {
let dist_mtime = match self.get_dist_file_mtime(component_id) {
Some(time) => time,
None => {
return false;
}
};
let source_mtime =
match std::fs::metadata(source_path).ok().and_then(|metadata| metadata.modified().ok())
{
Some(time) => time,
None => {
return false;
}
};
dist_mtime > source_mtime
}
pub fn project_root(&self) -> &Path {
&self.project_root
}
pub fn dist_dir(&self) -> &Path {
&self.dist_dir
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_get_dist_path() {
let resolver = DistPathResolver::new(PathBuf::from("/project"));
let path = resolver.get_dist_path("pages/home");
assert_eq!(path, PathBuf::from("/project/dist/server/pages/home.js"));
}
#[test]
fn test_get_dist_url() {
let resolver = DistPathResolver::new(PathBuf::from("/project"));
let url = resolver.get_dist_url("components/Button");
assert!(url.starts_with("file://"));
assert!(url.contains("dist/server/components/Button.js"));
}
#[test]
fn test_file_path_to_component_id() {
let resolver = DistPathResolver::new(PathBuf::from("/project"));
let id = resolver.file_path_to_component_id(Path::new("src/pages/home.tsx"));
assert_eq!(id, "pages/home");
let id = resolver.file_path_to_component_id(Path::new("components/Button.tsx"));
assert_eq!(id, "components/Button");
let id = resolver.file_path_to_component_id(Path::new("src/pages/[slug].tsx"));
assert_eq!(id, "pages/_slug_");
}
#[test]
fn test_file_path_to_component_id_absolute() {
let resolver = DistPathResolver::new(PathBuf::from("/project"));
let id = resolver.file_path_to_component_id(Path::new("/project/src/pages/about.tsx"));
assert_eq!(id, "pages/about");
}
}