import ts from 'typescript' ; import { TextDocumentContentChangeEvent } from 'vscode-languageserver' ; import { Document , DocumentManager } from '../../lib/documents' ; import { LSConfigManager } from '../../ls-config' ; import { debounceSameArg , normalizePath , pathToUrl } from '../../utils' ; import { DocumentSnapshot , SvelteDocumentSnapshot } from './DocumentSnapshot' ; import { getService , getServiceForTsconfig , forAllServices , LanguageServiceContainer , LanguageServiceDocumentContext } from './service' ; import { GlobalSnapshotsManager , SnapshotManager } from './SnapshotManager' ; export class LSAndTSDocResolver { param docManager param workspaceUris param configManager param notifyExceedSizeLimit param isSvelteCheck param tsconfigPath constructor ( private readonly docManager , private readonly workspaceUris , private readonly configManager , private readonly notifyExceedSizeLimit ? , private readonly isSvelteCheck = false , private readonly tsconfigPath ? ) { const handleDocumentChange = ( document ) => { this . getSnapshot ( document ) ; } ; docManager . on ( 'documentChange' , debounceSameArg ( handleDocumentChange , ( newDoc , prevDoc ) => newDoc . uri === prevDoc ?. uri , 1000 ) ) ; docManager . on ( 'documentOpen' , handleDocumentChange ) ; } /**
     * Create a svelte document -> should only be invoked with svelte files.
     */ private createDocument = ( fileName , content ) => { const uri = pathToUrl ( fileName ) ; const document = this . docManager . openDocument ( { text : content , uri } ) ; this . docManager . lockDocument ( uri ) ; return document ; } ; private globalSnapshotsManager = new GlobalSnapshotsManager ( ) ; private get lsDocumentContext ( ) : LanguageServiceDocumentContext { return { ambientTypesSource : this . isSvelteCheck ? 'svelte-check' : 'svelte2tsx' , createDocument : this . createDocument , transformOnTemplateError : ! this . isSvelteCheck , globalSnapshotsManager : this . globalSnapshotsManager , notifyExceedSizeLimit : this . notifyExceedSizeLimit } ; } async getLSForPath ( path ) { return ( await this . getTSService ( path ) ) . getService ( ) ; } async getLSAndTSDoc ( document ) { const lang = await this . getLSForPath ( document . getFilePath ( ) || '' ) ; const tsDoc = await this . getSnapshot ( document ) ; const userPreferences = this . getUserPreferences ( tsDoc . scriptKind ) ; return { tsDoc , lang , userPreferences } ; } /**
     * Retrieves and updates the snapshot for the given document or path from
     * the ts service it primarely belongs into.
     * The update is mirrored in all other services, too.
     */ async getSnapshot ( document ) ; async getSnapshot ( pathOrDoc ) ; async getSnapshot ( pathOrDoc ) { const filePath = typeof pathOrDoc === 'string' ? pathOrDoc : pathOrDoc . getFilePath ( ) || '' ; const tsService = await this . getTSService ( filePath ) ; return tsService . updateSnapshot ( pathOrDoc ) ; } /**
     * Updates snapshot path in all existing ts services and retrieves snapshot
     */ async updateSnapshotPath ( oldPath , newPath ) { await this . deleteSnapshot ( oldPath ) ; return this . getSnapshot ( newPath ) ; } /**
     * Deletes snapshot in all existing ts services
     */ async deleteSnapshot ( filePath ) { await forAllServices ( ( service ) => service . deleteSnapshot ( filePath ) ) ; this . docManager . releaseDocument ( pathToUrl ( filePath ) ) ; } /**
     * Updates project files in all existing ts services
     */ async updateProjectFiles ( ) { await forAllServices ( ( service ) => service . updateProjectFiles ( ) ) ; } /**
     * Updates file in all ts services where it exists
     */ async updateExistingTsOrJsFile ( path , changes ? ) { path = normalizePath ( path ) ; let didUpdate = false ; await forAllServices ( ( service ) => { if ( service . hasFile ( path ) && ! didUpdate ) { didUpdate = true ; service . updateTsOrJsFile ( path , changes ) ; } } ) ; } internal async getSnapshotManager ( filePath ) { return ( await this . getTSService ( filePath ) ) . snapshotManager ; } async getTSService ( filePath ? ) { if ( this . tsconfigPath ) { return getServiceForTsconfig ( this . tsconfigPath , this . lsDocumentContext ) ; } if ( ! filePath ) { throw new Error ( 'Cannot call getTSService without filePath and without tsconfigPath' ) ; } return getService ( filePath , this . workspaceUris , this . lsDocumentContext ) ; } private getUserPreferences ( scriptKind ) { const configLang = scriptKind === ts . ScriptKind . TS || scriptKind === ts . ScriptKind . TSX ? 'typescript' : 'javascript' ; return this . configManager . getTsUserPreferences ( configLang ) ; } }