From 81585d199c2c9778974bb0e08e6e2c87e9174d92 Mon Sep 17 00:00:00 2001 From: Simon Raming Date: Sun, 25 Jan 2026 18:38:33 +0100 Subject: [PATCH 1/3] check for node_modules and package.json instead of VCS --- src/utils.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 52cbf80..51e8982 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -183,14 +183,10 @@ function getPluginsVersions(names: string[]): (string | null)[] { function getProjectPath(rootPath: string): string { function isProjectPath(folderPath: string): boolean { - const gitPath = path.join(folderPath, ".git"); - if (fs.existsSync(gitPath)) return true; - const hgPath = path.join(folderPath, ".hg"); - if (fs.existsSync(hgPath)) return true; - const svnPath = path.join(folderPath, ".svn"); - if (fs.existsSync(svnPath)) return true; - const slPath = path.join(folderPath, ".sl"); - if (fs.existsSync(slPath)) return true; + const nodePath = path.join(folderPath, "node_modules"); + if (fs.existsSync(nodePath)) return true; + const pkgPath = path.join(folderPath, "package.json"); + if (fs.existsSync(pkgPath)) return true; return false; } From 9e0c0444058740cf1f4c0f5ed5151a33a07b1885 Mon Sep 17 00:00:00 2001 From: Simon Raming Date: Mon, 26 Jan 2026 21:28:20 +0100 Subject: [PATCH 2/3] re-add VCS for non-js repo --- src/utils.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utils.ts b/src/utils.ts index 51e8982..5a51768 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -183,6 +183,14 @@ function getPluginsVersions(names: string[]): (string | null)[] { function getProjectPath(rootPath: string): string { function isProjectPath(folderPath: string): boolean { + const gitPath = path.join(folderPath, ".git"); + if (fs.existsSync(gitPath)) return true; + const hgPath = path.join(folderPath, ".hg"); + if (fs.existsSync(hgPath)) return true; + const svnPath = path.join(folderPath, ".svn"); + if (fs.existsSync(svnPath)) return true; + const slPath = path.join(folderPath, ".sl"); + if (fs.existsSync(slPath)) return true; const nodePath = path.join(folderPath, "node_modules"); if (fs.existsSync(nodePath)) return true; const pkgPath = path.join(folderPath, "package.json"); From e42d589a86fb2b351ae2cc0667ec34a8f5c6febb Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Wed, 3 Jun 2026 11:18:54 +0100 Subject: [PATCH 3/3] fix: rework to separate concerns of cache root and project root If we change the project root to be the first `package.json` / `node_modules` we see, we break monorepo traversal for things other than the cache. Really, we just need the cache dir to end up in the first `node_modules` we see, without affecting all other traversal. For this reason, this separates the two into a `cacheRootPath` and a `rootPath`. The former is only used for the cache, and the latter is used for everything else. --- src/cache.ts | 6 ++++-- src/config_prettier.ts | 2 +- src/index.ts | 13 +++++++++++-- src/utils.ts | 35 +++++++++++++++++------------------ 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/cache.ts b/src/cache.ts index b0b2251..e620843 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -1,4 +1,5 @@ import fs from "node:fs"; +import os from "node:os"; import path from "node:path"; import { fastRelativePath, getCachePath, isArray, isBoolean, isObject, isString, isUndefined, sha1hex, sha1base64 } from "./utils.js"; import type Logger from "./logger.js"; @@ -31,11 +32,12 @@ class Cache { private logger: Logger; private dirty: boolean; - constructor(version: string, rootPath: string, options: Options, logger: Logger) { + constructor(version: string, rootPath: string, cacheRootPath: string | undefined, options: Options, logger: Logger) { this.version = sha1hex(version); this.logger = logger; this.rootPath = rootPath; - this.storePath = options.cacheLocation || path.join(getCachePath(rootPath), `${sha1hex(rootPath)}.json`); + const cachePath = cacheRootPath ? getCachePath(cacheRootPath) : path.join(os.tmpdir(), "prettier", ".prettier-caches"); + this.storePath = options.cacheLocation || path.join(cachePath, `${sha1hex(rootPath)}.json`); this.store = this.read(); this.dirty = false; } diff --git a/src/config_prettier.ts b/src/config_prettier.ts index 9c73ef1..8ee18c7 100644 --- a/src/config_prettier.ts +++ b/src/config_prettier.ts @@ -46,7 +46,7 @@ const Loaders = { }, toml: async (filePath: string): Promise => { const fileContent = fs.readFileSync(filePath, "utf8"); - const {parse} = await import("smol-toml"); + const { parse } = await import("smol-toml"); return parse(fileContent); }, yaml: async (filePath: string): Promise => { diff --git a/src/index.ts b/src/index.ts index 5f8a0c1..d9b9158 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,16 @@ import { PRETTIER_VERSION, CLI_VERSION } from "./constants.js"; import Known from "./known.js"; import Logger from "./logger.js"; import { makePrettier } from "./prettier.js"; -import { castArray, getExpandedFoldersPaths, getFoldersChildrenPaths, getPluginsVersions, getProjectPath, getStdin, getTargetsPaths } from "./utils.js"; +import { + castArray, + getCacheRootPath, + getExpandedFoldersPaths, + getFoldersChildrenPaths, + getPluginsVersions, + getProjectPath, + getStdin, + getTargetsPaths, +} from "./utils.js"; import { fastRelativePath, isNull, @@ -116,7 +125,7 @@ async function runGlobs(options: Options, pluginsDefaultOptions: PluginsOptions, const cacheVersion = stringify({ prettierVersion, cliVersion, pluginsNames, pluginsVersions, editorConfigs, ignoreContents, prettierConfigs, ignoreManualFilesPaths, ignoreManualFilesContents, prettierManualFilesPaths, prettierManualFilesContents, cliContextConfig, cliFormatConfig, pluginsDefaultOptions, pluginsCustomOptions }); // prettier-ignore const shouldCache = options.cache && !options.dump && !pluginsVersionsMissing.length && isUndefined(cliContextConfig.cursorOffset); - const cache = shouldCache ? new Cache(cacheVersion, projectPath, options, stdout) : undefined; + const cache = shouldCache ? new Cache(cacheVersion, projectPath, getCacheRootPath(rootPath), options, stdout) : undefined; const prettier = await makePrettier(options, cache); //TODO: Maybe do work in chunks here, as keeping too many formatted files in memory can be a problem diff --git a/src/utils.ts b/src/utils.ts index 5a51768..df933dc 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -56,6 +56,10 @@ function getCachePath(rootPath: string): string { return cachePath; } +function getCacheRootPath(rootPath: string): string | undefined { + return findDirectoryUpwards(rootPath, (folderPath) => fs.existsSync(path.join(folderPath, "node_modules"))); +} + function getDirectoryPaths(rootPath: string, withNodeModules: boolean) { const ignoreGlob = `**/{.git,.sl,.svn,.hg,.DS_Store,Thumbs.db${withNodeModules ? "" : ",node_modules"}}`; const ignoreRe = zeptomatch.compile(ignoreGlob); @@ -181,6 +185,17 @@ function getPluginsVersions(names: string[]): (string | null)[] { return pluginsVersions; } +function findDirectoryUpwards(rootPath: string, isMatch: (folderPath: string) => boolean): string | undefined { + let currentPath = rootPath; + + while (true) { + if (isMatch(currentPath)) return currentPath; + const currentPathNext = path.dirname(currentPath); + if (currentPath === currentPathNext) return; + currentPath = currentPathNext; + } +} + function getProjectPath(rootPath: string): string { function isProjectPath(folderPath: string): boolean { const gitPath = path.join(folderPath, ".git"); @@ -191,27 +206,10 @@ function getProjectPath(rootPath: string): string { if (fs.existsSync(svnPath)) return true; const slPath = path.join(folderPath, ".sl"); if (fs.existsSync(slPath)) return true; - const nodePath = path.join(folderPath, "node_modules"); - if (fs.existsSync(nodePath)) return true; - const pkgPath = path.join(folderPath, "package.json"); - if (fs.existsSync(pkgPath)) return true; return false; } - let currentPath = rootPath; - - while (true) { - if (isProjectPath(currentPath)) { - return currentPath; - } else { - const currentPathNext = path.dirname(currentPath); - if (currentPath === currentPathNext) { - return rootPath; - } else { - currentPath = currentPathNext; - } - } - } + return findDirectoryUpwards(rootPath, isProjectPath) ?? rootPath; } function getStats(targetPath: string): fs.Stats | undefined { @@ -757,6 +755,7 @@ export { fastRelativeChildPath, findLastIndex, getCachePath, + getCacheRootPath, getFolderChildrenPaths, getFoldersChildrenPaths, getExpandedFoldersPaths,