1#[cfg(feature = "eval")]
18pub mod eval;
19
20pub mod cabal;
21pub mod cabal_project;
22pub mod cargo;
23pub mod clojure;
24pub mod common_lisp;
25pub mod composer;
26pub mod conan;
27pub mod crystal;
28pub mod dub;
29pub mod dune;
30pub mod elm;
31pub mod erlang;
32pub mod flake;
33pub mod fortran_fpm;
34pub mod gemfile;
35pub mod gleam;
36pub mod go_mod;
37pub mod gradle;
38pub mod gradle_libs;
39pub mod julia;
40pub mod maven;
41pub mod mix_exs;
42pub mod nimble;
43pub mod npm;
44pub mod nuget;
45pub mod ocaml;
46pub mod perl;
47pub mod pip;
48pub mod pipfile;
49pub mod pubspec;
50pub mod purescript;
51pub mod pyproject;
52pub mod r_description;
53pub mod racket;
54pub mod rockspec;
55pub mod sbt;
56pub mod setup_cfg;
57pub mod setup_py;
58pub mod sexpr;
59pub mod stack;
60pub mod swift_pm;
61pub mod vcpkg;
62pub mod vlang;
63pub mod zig;
64
65pub use go_mod::GoModule;
66pub use npm::npm_entry_point;
67
68use serde::Serialize;
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
76#[serde(rename_all = "lowercase")]
77pub enum DepKind {
78 Normal,
79 Dev,
80 Build,
81 Optional,
82}
83
84#[derive(Debug, Clone, Serialize)]
86pub struct DeclaredDep {
87 pub name: String,
88 pub version_req: Option<String>,
90 pub kind: DepKind,
91}
92
93#[derive(Debug, Clone, Serialize)]
95pub struct ParsedManifest {
96 pub ecosystem: &'static str,
101 pub name: Option<String>,
102 pub version: Option<String>,
103 pub dependencies: Vec<DeclaredDep>,
104}
105
106#[derive(Debug)]
112pub struct ManifestError(pub String);
113
114impl std::fmt::Display for ManifestError {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 write!(f, "{}", self.0)
117 }
118}
119
120impl std::error::Error for ManifestError {}
121
122pub trait ManifestParser: Send + Sync {
124 fn filename(&self) -> &'static str;
127
128 fn parse(&self, content: &str) -> Result<ParsedManifest, ManifestError>;
130}
131
132pub fn parse_manifest(filename: &str, content: &str) -> Option<ParsedManifest> {
141 match filename {
142 "Cargo.toml" => cargo::CargoParser.parse(content).ok(),
144 "go.mod" => go_mod::GoModParser.parse(content).ok(),
146 "package.json" => npm::NpmParser.parse(content).ok(),
148 "requirements.txt" => pip::PipParser.parse(content).ok(),
150 "Pipfile" => pipfile::PipfileParser.parse(content).ok(),
151 "pyproject.toml" => pyproject::PyprojectParser.parse(content).ok(),
152 "setup.cfg" => setup_cfg::SetupCfgParser.parse(content).ok(),
153 "setup.py" => setup_py::SetupPyParser.parse(content).ok(),
154 "composer.json" => composer::ComposerParser.parse(content).ok(),
156 "pom.xml" => maven::MavenParser.parse(content).ok(),
158 "build.gradle" => gradle::GradleParser.parse(content).ok(),
159 "build.gradle.kts" => gradle::GradleKtsParser.parse(content).ok(),
160 "build.sbt" => sbt::SbtParser.parse(content).ok(),
161 "mix.exs" => mix_exs::MixExsParser.parse(content).ok(),
163 "Gemfile" => gemfile::GemfileParser.parse(content).ok(),
165 "pubspec.yaml" => pubspec::PubspecParser.parse(content).ok(),
167 "conanfile.txt" => conan::ConanTxtParser.parse(content).ok(),
169 "conanfile.py" => conan::ConanPyParser.parse(content).ok(),
170 "packages.config" => nuget::PackagesConfigParser.parse(content).ok(),
172 "Directory.Packages.props" => nuget::DirectoryPackagesPropsParser.parse(content).ok(),
173 "dub.json" => dub::DubJsonParser.parse(content).ok(),
175 "dub.sdl" => dub::DubSdlParser.parse(content).ok(),
176 "stack.yaml" => stack::StackParser.parse(content).ok(),
178 "flake.nix" => flake::FlakeParser.parse(content).ok(),
180 "Package.swift" => swift_pm::SwiftPmParser.parse(content).ok(),
182 "libs.versions.toml" => gradle_libs::GradleLibsParser.parse(content).ok(),
184 "vcpkg.json" => vcpkg::VcpkgParser.parse(content).ok(),
186 "elm.json" => elm::ElmParser.parse(content).ok(),
188 "gleam.toml" => gleam::GleamParser.parse(content).ok(),
190 "Project.toml" => julia::JuliaParser.parse(content).ok(),
192 "fpm.toml" => fortran_fpm::FortranFpmParser.parse(content).ok(),
194 "project.clj" => clojure::LeinParser.parse(content).ok(),
196 "deps.edn" => clojure::EclojureParser.parse(content).ok(),
197 "shard.yml" => crystal::CrystalShardsParser.parse(content).ok(),
199 "DESCRIPTION" => r_description::RDescriptionParser.parse(content).ok(),
201 "rebar.config" => erlang::RebarConfigParser.parse(content).ok(),
203 "cpanfile" => perl::CpanfileParser.parse(content).ok(),
205 "dune-project" => dune::DuneParser.parse(content).ok(),
207 "build.zig.zon" => zig::ZigZonParser.parse(content).ok(),
209 "spago.yaml" => purescript::SpagoParser.parse(content).ok(),
211 "info.rkt" => racket::RacketInfoParser.parse(content).ok(),
213 "v.mod" => vlang::VModParser.parse(content).ok(),
215 "cabal.project" => cabal_project::CabalProjectParser.parse(content).ok(),
217 _ => parse_manifest_by_extension_impl(filename, content),
219 }
220}
221
222pub fn parse_manifest_by_extension(filename: &str, content: &str) -> Option<ParsedManifest> {
229 parse_manifest_by_extension_impl(filename, content)
230}
231
232fn parse_manifest_by_extension_impl(filename: &str, content: &str) -> Option<ParsedManifest> {
233 let ext = filename.rsplit('.').next().unwrap_or(filename);
234
235 match ext {
236 "nimble" => nimble::NimbleParser.parse(content).ok(),
237 "cabal" => cabal::CabalParser.parse(content).ok(),
238 "csproj" | "vbproj" | "fsproj" => nuget::CsprojParser.parse(content).ok(),
239 "rockspec" => rockspec::RockspecParser.parse(content).ok(),
240 "opam" => ocaml::OpamParser.parse(content).ok(),
241 "asd" => common_lisp::AsdParser.parse(content).ok(),
242 _ => None,
243 }
244}
245
246#[cfg(feature = "eval")]
252#[derive(Debug, Clone, Copy, PartialEq, Eq)]
253pub enum EvalPolicy {
254 IfAvailable,
257 Required,
259}
260
261#[cfg(feature = "eval")]
279pub fn parse_manifest_eval(
280 filename: &str,
281 content: &str,
282 root: &std::path::Path,
283 policy: EvalPolicy,
284) -> Option<ParsedManifest> {
285 match eval::try_eval(filename, root) {
286 Some(m) => Some(m),
287 None if policy == EvalPolicy::IfAvailable => parse_manifest(filename, content),
288 None => None,
289 }
290}
291
292pub fn go_module(content: &str) -> Option<GoModule> {
296 go_mod::parse_go_module(content)
297}