Tell whether a path stays inside a directory. Zero dependencies, Node 20+.
npm install @chatluna/path-guardimport { homedir } from 'node:os'
import { isInside, isInsideReal, resolvePath } from '@chatluna/path-guard'
const root = '/srv/workspace'
const target = resolvePath(input, { cwd: root, home: homedir() })
isInside(root, target) // compared as written
await isInsideReal(root, target) // symlinks followed
// Then use `target`, not `input`, for the file operation.Returns an absolute, normalized path. ~ and ~/… expand to home when one is given; without it, ~ is an ordinary name, as it is for Node's fs. Relative paths resolve against cwd.
.. segments are folded lexically. Use the returned path for the file operation: the operating system resolves link/.. through the link, so checking one string and opening another lets a symlink escape.
Whether child is parent or below it, compared as written. Symlinks are not followed. /work/..data is inside /work; /workshop is not. Windows paths compare case-insensitively, and a path on another drive is never inside. Pass platform: 'posix' | 'win32' to check paths of another machine.
isInside on real locations: both paths have their symlinks followed, so a link inside parent that points outside counts as outside, and a root that is itself a link still contains its files. A path that does not exist yet resolves its nearest existing ancestor, so a file about to be created is placed where it would really land. It fails closed: a symlink loop or an unreadable ancestor counts as outside.
The real location of an absolute path, following every symlink, with a missing tail kept as written.
- The answer holds only until the file system changes. A symlink created between the check and the file operation is not seen.
- Hard links cannot be told apart from ordinary files.
isInsideRealreads the local file system. For a remote machine, useisInsidewith itsplatform.
MIT