import * as path from 'path' ; import { commands as Commands , ExtensionContext , window as Window , workspace as Workspace , FileSystemWatcher , } from 'vscode' ; import { DidChangeWatchedFilesNotification , DidChangeWatchedFilesParams , LanguageClient , LanguageClientOptions , RevealOutputChannelOn , ServerOptions , TransportKind , FileChangeType , Disposable , } from 'vscode-languageclient' ; import { ExtensionSettings } from './configuration' ; import { StartWatcherNotification , StartWatcherParams } from './notifications' ; let client ; let commands = undefined ; /**
 * The set of FileSystemWatcher objects that monitor Spectral configuration
 * files. The key is the path to the config file being watched.
 */ const watchers = new Map < string , FileSystemWatcher > ( ) ; param { string } path return { FileSystemWatcher } function createFileSystemWatcher ( path ) { const watcher = Workspace . createFileSystemWatcher ( path ) ; watcher . onDidChange ( ( event ) => { client . info ( `Ruleset file change: ${ event . fsPath }` ) ; sendFileChangeNotification ( event . toString ( ) , FileChangeType . Changed ) ; } ) ; watcher . onDidDelete ( ( event ) => { client . info ( `Ruleset deleted: ${ event . fsPath }` ) ; sendFileChangeNotification ( event . toString ( ) , FileChangeType . Deleted ) ; } ) ; watcher . onDidCreate ( ( event ) => { client . info ( `Ruleset created: ${ event . fsPath }` ) ; sendFileChangeNotification ( event . toString ( ) , FileChangeType . Created ) ; } ) ; return watcher ; } /**
 * Handles changes in configuration or workspace by disposing existing cached
 * FileSystemWatchers and preparing the cache for new watchers.
 */ function environmentChange ( ) { for ( const watcher of watchers . values ( ) ) { watcher . dispose ( ) ; } watchers . clear ( ) ; } param { string } uri param { FileChangeType } type function sendFileChangeNotification ( uri , type ) { const e = { changes : [ { uri : uri , type : type } ] } ; client . sendNotification ( DidChangeWatchedFilesNotification . type , e ) ; } param { ExtensionContext } context export function activate ( context ) { const serverModule = context . asAbsolutePath ( path . join ( 'server' , 'server.js' ) ) ; const serverOptions = { run : { module : serverModule , transport : TransportKind . ipc , } , debug : { module : serverModule , transport : TransportKind . ipc , options : { execArgv : [ '--nolazy' , '--inspect=6262' ] , } , } , } ; const clientOptions = { documentSelector : [ { scheme : 'file' } , { scheme : 'untitled' } ] , diagnosticCollectionName : 'spectral' , revealOutputChannelOn : RevealOutputChannelOn . Never , initializationFailedHandler : ( error ) => { client . error ( 'Server initialization failed.' , error ) ; client . outputChannel . show ( true ) ; return false ; } , middleware : { workspace : { configuration : async ( params , _token , _next ) : Promise < any [ ] > => { if ( params . items === undefined ) { return [ ] ; } const result = [ ] ; for ( const item of params . items ) { if ( item . section || ! item . scopeUri ) { result . push ( null ) ; continue ; } const resource = client . protocol2CodeConverter . asUri ( item . scopeUri ) ; const config = Workspace . getConfiguration ( 'spectral' , resource ) ; const workspaceFolder = Workspace . getWorkspaceFolder ( resource ) ; const settings = { enable : config . get ( 'enable' , true ) , rulesetFile : config . get ( 'rulesetFile' , undefined ) , run : config . get ( 'run' , 'onType' ) , validateFiles : config . get ( 'validateFiles' , [ ] ) , validateLanguages : config . get ( 'validateLanguages' , [ 'json' , 'yaml' ] ) , workspaceFolder : undefined , } ; if ( workspaceFolder !== undefined ) { settings . workspaceFolder = { name : workspaceFolder . name , uri : client . code2ProtocolConverter . asUri ( workspaceFolder . uri ) , } ; } result . push ( settings ) ; } return result ; } , didChangeConfiguration : ( event , next ) : void => { environmentChange ( ) ; next ( event ) ; } , didChangeWorkspaceFolders : ( event , next ) : void => { environmentChange ( ) ; next ( event ) ; } , } , } , } ; try { client = new LanguageClient ( 'spectral' , 'Spectral' , serverOptions , clientOptions ) ; } catch ( err ) { Window . showErrorMessage ( `The Spectral extension couldn't be started. See the Spectral output channel for details.` ) ; return ; } client . onReady ( ) . then ( ( ) => { client . onNotification ( StartWatcherNotification . type , ( params ) => { if ( ! watchers . has ( params . path ) ) { client . info ( `Watching ruleset: ${ params . path }` ) ; const watcher = createFileSystemWatcher ( params . path ) ; watchers . set ( params . path , watcher ) ; } } ) ; } ) ; client . start ( ) ; commands = [ Commands . registerCommand ( 'spectral.showOutputChannel' , ( ) => { client . outputChannel . show ( ) ; } ) ] ; } return { Thenable < void > | undefined } export function deactivate ( ) { if ( commands !== undefined ) { commands . forEach ( ( d ) => d . dispose ( ) ) ; commands = undefined ; } if ( ! client ) { return undefined ; } return client . stop ( ) ; }