@@ -22,19 +22,27 @@ use crate::lint::rules::indentation::{MAX_LENGTH_DEFAULT,
2222 INDENTATION_LEVEL_DEFAULT ,
2323 setup_indentation_size
2424 } ;
25+ use crate :: server:: { maybe_notify_unknown_lint_fields, Output } ;
2526
26- pub fn parse_lint_cfg ( path : PathBuf ) -> Result < LintCfg , String > {
27+ pub fn parse_lint_cfg ( path : PathBuf ) -> Result < ( LintCfg , Vec < String > ) , String > {
2728 debug ! ( "Reading Lint configuration from {:?}" , path) ;
28- let file_content = fs:: read_to_string ( path) . map_err (
29- |e|e. to_string ( ) ) ?;
29+ let file_content = fs:: read_to_string ( path) . map_err ( |e| e. to_string ( ) ) ?;
3030 trace ! ( "Content is {:?}" , file_content) ;
31- serde_json:: from_str ( & file_content)
32- . map_err ( |e|e. to_string ( ) )
31+
32+ let val: serde_json:: Value = serde_json:: from_str ( & file_content)
33+ . map_err ( |e| e. to_string ( ) ) ?;
34+
35+ let mut unknowns = Vec :: new ( ) ;
36+ let cfg = LintCfg :: try_deserialize ( & val, & mut unknowns) ?;
37+
38+ Ok ( ( cfg, unknowns) )
3339}
3440
35- pub fn maybe_parse_lint_cfg ( path : PathBuf ) -> Option < LintCfg > {
41+ pub fn maybe_parse_lint_cfg < O : Output > ( path : PathBuf , out : & O ) -> Option < LintCfg > {
3642 match parse_lint_cfg ( path) {
37- Ok ( mut cfg) => {
43+ Ok ( ( mut cfg, unknowns) ) => {
44+ // Send visible warning to client
45+ maybe_notify_unknown_lint_fields ( out, & unknowns) ;
3846 setup_indentation_size ( & mut cfg) ;
3947 Some ( cfg)
4048 } ,
@@ -45,9 +53,10 @@ pub fn maybe_parse_lint_cfg(path: PathBuf) -> Option<LintCfg> {
4553 }
4654}
4755
56+
57+
4858#[ derive( Clone , Debug , Serialize , Deserialize , PartialEq ) ]
4959#[ serde( default ) ]
50- #[ serde( deny_unknown_fields) ]
5160pub struct LintCfg {
5261 #[ serde( default ) ]
5362 pub sp_brace : Option < SpBraceOptions > ,
@@ -81,6 +90,21 @@ pub struct LintCfg {
8190 pub annotate_lints : bool ,
8291}
8392
93+ impl LintCfg {
94+ pub fn try_deserialize (
95+ val : & serde_json:: Value ,
96+ unknowns : & mut Vec < String > ,
97+ ) -> Result < LintCfg , String > {
98+ // Use serde_ignored to automatically track unknown fields
99+ match serde_ignored:: deserialize ( val, |json_field| {
100+ unknowns. push ( json_field. to_string ( ) ) ;
101+ } ) {
102+ Ok ( cfg) => Ok ( cfg) ,
103+ Err ( e) => Err ( e. to_string ( ) ) ,
104+ }
105+ }
106+ }
107+
84108fn get_true ( ) -> bool {
85109 true
86110}
@@ -421,8 +445,47 @@ pub mod tests {
421445 let example_path = format ! ( "{}{}" ,
422446 env!( "CARGO_MANIFEST_DIR" ) ,
423447 EXAMPLE_CFG ) ;
424- let example_cfg = parse_lint_cfg ( example_path. into ( ) ) . unwrap ( ) ;
448+ let ( example_cfg, unknowns ) = parse_lint_cfg ( example_path. into ( ) ) . unwrap ( ) ;
425449 assert_eq ! ( example_cfg, LintCfg :: default ( ) ) ;
450+ // Assert that there are no unknown fields in the example config:
451+ assert ! ( unknowns. is_empty( ) , "Example config should not have unknown fields: {:?}" , unknowns) ;
452+ }
453+
454+ #[ test]
455+ fn test_unknown_fields_detection ( ) {
456+ use crate :: lint:: LintCfg ;
457+
458+ // JSON with unknown fields
459+ let json_with_unknowns = r#"{
460+ "sp_brace": {},
461+ "unknown_field_1": true,
462+ "indent_size": {"indentation_spaces": 4},
463+ "another_unknown": "value"
464+ }"# ;
465+
466+ let val: serde_json:: Value = serde_json:: from_str ( json_with_unknowns) . unwrap ( ) ;
467+ let mut unknowns = Vec :: new ( ) ;
468+ let result = LintCfg :: try_deserialize ( & val, & mut unknowns) ;
469+
470+ assert ! ( result. is_ok( ) ) ;
471+ let cfg = result. unwrap ( ) ;
472+
473+ // Assert that unknown fields were detected
474+ assert_eq ! ( unknowns. len( ) , 2 ) ;
475+ assert ! ( unknowns. contains( & "unknown_field_1" . to_string( ) ) ) ;
476+ assert ! ( unknowns. contains( & "another_unknown" . to_string( ) ) ) ;
477+
478+ // Assert the final LintCfg matches expected json (the known fields)
479+ let expected_json = r#"{
480+ "sp_brace": {},
481+ "indent_size": {"indentation_spaces": 4}
482+ }"# ;
483+ let expected_val: serde_json:: Value = serde_json:: from_str ( expected_json) . unwrap ( ) ;
484+ let mut expected_unknowns = Vec :: new ( ) ;
485+ let expected_cfg = LintCfg :: try_deserialize ( & expected_val, & mut expected_unknowns) . unwrap ( ) ;
486+
487+ assert_eq ! ( cfg, expected_cfg) ;
488+ assert ! ( expected_unknowns. is_empty( ) ) ; // No unknown fields in the expected config
426489 }
427490
428491 #[ test]
0 commit comments