Compact set of path utilities that complement Node's builtin
pathmodule.
- Tilde expansion: expand
~to the current user's home directory withuntildify. - Safe joining and resolving: helpers that avoid common pitfalls when composing paths.
- Useful utilities: retrieve parent paths, absolute normalization, and platform-aware helpers.
- Small package with ESM and CJS builds
npm add @zokugun/fs-pathimport { isInDir, join, resolve } from '@zokugun/fs-path'
const configDir = resolve('~/.config/myapp')
const dataFile = join(configDir, 'data.json')
console.log('Config dir:', configDir)
console.log('Data file:', dataFile)
console.log('Is data file inside config dir?', isInDir(dataFile, configDir))This example expands the current user's home directory, joins paths safely, and prints the resolved absolute path for configDir.
absolute(...paths: string[]): string: Returns a normalized absolute path.isAbsolute(path: string): boolean: Returntruewhenpathis absolute for the current platform.isInDir(path: string, parent: string): boolean: Returntruewhenpathis equal to or contained withinparent.isInDirs(path: string, parents: string[]): boolean: Returntruewhenpathis equal to or contained within in one of theparents.isSafePath(path: string, options?): boolean: Returntruewhenpathis considered safe for use (guards against suspicious segments such as..when appropriate for the platform).isSafeSegment(segment: string, target?: Target | 'auto'): boolean: Returntruewhen a single path segment is safe (doesn't contain path separators or traversal sequences).join(...paths: string[]): string: Join path segments.leafExt(path: string, length?: number): string: Return the extensions.leafName(path: string, extension?: number | string): string: Return the basename ofpathwith/without the extensions.matchesGlob?(path: string, pattern: string): boolean: Optional platform-provided glob matcher when available.normalize(path: string): string: Normalize the path (same aspath.normalize).parentName(path: string): string: Return the parent name ofpath.parentPath(path: string): string: Return the parent directory ofpath.relative(from: string, to: string): string: Compute the relative path fromfromtoto.resolve(...paths: string[]): string: Resolve path segments to an absolute path. Supports tilde expansion:~expands to the current user's home directory.~username/...attempts to expand to that user's home directory when available.
sanitize(path: string, options?): Result<string>: Return a sanitized form ofpathwith unsafe segments normalized.untildify(path: string): string: Expand a leading~or~usernameto the home directory, or returnpathunchanged.delimiter: Platform-specific character (;/:).separator: Platform-specific character (\//).
export type PlatformPath = {
readonly delimiter: ';' | ':';
readonly separator: '\\' | '/';
readonly posix: PlatformPath;
readonly win32: PlatformPath;
absolute: (...paths: string[]) => string;
isAbsolute: (path: string) => boolean;
isInDir(path: string, parent: string): boolean;
isInDirs(path: string, parents: string[]): boolean;
isSafePath: (path: string, options?: {
parent?: string | null;
parents?: string | string[] | null;
target?: Target | 'auto';
}) => boolean;
isSafeSegment: (segment: string, target?: Target | 'auto') => boolean;
join: (...paths: string[]) => string;
leafExt: (path: string, length?: number) => string;
leafName: (path: string, extension?: number | string) => string;
matchesGlob?: (path: string, pattern: string) => boolean;
normalize: (path: string) => string;
parentName: (path: string) => string;
parentPath: (path: string) => string;
relative: (from: string, to: string) => string;
resolve: (...paths: string[]) => string;
sanitize(path: string, options?: {
parent?: string | null;
parents?: string | string[] | null;
replacement?: string | null;
target?: Target | 'auto'
}) => Result<string>
untildify: (path: string) => string;
};This library intentionally mirrors many of Node's path APIs but provides small ergonomic differences and extra features where useful:
join(...paths): wrapspath.join. Returns''instead of.when the joined result is the current directory.isAbsolute(path),normalize(path),relative(from, to): direct mappings topath.isAbsolute,path.normalize, andpath.relativerespectively.parentPath(file): wrapspath.dirname. Returns''instead of.for consistency withjoin.resolve(...paths): wrapspath.resolvebut adds tilde expansion (~and~username) before resolving.delimiter: same value aspath.delimiteron the current platform.separator: same value aspath.sepon the current platform.
Contributions are most welcome. Please:
- Open issues and feature requests under the repository discussions.
- Follow the
CONTRIBUTING.md.
Support this project by becoming a financial contributor.
| ko-fi.com/daiyam | |
| liberapay.com/daiyam/donate | |
| paypal.me/daiyam99 |
Copyright © 2026-present Baptiste Augrain
Licensed under the MIT license.