import { CancellationToken , CodeAction , CodeActionContext , CompletionContext , CompletionList , Diagnostic , FormattingOptions , Hover , Position , Range , SelectionRange , TextEdit , WorkspaceEdit } from 'vscode-languageserver' ; import { getPackageInfo , importPrettier } from '../../importPackage' ; import { Document } from '../../lib/documents' ; import { Logger } from '../../logger' ; import { LSConfigManager , LSSvelteConfig } from '../../ls-config' ; import { CodeActionsProvider , CompletionsProvider , DiagnosticsProvider , FormattingProvider , HoverProvider , SelectionRangeProvider } from '../interfaces' ; import { executeCommand , getCodeActions } from './features/getCodeActions' ; import { getCompletions } from './features/getCompletions' ; import { getDiagnostics } from './features/getDiagnostics' ; import { getHoverInfo } from './features/getHoverInfo' ; import { getSelectionRange } from './features/getSelectionRanges' ; import { SvelteCompileResult , SvelteDocument } from './SvelteDocument' ; export class SveltePlugin implements DiagnosticsProvider , FormattingProvider , CompletionsProvider , HoverProvider , CodeActionsProvider , SelectionRangeProvider { private docManager = new Map < Document , SvelteDocument > ( ) ; constructor ( private configManager ) { } async getDiagnostics ( document ) { if ( ! this . featureEnabled ( 'diagnostics' ) || ! this . configManager . getIsTrusted ( ) ) { return [ ] ; } return getDiagnostics ( document , await this . getSvelteDoc ( document ) , this . configManager . getConfig ( ) . svelte . compilerWarnings ) ; } async getCompiledResult ( document ) { try { const svelteDoc = await this . getSvelteDoc ( document ) ; return svelteDoc . getCompiledWith ( { generate : 'dom' } ) ; } catch ( error ) { return null ; } } async formatDocument ( document , options ) { if ( ! this . featureEnabled ( 'format' ) ) { return [ ] ; } const filePath = document . getFilePath ( ) ! ; const prettier = importPrettier ( filePath ) ; const config = this . configManager . getMergedPrettierConfig ( await prettier . resolveConfig ( filePath , { editorconfig : true } ) , options && { tabWidth : options . tabSize , useTabs : ! options . insertSpaces } ) ; if ( config ?. svelteSortOrder && getPackageInfo ( 'prettier-plugin-svelte' , filePath ) ?. version . major < 2 ) { config . svelteSortOrder = config . svelteSortOrder . replace ( '-options' , '' ) . replace ( 'options-' , '' ) ; } const fileInfo = await prettier . getFileInfo ( filePath , { ignorePath : this . configManager . getPrettierConfig ( ) ?. ignorePath ?? '.prettierignore' , withNodeModules : true } ) ; if ( fileInfo . ignored ) { Logger . log ( 'File is ignored, formatting skipped' ) ; return [ ] ; } const formattedCode = prettier . format ( document . getText ( ) , { ... config , plugins : getSveltePlugin ( ) , parser : 'svelte' as any } ) ; return document . getText ( ) === formattedCode ? [ ] : [ TextEdit . replace ( Range . create ( document . positionAt ( 0 ) , document . positionAt ( document . getTextLength ( ) ) ) , formattedCode ) ] ; function getSveltePlugin ( ) { const hasPluginLoadedAlready = prettier . getSupportInfo ( ) . languages . some ( ( l ) => l . name === 'svelte' ) ; return hasPluginLoadedAlready ? [ ] : [ require . resolve ( 'prettier-plugin-svelte' ) ] ; } } async getCompletions ( document , position , _ ? , cancellationToken ? ) { if ( ! this . featureEnabled ( 'completions' ) ) { return null ; } const svelteDoc = await this . getSvelteDoc ( document ) ; if ( cancellationToken ?. isCancellationRequested ) { return null ; } return getCompletions ( document , svelteDoc , position ) ; } async doHover ( document , position ) { if ( ! this . featureEnabled ( 'hover' ) ) { return null ; } return getHoverInfo ( document , await this . getSvelteDoc ( document ) , position ) ; } async getCodeActions ( document , range , context , cancellationToken ? ) { if ( ! this . featureEnabled ( 'codeActions' ) ) { return [ ] ; } const svelteDoc = await this . getSvelteDoc ( document ) ; if ( cancellationToken ?. isCancellationRequested ) { return [ ] ; } try { return getCodeActions ( svelteDoc , range , context ) ; } catch ( error ) { return [ ] ; } } async executeCommand ( document , command , args ? ) { if ( ! this . featureEnabled ( 'codeActions' ) ) { return null ; } const svelteDoc = await this . getSvelteDoc ( document ) ; try { return executeCommand ( svelteDoc , command , args ) ; } catch ( error ) { return null ; } } async getSelectionRange ( document , position ) { if ( ! this . featureEnabled ( 'selectionRange' ) ) { return null ; } const svelteDoc = await this . getSvelteDoc ( document ) ; return getSelectionRange ( svelteDoc , position ) ; } private featureEnabled ( feature ) { return ( this . configManager . enabled ( 'svelte.enable' ) && this . configManager . enabled ( `svelte.${ feature }.enable` ) ) ; } private async getSvelteDoc ( document ) { let svelteDoc = this . docManager . get ( document ) ; if ( ! svelteDoc || svelteDoc . version !== document . version ) { svelteDoc ?. destroyTranspiled ( ) ; svelteDoc = new SvelteDocument ( document ) ; this . docManager . set ( document , svelteDoc ) ; } return svelteDoc ; } }