From cc00bd880b260b30dac111dccee27738fae0bd83 Mon Sep 17 00:00:00 2001 From: Mark Lundin Date: Wed, 3 Jul 2024 11:32:00 +0100 Subject: [PATCH 1/6] Add deleteFile function to VirtualTypeScriptEnvironment --- packages/typescript-vfs/src/index.ts | 32 ++++++++- packages/typescript-vfs/test/fsbacked.test.ts | 72 ++++++++++++------- 2 files changed, 78 insertions(+), 26 deletions(-) diff --git a/packages/typescript-vfs/src/index.ts b/packages/typescript-vfs/src/index.ts index 8040f29ce242..6b5634ba7d9f 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,13 @@ export function createVirtualTypeScriptEnvironment( updateFile(newSourceFile) }, + deleteFile(fileName) { + const sourceFile = languageService.getProgram()!.getSourceFile(fileName) + if (!sourceFile) { + throw new Error("Did not find a source file for " + fileName) + } + deleteFile(sourceFile) + } } } @@ -545,6 +553,9 @@ export function createFSBackedSystem( writeFile: (fileName, contents) => { files.set(fileName, contents) }, + deleteFile: (fileName) => { + files.delete(fileName) + }, realpath: nodeSys.realpath, } } @@ -564,6 +575,7 @@ export function createVirtualCompilerHost(sys: System, compilerOptions: Compiler type Return = { compilerHost: CompilerHost updateFile: (sourceFile: SourceFile) => boolean + deleteFile: (sourceFile: SourceFile) => boolean } const vHost: Return = { @@ -595,6 +607,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 } @@ -610,7 +628,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 = { @@ -643,6 +661,7 @@ export function createVirtualLanguageServiceHost( type Return = { languageServiceHost: LanguageServiceHost updateFile: (sourceFile: import("typescript").SourceFile) => void + deleteFile: (sourceFile: import("typescript").SourceFile) => void } const lsHost: Return = { @@ -655,6 +674,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 bb0f18b2824e..7057306aad65 100644 --- a/packages/typescript-vfs/test/fsbacked.test.ts +++ b/packages/typescript-vfs/test/fsbacked.test.ts @@ -3,38 +3,38 @@ import { createFSBackedSystem, createVirtualTypeScriptEnvironment } from "../src import path from "path" import ts from "typescript" -it("can use a FS backed system ", () => { - const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } - const fsMap = new Map() +// it("can use a FS backed system ", () => { +// const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } +// const fsMap = new Map() - const content = `/// \nimport * as path from 'path';\npath.` - fsMap.set("index.ts", content) +// const content = `/// \nimport * as path from 'path';\npath.` +// fsMap.set("index.ts", content) - const monorepoRoot = path.join(__dirname, "..", "..", "..") - const system = createFSBackedSystem(fsMap, monorepoRoot, ts) - const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts) +// const monorepoRoot = path.join(__dirname, "..", "..", "..") +// const system = createFSBackedSystem(fsMap, monorepoRoot, ts) +// const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts) - const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {}) - const hasPathJoinFunc = completions?.entries.find(c => c.name === "join") - expect(hasPathJoinFunc).toBeTruthy() -}) +// const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {}) +// const hasPathJoinFunc = completions?.entries.find(c => c.name === "join") +// expect(hasPathJoinFunc).toBeTruthy() +// }) -it("can use a FS backed system to extract node modules", () => { - const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } - const fsMap = new Map() +// it("can use a FS backed system to extract node modules", () => { +// const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } +// const fsMap = new Map() - const content = `import React from "react"\nReact.Compone` - fsMap.set("index.ts", content) +// const content = `import React from "react"\nReact.Compone` +// fsMap.set("index.ts", content) - const monorepoRoot = path.join(__dirname, "..", "..", "..") - const system = createFSBackedSystem(fsMap, monorepoRoot, ts) - const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts) +// const monorepoRoot = path.join(__dirname, "..", "..", "..") +// const system = createFSBackedSystem(fsMap, monorepoRoot, ts) +// const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts) - const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {}) +// const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {}) - const hasReactComponentInCompletions = completions?.entries.find(c => c.name === "Component") - expect(hasReactComponentInCompletions).toBeTruthy() -}) +// const hasReactComponentInCompletions = completions?.entries.find(c => c.name === "Component") +// expect(hasReactComponentInCompletions).toBeTruthy() +// }) it("can import files in the virtual fs", () => { const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } @@ -58,3 +58,27 @@ it("can import files in the virtual fs", () => { expect(errs.map(e => e.messageText)).toEqual([]) }) + +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() + +}) From 4eb31784667988fcdab3755adc8f0e61c105ab0c Mon Sep 17 00:00:00 2001 From: Mark Lundin Date: Wed, 3 Jul 2024 11:34:11 +0100 Subject: [PATCH 2/6] Refactor FS backed system tests --- packages/typescript-vfs/test/fsbacked.test.ts | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/typescript-vfs/test/fsbacked.test.ts b/packages/typescript-vfs/test/fsbacked.test.ts index 7057306aad65..3f7e90778b0b 100644 --- a/packages/typescript-vfs/test/fsbacked.test.ts +++ b/packages/typescript-vfs/test/fsbacked.test.ts @@ -3,38 +3,38 @@ import { createFSBackedSystem, createVirtualTypeScriptEnvironment } from "../src import path from "path" import ts from "typescript" -// it("can use a FS backed system ", () => { -// const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } -// const fsMap = new Map() +it("can use a FS backed system ", () => { + const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } + const fsMap = new Map() -// const content = `/// \nimport * as path from 'path';\npath.` -// fsMap.set("index.ts", content) + const content = `/// \nimport * as path from 'path';\npath.` + fsMap.set("index.ts", content) -// const monorepoRoot = path.join(__dirname, "..", "..", "..") -// const system = createFSBackedSystem(fsMap, monorepoRoot, ts) -// const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts) + const monorepoRoot = path.join(__dirname, "..", "..", "..") + const system = createFSBackedSystem(fsMap, monorepoRoot, ts) + const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts) -// const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {}) -// const hasPathJoinFunc = completions?.entries.find(c => c.name === "join") -// expect(hasPathJoinFunc).toBeTruthy() -// }) + const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {}) + const hasPathJoinFunc = completions?.entries.find(c => c.name === "join") + expect(hasPathJoinFunc).toBeTruthy() +}) -// it("can use a FS backed system to extract node modules", () => { -// const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } -// const fsMap = new Map() +it("can use a FS backed system to extract node modules", () => { + const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } + const fsMap = new Map() -// const content = `import React from "react"\nReact.Compone` -// fsMap.set("index.ts", content) + const content = `import React from "react"\nReact.Compone` + fsMap.set("index.ts", content) -// const monorepoRoot = path.join(__dirname, "..", "..", "..") -// const system = createFSBackedSystem(fsMap, monorepoRoot, ts) -// const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts) + const monorepoRoot = path.join(__dirname, "..", "..", "..") + const system = createFSBackedSystem(fsMap, monorepoRoot, ts) + const env = createVirtualTypeScriptEnvironment(system, ["index.ts"], ts, compilerOpts) -// const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {}) + const completions = env.languageService.getCompletionsAtPosition("index.ts", content.length, {}) -// const hasReactComponentInCompletions = completions?.entries.find(c => c.name === "Component") -// expect(hasReactComponentInCompletions).toBeTruthy() -// }) + const hasReactComponentInCompletions = completions?.entries.find(c => c.name === "Component") + expect(hasReactComponentInCompletions).toBeTruthy() +}) it("can import files in the virtual fs", () => { const compilerOpts: ts.CompilerOptions = { target: ts.ScriptTarget.ES2016, esModuleInterop: true } From b21a9de6769c68f38dccd7eb56eaca7d1c11c769 Mon Sep 17 00:00:00 2001 From: Mark Lundin Date: Wed, 3 Jul 2024 14:26:20 +0100 Subject: [PATCH 3/6] Add deleteFile function to createSystem --- packages/typescript-vfs/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/typescript-vfs/src/index.ts b/packages/typescript-vfs/src/index.ts index 6b5634ba7d9f..80dff6b140b8 100755 --- a/packages/typescript-vfs/src/index.ts +++ b/packages/typescript-vfs/src/index.ts @@ -474,6 +474,9 @@ export function createSystem(files: Map): System { writeFile: (fileName, contents) => { files.set(fileName, contents) }, + deleteFile: (fileName) => { + files.delete(fileName) + }, } } From 62b55b5f7669cab4c34f2d29fab3ef2b564608d5 Mon Sep 17 00:00:00 2001 From: Mark Lundin Date: Fri, 5 Jul 2024 15:35:58 +0100 Subject: [PATCH 4/6] changeset --- .changeset/tame-garlics-shop.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changeset/tame-garlics-shop.md diff --git a/.changeset/tame-garlics-shop.md b/.changeset/tame-garlics-shop.md new file mode 100644 index 000000000000..a845151cc840 --- /dev/null +++ b/.changeset/tame-garlics-shop.md @@ -0,0 +1,2 @@ +--- +--- From cd7deb4d7b532485802302de7429414f63c2274d Mon Sep 17 00:00:00 2001 From: Mark Lundin Date: Mon, 8 Jul 2024 12:17:42 +0100 Subject: [PATCH 5/6] added descriptive changeset --- .changeset/tame-garlics-shop.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.changeset/tame-garlics-shop.md b/.changeset/tame-garlics-shop.md index a845151cc840..7a644eb15f37 100644 --- a/.changeset/tame-garlics-shop.md +++ b/.changeset/tame-garlics-shop.md @@ -1,2 +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 From 6cb5f8f14f1b56753a42d7edd5e2fe8da1fbf243 Mon Sep 17 00:00:00 2001 From: Mark Lundin Date: Mon, 8 Jul 2024 19:55:42 +0100 Subject: [PATCH 6/6] Fix deleteFile function in createVirtualTypeScriptEnvironment --- packages/typescript-vfs/src/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/typescript-vfs/src/index.ts b/packages/typescript-vfs/src/index.ts index 80dff6b140b8..e7fcf2f36439 100755 --- a/packages/typescript-vfs/src/index.ts +++ b/packages/typescript-vfs/src/index.ts @@ -102,10 +102,9 @@ export function createVirtualTypeScriptEnvironment( }, deleteFile(fileName) { const sourceFile = languageService.getProgram()!.getSourceFile(fileName) - if (!sourceFile) { - throw new Error("Did not find a source file for " + fileName) + if (sourceFile) { + deleteFile(sourceFile) } - deleteFile(sourceFile) } } }