diff --git a/.changeset/tame-garlics-shop.md b/.changeset/tame-garlics-shop.md new file mode 100644 index 000000000000..7a644eb15f37 --- /dev/null +++ b/.changeset/tame-garlics-shop.md @@ -0,0 +1,5 @@ +--- +"@typescript/vfs": minor +--- + +Adds `deleteFile` to the vfs api to which allows file to be removed from the file system. \ No newline at end of file diff --git a/packages/typescript-vfs/src/index.ts b/packages/typescript-vfs/src/index.ts index 84d388967510..de4bbcf1cbe0 100755 --- a/packages/typescript-vfs/src/index.ts +++ b/packages/typescript-vfs/src/index.ts @@ -32,6 +32,7 @@ export interface VirtualTypeScriptEnvironment { getSourceFile: (fileName: string) => import("typescript").SourceFile | undefined createFile: (fileName: string, content: string) => void updateFile: (fileName: string, content: string, replaceTextSpan?: import("typescript").TextSpan) => void + deleteFile: (fileName: string) => void } /** @@ -54,7 +55,7 @@ export function createVirtualTypeScriptEnvironment( ): VirtualTypeScriptEnvironment { const mergedCompilerOpts = { ...defaultCompilerOptions(ts), ...compilerOptions } - const { languageServiceHost, updateFile } = createVirtualLanguageServiceHost( + const { languageServiceHost, updateFile, deleteFile } = createVirtualLanguageServiceHost( sys, rootFiles, mergedCompilerOpts, @@ -99,6 +100,12 @@ export function createVirtualTypeScriptEnvironment( updateFile(newSourceFile) }, + deleteFile(fileName) { + const sourceFile = languageService.getProgram()!.getSourceFile(fileName) + if (sourceFile) { + deleteFile(sourceFile) + } + } } } @@ -466,6 +473,9 @@ export function createSystem(files: Map): System { writeFile: (fileName, contents) => { files.set(fileName, contents) }, + deleteFile: (fileName) => { + files.delete(fileName) + }, } } @@ -545,6 +555,9 @@ export function createFSBackedSystem( writeFile: (fileName, contents) => { files.set(fileName, contents) }, + deleteFile: (fileName) => { + files.delete(fileName) + }, realpath: nodeSys.realpath, } } @@ -564,6 +577,7 @@ export function createVirtualCompilerHost(sys: System, compilerOptions: Compiler type Return = { compilerHost: CompilerHost updateFile: (sourceFile: SourceFile) => boolean + deleteFile: (sourceFile: SourceFile) => boolean } const vHost: Return = { @@ -594,6 +608,12 @@ export function createVirtualCompilerHost(sys: System, compilerOptions: Compiler sourceFiles.set(sourceFile.fileName, sourceFile) return alreadyExists }, + deleteFile: sourceFile => { + const alreadyExists = sourceFiles.has(sourceFile.fileName) + sourceFiles.delete(sourceFile.fileName) + sys.deleteFile!(sourceFile.fileName) + return alreadyExists + } } return vHost } @@ -609,7 +629,7 @@ export function createVirtualLanguageServiceHost( customTransformers?: CustomTransformers ) { const fileNames = [...rootFiles] - const { compilerHost, updateFile } = createVirtualCompilerHost(sys, compilerOptions, ts) + const { compilerHost, updateFile, deleteFile } = createVirtualCompilerHost(sys, compilerOptions, ts) const fileVersions = new Map() let projectVersion = 0 const languageServiceHost: LanguageServiceHost = { @@ -642,6 +662,7 @@ export function createVirtualLanguageServiceHost( type Return = { languageServiceHost: LanguageServiceHost updateFile: (sourceFile: import("typescript").SourceFile) => void + deleteFile: (sourceFile: import("typescript").SourceFile) => void } const lsHost: Return = { @@ -654,6 +675,15 @@ export function createVirtualLanguageServiceHost( } updateFile(sourceFile) }, + deleteFile: sourceFile => { + projectVersion++ + fileVersions.set(sourceFile.fileName, projectVersion.toString()) + const index = fileNames.indexOf(sourceFile.fileName) + if (index !== -1) { + fileNames.splice(index, 1) + } + deleteFile(sourceFile) + } } return lsHost } diff --git a/packages/typescript-vfs/test/fsbacked.test.ts b/packages/typescript-vfs/test/fsbacked.test.ts index e0938a6678f4..48175f6d295c 100644 --- a/packages/typescript-vfs/test/fsbacked.test.ts +++ b/packages/typescript-vfs/test/fsbacked.test.ts @@ -72,3 +72,27 @@ it("searches node_modules/@types", () => { const semDiags = env.languageService.getSemanticDiagnostics("index.ts") expect(semDiags.length).toBe(0) }) + +it("can delete files in the virtual fs", () => { + const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } + const fsMap = new Map() + + const monorepoRoot = path.join(__dirname, "..", "..", "..") + const fakeFolder = path.join(monorepoRoot, "fake") + const exporter = path.join(fakeFolder, "file-with-export.ts") + const index = path.join(fakeFolder, "index.ts") + + // TODO: the VFS should really be normalizing paths when looking into fsMap instead. + fsMap.set(exporter.replace(/\\/g, "/"), `export const helloWorld = "Example string";`) + fsMap.set(index.replace(/\\/g, "/"), `import {helloWorld} from "./file-with-export"; console.log(helloWorld)`) + + const system = createFSBackedSystem(fsMap, monorepoRoot, ts) + const env = createVirtualTypeScriptEnvironment(system, [index, exporter], ts, compilerOpts) + + expect(env.getSourceFile(index)).toBeTruthy() + + env.deleteFile(index); + + expect(env.getSourceFile(index)).toBeFalsy() + +})