1use std::collections::HashMap;
2use std::path::Path;
3
4use serde::Deserialize;
5
6#[derive(Debug, Clone, Deserialize)]
7pub struct Config {
8 #[serde(default)]
9 pub rules: HashMap<String, String>,
10
11 #[serde(default)]
12 pub log: Option<String>,
13
14 #[serde(default = "default_format")]
15 #[allow(dead_code)]
16 pub format: String,
17
18 #[serde(default)]
19 pub max_warnings: Option<u32>,
20
21 #[serde(default)]
24 pub workspaces: Vec<String>,
25
26 #[serde(default)]
29 pub file_types: HashMap<String, HashMap<String, String>>,
30}
31
32fn default_format() -> String {
33 "stylish".to_string()
34}
35
36impl Default for Config {
37 fn default() -> Self {
38 Self {
39 rules: HashMap::new(),
40 log: None,
41 format: "stylish".to_string(),
42 max_warnings: None,
43 workspaces: Vec::new(),
44 file_types: HashMap::new(),
45 }
46 }
47}
48
49impl Config {
50 pub fn load(path: Option<&Path>) -> anyhow::Result<Self> {
51 let mut config = Self::default();
52
53 if let Some(config_path) = path {
54 if config_path.exists() {
55 let content = std::fs::read_to_string(config_path)?;
56 match config_path.extension().and_then(|e| e.to_str()) {
57 Some("toml") => config = toml::from_str(&content)?,
58 Some("json") | Some("jsonc") => config = serde_json::from_str(&content)?,
59 _ => config = serde_json::from_str(&content)?,
60 }
61 }
62 } else {
63 let candidates = [".rauditrc.toml", ".rauditrc.json", ".rauditrc"];
65
66 for candidate in &candidates {
67 let p = Path::new(candidate);
68 if p.exists() {
69 config = Self::load(Some(p))?;
70 break;
71 }
72 }
73
74 let pkg_path = Path::new("package.json");
76 if pkg_path.exists()
77 && let Ok(content) = std::fs::read_to_string(pkg_path)
78 && let Ok(pkg) = serde_json::from_str::<PackageJson>(&content)
79 && let Some(auditor) = pkg.react_auditor
80 {
81 config.rules.extend(auditor.rules);
82 config.log = config.log.or(auditor.log);
83 config.max_warnings = config.max_warnings.or(auditor.max_warnings);
84 }
85 }
86
87 Ok(config)
88 }
89}
90
91#[derive(Debug, Deserialize)]
92struct PackageJson {
93 #[serde(rename = "reactAuditor")]
94 react_auditor: Option<PackageConfig>,
95}
96
97#[derive(Debug, Deserialize)]
98struct PackageConfig {
99 #[serde(default)]
100 rules: HashMap<String, String>,
101 #[serde(default)]
102 log: Option<String>,
103 #[serde(default)]
104 max_warnings: Option<u32>,
105}