@@ -76,29 +76,29 @@ let telemetryReporter: TelemetryReporter | undefined;
7676
7777export function activate ( context : ExtensionContext ) {
7878
79- let toDispose = context . subscriptions ;
79+ const toDispose = context . subscriptions ;
8080
8181 let rangeFormatting : Disposable | undefined = undefined ;
8282
83- let packageInfo = getPackageInfo ( context ) ;
83+ const packageInfo = getPackageInfo ( context ) ;
8484 telemetryReporter = packageInfo && new TelemetryReporter ( packageInfo . name , packageInfo . version , packageInfo . aiKey ) ;
8585
86- let serverMain = readJSONFile ( context . asAbsolutePath ( './server/package.json' ) ) . main ;
87- let serverModule = context . asAbsolutePath ( path . join ( 'server' , serverMain ) ) ;
86+ const serverMain = readJSONFile ( context . asAbsolutePath ( './server/package.json' ) ) . main ;
87+ const serverModule = context . asAbsolutePath ( path . join ( 'server' , serverMain ) ) ;
8888
8989 // The debug options for the server
90- let debugOptions = { execArgv : [ '--nolazy' , '--inspect=' + ( 9000 + Math . round ( Math . random ( ) * 10000 ) ) ] } ;
90+ const debugOptions = { execArgv : [ '--nolazy' , '--inspect=' + ( 9000 + Math . round ( Math . random ( ) * 10000 ) ) ] } ;
9191
9292 // If the extension is launch in debug mode the debug server options are use
9393 // Otherwise the run options are used
94- let serverOptions : ServerOptions = {
94+ const serverOptions : ServerOptions = {
9595 run : { module : serverModule , transport : TransportKind . ipc } ,
9696 debug : { module : serverModule , transport : TransportKind . ipc , options : debugOptions }
9797 } ;
9898
99- let documentSelector = [ 'json' , 'jsonc' ] ;
99+ const documentSelector = [ 'json' , 'jsonc' ] ;
100100
101- let schemaResolutionErrorStatusBarItem = window . createStatusBarItem ( {
101+ const schemaResolutionErrorStatusBarItem = window . createStatusBarItem ( {
102102 id : 'status.json.resolveError' ,
103103 name : localize ( 'json.resolveError' , "JSON: Schema Resolution Error" ) ,
104104 alignment : StatusBarAlignment . Right ,
@@ -109,10 +109,10 @@ export function activate(context: ExtensionContext) {
109109 schemaResolutionErrorStatusBarItem . text = '$(alert)' ;
110110 toDispose . push ( schemaResolutionErrorStatusBarItem ) ;
111111
112- let fileSchemaErrors = new Map < string , string > ( ) ;
112+ const fileSchemaErrors = new Map < string , string > ( ) ;
113113
114114 // Options to control the language client
115- let clientOptions : LanguageClientOptions = {
115+ const clientOptions : LanguageClientOptions = {
116116 // Register the server for json documents
117117 documentSelector,
118118 initializationOptions : {
@@ -172,17 +172,17 @@ export function activate(context: ExtensionContext) {
172172 } ;
173173
174174 // Create the language client and start the client.
175- let client = new LanguageClient ( 'json' , localize ( 'jsonserver.name' , 'JSON Language Server' ) , serverOptions , clientOptions ) ;
175+ const client = new LanguageClient ( 'json' , localize ( 'jsonserver.name' , 'JSON Language Server' ) , serverOptions , clientOptions ) ;
176176 client . registerProposedFeatures ( ) ;
177177
178- let disposable = client . start ( ) ;
178+ const disposable = client . start ( ) ;
179179 toDispose . push ( disposable ) ;
180180 client . onReady ( ) . then ( ( ) => {
181181 const schemaDocuments : { [ uri : string ] : boolean } = { } ;
182182
183183 // handle content request
184184 client . onRequest ( VSCodeContentRequest . type , ( uriPath : string ) => {
185- let uri = Uri . parse ( uriPath ) ;
185+ const uri = Uri . parse ( uriPath ) ;
186186 if ( uri . scheme !== 'http' && uri . scheme !== 'https' ) {
187187 return workspace . openTextDocument ( uri ) . then ( doc => {
188188 schemaDocuments [ uri . toString ( ) ] = true ;
@@ -212,15 +212,15 @@ export function activate(context: ExtensionContext) {
212212 }
213213 } ) ;
214214
215- let handleContentChange = ( uriString : string ) => {
215+ const handleContentChange = ( uriString : string ) => {
216216 if ( schemaDocuments [ uriString ] ) {
217217 client . sendNotification ( SchemaContentChangeNotification . type , uriString ) ;
218218 return true ;
219219 }
220220 return false ;
221221 } ;
222222
223- let handleActiveEditorChange = ( activeEditor ?: TextEditor ) => {
223+ const handleActiveEditorChange = ( activeEditor ?: TextEditor ) => {
224224 if ( ! activeEditor ) {
225225 return ;
226226 }
@@ -244,7 +244,7 @@ export function activate(context: ExtensionContext) {
244244 } ) ) ;
245245 toDispose . push ( window . onDidChangeActiveTextEditor ( handleActiveEditorChange ) ) ;
246246
247- let handleRetryResolveSchemaCommand = ( ) => {
247+ const handleRetryResolveSchemaCommand = ( ) => {
248248 if ( window . activeTextEditor ) {
249249 schemaResolutionErrorStatusBarItem . text = '$(watch)' ;
250250 const activeDocUri = window . activeTextEditor . document . uri . toString ( ) ;
@@ -282,7 +282,7 @@ export function activate(context: ExtensionContext) {
282282
283283 } ) ;
284284
285- let languageConfiguration : LanguageConfiguration = {
285+ const languageConfiguration : LanguageConfiguration = {
286286 wordPattern : / ( " (?: [ ^ \\ \" ] * (?: \\ .) ? ) * " ? ) | [ ^ \s { } \[ \] , : ] + / ,
287287 indentationRules : {
288288 increaseIndentPattern : / ( { + (? = ( [ ^ " ] * " [ ^ " ] * " ) * [ ^ " } ] * $ ) ) | ( \[ + (? = ( [ ^ " ] * " [ ^ " ] * " ) * [ ^ " \] ] * $ ) ) / ,
@@ -300,7 +300,7 @@ export function activate(context: ExtensionContext) {
300300 } else if ( formatEnabled && ! rangeFormatting ) {
301301 rangeFormatting = languages . registerDocumentRangeFormattingEditProvider ( documentSelector , {
302302 provideDocumentRangeFormattingEdits ( document : TextDocument , range : Range , options : FormattingOptions , token : CancellationToken ) : ProviderResult < TextEdit [ ] > {
303- let params : DocumentRangeFormattingParams = {
303+ const params : DocumentRangeFormattingParams = {
304304 textDocument : client . code2ProtocolConverter . asTextDocumentIdentifier ( document ) ,
305305 range : client . code2ProtocolConverter . asRange ( range ) ,
306306 options : client . code2ProtocolConverter . asFormattingOptions ( options )
@@ -325,11 +325,11 @@ export function deactivate(): Promise<any> {
325325}
326326
327327function getSchemaAssociation ( _context : ExtensionContext ) : ISchemaAssociations {
328- let associations : ISchemaAssociations = { } ;
328+ const associations : ISchemaAssociations = { } ;
329329 extensions . all . forEach ( extension => {
330- let packageJSON = extension . packageJSON ;
330+ const packageJSON = extension . packageJSON ;
331331 if ( packageJSON && packageJSON . contributes && packageJSON . contributes . jsonValidation ) {
332- let jsonValidation = packageJSON . contributes . jsonValidation ;
332+ const jsonValidation = packageJSON . contributes . jsonValidation ;
333333 if ( Array . isArray ( jsonValidation ) ) {
334334 jsonValidation . forEach ( jv => {
335335 let { fileMatch, url } = jv ;
@@ -359,11 +359,11 @@ function getSchemaAssociation(_context: ExtensionContext): ISchemaAssociations {
359359}
360360
361361function getSettings ( ) : Settings {
362- let httpSettings = workspace . getConfiguration ( 'http' ) ;
362+ const httpSettings = workspace . getConfiguration ( 'http' ) ;
363363
364- let resultLimit : number = Math . trunc ( Math . max ( 0 , Number ( workspace . getConfiguration ( ) . get ( 'json.maxItemsComputed' ) ) ) ) || 5000 ;
364+ const resultLimit : number = Math . trunc ( Math . max ( 0 , Number ( workspace . getConfiguration ( ) . get ( 'json.maxItemsComputed' ) ) ) ) || 5000 ;
365365
366- let settings : Settings = {
366+ const settings : Settings = {
367367 http : {
368368 proxy : httpSettings . get ( 'proxy' ) ,
369369 proxyStrictSSL : httpSettings . get ( 'proxyStrictSSL' )
@@ -373,10 +373,18 @@ function getSettings(): Settings {
373373 resultLimit
374374 }
375375 } ;
376- let schemaSettingsById : { [ schemaId : string ] : JSONSchemaSettings } = Object . create ( null ) ;
377- let collectSchemaSettings = ( schemaSettings : JSONSchemaSettings [ ] , rootPath ?: string , fileMatchPrefix ?: string ) => {
378- for ( let setting of schemaSettings ) {
379- let url = getSchemaId ( setting , rootPath ) ;
376+ const schemaSettingsById : { [ schemaId : string ] : JSONSchemaSettings } = Object . create ( null ) ;
377+ const collectSchemaSettings = ( schemaSettings : JSONSchemaSettings [ ] , folderUri ?: Uri , isMultiRoot ?: boolean ) => {
378+
379+ let fileMatchPrefix = undefined ;
380+ if ( folderUri && isMultiRoot ) {
381+ fileMatchPrefix = folderUri . toString ( ) ;
382+ if ( fileMatchPrefix [ fileMatchPrefix . length - 1 ] === '/' ) {
383+ fileMatchPrefix = fileMatchPrefix . substr ( 0 , fileMatchPrefix . length - 1 ) ;
384+ }
385+ }
386+ for ( const setting of schemaSettings ) {
387+ const url = getSchemaId ( setting , folderUri ) ;
380388 if ( ! url ) {
381389 continue ;
382390 }
@@ -385,69 +393,78 @@ function getSettings(): Settings {
385393 schemaSetting = schemaSettingsById [ url ] = { url, fileMatch : [ ] } ;
386394 settings . json ! . schemas ! . push ( schemaSetting ) ;
387395 }
388- let fileMatches = setting . fileMatch ;
389- let resultingFileMatches = schemaSetting . fileMatch ! ;
396+ const fileMatches = setting . fileMatch ;
390397 if ( Array . isArray ( fileMatches ) ) {
391- if ( fileMatchPrefix ) {
392- for ( let fileMatch of fileMatches ) {
398+ const resultingFileMatches = schemaSetting . fileMatch || [ ] ;
399+ schemaSetting . fileMatch = resultingFileMatches ;
400+ const addMatch = ( pattern : string ) => { // filter duplicates
401+ if ( resultingFileMatches . indexOf ( pattern ) === - 1 ) {
402+ resultingFileMatches . push ( pattern ) ;
403+ }
404+ } ;
405+ for ( const fileMatch of fileMatches ) {
406+ if ( fileMatchPrefix ) {
393407 if ( fileMatch [ 0 ] === '/' ) {
394- resultingFileMatches . push ( fileMatchPrefix + fileMatch ) ;
395- resultingFileMatches . push ( fileMatchPrefix + '/*' + fileMatch ) ;
408+ addMatch ( fileMatchPrefix + fileMatch ) ;
409+ addMatch ( fileMatchPrefix + '/*' + fileMatch ) ;
396410 } else {
397- resultingFileMatches . push ( fileMatchPrefix + '/' + fileMatch ) ;
398- resultingFileMatches . push ( fileMatchPrefix + '/*/' + fileMatch ) ;
411+ addMatch ( fileMatchPrefix + '/' + fileMatch ) ;
412+ addMatch ( fileMatchPrefix + '/*/' + fileMatch ) ;
399413 }
414+ } else {
415+ addMatch ( fileMatch ) ;
400416 }
401- } else {
402- resultingFileMatches . push ( ...fileMatches ) ;
403417 }
404-
405418 }
406- if ( setting . schema ) {
419+ if ( setting . schema && ! schemaSetting . schema ) {
407420 schemaSetting . schema = setting . schema ;
408421 }
409422 }
410423 } ;
411424
425+ const folders = workspace . workspaceFolders ;
426+
412427 // merge global and folder settings. Qualify all file matches with the folder path.
413- let globalSettings = workspace . getConfiguration ( 'json' , null ) . get < JSONSchemaSettings [ ] > ( 'schemas' ) ;
428+ const globalSettings = workspace . getConfiguration ( 'json' , null ) . get < JSONSchemaSettings [ ] > ( 'schemas' ) ;
414429 if ( Array . isArray ( globalSettings ) ) {
415- collectSchemaSettings ( globalSettings , workspace . rootPath ) ;
430+ if ( ! folders ) {
431+ collectSchemaSettings ( globalSettings ) ;
432+ }
416433 }
417- let folders = workspace . workspaceFolders ;
418434 if ( folders ) {
419- for ( let folder of folders ) {
420- let folderUri = folder . uri ;
435+ const isMultiRoot = folders . length > 1 ;
436+ for ( const folder of folders ) {
437+ const folderUri = folder . uri ;
421438
422- let schemaConfigInfo = workspace . getConfiguration ( 'json' , folderUri ) . inspect < JSONSchemaSettings [ ] > ( 'schemas' ) ;
439+ const schemaConfigInfo = workspace . getConfiguration ( 'json' , folderUri ) . inspect < JSONSchemaSettings [ ] > ( 'schemas' ) ;
423440
424- let folderSchemas = schemaConfigInfo ! . workspaceFolderValue ;
441+ const folderSchemas = schemaConfigInfo ! . workspaceFolderValue ;
425442 if ( Array . isArray ( folderSchemas ) ) {
426- let folderPath = folderUri . toString ( ) ;
427- if ( folderPath [ folderPath . length - 1 ] === '/' ) {
428- folderPath = folderPath . substr ( 0 , folderPath . length - 1 ) ;
429- }
430- collectSchemaSettings ( folderSchemas , folderUri . fsPath , folderPath ) ;
443+ collectSchemaSettings ( folderSchemas , folderUri , isMultiRoot ) ;
431444 }
445+ if ( Array . isArray ( globalSettings ) ) {
446+ collectSchemaSettings ( globalSettings , folderUri , isMultiRoot ) ;
447+ }
448+
432449 }
433450 }
434451 return settings ;
435452}
436453
437- function getSchemaId ( schema : JSONSchemaSettings , rootPath ?: string ) {
454+ function getSchemaId ( schema : JSONSchemaSettings , folderUri ?: Uri ) {
438455 let url = schema . url ;
439456 if ( ! url ) {
440457 if ( schema . schema ) {
441458 url = schema . schema . id || `vscode://schemas/custom/${ encodeURIComponent ( hash ( schema . schema ) . toString ( 16 ) ) } ` ;
442459 }
443- } else if ( rootPath && ( url [ 0 ] === '.' || url [ 0 ] === '/' ) ) {
444- url = Uri . file ( path . normalize ( path . join ( rootPath , url ) ) ) . toString ( ) ;
460+ } else if ( folderUri && ( url [ 0 ] === '.' || url [ 0 ] === '/' ) ) {
461+ url = folderUri . with ( { path : path . posix . join ( folderUri . path , url ) } ) . toString ( ) ;
445462 }
446463 return url ;
447464}
448465
449466function getPackageInfo ( context : ExtensionContext ) : IPackageInfo | undefined {
450- let extensionPackage = readJSONFile ( context . asAbsolutePath ( './package.json' ) ) ;
467+ const extensionPackage = readJSONFile ( context . asAbsolutePath ( './package.json' ) ) ;
451468 if ( extensionPackage ) {
452469 return {
453470 name : extensionPackage . name ,
0 commit comments