11use std:: fmt;
22use std:: fs;
33use std:: path:: { Path , PathBuf } ;
4- use std:: collections:: HashMap ;
5- use serde_json:: Value ;
64use log:: { debug, error, trace} ;
75use serde:: { Deserialize , Serialize } ;
86use 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
3336pub 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 ) ]
5255pub 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+
87114fn get_true ( ) -> bool {
88115 true
89116}
90117
91118impl 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