import { readdirSync, statSync } from "node:fs" import { dirname, join, parse, resolve } from "node:path" import type { ResolveFriendlyOptions } from "./resolve.ts" import { resolveStartDirectory } from "./resolve.ts" export interface FindClosestFilePathOptions extends ResolveFriendlyOptions { targetBase: string } /** * @description 从指定地址开始,逐级向上查找,直到找到指定的文件为止,并返回该文件的路径。 * 若未找到指定的文件,则返回 undefined。 */ export const findClosestFilePath = (options: FindClosestFilePathOptions): string | undefined => { const { targetBase } = options let currentDir = resolveStartDirectory(options) const { root } = parse(currentDir) while (true) { const filePath = resolve(join(currentDir, targetBase)) try { const stat = statSync(filePath) if (stat.isFile()) { return filePath } } catch { // } if (currentDir === root) { break } currentDir = dirname(currentDir) } return undefined } export interface FindPathOptions extends ResolveFriendlyOptions { targetPath: string[] } /** * @description 从指定地址开始,逐个判断目标路径是否存在,直到找到一个存在的路径为止,并返回该路径。 * - 若目标路径是相对路径,则相对于当前地址进行解析。 * - 若目标路径是绝对路径,则直接进行判断。 * 若未找到存在的路径,则返回 undefined。 */ export const findPath = (options: FindPathOptions): string | undefined => { const { targetPath } = options const currentDir = resolveStartDirectory(options) for (const currentPath of targetPath) { const filePath = resolve(currentDir, currentPath) try { statSync(filePath) return filePath } catch { // } } return undefined } export interface FindFilesOptions extends ResolveFriendlyOptions { basePattern: RegExp } /** * @description 在指定目录下查找所有符合指定模式的文件,并返回其路径列表。 * - 仅查找指定目录本身,不递归查找子目录。 */ export const findFiles = (options: FindFilesOptions): string[] => { const { startPath, basePattern } = options const startDirectory = resolveStartDirectory({ startPath }) const filePathList: string[] = [] for (const entry of readdirSync(startDirectory, { withFileTypes: true })) { if (entry.isFile()) { const currentPath = resolve(join(startDirectory, entry.name)) basePattern.lastIndex = 0 if (basePattern.test(entry.name)) { filePathList.push(currentPath) } } } return filePathList }