distant-filesystem
v1.0.0
Published
Get a filesystem API that is rooted in another directory on disk.
Maintainers
Readme
distant-filesystem
Get a filesystem API that is rooted in another directory on disk.
With no arguments passed, it finds the nearest package.json above your current working directory and gives you the path and parsed contents, as well as a rooted API for fs operations relative to that package root.
The core value is simple: cleaner DX for root-relative fs operations without changing process cwd.
Install
npm add distant-filesystemQuick Start
import distant from 'distant-filesystem'
const dfs = await distant.filesystem()
console.log(dfs.rootPath)
console.log(dfs.packageJsonPath)
console.log(dfs.packageJson)
const readmeText = await dfs.file.read('README.md')
const hasTsconfig = await dfs.exists('tsconfig.json')
const sourceEntryPath = dfs.resolve('source/index.ts')
const config = await dfs.file.load('./some-config.ts')Why it is useful
Tooling code often needs a stable filesystem root that is not the process cwd.
distant.filesystem() keeps those operations explicit and clean by scoping them to one rooted helper.
The package lookup is a big convenience. The main win is the tiny rooted fs API and the cleaner code shape it enables.
API
distant.filesystem(input?)
Creates a rooted filesystem helper.
| Input | Behavior |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| undefined | Finds nearest package.json upward from process.cwd(), then roots the helper at that package directory. |
| string | Treats the string as a custom root path and roots the helper there. If a package.json exists in that root directory, package metadata is included. |
If no package.json can be found when no argument is provided, it throws an error with code DISTANT_FS_PACKAGE_NOT_FOUND.
Returned object (DfsT)
| Property | Type | Description |
| ----------------- | -------------------------------------------- | ----------------------------------------------------------------- |
| rootPath | string | Root directory for all helper operations. |
| packageJsonPath | string? | Absolute path to the loaded package.json when available. |
| packageJson | Record<string, unknown>? | Parsed package.json contents loaded via jiti when available. |
| resolve | (relativePath: string) => string | Resolves a root-relative path to absolute. |
| exists | (relativePath: string) => Promise<boolean> | Checks whether a root-relative path exists (file or folder). |
| file | DfsFileT | File operations scoped to the root. See below. |
| folder | DfsFolderT | Folder operations scoped to the root. See below. |
| find | DfsFindT | Searches downward from the root. Callable, with .all. See below. |
dfs.file
| Method | Type | Description |
| -------- | ------------------------------------------------------ | ------------------------------------------------------ |
| exists | (relativePath: string) => Promise<boolean> | True only when the path exists and is a file. |
| read | (relativePath: string) => Promise<string> | Reads a UTF-8 file. |
| write | (relativePath: string, content: string) => Promise<void> | Writes a UTF-8 file, creating parent folders. |
| remove | (relativePath: string) => Promise<void> | Removes a file (no error if missing). |
| load | <ExportT>(relativePath: string) => Promise<ExportT> | Imports a TS/JS/JSON module via jiti. |
dfs.folder
| Method | Type | Description |
| -------- | ---------------------------------------------------- | ------------------------------------------------- |
| exists | (relativePath: string) => Promise<boolean> | True only when the path exists and is a folder. |
| ensure | (relativePath: string) => Promise<void> | Creates the folder (and parents) if missing. |
| remove | (relativePath: string) => Promise<void> | Removes the folder recursively (no error if missing). |
| list | (relativePath: string) => Promise<Array<string>> | Lists the folder's entry names. |
dfs.find
Searches downward from rootPath using glob or regex patterns.
const firstTsConfig = await dfs.find('**/tsconfig*.json') // string | null
const allTests = await dfs.find.all(/\.test\.ts$/) // Array<string>| Call | Type | Description |
| ---------------- | ------------------------------------------ | -------------------------------------------- |
| find(pattern) | (pattern: string \| RegExp) => Promise<string \| null> | First match, or null. |
| find.all(pattern) | (pattern: string \| RegExp) => Promise<Array<string>> | Every match. |
Rooted filesystem operations
Once you have dfs, treat it like a virtual cwd:
const packageRootReadme = await dfs.file.read('README.md')
const hasPackageLock = await dfs.exists('package-lock.json')
const absoluteScriptPath = dfs.resolve('scripts/release.ts')
const loadedConfig = await dfs.file.load('./tooling/config.ts')
await dfs.folder.ensure('build/assets')
await dfs.file.write('build/output.json', '{}')
const buildEntries = await dfs.folder.list('build')You can also root operations in another directory:
const toolsDfs = await distant.filesystem('../some/other/project')
const outputPath = toolsDfs.resolve('build/output.json')
const hasReadme = await toolsDfs.exists('README.md')Exported helpers
The package also exports findUp and findDown directly. These cover advanced discovery (upward search, content filters, custom ignores) that the rooted dfs.find intentionally keeps simple.
import { findUp, findDown } from 'distant-filesystem'
const packagePath = await findUp('package.json')
const allTsConfigs = await findDown({
cwd: process.cwd(),
match: '**/tsconfig*.json',
multiple: true
})findUp(fileName, cwd?)
Searches for a file in cwd, then parent directories, up to filesystem root.
Best use cases:
- find project boundaries (
package.json,.git,pnpm-workspace.yaml) - locate nearest config override from a nested directory
findDown(options)
Searches downward from a starting directory using glob and/or regex matching.
| Option | Type | Description |
| ---------- | --------------------------------------------- | ------------------------------------------------------------ |
| cwd | string | Directory to search from. Defaults to process.cwd(). |
| match | string \| RegExp \| Array<string \| RegExp> | Path patterns to match. |
| content | string \| RegExp \| Array<string \| RegExp> | Optional file-content filters. |
| ignore | string[] | Glob ignore patterns. Defaults to node_modules and .git. |
| multiple | boolean | Return all matches (true) or first match (false). |
Notes
dfs.file.load()is powered byjiti, so TS/ESM/CJS/JSON imports are supported.- File and folder operations are backed by
fs-extra, so writes create parent folders and removes are recursive and forgiving. dfs.read()-style UTF-8 reads live underdfs.file.read().
License
MIT
