@@ -23,6 +23,7 @@ pub struct ValidationError {
2323
2424pub struct SpannedValidator {
2525 spans : HashMap < String , SpanInfo > ,
26+ key_spans : HashMap < String , SpanInfo > , // Track key spans separately
2627 json_value : serde_json:: Value ,
2728 source : String ,
2829 file_path : String ,
@@ -38,10 +39,13 @@ impl SpannedValidator {
3839
3940 // Strip spans and build lookup map
4041 let mut spans = HashMap :: new ( ) ;
41- let json_value = Self :: strip_spans_and_index ( & spanned_yaml, String :: new ( ) , & mut spans) ;
42+ let mut key_spans = HashMap :: new ( ) ;
43+ let json_value =
44+ Self :: strip_spans_and_index ( & spanned_yaml, String :: new ( ) , & mut spans, & mut key_spans) ;
4245
4346 Ok ( Self {
4447 spans,
48+ key_spans,
4549 json_value,
4650 source,
4751 file_path : file_path_str,
@@ -73,10 +77,33 @@ impl SpannedValidator {
7377 }
7478 }
7579
80+ pub fn create_error_for_key ( & self , instance_path : & str , message : String ) -> ValidationError {
81+ let pointer_str = instance_path;
82+
83+ // For key errors, look up key span first, then fall back to value span
84+ let span_info = self
85+ . key_spans
86+ . get ( pointer_str)
87+ . or_else ( || self . spans . get ( pointer_str) )
88+ . or_else ( || self . spans . get ( "" ) )
89+ . cloned ( )
90+ . unwrap_or ( SpanInfo { start : 0 , end : 0 } ) ;
91+
92+ ValidationError {
93+ source_code : crate :: error_utils:: create_named_source (
94+ Path :: new ( & self . file_path ) ,
95+ self . source . clone ( ) ,
96+ ) ,
97+ span : SourceSpan :: new ( span_info. start . into ( ) , span_info. end - span_info. start ) ,
98+ message,
99+ }
100+ }
101+
76102 fn strip_spans_and_index (
77103 spanned : & Spanned < YamlValue > ,
78104 path : String ,
79105 spans : & mut HashMap < String , SpanInfo > ,
106+ key_spans : & mut HashMap < String , SpanInfo > ,
80107 ) -> serde_json:: Value {
81108 // Record span for this path
82109 let span = spanned. span ( ) ;
@@ -115,7 +142,7 @@ impl SpannedValidator {
115142 } else {
116143 format ! ( "{path}/{i}" )
117144 } ;
118- Self :: strip_spans_and_index ( item, item_path, spans)
145+ Self :: strip_spans_and_index ( item, item_path, spans, key_spans )
119146 } )
120147 . collect ( ) ;
121148 serde_json:: Value :: Array ( arr)
@@ -129,14 +156,30 @@ impl SpannedValidator {
129156 } else {
130157 format ! ( "{path}/{key}" )
131158 } ;
132- let value = Self :: strip_spans_and_index ( value_spanned, value_path, spans) ;
159+
160+ // Record the key span for this path
161+ let key_span = key_spanned. span ( ) ;
162+ key_spans. insert (
163+ value_path. clone ( ) ,
164+ SpanInfo {
165+ start : key_span. start . unwrap_or_default ( ) . byte_index ,
166+ end : key_span. end . unwrap_or_default ( ) . byte_index ,
167+ } ,
168+ ) ;
169+
170+ let value = Self :: strip_spans_and_index (
171+ value_spanned,
172+ value_path,
173+ spans,
174+ key_spans,
175+ ) ;
133176 obj. insert ( key. clone ( ) , value) ;
134177 }
135178 }
136179 serde_json:: Value :: Object ( obj)
137180 }
138181 YamlValue :: Tagged ( tagged_value) => {
139- Self :: strip_spans_and_index ( & tagged_value. value , path, spans)
182+ Self :: strip_spans_and_index ( & tagged_value. value , path, spans, key_spans )
140183 }
141184 }
142185 }
0 commit comments