use crate::{ErrorKind, Result};
use cached::proc_macro::cached;
use path_clean::PathClean;
use std::env;
use std::path::{Path, PathBuf};
use std::sync::LazyLock;
static CURRENT_DIR: LazyLock<PathBuf> =
LazyLock::new(|| env::current_dir().expect("cannot get current dir from environment"));
#[cached]
pub(crate) fn absolute_path(path: PathBuf) -> PathBuf {
let absolute = if path.is_absolute() {
path
} else {
CURRENT_DIR.join(path)
};
absolute.clean()
}
pub(crate) fn resolve(
src: &Path,
dst: &PathBuf,
ignore_absolute_local_links: bool,
) -> Result<Option<PathBuf>> {
let resolved = match dst {
relative if dst.is_relative() => {
let Some(parent) = src.parent() else {
return Err(ErrorKind::InvalidFile(relative.clone()));
};
parent.join(relative)
}
absolute if dst.is_absolute() => {
if ignore_absolute_local_links {
return Ok(None);
}
PathBuf::from(absolute)
}
_ => return Err(ErrorKind::InvalidFile(dst.clone())),
};
Ok(Some(absolute_path(resolved)))
}
#[cfg(test)]
mod test_path {
use super::*;
use crate::Result;
#[test]
fn test_resolve_relative() -> Result<()> {
let dummy = PathBuf::from("index.html");
let abs_path = PathBuf::from("./foo.html");
assert_eq!(
resolve(&dummy, &abs_path, true)?,
Some(env::current_dir().unwrap().join("foo.html"))
);
Ok(())
}
#[test]
fn test_resolve_relative_index() -> Result<()> {
let dummy = PathBuf::from("./index.html");
let abs_path = PathBuf::from("./foo.html");
assert_eq!(
resolve(&dummy, &abs_path, true)?,
Some(env::current_dir().unwrap().join("foo.html"))
);
Ok(())
}
#[test]
fn test_resolve_from_absolute() -> Result<()> {
let abs_index = PathBuf::from("/path/to/index.html");
let abs_path = PathBuf::from("./foo.html");
assert_eq!(
resolve(&abs_index, &abs_path, true)?,
Some(PathBuf::from("/path/to/foo.html"))
);
Ok(())
}
}