From be634bf70a4eabbc17f06f628fb3f8696eefd390 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 8 Jul 2024 11:53:09 -0700 Subject: [PATCH] Instead of iterating over program files to determine if file needs to be detached, do it though existing mechanism of releasing oldSourceFile --- src/compiler/program.ts | 4 +- src/compiler/resolutionCache.ts | 30 ++++++--------- src/compiler/types.ts | 2 +- src/server/project.ts | 38 ++++++++++--------- src/services/services.ts | 9 ++++- src/services/types.ts | 1 + .../using-referenced-project-built.js | 4 +- .../using-referenced-project.js | 4 +- 8 files changed, 47 insertions(+), 45 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index f111faaa4efdb..763d91c2fe79f 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1860,13 +1860,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // old file wasn't redirect but new file is (oldSourceFile.resolvedPath === oldSourceFile.path && newFile.resolvedPath !== oldSourceFile.path) ) { - host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path)); + host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path), newFile); } } if (!host.getParsedCommandLine) { oldProgram.forEachResolvedProjectReference(resolvedProjectReference => { if (!getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) { - host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false); + host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false, /*newSourceFileByResolvedPath*/ undefined); } }); } diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index ab54952304f67..2522cc3d97fbb 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -141,7 +141,7 @@ export interface ResolutionCache { invalidateResolutionsOfFailedLookupLocations(): boolean; invalidateResolutionOfFile(filePath: Path): void; - removeResolutionsOfFile(filePath: Path, syncDirWatcherRemove?: boolean): void; + removeResolutionsOfFile(filePath: Path): void; removeResolutionsFromProjectReferenceRedirects(filePath: Path): void; setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: Map): void; createHasInvalidatedResolutions( @@ -1273,7 +1273,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD else if (packageDirWatcher.isSymlink !== isSymlink) { // Handle the change packageDirWatcher.dirPathToWatcher.forEach(watcher => { - removeDirectoryWatcher(packageDirWatcher!.isSymlink ? packageDirPath : dirPath, /*syncDirWatcherRemove*/ false); + removeDirectoryWatcher(packageDirWatcher!.isSymlink ? packageDirPath : dirPath); watcher.watcher = createDirPathToWatcher(); }); packageDirWatcher.isSymlink = isSymlink; @@ -1329,7 +1329,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD return dirWatcher; } - function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean, syncDirWatcherRemove: boolean | undefined) { + function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean) { const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); const toWatch = getDirectoryToWatchFailedLookupLocation( failedLookupLocation, @@ -1350,7 +1350,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD const forDirPath = packageDirWatcher.dirPathToWatcher.get(dirPath)!; forDirPath.refCount--; if (forDirPath.refCount === 0) { - removeDirectoryWatcher(packageDirWatcher.isSymlink ? packageDirPath : dirPath, syncDirWatcherRemove); + removeDirectoryWatcher(packageDirWatcher.isSymlink ? packageDirPath : dirPath); packageDirWatcher.dirPathToWatcher.delete(dirPath); if (packageDirWatcher.isSymlink) { const refCount = dirPathToSymlinkPackageRefCount.get(dirPath)! - 1; @@ -1361,11 +1361,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD dirPathToSymlinkPackageRefCount.set(dirPath, refCount); } } - if (syncDirWatcherRemove) closePackageDirWatcher(packageDirWatcher, packageDirPath); } } else { - removeDirectoryWatcher(dirPath, syncDirWatcherRemove); + removeDirectoryWatcher(dirPath); } } return removeAtRoot; @@ -1375,7 +1374,6 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD resolution: T, filePath: Path, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName, - syncDirWatcherRemove?: boolean, ) { Debug.checkDefined(resolution.files).delete(filePath); if (resolution.files!.size) return; @@ -1392,11 +1390,11 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD let removeAtRoot = false; if (failedLookupLocations) { for (const failedLookupLocation of failedLookupLocations) { - removeAtRoot = stopWatchFailedLookupLocation(failedLookupLocation, removeAtRoot, syncDirWatcherRemove); + removeAtRoot = stopWatchFailedLookupLocation(failedLookupLocation, removeAtRoot); } } - if (alternateResult) removeAtRoot = stopWatchFailedLookupLocation(alternateResult, removeAtRoot, syncDirWatcherRemove); - if (removeAtRoot) removeDirectoryWatcher(rootPath, syncDirWatcherRemove); + if (alternateResult) removeAtRoot = stopWatchFailedLookupLocation(alternateResult, removeAtRoot); + if (removeAtRoot) removeDirectoryWatcher(rootPath); } else if (affectingLocations?.length) { resolutionsWithOnlyAffectingLocations.delete(resolution); @@ -1406,16 +1404,14 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD for (const affectingLocation of affectingLocations) { const watcher = fileWatchesOfAffectingLocations.get(affectingLocation)!; watcher.resolutions--; - if (syncDirWatcherRemove) closeFileWatcherOfAffectingLocation(watcher, affectingLocation); } } } - function removeDirectoryWatcher(dirPath: Path, syncDirWatcherRemove: boolean | undefined) { + function removeDirectoryWatcher(dirPath: Path) { const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath)!; // Do not close the watcher yet since it might be needed by other failed lookup locations. dirWatcher.refCount--; - if (syncDirWatcherRemove) closeDirectoryWatchesOfFailedLookup(dirWatcher, dirPath); } function createDirectoryWatcher(directory: string, dirPath: Path, nonRecursive: boolean | undefined) { @@ -1434,7 +1430,6 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD cache: Map>, filePath: Path, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName, - syncDirWatcherRemove: boolean | undefined, ) { // Deleted file, stop watching failed lookups for all the resolutions in the file const resolutions = cache.get(filePath); @@ -1444,7 +1439,6 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD resolution, filePath, getResolutionWithResolvedFileName, - syncDirWatcherRemove, ) ); cache.delete(filePath); @@ -1465,9 +1459,9 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD resolvedProjectReference.commandLine.fileNames.forEach(f => removeResolutionsOfFile(resolutionHost.toPath(f))); } - function removeResolutionsOfFile(filePath: Path, syncDirWatcherRemove?: boolean) { - removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModuleFromResolution, syncDirWatcherRemove); - removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirectiveFromResolution, syncDirWatcherRemove); + function removeResolutionsOfFile(filePath: Path) { + removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModuleFromResolution); + removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirectiveFromResolution); } function invalidateResolutions(resolutions: Set | Map | undefined, canInvalidate: (resolution: ResolutionWithFailedLookupLocations) => boolean | undefined) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 508042f69bee8..f4fb90cd11cbe 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7963,7 +7963,7 @@ export interface CompilerHost extends ModuleResolutionHost { */ hasInvalidatedLibResolutions?(libFileName: string): boolean; getEnvironmentVariable?(name: string): string | undefined; - /** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void; + /** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean, newSourceFileByResolvedPath: SourceFile | undefined): void; /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; /** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */ hasInvalidatedResolutions?(filePath: Path): boolean; diff --git a/src/server/project.ts b/src/server/project.ts index 1dc5b9b93be09..d6fb86425ded2 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1393,6 +1393,24 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.hasAddedOrRemovedSymlinks = true; } + /** @internal */ + onReleaseOldSourceFile( + oldSourceFile: SourceFile, + _oldOptions: CompilerOptions, + hasSourceFileByPath: boolean, + newSourceFileByResolvedPath: SourceFile | undefined, + ) { + if ( + !newSourceFileByResolvedPath || + (oldSourceFile.resolvedPath === oldSourceFile.path && newSourceFileByResolvedPath.resolvedPath !== oldSourceFile.path) + ) { + // new program does not contain this file - detach it from the project + // - remove resolutions only if the new program doesnt contain source file by the path + // (not resolvedPath since path is used for resolution) + this.detachScriptInfoFromProject(oldSourceFile.fileName, hasSourceFileByPath); + } + } + /** @internal */ updateFromProjectInProgress = false; @@ -1639,22 +1657,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo let hasNewProgram = false; if (this.program && (!oldProgram || (this.program !== oldProgram && this.program.structureIsReused !== StructureIsReused.Completely))) { hasNewProgram = true; - if (oldProgram) { - for (const f of oldProgram.getSourceFiles()) { - const newFile = this.program.getSourceFileByPath(f.resolvedPath); - if (!newFile || (f.resolvedPath === f.path && newFile.resolvedPath !== f.path)) { - // new program does not contain this file - detach it from the project - // - remove resolutions only if the new program doesnt contain source file by the path (not resolvedPath since path is used for resolution) - this.detachScriptInfoFromProject(f.fileName, !!this.program.getSourceFileByPath(f.path), /*syncDirWatcherRemove*/ true); - } - } - - oldProgram.forEachResolvedProjectReference(resolvedProjectReference => { - if (!this.program!.getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) { - this.detachScriptInfoFromProject(resolvedProjectReference.sourceFile.fileName, /*noRemoveResolution*/ undefined, /*syncDirWatcherRemove*/ true); - } - }); - } // Update roots this.rootFilesMap.forEach((value, path) => { @@ -1791,12 +1793,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.projectService.sendPerformanceEvent(kind, durationMs); } - private detachScriptInfoFromProject(uncheckedFileName: string, noRemoveResolution?: boolean, syncDirWatcherRemove?: boolean) { + private detachScriptInfoFromProject(uncheckedFileName: string, noRemoveResolution?: boolean) { const scriptInfoToDetach = this.projectService.getScriptInfo(uncheckedFileName); if (scriptInfoToDetach) { scriptInfoToDetach.detachFromProject(this); if (!noRemoveResolution) { - this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path, syncDirWatcherRemove); + this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path); } } } diff --git a/src/services/services.ts b/src/services/services.ts index 0afdecd646e0f..101fcebc91a99 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1866,17 +1866,22 @@ export function createLanguageService( host.onReleaseParsedCommandLine?.(configFileName, oldResolvedRef, oldOptions); } else if (oldResolvedRef) { - onReleaseOldSourceFile(oldResolvedRef.sourceFile, oldOptions); + releaseOldSourceFile(oldResolvedRef.sourceFile, oldOptions); } } // Release any files we have acquired in the old program but are // not part of the new program. - function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) { + function releaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) { const oldSettingsKey = documentRegistry.getKeyForCompilationSettings(oldOptions); documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath, oldSettingsKey, oldSourceFile.scriptKind, oldSourceFile.impliedNodeFormat); } + function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean, newSourceFileByResolvedPath: SourceFile | undefined) { + releaseOldSourceFile(oldSourceFile, oldOptions); + host.onReleaseOldSourceFile?.(oldSourceFile, oldOptions, hasSourceFileByPath, newSourceFileByResolvedPath); + } + function getOrCreateSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined { return getOrCreateSourceFileByPath(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), languageVersionOrOptions, onError, shouldCreateNewSourceFile); } diff --git a/src/services/types.ts b/src/services/types.ts index cce53de46e9fc..082a62d2a5d92 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -430,6 +430,7 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR /** @internal */ sendPerformanceEvent?(kind: PerformanceEvent["kind"], durationMs: number): void; getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; + /** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean, newSourceFileByResolvedPath: SourceFile | undefined): void; /** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache; /** @internal */ runWithTemporaryFileUpdate?(rootFile: string, updatedText: string, cb: (updatedProgram: Program, originalProgram: Program | undefined, updatedPastedText: SourceFile) => void): void; jsDocParsingMode?: JSDocParsingMode | undefined; diff --git a/tests/baselines/reference/tsserver/moduleResolution/using-referenced-project-built.js b/tests/baselines/reference/tsserver/moduleResolution/using-referenced-project-built.js index 5e413016d5383..60f44eac5be4e 100644 --- a/tests/baselines/reference/tsserver/moduleResolution/using-referenced-project-built.js +++ b/tests/baselines/reference/tsserver/moduleResolution/using-referenced-project-built.js @@ -879,13 +879,13 @@ Info seq [hh:mm:ss:mss] ======== Module name 'package-aX' was not resolved. === Info seq [hh:mm:ss:mss] Reusing resolution of module '@typescript/lib-es2021' from '/home/src/projects/project/packages/package-b/__lib_node_modules_lookup_lib.es2021.d.ts__.ts' of old program, it was not resolved. Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /home/src/projects/project/packages/package-b/package-aX 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /home/src/projects/project/packages/package-b/package-aX 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-b/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-b/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/node_modules/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/node_modules/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a/package.json 2000 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: File location affecting resolution -Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations -Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /home/src/projects/project/packages/package-b/tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: true structureIsReused:: SafeModules Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/home/src/projects/project/packages/package-b/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (2) diff --git a/tests/baselines/reference/tsserver/moduleResolution/using-referenced-project.js b/tests/baselines/reference/tsserver/moduleResolution/using-referenced-project.js index 25edb0a64133f..37d09fe7d1f04 100644 --- a/tests/baselines/reference/tsserver/moduleResolution/using-referenced-project.js +++ b/tests/baselines/reference/tsserver/moduleResolution/using-referenced-project.js @@ -696,13 +696,13 @@ Info seq [hh:mm:ss:mss] ======== Module name 'package-aX' was not resolved. === Info seq [hh:mm:ss:mss] Reusing resolution of module '@typescript/lib-es2021' from '/home/src/projects/project/packages/package-b/__lib_node_modules_lookup_lib.es2021.d.ts__.ts' of old program, it was not resolved. Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /home/src/projects/project/packages/package-b/package-aX 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /home/src/projects/project/packages/package-b/package-aX 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-b/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-b/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/node_modules/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/node_modules/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a/package.json 2000 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: File location affecting resolution -Info seq [hh:mm:ss:mss] DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations -Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Close:: WatchInfo: /home/src/projects/project/packages/package-a 1 undefined Project: /home/src/projects/project/packages/package-b/tsconfig.json WatchType: Failed Lookup Locations Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /home/src/projects/project/packages/package-b/tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: true structureIsReused:: SafeModules Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/home/src/projects/project/packages/package-b/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (2)