Skip to main content

claude_native/scan/
classifiers.rs

1use std::path::Path;
2
3use crate::scan::ManifestKind;
4
5// ── Skip patterns (hardcoded sensible defaults) ─────────────────────
6
7const SKIP_DIRS: &[&str] = &[
8    ".git", "node_modules", "target", ".next", "dist", "build",
9    "__pycache__", ".venv", "venv", "vendor", ".dart_tool",
10    ".gradle", "Pods", "DerivedData", ".build", ".expo",
11    ".aws-sam", ".serverless", ".terraform", "Library",
12    ".godot", ".import", "coverage", ".turbo", ".nuxt",
13    ".angular", ".cache",
14];
15
16pub fn should_skip_dir(name: &str) -> bool {
17    SKIP_DIRS.contains(&name)
18}
19
20pub fn is_source_extension(ext: &str) -> bool {
21    matches!(ext,
22        "rs" | "ts" | "tsx" | "js" | "jsx" | "mjs" | "cjs" |
23        "py" | "go" | "dart" | "swift" | "kt" | "kts" | "java" |
24        "rb" | "cs" | "ex" | "exs" | "cpp" | "cc" | "c" | "h" | "hpp" |
25        "vue" | "svelte" | "tf" | "hcl" | "yaml" | "yml" | "toml" | "json" |
26        "graphql" | "proto" | "prisma" | "sql" | "sh" | "bash" | "zsh" |
27        "md" | "mdx" | "css" | "scss" | "less" | "html" | "xml"
28    )
29}
30
31pub fn is_test_file(path: &Path) -> bool {
32    let name = path.file_stem()
33        .and_then(|s| s.to_str())
34        .unwrap_or("");
35    let full = path.to_string_lossy();
36
37    name.ends_with("_test")
38        || name.ends_with(".test")
39        || name.ends_with("_spec")
40        || name.ends_with(".spec")
41        || name.starts_with("test_")
42        || full.contains("__tests__")
43        || full.contains("/tests/")
44        || full.contains("/test/")
45        || full.contains("/spec/")
46}
47
48pub fn is_generated_file(path: &Path) -> bool {
49    let full = path.to_string_lossy();
50    let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
51
52    full.contains("/generated/")
53        || full.contains("/gen/")
54        || name.contains(".g.")
55        || name.contains(".generated.")
56        || name.contains(".freezed.")
57        || name.contains(".pb.")
58        || name == "R.java"
59        || name == "R.kt"
60        || name == "BuildConfig.kt"
61        || name == "BuildConfig.java"
62}
63
64pub fn is_lock_file(name: &str) -> bool {
65    matches!(name,
66        "package-lock.json" | "yarn.lock" | "pnpm-lock.yaml" |
67        "Cargo.lock" | "Gemfile.lock" | "poetry.lock" | "go.sum" |
68        "composer.lock" | "pubspec.lock" | "Pipfile.lock"
69    )
70}
71
72pub fn is_ci_config(path: &Path) -> bool {
73    let full = path.to_string_lossy();
74    let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
75
76    full.contains(".github/workflows")
77        || name == ".gitlab-ci.yml"
78        || name == "Jenkinsfile"
79        || name == ".circleci"
80        || name == ".travis.yml"
81        || name == "azure-pipelines.yml"
82        || name == "bitbucket-pipelines.yml"
83}
84
85pub fn is_env_file(name: &str) -> bool {
86    name == ".env"
87        || name.starts_with(".env.")
88        || name.ends_with(".env")
89}
90
91pub fn is_manifest(name: &str) -> Option<ManifestKind> {
92    match name {
93        "package.json" => Some(ManifestKind::PackageJson),
94        "Cargo.toml" => Some(ManifestKind::CargoToml),
95        "go.mod" => Some(ManifestKind::GoMod),
96        "pubspec.yaml" => Some(ManifestKind::PubspecYaml),
97        "requirements.txt" => Some(ManifestKind::RequirementsTxt),
98        "pyproject.toml" => Some(ManifestKind::PyprojectToml),
99        "Gemfile" => Some(ManifestKind::Gemfile),
100        "mix.exs" => Some(ManifestKind::MixExs),
101        _ => None,
102    }
103}