import { combinePaths, createPackageJsonInfo, Debug, forEachAncestorDirectoryStoppingAtGlobalCache, getDirectoryPath, Path, ProjectPackageJsonInfo, Ternary, tryFileExists, } from "./_namespaces/ts.js"; import { Project, ProjectService, } from "./_namespaces/ts.server.js"; /** @internal */ export interface PackageJsonCache { addOrUpdate(fileName: string, path: Path): void; invalidate(path: Path): void; delete(fileName: Path): void; getInDirectory(directory: string): ProjectPackageJsonInfo | undefined; directoryHasPackageJson(directory: string): Ternary; searchDirectoryAndAncestors(directory: string, project: Project): void; } /** @internal */ export function createPackageJsonCache(host: ProjectService): PackageJsonCache { const packageJsons = new Map(); const directoriesWithoutPackageJson = new Map(); return { addOrUpdate, invalidate, delete: fileName => { packageJsons.delete(fileName); directoriesWithoutPackageJson.set(getDirectoryPath(fileName), true); }, getInDirectory: directory => { return packageJsons.get(host.toPath(combinePaths(directory, "package.json"))) || undefined; }, directoryHasPackageJson: directory => directoryHasPackageJson(host.toPath(directory)), searchDirectoryAndAncestors: (directory, project) => { forEachAncestorDirectoryStoppingAtGlobalCache( project, directory, ancestor => { const ancestorPath = host.toPath(ancestor); if (directoryHasPackageJson(ancestorPath) !== Ternary.Maybe) { return true; } const packageJsonFileName = combinePaths(ancestor, "package.json"); if (tryFileExists(host, packageJsonFileName)) { addOrUpdate(packageJsonFileName, combinePaths(ancestorPath, "package.json") as Path); } else { directoriesWithoutPackageJson.set(ancestorPath, true); } }, ); }, }; function addOrUpdate(fileName: string, path: Path) { const packageJsonInfo = Debug.checkDefined(createPackageJsonInfo(fileName, host.host)); packageJsons.set(path, packageJsonInfo); directoriesWithoutPackageJson.delete(getDirectoryPath(path)); } function invalidate(path: Path) { packageJsons.delete(path); directoriesWithoutPackageJson.delete(getDirectoryPath(path)); } function directoryHasPackageJson(directory: Path) { return packageJsons.has(combinePaths(directory, "package.json") as Path) ? Ternary.True : directoriesWithoutPackageJson.has(directory) ? Ternary.False : Ternary.Maybe; } }