@@ -16,10 +16,12 @@ import {
1616import { CommonLanguageClient , RequestType } from 'vscode-languageclient/node' ;
1717
1818type FileUri = string ;
19+ type SchemaVersions = { [ version : string ] : string } ;
1920interface JSONSchema {
2021 name ?: string ;
2122 description ?: string ;
2223 uri : string ;
24+ versions ?: SchemaVersions ;
2325}
2426
2527interface MatchingJSONSchema extends JSONSchema {
@@ -31,15 +33,24 @@ interface SchemaItem extends QuickPickItem {
3133 schema ?: MatchingJSONSchema ;
3234}
3335
36+ interface SchemaVersionItem extends QuickPickItem {
37+ version : string ;
38+ url : string ;
39+ }
40+
3441// eslint-disable-next-line @typescript-eslint/ban-types
35- const getJSONSchemas : RequestType < FileUri , MatchingJSONSchema [ ] , { } > = new RequestType ( 'yaml/get/all/jsonSchemas' ) ;
42+ const getJSONSchemasRequestType : RequestType < FileUri , MatchingJSONSchema [ ] , { } > = new RequestType ( 'yaml/get/all/jsonSchemas' ) ;
3643
3744// eslint-disable-next-line @typescript-eslint/ban-types
38- const getSchema : RequestType < FileUri , JSONSchema [ ] , { } > = new RequestType ( 'yaml/get/jsonSchema' ) ;
45+ const getSchemaRequestType : RequestType < FileUri , JSONSchema [ ] , { } > = new RequestType ( 'yaml/get/jsonSchema' ) ;
3946
4047export let statusBarItem : StatusBarItem ;
4148
4249let client : CommonLanguageClient ;
50+ let versionSelection : SchemaItem = undefined ;
51+
52+ const selectVersionLabel = 'Select Different Version' ;
53+
4354export function createJSONSchemaStatusBarItem ( context : ExtensionContext , languageclient : CommonLanguageClient ) : void {
4455 if ( statusBarItem ) {
4556 updateStatusBar ( window . activeTextEditor ) ;
@@ -61,14 +72,32 @@ export function createJSONSchemaStatusBarItem(context: ExtensionContext, languag
6172
6273async function updateStatusBar ( editor : TextEditor ) : Promise < void > {
6374 if ( editor && editor . document . languageId === 'yaml' ) {
75+ versionSelection = undefined ;
6476 // get schema info there
65- const schema = await client . sendRequest ( getSchema , editor . document . uri . toString ( ) ) ;
77+ const schema = await client . sendRequest ( getSchemaRequestType , editor . document . uri . toString ( ) ) ;
6678 if ( ! schema || schema . length === 0 ) {
6779 statusBarItem . text = 'No JSON Schema' ;
6880 statusBarItem . tooltip = 'Select JSON Schema' ;
6981 statusBarItem . backgroundColor = undefined ;
7082 } else if ( schema . length === 1 ) {
7183 statusBarItem . text = schema [ 0 ] . name ?? schema [ 0 ] . uri ;
84+ let version ;
85+ if ( schema [ 0 ] . versions ) {
86+ version = findUsedVersion ( schema [ 0 ] . versions , schema [ 0 ] . uri ) ;
87+ } else {
88+ const schemas = await client . sendRequest ( getJSONSchemasRequestType , window . activeTextEditor . document . uri . toString ( ) ) ;
89+ let versionSchema : JSONSchema ;
90+ const schemaStoreItem = findSchemaStoreItem ( schemas , schema [ 0 ] . uri ) ;
91+ if ( schemaStoreItem ) {
92+ [ version , versionSchema ] = schemaStoreItem ;
93+ ( versionSchema as MatchingJSONSchema ) . usedForCurrentFile = true ;
94+ versionSchema . uri = schema [ 0 ] . uri ;
95+ versionSelection = createSelectVersionItem ( version , versionSchema as MatchingJSONSchema ) ;
96+ }
97+ }
98+ if ( version && ! statusBarItem . text . includes ( version ) ) {
99+ statusBarItem . text += `(${ version } )` ;
100+ }
72101 statusBarItem . tooltip = 'Select JSON Schema' ;
73102 statusBarItem . backgroundColor = undefined ;
74103 } else {
@@ -84,11 +113,15 @@ async function updateStatusBar(editor: TextEditor): Promise<void> {
84113}
85114
86115async function showSchemaSelection ( ) : Promise < void > {
87- const schemas = await client . sendRequest ( getJSONSchemas , window . activeTextEditor . document . uri . toString ( ) ) ;
116+ const schemas = await client . sendRequest ( getJSONSchemasRequestType , window . activeTextEditor . document . uri . toString ( ) ) ;
88117 const schemasPick = window . createQuickPick < SchemaItem > ( ) ;
89- const pickItems : SchemaItem [ ] = [ ] ;
118+ let pickItems : SchemaItem [ ] = [ ] ;
90119
91120 for ( const val of schemas ) {
121+ if ( val . usedForCurrentFile && val . versions ) {
122+ const item = createSelectVersionItem ( findUsedVersion ( val . versions , val . uri ) , val ) ;
123+ pickItems . unshift ( item ) ;
124+ }
92125 const item = {
93126 label : val . name ?? val . uri ,
94127 description : val . description ,
@@ -98,8 +131,17 @@ async function showSchemaSelection(): Promise<void> {
98131 } ;
99132 pickItems . push ( item ) ;
100133 }
134+ if ( versionSelection ) {
135+ pickItems . unshift ( versionSelection ) ;
136+ }
101137
102- pickItems . sort ( ( a , b ) => {
138+ pickItems = pickItems . sort ( ( a , b ) => {
139+ if ( a . schema ?. usedForCurrentFile && a . schema ?. versions ) {
140+ return - 1 ;
141+ }
142+ if ( b . schema ?. usedForCurrentFile && b . schema ?. versions ) {
143+ return 1 ;
144+ }
103145 if ( a . schema ?. usedForCurrentFile ) {
104146 return - 1 ;
105147 }
@@ -117,23 +159,10 @@ async function showSchemaSelection(): Promise<void> {
117159 schemasPick . onDidChangeSelection ( ( selection ) => {
118160 try {
119161 if ( selection . length > 0 ) {
120- if ( selection [ 0 ] . schema ) {
121- const settings : Record < string , unknown > = workspace . getConfiguration ( 'yaml' ) . get ( 'schemas' ) ;
122- const fileUri = window . activeTextEditor . document . uri . toString ( ) ;
123- const newSettings = Object . assign ( { } , settings ) ;
124- deleteExistingFilePattern ( newSettings , fileUri ) ;
125- const schemaURI = selection [ 0 ] . schema . uri ;
126- const schemaSettings = newSettings [ schemaURI ] ;
127- if ( schemaSettings ) {
128- if ( Array . isArray ( schemaSettings ) ) {
129- ( schemaSettings as Array < string > ) . push ( fileUri ) ;
130- } else if ( typeof schemaSettings === 'string' ) {
131- newSettings [ schemaURI ] = [ schemaSettings , fileUri ] ;
132- }
133- } else {
134- newSettings [ schemaURI ] = fileUri ;
135- }
136- workspace . getConfiguration ( 'yaml' ) . update ( 'schemas' , newSettings ) ;
162+ if ( selection [ 0 ] . label === selectVersionLabel ) {
163+ handleSchemaVersionSelection ( selection [ 0 ] . schema ) ;
164+ } else if ( selection [ 0 ] . schema ) {
165+ writeSchemaUriMapping ( selection [ 0 ] . schema . uri ) ;
137166 }
138167 }
139168 } catch ( err ) {
@@ -162,3 +191,77 @@ function deleteExistingFilePattern(settings: Record<string, unknown>, fileUri: s
162191
163192 return settings ;
164193}
194+
195+ function createSelectVersionItem ( version : string , schema : MatchingJSONSchema ) : SchemaItem {
196+ return {
197+ label : selectVersionLabel ,
198+ detail : `Current: ${ version } ` ,
199+ alwaysShow : true ,
200+ schema : schema ,
201+ } ;
202+ }
203+ function findSchemaStoreItem ( schemas : JSONSchema [ ] , url : string ) : [ string , JSONSchema ] | undefined {
204+ for ( const schema of schemas ) {
205+ if ( schema . versions ) {
206+ for ( const version in schema . versions ) {
207+ if ( url === schema . versions [ version ] ) {
208+ return [ version , schema ] ;
209+ }
210+ }
211+ }
212+ }
213+ }
214+
215+ function writeSchemaUriMapping ( schemaUrl : string ) : void {
216+ const settings : Record < string , unknown > = workspace . getConfiguration ( 'yaml' ) . get ( 'schemas' ) ;
217+ const fileUri = window . activeTextEditor . document . uri . toString ( ) ;
218+ const newSettings = Object . assign ( { } , settings ) ;
219+ deleteExistingFilePattern ( newSettings , fileUri ) ;
220+ const schemaSettings = newSettings [ schemaUrl ] ;
221+ if ( schemaSettings ) {
222+ if ( Array . isArray ( schemaSettings ) ) {
223+ ( schemaSettings as Array < string > ) . push ( fileUri ) ;
224+ } else if ( typeof schemaSettings === 'string' ) {
225+ newSettings [ schemaUrl ] = [ schemaSettings , fileUri ] ;
226+ }
227+ } else {
228+ newSettings [ schemaUrl ] = fileUri ;
229+ }
230+ workspace . getConfiguration ( 'yaml' ) . update ( 'schemas' , newSettings ) ;
231+ }
232+
233+ function handleSchemaVersionSelection ( schema : MatchingJSONSchema ) : void {
234+ const versionPick = window . createQuickPick < SchemaVersionItem > ( ) ;
235+ const versionItems : SchemaVersionItem [ ] = [ ] ;
236+ const usedVersion = findUsedVersion ( schema . versions , schema . uri ) ;
237+ for ( const version in schema . versions ) {
238+ versionItems . push ( {
239+ label : version + ( usedVersion === version ? '$(check)' : '' ) ,
240+ url : schema . versions [ version ] ,
241+ version : version ,
242+ } ) ;
243+ }
244+
245+ versionPick . items = versionItems ;
246+ versionPick . title = `Select JSON Schema version for ${ schema . name } ` ;
247+ versionPick . placeholder = 'Version' ;
248+ versionPick . onDidHide ( ( ) => versionPick . dispose ( ) ) ;
249+
250+ versionPick . onDidChangeSelection ( ( items ) => {
251+ if ( items && items . length === 1 ) {
252+ writeSchemaUriMapping ( items [ 0 ] . url ) ;
253+ }
254+ versionPick . hide ( ) ;
255+ } ) ;
256+ versionPick . show ( ) ;
257+ }
258+
259+ function findUsedVersion ( versions : SchemaVersions , uri : string ) : string {
260+ for ( const version in versions ) {
261+ const versionUri = versions [ version ] ;
262+ if ( versionUri === uri ) {
263+ return version ;
264+ }
265+ }
266+ return 'latest' ;
267+ }
0 commit comments