@@ -100,7 +100,14 @@ export function validateConfig(document: TextDocument): Diagnostic[] {
100100
101101 let validate ;
102102 try {
103- validate = ajv . compile ( schemaInfo . schema ) ;
103+ // Create a copy of the schema and modify $ref to use Draft 07 instead of Draft 04
104+ const modifiedSchema = JSON . parse ( JSON . stringify ( schemaInfo . schema ) ) ;
105+ if (
106+ modifiedSchema . $schema === "http://json-schema.org/draft-04/schema#"
107+ ) {
108+ modifiedSchema . $schema = "http://json-schema.org/draft-07/schema#" ;
109+ }
110+ validate = ajv . compile ( modifiedSchema ) ;
104111 } catch ( schemaError ) {
105112 console . error ( `[JSON_CONFIG] Failed to compile schema:` , schemaError ) ;
106113 return [ ] ;
@@ -281,6 +288,33 @@ export function getConfigCompletions(document: TextDocument): CompletionItem[] {
281288 ) ;
282289}
283290
291+ // Helper function to detect if JSON is minified (single line without meaningful whitespace)
292+ function isMinifiedJson ( jsonContent : string ) : boolean {
293+ const lineCount = jsonContent . split ( "\n" ) . length ;
294+ const trimmed = jsonContent . trim ( ) ;
295+
296+ // Consider it minified if it's just one line, or if it's very compact
297+ return lineCount === 1 || ( lineCount <= 3 && trimmed . length < 200 ) ;
298+ }
299+
300+ // Helper function to normalize JSON content for position calculations
301+ // Only formats if the JSON appears to be truly minified (single line)
302+ function normalizeJsonContent ( jsonContent : string ) : string {
303+ try {
304+ // Only format if it's clearly minified (single line with no meaningful line breaks)
305+ if ( isMinifiedJson ( jsonContent ) ) {
306+ const parsed = JSON . parse ( jsonContent ) ;
307+ return JSON . stringify ( parsed , null , 2 ) ;
308+ }
309+
310+ // Otherwise, use original content to preserve manual formatting
311+ return jsonContent ;
312+ } catch {
313+ // If parsing fails, return original content
314+ return jsonContent ;
315+ }
316+ }
317+
284318export function getConfigHover (
285319 document : TextDocument ,
286320 position : Position ,
@@ -303,16 +337,62 @@ export function getConfigHover(
303337 return null ;
304338 }
305339
306- const line = document . getText (
307- Range . create ( position . line , 0 , position . line , 1000 ) ,
340+ // Normalize the JSON content for position calculations
341+ const originalContent = document . getText ( ) ;
342+ const normalizedContent = normalizeJsonContent ( originalContent ) ;
343+
344+ // Split into lines for position calculation
345+ const formattedLines = normalizedContent . split ( "\n" ) ;
346+
347+ // Make sure the position is valid
348+ if ( position . line >= formattedLines . length ) {
349+ return null ;
350+ }
351+
352+ const line = formattedLines [ position . line ] ;
353+
354+ // Find all quoted strings on the line with their positions
355+ const quotes = [ ] ;
356+ const regex = / " ( [ ^ " ] + ) " / g;
357+ let match ;
358+ while ( ( match = regex . exec ( line ) ) !== null ) {
359+ quotes . push ( {
360+ text : match [ 0 ] ,
361+ value : match [ 1 ] ,
362+ start : match . index ,
363+ end : match . index + match [ 0 ] . length ,
364+ } ) ;
365+ }
366+
367+ // Find which quote contains the cursor position
368+ const cursorQuote = quotes . find (
369+ ( q ) => position . character >= q . start && position . character <= q . end ,
308370 ) ;
309- const match = line . match ( / " ( [ ^ " ] + ) " / ) ;
310371
311- if ( ! match ) {
372+ if ( ! cursorQuote ) {
312373 return null ;
313374 }
314375
315- const propertyName = match [ 1 ] ;
376+ // Check if this is a property key (followed by colon) or property value
377+ const isPropertyKey = line . substring ( cursorQuote . end ) . trim ( ) . startsWith ( ":" ) ;
378+
379+ let propertyName ;
380+ if ( isPropertyKey ) {
381+ // This is a property key, use it directly
382+ propertyName = cursorQuote . value ;
383+ } else {
384+ // This is a property value, try to find the corresponding key
385+ // Look backwards to find the property key
386+ const beforeCursor = line . substring ( 0 , cursorQuote . start ) ;
387+ const keyMatch = beforeCursor . match ( / " ( [ ^ " ] + ) " \s * : \s * [ ^ : ] * $ / ) ;
388+ if ( keyMatch ) {
389+ propertyName = keyMatch [ 1 ] ;
390+ } else {
391+ // If we can't find the key, this might be an array value or nested property
392+ return null ;
393+ }
394+ }
395+
316396 const property = schemaInfo . schema . properties [ propertyName ] ;
317397
318398 if ( property ?. description ) {
0 commit comments