diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 6efa2af13de0f..28e7dd1cd85b7 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -474,9 +474,8 @@ interface Array { length: number; [n: number]: T; }` return new Date(this.time); } - reloadFS(fileOrFolderOrSymLinkList: readonly FileOrFolderOrSymLink[], options?: Partial) { - const mapNewLeaves = createMap(); - const isNewFs = this.fs.size === 0; + private reloadFS(fileOrFolderOrSymLinkList: readonly FileOrFolderOrSymLink[], options?: Partial) { + Debug.assert(this.fs.size === 0); fileOrFolderOrSymLinkList = fileOrFolderOrSymLinkList.concat(this.withSafeList ? safeList : []); const filesOrFoldersToLoad: readonly FileOrFolderOrSymLink[] = !this.windowsStyleRoot ? fileOrFolderOrSymLinkList : fileOrFolderOrSymLinkList.map(f => { @@ -486,7 +485,6 @@ interface Array { length: number; [n: number]: T; }` }); for (const fileOrDirectory of filesOrFoldersToLoad) { const path = this.toFullPath(fileOrDirectory.path); - mapNewLeaves.set(path, true); // If its a change const currentEntry = this.fs.get(path); if (currentEntry) { @@ -520,18 +518,6 @@ interface Array { length: number; [n: number]: T; }` this.ensureFileOrFolder(fileOrDirectory, options && options.ignoreWatchInvokedWithTriggerAsFileCreate); } } - - if (!isNewFs) { - this.fs.forEach((fileOrDirectory, path) => { - // If this entry is not from the new file or folder - if (!mapNewLeaves.get(path)) { - // Leaf entries that arent in new list => remove these - if (isFsFile(fileOrDirectory) || isFsSymLink(fileOrDirectory) || isFsFolder(fileOrDirectory) && fileOrDirectory.entries.length === 0) { - this.removeFileOrFolder(fileOrDirectory, folder => !mapNewLeaves.get(folder.path)); - } - } - }); - } } modifyFile(filePath: string, content: string, options?: Partial) { diff --git a/src/testRunner/unittests/tscWatch/resolutionCache.ts b/src/testRunner/unittests/tscWatch/resolutionCache.ts index 9de81f08410f2..a3f498ddce4b8 100644 --- a/src/testRunner/unittests/tscWatch/resolutionCache.ts +++ b/src/testRunner/unittests/tscWatch/resolutionCache.ts @@ -26,7 +26,7 @@ namespace ts.tscWatch { const newContent = `import {x} from "f1" var x: string = 1;`; root.content = newContent; - host.reloadFS(files); + host.writeFile(root.path, root.content); // patch fileExists to make sure that disk is not touched host.fileExists = notImplemented; @@ -53,7 +53,7 @@ namespace ts.tscWatch { }; root.content = `import {x} from "f2"`; - host.reloadFS(files); + host.writeFile(root.path, root.content); // trigger synchronization to make sure that system will try to find 'f2' module on disk host.runQueuedTimeoutCallbacks(); @@ -79,7 +79,7 @@ namespace ts.tscWatch { const newContent = `import {x} from "f1"`; root.content = newContent; - host.reloadFS(files); + host.writeFile(root.path, root.content); host.runQueuedTimeoutCallbacks(); checkOutputErrorsIncremental(host, [f1IsNotModule, cannotFindFoo]); @@ -123,7 +123,8 @@ namespace ts.tscWatch { fileExistsCalledForBar = false; root.content = `import {y} from "bar"`; - host.reloadFS(files.concat(imported)); + host.writeFile(root.path, root.content); + host.writeFile(imported.path, imported.content); host.runQueuedTimeoutCallbacks(); checkOutputErrorsIncremental(host, emptyArray); @@ -141,9 +142,7 @@ namespace ts.tscWatch { content: `export const y = 1;export const x = 10;` }; - const files = [root, libFile]; - const filesWithImported = files.concat(imported); - const host = createWatchedSystem(filesWithImported); + const host = createWatchedSystem([root, libFile, imported]); const originalFileExists = host.fileExists; let fileExistsCalledForBar = false; host.fileExists = fileName => { @@ -162,7 +161,7 @@ namespace ts.tscWatch { checkOutputErrorsInitial(host, emptyArray); fileExistsCalledForBar = false; - host.reloadFS(files); + host.deleteFile(imported.path); host.runQueuedTimeoutCallbacks(); assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); checkOutputErrorsIncremental(host, [ @@ -170,7 +169,7 @@ namespace ts.tscWatch { ]); fileExistsCalledForBar = false; - host.reloadFS(filesWithImported); + host.writeFile(imported.path, imported.content); host.checkTimeoutQueueLengthAndRun(1); checkOutputErrorsIncremental(host, emptyArray); assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); diff --git a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts index 601e2fa345151..7187be8c13946 100644 --- a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts +++ b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts @@ -246,7 +246,7 @@ namespace ts.projectSystem { callsTrackingHost.clear(); - host.reloadFS([root, imported]); + host.writeFile(imported.path, imported.content); host.runQueuedTimeoutCallbacks(); diags = project.getLanguageService().getSemanticDiagnostics(root.path); assert.equal(diags.length, 0); @@ -400,7 +400,7 @@ namespace ts.projectSystem { // Create file cookie.ts projectFiles.push(file3); - host.reloadFS(projectFiles); + host.writeFile(file3.path, file3.content); host.runQueuedTimeoutCallbacks(); const canonicalFile3Path = useCaseSensitiveFileNames ? file3.path : file3.path.toLocaleLowerCase(); @@ -482,7 +482,7 @@ namespace ts.projectSystem { content: "export {}" }; files.push(debugTypesFile); - host.reloadFS(files); + host.writeFile(debugTypesFile.path, debugTypesFile.content); host.runQueuedTimeoutCallbacks(); checkProjectActualFiles(project, files.map(f => f.path)); assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(file1.path).map(diag => diag.messageText), []); @@ -575,12 +575,13 @@ namespace ts.projectSystem { { path: "/a/b/node_modules/.staging/rxjs-22375c61/add/operator" }, { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/package.json", content: "{\n \"name\": \"@types/lodash\",\n \"version\": \"4.14.74\",\n \"description\": \"TypeScript definitions for Lo-Dash\",\n \"license\": \"MIT\",\n \"contributors\": [\n {\n \"name\": \"Brian Zengel\",\n \"url\": \"https://github.com/bczengel\"\n },\n {\n \"name\": \"Ilya Mochalov\",\n \"url\": \"https://github.com/chrootsu\"\n },\n {\n \"name\": \"Stepan Mikhaylyuk\",\n \"url\": \"https://github.com/stepancar\"\n },\n {\n \"name\": \"Eric L Anderson\",\n \"url\": \"https://github.com/ericanderson\"\n },\n {\n \"name\": \"AJ Richardson\",\n \"url\": \"https://github.com/aj-r\"\n },\n {\n \"name\": \"Junyoung Clare Jang\",\n \"url\": \"https://github.com/ailrun\"\n }\n ],\n \"main\": \"\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://www.github.com/DefinitelyTyped/DefinitelyTyped.git\"\n },\n \"scripts\": {},\n \"dependencies\": {},\n \"typesPublisherContentHash\": \"12af578ffaf8d86d2df37e591857906a86b983fa9258414326544a0fe6af0de8\",\n \"typeScriptVersion\": \"2.2\"\n}" }, { path: "/a/b/node_modules/.staging/lodash-b0733faa/index.js", content: "module.exports = require('./lodash');" }, - { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594" } + { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594", content: "" } ].map(getRootedFileOrFolder)); // Since we added/removed in .staging no timeout verifyAfterPartialOrCompleteNpmInstall(0); // Remove file "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594" + host.deleteFile(last(filesAndFoldersToAdd).path); filesAndFoldersToAdd.length--; verifyAfterPartialOrCompleteNpmInstall(0); @@ -602,6 +603,7 @@ namespace ts.projectSystem { verifyAfterPartialOrCompleteNpmInstall(0); // remove /a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041 + host.deleteFile(last(filesAndFoldersToAdd).path); filesAndFoldersToAdd.length--; // and add few more folders/files filesAndFoldersToAdd.push(...[ @@ -622,6 +624,7 @@ namespace ts.projectSystem { .replace(/[\-\.][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w][\d\w]/g, ""); }); + host.deleteFolder(root + "/a/b/node_modules/.staging", /*recursive*/ true); const lodashIndexPath = root + "/a/b/node_modules/@types/lodash/index.d.ts"; projectFiles.push(find(filesAndFoldersToAdd, f => f.path === lodashIndexPath)!); // we would now not have failed lookup in the parent of appFolder since lodash is available @@ -631,7 +634,7 @@ namespace ts.projectSystem { verifyAfterPartialOrCompleteNpmInstall(2); function verifyAfterPartialOrCompleteNpmInstall(timeoutQueueLengthWhenRunningTimeouts: number) { - host.reloadFS(projectFiles.concat(otherFiles, filesAndFoldersToAdd)); + filesAndFoldersToAdd.forEach(f => host.ensureFileOrFolder(f)); if (npmInstallComplete || timeoutDuringPartialInstallation) { host.checkTimeoutQueueLengthAndRun(timeoutQueueLengthWhenRunningTimeouts); } @@ -696,7 +699,7 @@ namespace ts.projectSystem { invoker.call(host, fullPath, eventName, entryFullPath); } }; - host.reloadFS(files); + host.writeFile(debugTypesFile.path, debugTypesFile.content); host.runQueuedTimeoutCallbacks(); checkProjectActualFiles(project, files.map(f => f.path)); assert.deepEqual(project.getLanguageService().getSemanticDiagnostics(app.path).map(diag => diag.messageText), []); diff --git a/src/testRunner/unittests/tsserver/compileOnSave.ts b/src/testRunner/unittests/tsserver/compileOnSave.ts index 29bb0a9525937..ae79a952d563c 100644 --- a/src/testRunner/unittests/tsserver/compileOnSave.ts +++ b/src/testRunner/unittests/tsserver/compileOnSave.ts @@ -192,8 +192,7 @@ namespace ts.projectSystem { // Send an initial compileOnSave request sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); - file1Consumer1.content = `let y = 10;`; - host.reloadFS([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]); + host.writeFile(file1Consumer1.path, `let y = 10;`); session.executeCommand(changeModuleFile1ShapeRequest1); sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer2] }]); @@ -209,7 +208,7 @@ namespace ts.projectSystem { session.executeCommand(changeModuleFile1ShapeRequest1); // Delete file1Consumer2 - host.reloadFS([moduleFile1, file1Consumer1, configFile, libFile]); + host.deleteFile(file1Consumer2.path); sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1] }]); }); @@ -225,7 +224,7 @@ namespace ts.projectSystem { path: "/a/b/file1Consumer3.ts", content: `import {Foo} from "./moduleFile1"; let y = Foo();` }; - host.reloadFS([moduleFile1, file1Consumer1, file1Consumer2, file1Consumer3, globalFile3, configFile, libFile]); + host.writeFile(file1Consumer3.path, file1Consumer3.content); host.runQueuedTimeoutCallbacks(); session.executeCommand(changeModuleFile1ShapeRequest1); sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2, file1Consumer3] }]); @@ -475,7 +474,7 @@ namespace ts.projectSystem { const session = createSession(host); openFilesForSession([referenceFile1], session); - host.reloadFS([referenceFile1, configFile]); + host.deleteFile(moduleFile1.path); const request = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); sendAffectedFileRequestAndCheckResult(session, request, [ diff --git a/src/testRunner/unittests/tsserver/configFileSearch.ts b/src/testRunner/unittests/tsserver/configFileSearch.ts index 5b8bce403c5dc..9da005e19e52e 100644 --- a/src/testRunner/unittests/tsserver/configFileSearch.ts +++ b/src/testRunner/unittests/tsserver/configFileSearch.ts @@ -48,7 +48,7 @@ namespace ts.projectSystem { checkWatchedDirectories(host, typeRootLocations.concat(configFileLocation), /*recursive*/ true); // Delete config file - should create inferred project and not configured project - host.reloadFS([f1, libFile, configFile2]); + host.deleteFile(configFile.path); host.runQueuedTimeoutCallbacks(); checkNumberOfProjects(service, { inferredProjects: 1 }); checkWatchedFiles(host, [libFile.path, configFile.path, `${configFileLocation}/jsconfig.json`, `${projectDir}/tsconfig.json`, `${projectDir}/jsconfig.json`]); @@ -81,7 +81,7 @@ namespace ts.projectSystem { checkWatchedDirectories(host, getTypeRootsFromLocation(configFileLocation).concat(configFileLocation), /*recursive*/ true); // Delete config file - should create inferred project with project root path set - host.reloadFS([f1, libFile, configFile2]); + host.deleteFile(configFile.path); host.runQueuedTimeoutCallbacks(); checkNumberOfProjects(service, { inferredProjects: 1 }); assert.equal(service.inferredProjects[0].projectRootPath, projectDir); @@ -100,8 +100,6 @@ namespace ts.projectSystem { path: `${projectRoot}/tsconfig.json`, content: "{}" }; - const files = [file, libFile]; - const filesWithConfig = files.concat(tsconfig); const dirOfFile = getDirectoryPath(file.path); function openClientFile(files: File[]) { @@ -141,27 +139,27 @@ namespace ts.projectSystem { } it("tsconfig for the file exists", () => { - const { host, projectService } = openClientFile(filesWithConfig); + const { host, projectService } = openClientFile([file, libFile, tsconfig]); verifyConfiguredProject(host, projectService); - host.reloadFS(files); + host.deleteFile(tsconfig.path); host.runQueuedTimeoutCallbacks(); verifyInferredProject(host, projectService); - host.reloadFS(filesWithConfig); + host.writeFile(tsconfig.path, tsconfig.content); host.runQueuedTimeoutCallbacks(); verifyConfiguredProject(host, projectService, /*orphanInferredProject*/ true); }); it("tsconfig for the file does not exist", () => { - const { host, projectService } = openClientFile(files); + const { host, projectService } = openClientFile([file, libFile]); verifyInferredProject(host, projectService); - host.reloadFS(filesWithConfig); + host.writeFile(tsconfig.path, tsconfig.content); host.runQueuedTimeoutCallbacks(); verifyConfiguredProject(host, projectService, /*orphanInferredProject*/ true); - host.reloadFS(files); + host.deleteFile(tsconfig.path); host.runQueuedTimeoutCallbacks(); verifyInferredProject(host, projectService); }); diff --git a/src/testRunner/unittests/tsserver/configuredProjects.ts b/src/testRunner/unittests/tsserver/configuredProjects.ts index b8ec47946a302..7e53d229a175c 100644 --- a/src/testRunner/unittests/tsserver/configuredProjects.ts +++ b/src/testRunner/unittests/tsserver/configuredProjects.ts @@ -97,10 +97,8 @@ namespace ts.projectSystem { content: "let y = 1" }; - const filesWithoutConfig = [libFile, commonFile1, commonFile2]; - const host = createServerHost(filesWithoutConfig); + const host = createServerHost([libFile, commonFile1, commonFile2]); - const filesWithConfig = [libFile, commonFile1, commonFile2, configFile]; const projectService = createProjectService(host); projectService.openClientFile(commonFile1.path); projectService.openClientFile(commonFile2.path); @@ -113,7 +111,7 @@ namespace ts.projectSystem { checkWatchedFiles(host, watchedFiles); // Add a tsconfig file - host.reloadFS(filesWithConfig); + host.writeFile(configFile.path, configFile.content); host.checkTimeoutQueueLengthAndRun(2); // load configured project from disk + ensureProjectsForOpenFiles projectService.checkNumberOfProjects({ inferredProjects: 2, configuredProjects: 1 }); @@ -124,7 +122,7 @@ namespace ts.projectSystem { checkWatchedFiles(host, watchedFiles); // remove the tsconfig file - host.reloadFS(filesWithoutConfig); + host.deleteFile(configFile.path); projectService.checkNumberOfProjects({ inferredProjects: 2 }); assert.isTrue(projectService.inferredProjects[0].isOrphan()); @@ -154,7 +152,7 @@ namespace ts.projectSystem { checkProjectRootFiles(project, [commonFile1.path]); // add a new ts file - host.reloadFS([commonFile1, commonFile2, libFile, configFile]); + host.writeFile(commonFile2.path, commonFile2.content); host.checkTimeoutQueueLengthAndRun(2); // project service waits for 250ms to update the project structure, therefore the assertion needs to wait longer. checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]); @@ -196,12 +194,12 @@ namespace ts.projectSystem { checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]); // delete commonFile2 - host.reloadFS([commonFile1, configFile]); + host.deleteFile(commonFile2.path); host.checkTimeoutQueueLengthAndRun(2); checkProjectRootFiles(project, [commonFile1.path]); // re-add commonFile2 - host.reloadFS([commonFile1, commonFile2, configFile]); + host.writeFile(commonFile2.path, commonFile2.content); host.checkTimeoutQueueLengthAndRun(2); checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]); }); @@ -269,13 +267,12 @@ namespace ts.projectSystem { checkProjectActualFiles(project, [file1.path, nodeModuleFile.path, configFile.path]); checkProjectActualFiles(projectService.inferredProjects[0], [classicModuleFile.path]); - configFile.content = `{ + host.writeFile(configFile.path, `{ "compilerOptions": { "moduleResolution": "classic" }, "files": ["${file1.path}"] - }`; - host.reloadFS(files); + }`); host.checkTimeoutQueueLengthAndRun(2); checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); // will not remove project 1 @@ -468,7 +465,7 @@ namespace ts.projectSystem { checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); - host.reloadFS([file1, file2, file3, configFile]); + host.writeFile(configFile.path, configFile.content); host.checkTimeoutQueueLengthAndRun(2); // load configured project from disk + ensureProjectsForOpenFiles checkNumberOfProjects(projectService, { configuredProjects: 1, inferredProjects: 2 }); checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, file3.path, configFile.path]); @@ -497,7 +494,7 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, configFile.path]); - host.reloadFS([file1, file2, configFile]); + host.writeFile(file2.path, file2.content); host.checkTimeoutQueueLengthAndRun(2); @@ -526,12 +523,7 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, configFile.path]); - const modifiedConfigFile = { - path: configFile.path, - content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }) - }; - - host.reloadFS([file1, file2, modifiedConfigFile]); + host.writeFile(configFile.path, JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })); checkNumberOfProjects(projectService, { configuredProjects: 1 }); host.checkTimeoutQueueLengthAndRun(2); @@ -559,12 +551,7 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, configFile.path]); - const modifiedConfigFile = { - path: configFile.path, - content: JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] }) - }; - - host.reloadFS([file1, file2, modifiedConfigFile]); + host.writeFile(configFile.path, JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] })); checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectRootFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path]); @@ -612,8 +599,7 @@ namespace ts.projectSystem { const inferredProject2 = projectService.inferredProjects[1]; checkProjectActualFiles(inferredProject2, [file4.path]); - configFile.content = "{}"; - host.reloadFS(files.concat(configFile)); + host.writeFile(configFile.path, "{}"); host.runQueuedTimeoutCallbacks(); verifyScriptInfos(); @@ -653,7 +639,7 @@ namespace ts.projectSystem { path: "/file5.ts", content: "let zz = 1;" }; - host.reloadFS(files.concat(configFile, file5)); + host.writeFile(file5.path, file5.content); projectService.openClientFile(file5.path); verifyScriptInfosAreUndefined([file1, file2, file3]); assert.strictEqual(projectService.getScriptInfoForPath(file4.path as Path), find(infos, info => info.path === file4.path)); @@ -724,8 +710,7 @@ namespace ts.projectSystem { projectService.closeClientFile(file3.path); assert.isFalse(configuredProject.hasOpenRef()); // No files - configFile.content = "{}"; - host.reloadFS(files.concat(configFile)); + host.writeFile(configFile.path, "{}"); // Time out is not yet run so there is project update pending assert.isTrue(configuredProject.hasOpenRef()); // Pending update and file2 might get into the project @@ -795,7 +780,7 @@ namespace ts.projectSystem { path: "/aa.js", content: "var x = 1" }; - host.reloadFS([f1, f2, f3, config, f4]); + host.writeFile(f4.path, f4.content); projectService.openClientFile(f4.path); projectService.checkNumberOfProjects({ inferredProjects: 1 }); assert.isFalse(project.hasOpenRef()); // No files @@ -1219,7 +1204,7 @@ foo();` checkWatchedDirectoriesDetailed(host, ["/a/b/node_modules/@types"], 1, /*recursive*/ true); files.push(file2); - host.reloadFS(files); + host.writeFile(file2.path, file2.content); host.runQueuedTimeoutCallbacks(); checkNumberOfProjects(projectService, { configuredProjects: 1 }); assert.strictEqual(projectService.configuredProjects.get(configFile.path), project); diff --git a/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts b/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts index 231c46c350b7a..da6718ef9c7ff 100644 --- a/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts +++ b/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts @@ -38,7 +38,7 @@ namespace ts.projectSystem { assert.equal(events[0].data.project.getProjectName(), config.path, "config path"); assert.isFalse(events[0].data.languageServiceEnabled, "Language service state"); - host.reloadFS([f1, f2, configWithExclude]); + host.writeFile(configWithExclude.path, configWithExclude.content); host.checkTimeoutQueueLengthAndRun(2); checkNumberOfProjects(projectService, { configuredProjects: 1 }); assert.isTrue(project.languageServiceEnabled, "Language service enabled"); diff --git a/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts b/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts index c247e2c224ddf..f6bf4e4a970c2 100644 --- a/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts +++ b/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts @@ -51,7 +51,7 @@ namespace ts.projectSystem { const { verifyProjectsUpdatedInBackgroundEventHandler, verifyInitialOpen } = createSession(host); verifyInitialOpen(commonFile1); - host.reloadFS([commonFile1, libFile, configFile, commonFile2]); + host.writeFile(commonFile2.path, commonFile2.content); host.runQueuedTimeoutCallbacks(); verifyProjectsUpdatedInBackgroundEventHandler([{ eventName: server.ProjectsUpdatedInBackgroundEvent, @@ -60,7 +60,7 @@ namespace ts.projectSystem { } }]); - host.reloadFS([commonFile1, commonFile2, libFile, configFile, commonFile3]); + host.writeFile(commonFile3.path, commonFile3.content); host.runQueuedTimeoutCallbacks(); verifyProjectsUpdatedInBackgroundEventHandler([{ eventName: server.ProjectsUpdatedInBackgroundEvent, @@ -94,8 +94,7 @@ namespace ts.projectSystem { const { verifyInitialOpen, verifyProjectsUpdatedInBackgroundEventHandler } = createSession(host); verifyInitialOpen(f1); - files.push(f2); - host.reloadFS(files); + host.writeFile(f2.path, f2.content); host.runQueuedTimeoutCallbacks(); verifyProjectsUpdatedInBackgroundEventHandler([{ @@ -105,8 +104,7 @@ namespace ts.projectSystem { } }]); - f2.content = "export let x = 11"; - host.reloadFS(files); + host.writeFile(f2.path, "export let x = 11"); host.runQueuedTimeoutCallbacks(); verifyProjectsUpdatedInBackgroundEventHandler([{ eventName: server.ProjectsUpdatedInBackgroundEvent, @@ -186,11 +184,12 @@ namespace ts.projectSystem { verifyInitialOpen(filesToReload[0]); // Since this is first event, it will have all the files - verifyProjectsUpdatedInBackgroundEvent(filesToReload); + filesToReload.forEach(f => host.ensureFileOrFolder(f)); + verifyProjectsUpdatedInBackgroundEvent(); return { + host, moduleFile1, file1Consumer1, file1Consumer2, moduleFile2, globalFile3, configFile, - files, updateContentOfOpenFile, verifyNoProjectsUpdatedInBackgroundEvent, verifyProjectsUpdatedInBackgroundEvent @@ -204,14 +203,12 @@ namespace ts.projectSystem { return find(files, file => file.path === fileName)!; } - function verifyNoProjectsUpdatedInBackgroundEvent(filesToReload?: File[]) { - host.reloadFS(filesToReload || files); + function verifyNoProjectsUpdatedInBackgroundEvent() { host.runQueuedTimeoutCallbacks(); verifyProjectsUpdatedInBackgroundEventHandler([]); } - function verifyProjectsUpdatedInBackgroundEvent(filesToReload?: File[]) { - host.reloadFS(filesToReload || files); + function verifyProjectsUpdatedInBackgroundEvent() { host.runQueuedTimeoutCallbacks(); verifyProjectsUpdatedInBackgroundEventHandler([{ eventName: server.ProjectsUpdatedInBackgroundEvent, @@ -238,26 +235,26 @@ namespace ts.projectSystem { } it("should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", () => { - const { moduleFile1, verifyProjectsUpdatedInBackgroundEvent } = getInitialState(); + const { host, moduleFile1, verifyProjectsUpdatedInBackgroundEvent } = getInitialState(); // Change the content of moduleFile1 to `export var T: number;export function Foo() { };` - moduleFile1.content = `export var T: number;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); verifyProjectsUpdatedInBackgroundEvent(); // Change the content of moduleFile1 to `export var T: number;export function Foo() { console.log('hi'); };` - moduleFile1.content = `export var T: number;export function Foo() { console.log('hi'); };`; + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { console.log('hi'); };`); verifyProjectsUpdatedInBackgroundEvent(); }); it("should be up-to-date with the reference map changes", () => { - const { moduleFile1, file1Consumer1, updateContentOfOpenFile, verifyProjectsUpdatedInBackgroundEvent, verifyNoProjectsUpdatedInBackgroundEvent } = getInitialState(); + const { host, moduleFile1, file1Consumer1, updateContentOfOpenFile, verifyProjectsUpdatedInBackgroundEvent, verifyNoProjectsUpdatedInBackgroundEvent } = getInitialState(); // Change file1Consumer1 content to `export let y = Foo();` updateContentOfOpenFile(file1Consumer1, "export let y = Foo();"); verifyNoProjectsUpdatedInBackgroundEvent(); // Change the content of moduleFile1 to `export var T: number;export function Foo() { };` - moduleFile1.content = `export var T: number;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); verifyProjectsUpdatedInBackgroundEvent(); // Add the import statements back to file1Consumer1 @@ -265,7 +262,7 @@ namespace ts.projectSystem { verifyNoProjectsUpdatedInBackgroundEvent(); // Change the content of moduleFile1 to `export var T: number;export var T2: string;export function Foo() { };` - moduleFile1.content = `export var T: number;export var T2: string;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T: number;export var T2: string;export function Foo() { };`); verifyProjectsUpdatedInBackgroundEvent(); // Multiple file edits in one go: @@ -273,68 +270,65 @@ namespace ts.projectSystem { // Change file1Consumer1 content to `export let y = Foo();` // Change the content of moduleFile1 to `export var T: number;export function Foo() { };` updateContentOfOpenFile(file1Consumer1, `export let y = Foo();`); - moduleFile1.content = `export var T: number;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); verifyProjectsUpdatedInBackgroundEvent(); }); it("should be up-to-date with deleted files", () => { - const { moduleFile1, file1Consumer2, files, verifyProjectsUpdatedInBackgroundEvent } = getInitialState(); + const { host, moduleFile1, file1Consumer2, verifyProjectsUpdatedInBackgroundEvent } = getInitialState(); // Change the content of moduleFile1 to `export var T: number;export function Foo() { };` - moduleFile1.content = `export var T: number;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); // Delete file1Consumer2 - const filesToLoad = filter(files, file => file !== file1Consumer2); - verifyProjectsUpdatedInBackgroundEvent(filesToLoad); + host.deleteFile(file1Consumer2.path); + verifyProjectsUpdatedInBackgroundEvent(); }); it("should be up-to-date with newly created files", () => { - const { moduleFile1, files, verifyProjectsUpdatedInBackgroundEvent, } = getInitialState(); + const { host, moduleFile1, verifyProjectsUpdatedInBackgroundEvent, } = getInitialState(); - const file1Consumer3: File = { - path: "/a/b/file1Consumer3.ts", - content: `import {Foo} from "./moduleFile1"; let y = Foo();` - }; - moduleFile1.content = `export var T: number;export function Foo() { };`; - verifyProjectsUpdatedInBackgroundEvent(files.concat(file1Consumer3)); + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); + host.writeFile("/a/b/file1Consumer3.ts", `import {Foo} from "./moduleFile1"; let y = Foo();`); + verifyProjectsUpdatedInBackgroundEvent(); }); it("should detect changes in non-root files", () => { - const { moduleFile1, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ + const { host, moduleFile1, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ configObj: { files: [file1Consumer1Path] }, }); - moduleFile1.content = `export var T: number;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); verifyProjectsUpdatedInBackgroundEvent(); // change file1 internal, and verify only file1 is affected - moduleFile1.content += "var T1: number;"; + host.writeFile(moduleFile1.path, moduleFile1.content + "var T1: number;"); verifyProjectsUpdatedInBackgroundEvent(); }); it("should return all files if a global file changed shape", () => { - const { globalFile3, verifyProjectsUpdatedInBackgroundEvent } = getInitialState(); + const { host, globalFile3, verifyProjectsUpdatedInBackgroundEvent } = getInitialState(); - globalFile3.content += "var T2: string;"; + host.writeFile(globalFile3.path, globalFile3.content + "var T2: string;"); verifyProjectsUpdatedInBackgroundEvent(); }); it("should always return the file itself if '--isolatedModules' is specified", () => { - const { moduleFile1, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ + const { host, moduleFile1, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ configObj: { compilerOptions: { isolatedModules: true } } }); - moduleFile1.content = `export var T: number;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); verifyProjectsUpdatedInBackgroundEvent(); }); it("should always return the file itself if '--out' or '--outFile' is specified", () => { const outFilePath = "/a/b/out.js"; - const { moduleFile1, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ + const { host, moduleFile1, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ configObj: { compilerOptions: { module: "system", outFile: outFilePath } } }); - moduleFile1.content = `export var T: number;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); verifyProjectsUpdatedInBackgroundEvent(); }); @@ -343,7 +337,7 @@ namespace ts.projectSystem { path: "/a/b/file1Consumer1Consumer1.ts", content: `import {y} from "./file1Consumer1";` }; - const { moduleFile1, file1Consumer1, updateContentOfOpenFile, verifyNoProjectsUpdatedInBackgroundEvent, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ + const { host, moduleFile1, file1Consumer1, updateContentOfOpenFile, verifyNoProjectsUpdatedInBackgroundEvent, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ getAdditionalFileOrFolder: () => [file1Consumer1Consumer1] }); @@ -351,12 +345,12 @@ namespace ts.projectSystem { verifyNoProjectsUpdatedInBackgroundEvent(); // Doesnt change the shape of file1Consumer1 - moduleFile1.content = `export var T: number;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); verifyProjectsUpdatedInBackgroundEvent(); // Change both files before the timeout updateContentOfOpenFile(file1Consumer1, file1Consumer1.content + "export var T2: number;"); - moduleFile1.content = `export var T2: number;export function Foo() { };`; + host.writeFile(moduleFile1.path, `export var T2: number;export function Foo() { };`); verifyProjectsUpdatedInBackgroundEvent(); }); @@ -373,13 +367,13 @@ namespace ts.projectSystem { /// export var t2 = 10;` }; - const { configFile, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ + const { host, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ getAdditionalFileOrFolder: () => [file1, file2], firstReloadFileList: [file1.path, libFile.path, file2.path, configFilePath] }); - file2.content += "export var t3 = 10;"; - verifyProjectsUpdatedInBackgroundEvent([file1, file2, libFile, configFile]); + host.writeFile(file2.path, file2.content + "export var t3 = 10;"); + verifyProjectsUpdatedInBackgroundEvent(); }); it("should detect removed code file", () => { @@ -389,12 +383,13 @@ namespace ts.projectSystem { /// export var x = Foo();` }; - const { configFile, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ + const { host, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ getAdditionalFileOrFolder: () => [referenceFile1], firstReloadFileList: [referenceFile1.path, libFile.path, moduleFile1Path, configFilePath] }); - verifyProjectsUpdatedInBackgroundEvent([libFile, referenceFile1, configFile]); + host.deleteFile(moduleFile1Path); + verifyProjectsUpdatedInBackgroundEvent(); }); it("should detect non-existing code file", () => { @@ -404,16 +399,17 @@ namespace ts.projectSystem { /// export var x = Foo();` }; - const { configFile, moduleFile2, updateContentOfOpenFile, verifyNoProjectsUpdatedInBackgroundEvent, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ + const { host, moduleFile2, updateContentOfOpenFile, verifyNoProjectsUpdatedInBackgroundEvent, verifyProjectsUpdatedInBackgroundEvent } = getInitialState({ getAdditionalFileOrFolder: () => [referenceFile1], firstReloadFileList: [referenceFile1.path, libFile.path, configFilePath] }); updateContentOfOpenFile(referenceFile1, referenceFile1.content + "export var yy = Foo();"); - verifyNoProjectsUpdatedInBackgroundEvent([libFile, referenceFile1, configFile]); + verifyNoProjectsUpdatedInBackgroundEvent(); // Create module File2 and see both files are saved - verifyProjectsUpdatedInBackgroundEvent([libFile, moduleFile2, referenceFile1, configFile]); + host.writeFile(moduleFile2.path, moduleFile2.content); + verifyProjectsUpdatedInBackgroundEvent(); }); }); @@ -453,7 +449,7 @@ namespace ts.projectSystem { verifyProject(); file3.content += "export class d {}"; - host.reloadFS(projectFiles); + host.writeFile(file3.path, file3.content); host.checkTimeoutQueueLengthAndRun(2); // Since this is first event @@ -466,7 +462,7 @@ namespace ts.projectSystem { }]); projectFiles.push(file2); - host.reloadFS(projectFiles); + host.writeFile(file2.path, file2.content); host.runQueuedTimeoutCallbacks(); if (useSlashRootAsSomeNotRootFolderInUserDirectory) { watchedRecursiveDirectories.length = 3; diff --git a/src/testRunner/unittests/tsserver/externalProjects.ts b/src/testRunner/unittests/tsserver/externalProjects.ts index 54a488c0c94c2..57f9aa1544f8d 100644 --- a/src/testRunner/unittests/tsserver/externalProjects.ts +++ b/src/testRunner/unittests/tsserver/externalProjects.ts @@ -528,7 +528,7 @@ namespace ts.projectSystem { emptyArray : // Since no files opened from this project, its not loaded [configFile.path]); - host.reloadFS([libFile, site]); + host.deleteFile(configFile.path); host.checkTimeoutQueueLengthAndRun(1); knownProjects = projectService.synchronizeProjectList(map(knownProjects, proj => proj.info!)); // TODO: GH#18217 GH#20039 @@ -578,7 +578,7 @@ namespace ts.projectSystem { checkProjectActualFiles(projectService.externalProjects[0], [f1.path, f2.path]); // rename lib.ts to tsconfig.json - host.reloadFS([f1, tsconfig]); + host.renameFile(f2.path, tsconfig.path); projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path, tsconfig.path]), @@ -592,7 +592,7 @@ namespace ts.projectSystem { checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]); // rename tsconfig.json back to lib.ts - host.reloadFS([f1, f2]); + host.renameFile(tsconfig.path, f2.path); projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path, f2.path]), @@ -762,7 +762,7 @@ namespace ts.projectSystem { projectService.checkNumberOfProjects({ configuredProjects: 1 }); checkProjectActualFiles(configuredProjectAt(projectService, 0), [libES5.path, app.path, config1.path]); - host.reloadFS([libES5, libES2015Promise, app, config2]); + host.writeFile(config2.path, config2.content); host.checkTimeoutQueueLengthAndRun(2); projectService.checkNumberOfProjects({ configuredProjects: 1 }); diff --git a/src/testRunner/unittests/tsserver/importSuggestionsCache.ts b/src/testRunner/unittests/tsserver/importSuggestionsCache.ts index 657c376db3aba..053c230972402 100644 --- a/src/testRunner/unittests/tsserver/importSuggestionsCache.ts +++ b/src/testRunner/unittests/tsserver/importSuggestionsCache.ts @@ -24,7 +24,7 @@ namespace ts.projectSystem { it("invalidates the cache when new files are added", () => { const { host, importSuggestionsCache, checker } = setup(); - host.reloadFS([aTs, bTs, ambientDeclaration, tsconfig, { ...aTs, path: "/src/a2.ts" }]); + host.writeFile("/src/a2.ts", aTs.content); host.runQueuedTimeoutCallbacks(); assert.isUndefined(importSuggestionsCache.get(bTs.path, checker)); }); @@ -32,7 +32,7 @@ namespace ts.projectSystem { it("invalidates the cache when files are deleted", () => { const { host, projectService, importSuggestionsCache, checker } = setup(); projectService.closeClientFile(aTs.path); - host.reloadFS([bTs, ambientDeclaration, tsconfig]); + host.deleteFile(aTs.path); host.runQueuedTimeoutCallbacks(); assert.isUndefined(importSuggestionsCache.get(bTs.path, checker)); }); diff --git a/src/testRunner/unittests/tsserver/inferredProjects.ts b/src/testRunner/unittests/tsserver/inferredProjects.ts index 04a849353b80f..8fb0e9fd69819 100644 --- a/src/testRunner/unittests/tsserver/inferredProjects.ts +++ b/src/testRunner/unittests/tsserver/inferredProjects.ts @@ -64,7 +64,7 @@ namespace ts.projectSystem { checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path, libFile.path]); - host.reloadFS([file1, configFile, file2, file3, libFile]); + host.writeFile(configFile.path, configFile.content); host.checkTimeoutQueueLengthAndRun(2); // load configured project from disk + ensureProjectsForOpenFiles checkNumberOfConfiguredProjects(projectService, 1); checkNumberOfInferredProjects(projectService, 1); diff --git a/src/testRunner/unittests/tsserver/openFile.ts b/src/testRunner/unittests/tsserver/openFile.ts index 52949ab821a64..805422cabdfb5 100644 --- a/src/testRunner/unittests/tsserver/openFile.ts +++ b/src/testRunner/unittests/tsserver/openFile.ts @@ -94,7 +94,7 @@ namespace ts.projectSystem { content: `export {}; declare module "./a" { export const y: number; }` }; files.push(bFile); - host.reloadFS(files); + host.writeFile(bFile.path, bFile.content); service.openClientFile(bFile.path, /*fileContent*/ undefined, ScriptKind.TS, projectFolder); verifyProject(); diff --git a/src/testRunner/unittests/tsserver/packageJsonInfo.ts b/src/testRunner/unittests/tsserver/packageJsonInfo.ts index 20be7ce56e3ab..4e0908ec9092a 100644 --- a/src/testRunner/unittests/tsserver/packageJsonInfo.ts +++ b/src/testRunner/unittests/tsserver/packageJsonInfo.ts @@ -29,7 +29,7 @@ namespace ts.projectSystem { assert.isUndefined(project.packageJsonCache.getInDirectory("/" as Path)); // Add package.json - host.reloadFS([tsConfig, packageJson]); + host.writeFile(packageJson.path, packageJson.content); let packageJsonInfo = project.packageJsonCache.getInDirectory("/" as Path)!; assert.ok(packageJsonInfo); assert.ok(packageJsonInfo.dependencies); @@ -38,16 +38,10 @@ namespace ts.projectSystem { assert.ok(packageJsonInfo.optionalDependencies); // Edit package.json - host.reloadFS([ - tsConfig, - { - ...packageJson, - content: JSON.stringify({ - ...packageJsonContent, - dependencies: undefined - }) - } - ]); + host.writeFile(packageJson.path, JSON.stringify({ + ...packageJsonContent, + dependencies: undefined + })); packageJsonInfo = project.packageJsonCache.getInDirectory("/" as Path)!; assert.isUndefined(packageJsonInfo.dependencies); }); @@ -59,7 +53,7 @@ namespace ts.projectSystem { assert.ok(project.packageJsonCache.getInDirectory("/" as Path)); // Delete package.json - host.reloadFS([tsConfig]); + host.deleteFile(packageJson.path); assert.isUndefined(project.packageJsonCache.getInDirectory("/" as Path)); }); @@ -67,7 +61,7 @@ namespace ts.projectSystem { // Initialize project with package.json at root const { project, host } = setup(); // Add package.json in /src - host.reloadFS([tsConfig, packageJson, { ...packageJson, path: "/src/package.json" }]); + host.writeFile("/src/package.json", packageJson.content); assert.lengthOf(project.getPackageJsonsVisibleToFile("/a.ts" as Path), 1); assert.lengthOf(project.getPackageJsonsVisibleToFile("/src/b.ts" as Path), 2); }); diff --git a/src/testRunner/unittests/tsserver/projectErrors.ts b/src/testRunner/unittests/tsserver/projectErrors.ts index 9019644537561..b5386939807eb 100644 --- a/src/testRunner/unittests/tsserver/projectErrors.ts +++ b/src/testRunner/unittests/tsserver/projectErrors.ts @@ -57,7 +57,7 @@ namespace ts.projectSystem { // only file1 exists - expect error checkDiagnosticsWithLinePos(diags, ["File '/a/b/applib.ts' not found."]); } - host.reloadFS([file2, libFile]); + host.renameFile(file1.path, file2.path); { // only file2 exists - expect error checkNumberOfProjects(projectService, { externalProjects: 1 }); @@ -65,7 +65,7 @@ namespace ts.projectSystem { checkDiagnosticsWithLinePos(diags, ["File '/a/b/app.ts' not found."]); } - host.reloadFS([file1, file2, libFile]); + host.writeFile(file1.path, file1.content); { // both files exist - expect no errors checkNumberOfProjects(projectService, { externalProjects: 1 }); @@ -102,7 +102,7 @@ namespace ts.projectSystem { let diags = session.executeCommand(compilerOptionsRequest).response as server.protocol.DiagnosticWithLinePosition[]; checkDiagnosticsWithLinePos(diags, ["File '/a/b/applib.ts' not found."]); - host.reloadFS([file1, file2, config, libFile]); + host.writeFile(file2.path, file2.content); checkNumberOfProjects(projectService, { configuredProjects: 1 }); diags = session.executeCommand(compilerOptionsRequest).response as server.protocol.DiagnosticWithLinePosition[]; @@ -143,7 +143,7 @@ namespace ts.projectSystem { assert.equal(projectErrors[0].file!.fileName, corruptedConfig.path); } // fix config and trigger watcher - host.reloadFS([file1, file2, correctConfig]); + host.writeFile(correctConfig.path, correctConfig.content); { projectService.checkNumberOfProjects({ configuredProjects: 1 }); const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; @@ -184,7 +184,7 @@ namespace ts.projectSystem { checkProjectErrorsWorker(projectErrors, []); } // break config and trigger watcher - host.reloadFS([file1, file2, corruptedConfig]); + host.writeFile(corruptedConfig.path, corruptedConfig.content); { projectService.checkNumberOfProjects({ configuredProjects: 1 }); const configuredProject = find(projectService.synchronizeProjectList([]), f => f.info!.projectName === corruptedConfig.path)!; @@ -613,7 +613,7 @@ declare module '@custom/plugin' { "haha": 123 } }`; - serverEventManager.host.reloadFS(files); + serverEventManager.host.writeFile(configFile.path, configFile.content); serverEventManager.host.runQueuedTimeoutCallbacks(); serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path, [ getUnknownCompilerOptionDiagnostic(configFile, "haha") @@ -622,7 +622,7 @@ declare module '@custom/plugin' { configFile.content = `{ "compilerOptions": {} }`; - serverEventManager.host.reloadFS(files); + serverEventManager.host.writeFile(configFile.path, configFile.content); serverEventManager.host.runQueuedTimeoutCallbacks(); serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path, emptyArray); }); @@ -859,7 +859,7 @@ declare module '@custom/plugin' { assert.isTrue(diags.length === 3); configFile.content = configFileContentWithoutCommentLine; - host.reloadFS([file, configFile]); + host.writeFile(configFile.path, configFile.content); const diagsAfterEdit = session.executeCommand({ type: "request", diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index fe6486e706d96..2de2da67af3d8 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -27,7 +27,7 @@ namespace ts.projectSystem { { diagnosticMessage: Diagnostics.File_0_not_found, errorTextArguments: [commonFile2.path] } ]); - host.reloadFS([file1, commonFile2, libFile]); + host.writeFile(commonFile2.path, commonFile2.content); host.runQueuedTimeoutCallbacks(); checkNumberOfInferredProjects(projectService, 1); assert.strictEqual(projectService.inferredProjects[0], project, "Inferred project should be same"); @@ -56,7 +56,7 @@ namespace ts.projectSystem { "compilerOptions": {}, "files": ["${commonFile1.path}"] }`; - host.reloadFS(files); + host.writeFile(configFile.path, configFile.content); checkNumberOfConfiguredProjects(projectService, 1); checkProjectRootFiles(project, [commonFile1.path, commonFile2.path]); @@ -302,16 +302,11 @@ namespace ts.projectSystem { const inferredProject1 = projectService.inferredProjects[1]; checkProjectActualFiles(projectService.inferredProjects[1], [file3.path]); - const modifiedFile2 = { - path: file2.path, - content: `export * from "../c/f3"` // now inferred project should inclule file3 - }; - - host.reloadFS([file1, modifiedFile2, file3]); + host.writeFile(file2.path, `export * from "../c/f3"`); // now inferred project should inclule file3 host.checkTimeoutQueueLengthAndRun(2); checkNumberOfProjects(projectService, { inferredProjects: 2 }); assert.strictEqual(projectService.inferredProjects[0], inferredProject0); - checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, modifiedFile2.path, file3.path]); + checkProjectActualFiles(projectService.inferredProjects[0], [file1.path, file2.path, file3.path]); assert.strictEqual(projectService.inferredProjects[1], inferredProject1); assert.isTrue(inferredProject1.isOrphan()); }); @@ -341,7 +336,7 @@ namespace ts.projectSystem { projectService.openClientFile(file3.path); checkNumberOfProjects(projectService, { inferredProjects: 1 }); - host.reloadFS([file1, file3]); + host.deleteFile(file2.path); host.checkTimeoutQueueLengthAndRun(2); checkNumberOfProjects(projectService, { inferredProjects: 2 }); @@ -621,7 +616,7 @@ namespace ts.projectSystem { checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectActualFiles(configuredProjectAt(projectService, 0), [file1.path, file2.path, config.path]); - host.reloadFS([file1, file2]); + host.deleteFile(config.path); host.checkTimeoutQueueLengthAndRun(1); checkNumberOfProjects(projectService, { inferredProjects: 2 }); checkProjectActualFiles(projectService.inferredProjects[0], [file1.path]); @@ -1182,7 +1177,7 @@ namespace ts.projectSystem { }); file2.content += "export let z = 10;"; - host.reloadFS(files); + host.writeFile(file2.path, file2.content); // Do not let the timeout runs, before executing command const startOffset = file2.content.indexOf("y") + 1; session.executeCommandSeq({ @@ -1277,14 +1272,14 @@ namespace ts.projectSystem { files: ["src/file1.ts"] }); config.content = configContent2; - host.reloadFS(files); + host.writeFile(config.path, config.content); host.runQueuedTimeoutCallbacks(); checkProjectActualFiles(service.configuredProjects.get(config.path)!, [file1.path, libFile.path, config.path]); verifyFile2InfoIsOrphan(); file2.content += "export let z = 10;"; - host.reloadFS(files); + host.writeFile(file2.path, file2.content); host.runQueuedTimeoutCallbacks(); checkProjectActualFiles(service.configuredProjects.get(config.path)!, [file1.path, libFile.path, config.path]); @@ -1518,7 +1513,9 @@ namespace ts.projectSystem { // This should schedule 2 timeouts for ensuring project structure and ensuring projects for open file const filesWithFileA = files.map(f => f === fileSubA ? fileA : f); - host.reloadFS(files.map(f => f === fileSubA ? fileA : f)); + host.deleteFile(fileSubA.path); + host.deleteFolder(getDirectoryPath(fileSubA.path)); + host.writeFile(fileA.path, fileA.content); host.checkTimeoutQueueLength(2); closeFilesForSession([fileSubA], session); @@ -1555,7 +1552,8 @@ namespace ts.projectSystem { host.fileExists = originalFileExists; // Actually trigger the file move - host.reloadFS(files); + host.deleteFile(fileA.path); + host.ensureFileOrFolder(fileSubA); host.checkTimeoutQueueLength(2); verifyGetErrRequestNoErrors({ diff --git a/src/testRunner/unittests/tsserver/resolutionCache.ts b/src/testRunner/unittests/tsserver/resolutionCache.ts index d89a739c8d1ca..8a4beb47dc92b 100644 --- a/src/testRunner/unittests/tsserver/resolutionCache.ts +++ b/src/testRunner/unittests/tsserver/resolutionCache.ts @@ -75,7 +75,7 @@ namespace ts.projectSystem { checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, t1.path, tsconfig.path]); // delete t1 - host.reloadFS([f1, tsconfig]); + host.deleteFile(t1.path); // run throttled operation host.runQueuedTimeoutCallbacks(); @@ -83,7 +83,7 @@ namespace ts.projectSystem { checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, tsconfig.path]); // create t2 - host.reloadFS([f1, tsconfig, t2]); + host.writeFile(t2.path, t2.content); // run throttled operation host.runQueuedTimeoutCallbacks(); @@ -114,7 +114,7 @@ namespace ts.projectSystem { { diagnosticMessage: Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations, errorTextArguments: ["./moduleFile"] } ]); - host.reloadFS([file1, moduleFile]); + host.writeFile(moduleFile.path, moduleFile.content); host.runQueuedTimeoutCallbacks(); // Make a change to trigger the program rebuild @@ -135,8 +135,7 @@ namespace ts.projectSystem { path: `${folderPath}/a.ts`, content: 'import f = require("pad"); f;' }; - const files = [file1, libFile]; - const host = createServerHost(files); + const host = createServerHost([file1, libFile]); const session = createSession(host, { canUseEvents: true }); const service = session.getProjectService(); session.executeCommandSeq({ @@ -168,8 +167,7 @@ namespace ts.projectSystem { path: `${folderPath}/node_modules/@types/pad/index.d.ts`, content: "export = pad;declare function pad(length: number, text: string, char ?: string): string;" }; - files.push(padIndex); - host.reloadFS(files, { ignoreWatchInvokedWithTriggerAsFileCreate: true }); + host.ensureFileOrFolder(padIndex, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true); host.runQueuedTimeoutCallbacks(); checkProjectUpdatedInBackgroundEvent(session, [file1.path]); session.clearMessages(); @@ -335,10 +333,8 @@ namespace ts.projectSystem { let diags = session.executeCommand(getErrRequest).response as server.protocol.Diagnostic[]; verifyNoDiagnostics(diags); - const moduleFileOldPath = moduleFile.path; const moduleFileNewPath = "/a/b/moduleFile1.ts"; - moduleFile.path = moduleFileNewPath; - host.reloadFS([moduleFile, file1]); + host.renameFile(moduleFile.path, moduleFileNewPath); host.runQueuedTimeoutCallbacks(); diags = session.executeCommand(getErrRequest).response as server.protocol.Diagnostic[]; verifyDiagnostics(diags, [ @@ -346,8 +342,7 @@ namespace ts.projectSystem { ]); assert.equal(diags.length, 1); - moduleFile.path = moduleFileOldPath; - host.reloadFS([moduleFile, file1]); + host.renameFile(moduleFileNewPath, moduleFile.path); host.runQueuedTimeoutCallbacks(); // Make a change to trigger the program rebuild @@ -386,18 +381,15 @@ namespace ts.projectSystem { let diags = session.executeCommand(getErrRequest).response as server.protocol.Diagnostic[]; verifyNoDiagnostics(diags); - const moduleFileOldPath = moduleFile.path; const moduleFileNewPath = "/a/b/moduleFile1.ts"; - moduleFile.path = moduleFileNewPath; - host.reloadFS([moduleFile, file1, configFile]); + host.renameFile(moduleFile.path, moduleFileNewPath); host.runQueuedTimeoutCallbacks(); diags = session.executeCommand(getErrRequest).response as server.protocol.Diagnostic[]; verifyDiagnostics(diags, [ { diagnosticMessage: Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations, errorTextArguments: ["./moduleFile"] } ]); - moduleFile.path = moduleFileOldPath; - host.reloadFS([moduleFile, file1, configFile]); + host.renameFile(moduleFileNewPath, moduleFile.path); host.runQueuedTimeoutCallbacks(); diags = session.executeCommand(getErrRequest).response as server.protocol.Diagnostic[]; verifyNoDiagnostics(diags); @@ -420,7 +412,7 @@ namespace ts.projectSystem { // should have one external project since config file is missing projectService.checkNumberOfProjects({ externalProjects: 1 }); - host.reloadFS([f1, config]); + host.writeFile(config.path, config.content); projectService.openExternalProject({ rootFiles: toExternalFiles([f1.path, config.path]), options: {}, projectFileName: projectName }); projectService.checkNumberOfProjects({ configuredProjects: 1 }); }); @@ -603,9 +595,8 @@ namespace ts.projectSystem { verifyTrace(resolutionTrace, expectedTrace); verifyWatchesWithConfigFile(host, files, file1); - file1.content += fileContent; - file2.content += fileContent; - host.reloadFS(files); + host.writeFile(file1.path, file1.content + fileContent); + host.writeFile(file2.path, file2.content + fileContent); host.runQueuedTimeoutCallbacks(); verifyTrace(resolutionTrace, [ getExpectedReusingResolutionFromOldProgram(file1, module1Name), @@ -631,9 +622,8 @@ namespace ts.projectSystem { verifyTrace(resolutionTrace, expectedTrace); verifyWatchesWithConfigFile(host, files, file1, expectedNonRelativeDirectories); - file1.content += fileContent; - file2.content += fileContent; - host.reloadFS(files); + host.writeFile(file1.path, file1.content + fileContent); + host.writeFile(file2.path, file2.content + fileContent); host.runQueuedTimeoutCallbacks(); verifyTrace(resolutionTrace, [ getExpectedReusingResolutionFromOldProgram(file1, module1Name), @@ -693,11 +683,10 @@ namespace ts.projectSystem { verifyTrace(resolutionTrace, expectedTrace); verifyWatchesWithConfigFile(host, files, file1); - file1.content += fileContent1; - file2.content += fileContent2; - file3.content += fileContent3; - file4.content += fileContent4; - host.reloadFS(files); + host.writeFile(file1.path, file1.content + fileContent1); + host.writeFile(file2.path, file2.content + fileContent2); + host.writeFile(file3.path, file3.content + fileContent3); + host.writeFile(file4.path, file4.content + fileContent4); host.runQueuedTimeoutCallbacks(); verifyTrace(resolutionTrace, [ @@ -730,11 +719,10 @@ namespace ts.projectSystem { verifyTrace(resolutionTrace, expectedTrace); verifyWatchesWithConfigFile(host, files, file1, expectedNonRelativeDirectories); - file1.content += fileContent; - file2.content += fileContent; - file3.content += fileContent; - file4.content += fileContent; - host.reloadFS(files); + host.writeFile(file1.path, file1.content + fileContent); + host.writeFile(file2.path, file2.content + fileContent); + host.writeFile(file3.path, file3.content + fileContent); + host.writeFile(file4.path, file4.content + fileContent); host.runQueuedTimeoutCallbacks(); verifyTrace(resolutionTrace, [ @@ -782,11 +770,10 @@ namespace ts.projectSystem { ]); checkWatches(); - file1.content += importModuleContent; - file2.content += importModuleContent; - file3.content += importModuleContent; - file4.content += importModuleContent; - host.reloadFS(files); + host.writeFile(file1.path, file1.content + importModuleContent); + host.writeFile(file2.path, file2.content + importModuleContent); + host.writeFile(file3.path, file3.content + importModuleContent); + host.writeFile(file4.path, file4.content + importModuleContent); host.runQueuedTimeoutCallbacks(); verifyTrace(resolutionTrace, [ diff --git a/src/testRunner/unittests/tsserver/symLinks.ts b/src/testRunner/unittests/tsserver/symLinks.ts index 8d22b240419a9..59fb744f0e78e 100644 --- a/src/testRunner/unittests/tsserver/symLinks.ts +++ b/src/testRunner/unittests/tsserver/symLinks.ts @@ -182,8 +182,6 @@ new C();` function verifyModuleResolution(withPathMapping: boolean) { describe(withPathMapping ? "when tsconfig file contains path mapping" : "when tsconfig does not contain path mapping", () => { const filesWithSources = [libFile, recognizersDateTimeSrcFile, withPathMapping ? recognizerDateTimeTsconfigWithPathMapping : recognizerDateTimeTsconfigWithoutPathMapping, recognizerTextSrcFile, recongnizerTextPackageJson]; - const filesWithNodeModulesSetup = [...filesWithSources, nodeModulesRecorgnizersText]; - const filesAfterCompilation = [...filesWithNodeModulesSetup, recongnizerTextDistTypingFile]; const watchedDirectoriesWithResolvedModule = arrayToMap(getTypeRootsFromLocation(recognizersDateTime), k => k, () => 1); watchedDirectoriesWithResolvedModule.set(`${recognizersDateTime}/src`, withPathMapping ? 1 : 2); // wild card + failed lookups @@ -221,18 +219,19 @@ new C();` const session = createSessionAndOpenFile(host); verifyProjectWithUnresolvedModule(session); - host.reloadFS(filesAfterCompilation); + host.ensureFileOrFolder(nodeModulesRecorgnizersText); + host.writeFile(recongnizerTextDistTypingFile.path, recongnizerTextDistTypingFile.content); host.runQueuedTimeoutCallbacks(); verifyProjectWithResolvedModule(session); }); it("when project has node_modules setup but doesnt have modules in typings folder and then recompiles", () => { - const host = createServerHost(filesWithNodeModulesSetup); + const host = createServerHost([...filesWithSources, nodeModulesRecorgnizersText]); const session = createSessionAndOpenFile(host); verifyProjectWithUnresolvedModule(session); - host.reloadFS(filesAfterCompilation); + host.writeFile(recongnizerTextDistTypingFile.path, recongnizerTextDistTypingFile.content); host.runQueuedTimeoutCallbacks(); if (withPathMapping) { @@ -245,7 +244,7 @@ new C();` }); it("when project recompiles after deleting generated folders", () => { - const host = createServerHost(filesAfterCompilation); + const host = createServerHost([...filesWithSources, nodeModulesRecorgnizersText, recongnizerTextDistTypingFile]); const session = createSessionAndOpenFile(host); verifyProjectWithResolvedModule(session); diff --git a/src/testRunner/unittests/tsserver/typingsInstaller.ts b/src/testRunner/unittests/tsserver/typingsInstaller.ts index d93ff99303cd6..2120e86836d27 100644 --- a/src/testRunner/unittests/tsserver/typingsInstaller.ts +++ b/src/testRunner/unittests/tsserver/typingsInstaller.ts @@ -935,7 +935,7 @@ namespace ts.projectSystem { installer.checkPendingCommands(/*expectedCount*/ 0); - host.reloadFS([f, fixedPackageJson]); + host.writeFile(fixedPackageJson.path, fixedPackageJson.content); host.checkTimeoutQueueLengthAndRun(2); // To refresh the project and refresh inferred projects // expected install request installer.installAll(/*expectedCount*/ 1); diff --git a/src/testRunner/unittests/tsserver/watchEnvironment.ts b/src/testRunner/unittests/tsserver/watchEnvironment.ts index 421d02fff8caf..1bda288495033 100644 --- a/src/testRunner/unittests/tsserver/watchEnvironment.ts +++ b/src/testRunner/unittests/tsserver/watchEnvironment.ts @@ -53,11 +53,10 @@ namespace ts.projectSystem { path: `${projectSrcFolder}/file2.ts`, content: "" }; - files.push(file2); fileNames.push(file2.path); expectedWatchedFiles.set(file2.path, 1); expectedCompletions.push("file2"); - host.reloadFS(files); + host.writeFile(file2.path, file2.content); host.runQueuedTimeoutCallbacks(); assert.equal(projectService.configuredProjects.get(configFile.path), project); verifyProjectAndCompletions();