From 961d9b28258ed77670a756fc477a86d92ff28fb7 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Wed, 23 Jul 2025 19:22:08 +0100 Subject: [PATCH 1/6] chore: replace find-up with empathic Replaces `find-up` with `empathic`, a faster library. We can follow this up with replacements of other similar dependencies duplicating this work, so everything is consolidated around `empathic`. --- package-lock.json | 17 ++++++--- packages/build-info/package.json | 2 +- packages/build-info/src/node/file-system.ts | 24 ++++++++++--- packages/build-info/vite.config.ts | 2 +- packages/config/package.json | 2 +- .../config/src/options/repository_root.js | 4 +-- packages/config/src/path.ts | 2 +- .../edge-bundler/node/npm_dependencies.ts | 6 ++-- packages/edge-bundler/node/package_json.ts | 15 ++++---- packages/edge-bundler/package.json | 2 +- packages/zip-it-and-ship-it/package.json | 2 +- .../runtimes/node/bundlers/zisi/resolve.ts | 9 +++-- .../src/runtimes/node/utils/package_json.ts | 35 +++++++++++-------- .../node/utils/plugin_modules_path.ts | 8 +++-- 14 files changed, 81 insertions(+), 49 deletions(-) diff --git a/package-lock.json b/package-lock.json index 54c02f97f7..fbfed56e38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10304,6 +10304,15 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "license": "MIT" }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", @@ -23977,7 +23986,7 @@ "@bugsnag/js": "^8.0.0", "@iarna/toml": "^2.2.5", "dot-prop": "^9.0.0", - "find-up": "^7.0.0", + "empathic": "^2.0.0", "minimatch": "^9.0.0", "read-pkg": "^9.0.0", "semver": "^7.3.8", @@ -24283,11 +24292,11 @@ "cron-parser": "^4.1.0", "deepmerge": "^4.2.2", "dot-prop": "^9.0.0", + "empathic": "^2.0.0", "execa": "^8.0.0", "fast-safe-stringify": "^2.0.7", "figures": "^6.0.0", "filter-obj": "^6.0.0", - "find-up": "^7.0.0", "indent-string": "^5.0.0", "is-plain-obj": "^4.0.0", "map-obj": "^5.0.0", @@ -24336,10 +24345,10 @@ "ajv-errors": "^3.0.0", "better-ajv-errors": "^1.2.0", "common-path-prefix": "^3.0.0", + "empathic": "^2.0.0", "env-paths": "^3.0.0", "esbuild": "0.25.6", "execa": "^8.0.0", - "find-up": "^7.0.0", "get-package-name": "^2.2.0", "get-port": "^7.0.0", "is-path-inside": "^4.0.0", @@ -25571,12 +25580,12 @@ "archiver": "^7.0.0", "common-path-prefix": "^3.0.0", "copy-file": "^11.0.0", + "empathic": "^2.0.0", "es-module-lexer": "^1.0.0", "esbuild": "0.25.6", "execa": "^8.0.0", "fast-glob": "^3.3.3", "filter-obj": "^6.0.0", - "find-up": "^7.0.0", "is-builtin-module": "^3.1.0", "is-path-inside": "^4.0.0", "junk": "^4.0.0", diff --git a/packages/build-info/package.json b/packages/build-info/package.json index 4dcbcb7036..0420150a9a 100644 --- a/packages/build-info/package.json +++ b/packages/build-info/package.json @@ -47,7 +47,7 @@ "@bugsnag/js": "^8.0.0", "@iarna/toml": "^2.2.5", "dot-prop": "^9.0.0", - "find-up": "^7.0.0", + "empathic": "^2.0.0", "minimatch": "^9.0.0", "read-pkg": "^9.0.0", "semver": "^7.3.8", diff --git a/packages/build-info/src/node/file-system.ts b/packages/build-info/src/node/file-system.ts index 75919cfa71..513a2425e0 100644 --- a/packages/build-info/src/node/file-system.ts +++ b/packages/build-info/src/node/file-system.ts @@ -1,7 +1,8 @@ -import { promises as fs } from 'fs' +import { promises as fs, existsSync } from 'fs' import { basename, dirname, isAbsolute, join, relative, resolve } from 'path' -import { findUp, findUpMultiple } from 'find-up' +import { any as findUpAny, up as findUp } from 'empathic/find' +import { up as walkUp } from 'empathic/walk' import { DirType, Environment, FileSystem, findUpOptions } from '../file-system.js' @@ -68,12 +69,25 @@ export class NodeFS extends FileSystem { } /** Node implementation of finding a file or directory by walking up parent directories. */ - findUp(name: string | readonly string[], options: findUpOptions = {}): Promise { - return findUp(name, options) + findUp(name: string | string[], options: findUpOptions = {}): Promise { + if (typeof name === 'string') { + return Promise.resolve(findUp(name, options)) + } + return Promise.resolve(findUpAny(name, options)) } /** Node implementation of finding files or directories by walking up parent directories. */ findUpMultiple(name: string | readonly string[], options: findUpOptions = {}): Promise { - return findUpMultiple(name, options) + const results: string[] = [] + const normalisedNames = typeof name === 'string' ? [name] : name; + for (const dir of walkUp(options.cwd ?? '.', options)) { + for (const potentialName of normalisedNames) { + const filePath = join(dir, potentialName); + if (existsSync(filePath)) { + results.push(filePath); + } + } + } + return Promise.resolve(results) } } diff --git a/packages/build-info/vite.config.ts b/packages/build-info/vite.config.ts index aa694bdfba..725ff65b7e 100644 --- a/packages/build-info/vite.config.ts +++ b/packages/build-info/vite.config.ts @@ -15,7 +15,7 @@ export default defineConfig({ setupFiles: ['tests/test-setup.ts'], deps: { // this is to work inside memfs as well - inline: ['find-up', 'locate-path'], + inline: ['empathic', 'locate-path'], }, }, }) diff --git a/packages/config/package.json b/packages/config/package.json index 22880ff7ce..2306592792 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -66,11 +66,11 @@ "cron-parser": "^4.1.0", "deepmerge": "^4.2.2", "dot-prop": "^9.0.0", + "empathic": "^2.0.0", "execa": "^8.0.0", "fast-safe-stringify": "^2.0.7", "figures": "^6.0.0", "filter-obj": "^6.0.0", - "find-up": "^7.0.0", "indent-string": "^5.0.0", "is-plain-obj": "^4.0.0", "map-obj": "^5.0.0", diff --git a/packages/config/src/options/repository_root.js b/packages/config/src/options/repository_root.js index 810f1a7594..9d18937ac3 100644 --- a/packages/config/src/options/repository_root.js +++ b/packages/config/src/options/repository_root.js @@ -1,6 +1,6 @@ import { dirname } from 'path' -import { findUp } from 'find-up' +import { dir as findUp } from 'empathic/find' // Find out repository root among (in priority order): // - `repositoryRoot` option @@ -11,7 +11,7 @@ export const getRepositoryRoot = async function ({ repositoryRoot, cwd }) { return repositoryRoot } - const repositoryRootA = await findUp('.git', { cwd, type: 'directory' }) + const repositoryRootA = findUp('.git', { cwd }) if (repositoryRootA === undefined) { return cwd diff --git a/packages/config/src/path.ts b/packages/config/src/path.ts index bbcd2d6a8c..1ab4f60eb8 100644 --- a/packages/config/src/path.ts +++ b/packages/config/src/path.ts @@ -1,7 +1,7 @@ import { existsSync } from 'fs' import { join, resolve } from 'path' -import { findUp } from 'find-up' +import { file as findUp } from 'empathic/find' import pLocate from 'p-locate' const FILENAME = 'netlify.toml' diff --git a/packages/edge-bundler/node/npm_dependencies.ts b/packages/edge-bundler/node/npm_dependencies.ts index 8d016c4a95..14d864bf5a 100644 --- a/packages/edge-bundler/node/npm_dependencies.ts +++ b/packages/edge-bundler/node/npm_dependencies.ts @@ -5,7 +5,7 @@ import { fileURLToPath, pathToFileURL } from 'url' import { resolve, ParsedImportMap } from '@import-maps/resolve' import { build } from 'esbuild' -import { findUp } from 'find-up' +import { up as findUp } from 'empathic/find' import { parseImports } from 'parse-imports' import tmp from 'tmp-promise' @@ -40,7 +40,7 @@ const getTypePathFromTypesPackage = async ( packageName: string, packageJsonPath: string, ): Promise => { - const typesPackagePath = await findUp(`node_modules/${getTypesPackageName(packageName)}/package.json`, { + const typesPackagePath = findUp(`node_modules/${getTypesPackageName(packageName)}/package.json`, { cwd: packageJsonPath, }) if (!typesPackagePath) { @@ -81,7 +81,7 @@ function packageName(specifier: string) { const safelyDetectTypes = async (pkg: string, basePath: string): Promise => { try { - const json = await findUp(`node_modules/${packageName(pkg)}/package.json`, { + const json = findUp(`node_modules/${packageName(pkg)}/package.json`, { cwd: basePath, }) if (json) { diff --git a/packages/edge-bundler/node/package_json.ts b/packages/edge-bundler/node/package_json.ts index 75ac6ae37e..897f62c692 100644 --- a/packages/edge-bundler/node/package_json.ts +++ b/packages/edge-bundler/node/package_json.ts @@ -1,18 +1,15 @@ import { readFileSync } from 'fs' -import { join } from 'path' +import { dirname, join } from 'path' import { fileURLToPath } from 'url' -import { findUpSync, pathExistsSync } from 'find-up' +import { file as findUp } from 'empathic/find' const getPackagePath = () => { - const packagePath = findUpSync( - (directory: string) => { - if (pathExistsSync(join(directory, 'package.json'))) { - return directory - } - }, - { cwd: fileURLToPath(import.meta.url), type: 'directory' }, + const packageJsonPath = findUp( + 'package.json', + { cwd: dirname(fileURLToPath(import.meta.url)) }, ) + const packagePath = packageJsonPath ? dirname(packageJsonPath) : undefined // We should never get here, but let's show a somewhat useful error message. if (packagePath === undefined) { diff --git a/packages/edge-bundler/package.json b/packages/edge-bundler/package.json index 6967fa8dd9..ce6eec945e 100644 --- a/packages/edge-bundler/package.json +++ b/packages/edge-bundler/package.json @@ -64,10 +64,10 @@ "ajv-errors": "^3.0.0", "better-ajv-errors": "^1.2.0", "common-path-prefix": "^3.0.0", + "empathic": "^2.0.0", "env-paths": "^3.0.0", "esbuild": "0.25.6", "execa": "^8.0.0", - "find-up": "^7.0.0", "get-package-name": "^2.2.0", "get-port": "^7.0.0", "is-path-inside": "^4.0.0", diff --git a/packages/zip-it-and-ship-it/package.json b/packages/zip-it-and-ship-it/package.json index b5f70ca9c3..3abf087d3d 100644 --- a/packages/zip-it-and-ship-it/package.json +++ b/packages/zip-it-and-ship-it/package.json @@ -52,9 +52,9 @@ "es-module-lexer": "^1.0.0", "esbuild": "0.25.6", "execa": "^8.0.0", + "empathic": "^2.0.0", "fast-glob": "^3.3.3", "filter-obj": "^6.0.0", - "find-up": "^7.0.0", "is-builtin-module": "^3.1.0", "is-path-inside": "^4.0.0", "junk": "^4.0.0", diff --git a/packages/zip-it-and-ship-it/src/runtimes/node/bundlers/zisi/resolve.ts b/packages/zip-it-and-ship-it/src/runtimes/node/bundlers/zisi/resolve.ts index 1d7664c806..8985ae07cf 100644 --- a/packages/zip-it-and-ship-it/src/runtimes/node/bundlers/zisi/resolve.ts +++ b/packages/zip-it-and-ship-it/src/runtimes/node/bundlers/zisi/resolve.ts @@ -1,7 +1,7 @@ import { createRequire } from 'module' import { version as nodeVersion } from 'process' -import { findUp } from 'find-up' +import { up as walkUp } from 'empathic/walk' import { pathExists } from 'path-exists' // @ts-expect-error doesnt export async import { async as asyncResolve } from 'resolve' @@ -94,7 +94,12 @@ const resolvePathFollowSymlinks = function (path: string, baseDirs: string[]) { // unlikely, and we don't have any better alternative. const resolvePackageFallback = async function (moduleName: string, baseDirs: string[], error: Error) { const mainFilePath = resolvePathFollowSymlinks(moduleName, baseDirs) - const packagePath = await findUp(isPackageDir.bind(null, moduleName), { cwd: mainFilePath, type: 'directory' }) + let packagePath + for (const dir of walkUp(mainFilePath)) { + if (await isPackageDir(moduleName, dir)) { + packagePath = dir + } + } if (packagePath === undefined) { throw error diff --git a/packages/zip-it-and-ship-it/src/runtimes/node/utils/package_json.ts b/packages/zip-it-and-ship-it/src/runtimes/node/utils/package_json.ts index bf64d10d76..ce3dc2f1fc 100644 --- a/packages/zip-it-and-ship-it/src/runtimes/node/utils/package_json.ts +++ b/packages/zip-it-and-ship-it/src/runtimes/node/utils/package_json.ts @@ -1,7 +1,7 @@ import { promises as fs } from 'fs' import { basename, join } from 'path' -import { findUp, findUpStop, pathExists } from 'find-up' +import { up as walkUp } from 'empathic/walk' export interface PackageJson { name?: string @@ -23,21 +23,26 @@ export interface PackageJsonFile { } export const getClosestPackageJson = async (resolveDir: string, boundary?: string): Promise => { - const packageJsonPath = await findUp( - async (directory) => { - // We stop traversing if we're about to leave the boundaries of any - // node_modules directory. - if (basename(directory) === 'node_modules') { - return findUpStop + let packageJsonPath + + for (const directory of walkUp(resolveDir, { last: boundary })) { + // We stop traversing if we're about to leave the boundaries of any + // node_modules directory. + if (basename(directory) === 'node_modules') { + break; + } + + const path = join(directory, 'package.json') + try { + const stats = await fs.stat(path) + if (stats.isFile()) { + packageJsonPath = path + break } - - const path = join(directory, 'package.json') - const hasPackageJson = await pathExists(path) - - return hasPackageJson ? path : undefined - }, - { cwd: resolveDir, stopAt: boundary }, - ) + } catch { + // do nothing, continue searching + } + } if (packageJsonPath === undefined) { return null diff --git a/packages/zip-it-and-ship-it/src/runtimes/node/utils/plugin_modules_path.ts b/packages/zip-it-and-ship-it/src/runtimes/node/utils/plugin_modules_path.ts index 447510a14e..8e3461f1a9 100644 --- a/packages/zip-it-and-ship-it/src/runtimes/node/utils/plugin_modules_path.ts +++ b/packages/zip-it-and-ship-it/src/runtimes/node/utils/plugin_modules_path.ts @@ -1,6 +1,6 @@ import { join, relative } from 'path' -import { findUp } from 'find-up' +import { dir as findUp } from 'empathic/find' const AUTO_PLUGINS_DIR = '.netlify/plugins/' @@ -21,5 +21,7 @@ export const createAliases = ( }) } -export const getPluginsModulesPath = (srcDir: string): Promise => - findUp(`${AUTO_PLUGINS_DIR}node_modules`, { cwd: srcDir, type: 'directory' }) +export const getPluginsModulesPath = (srcDir: string): Promise => { + const result = findUp(`${AUTO_PLUGINS_DIR}node_modules`, { cwd: srcDir }); + return Promise.resolve(result); +}; From 7ab4939bd9de74742f2f575b49fb59f4c65fd326 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:40:16 +0100 Subject: [PATCH 2/6] chore: drop package-directory Empathic can do this with a basic dirname check. --- package-lock.json | 16 ---------------- packages/build-info/src/node/file-system.ts | 6 +++--- packages/build/package.json | 1 - packages/build/src/install/local.js | 7 +++++-- packages/edge-bundler/node/package_json.ts | 5 +---- .../src/runtimes/node/utils/package_json.ts | 2 +- .../runtimes/node/utils/plugin_modules_path.ts | 6 +++--- 7 files changed, 13 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index fbfed56e38..26ec9f9c4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18637,21 +18637,6 @@ "node": ">=8" } }, - "node_modules/package-directory": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/package-directory/-/package-directory-8.1.0.tgz", - "integrity": "sha512-qHKRW0pw3lYdZMQVkjDBqh8HlamH/LCww2PH7OWEp4Qrt3SFeYMNpnJrQzlSnGrDD5zGR51XqBh7FnNCdVNEHA==", - "license": "MIT", - "dependencies": { - "find-up-simple": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -23919,7 +23904,6 @@ "p-locate": "^6.0.0", "p-map": "^7.0.0", "p-reduce": "^3.0.0", - "package-directory": "^8.0.0", "path-exists": "^5.0.0", "path-type": "^6.0.0", "pretty-ms": "^9.0.0", diff --git a/packages/build-info/src/node/file-system.ts b/packages/build-info/src/node/file-system.ts index 513a2425e0..48e2b81e8c 100644 --- a/packages/build-info/src/node/file-system.ts +++ b/packages/build-info/src/node/file-system.ts @@ -79,12 +79,12 @@ export class NodeFS extends FileSystem { /** Node implementation of finding files or directories by walking up parent directories. */ findUpMultiple(name: string | readonly string[], options: findUpOptions = {}): Promise { const results: string[] = [] - const normalisedNames = typeof name === 'string' ? [name] : name; + const normalisedNames = typeof name === 'string' ? [name] : name for (const dir of walkUp(options.cwd ?? '.', options)) { for (const potentialName of normalisedNames) { - const filePath = join(dir, potentialName); + const filePath = join(dir, potentialName) if (existsSync(filePath)) { - results.push(filePath); + results.push(filePath) } } } diff --git a/packages/build/package.json b/packages/build/package.json index a1eb585f02..da9835586c 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -101,7 +101,6 @@ "p-locate": "^6.0.0", "p-map": "^7.0.0", "p-reduce": "^3.0.0", - "package-directory": "^8.0.0", "path-exists": "^5.0.0", "path-type": "^6.0.0", "pretty-ms": "^9.0.0", diff --git a/packages/build/src/install/local.js b/packages/build/src/install/local.js index ff6a33d108..56236948eb 100644 --- a/packages/build/src/install/local.js +++ b/packages/build/src/install/local.js @@ -1,4 +1,6 @@ -import { packageDirectory } from 'package-directory' +import { dirname } from 'path' + +import { up as packagePath } from 'empathic/package' import { logInstallLocalPluginsDeps } from '../log/messages/install.js' @@ -57,6 +59,7 @@ const hasPackageDir = function ({ packageDir }) { // We only install dependencies of local plugins that have their own `package.json` const removeMainRoot = async function (localPluginsOptions, buildDir) { - const mainPackageDir = await packageDirectory({ cwd: buildDir }) + const mainPackagePath = packagePath({ cwd: buildDir }) + const mainPackageDir = mainPackagePath ? dirname(mainPackagePath) : undefined return localPluginsOptions.filter(({ packageDir }) => packageDir !== mainPackageDir) } diff --git a/packages/edge-bundler/node/package_json.ts b/packages/edge-bundler/node/package_json.ts index 897f62c692..36d07b3cc1 100644 --- a/packages/edge-bundler/node/package_json.ts +++ b/packages/edge-bundler/node/package_json.ts @@ -5,10 +5,7 @@ import { fileURLToPath } from 'url' import { file as findUp } from 'empathic/find' const getPackagePath = () => { - const packageJsonPath = findUp( - 'package.json', - { cwd: dirname(fileURLToPath(import.meta.url)) }, - ) + const packageJsonPath = findUp('package.json', { cwd: dirname(fileURLToPath(import.meta.url)) }) const packagePath = packageJsonPath ? dirname(packageJsonPath) : undefined // We should never get here, but let's show a somewhat useful error message. diff --git a/packages/zip-it-and-ship-it/src/runtimes/node/utils/package_json.ts b/packages/zip-it-and-ship-it/src/runtimes/node/utils/package_json.ts index ce3dc2f1fc..336a00008a 100644 --- a/packages/zip-it-and-ship-it/src/runtimes/node/utils/package_json.ts +++ b/packages/zip-it-and-ship-it/src/runtimes/node/utils/package_json.ts @@ -29,7 +29,7 @@ export const getClosestPackageJson = async (resolveDir: string, boundary?: strin // We stop traversing if we're about to leave the boundaries of any // node_modules directory. if (basename(directory) === 'node_modules') { - break; + break } const path = join(directory, 'package.json') diff --git a/packages/zip-it-and-ship-it/src/runtimes/node/utils/plugin_modules_path.ts b/packages/zip-it-and-ship-it/src/runtimes/node/utils/plugin_modules_path.ts index 8e3461f1a9..972e7b01d8 100644 --- a/packages/zip-it-and-ship-it/src/runtimes/node/utils/plugin_modules_path.ts +++ b/packages/zip-it-and-ship-it/src/runtimes/node/utils/plugin_modules_path.ts @@ -22,6 +22,6 @@ export const createAliases = ( } export const getPluginsModulesPath = (srcDir: string): Promise => { - const result = findUp(`${AUTO_PLUGINS_DIR}node_modules`, { cwd: srcDir }); - return Promise.resolve(result); -}; + const result = findUp(`${AUTO_PLUGINS_DIR}node_modules`, { cwd: srcDir }) + return Promise.resolve(result) +} From 0797cc9c9bfcda26eb461234f864be449881b8a7 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Mon, 28 Jul 2025 19:45:59 +0100 Subject: [PATCH 3/6] fix: support find boundaries --- packages/build-info/src/node/file-system.ts | 46 ++++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/packages/build-info/src/node/file-system.ts b/packages/build-info/src/node/file-system.ts index 48e2b81e8c..a4ed9a2d62 100644 --- a/packages/build-info/src/node/file-system.ts +++ b/packages/build-info/src/node/file-system.ts @@ -1,7 +1,6 @@ -import { promises as fs, existsSync } from 'fs' +import { promises as fs } from 'fs' import { basename, dirname, isAbsolute, join, relative, resolve } from 'path' -import { any as findUpAny, up as findUp } from 'empathic/find' import { up as walkUp } from 'empathic/walk' import { DirType, Environment, FileSystem, findUpOptions } from '../file-system.js' @@ -69,25 +68,50 @@ export class NodeFS extends FileSystem { } /** Node implementation of finding a file or directory by walking up parent directories. */ - findUp(name: string | string[], options: findUpOptions = {}): Promise { - if (typeof name === 'string') { - return Promise.resolve(findUp(name, options)) + async findUp(name: string | string[], options: findUpOptions = {}): Promise { + const walkOptions = { + cwd: options.cwd, + last: options.stopAt, + }; + const names = typeof name === 'string' ? [name] : name; + for (const dir of walkUp('.', walkOptions)) { + for (const potentialName of names) { + const filePath = join(dir, potentialName) + try { + const stats = await fs.stat(filePath); + const type = stats.isFile() ? 'file' : 'directory'; + if (options.type === type || !options.type) { + return filePath; + } + } catch { + // ignore + } + } } - return Promise.resolve(findUpAny(name, options)) } /** Node implementation of finding files or directories by walking up parent directories. */ - findUpMultiple(name: string | readonly string[], options: findUpOptions = {}): Promise { + async findUpMultiple(name: string | readonly string[], options: findUpOptions = {}): Promise { const results: string[] = [] const normalisedNames = typeof name === 'string' ? [name] : name - for (const dir of walkUp(options.cwd ?? '.', options)) { + const walkOptions = { + cwd: options.cwd, + last: options.stopAt, + }; + for (const dir of walkUp(options.cwd ?? '.', walkOptions)) { for (const potentialName of normalisedNames) { const filePath = join(dir, potentialName) - if (existsSync(filePath)) { - results.push(filePath) + try { + const stats = await fs.stat(filePath); + const type = stats.isFile() ? 'file' : 'directory'; + if (options.type === type || !options.type) { + results.push(filePath); + } + } catch { + // ignore } } } - return Promise.resolve(results) + return results } } From b45a7bea5b429cef95e4314c2b7ce95c2de65edd Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Mon, 28 Jul 2025 19:49:25 +0100 Subject: [PATCH 4/6] chore: run format --- packages/build-info/src/node/file-system.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/build-info/src/node/file-system.ts b/packages/build-info/src/node/file-system.ts index a4ed9a2d62..a4dd512ba5 100644 --- a/packages/build-info/src/node/file-system.ts +++ b/packages/build-info/src/node/file-system.ts @@ -72,16 +72,16 @@ export class NodeFS extends FileSystem { const walkOptions = { cwd: options.cwd, last: options.stopAt, - }; - const names = typeof name === 'string' ? [name] : name; + } + const names = typeof name === 'string' ? [name] : name for (const dir of walkUp('.', walkOptions)) { for (const potentialName of names) { const filePath = join(dir, potentialName) try { - const stats = await fs.stat(filePath); - const type = stats.isFile() ? 'file' : 'directory'; + const stats = await fs.stat(filePath) + const type = stats.isFile() ? 'file' : 'directory' if (options.type === type || !options.type) { - return filePath; + return filePath } } catch { // ignore @@ -97,15 +97,15 @@ export class NodeFS extends FileSystem { const walkOptions = { cwd: options.cwd, last: options.stopAt, - }; + } for (const dir of walkUp(options.cwd ?? '.', walkOptions)) { for (const potentialName of normalisedNames) { const filePath = join(dir, potentialName) try { - const stats = await fs.stat(filePath); - const type = stats.isFile() ? 'file' : 'directory'; + const stats = await fs.stat(filePath) + const type = stats.isFile() ? 'file' : 'directory' if (options.type === type || !options.type) { - results.push(filePath); + results.push(filePath) } } catch { // ignore From 1abeee36ac27ff3d273ccc195991710801b4e571 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Mon, 28 Jul 2025 20:56:45 +0100 Subject: [PATCH 5/6] fix: add missing type --- package-lock.json | 1 + packages/build/package.json | 1 + .../src/runtimes/node/bundlers/zisi/resolve.ts | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 26ec9f9c4d..30901c01ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23884,6 +23884,7 @@ "ansi-escapes": "^7.0.0", "chalk": "^5.0.0", "clean-stack": "^5.0.0", + "empathic": "^2.0.0", "execa": "^8.0.0", "fdir": "^6.0.1", "figures": "^6.0.0", diff --git a/packages/build/package.json b/packages/build/package.json index da9835586c..a6082f0e53 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -81,6 +81,7 @@ "ansi-escapes": "^7.0.0", "chalk": "^5.0.0", "clean-stack": "^5.0.0", + "empathic": "^2.0.0", "execa": "^8.0.0", "fdir": "^6.0.1", "figures": "^6.0.0", diff --git a/packages/zip-it-and-ship-it/src/runtimes/node/bundlers/zisi/resolve.ts b/packages/zip-it-and-ship-it/src/runtimes/node/bundlers/zisi/resolve.ts index 8985ae07cf..4c8a195fe3 100644 --- a/packages/zip-it-and-ship-it/src/runtimes/node/bundlers/zisi/resolve.ts +++ b/packages/zip-it-and-ship-it/src/runtimes/node/bundlers/zisi/resolve.ts @@ -94,7 +94,7 @@ const resolvePathFollowSymlinks = function (path: string, baseDirs: string[]) { // unlikely, and we don't have any better alternative. const resolvePackageFallback = async function (moduleName: string, baseDirs: string[], error: Error) { const mainFilePath = resolvePathFollowSymlinks(moduleName, baseDirs) - let packagePath + let packagePath: string | undefined for (const dir of walkUp(mainFilePath)) { if (await isPackageDir(moduleName, dir)) { packagePath = dir From d881a5c734519ebcac007f62decea0603b4f49ca Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Mon, 28 Jul 2025 21:10:42 +0100 Subject: [PATCH 6/6] fix: use exact file path as cwd --- packages/edge-bundler/node/package_json.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edge-bundler/node/package_json.ts b/packages/edge-bundler/node/package_json.ts index 36d07b3cc1..d35cb724b4 100644 --- a/packages/edge-bundler/node/package_json.ts +++ b/packages/edge-bundler/node/package_json.ts @@ -5,7 +5,7 @@ import { fileURLToPath } from 'url' import { file as findUp } from 'empathic/find' const getPackagePath = () => { - const packageJsonPath = findUp('package.json', { cwd: dirname(fileURLToPath(import.meta.url)) }) + const packageJsonPath = findUp('package.json', { cwd: fileURLToPath(import.meta.url) }) const packagePath = packageJsonPath ? dirname(packageJsonPath) : undefined // We should never get here, but let's show a somewhat useful error message.