Skip to content

Commit 74498f2

Browse files
committed
feat: capture and log unknown fields
1 parent 2fd9558 commit 74498f2

File tree

1 file changed

+70
-8
lines changed

1 file changed

+70
-8
lines changed

src/lint/mod.rs

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,27 @@ use crate::lint::rules::indentation::{MAX_LENGTH_DEFAULT,
1919
setup_indentation_size
2020
};
2121

22-
pub fn parse_lint_cfg(path: PathBuf) -> Result<LintCfg, String> {
22+
pub fn parse_lint_cfg(path: PathBuf) -> Result<(LintCfg, Vec<String>), String> {
2323
debug!("Reading Lint configuration from {:?}", path);
24-
let file_content = fs::read_to_string(path).map_err(
25-
|e|e.to_string())?;
24+
let file_content = fs::read_to_string(path).map_err(|e| e.to_string())?;
2625
trace!("Content is {:?}", file_content);
27-
serde_json::from_str(&file_content)
28-
.map_err(|e|e.to_string())
26+
27+
let val: serde_json::Value = serde_json::from_str(&file_content)
28+
.map_err(|e| e.to_string())?;
29+
30+
let mut unknowns = Vec::new();
31+
let cfg = LintCfg::try_deserialize(&val, &mut unknowns)?;
32+
33+
Ok((cfg, unknowns))
2934
}
3035

3136
pub fn maybe_parse_lint_cfg(path: PathBuf) -> Option<LintCfg> {
3237
match parse_lint_cfg(path) {
33-
Ok(mut cfg) => {
38+
Ok((mut cfg, unknowns)) => {
39+
if !unknowns.is_empty() {
40+
// Log the unknown fields as a comma-separated list
41+
error!("Unknown lint config fields: {}", unknowns.join(", "));
42+
}
3443
setup_indentation_size(&mut cfg);
3544
Some(cfg)
3645
},
@@ -43,7 +52,6 @@ pub fn maybe_parse_lint_cfg(path: PathBuf) -> Option<LintCfg> {
4352

4453
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
4554
#[serde(default)]
46-
#[serde(deny_unknown_fields)]
4755
pub struct LintCfg {
4856
#[serde(default)]
4957
pub sp_brace: Option<SpBraceOptions>,
@@ -77,6 +85,21 @@ pub struct LintCfg {
7785
pub annotate_lints: bool,
7886
}
7987

88+
impl LintCfg {
89+
pub fn try_deserialize(
90+
val: &serde_json::Value,
91+
unknowns: &mut Vec<String>,
92+
) -> Result<LintCfg, String> {
93+
// Use serde_ignored to automatically track unknown fields
94+
match serde_ignored::deserialize(val, |json_field| {
95+
unknowns.push(json_field.to_string());
96+
}) {
97+
Ok(cfg) => Ok(cfg),
98+
Err(e) => Err(e.to_string()),
99+
}
100+
}
101+
}
102+
80103
fn get_true() -> bool {
81104
true
82105
}
@@ -263,8 +286,47 @@ pub mod tests {
263286
let example_path = format!("{}{}",
264287
env!("CARGO_MANIFEST_DIR"),
265288
EXAMPLE_CFG);
266-
let example_cfg = parse_lint_cfg(example_path.into()).unwrap();
289+
let (example_cfg, unknowns) = parse_lint_cfg(example_path.into()).unwrap();
267290
assert_eq!(example_cfg, LintCfg::default());
291+
// Assert that there are no unknown fields in the example config:
292+
assert!(unknowns.is_empty(), "Example config should not have unknown fields: {:?}", unknowns);
293+
}
294+
295+
#[test]
296+
fn test_unknown_fields_detection() {
297+
use crate::lint::LintCfg;
298+
299+
// JSON with unknown fields
300+
let json_with_unknowns = r#"{
301+
"sp_brace": {},
302+
"unknown_field_1": true,
303+
"indent_size": {"indentation_spaces": 4},
304+
"another_unknown": "value"
305+
}"#;
306+
307+
let val: serde_json::Value = serde_json::from_str(json_with_unknowns).unwrap();
308+
let mut unknowns = Vec::new();
309+
let result = LintCfg::try_deserialize(&val, &mut unknowns);
310+
311+
assert!(result.is_ok());
312+
let cfg = result.unwrap();
313+
314+
// Assert that unknown fields were detected
315+
assert_eq!(unknowns.len(), 2);
316+
assert!(unknowns.contains(&"unknown_field_1".to_string()));
317+
assert!(unknowns.contains(&"another_unknown".to_string()));
318+
319+
// Assert the final LintCfg matches expected json (the known fields)
320+
let expected_json = r#"{
321+
"sp_brace": {},
322+
"indent_size": {"indentation_spaces": 4}
323+
}"#;
324+
let expected_val: serde_json::Value = serde_json::from_str(expected_json).unwrap();
325+
let mut expected_unknowns = Vec::new();
326+
let expected_cfg = LintCfg::try_deserialize(&expected_val, &mut expected_unknowns).unwrap();
327+
328+
assert_eq!(cfg, expected_cfg);
329+
assert!(expected_unknowns.is_empty()); // No unknown fields in the expected config
268330
}
269331

270332
#[test]

0 commit comments

Comments
 (0)