@@ -4,12 +4,11 @@ import {
4
4
} from "vscode-languageserver" ;
5
5
import * as SchemaDocument from "../../model/schema-document.js" ;
6
6
import * as SchemaNode from "../../model/schema-node.js" ;
7
-
8
-
7
+ import * as jsoncParser from "jsonc-parser" ;
9
8
/**
10
- * @import { Schemas } from "../../services/schemas .js";
11
- * @import { Server } from "../../services/server .js";
12
- * @import {CodeAction} from "vscode-languageserver";
9
+ * @import { Server } from "../../services/server .js"
10
+ * @import { Schemas } from "../../services/schemas .js"
11
+ * @import { CodeAction } from "vscode-languageserver";
13
12
*/
14
13
export class ExtractSubSchemaToDefs {
15
14
/**
@@ -25,7 +24,18 @@ export class ExtractSubSchemaToDefs {
25
24
}
26
25
} ) ) ;
27
26
28
- server . onCodeAction ( async ( { textDocument, range} ) => {
27
+ // Helper function to format new def using jsonc-parser
28
+ const formatNewDef = ( /** @type {string } */ newDefText ) => {
29
+ try {
30
+ /** @type {unknown } */
31
+ const parsedDef = jsoncParser . parse ( newDefText ) ;
32
+ return JSON . stringify ( parsedDef , null , 2 ) . replace ( / \n / g, "\n " ) ;
33
+ } catch {
34
+ return newDefText ;
35
+ }
36
+ } ;
37
+
38
+ server . onCodeAction ( async ( { textDocument, range } ) => {
29
39
const uri = textDocument . uri ;
30
40
let schemaDocument = await schemas . getOpen ( uri ) ;
31
41
if ( ! schemaDocument ) {
@@ -37,22 +47,30 @@ export class ExtractSubSchemaToDefs {
37
47
if ( ! node ?. isSchema ) {
38
48
return [ ] ;
39
49
}
40
-
41
- // Finding the $defs node
42
- let findDef ;
50
+ let definitionsNode ;
43
51
for ( const schemaNode of SchemaNode . allNodes ( node . root ) ) {
44
52
if ( schemaNode . keywordUri === "https://json-schema.org/keyword/definitions" ) {
45
- findDef = schemaNode ;
53
+ definitionsNode = schemaNode ;
46
54
break ;
47
55
}
48
56
}
49
-
50
- // Getting the name from pointer
51
- let newDefName = "unknown" ;
52
- if ( node . pointer ) {
53
- const parts = node . pointer . split ( "/" ) ;
54
- newDefName = parts [ parts . length - 1 ] || "unknown" ;
57
+ let highestDefNumber = 0 ;
58
+ if ( definitionsNode ) {
59
+ const defsContent = schemaDocument . textDocument . getText ( ) . slice (
60
+ definitionsNode . offset ,
61
+ definitionsNode . offset + definitionsNode . textLength
62
+ ) ;
63
+ const defMatches = [ ...defsContent . matchAll ( / " d e f ( \d + ) " : / g) ] ;
64
+ defMatches . forEach ( ( match ) =>
65
+ highestDefNumber = Math . max ( highestDefNumber , parseInt ( match [ 1 ] , 10 ) )
66
+ ) ;
55
67
}
68
+ let newDefName = `def${ highestDefNumber + 1 } ` ;
69
+ const extractedDef = schemaDocument . textDocument . getText ( range ) ;
70
+ const newFormattedDef = formatNewDef ( extractedDef ) ;
71
+ let defName = ( node . root . dialectUri === "https://json-schema.org/draft/2020-12/schema"
72
+ || node . root . dialectUri === "https://json-schema.org/draft/2019-09/schema" )
73
+ ? "$defs" : "definitions" ;
56
74
57
75
/** @type {CodeAction } */
58
76
const codeAction = {
@@ -63,22 +81,22 @@ export class ExtractSubSchemaToDefs {
63
81
TextDocumentEdit . create ( { uri : textDocument . uri , version : null } , [
64
82
{
65
83
range : range ,
66
- newText : `{ "$ref": "#/$defs /${ newDefName } " }`
84
+ newText : `{ "$ref": "#/${ defName } /${ newDefName } " }`
67
85
} ,
68
- findDef
86
+ definitionsNode
69
87
? {
70
88
range : {
71
- start : schemaDocument . textDocument . positionAt ( findDef . offset + 1 ) ,
72
- end : schemaDocument . textDocument . positionAt ( findDef . offset + 1 )
89
+ start : schemaDocument . textDocument . positionAt ( definitionsNode . offset + 1 ) ,
90
+ end : schemaDocument . textDocument . positionAt ( definitionsNode . offset + 1 )
73
91
} ,
74
- newText : `\n "${ newDefName } ":${ schemaDocument . textDocument . getText ( range ) } ,`
92
+ newText : `\n "${ newDefName } ": ${ newFormattedDef } ,`
75
93
}
76
94
: {
77
95
range : {
78
- start : { line : 1 , character : 0 } ,
79
- end : { line : 1 , character : 0 }
96
+ start : schemaDocument . textDocument . positionAt ( node . root . offset + node . root . textLength - 2 ) ,
97
+ end : schemaDocument . textDocument . positionAt ( node . root . offset + node . root . textLength - 2 )
80
98
} ,
81
- newText : ` "$defs ": {\n "${ newDefName } ":${ schemaDocument . textDocument . getText ( range ) } \n },\n `
99
+ newText : `,\n "${ defName } ": {\n "${ newDefName } ": ${ newFormattedDef } \n }`
82
100
}
83
101
] )
84
102
]
0 commit comments