use std::path::Path;
use super::{DetectedConfig, Tool};
pub fn detect_configs(
project_root: &Path,
tool_filter: Option<Tool>,
) -> Result<Vec<DetectedConfig>, String> {
let mut detected = Vec::new();
if tool_filter.is_none() || tool_filter == Some(Tool::ESLint) {
detected.extend(detect_eslint_configs(project_root)?);
}
if tool_filter.is_none() || tool_filter == Some(Tool::Prettier) {
detected.extend(detect_prettier_configs(project_root)?);
}
if tool_filter.is_none() || matches!(tool_filter, Some(Tool::Black) | Some(Tool::Isort)) {
detected.extend(detect_python_configs(project_root, tool_filter)?);
}
Ok(detected)
}
fn detect_eslint_configs(root: &Path) -> Result<Vec<DetectedConfig>, String> {
let mut configs = Vec::new();
let config_names = [
".eslintrc.js",
".eslintrc.cjs",
".eslintrc.json",
".eslintrc.yml",
".eslintrc.yaml",
".eslintrc",
"eslint.config.js",
"eslint.config.mjs",
];
for name in &config_names {
let path = root.join(name);
if path.exists() {
configs.push(DetectedConfig {
tool: Tool::ESLint,
path,
language: "javascript".to_string(),
});
break; }
}
if configs.is_empty() {
let pkg_json = root.join("package.json");
if pkg_json.exists() {
if let Ok(content) = std::fs::read_to_string(&pkg_json) {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
if json.get("eslintConfig").is_some() {
configs.push(DetectedConfig {
tool: Tool::ESLint,
path: pkg_json,
language: "javascript".to_string(),
});
}
}
}
}
}
Ok(configs)
}
fn detect_prettier_configs(root: &Path) -> Result<Vec<DetectedConfig>, String> {
let mut configs = Vec::new();
let config_names = [
".prettierrc",
".prettierrc.json",
".prettierrc.yml",
".prettierrc.yaml",
".prettierrc.js",
".prettierrc.cjs",
"prettier.config.js",
"prettier.config.cjs",
];
for name in &config_names {
let path = root.join(name);
if path.exists() {
configs.push(DetectedConfig {
tool: Tool::Prettier,
path,
language: "javascript".to_string(),
});
break;
}
}
if configs.is_empty() {
let pkg_json = root.join("package.json");
if pkg_json.exists() {
if let Ok(content) = std::fs::read_to_string(&pkg_json) {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
if json.get("prettier").is_some() {
configs.push(DetectedConfig {
tool: Tool::Prettier,
path: pkg_json,
language: "javascript".to_string(),
});
}
}
}
}
}
Ok(configs)
}
fn detect_python_configs(
root: &Path,
tool_filter: Option<Tool>,
) -> Result<Vec<DetectedConfig>, String> {
let mut configs = Vec::new();
let pyproject = root.join("pyproject.toml");
if pyproject.exists() {
if let Ok(content) = std::fs::read_to_string(&pyproject) {
if let Ok(toml) = content.parse::<toml::Value>() {
if let Some(tool) = toml.get("tool") {
if (tool_filter.is_none() || tool_filter == Some(Tool::Black))
&& tool.get("black").is_some()
{
configs.push(DetectedConfig {
tool: Tool::Black,
path: pyproject.clone(),
language: "python".to_string(),
});
}
if (tool_filter.is_none() || tool_filter == Some(Tool::Isort))
&& tool.get("isort").is_some()
{
configs.push(DetectedConfig {
tool: Tool::Isort,
path: pyproject.clone(),
language: "python".to_string(),
});
}
}
}
}
}
Ok(configs)
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_detect_eslint_json_config() {
let dir = TempDir::new().unwrap();
std::fs::write(
dir.path().join(".eslintrc.json"),
r#"{"extends": ["eslint:recommended"]}"#,
)
.unwrap();
let configs = detect_configs(dir.path(), None).unwrap();
assert_eq!(configs.len(), 1);
assert_eq!(configs[0].tool, Tool::ESLint);
}
#[test]
fn test_detect_prettier_config() {
let dir = TempDir::new().unwrap();
std::fs::write(dir.path().join(".prettierrc"), r#"{"tabWidth": 4}"#).unwrap();
let configs = detect_configs(dir.path(), None).unwrap();
assert_eq!(configs.len(), 1);
assert_eq!(configs[0].tool, Tool::Prettier);
}
#[test]
fn test_detect_black_config() {
let dir = TempDir::new().unwrap();
std::fs::write(
dir.path().join("pyproject.toml"),
r#"
[tool.black]
line-length = 100
"#,
)
.unwrap();
let configs = detect_configs(dir.path(), Some(Tool::Black)).unwrap();
assert_eq!(configs.len(), 1);
assert_eq!(configs[0].tool, Tool::Black);
}
#[test]
fn test_detect_no_configs() {
let dir = TempDir::new().unwrap();
let configs = detect_configs(dir.path(), None).unwrap();
assert!(configs.is_empty());
}
}