callisto-graph 0.3.1

Dependency graph, cascade, aggregation, and config resolution for callisto.
Documentation
use std::fs;
use std::path::{Path, PathBuf};

use crate::locate::LocateError;

pub fn find_workspace_root(start: &Path) -> Result<PathBuf, LocateError> {
    let canonical = start.canonicalize().unwrap_or_else(|_| start.to_path_buf());
    let mut current: &Path = &canonical;

    loop {
        if is_workspace_root(current) {
            return Ok(current.to_path_buf());
        }
        match current.parent() {
            Some(parent) => current = parent,
            None => {
                return Err(LocateError::WorkspaceRootNotFound {
                    start: start.to_path_buf(),
                });
            }
        }
    }
}

fn is_workspace_root(dir: &Path) -> bool {
    let cargo_toml = dir.join("Cargo.toml");
    if cargo_toml.exists() {
        if let Ok(content) = fs::read_to_string(&cargo_toml) {
            if content.contains("[workspace]") {
                return true;
            }
        }
    }

    let pkg_json = dir.join("package.json");
    if pkg_json.exists() {
        if let Ok(content) = fs::read_to_string(&pkg_json) {
            if let Ok(val) = serde_json::from_str::<serde_json::Value>(&content) {
                if val.get("workspaces").is_some() {
                    return true;
                }
            }
        }
    }

    if dir.join("pnpm-workspace.yaml").exists() {
        return true;
    }

    if dir.join(".moon").is_dir() {
        return true;
    }

    false
}