From c8ae56e4e33f98652bbc4e334cf44fe91a60df84 Mon Sep 17 00:00:00 2001 From: "Lyu, Wei-Da" <36730922+jasonlyu123@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:30:01 +0800 Subject: [PATCH] (fix) only allow client files and project files to be root (#2146) #2132 This PR moved the tracking of "document is open by the client" to document so it can be copied over to ts snapshot and create a new documentManager.openClientDocument to replace openDoucment in existing places. This will mark the file as client files in one method call, so we don't have to add markAsOpenByClient to all existing tests. The reason that we need client files is that files might be opened by the client and not in the project files. One reason is that the user has an empty include in the tsconfig or has the default one. Also, we didn't watch Svelte files with File Watcher. So the new svelte file won't be in the project files. We probably should do it for something like git checkout, but that can be a separate PR. We have to use a TypeScript internal API and add a layer of synchronization because of a module resolution bug. The way getSnapshot prevents the problem before the amount of root files have changed so that TypeScript will check more thoroughly. The existing test is different from how it'll work in typical cases. It probably worked when it was introduced, but we later changed to not run getSnapshot in new ts/js files, so it's not actually preventing the error. --- .../src/lib/documents/Document.ts | 1 + .../src/lib/documents/DocumentManager.ts | 31 +++-- .../src/lib/documents/fileCollection.ts | 4 + .../plugins/typescript/DocumentSnapshot.ts | 13 +++ .../plugins/typescript/LSAndTSDocResolver.ts | 39 ++++++- .../src/plugins/typescript/SnapshotManager.ts | 6 +- .../plugins/typescript/TypeScriptPlugin.ts | 19 ++- .../features/CodeActionsProvider.ts | 1 + .../typescript/features/CompletionProvider.ts | 11 +- .../typescript/features/InlayHintProvider.ts | 6 +- .../src/plugins/typescript/module-loader.ts | 77 +++++++++--- .../src/plugins/typescript/service.ts | 110 ++++++++++++++++-- packages/language-server/src/server.ts | 3 +- packages/language-server/src/svelte-check.ts | 3 +- .../lib/documents/DocumentManager.test.ts | 12 +- .../test/plugins/PluginHost.test.ts | 10 +- .../test/plugins/css/CSSPlugin.test.ts | 2 +- .../css/features/getIdClassCompletion.test.ts | 2 +- .../test/plugins/html/HTMLPlugin.test.ts | 2 +- .../test/plugins/svelte/SveltePlugin.test.ts | 2 +- .../typescript/TypescriptPlugin.test.ts | 2 +- .../features/CallHierarchyProvider.test.ts | 2 +- .../features/CodeActionsProvider.test.ts | 2 +- .../features/CompletionProvider.test.ts | 6 +- .../features/DiagnosticsProvider.test.ts | 43 ++++++- .../FindComponentReferencesProvider.test.ts | 8 +- .../FindFileReferencesProvider.test.ts | 2 +- .../features/FindReferencesProvider.test.ts | 2 +- .../typescript/features/HoverProvider.test.ts | 2 +- .../features/ImplemenationProvider.test.ts | 2 +- .../features/RenameProvider.test.ts | 2 +- .../features/SelectionRangeProvider.test.ts | 2 +- .../features/SemanticTokensProvider.test.ts | 2 +- .../features/SignatureHelpProvider.test.ts | 2 +- .../features/TypeDefinitionProvider.test.ts | 2 +- .../features/UpdateImportsProvider.test.ts | 2 +- .../features/diagnostics/index.test.ts | 2 +- .../features/inlayHints/index.test.ts | 2 +- .../typescript/features/preferences.test.ts | 2 +- .../test/plugins/typescript/test-utils.ts | 7 +- .../typescript/typescript-performance.test.ts | 2 +- 41 files changed, 346 insertions(+), 106 deletions(-) diff --git a/packages/language-server/src/lib/documents/Document.ts b/packages/language-server/src/lib/documents/Document.ts index c18ea25a4..bb69158f6 100644 --- a/packages/language-server/src/lib/documents/Document.ts +++ b/packages/language-server/src/lib/documents/Document.ts @@ -18,6 +18,7 @@ export class Document extends WritableDocument { configPromise: Promise; config?: SvelteConfig; html!: HTMLDocument; + openedByClient = false; /** * Compute and cache directly because of performance reasons * and it will be called anyway. diff --git a/packages/language-server/src/lib/documents/DocumentManager.ts b/packages/language-server/src/lib/documents/DocumentManager.ts index f5be02327..bbf86303b 100644 --- a/packages/language-server/src/lib/documents/DocumentManager.ts +++ b/packages/language-server/src/lib/documents/DocumentManager.ts @@ -16,7 +16,6 @@ export type DocumentEvent = 'documentOpen' | 'documentChange' | 'documentClose'; */ export class DocumentManager { private emitter = new EventEmitter(); - private openedInClient: FileSet; private documents: FileMap; private locked: FileSet; private deleteCandidates: FileSet; @@ -27,13 +26,19 @@ export class DocumentManager { useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames } ) { - this.openedInClient = new FileSet(options.useCaseSensitiveFileNames); this.documents = new FileMap(options.useCaseSensitiveFileNames); this.locked = new FileSet(options.useCaseSensitiveFileNames); this.deleteCandidates = new FileSet(options.useCaseSensitiveFileNames); } - openDocument(textDocument: Pick): Document { + openClientDocument(textDocument: Pick): Document { + return this.openDocument(textDocument, /**openedByClient */ true); + } + + openDocument( + textDocument: Pick, + openedByClient: boolean + ): Document { textDocument = { ...textDocument, uri: normalizeUri(textDocument.uri) @@ -50,6 +55,7 @@ export class DocumentManager { } this.notify('documentChange', document); + document.openedByClient = openedByClient; return document; } @@ -59,24 +65,29 @@ export class DocumentManager { } markAsOpenedInClient(uri: string): void { - this.openedInClient.add(normalizeUri(uri)); + const document = this.documents.get(normalizeUri(uri)); + if (document) { + document.openedByClient = true; + } } getAllOpenedByClient() { - return Array.from(this.documents.entries()).filter((doc) => - this.openedInClient.has(doc[0]) - ); + return Array.from(this.documents.entries()).filter((doc) => doc[1].openedByClient); } isOpenedInClient(uri: string) { - return this.openedInClient.has(normalizeUri(uri)); + const document = this.documents.get(normalizeUri(uri)); + return !!document?.openedByClient; } releaseDocument(uri: string): void { uri = normalizeUri(uri); this.locked.delete(uri); - this.openedInClient.delete(uri); + const document = this.documents.get(uri); + if (document) { + document.openedByClient = false; + } if (this.deleteCandidates.has(uri)) { this.deleteCandidates.delete(uri); this.closeDocument(uri); @@ -100,7 +111,7 @@ export class DocumentManager { this.deleteCandidates.add(uri); } - this.openedInClient.delete(uri); + document.openedByClient = false; } updateDocument( diff --git a/packages/language-server/src/lib/documents/fileCollection.ts b/packages/language-server/src/lib/documents/fileCollection.ts index 27098ce63..5ea5dd5b4 100644 --- a/packages/language-server/src/lib/documents/fileCollection.ts +++ b/packages/language-server/src/lib/documents/fileCollection.ts @@ -91,6 +91,10 @@ export class FileSet implements Iterable { return this.set.delete(this.getCanonicalFileName(filePath)); } + clear() { + this.set.clear(); + } + [Symbol.iterator](): Iterator { return this.set[Symbol.iterator](); } diff --git a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts index ca2d4c858..764e8cfc7 100644 --- a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts +++ b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts @@ -61,6 +61,7 @@ export interface DocumentSnapshot extends ts.IScriptSnapshot, DocumentMapper { * Convenience function for getText(0, getLength()) */ getFullText(): string; + isOpenedInClient(): boolean; } /** @@ -372,6 +373,10 @@ export class SvelteDocumentSnapshot implements DocumentSnapshot { return this.url; } + isOpenedInClient() { + return this.parent.openedByClient; + } + private getLineOffsets() { if (!this.lineOffsets) { this.lineOffsets = getLineOffsets(this.text); @@ -428,6 +433,12 @@ export class JSOrTSDocumentSnapshot extends IdentityMapper implements DocumentSn private serverHooksPath = 'src/hooks.server'; private clientHooksPath = 'src/hooks.client'; + private openedByClient = false; + + isOpenedInClient(): boolean { + return this.openedByClient; + } + constructor(public version: number, public readonly filePath: string, private text: string) { super(pathToUrl(filePath)); this.adjustText(); @@ -516,6 +527,8 @@ export class JSOrTSDocumentSnapshot extends IdentityMapper implements DocumentSn this.version++; this.lineOffsets = undefined; this.internalLineOffsets = undefined; + // only client can have incremental updates + this.openedByClient = true; } protected getLineOffsets() { diff --git a/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts b/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts index 22a1a2728..2d438cedb 100644 --- a/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts +++ b/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts @@ -78,10 +78,13 @@ export class LSAndTSDocResolver { */ private createDocument = (fileName: string, content: string) => { const uri = pathToUrl(fileName); - const document = this.docManager.openDocument({ - text: content, - uri - }); + const document = this.docManager.openDocument( + { + text: content, + uri + }, + /* openedByClient */ false + ); this.docManager.lockDocument(uri); return document; }; @@ -116,11 +119,31 @@ export class LSAndTSDocResolver { lang: ts.LanguageService; userPreferences: ts.UserPreferences; }> { - const lang = await this.getLSForPath(document.getFilePath() || ''); + const { tsDoc, lsContainer, userPreferences } = await this.getLSAndTSDocWorker(document); + + return { tsDoc, lang: lsContainer.getService(), userPreferences }; + } + + /** + * Retrieves the LS for operations that don't need cross-files information. + * can save some time by not synchronizing languageService program + */ + async getLsForSyntheticOperations(document: Document): Promise<{ + tsDoc: SvelteDocumentSnapshot; + lang: ts.LanguageService; + userPreferences: ts.UserPreferences; + }> { + const { tsDoc, lsContainer, userPreferences } = await this.getLSAndTSDocWorker(document); + + return { tsDoc, userPreferences, lang: lsContainer.getService(/* skipSynchronize */ true) }; + } + + private async getLSAndTSDocWorker(document: Document) { + const lsContainer = await this.getTSService(document.getFilePath() || ''); const tsDoc = await this.getSnapshot(document); const userPreferences = this.getUserPreferences(tsDoc); - return { tsDoc, lang, userPreferences }; + return { tsDoc, lsContainer, userPreferences }; } /** @@ -161,6 +184,10 @@ export class LSAndTSDocResolver { this.docManager.releaseDocument(uri); } + async invalidateModuleCache(filePath: string) { + await forAllServices((service) => service.invalidateModuleCache(filePath)); + } + /** * Updates project files in all existing ts services */ diff --git a/packages/language-server/src/plugins/typescript/SnapshotManager.ts b/packages/language-server/src/plugins/typescript/SnapshotManager.ts index 51f86f669..b92b813bc 100644 --- a/packages/language-server/src/plugins/typescript/SnapshotManager.ts +++ b/packages/language-server/src/plugins/typescript/SnapshotManager.ts @@ -225,8 +225,10 @@ export class SnapshotManager { this.globalSnapshotsManager.delete(fileName); } - getFileNames(): string[] { - return Array.from(this.documents.entries()).map(([_, doc]) => doc.filePath); + getClientFileNames(): string[] { + return Array.from(this.documents.values()) + .filter((doc) => doc.isOpenedInClient()) + .map((doc) => doc.filePath); } getProjectFileNames(): string[] { diff --git a/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts b/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts index 5dbdf5271..05be1bccb 100644 --- a/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts +++ b/packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts @@ -510,14 +510,21 @@ export class TypeScriptPlugin continue; } - if (changeType === FileChangeType.Created && !doneUpdateProjectFiles) { - doneUpdateProjectFiles = true; - await this.lsAndTsDocResolver.updateProjectFiles(); - } else if (changeType === FileChangeType.Deleted) { + if (changeType === FileChangeType.Deleted) { await this.lsAndTsDocResolver.deleteSnapshot(fileName); - } else { - await this.lsAndTsDocResolver.updateExistingTsOrJsFile(fileName); + continue; + } + + if (changeType === FileChangeType.Created) { + if (!doneUpdateProjectFiles) { + doneUpdateProjectFiles = true; + await this.lsAndTsDocResolver.updateProjectFiles(); + } + await this.lsAndTsDocResolver.invalidateModuleCache(fileName); + continue; } + + await this.lsAndTsDocResolver.updateExistingTsOrJsFile(fileName); } } diff --git a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts index 853e7e83a..1fd2a9805 100644 --- a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts @@ -312,6 +312,7 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { : `${document.getText()}`; const virtualDoc = new Document(virtualUri, newText); + virtualDoc.openedByClient = true; // let typescript know about the virtual document await this.lsAndTsDocResolver.getSnapshot(virtualDoc); diff --git a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts index bdfdd3f5d..8f9724f43 100644 --- a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts @@ -103,9 +103,11 @@ export class CompletionsProviderImpl implements CompletionsProvider { - const { lang, tsDoc, userPreferences } = await this.lsAndTsDocResolver.getLSAndTSDoc( + // Don't sync yet so we can skip TypeScript's synchronizeHostData if inlay hints are disabled + const { userPreferences } = await this.lsAndTsDocResolver.getLsForSyntheticOperations( document ); if ( cancellationToken?.isCancellationRequested || - // skip TypeScript's synchronizeHostData !this.areInlayHintsEnabled(userPreferences) ) { return null; } + const { tsDoc, lang } = await this.lsAndTsDocResolver.getLSAndTSDoc(document); + const inlayHints = lang.provideInlayHints( tsDoc.filePath, this.convertToTargetTextSpan(range, tsDoc), diff --git a/packages/language-server/src/plugins/typescript/module-loader.ts b/packages/language-server/src/plugins/typescript/module-loader.ts index aa12a1512..581b90b3a 100644 --- a/packages/language-server/src/plugins/typescript/module-loader.ts +++ b/packages/language-server/src/plugins/typescript/module-loader.ts @@ -1,5 +1,5 @@ import ts from 'typescript'; -import { FileMap } from '../../lib/documents/fileCollection'; +import { FileMap, FileSet } from '../../lib/documents/fileCollection'; import { createGetCanonicalFileName, getLastPartOfPath, toFileNameLowerCase } from '../../utils'; import { DocumentSnapshot } from './DocumentSnapshot'; import { createSvelteSys } from './svelte-sys'; @@ -11,11 +11,13 @@ import { toVirtualSvelteFilePath } from './utils'; +const CACHE_KEY_SEPARATOR = ':::'; /** * Caches resolved modules. */ class ModuleResolutionCache { private cache = new FileMap(); + private pendingInvalidations = new FileSet(); private getCanonicalFileName = createGetCanonicalFileName(ts.sys.useCaseSensitiveFileNames); /** @@ -49,6 +51,7 @@ class ModuleResolutionCache { this.cache.forEach((val, key) => { if (val && this.getCanonicalFileName(val.resolvedFileName) === resolvedModuleName) { this.cache.delete(key); + this.pendingInvalidations.add(key.split(CACHE_KEY_SEPARATOR).shift() || ''); } }); } @@ -61,15 +64,24 @@ class ModuleResolutionCache { const fileNameWithoutEnding = getLastPartOfPath(this.getCanonicalFileName(path)).split('.').shift() || ''; this.cache.forEach((val, key) => { - const moduleName = key.split(':::').pop() || ''; + const [containingFile, moduleName = ''] = key.split(CACHE_KEY_SEPARATOR); if (!val && moduleName.includes(fileNameWithoutEnding)) { this.cache.delete(key); + this.pendingInvalidations.add(containingFile); } }); } private getKey(moduleName: string, containingFile: string) { - return containingFile + ':::' + ensureRealSvelteFilePath(moduleName); + return containingFile + CACHE_KEY_SEPARATOR + ensureRealSvelteFilePath(moduleName); + } + + clearPendingInvalidations() { + this.pendingInvalidations.clear(); + } + + oneOfResolvedModuleChanged(path: string) { + return this.pendingInvalidations.has(path); } } @@ -171,6 +183,8 @@ export function createSvelteModuleLoader( >(); const impliedNodeFormatResolver = new ImpliedNodeFormatResolver(); + const failedPathToContainingFile = new FileMap(); + const failedLocationInvalidated = new FileSet(); return { fileExists: svelteSys.fileExists, @@ -183,9 +197,17 @@ export function createSvelteModuleLoader( deleteUnresolvedResolutionsFromCache: (path: string) => { svelteSys.deleteFromCache(path); moduleCache.deleteUnresolvedResolutionsFromCache(path); + + const previousTriedButFailed = failedPathToContainingFile.get(path); + + for (const containingFile of previousTriedButFailed ?? []) { + failedLocationInvalidated.add(containingFile); + } }, resolveModuleNames, - resolveTypeReferenceDirectiveReferences + resolveTypeReferenceDirectiveReferences, + mightHaveInvalidatedResolutions, + clearPendingInvalidations }; function resolveModuleNames( @@ -207,8 +229,15 @@ export function createSvelteModuleLoader( containingSourceFile, index ); - moduleCache.set(moduleName, containingFile, resolvedModule); - return resolvedModule; + + resolvedModule?.failedLookupLocations?.forEach((failedLocation) => { + const failedPaths = failedPathToContainingFile.get(failedLocation) ?? new FileSet(); + failedPaths.add(containingFile); + failedPathToContainingFile.set(failedLocation, failedPaths); + }); + + moduleCache.set(moduleName, containingFile, resolvedModule?.resolvedModule); + return resolvedModule?.resolvedModule; }); } @@ -217,7 +246,7 @@ export function createSvelteModuleLoader( containingFile: string, containingSourceFile: ts.SourceFile | undefined, index: number - ): ts.ResolvedModule | undefined { + ): ts.ResolvedModuleWithFailedLookupLocations { const mode = impliedNodeFormatResolver.resolve( name, index, @@ -227,7 +256,7 @@ export function createSvelteModuleLoader( // Delegate to the TS resolver first. // If that does not bring up anything, try the Svelte Module loader // which is able to deal with .svelte files. - const tsResolvedModule = tsModule.resolveModuleName( + const tsResolvedModuleWithFailedLookup = tsModule.resolveModuleName( name, containingFile, compilerOptions, @@ -235,12 +264,14 @@ export function createSvelteModuleLoader( tsModuleCache, undefined, mode - ).resolvedModule; + ); + + const tsResolvedModule = tsResolvedModuleWithFailedLookup.resolvedModule; if (tsResolvedModule && !isVirtualSvelteFilePath(tsResolvedModule.resolvedFileName)) { - return tsResolvedModule; + return tsResolvedModuleWithFailedLookup; } - const svelteResolvedModule = tsModule.resolveModuleName( + const svelteResolvedModuleWithFailedLookup = tsModule.resolveModuleName( name, containingFile, compilerOptions, @@ -248,12 +279,14 @@ export function createSvelteModuleLoader( undefined, undefined, mode - ).resolvedModule; + ); + + const svelteResolvedModule = svelteResolvedModuleWithFailedLookup.resolvedModule; if ( !svelteResolvedModule || !isVirtualSvelteFilePath(svelteResolvedModule.resolvedFileName) ) { - return svelteResolvedModule; + return svelteResolvedModuleWithFailedLookup; } const resolvedFileName = ensureRealSvelteFilePath(svelteResolvedModule.resolvedFileName); @@ -264,7 +297,10 @@ export function createSvelteModuleLoader( resolvedFileName, isExternalLibraryImport: svelteResolvedModule.isExternalLibraryImport }; - return resolvedSvelteModule; + return { + ...svelteResolvedModuleWithFailedLookup, + resolvedModule: resolvedSvelteModule + }; } function resolveTypeReferenceDirectiveReferences( @@ -303,4 +339,17 @@ export function createSvelteModuleLoader( return result; }); } + + function mightHaveInvalidatedResolutions(path: string) { + return ( + moduleCache.oneOfResolvedModuleChanged(path) || + // tried but failed file might now exist + failedLocationInvalidated.has(path) + ); + } + + function clearPendingInvalidations() { + moduleCache.clearPendingInvalidations(); + failedLocationInvalidated.clear(); + } } diff --git a/packages/language-server/src/plugins/typescript/service.ts b/packages/language-server/src/plugins/typescript/service.ts index 40f856428..72d6ae0c6 100644 --- a/packages/language-server/src/plugins/typescript/service.ts +++ b/packages/language-server/src/plugins/typescript/service.ts @@ -29,9 +29,10 @@ export interface LanguageServiceContainer { * @internal Public for tests only */ readonly snapshotManager: SnapshotManager; - getService(): ts.LanguageService; + getService(skipSynchronize?: boolean): ts.LanguageService; updateSnapshot(documentOrFilePath: Document | string): DocumentSnapshot; deleteSnapshot(filePath: string): void; + invalidateModuleCache(filePath: string): void; updateProjectFiles(): void; updateTsOrJsFile(fileName: string, changes?: TextDocumentContentChangeEvent[]): void; /** @@ -48,6 +49,32 @@ export interface LanguageServiceContainer { dispose(): void; } +declare module 'typescript' { + interface LanguageServiceHost { + /** + * @internal + * This is needed for the languageService program to know that there is a new file + * that might change the module resolution results + */ + hasInvalidatedResolutions?: (sourceFile: string) => boolean; + } + + interface ResolvedModuleWithFailedLookupLocations { + /** @internal */ + failedLookupLocations?: string[]; + /** @internal */ + affectingLocations?: string[]; + /** @internal */ + resolutionDiagnostics?: ts.Diagnostic[]; + /** + * @internal + * Used to issue a diagnostic if typings for a non-relative import couldn't be found + * while respecting package.json `exports`, but were found when disabling `exports`. + */ + node10Result?: string; + } +} + const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024; // 20 MB const services = new FileMap>(); const serviceSizeMap = new FileMap(); @@ -235,6 +262,7 @@ async function createLanguageService( let languageServiceReducedMode = false; let projectVersion = 0; + let dirty = false; const getCanonicalFileName = createGetCanonicalFileName(tsSystem.useCaseSensitiveFileNames); @@ -242,8 +270,9 @@ async function createLanguageService( log: (message) => Logger.debug(`[ts] ${message}`), getCompilationSettings: () => compilerOptions, getScriptFileNames, - getScriptVersion: (fileName: string) => getSnapshot(fileName).version.toString(), - getScriptSnapshot: getSnapshot, + getScriptVersion: (fileName: string) => + getSnapshotIfExists(fileName)?.version.toString() || '', + getScriptSnapshot: getSnapshotIfExists, getCurrentDirectory: () => workspacePath, getDefaultLibFileName: ts.getDefaultLibFilePath, fileExists: svelteModuleLoader.fileExists, @@ -256,7 +285,8 @@ async function createLanguageService( getProjectVersion: () => projectVersion.toString(), getNewLine: () => tsSystem.newLine, resolveTypeReferenceDirectiveReferences: - svelteModuleLoader.resolveTypeReferenceDirectiveReferences + svelteModuleLoader.resolveTypeReferenceDirectiveReferences, + hasInvalidatedResolutions: svelteModuleLoader.mightHaveInvalidatedResolutions }; let languageService = ts.createLanguageService(host); @@ -265,10 +295,7 @@ async function createLanguageService( typingsNamespace: raw?.svelteOptions?.namespace || 'svelteHTML' }; - const onSnapshotChange = () => { - projectVersion++; - }; - docContext.globalSnapshotsManager.onChange(onSnapshotChange); + docContext.globalSnapshotsManager.onChange(scheduleUpdate); reduceLanguageServiceCapabilityIfFileSizeTooBig(); updateExtendedConfigDependents(); @@ -278,7 +305,7 @@ async function createLanguageService( tsconfigPath, compilerOptions, configErrors, - getService: () => languageService, + getService, updateSnapshot, deleteSnapshot, updateProjectFiles, @@ -286,15 +313,31 @@ async function createLanguageService( hasFile, fileBelongsToProject, snapshotManager, + invalidateModuleCache, dispose }; + function getService(skipSynchronize?: boolean) { + if (!skipSynchronize) { + updateIfDirty(); + } + + return languageService; + } + function deleteSnapshot(filePath: string): void { svelteModuleLoader.deleteFromModuleCache(filePath); snapshotManager.delete(filePath); configFileForOpenFiles.delete(filePath); } + function invalidateModuleCache(filePath: string) { + svelteModuleLoader.deleteFromModuleCache(filePath); + svelteModuleLoader.deleteUnresolvedResolutionsFromCache(filePath); + + scheduleUpdate(); + } + function updateSnapshot(documentOrFilePath: Document | string): DocumentSnapshot { return typeof documentOrFilePath === 'string' ? updateSnapshotFromFilePath(documentOrFilePath) @@ -341,6 +384,26 @@ async function createLanguageService( return newSnapshot; } + /** + * Deleted files will still be requested during the program update. + * Don't create snapshots for them. + * Otherwise, deleteUnresolvedResolutionsFromCache won't be called when the file is created again + */ + function getSnapshotIfExists(fileName: string): DocumentSnapshot | undefined { + fileName = ensureRealSvelteFilePath(fileName); + + let doc = snapshotManager.get(fileName); + if (doc) { + return doc; + } + + if (!svelteModuleLoader.fileExists(fileName)) { + return undefined; + } + + return createSnapshot(fileName, doc); + } + function getSnapshot(fileName: string): DocumentSnapshot { fileName = ensureRealSvelteFilePath(fileName); @@ -349,6 +412,10 @@ async function createLanguageService( return doc; } + return createSnapshot(fileName, doc); + } + + function createSnapshot(fileName: string, doc: DocumentSnapshot | undefined) { svelteModuleLoader.deleteUnresolvedResolutionsFromCache(fileName); doc = DocumentSnapshot.fromFilePath( fileName, @@ -362,6 +429,7 @@ async function createLanguageService( function updateProjectFiles(): void { projectVersion++; + dirty = true; const projectFileCountBefore = snapshotManager.getProjectFileNames().length; snapshotManager.updateProjectFiles(); const projectFileCountAfter = snapshotManager.getProjectFileNames().length; @@ -385,7 +453,7 @@ async function createLanguageService( // project file is read from the file system so it's more likely to have // the correct casing ...snapshotManager - .getFileNames() + .getClientFileNames() .filter((file) => !canonicalProjectFileNames.has(getCanonicalFileName(file))), ...svelteTsxFiles ]) @@ -570,7 +638,7 @@ async function createLanguageService( configWatchers.get(tsconfigPath)?.close(); configWatchers.delete(tsconfigPath); configFileForOpenFiles.clear(); - docContext.globalSnapshotsManager.removeChangeListener(onSnapshotChange); + docContext.globalSnapshotsManager.removeChangeListener(scheduleUpdate); } function updateExtendedConfigDependents() { @@ -636,6 +704,26 @@ async function createLanguageService( docContext.onProjectReloaded?.(); } + + function updateIfDirty() { + if (!dirty) { + return; + } + + languageService.getProgram(); + svelteModuleLoader.clearPendingInvalidations(); + + dirty = false; + } + + function scheduleUpdate() { + if (dirty) { + return; + } + + projectVersion++; + dirty = true; + } } /** diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index ab6200d2f..3a27f5a35 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -346,8 +346,7 @@ export function startServer(options?: LSOptions) { }); connection.onDidOpenTextDocument((evt) => { - const document = docManager.openDocument(evt.textDocument); - docManager.markAsOpenedInClient(evt.textDocument.uri); + const document = docManager.openClientDocument(evt.textDocument); diagnosticsManager.scheduleUpdate(document); }); diff --git a/packages/language-server/src/svelte-check.ts b/packages/language-server/src/svelte-check.ts index e8d2f9b41..4e5c3c6ae 100644 --- a/packages/language-server/src/svelte-check.ts +++ b/packages/language-server/src/svelte-check.ts @@ -136,11 +136,10 @@ export class SvelteCheck { } ]); } else { - this.docManager.openDocument({ + this.docManager.openClientDocument({ text: doc.text, uri: doc.uri }); - this.docManager.markAsOpenedInClient(doc.uri); } } diff --git a/packages/language-server/test/lib/documents/DocumentManager.test.ts b/packages/language-server/test/lib/documents/DocumentManager.test.ts index e873612e4..db5ad798e 100644 --- a/packages/language-server/test/lib/documents/DocumentManager.test.ts +++ b/packages/language-server/test/lib/documents/DocumentManager.test.ts @@ -15,10 +15,10 @@ describe('Document Manager', () => { new Document(textDocument.uri, textDocument.text); it('opens documents', () => { - const createDocument = sinon.spy(); + const createDocument = sinon.spy((_) => new Document('', '')); const manager = new DocumentManager(createDocument); - manager.openDocument(textDocument); + manager.openClientDocument(textDocument); sinon.assert.calledOnce(createDocument); sinon.assert.calledWith(createDocument.firstCall, textDocument); @@ -30,7 +30,7 @@ describe('Document Manager', () => { const createDocument = sinon.stub().returns(document); const manager = new DocumentManager(createDocument); - manager.openDocument(textDocument); + manager.openClientDocument(textDocument); manager.updateDocument(textDocument, [{ text: 'New content' }]); sinon.assert.calledOnce(update); @@ -43,7 +43,7 @@ describe('Document Manager', () => { const createDocument = sinon.stub().returns(document); const manager = new DocumentManager(createDocument); - manager.openDocument(textDocument); + manager.openClientDocument(textDocument); manager.updateDocument(textDocument, [ { text: 'svelte', @@ -74,7 +74,7 @@ describe('Document Manager', () => { manager.on('documentChange', cb); - manager.openDocument(textDocument); + manager.openClientDocument(textDocument); sinon.assert.calledOnce(cb); manager.updateDocument(textDocument, []); @@ -92,7 +92,7 @@ describe('Document Manager', () => { useCaseSensitiveFileNames: false }); - manager.openDocument(textDocument); + manager.openClientDocument(textDocument); const firstVersion = manager.get(textDocument.uri)!.version; const position = { line: 0, character: textDocument.text.length }; diff --git a/packages/language-server/test/plugins/PluginHost.test.ts b/packages/language-server/test/plugins/PluginHost.test.ts index 3a75aec55..d18c76403 100644 --- a/packages/language-server/test/plugins/PluginHost.test.ts +++ b/packages/language-server/test/plugins/PluginHost.test.ts @@ -47,7 +47,7 @@ describe('PluginHost', () => { const { docManager, pluginHost, plugin } = setup({ getDiagnostics: sinon.stub().returns([]) }); - const document = docManager.openDocument(textDocument); + const document = docManager.openClientDocument(textDocument); await pluginHost.getDiagnostics(textDocument); @@ -59,7 +59,7 @@ describe('PluginHost', () => { const { docManager, pluginHost, plugin } = setup({ doHover: sinon.stub().returns(null) }); - const document = docManager.openDocument(textDocument); + const document = docManager.openClientDocument(textDocument); const pos = Position.create(0, 0); await pluginHost.doHover(textDocument, pos); @@ -72,7 +72,7 @@ describe('PluginHost', () => { const { docManager, pluginHost, plugin } = setup({ getCompletions: sinon.stub().returns({ items: [] }) }); - const document = docManager.openDocument(textDocument); + const document = docManager.openClientDocument(textDocument); const pos = Position.create(0, 0); await pluginHost.getCompletions(textDocument, pos, { @@ -104,7 +104,7 @@ describe('PluginHost', () => { }, { definitionLinkSupport: true, filterIncompleteCompletions: filterServerSide } ); - docManager.openDocument(textDocument); + docManager.openClientDocument(textDocument); return pluginHost; } @@ -149,7 +149,7 @@ describe('PluginHost', () => { }, { definitionLinkSupport: linkSupport, filterIncompleteCompletions: false } ); - docManager.openDocument(textDocument); + docManager.openClientDocument(textDocument); return pluginHost; } diff --git a/packages/language-server/test/plugins/css/CSSPlugin.test.ts b/packages/language-server/test/plugins/css/CSSPlugin.test.ts index b511d4f39..97aef32f6 100644 --- a/packages/language-server/test/plugins/css/CSSPlugin.test.ts +++ b/packages/language-server/test/plugins/css/CSSPlugin.test.ts @@ -33,7 +33,7 @@ describe('CSS Plugin', () => { ], createLanguageServices(lsOptions) ); - docManager.openDocument('some doc'); + docManager.openClientDocument('some doc'); return { plugin, document }; } diff --git a/packages/language-server/test/plugins/css/features/getIdClassCompletion.test.ts b/packages/language-server/test/plugins/css/features/getIdClassCompletion.test.ts index a49c9efc2..036758a1f 100644 --- a/packages/language-server/test/plugins/css/features/getIdClassCompletion.test.ts +++ b/packages/language-server/test/plugins/css/features/getIdClassCompletion.test.ts @@ -55,7 +55,7 @@ describe('getIdClassCompletion', () => { [{ name: '', uri: pathToUrl(process.cwd()) }], createLanguageServices() ); - docManager.openDocument('some doc'); + docManager.openClientDocument('some doc'); return { plugin, document }; } diff --git a/packages/language-server/test/plugins/html/HTMLPlugin.test.ts b/packages/language-server/test/plugins/html/HTMLPlugin.test.ts index 2d8ecd697..e9d4be84a 100644 --- a/packages/language-server/test/plugins/html/HTMLPlugin.test.ts +++ b/packages/language-server/test/plugins/html/HTMLPlugin.test.ts @@ -19,7 +19,7 @@ describe('HTML Plugin', () => { const docManager = new DocumentManager(() => document); const configManager = new LSConfigManager(); const plugin = new HTMLPlugin(docManager, configManager); - docManager.openDocument('some doc'); + docManager.openClientDocument('some doc'); return { plugin, document, configManager }; } diff --git a/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts b/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts index 335215fcf..420098603 100644 --- a/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts +++ b/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts @@ -25,7 +25,7 @@ describe('Svelte Plugin', () => { pluginManager.updateIsTrusted(trusted); pluginManager.updatePrettierConfig(prettierConfig); const plugin = new SveltePlugin(pluginManager); - docManager.openDocument('some doc'); + docManager.openClientDocument('some doc'); return { plugin, document }; } diff --git a/packages/language-server/test/plugins/typescript/TypescriptPlugin.test.ts b/packages/language-server/test/plugins/typescript/TypescriptPlugin.test.ts index 1839ccd96..8ef10793e 100644 --- a/packages/language-server/test/plugins/typescript/TypescriptPlugin.test.ts +++ b/packages/language-server/test/plugins/typescript/TypescriptPlugin.test.ts @@ -47,7 +47,7 @@ describe('TypescriptPlugin', function () { new LSAndTSDocResolver(docManager, [pathToUrl(testDir)], lsConfigManager), workspaceUris ); - docManager.openDocument('some doc'); + docManager.openClientDocument('some doc'); return { plugin, document }; } diff --git a/packages/language-server/test/plugins/typescript/features/CallHierarchyProvider.test.ts b/packages/language-server/test/plugins/typescript/features/CallHierarchyProvider.test.ts index 6005cee78..51ce09449 100644 --- a/packages/language-server/test/plugins/typescript/features/CallHierarchyProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/CallHierarchyProvider.test.ts @@ -46,7 +46,7 @@ describe('CallHierarchyProvider', function () { ); const provider = new CallHierarchyProviderImpl(lsAndTsDocResolver, workspaceUris); const filePath = getFullPath(filename); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: harmonizeNewLines(ts.sys.readFile(filePath) || '') }); diff --git a/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts b/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts index 6b7c51a17..9083ab972 100644 --- a/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts @@ -60,7 +60,7 @@ describe('CodeActionsProvider', function () { lsConfigManager ); const filePath = getFullPath(filename); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: harmonizeNewLines(ts.sys.readFile(filePath) || '') }); diff --git a/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts b/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts index 4d8d28911..d9e56a39a 100644 --- a/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts @@ -54,7 +54,7 @@ describe('CompletionProviderImpl', function () { ); const completionProvider = new CompletionsProviderImpl(lsAndTsDocResolver, lsConfigManager); const filePath = join(testFilesDir, filename); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); @@ -786,7 +786,7 @@ describe('CompletionProviderImpl', function () { name = 'imported-file.svelte' ) { const filePath = join(testFilesDir, name); - const hoverinfoDoc = docManager.openDocument({ + const hoverinfoDoc = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); @@ -1368,7 +1368,7 @@ describe('CompletionProviderImpl', function () { const completionProvider = new CompletionsProviderImpl(lsAndTsDocResolver, lsConfigManager); // let the language service aware of random-package and random-package2 - docManager.openDocument({ + docManager.openClientDocument({ text: '', uri: pathToUrl(join(virtualTestDir, 'test.svelte')) }); diff --git a/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts b/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts index eca5a832e..b01473ef0 100644 --- a/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/DiagnosticsProvider.test.ts @@ -26,7 +26,7 @@ describe('DiagnosticsProvider', function () { ); const plugin = new DiagnosticsProviderImpl(lsAndTsDocResolver, new LSConfigManager()); const filePath = path.join(testDir, filename); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); @@ -43,7 +43,7 @@ describe('DiagnosticsProvider', function () { const newFilePath = normalizePath(path.join(testDir, 'doesntexistyet.js')) || ''; writeFileSync(newFilePath, 'export default function foo() {}'); assert.ok(existsSync(newFilePath)); - await lsAndTsDocResolver.getSnapshot(newFilePath); + await lsAndTsDocResolver.invalidateModuleCache(newFilePath); try { const diagnostics2 = await plugin.getDiagnostics(document); @@ -57,6 +57,41 @@ describe('DiagnosticsProvider', function () { assert.deepStrictEqual(diagnostics3.length, 1); }).timeout(5000); + it('notices changes of module resolution because of new file', async () => { + const { plugin, document, lsAndTsDocResolver } = setup('unresolvedimport.svelte'); + + const diagnostics1 = await plugin.getDiagnostics(document); + assert.deepStrictEqual(diagnostics1.length, 1); + + // back-and-forth-conversion normalizes slashes + const newFilePath = normalizePath(path.join(testDir, 'doesntexistyet.js')) || ''; + const newTsFilePath = normalizePath(path.join(testDir, 'doesntexistyet.ts')) || ''; + writeFileSync(newFilePath, 'export function foo() {}'); + assert.ok(existsSync(newFilePath)); + await lsAndTsDocResolver.invalidateModuleCache(newFilePath); + + try { + const diagnostics2 = await plugin.getDiagnostics(document); + assert.deepStrictEqual(diagnostics2[0].code, 2613); + } catch (e) { + unlinkSync(newFilePath); + throw e; + } + + writeFileSync(newTsFilePath, 'export default function foo() {}'); + assert.ok(existsSync(newTsFilePath)); + await lsAndTsDocResolver.invalidateModuleCache(newTsFilePath); + + try { + const diagnostics3 = await plugin.getDiagnostics(document); + assert.deepStrictEqual(diagnostics3.length, 1); + await lsAndTsDocResolver.deleteSnapshot(newTsFilePath); + } finally { + unlinkSync(newTsFilePath); + unlinkSync(newFilePath); + } + }).timeout(5000); + it('notices update of imported module', async () => { const { plugin, document, lsAndTsDocResolver } = setup( 'diagnostics-imported-js-update.svelte' @@ -95,14 +130,14 @@ describe('DiagnosticsProvider', function () { 'different-ts-service', 'different-ts-service.svelte' ); - const otherDocument = docManager.openDocument({ + const otherDocument = docManager.openClientDocument({ uri: pathToUrl(otherFilePath), text: ts.sys.readFile(otherFilePath) || '' }); // needed because tests have nasty dependencies between them. The ts service // is cached and knows the docs already const sharedFilePath = path.join(testDir, 'shared-comp.svelte'); - docManager.openDocument({ + docManager.openClientDocument({ uri: pathToUrl(sharedFilePath), text: ts.sys.readFile(sharedFilePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/FindComponentReferencesProvider.test.ts b/packages/language-server/test/plugins/typescript/features/FindComponentReferencesProvider.test.ts index 05d64b7ba..482af1ffd 100644 --- a/packages/language-server/test/plugins/typescript/features/FindComponentReferencesProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/FindComponentReferencesProvider.test.ts @@ -8,16 +8,16 @@ import { LSAndTSDocResolver } from '../../../../src/plugins/typescript/LSAndTSDo import { pathToUrl } from '../../../../src/utils'; import { serviceWarmup } from '../test-utils'; -const testDir = path.join(__dirname, '..'); +const testDir = path.join(__dirname, '..', 'testfiles'); describe('FindComponentReferencesProvider', function () { serviceWarmup(this, testDir); function getFullPath(filename: string) { - return path.join(testDir, 'testfiles', filename); + return path.join(testDir, filename); } function getUri(filename: string) { - const filePath = path.join(testDir, 'testfiles', filename); + const filePath = path.join(testDir, filename); return pathToUrl(filePath); } @@ -38,7 +38,7 @@ describe('FindComponentReferencesProvider', function () { function openDoc(filename: string) { const filePath = getFullPath(filename); - const doc = docManager.openDocument({ + const doc = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/FindFileReferencesProvider.test.ts b/packages/language-server/test/plugins/typescript/features/FindFileReferencesProvider.test.ts index 4fa650c75..03d5978c0 100644 --- a/packages/language-server/test/plugins/typescript/features/FindFileReferencesProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/FindFileReferencesProvider.test.ts @@ -38,7 +38,7 @@ describe('FindFileReferencesProvider', function () { function openDoc(filename: string) { const filePath = getFullPath(filename); - const doc = docManager.openDocument({ + const doc = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts b/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts index 4ce44f953..1719ca933 100644 --- a/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/FindReferencesProvider.test.ts @@ -35,7 +35,7 @@ describe('FindReferencesProvider', function () { function openDoc(filename: string) { const filePath = getFullPath(filename); - const doc = docManager.openDocument({ + const doc = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/HoverProvider.test.ts b/packages/language-server/test/plugins/typescript/features/HoverProvider.test.ts index 501fb171e..17b6d8c35 100644 --- a/packages/language-server/test/plugins/typescript/features/HoverProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/HoverProvider.test.ts @@ -32,7 +32,7 @@ describe('HoverProvider', function () { function openDoc(filename: string) { const filePath = getFullPath(filename); - const doc = docManager.openDocument({ + const doc = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/ImplemenationProvider.test.ts b/packages/language-server/test/plugins/typescript/features/ImplemenationProvider.test.ts index 8679d8560..c272b0ebb 100644 --- a/packages/language-server/test/plugins/typescript/features/ImplemenationProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/ImplemenationProvider.test.ts @@ -34,7 +34,7 @@ describe('ImplementationProvider', function () { ); const provider = new ImplementationProviderImpl(lsAndTsDocResolver); const filePath = getFullPath(filename); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/RenameProvider.test.ts b/packages/language-server/test/plugins/typescript/features/RenameProvider.test.ts index d86397e30..3ad669246 100644 --- a/packages/language-server/test/plugins/typescript/features/RenameProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/RenameProvider.test.ts @@ -65,7 +65,7 @@ describe('RenameProvider', function () { async function openDoc(filename: string) { const filePath = getFullPath(filename); - const doc = docManager.openDocument({ + const doc = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/SelectionRangeProvider.test.ts b/packages/language-server/test/plugins/typescript/features/SelectionRangeProvider.test.ts index 46a25b027..3156992bd 100644 --- a/packages/language-server/test/plugins/typescript/features/SelectionRangeProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/SelectionRangeProvider.test.ts @@ -31,7 +31,7 @@ describe('SelectionRangeProvider', function () { new LSConfigManager() ); const provider = new SelectionRangeProviderImpl(lsAndTsDocResolver); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) }); diff --git a/packages/language-server/test/plugins/typescript/features/SemanticTokensProvider.test.ts b/packages/language-server/test/plugins/typescript/features/SemanticTokensProvider.test.ts index 410792f21..8b585fb4e 100644 --- a/packages/language-server/test/plugins/typescript/features/SemanticTokensProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/SemanticTokensProvider.test.ts @@ -33,7 +33,7 @@ describe('SemanticTokensProvider', function () { new LSConfigManager() ); const provider = new SemanticTokensProviderImpl(lsAndTsDocResolver); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) }); diff --git a/packages/language-server/test/plugins/typescript/features/SignatureHelpProvider.test.ts b/packages/language-server/test/plugins/typescript/features/SignatureHelpProvider.test.ts index 70324bc79..9c18f526b 100644 --- a/packages/language-server/test/plugins/typescript/features/SignatureHelpProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/SignatureHelpProvider.test.ts @@ -31,7 +31,7 @@ describe('SignatureHelpProvider', function () { new LSConfigManager() ); const provider = new SignatureHelpProviderImpl(lsAndTsDocResolver); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) }); diff --git a/packages/language-server/test/plugins/typescript/features/TypeDefinitionProvider.test.ts b/packages/language-server/test/plugins/typescript/features/TypeDefinitionProvider.test.ts index 4f5d2c2f1..9a38c34d4 100644 --- a/packages/language-server/test/plugins/typescript/features/TypeDefinitionProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/TypeDefinitionProvider.test.ts @@ -34,7 +34,7 @@ describe('TypeDefinitionProvider', function () { ); const provider = new TypeDefinitionProviderImpl(lsAndTsDocResolver); const filePath = getFullPath(filename); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/UpdateImportsProvider.test.ts b/packages/language-server/test/plugins/typescript/features/UpdateImportsProvider.test.ts index 696bd47b4..998896aa3 100644 --- a/packages/language-server/test/plugins/typescript/features/UpdateImportsProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/UpdateImportsProvider.test.ts @@ -36,7 +36,7 @@ describe('UpdateImportsProviderImpl', function () { const updateImportsProvider = new UpdateImportsProviderImpl(lsAndTsDocResolver); const filePath = join(updateImportTestDir, filename); const fileUri = pathToUrl(filePath); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: fileUri, text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/index.test.ts b/packages/language-server/test/plugins/typescript/features/diagnostics/index.test.ts index 03cc2ba9d..378e6dcfe 100644 --- a/packages/language-server/test/plugins/typescript/features/diagnostics/index.test.ts +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/index.test.ts @@ -26,7 +26,7 @@ function setup(workspaceDir: string, filePath: string) { configManager ); const plugin = new DiagnosticsProviderImpl(lsAndTsDocResolver, configManager); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/inlayHints/index.test.ts b/packages/language-server/test/plugins/typescript/features/inlayHints/index.test.ts index 295db9a32..f9a8cc35e 100644 --- a/packages/language-server/test/plugins/typescript/features/inlayHints/index.test.ts +++ b/packages/language-server/test/plugins/typescript/features/inlayHints/index.test.ts @@ -40,7 +40,7 @@ function setup(workspaceDir: string, filePath: string) { configManager ); const plugin = new InlayHintProviderImpl(lsAndTsDocResolver); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/features/preferences.test.ts b/packages/language-server/test/plugins/typescript/features/preferences.test.ts index 7df555eef..c794dc55b 100644 --- a/packages/language-server/test/plugins/typescript/features/preferences.test.ts +++ b/packages/language-server/test/plugins/typescript/features/preferences.test.ts @@ -28,7 +28,7 @@ describe('ts user preferences', function () { ); const filePath = join(testFilesDir, filename); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); diff --git a/packages/language-server/test/plugins/typescript/test-utils.ts b/packages/language-server/test/plugins/typescript/test-utils.ts index 68a956abc..f8f0c7f1d 100644 --- a/packages/language-server/test/plugins/typescript/test-utils.ts +++ b/packages/language-server/test/plugins/typescript/test-utils.ts @@ -146,7 +146,7 @@ export function setupVirtualEnvironment({ const filePath = join(testDir, filename); virtualSystem.writeFile(filePath, fileContent); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: virtualSystem.readFile(filePath) || '' }); @@ -270,13 +270,12 @@ export function serviceWarmup(suite: Mocha.Suite, testDir: string, rootUri = pat ); const filePath = join(testDir, 'DoesNotMater.svelte'); - const document = docManager.openDocument({ + const document = docManager.openClientDocument({ uri: pathToUrl(filePath), text: ts.sys.readFile(filePath) || '' }); - const { lang } = await lsAndTsDocResolver.getLSAndTSDoc(document); - lang.getProgram(); + await lsAndTsDocResolver.getLSAndTSDoc(document); console.log(`Service warming up done in ${Date.now() - start}ms`); }); diff --git a/packages/language-server/test/plugins/typescript/typescript-performance.test.ts b/packages/language-server/test/plugins/typescript/typescript-performance.test.ts index a94e5deee..13ba896da 100644 --- a/packages/language-server/test/plugins/typescript/typescript-performance.test.ts +++ b/packages/language-server/test/plugins/typescript/typescript-performance.test.ts @@ -21,7 +21,7 @@ describe('TypeScript Plugin Performance Tests', () => { new LSAndTSDocResolver(docManager, workspaceUris, pluginManager), workspaceUris ); - docManager.openDocument({ uri, text: document.getText() }); + docManager.openClientDocument({ uri, text: document.getText() }); const append = (newText: string) => docManager.updateDocument({ uri, version: 1 }, [ { range: Range.create(Position.create(9, 0), Position.create(9, 0)), text: newText }