import ts from 'typescript' ; import { DocumentSnapshot , JSOrTSDocumentSnapshot } from './DocumentSnapshot' ; import { Logger } from '../../logger' ; import { TextDocumentContentChangeEvent } from 'vscode-languageserver' ; import { normalizePath } from '../../utils' ; import { EventEmitter } from 'events' ; /**
 * Every snapshot corresponds to a unique file on disk.
 * A snapshot can be part of multiple projects, but for a given file path
 * there can be only one snapshot.
 */ export class GlobalSnapshotsManager { private emitter = new EventEmitter ( ) ; private documents = new Map < string , DocumentSnapshot > ( ) ; get ( fileName ) { fileName = normalizePath ( fileName ) ; return this . documents . get ( fileName ) ; } set ( fileName , document ) { fileName = normalizePath ( fileName ) ; const prev = this . get ( fileName ) ; if ( prev ) { prev . destroyFragment ( ) ; } this . documents . set ( fileName , document ) ; this . emitter . emit ( 'change' , fileName , document ) ; } delete ( fileName ) { fileName = normalizePath ( fileName ) ; this . documents . delete ( fileName ) ; this . emitter . emit ( 'change' , fileName , undefined ) ; } updateTsOrJsFile ( fileName , changes ? ) { fileName = normalizePath ( fileName ) ; const previousSnapshot = this . get ( fileName ) ; if ( changes ) { if ( ! ( previousSnapshot instanceof JSOrTSDocumentSnapshot ) ) { return ; } previousSnapshot . update ( changes ) ; this . emitter . emit ( 'change' , fileName , previousSnapshot ) ; return previousSnapshot ; } else { const newSnapshot = DocumentSnapshot . fromNonSvelteFilePath ( fileName ) ; if ( previousSnapshot ) { newSnapshot . version = previousSnapshot . version + 1 ; } else { newSnapshot . version += 1 ; } this . set ( fileName , newSnapshot ) ; return newSnapshot ; } } onChange ( listener ) { this . emitter . on ( 'change' , listener ) ; } } export interface TsFilesSpec { include ? : readonly string [ ] ; exclude ? : readonly string [ ] ; } /**
 * Should only be used by `service.ts`
 */ export class SnapshotManager { private documents = new Map < string , DocumentSnapshot > ( ) ; private lastLogged = new Date ( new Date ( ) . getTime ( ) - 60001 ) ; private readonly watchExtensions = [ ts . Extension . Dts , ts . Extension . Js , ts . Extension . Jsx , ts . Extension . Ts , ts . Extension . Tsx , ts . Extension . Json ] ; constructor ( private globalSnapshotsManager , private projectFiles , private fileSpec , private workspaceRoot ) { this . globalSnapshotsManager . onChange ( ( fileName , document ) => { if ( ! document ) { this . documents . delete ( fileName ) ; } else if ( this . documents . has ( fileName ) ) { this . documents . set ( fileName , document ) ; } } ) ; } updateProjectFiles ( ) { const { include , exclude } = this . fileSpec ; if ( include ?. length === 0 ) { return ; } const projectFiles = ts . sys . readDirectory ( this . workspaceRoot , this . watchExtensions , exclude , include ) . map ( normalizePath ) ; this . projectFiles = Array . from ( new Set ( [ ... this . projectFiles , ... projectFiles ] ) ) ; } updateTsOrJsFile ( fileName , changes ? ) { const snapshot = this . globalSnapshotsManager . updateTsOrJsFile ( fileName , changes ) ; if ( snapshot ) { this . documents . set ( normalizePath ( fileName ) , snapshot ) ; } } has ( fileName ) { fileName = normalizePath ( fileName ) ; return this . projectFiles . includes ( fileName ) || this . getFileNames ( ) . includes ( fileName ) ; } set ( fileName , snapshot ) { this . globalSnapshotsManager . set ( fileName , snapshot ) ; this . documents . set ( normalizePath ( fileName ) , snapshot ) ; this . logStatistics ( ) ; } get ( fileName ) { fileName = normalizePath ( fileName ) ; let snapshot = this . documents . get ( fileName ) ; if ( ! snapshot ) { snapshot = this . globalSnapshotsManager . get ( fileName ) ; if ( snapshot ) { this . documents . set ( fileName , snapshot ) ; } } return snapshot ; } delete ( fileName ) { fileName = normalizePath ( fileName ) ; this . projectFiles = this . projectFiles . filter ( ( s ) => s !== fileName ) ; this . globalSnapshotsManager . delete ( fileName ) ; } getFileNames ( ) { return Array . from ( this . documents . keys ( ) ) ; } getProjectFileNames ( ) { return [ ... this . projectFiles ] ; } private logStatistics ( ) { const date = new Date ( ) ; if ( date . getTime ( ) - this . lastLogged . getTime ( ) > 60000 ) { this . lastLogged = date ; const projectFiles = this . getProjectFileNames ( ) ; const allFiles = Array . from ( new Set ( [ ... projectFiles , ... this . getFileNames ( ) ] ) ) ; Logger . log ( 'SnapshotManager File Statistics:\n' + `Project files: ${ projectFiles . length }\n` + `Svelte files: ${ allFiles . filter ( ( name ) => name . endsWith ( '.svelte' ) ) . length }\n` + `From node_modules: ${ allFiles . filter ( ( name ) => name . includes ( 'node_modules' ) ) . length }\n` + `Total: ${ allFiles . length }` ) ; } } } export const ignoredBuildDirectories = [ '__sapper__' , '.svelte-kit' ] ;