mod cargo;
mod discover;
mod gomod;
mod mix;
mod npm;
mod pyproject;
mod radius;
use std::path::{Path, PathBuf};
pub use discover::{files_on_disk, is_manifest, is_skipped};
pub fn cargo_package(manifest: &str) -> Option<String> {
cargo::read(manifest).name
}
pub fn python_roots(manifest: &Path, text: &str) -> Vec<PathBuf> {
let dir = manifest.parent().unwrap_or(Path::new(""));
pyproject::import_roots(text)
.iter()
.filter_map(|root| discover::normalize(&dir.join(root)))
.collect()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Ecosystem {
Cargo,
Npm,
Mix,
Go,
Python,
}
impl Ecosystem {
fn key(self, name: &str) -> String {
if self != Ecosystem::Python {
return name.to_string();
}
name.split(['-', '_', '.'])
.filter(|part| !part.is_empty())
.map(str::to_lowercase)
.collect::<Vec<_>>()
.join("-")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Scope {
Runtime,
Build,
Optional,
Dev,
}
impl Scope {
pub fn label(self) -> &'static str {
match self {
Scope::Runtime => "",
Scope::Build => "build",
Scope::Optional => "optional",
Scope::Dev => "dev",
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum DepTarget {
Path(PathBuf),
Name(String),
Workspace(String),
}
#[derive(Debug, Clone, PartialEq)]
pub struct RawDep {
pub target: DepTarget,
pub scope: Scope,
}
#[derive(Debug, Default, PartialEq)]
pub struct Manifest {
pub name: Option<String>,
pub deps: Vec<RawDep>,
pub workspace_paths: Vec<(String, PathBuf)>,
pub is_workspace_root: bool,
pub unread: usize,
}
type Reader = fn(&str) -> Manifest;
fn pnpm_workspace(_source: &str) -> Manifest {
Manifest {
is_workspace_root: true,
..Manifest::default()
}
}
fn reader(file_name: &str) -> Option<(Ecosystem, Reader)> {
match file_name {
"Cargo.toml" => Some((Ecosystem::Cargo, cargo::read)),
"package.json" => Some((Ecosystem::Npm, npm::read)),
"pnpm-workspace.yaml" => Some((Ecosystem::Npm, pnpm_workspace)),
"mix.exs" => Some((Ecosystem::Mix, mix::read)),
"go.mod" => Some((Ecosystem::Go, gomod::read)),
"go.work" => Some((Ecosystem::Go, gomod::read_work)),
"pyproject.toml" => Some((Ecosystem::Python, pyproject::read)),
_ => None,
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Project {
pub root: PathBuf,
pub name: String,
}
impl Project {
pub fn display_root(&self) -> String {
if self.root.as_os_str().is_empty() {
".".to_string()
} else {
self.root.display().to_string()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Edge {
pub from: usize,
pub to: usize,
pub scope: Scope,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Reach {
pub project: usize,
pub origin: usize,
pub distance: usize,
pub via: usize,
pub scope: Scope,
}
#[derive(Debug, Default)]
pub struct ProjectGraph {
pub projects: Vec<Project>,
pub edges: Vec<Edge>,
pub workspaces: Vec<PathBuf>,
pub unread: Vec<(PathBuf, usize)>,
}
#[cfg(test)]
#[path = "mod_test.rs"]
mod tests;