Use search-closest to search Prettier config and Project root (#17412)

This commit is contained in:
fisker Cheung authored and GitHub committed 2025-04-29 02:39:18 +08:00
1 parent 3640a4e70f
commit eaeb1e7c04
9 files changed
+61 -150

No files matched your search

+4
View File
@@ -53,6 +53,10 @@
groupName: "Regex related dependencies",
matchPackageNames: ["regexp-util", "unicode-regex", "cjk-regex"],
},
{
groupName: "Config search related dependencies",
matchPackageNames: ["url-or-path", "search-closest"],
},
{
branchPrefix: "renovate/website/",
matchFileNames: ["website/package.json"],
+2 -2
View File
@@ -69,7 +69,6 @@
"ignore": "7.0.3",
"import-meta-resolve": "4.1.0",
"is-es5-identifier-name": "1.0.0",
"iterate-directory-up": "1.1.1",
"jest-docblock": "30.0.0-alpha.7",
"js-yaml": "4.1.0",
"json5": "2.2.3",
@@ -94,6 +93,7 @@
"remark-math": "3.0.1",
"remark-parse": "8.0.3",
"sdbm": "2.0.0",
"search-closest": "0.1.1",
"smol-toml": "1.3.4",
"strip-ansi": "7.1.0",
"to-fast-properties": "4.0.0",
@@ -101,7 +101,7 @@
"typescript": "5.8.3",
"unicode-regex": "4.1.2",
"unified": "9.2.2",
"url-or-path": "2.3.2",
"url-or-path": "2.6.1",
"vnopts": "2.0.2",
"wcwidth.js": "2.0.0",
"yaml-unist-parser": "2.0.5"
+9 -11
View File
@@ -2,16 +2,12 @@
// https://github.com/kirstein/find-project-root/blob/master/index.js
import * as path from "node:path";
import isDirectory from "../utils/is-directory.js";
import Searcher from "./searcher.js";
import { DirectorySearcher } from "search-closest";
const MARKERS = [".git", ".hg"];
const DIRECTORIES = [".git", ".hg"];
/** @type {DirectorySearcher} */
let searcher;
const searchOptions = {
names: MARKERS,
filter: ({ path: directory }) =>
isDirectory(directory, { allowSymlinks: false }),
};
/**
* Find the directory contains a version control system directory
@@ -20,10 +16,12 @@ const searchOptions = {
* @returns {Promise<string | undefined>}
*/
async function findProjectRoot(startDirectory, options) {
searcher ??= new Searcher(searchOptions);
const mark = await searcher.search(startDirectory, options);
searcher ??= new DirectorySearcher(DIRECTORIES, { allowSymlinks: false });
const directory = await searcher.search(startDirectory, {
cache: options.shouldCache,
});
return mark ? path.dirname(mark) : undefined;
return directory ? path.dirname(directory) : undefined;
}
function clearFindProjectRootCache() {
@@ -1,10 +1,13 @@
import isFile from "../../utils/is-file.js";
import Searcher from "../searcher.js";
import { FileSearcher } from "search-closest";
import {
loadConfigFromPackageJson,
loadConfigFromPackageYaml,
} from "./loaders.js";
/**
@import {SearcherOptions} from 'search-closest'
*/
const CONFIG_FILE_NAMES = [
"package.json",
"package.yaml",
@@ -28,11 +31,8 @@ const CONFIG_FILE_NAMES = [
".prettierrc.toml",
];
/** @type {SearcherOptions["filter"]} */
async function filter({ name, path: file }) {
if (!(await isFile(file))) {
return false;
}
if (name === "package.json") {
try {
return Boolean(await loadConfigFromPackageJson(file));
@@ -53,7 +53,7 @@ async function filter({ name, path: file }) {
}
function getSearcher(stopDirectory) {
return new Searcher({ names: CONFIG_FILE_NAMES, filter, stopDirectory });
return new FileSearcher(CONFIG_FILE_NAMES, { filter, stopDirectory });
}
export default getSearcher;
+9 -4
View File
@@ -3,6 +3,10 @@ import mockable from "../../common/mockable.js";
import getConfigSearcher from "./config-searcher.js";
import loadConfig from "./load-config.js";
/**
@import {FileSearcher} from 'search-closest'
*/
const loadCache = new Map();
const searchCache = new Map();
function clearPrettierConfigCache() {
@@ -27,8 +31,9 @@ function loadPrettierConfig(configFile, { shouldCache }) {
}
/**
* @param {string} stopDirectory
*/
@param {string} stopDirectory
@returns {FileSearcher["search"]}
*/
function getSearchFunction(stopDirectory) {
stopDirectory = stopDirectory ? path.resolve(stopDirectory) : undefined;
@@ -44,7 +49,7 @@ function getSearchFunction(stopDirectory) {
/**
* @param {string} startDirectory
* @param {{shouldCache?: boolean}} options
* @returns {Promise<string>}
* @returns {Promise<string | void>}
*/
function searchPrettierConfig(startDirectory, options = {}) {
startDirectory = startDirectory
@@ -55,7 +60,7 @@ function searchPrettierConfig(startDirectory, options = {}) {
const search = getSearchFunction(stopDirectory);
return search(startDirectory, { shouldCache: options.shouldCache });
return search(startDirectory, { cache: options.shouldCache });
}
export { clearPrettierConfigCache, loadPrettierConfig, searchPrettierConfig };
-71
View File
@@ -1,71 +0,0 @@
import path from "node:path";
import iterateDirectoryUp from "iterate-directory-up";
class Searcher {
#names;
#filter;
#stopDirectory;
#cache = new Map();
/**
* @param {{
* names: string[],
* filter: (fileOrDirectory: {name: string, path: string}) => Promise<boolean>,
* stopDirectory?: string,
* }} param0
*/
constructor({ names, filter, stopDirectory }) {
this.#names = names;
this.#filter = filter;
this.#stopDirectory = stopDirectory;
}
async #searchInDirectory(directory, shouldCache) {
const cache = this.#cache;
if (shouldCache && cache.has(directory)) {
return cache.get(directory);
}
for (const name of this.#names) {
const fileOrDirectory = path.join(directory, name);
if (await this.#filter({ name, path: fileOrDirectory })) {
return fileOrDirectory;
}
}
}
async search(startDirectory, { shouldCache }) {
const cache = this.#cache;
if (shouldCache && cache.has(startDirectory)) {
return cache.get(startDirectory);
}
const searchedDirectories = [];
let result;
for (const directory of iterateDirectoryUp(
startDirectory,
this.#stopDirectory,
)) {
searchedDirectories.push(directory);
result = await this.#searchInDirectory(directory, shouldCache);
if (result) {
break;
}
}
// Always cache the result, so we can use it when `useCache` is set to true
for (const directory of searchedDirectories) {
cache.set(directory, result);
}
return result;
}
clearCache() {
this.#cache.clear();
}
}
export default Searcher;
-22
View File
@@ -1,22 +0,0 @@
import fs from "node:fs/promises";
import { toPath } from "url-or-path";
/**
* @param {string | URL} directory
* @param {{allowSymlinks: boolean}} [options]
* @returns {Promise<boolean>}
*/
async function isDirectory(directory, options) {
const allowSymlinks = options?.allowSymlinks ?? true;
let stats;
try {
stats = await (allowSymlinks ? fs.stat : fs.lstat)(toPath(directory));
} catch {
return false;
}
return stats.isDirectory();
}
export default isDirectory;
-22
View File
@@ -1,22 +0,0 @@
import fs from "node:fs/promises";
import { toPath } from "url-or-path";
/**
* @param {string | URL} file
* @param {{allowSymlinks: boolean}} [options]
* @returns {Promise<boolean>}
*/
async function isFile(file, options) {
const allowSymlinks = options?.allowSymlinks ?? true;
let stats;
try {
stats = await (allowSymlinks ? fs.stat : fs.lstat)(toPath(file));
} catch {
return false;
}
return stats.isFile();
}
export default isFile;
+30 -11
View File
@@ -4365,6 +4365,15 @@ __metadata:
languageName: node
linkType: hard
"find-in-directory@npm:^2.0.1":
version: 2.0.1
resolution: "find-in-directory@npm:2.0.1"
dependencies:
url-or-path: "npm:2.6.1"
checksum: 10/1a02fdec539ff4c4d63d0e296d853bf88a633a882bc82fba8addc24fb08de799eaa2f05c4721e3954a23dddeb8301cc994dd509b58b5cac34d90a95a43e6a5ea
languageName: node
linkType: hard
"find-up-json@npm:^2.0.4, find-up-json@npm:^2.0.5":
version: 2.0.5
resolution: "find-up-json@npm:2.0.5"
@@ -5213,12 +5222,12 @@ __metadata:
languageName: node
linkType: hard
"iterate-directory-up@npm:1.1.1":
version: 1.1.1
resolution: "iterate-directory-up@npm:1.1.1"
"iterate-directory-up@npm:^1.2.1":
version: 1.2.1
resolution: "iterate-directory-up@npm:1.2.1"
dependencies:
url-or-path: "npm:^2.3.0"
checksum: 10/b724f63d1035a453b974d15dd9f809a0862131aa38cfe2960b0f388ee8100e42404f8fb8b52c46c82dc2c263c3ca9b30ba8716216ab9ae78cb9142d85110d706
url-or-path: "npm:^2.6.1"
checksum: 10/35846f8df1d31b6e37eef19cd7c4a7b3c4cbacbbdf80e1b7b1eb2f75ec7a611039da895592328a55885ace3f06def73015402d55409d0aec9e959fd4cb0d6b7e
languageName: node
linkType: hard
@@ -7035,7 +7044,6 @@ __metadata:
import-meta-resolve: "npm:4.1.0"
index-to-position: "npm:1.1.0"
is-es5-identifier-name: "npm:1.0.0"
iterate-directory-up: "npm:1.1.1"
jest: "npm:30.0.0-alpha.7"
jest-docblock: "npm:30.0.0-alpha.7"
jest-light-runner: "npm:0.7.8"
@@ -7073,6 +7081,7 @@ __metadata:
remark-parse: "npm:8.0.3"
rollup-plugin-license: "npm:3.6.0"
sdbm: "npm:2.0.0"
search-closest: "npm:0.1.1"
semver: "npm:7.7.1"
serialize-javascript: "npm:6.0.2"
smol-toml: "npm:1.3.4"
@@ -7086,7 +7095,7 @@ __metadata:
typescript: "npm:5.8.3"
unicode-regex: "npm:4.1.2"
unified: "npm:9.2.2"
url-or-path: "npm:2.3.2"
url-or-path: "npm:2.6.1"
vnopts: "npm:2.0.2"
wcwidth.js: "npm:2.0.0"
yaml-unist-parser: "npm:2.0.5"
@@ -7475,6 +7484,16 @@ __metadata:
languageName: node
linkType: hard
"search-closest@npm:0.1.1":
version: 0.1.1
resolution: "search-closest@npm:0.1.1"
dependencies:
find-in-directory: "npm:^2.0.1"
iterate-directory-up: "npm:^1.2.1"
checksum: 10/5285c2d5e7e5d7ffbb2aa0bf2fd37acd19dff58c3975889125f2a92e9a0c17adea10484c43f1ae67ccf03896f891e7721b54211fea777164ac90b26dde7c93ff
languageName: node
linkType: hard
"semver-compare@npm:^1.0.0":
version: 1.0.0
resolution: "semver-compare@npm:1.0.0"
@@ -8468,10 +8487,10 @@ __metadata:
languageName: node
linkType: hard
"url-or-path@npm:2.3.2, url-or-path@npm:^2.3.0":
version: 2.3.2
resolution: "url-or-path@npm:2.3.2"
checksum: 10/9078f06d5754293464332da3f98eddd9878dc6a2b4ece5303f72e6a5fa72c3d25a3c33f01bd097bf54cccd29e61283fec38432c928894c032630a04867ceaf81
"url-or-path@npm:2.6.1, url-or-path@npm:^2.3.0, url-or-path@npm:^2.6.1":
version: 2.6.1
resolution: "url-or-path@npm:2.6.1"
checksum: 10/707d340bc72dbaccfaa0a371f8e70816518141ecbfdebddc4d6faf8e5e5afa6f33cb01e4e5701c0e76dc661bd699e00041c3b00f1a3e2fb7a0c4e144c9dd6ace
languageName: node
linkType: hard