Skip to content
NewBun 1.4.5 is out. Release notes
AphrodyBun

Linter · Rules

bun/no-cwd-dependent-path

Disallow relative paths that depend on the directory the process was started in

readFileSync("config.json") doesn't look next to the file that calls it. It looks in the directory the process was started in. The code works when you run it from the project root and fails with ENOENT when it runs from anywhere else. Start from import.meta.dirname to name a file next to your source.

The rule checks a string or a template literal that starts with a relative path, in these places:

  • The node:fs and node:fs/promises functions, except glob and globSync. For copyFile, cp, link, and rename, both paths are checked. For symlink, only the second one is, because the target is relative to the link.
  • path.resolve(), if every argument is a literal like that.
  • Bun.file() and Bun.write().

Configure

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"bun/no-cwd-dependent-path" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"bun/no-cwd-dependent-path" = ["error", {
  functions = [], # list of strings
}]

Examples

Reported:

import { readFileSync } from "node:fs";

const config = JSON.parse(readFileSync("config.json", "utf8"));
import path from "node:path";

const schema = Bun.file(`schemas/${name}.json`);
const output = path.resolve("dist", "index.js");

Not reported:

import { readFileSync } from "node:fs";
import path from "node:path";

const config = JSON.parse(readFileSync(path.join(import.meta.dirname, "config.json"), "utf8"));
const schema = Bun.file(new URL(`./schemas/${name}.json`, import.meta.url));
const output = path.resolve(import.meta.dirname, "dist", "index.js");

Absolute paths and paths that come from a variable are fine:

import { readFileSync } from "node:fs";

readFileSync("/etc/hosts", "utf8");
readFileSync(process.argv[2], "utf8");
readFileSync(`${root}/config.json`, "utf8");

Options

OptionDefaultWhat it does
functions[]Names of more functions that take a path as their first argument. A name matches both loadFixture() and helpers.loadFixture().
const user = loadFixture("fixtures/user.json");
const team = helpers.loadFixture("fixtures/team.json");

When not to use it

A command-line tool often means the working directory, like when it reads the package.json of the project it was started in. Say so with process.cwd(), or turn the rule off for those files:

import { readFileSync } from "node:fs";
import path from "node:path";

const manifest = readFileSync(path.resolve(process.cwd(), "package.json"), "utf8");