From b78579011404ef9773ad0f3637f58ee766272bc3 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 12 Jun 2024 14:14:52 +0000 Subject: [PATCH 1/2] Simply create a new file when calling `updateFile`. Previously the code used TypeScript's `updateFile`, which performs an incremental parse; however, if we don't expect the contents to be similar enough, this wastes a lot of work. Reuse should still done for untouched files from old versions of the program. --- packages/typescript-vfs/src/index.ts | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/typescript-vfs/src/index.ts b/packages/typescript-vfs/src/index.ts index 8040f29ce242..236504e55ee6 100755 --- a/packages/typescript-vfs/src/index.ts +++ b/packages/typescript-vfs/src/index.ts @@ -31,7 +31,7 @@ export interface VirtualTypeScriptEnvironment { languageService: import("typescript").LanguageService getSourceFile: (fileName: string) => import("typescript").SourceFile | undefined createFile: (fileName: string, content: string) => void - updateFile: (fileName: string, content: string, replaceTextSpan?: import("typescript").TextSpan) => void + updateFile: (fileName: string, content: string) => void } /** @@ -77,25 +77,15 @@ export function createVirtualTypeScriptEnvironment( getSourceFile: fileName => languageService.getProgram()?.getSourceFile(fileName), createFile: (fileName, content) => { - updateFile(ts.createSourceFile(fileName, content, mergedCompilerOpts.target!, false)) + updateFile(ts.createSourceFile(fileName, content, mergedCompilerOpts.target!)) }, - updateFile: (fileName, content, optPrevTextSpan) => { + updateFile: (fileName, content) => { const prevSourceFile = languageService.getProgram()!.getSourceFile(fileName) if (!prevSourceFile) { throw new Error("Did not find a source file for " + fileName) } - const prevFullContents = prevSourceFile.text - - // TODO: Validate if the default text span has a fencepost error? - const prevTextSpan = optPrevTextSpan ?? ts.createTextSpan(0, prevFullContents.length) - const newText = - prevFullContents.slice(0, prevTextSpan.start) + - content + - prevFullContents.slice(prevTextSpan.start + prevTextSpan.length) - const newSourceFile = ts.updateSourceFile(prevSourceFile, newText, { - span: prevTextSpan, - newLength: content.length, - }) + + const newSourceFile = ts.createSourceFile(fileName, content, mergedCompilerOpts.target!) updateFile(newSourceFile) }, From db7b005d96715d6f1fe748d842bca1c547dd7ff2 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 12 Jun 2024 14:22:44 +0000 Subject: [PATCH 2/2] Rewrite imports, apply formatting. --- packages/typescript-vfs/src/index.ts | 40 +++++++++++++++------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/typescript-vfs/src/index.ts b/packages/typescript-vfs/src/index.ts index 236504e55ee6..f57004d9b9e9 100755 --- a/packages/typescript-vfs/src/index.ts +++ b/packages/typescript-vfs/src/index.ts @@ -1,10 +1,12 @@ -type System = import("typescript").System -type CompilerOptions = import("typescript").CompilerOptions -type CustomTransformers = import("typescript").CustomTransformers -type LanguageServiceHost = import("typescript").LanguageServiceHost -type CompilerHost = import("typescript").CompilerHost -type SourceFile = import("typescript").SourceFile -type TS = typeof import("typescript") +import type { + System, + CompilerOptions, + CustomTransformers, + SourceFile, + CompilerHost, + LanguageServiceHost, +} from "typescript" +import type TS from "typescript" type FetchLike = (url: string) => Promise<{ json(): Promise; text(): Promise }> @@ -14,13 +16,13 @@ interface LocalStorageLike { removeItem(key: string): void } -declare var localStorage: LocalStorageLike | undefined; -declare var fetch: FetchLike | undefined; +declare var localStorage: LocalStorageLike | undefined +declare var fetch: FetchLike | undefined let hasLocalStorage = false try { hasLocalStorage = typeof localStorage !== `undefined` -} catch (error) { } +} catch (error) {} const hasProcess = typeof process !== `undefined` const shouldDebug = (hasLocalStorage && localStorage!.getItem("DEBUG")) || (hasProcess && process.env.DEBUG) @@ -48,7 +50,7 @@ export interface VirtualTypeScriptEnvironment { export function createVirtualTypeScriptEnvironment( sys: System, rootFiles: string[], - ts: TS, + ts: typeof TS, compilerOptions: CompilerOptions = {}, customTransformers?: CustomTransformers ): VirtualTypeScriptEnvironment { @@ -103,7 +105,7 @@ export function createVirtualTypeScriptEnvironment( * @param target The compiler settings target baseline * @param ts A copy of the TypeScript module */ -export const knownLibFilesForCompilerOptions = (compilerOptions: CompilerOptions, ts: TS) => { +export const knownLibFilesForCompilerOptions = (compilerOptions: CompilerOptions, ts: typeof TS) => { const target = compilerOptions.target || ts.ScriptTarget.ES5 const lib = compilerOptions.lib || [] @@ -197,7 +199,7 @@ export const knownLibFilesForCompilerOptions = (compilerOptions: CompilerOptions "lib.esnext.promise.d.ts", "lib.esnext.string.d.ts", "lib.esnext.symbol.d.ts", - "lib.esnext.weakref.d.ts" + "lib.esnext.weakref.d.ts", ] const targetToCut = ts.ScriptTarget[target] @@ -316,7 +318,7 @@ export const createDefaultMapFromCDN = ( options: CompilerOptions, version: string, cache: boolean, - ts: TS, + ts: typeof TS, lzstring?: LZString, fetcher?: FetchLike, storer?: LocalStorageLike @@ -342,7 +344,7 @@ export const createDefaultMapFromCDN = ( contents.forEach((text, index) => fsMap.set("/" + files[index], text)) }) // Return a NOOP for .d.ts files which aren't in the current build of TypeScript - .catch(() => { }) + .catch(() => {}) ) } @@ -373,7 +375,7 @@ export const createDefaultMapFromCDN = ( return t }) // Return a NOOP for .d.ts files which aren't in the current build of TypeScript - .catch(() => { }) + .catch(() => {}) ) } else { return Promise.resolve(unzip(content)) @@ -467,7 +469,7 @@ export function createSystem(files: Map): System { export function createFSBackedSystem( files: Map, _projectRoot: string, - ts: TS, + ts: typeof TS, tsLibDirectory?: string ): System { // We need to make an isolated folder for the tsconfig, but also need to be able to resolve the @@ -544,7 +546,7 @@ export function createFSBackedSystem( * which works with TypeScript objects - returns both a compiler host, and a way to add new SourceFile * instances to the in-memory file system. */ -export function createVirtualCompilerHost(sys: System, compilerOptions: CompilerOptions, ts: TS) { +export function createVirtualCompilerHost(sys: System, compilerOptions: CompilerOptions, ts: typeof TS) { const sourceFiles = new Map() const save = (sourceFile: SourceFile) => { sourceFiles.set(sourceFile.fileName, sourceFile) @@ -596,7 +598,7 @@ export function createVirtualLanguageServiceHost( sys: System, rootFiles: string[], compilerOptions: CompilerOptions, - ts: TS, + ts: typeof TS, customTransformers?: CustomTransformers ) { const fileNames = [...rootFiles]