1- import { dirname } from 'path' ;
1+ import { dirname , join } from 'path' ;
22import ts from 'typescript' ;
33import { TextDocumentContentChangeEvent } from 'vscode-languageserver' ;
44import { Document , DocumentManager } from '../../lib/documents' ;
@@ -19,8 +19,10 @@ import {
1919 LanguageServiceContainer ,
2020 LanguageServiceDocumentContext
2121} from './service' ;
22+ import { createProjectService } from './serviceCache' ;
2223import { GlobalSnapshotsManager , SnapshotManager } from './SnapshotManager' ;
2324import { isSubPath } from './utils' ;
25+ import { FileMap } from '../../lib/documents/fileCollection' ;
2426
2527interface LSAndTSDocResolverOptions {
2628 notifyExceedSizeLimit ?: ( ) => void ;
@@ -71,6 +73,40 @@ export class LSAndTSDocResolver {
7173 this . getCanonicalFileName = createGetCanonicalFileName (
7274 ( options ?. tsSystem ?? ts . sys ) . useCaseSensitiveFileNames
7375 ) ;
76+
77+ this . tsSystem = this . wrapWithPackageJsonMonitoring ( this . options ?. tsSystem ?? ts . sys ) ;
78+ this . globalSnapshotsManager = new GlobalSnapshotsManager ( this . tsSystem ) ;
79+ this . userPreferencesAccessor = { preferences : this . getTsUserPreferences ( ) } ;
80+ const projectService = createProjectService ( this . tsSystem , this . userPreferencesAccessor ) ;
81+
82+ configManager . onChange ( ( ) => {
83+ const newPreferences = this . getTsUserPreferences ( ) ;
84+ const autoImportConfigChanged =
85+ newPreferences . includePackageJsonAutoImports !==
86+ this . userPreferencesAccessor . preferences . includePackageJsonAutoImports ;
87+
88+ this . userPreferencesAccessor . preferences = newPreferences ;
89+
90+ if ( autoImportConfigChanged ) {
91+ forAllServices ( ( service ) => {
92+ service . onAutoImportProviderSettingsChanged ( ) ;
93+ } ) ;
94+ }
95+ } ) ;
96+
97+ this . watchers = new FileMap ( this . tsSystem . useCaseSensitiveFileNames ) ;
98+ this . lsDocumentContext = {
99+ ambientTypesSource : this . options ?. isSvelteCheck ? 'svelte-check' : 'svelte2tsx' ,
100+ createDocument : this . createDocument ,
101+ transformOnTemplateError : ! this . options ?. isSvelteCheck ,
102+ globalSnapshotsManager : this . globalSnapshotsManager ,
103+ notifyExceedSizeLimit : this . options ?. notifyExceedSizeLimit ,
104+ extendedConfigCache : this . extendedConfigCache ,
105+ onProjectReloaded : this . options ?. onProjectReloaded ,
106+ watchTsConfig : ! ! this . options ?. watch ,
107+ tsSystem : this . tsSystem ,
108+ projectService : projectService
109+ } ;
74110 }
75111
76112 /**
@@ -89,26 +125,15 @@ export class LSAndTSDocResolver {
89125 return document ;
90126 } ;
91127
92- private globalSnapshotsManager = new GlobalSnapshotsManager (
93- this . lsDocumentContext . tsSystem ,
94- /* watchPackageJson */ ! ! this . options ?. watch
95- ) ;
128+ private tsSystem : ts . System ;
129+ private globalSnapshotsManager : GlobalSnapshotsManager ;
96130 private extendedConfigCache = new Map < string , ts . ExtendedConfigCacheEntry > ( ) ;
97131 private getCanonicalFileName : GetCanonicalFileName ;
98132
99- private get lsDocumentContext ( ) : LanguageServiceDocumentContext {
100- return {
101- ambientTypesSource : this . options ?. isSvelteCheck ? 'svelte-check' : 'svelte2tsx' ,
102- createDocument : this . createDocument ,
103- transformOnTemplateError : ! this . options ?. isSvelteCheck ,
104- globalSnapshotsManager : this . globalSnapshotsManager ,
105- notifyExceedSizeLimit : this . options ?. notifyExceedSizeLimit ,
106- extendedConfigCache : this . extendedConfigCache ,
107- onProjectReloaded : this . options ?. onProjectReloaded ,
108- watchTsConfig : ! ! this . options ?. watch ,
109- tsSystem : this . options ?. tsSystem ?? ts . sys
110- } ;
111- }
133+ private userPreferencesAccessor : { preferences : ts . UserPreferences } ;
134+ private readonly watchers : FileMap < ts . FileWatcher > ;
135+
136+ private lsDocumentContext : LanguageServiceDocumentContext ;
112137
113138 async getLSForPath ( path : string ) {
114139 return ( await this . getTSService ( path ) ) . getService ( ) ;
@@ -251,4 +276,73 @@ export class LSAndTSDocResolver {
251276 nearestWorkspaceUri ? urlToPath ( nearestWorkspaceUri ) : null
252277 ) ;
253278 }
279+
280+ private getTsUserPreferences ( ) {
281+ return this . configManager . getTsUserPreferences ( 'typescript' , null ) ;
282+ }
283+
284+ private wrapWithPackageJsonMonitoring ( sys : ts . System ) : ts . System {
285+ if ( ! sys . watchFile || ! this . options ?. watch ) {
286+ return sys ;
287+ }
288+
289+ const watchFile = sys . watchFile ;
290+ return {
291+ ...sys ,
292+ readFile : ( path , encoding ) => {
293+ if ( path . endsWith ( 'package.json' ) && ! this . watchers . has ( path ) ) {
294+ this . watchers . set (
295+ path ,
296+ watchFile ( path , this . onPackageJsonWatchChange . bind ( this ) , 3_000 )
297+ ) ;
298+ }
299+
300+ return sys . readFile ( path , encoding ) ;
301+ }
302+ } ;
303+ }
304+
305+ private onPackageJsonWatchChange ( path : string , onWatchChange : ts . FileWatcherEventKind ) {
306+ const dir = dirname ( path ) ;
307+ const projectService = this . lsDocumentContext . projectService ;
308+ const packageJsonCache = projectService ?. packageJsonCache ;
309+ const normalizedPath = projectService ?. toPath ( path ) ;
310+
311+ if ( onWatchChange === ts . FileWatcherEventKind . Deleted ) {
312+ this . watchers . get ( path ) ?. close ( ) ;
313+ this . watchers . delete ( path ) ;
314+ packageJsonCache ?. delete ( normalizedPath ) ;
315+ } else {
316+ packageJsonCache ?. addOrUpdate ( normalizedPath ) ;
317+ }
318+
319+ forAllServices ( ( service ) => {
320+ service . onPackageJsonChange ( path ) ;
321+ } ) ;
322+ if ( ! path . includes ( 'node_modules' ) ) {
323+ return ;
324+ }
325+
326+ setTimeout ( ( ) => {
327+ this . updateSnapshotsInDirectory ( dir ) ;
328+ const realPath =
329+ this . tsSystem . realpath &&
330+ this . getCanonicalFileName ( normalizePath ( this . tsSystem . realpath ?.( dir ) ) ) ;
331+
332+ // pnpm
333+ if ( realPath && realPath !== dir ) {
334+ this . updateSnapshotsInDirectory ( realPath ) ;
335+ const realPkgPath = join ( realPath , 'package.json' ) ;
336+ forAllServices ( ( service ) => {
337+ service . onPackageJsonChange ( realPkgPath ) ;
338+ } ) ;
339+ }
340+ } , 500 ) ;
341+ }
342+
343+ private updateSnapshotsInDirectory ( dir : string ) {
344+ this . globalSnapshotsManager . getByPrefix ( dir ) . forEach ( ( snapshot ) => {
345+ this . globalSnapshotsManager . updateTsOrJsFile ( snapshot . filePath ) ;
346+ } ) ;
347+ }
254348}
0 commit comments