project-detect 0.1.0

Zero-config project type detection — identify any project's language, build system, and toolchain from directory contents
Documentation

Point it at a directory and it tells you what kind of project lives there. No config files, no setup — just file detection.

use project_detect::{detect, ProjectKind};

if let Some(kind) = detect(".") {
    println!("{} project ({})", kind.label(), kind.detected_file());
    // "Rust project (Cargo.toml)"
}

Features

  • 29 ecosystems detected out of the box
  • Priority-ordered — language-specific files win over generic build systems
  • Ecosystem metadata — Node.js package manager, Flutter vs Dart, Stack vs Cabal, etc.
  • Directory walkingdetect_walk searches up the directory tree for monorepo support
  • Artifact directories — know what to clean for every ecosystem
  • Zero dependencies beyond serde_json (for package.json parsing)

Supported Ecosystems

Priority File Ecosystem Label
1 Cargo.toml Rust "Rust"
2 go.mod Go "Go"
3 mix.exs Elixir "Elixir"
4 pyproject.toml / setup.py Python "Python"
5 package.json Node.js "Node.js"
6 build.gradle Gradle (Java/Kotlin) "Gradle"
7 pom.xml Maven (Java) "Maven"
8 build.sbt Scala "Scala"
9 Gemfile Ruby "Ruby"
10 Package.swift Swift "Swift"
11 build.zig Zig "Zig"
12 *.csproj / *.sln .NET ".NET"
13 composer.json PHP "PHP"
14 pubspec.yaml Dart / Flutter "Dart" / "Flutter"
15 stack.yaml / *.cabal Haskell "Haskell"
16 project.clj / deps.edn Clojure "Clojure"
17 rebar.config Erlang "Erlang"
18 dune-project OCaml "OCaml"
19 cpanfile / Makefile.PL Perl "Perl"
20 Project.toml Julia "Julia"
21 *.nimble Nim "Nim"
22 shard.yml Crystal "Crystal"
23 v.mod V "V"
24 gleam.toml Gleam "Gleam"
25 *.rockspec Lua "Lua"
26 MODULE.bazel / WORKSPACE Bazel "Bazel"
27 meson.build Meson "Meson"
28 CMakeLists.txt CMake "CMake"
29 Makefile Make "Make"

Usage

Basic detection

use project_detect::{detect, ProjectKind};

let kind = detect("/path/to/project").unwrap();
println!("{}", kind.label());           // "Rust"
println!("{}", kind.detected_file());   // "Cargo.toml"

Walk up the directory tree

use project_detect::detect_walk;

// Running from src/lib/ inside a Cargo workspace?
// detect_walk finds the Cargo.toml in the parent.
if let Some((kind, project_dir)) = detect_walk(".") {
    println!("Found {} at {}", kind.label(), project_dir.display());
}

Ecosystem metadata

use project_detect::{detect, ProjectKind, NodePM};

match detect(".") {
    Some(ProjectKind::Node { manager: NodePM::Pnpm }) => println!("pnpm project"),
    Some(ProjectKind::Dart { flutter: true }) => println!("Flutter app"),
    Some(ProjectKind::Haskell { stack: true }) => println!("Stack project"),
    Some(ProjectKind::Haskell { stack: false }) => println!("Cabal project"),
    Some(kind) => println!("{}", kind.label()),
    None => println!("No project detected"),
}

Clean artifacts

use project_detect::detect;

if let Some(kind) = detect(".") {
    for dir in kind.artifact_dirs() {
        println!("Can remove: {dir}/");
    }
    // Rust: ["target"]
    // Node.js: ["node_modules", ".next", ".nuxt", ".turbo"]
    // Haskell (Stack): [".stack-work"]
}

Node.js helpers

use project_detect::{node_has_script, node_has_bin, detect_node_workspace};
use std::path::Path;

let dir = Path::new(".");
if node_has_script(dir, "build") { /* has a build script */ }
if node_has_bin(dir) { /* has a bin field */ }
if let Some(packages) = detect_node_workspace(dir) {
    for pkg in packages {
        println!("{}: {}", pkg.name, pkg.dev_script);
    }
}

License

MIT