use miette::{IntoDiagnostic, miette};
use std::path::{Path, PathBuf};
use std::sync::RwLock;
static CWD: RwLock<Option<PathBuf>> = RwLock::new(None);
pub fn cwd() -> miette::Result<PathBuf> {
if let Some(p) = CWD.read().expect("cwd lock poisoned").as_ref() {
return Ok(p.clone());
}
let mut cwd = CWD.write().expect("cwd lock poisoned");
if let Some(p) = cwd.as_ref() {
return Ok(p.clone());
}
let p = std::env::current_dir().into_diagnostic()?;
Ok(cwd.insert(p).clone())
}
pub fn find_project_root(start: &Path) -> Option<PathBuf> {
let stop = home_stop_boundary();
for dir in start.ancestors() {
if dir.join("package.json").is_file() {
return Some(dir.to_path_buf());
}
if stop.as_deref() == Some(dir) {
return None;
}
}
None
}
fn home_stop_boundary() -> Option<PathBuf> {
aube_util::env::home_dir()
}
pub fn find_workspace_root(start: &Path) -> Option<PathBuf> {
let stop = home_stop_boundary();
for dir in start.ancestors() {
if aube_manifest::workspace::workspace_yaml_existing(dir).is_some() {
return Some(dir.to_path_buf());
}
let pkg = dir.join("package.json");
if pkg.is_file()
&& let Ok(manifest) = aube_manifest::PackageJson::from_path(&pkg)
&& manifest.workspaces.is_some()
{
return Some(dir.to_path_buf());
}
if stop.as_deref() == Some(dir) {
return None;
}
}
None
}
pub fn find_workspace_yaml_root(start: &Path) -> Option<PathBuf> {
let stop = home_stop_boundary();
for dir in start.ancestors() {
if aube_manifest::workspace::workspace_yaml_existing(dir).is_some() {
return Some(dir.to_path_buf());
}
if stop.as_deref() == Some(dir) {
return None;
}
}
None
}
pub fn project_root() -> miette::Result<PathBuf> {
let initial_cwd = cwd()?;
find_project_root(&initial_cwd).ok_or_else(|| {
miette!(
"no package.json found in {} or any parent directory",
initial_cwd.display()
)
})
}
pub fn project_root_or_cwd() -> miette::Result<PathBuf> {
let initial_cwd = cwd()?;
Ok(find_project_root(&initial_cwd).unwrap_or(initial_cwd))
}
pub fn set_cwd(path: &Path) -> miette::Result<()> {
let path = if path.is_absolute() {
path.to_path_buf()
} else {
std::env::current_dir().into_diagnostic()?.join(path)
};
*CWD.write().expect("cwd lock poisoned") = Some(path);
Ok(())
}
pub fn canonicalize(path: &Path) -> std::io::Result<PathBuf> {
let canon = std::fs::canonicalize(path)?;
Ok(aube_util::path::strip_verbatim_prefix(&canon))
}
#[cfg(test)]
mod tests {
use super::*;
fn write(path: &Path, content: &str) {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).unwrap();
}
std::fs::write(path, content).unwrap();
}
#[test]
fn find_workspace_root_finds_pnpm_workspace_yaml() {
let dir = tempfile::tempdir().unwrap();
write(
&dir.path().join("pnpm-workspace.yaml"),
"packages:\n - 'packages/*'\n",
);
write(&dir.path().join("packages/a/package.json"), "{}");
let child = dir.path().join("packages/a");
assert_eq!(find_workspace_root(&child).unwrap(), dir.path());
}
#[test]
fn find_workspace_root_finds_package_json_workspaces_array() {
let dir = tempfile::tempdir().unwrap();
write(
&dir.path().join("package.json"),
r#"{"name":"root","workspaces":["packages/*"]}"#,
);
write(
&dir.path().join("packages/a/package.json"),
r#"{"name":"a"}"#,
);
let child = dir.path().join("packages/a");
assert_eq!(find_workspace_root(&child).unwrap(), dir.path());
}
#[test]
fn find_workspace_root_finds_package_json_workspaces_object() {
let dir = tempfile::tempdir().unwrap();
write(
&dir.path().join("package.json"),
r#"{"name":"root","workspaces":{"packages":["apps/*"]}}"#,
);
write(&dir.path().join("apps/a/package.json"), r#"{"name":"a"}"#);
let child = dir.path().join("apps/a");
assert_eq!(find_workspace_root(&child).unwrap(), dir.path());
}
#[test]
fn find_workspace_root_ignores_package_json_without_workspaces() {
let dir = tempfile::tempdir().unwrap();
write(
&dir.path().join("package.json"),
r#"{"name":"root","workspaces":["packages/*"]}"#,
);
write(
&dir.path().join("packages/a/package.json"),
r#"{"name":"a"}"#,
);
let child = dir.path().join("packages/a");
let root = find_workspace_root(&child).unwrap();
assert_eq!(root, dir.path());
assert_ne!(root, child);
}
#[test]
fn find_workspace_yaml_root_ignores_package_json_workspaces() {
let dir = tempfile::tempdir().unwrap();
write(
&dir.path().join("package.json"),
r#"{"name":"root","workspaces":["packages/*"]}"#,
);
write(
&dir.path().join("packages/a/package.json"),
r#"{"name":"a"}"#,
);
let child = dir.path().join("packages/a");
assert!(find_workspace_yaml_root(&child).is_none());
}
#[test]
fn find_workspace_root_returns_none_without_markers() {
let dir = tempfile::tempdir().unwrap();
write(&dir.path().join("package.json"), r#"{"name":"solo"}"#);
assert!(find_workspace_root(dir.path()).is_none());
}
#[test]
fn canonicalize_round_trips_an_existing_path() {
let dir = tempfile::tempdir().unwrap();
let canon = canonicalize(dir.path()).unwrap();
assert!(canon.is_absolute());
assert!(canon.exists());
}
#[cfg(windows)]
#[test]
fn canonicalize_strips_verbatim_drive_prefix() {
let dir = tempfile::tempdir().unwrap();
let canon = canonicalize(dir.path()).unwrap();
let s = canon.to_string_lossy();
assert!(
!s.starts_with(r"\\?\"),
"expected non-verbatim path, got {s}"
);
assert!(
s.chars().nth(1) == Some(':'),
"expected drive form, got {s}"
);
}
}