Skip to content

Commit 58e2923

Browse files
committed
feat: capture and log unknown fields
1 parent 8981bbd commit 58e2923

File tree

1 file changed

+42
-14
lines changed

1 file changed

+42
-14
lines changed

src/lint/mod.rs

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use std::fmt;
22
use std::fs;
33
use std::path::{Path, PathBuf};
4-
use std::collections::HashMap;
5-
use serde_json::Value;
64
use log::{debug, error, trace};
75
use serde::{Deserialize, Serialize};
86
use rules::{instantiate_rules, CurrentRules, RuleType};
@@ -21,21 +19,26 @@ use crate::lint::rules::indentation::{MAX_LENGTH_DEFAULT,
2119
setup_indentation_size
2220
};
2321

24-
pub fn parse_lint_cfg(path: PathBuf) -> Result<LintCfg, String> {
22+
pub fn parse_lint_cfg(path: PathBuf) -> Result<(LintCfg, Vec<String>), String> {
2523
debug!("Reading Lint configuration from {:?}", path);
26-
let file_content = fs::read_to_string(path).map_err(
27-
|e|e.to_string())?;
24+
let file_content = fs::read_to_string(path).map_err(|e| e.to_string())?;
2825
trace!("Content is {:?}", file_content);
29-
serde_json::from_str(&file_content)
30-
.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))
3134
}
3235

3336
pub fn maybe_parse_lint_cfg(path: PathBuf) -> Option<LintCfg> {
3437
match parse_lint_cfg(path) {
35-
Ok(mut cfg) => {
36-
if !cfg.unknown_fields.is_empty() {
38+
Ok((mut cfg, unknowns)) => {
39+
if !unknowns.is_empty() {
3740
// Log the unknown fields as a comma-separated list
38-
error!("Unknown lint config fields: {}", cfg.unknown_fields.keys().cloned().collect::<Vec<_>>().join(", "));
41+
error!("Unknown lint config fields: {}", unknowns.join(", "));
3942
}
4043
setup_indentation_size(&mut cfg);
4144
Some(cfg)
@@ -50,8 +53,6 @@ pub fn maybe_parse_lint_cfg(path: PathBuf) -> Option<LintCfg> {
5053
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
5154
#[serde(default)]
5255
pub struct LintCfg {
53-
#[serde(flatten)]
54-
pub unknown_fields: HashMap<String, Value>,
5556
#[serde(default)]
5657
pub sp_brace: Option<SpBraceOptions>,
5758
#[serde(default)]
@@ -84,14 +85,39 @@ pub struct LintCfg {
8485
pub annotate_lints: bool,
8586
}
8687

88+
impl LintCfg {
89+
pub fn try_deserialize(
90+
val: &serde_json::Value,
91+
unknowns: &mut Vec<String>,
92+
) -> Result<LintCfg, String> {
93+
// Handle unknown fields by collecting field names
94+
if let Some(obj) = val.as_object() {
95+
let known_fields = [
96+
"sp_brace", "sp_punct", "nsp_funpar", "nsp_inparen",
97+
"nsp_unary", "nsp_trailing", "long_lines", "indent_size",
98+
"indent_no_tabs", "indent_code_block", "indent_closing_brace",
99+
"indent_paren_expr", "indent_switch_case", "indent_empty_loop",
100+
"annotate_lints"
101+
];
102+
103+
for key in obj.keys() {
104+
if !known_fields.contains(&key.as_str()) {
105+
unknowns.push(key.clone());
106+
}
107+
}
108+
}
109+
110+
serde_json::from_value(val.clone()).map_err(|e| e.to_string())
111+
}
112+
}
113+
87114
fn get_true() -> bool {
88115
true
89116
}
90117

91118
impl Default for LintCfg {
92119
fn default() -> LintCfg {
93120
LintCfg {
94-
unknown_fields: HashMap::new(),
95121
sp_brace: Some(SpBraceOptions{}),
96122
sp_punct: Some(SpPunctOptions{}),
97123
nsp_funpar: Some(NspFunparOptions{}),
@@ -271,8 +297,10 @@ pub mod tests {
271297
let example_path = format!("{}{}",
272298
env!("CARGO_MANIFEST_DIR"),
273299
EXAMPLE_CFG);
274-
let example_cfg = parse_lint_cfg(example_path.into()).unwrap();
300+
let (example_cfg, unknowns) = parse_lint_cfg(example_path.into()).unwrap();
275301
assert_eq!(example_cfg, LintCfg::default());
302+
// Assert that there are no unknown fields in the example config:
303+
assert!(unknowns.is_empty(), "Example config should not have unknown fields: {:?}", unknowns);
276304
}
277305

278306
#[test]

0 commit comments

Comments
 (0)