diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 54bcd16b28d..7c07391237a 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -839,7 +839,7 @@ namespace ts.server { if (this.host.realpath) { this.realpathToScriptInfos = createMultiMap(); } - const fshost = this.fshost || this.host + const fshost = this.fshost || this.host; this.currentDirectory = toNormalizedPath(fshost.getCurrentDirectory()); this.toCanonicalFileName = createGetCanonicalFileName(fshost.useCaseSensitiveFileNames); this.globalCacheLocationDirectoryPath = this.typingsInstaller.globalTypingsCacheLocation @@ -1959,7 +1959,7 @@ namespace ts.server { /** Get a filename if the language service exceeds the maximum allowed program size; otherwise returns undefined. */ private getFilenameForExceededTotalSizeLimitForNonTsFiles(name: string, options: CompilerOptions | undefined, fileNames: T[], propertyReader: FilePropertyReader): string | undefined { - const fshost = this.fshost || this.host + const fshost = this.fshost || this.host; if (options && options.disableSizeLimit || !fshost.getFileSize) { return; } @@ -3700,40 +3700,23 @@ namespace ts.server { } /* @internal */ - updateFileSystem(createdFiles: Iterator | undefined, updatedFiles?: Iterator, deletedFiles?: string[]) { + updateFileSystem(updatedFiles: protocol.FileSystemRequestArgs[] | undefined, deletedFiles?: string[]) { Debug.assert(this.fshost); const fs = this.fshost as TestFSWithWatch.VirtualServerHost; - if (createdFiles) { - let it; - while (!(it = createdFiles.next()).done) { - const document = it.value; - if (document.fileContent) { - if (!fs.directoryExists(getDirectoryPath(document.file))) { - fs.createDirectory(getDirectoryPath(document.file), /*recursive*/ true); - } - fs.writeFile(document.file, document.fileContent); - } - } - } - if (updatedFiles) { - let it; - while (!(it = updatedFiles.next()).done) { - if (it.value.fileContent) { - if (fs.fileExists(it.value.file)) { - fs.modifyFile(it.value.file, it.value.fileContent); - } - else { - fs.createDirectory(getDirectoryPath(it.value.file), /*recursive*/ true); - fs.writeFile(it.value.file, it.value.fileContent); - } + for (const { file, fileContent } of updatedFiles) { + if (fs.fileExists(file)) { + fs.modifyFile(file, fileContent); + } + else { + fs.ensureFileOrFolder({ path: getDirectoryPath(file) }); + fs.writeFile(file, fileContent); } } } if (deletedFiles) { - // TODO: Probably want to delete empty parent folders while they are empty too for (const file of deletedFiles) { - fs.deleteFile(file); + fs.deleteFile(file, /*deleteEmptyParentFolders*/ true); } } } diff --git a/src/server/project.ts b/src/server/project.ts index 18feb114b58..23091cc4818 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -459,7 +459,7 @@ namespace ts.server { } readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { - return this.directoryStructureHost.readDirectory!(path, extensions, exclude, include, depth) + return this.directoryStructureHost.readDirectory!(path, extensions, exclude, include, depth); } readFile(fileName: string): string | undefined { diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 5f8ca382f42..2b1ee6f004a 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -1849,25 +1849,22 @@ namespace ts.server.protocol { export interface UpdateFileSystemRequestArgs { /** For now, only 'memfs', initially for exclusive in-memory operation, but it could be other in-memory names later */ fileSystem: string; - /** List of newly created or newly available files. */ - created: FileSystemRequestArgs[]; + /** List of newly created or updated files. */ + files: FileSystemRequestArgs[]; /** Names of just-deleted files. */ deleted: string[]; - /** List of updated files. */ - updated: FileSystemRequestArgs[]; } - export interface FileSystemRequestArgs extends FileRequestArgs { + export interface FileSystemRequestArgs { + /** + * The file for the request (absolute pathname required). + */ + file: string; /** * Used to replace the content that would be on disk. * Then the known content will be used upon opening instead of the disk copy */ - fileContent?: string; - /** - * Used to specify the script kind of the file explicitly. It could be one of the following: - * "TS", "JS", "TSX", "JSX" - */ - scriptKindName?: ScriptKindName; + fileContent: string; } /** diff --git a/src/server/session.ts b/src/server/session.ts index 8f015bb3967..4979246368e 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -689,8 +689,7 @@ namespace ts.server { private suppressDiagnosticEvents?: boolean; private eventHandler: ProjectServiceEventHandler | undefined; private readonly noGetErrOnBackgroundUpdate?: boolean; - // TODO: Also need to do this in all of project too - private fshost: ServerHost | undefined + private fshost: ServerHost | undefined; constructor(opts: SessionOptions) { this.host = opts.host; @@ -2903,11 +2902,7 @@ namespace ts.server { }, [CommandNames.UpdateFileSystem]: (request: protocol.UpdateFileSystemRequest) => { this.changeSeq++; - this.projectService.updateFileSystem( - request.arguments.created && arrayIterator(request.arguments.created), - request.arguments.updated && arrayIterator(request.arguments.updated), - request.arguments.deleted, - ); + this.projectService.updateFileSystem(request.arguments.files, request.arguments.deleted); return this.requiredResponse(/*response*/ true); }, [CommandNames.Exit]: () => { diff --git a/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts b/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts index c51e398f188..75ab596c38e 100644 --- a/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts +++ b/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts @@ -57,14 +57,13 @@ ${file.fileContent}`; // TODO: probably some other watcher tests, not sure what const host = TestFSWithWatch.createVirtualServerHost([], { executingFilePath: "/a/tsc.js" }); const session = createVirtualFilesystemSession(host, host); - const created = [app, file1, file2, file3, config, lib]; + const files = [app, file1, file2, file3, config, lib]; session.executeCommandSeq({ command: protocol.CommandTypes.UpdateFileSystem, arguments:{ fileSystem: "memfs", - created, - deleted: [], // string[]; - updated: [], //FileSystemRequestArgs[]; + files, + deleted: [], } }); session.executeCommandSeq({ @@ -89,10 +88,10 @@ ${file.fileContent}`; verifyProjectVersion(project, 2); // Verify Texts - verifyFileSystem(host, created); - verifyText(service, file1.file, file1.fileContent!); + verifyFileSystem(host, files); + verifyText(service, file1.file, file1.fileContent); verifyText(service, commonFile2.path, commonFile2.content); - verifyText(service, app.file, app.fileContent!); + verifyText(service, app.file, app.fileContent); verifyText(service, file3.file, fileContentWithComment(file3)); assert.equal(fakehost.fsWatches.size, 0); assert.equal(fakehost.fsWatchesRecursive.size, 2); @@ -102,19 +101,18 @@ ${file.fileContent}`; command: protocol.CommandTypes.UpdateFileSystem, arguments:{ fileSystem: "memfs", - created: [], - deleted: [], // string[]; - updated: [], //FileSystemRequestArgs[]; + files: [], + deleted: [], } }); // no change when not deleting file verifyProjectVersion(project, 2); // Verify Texts - verifyFileSystem(host, created); - verifyText(service, file1.file, file1.fileContent!); + verifyFileSystem(host, files); + verifyText(service, file1.file, file1.fileContent); verifyText(service, commonFile2.path, commonFile2.content); - verifyText(service, app.file, app.fileContent!); + verifyText(service, app.file, app.fileContent); verifyText(service, file3.file, fileContentWithComment(file3)); assert.equal(fakehost.fsWatches.size, 0); assert.equal(fakehost.fsWatchesRecursive.size, 2); @@ -124,9 +122,8 @@ ${file.fileContent}`; command: protocol.CommandTypes.UpdateFileSystem, arguments:{ fileSystem: "memfs", - created: [], - deleted: [file1.file], // string[]; - updated: [], //FileSystemRequestArgs[]; + files: [], + deleted: [file1.file], } }); verifyProjectVersion(project, 3); @@ -134,7 +131,7 @@ ${file.fileContent}`; // Verify Texts verifyFileSystem(host, [app, file2, file3, config, lib]); verifyText(service, commonFile2.path, commonFile2.content); - verifyText(service, app.file, app.fileContent!); + verifyText(service, app.file, app.fileContent); verifyText(service, file3.file, fileContentWithComment(file3)); assert.equal(fakehost.fsWatches.size, 0); assert.equal(fakehost.fsWatchesRecursive.size, 2); @@ -151,7 +148,7 @@ ${file.fileContent}`; // Verify Texts verifyFileSystem(host, [app, file2, file3, config, lib]); verifyText(service, commonFile2.path, commonFile2.content); - verifyText(service, app.file, app.fileContent!); + verifyText(service, app.file, app.fileContent); verifyText(service, file3.file, fileContentWithComment(file3)); assert.equal(fakehost.fsWatches.size, 0); assert.equal(fakehost.fsWatchesRecursive.size, 2); diff --git a/src/tsserver/nodeServer.ts b/src/tsserver/nodeServer.ts index b6bcaf131ed..43fe0b77fff 100644 --- a/src/tsserver/nodeServer.ts +++ b/src/tsserver/nodeServer.ts @@ -680,7 +680,7 @@ namespace ts.server { this.event(body, eventName); }; - const host = fs // sys as ServerHost; + const host = fs; // sys as ServerHost; const typingsInstaller = disableAutomaticTypingAcquisition ? undefined @@ -688,6 +688,7 @@ namespace ts.server { super({ host, + fshost: host, cancellationToken, ...options, typingsInstaller: typingsInstaller || nullTypingsInstaller, diff --git a/src/tsserver/server.ts b/src/tsserver/server.ts index 39af0f4df16..a72cb263055 100644 --- a/src/tsserver/server.ts +++ b/src/tsserver/server.ts @@ -77,7 +77,7 @@ namespace ts.server { setStackTraceLimit(); // TODO: Not sure this is right - const fs = findArgument("vfs") ? TestFSWithWatch.createVirtualServerHost([]) : ts.sys as ServerHost + const fs = findArgument("vfs") ? TestFSWithWatch.createVirtualServerHost([]) : sys as ServerHost; // Cannot check process var directory in webworker so has to be typeof check here if (typeof process !== "undefined") { start(initializeNodeSystem(), require("os").platform(), fs); diff --git a/src/tsserver/webServer.ts b/src/tsserver/webServer.ts index 771dd2d58d1..3093819f452 100644 --- a/src/tsserver/webServer.ts +++ b/src/tsserver/webServer.ts @@ -98,7 +98,7 @@ namespace ts.server { // TODO: Maybe should leave as ServerHost cast below and declare fs: System // TODO: host is probably still a better name - function startWebSession(options: StartSessionOptions, logger: Logger, cancellationToken: ServerCancellationToken, fs: ServerHost) { + function startWebSession(options: StartSessionOptions, logger: Logger, cancellationToken: ServerCancellationToken, _fs_TODO: ServerHost) { class WorkerSession extends server.WorkerSession { constructor() { // TODO: Not really sure this is the way to do it diff --git a/src/vfs/tsconfig.json b/src/vfs/tsconfig.json index 655951fd7d3..b34f208d223 100644 --- a/src/vfs/tsconfig.json +++ b/src/vfs/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "outFile": "../../built/local/vfs.js", "types": [ - "node", "mocha", "chai" + "node" ], "lib": [ "es6", @@ -11,9 +11,7 @@ ] }, "references": [ - { "path": "../compiler" }, - { "path": "../jsTyping" }, - { "path": "../services" } + { "path": "../compiler" } ], "files": [ diff --git a/src/vfs/virtualFileSystemWithWatch.ts b/src/vfs/virtualFileSystemWithWatch.ts index cb000deb482..12add93babf 100644 --- a/src/vfs/virtualFileSystemWithWatch.ts +++ b/src/vfs/virtualFileSystemWithWatch.ts @@ -337,7 +337,7 @@ namespace ts.TestFSWithWatch { } if (options && options.invokeFileDeleteCreateAsPartInsteadOfChange) { - this.removeFileOrFolder(currentEntry, returnFalse); + this.removeFileOrFolder(currentEntry, false); this.ensureFileOrFolder({ path: filePath, content }); } else { @@ -363,7 +363,7 @@ namespace ts.TestFSWithWatch { Debug.assert(!!file); // Only remove the file - this.removeFileOrFolder(file, returnFalse, /*isRenaming*/ true); + this.removeFileOrFolder(file, false, /*isRenaming*/ true); // Add updated folder with new folder name const newFullPath = getNormalizedAbsolutePath(newFileName, this.currentDirectory); @@ -383,7 +383,7 @@ namespace ts.TestFSWithWatch { Debug.assert(!!folder); // Only remove the folder - this.removeFileOrFolder(folder, returnFalse, /*isRenaming*/ true); + this.removeFileOrFolder(folder, false, /*isRenaming*/ true); // Add updated folder with new folder name const newFullPath = getNormalizedAbsolutePath(newFolderName, this.currentDirectory); @@ -474,7 +474,7 @@ namespace ts.TestFSWithWatch { this.invokeFileAndFsWatches(folder.fullPath, FileWatcherEventKind.Changed); } - private removeFileOrFolder(fileOrDirectory: FsFile | FsFolder | FsSymLink, isRemovableLeafFolder: (folder: FsFolder) => boolean, isRenaming = false) { + private removeFileOrFolder(fileOrDirectory: FsFile | FsFolder | FsSymLink, isRemovableLeafFolder: boolean, isRenaming = false) { const basePath = getDirectoryPath(fileOrDirectory.path); const baseFolder = this.fs.get(basePath) as FsFolder; if (basePath !== fileOrDirectory.path) { @@ -491,16 +491,16 @@ namespace ts.TestFSWithWatch { this.invokeFileAndFsWatches(baseFolder.fullPath, FileWatcherEventKind.Changed); if (basePath !== fileOrDirectory.path && baseFolder.entries.length === 0 && - isRemovableLeafFolder(baseFolder)) { + isRemovableLeafFolder) { this.removeFileOrFolder(baseFolder, isRemovableLeafFolder); } } - deleteFile(filePath: string) { + deleteFile(filePath: string, deleteEmptyParentFolders = false) { const path = this.toFullPath(filePath); const currentEntry = this.fs.get(path) as FsFile; Debug.assert(isFsFile(currentEntry)); - this.removeFileOrFolder(currentEntry, returnFalse); + this.removeFileOrFolder(currentEntry, deleteEmptyParentFolders); } deleteFolder(folderPath: string, recursive?: boolean) { @@ -514,11 +514,11 @@ namespace ts.TestFSWithWatch { this.deleteFolder(fsEntry.fullPath, recursive); } else { - this.removeFileOrFolder(fsEntry, returnFalse); + this.removeFileOrFolder(fsEntry, false); } }); } - this.removeFileOrFolder(currentEntry, returnFalse); + this.removeFileOrFolder(currentEntry, false); } private watchFileWorker(fileName: string, cb: FileWatcherCallback, pollingInterval: PollingInterval) {