use anyhow::{Context, Result};
use serde::Deserialize;
use std::env;
use std::fs::{create_dir_all, File};
use std::io::Write;
use std::path::{Path, PathBuf};
pub fn write_file(file_path: &Path, content: String) -> Result<()> {
let dir_path = file_path
.parent()
.context("Failed to get parent directory")?;
create_dir_all(&dir_path)?;
let mut file = File::create(&file_path)
.with_context(|| format!("Failed to create file: {:?}", file_path))?;
file.write_all(content.as_bytes())?;
Ok(())
}
pub fn get_workspace_dir() -> Result<PathBuf> {
#[derive(Deserialize)]
struct Manifest {
workspace_root: String,
}
let package_dir = env::var("CARGO_MANIFEST_DIR").context("CARGO_MANIFEST_DIR")?;
let output = std::process::Command::new(env!("CARGO"))
.arg("metadata")
.arg("--format-version=1")
.current_dir(&package_dir)
.output()?;
let manifest: Manifest = serde_json::from_slice(&output.stdout)?;
Ok(PathBuf::from(manifest.workspace_root))
}
pub fn resolve_module_file_path(
source_path: &str,
css_module_path: &str,
is_windows_host: bool,
) -> String {
let source_path_normalized = if is_windows_host {
source_path.replace('\\', "/")
} else {
source_path.to_owned()
};
join_paths(&source_path_normalized, css_module_path)
}
fn join_paths(lhs: &str, rhs: &str) -> String {
let mut lhs = lhs.trim_end_matches(|c| c != '/');
let mut rhs = rhs;
while rhs.starts_with("../") {
lhs = lhs.trim_end_matches(|c| c != '/');
lhs = lhs.strip_suffix('/').unwrap_or("");
lhs = lhs.trim_end_matches(|c| c != '/');
rhs = rhs.strip_prefix("../").unwrap_or("");
}
lhs.to_owned() + rhs
}
#[cfg(test)]
mod join_paths {
use super::*;
#[test]
fn basic() {
assert_eq!(join_paths("a/b/c", "d"), "a/b/d");
assert_eq!(join_paths("a/b/", "d"), "a/b/d");
assert_eq!(join_paths("a/b/", "c/d"), "a/b/c/d");
}
#[test]
fn two_dot_normalization() {
assert_eq!(join_paths("a/b/", "../d"), "a/d");
assert_eq!(join_paths("a/b/c", "../d"), "a/d");
assert_eq!(join_paths("a/b/c", "../../d"), "d");
assert_eq!(join_paths("a/b/c", "../../../d"), "d");
}
#[test]
fn exceptions() {
assert_eq!(join_paths("a/./b/c", "./d"), "a/./b/./d");
assert_eq!(join_paths("a/../b/", "c/../d"), "a/../b/c/../d");
assert_eq!(join_paths("a\\b\\c", "d"), "d");
assert_eq!(join_paths("a/b/c", "..\\d"), "a/b/..\\d");
}
}