#[cfg(feature = "eval")]
pub mod eval;
pub mod cabal;
pub mod cabal_project;
pub mod cargo;
pub mod clojure;
pub mod common_lisp;
pub mod composer;
pub mod conan;
pub mod crystal;
pub mod dub;
pub mod dune;
pub mod elm;
pub mod erlang;
pub mod flake;
pub mod fortran_fpm;
pub mod gemfile;
pub mod gleam;
pub mod go_mod;
pub mod gradle;
pub mod gradle_libs;
pub mod julia;
pub mod maven;
pub mod mix_exs;
pub mod nimble;
pub mod npm;
pub mod nuget;
pub mod ocaml;
pub mod perl;
pub mod pip;
pub mod pipfile;
pub mod pubspec;
pub mod purescript;
pub mod pyproject;
pub mod r_description;
pub mod racket;
pub mod rockspec;
pub mod sbt;
pub mod setup_cfg;
pub mod setup_py;
pub mod sexpr;
pub mod stack;
pub mod swift_pm;
pub mod vcpkg;
pub mod vlang;
pub mod zig;
pub use go_mod::GoModule;
pub use npm::npm_entry_point;
use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum DepKind {
Normal,
Dev,
Build,
Optional,
}
#[derive(Debug, Clone, Serialize)]
pub struct DeclaredDep {
pub name: String,
pub version_req: Option<String>,
pub kind: DepKind,
}
#[derive(Debug, Clone, Serialize)]
pub struct ParsedManifest {
pub ecosystem: &'static str,
pub name: Option<String>,
pub version: Option<String>,
pub dependencies: Vec<DeclaredDep>,
}
#[derive(Debug)]
pub struct ManifestError(pub String);
impl std::fmt::Display for ManifestError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::error::Error for ManifestError {}
pub trait ManifestParser: Send + Sync {
fn filename(&self) -> &'static str;
fn parse(&self, content: &str) -> Result<ParsedManifest, ManifestError>;
}
pub fn parse_manifest(filename: &str, content: &str) -> Option<ParsedManifest> {
match filename {
"Cargo.toml" => cargo::CargoParser.parse(content).ok(),
"go.mod" => go_mod::GoModParser.parse(content).ok(),
"package.json" => npm::NpmParser.parse(content).ok(),
"requirements.txt" => pip::PipParser.parse(content).ok(),
"Pipfile" => pipfile::PipfileParser.parse(content).ok(),
"pyproject.toml" => pyproject::PyprojectParser.parse(content).ok(),
"setup.cfg" => setup_cfg::SetupCfgParser.parse(content).ok(),
"setup.py" => setup_py::SetupPyParser.parse(content).ok(),
"composer.json" => composer::ComposerParser.parse(content).ok(),
"pom.xml" => maven::MavenParser.parse(content).ok(),
"build.gradle" => gradle::GradleParser.parse(content).ok(),
"build.gradle.kts" => gradle::GradleKtsParser.parse(content).ok(),
"build.sbt" => sbt::SbtParser.parse(content).ok(),
"mix.exs" => mix_exs::MixExsParser.parse(content).ok(),
"Gemfile" => gemfile::GemfileParser.parse(content).ok(),
"pubspec.yaml" => pubspec::PubspecParser.parse(content).ok(),
"conanfile.txt" => conan::ConanTxtParser.parse(content).ok(),
"conanfile.py" => conan::ConanPyParser.parse(content).ok(),
"packages.config" => nuget::PackagesConfigParser.parse(content).ok(),
"Directory.Packages.props" => nuget::DirectoryPackagesPropsParser.parse(content).ok(),
"dub.json" => dub::DubJsonParser.parse(content).ok(),
"dub.sdl" => dub::DubSdlParser.parse(content).ok(),
"stack.yaml" => stack::StackParser.parse(content).ok(),
"flake.nix" => flake::FlakeParser.parse(content).ok(),
"Package.swift" => swift_pm::SwiftPmParser.parse(content).ok(),
"libs.versions.toml" => gradle_libs::GradleLibsParser.parse(content).ok(),
"vcpkg.json" => vcpkg::VcpkgParser.parse(content).ok(),
"elm.json" => elm::ElmParser.parse(content).ok(),
"gleam.toml" => gleam::GleamParser.parse(content).ok(),
"Project.toml" => julia::JuliaParser.parse(content).ok(),
"fpm.toml" => fortran_fpm::FortranFpmParser.parse(content).ok(),
"project.clj" => clojure::LeinParser.parse(content).ok(),
"deps.edn" => clojure::EclojureParser.parse(content).ok(),
"shard.yml" => crystal::CrystalShardsParser.parse(content).ok(),
"DESCRIPTION" => r_description::RDescriptionParser.parse(content).ok(),
"rebar.config" => erlang::RebarConfigParser.parse(content).ok(),
"cpanfile" => perl::CpanfileParser.parse(content).ok(),
"dune-project" => dune::DuneParser.parse(content).ok(),
"build.zig.zon" => zig::ZigZonParser.parse(content).ok(),
"spago.yaml" => purescript::SpagoParser.parse(content).ok(),
"info.rkt" => racket::RacketInfoParser.parse(content).ok(),
"v.mod" => vlang::VModParser.parse(content).ok(),
"cabal.project" => cabal_project::CabalProjectParser.parse(content).ok(),
_ => parse_manifest_by_extension_impl(filename, content),
}
}
pub fn parse_manifest_by_extension(filename: &str, content: &str) -> Option<ParsedManifest> {
parse_manifest_by_extension_impl(filename, content)
}
fn parse_manifest_by_extension_impl(filename: &str, content: &str) -> Option<ParsedManifest> {
let ext = filename.rsplit('.').next().unwrap_or(filename);
match ext {
"nimble" => nimble::NimbleParser.parse(content).ok(),
"cabal" => cabal::CabalParser.parse(content).ok(),
"csproj" | "vbproj" | "fsproj" => nuget::CsprojParser.parse(content).ok(),
"rockspec" => rockspec::RockspecParser.parse(content).ok(),
"opam" => ocaml::OpamParser.parse(content).ok(),
"asd" => common_lisp::AsdParser.parse(content).ok(),
_ => None,
}
}
#[cfg(feature = "eval")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EvalPolicy {
IfAvailable,
Required,
}
#[cfg(feature = "eval")]
pub fn parse_manifest_eval(
filename: &str,
content: &str,
root: &std::path::Path,
policy: EvalPolicy,
) -> Option<ParsedManifest> {
match eval::try_eval(filename, root) {
Some(m) => Some(m),
None if policy == EvalPolicy::IfAvailable => parse_manifest(filename, content),
None => None,
}
}
pub fn go_module(content: &str) -> Option<GoModule> {
go_mod::parse_go_module(content)
}