CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-yarnpkg--fslib

A TypeScript library abstracting the Node filesystem APIs with virtual filesystems and cross-platform path handling

Overview
Eval results
Files

path-handling.mddocs/

Path Handling

Cross-platform path manipulation utilities that provide type-safe path operations and conversion between different path formats.

Overview

The @yarnpkg/fslib package provides comprehensive path handling through two main utilities:

  • ppath - Portable path utilities for cross-platform compatibility
  • npath - Native path utilities with platform-specific behavior

Core Types

Path Types

// Basic path types
type PortablePath = string & { readonly __portable_path__: unique symbol };
type NativePath = string & { readonly __native_path__: unique symbol };
type Filename = string & { readonly __filename__: unique symbol };
type Path = PortablePath | NativePath;
type FSPath<T> = T | number; // Path or file descriptor

// Path component types
interface ParsedPath<P extends Path> {
  root: P;
  dir: P;
  base: Filename;
  ext: string;
  name: string;
}

interface FormatInputPathObject<P extends Path> {
  root?: P;
  dir?: P;
  base?: Filename;
  ext?: string;
  name?: string;
}

Portable Path Utilities (ppath)

The ppath utility provides cross-platform path operations that always use forward slashes as separators.

Basic Operations

import { ppath, type PortablePath } from '@yarnpkg/fslib';

// Join path segments
const joined = ppath.join('/base' as PortablePath, 'sub', 'file.txt');
// Result: '/base/sub/file.txt' as PortablePath

// Resolve to absolute path
const resolved = ppath.resolve('/current' as PortablePath, '../relative/path');
// Result: '/relative/path' as PortablePath

// Normalize path
const normalized = ppath.normalize('/path/./to/../file.txt' as PortablePath);
// Result: '/path/file.txt' as PortablePath

Path Analysis

import { ppath, type PortablePath } from '@yarnpkg/fslib';

// Check if path is absolute
const isAbsolute = ppath.isAbsolute('/absolute/path' as PortablePath);
// Result: true

// Get relative path between two paths
const relative = ppath.relative(
  '/from/directory' as PortablePath, 
  '/to/file.txt' as PortablePath
);
// Result: '../to/file.txt' as PortablePath

// Check if one path contains another
const contains = ppath.contains(
  '/parent' as PortablePath,
  '/parent/child/file.txt' as PortablePath
);
// Result: true

Path Components

import { ppath, type PortablePath, type Filename } from '@yarnpkg/fslib';

const filePath = '/path/to/file.txt' as PortablePath;

// Get directory name
const dirname = ppath.dirname(filePath);
// Result: '/path/to' as PortablePath

// Get base name
const basename = ppath.basename(filePath);
// Result: 'file.txt' as Filename

const basenameNoExt = ppath.basename(filePath, '.txt');
// Result: 'file' as Filename

// Get file extension
const extension = ppath.extname(filePath);
// Result: '.txt'

Path Parsing and Formatting

import { ppath, type PortablePath } from '@yarnpkg/fslib';

// Parse path into components
const parsed = ppath.parse('/path/to/file.txt' as PortablePath);
// Result: {
//   root: '/' as PortablePath,
//   dir: '/path/to' as PortablePath,
//   base: 'file.txt' as Filename,
//   ext: '.txt',
//   name: 'file'
// }

// Format path from components
const formatted = ppath.format({
  dir: '/path/to' as PortablePath,
  name: 'file',
  ext: '.txt'
});
// Result: '/path/to/file.txt' as PortablePath

Working Directory Operations

import { ppath } from '@yarnpkg/fslib';

// Get current working directory
const cwd = ppath.cwd();
// Result: Current working directory as PortablePath

Native Path Utilities (npath)

The npath utility provides platform-specific path operations and conversion utilities.

Basic Operations

import { npath, type NativePath } from '@yarnpkg/fslib';

// All standard path operations (same interface as ppath)
const joined = npath.join('/base' as NativePath, 'sub', 'file.txt');
const resolved = npath.resolve('/current' as NativePath, '../relative/path');
const normalized = npath.normalize('/path/./to/../file.txt' as NativePath);

Path Conversion

import { npath, type PortablePath, type NativePath } from '@yarnpkg/fslib';

// Convert portable path to native path
const portablePath = '/path/to/file.txt' as PortablePath;
const nativePath = npath.fromPortablePath(portablePath);
// On Windows: 'C:\\path\\to\\file.txt' as NativePath
// On Unix: '/path/to/file.txt' as NativePath

// Convert native path to portable path
const backToPortable = npath.toPortablePath(nativePath);
// Result: '/path/to/file.txt' as PortablePath

Path Constants

Portable Path Constants

import { PortablePath } from '@yarnpkg/fslib';

// Root path
const root = PortablePath.root; // '/' as PortablePath

// Current directory
const dot = PortablePath.dot; // '.' as PortablePath

// Parent directory  
const parent = PortablePath.parent; // '..' as PortablePath

Filename Constants

import { Filename } from '@yarnpkg/fslib';

// Common directory and file names
const home = Filename.home; // '~' as Filename
const nodeModules = Filename.nodeModules; // 'node_modules' as Filename
const packageJson = Filename.manifest; // 'package.json' as Filename
const yarnLock = Filename.lockfile; // 'yarn.lock' as Filename

// Yarn-specific files
const virtual = Filename.virtual; // '__virtual__' as Filename
const pnpCjs = Filename.pnpCjs; // '.pnp.cjs' as Filename
const pnpData = Filename.pnpData; // '.pnp.data.json' as Filename
const pnpLoader = Filename.pnpEsmLoader; // '.pnp.loader.mjs' as Filename
const yarnrc = Filename.rc; // '.yarnrc.yml' as Filename
const env = Filename.env; // '.env' as Filename

Advanced Path Operations

Generic Path Conversion

import { convertPath, ppath, npath, type PortablePath, type NativePath } from '@yarnpkg/fslib';

// Convert between path types using utilities
const nativePath = '/some/path' as NativePath;
const portablePath = convertPath(ppath, nativePath);
// Result: '/some/path' as PortablePath

const backToNative = convertPath(npath, portablePath);
// Result: '/some/path' as NativePath (or platform-specific format)

Path Validation and Safety

import { ppath, type PortablePath } from '@yarnpkg/fslib';

// Check if path is contained within another path (security)
function isPathSafe(basePath: PortablePath, targetPath: PortablePath): boolean {
  const resolved = ppath.resolve(basePath, targetPath);
  return ppath.contains(basePath, resolved);
}

// Usage
const isAllowed = isPathSafe(
  '/safe/directory' as PortablePath,
  'relative/path/to/file.txt' as PortablePath
);

Working with Path Collections

import { ppath, type PortablePath } from '@yarnpkg/fslib';

// Find common ancestor path
function findCommonPath(paths: PortablePath[]): PortablePath {
  if (paths.length === 0) return '/' as PortablePath;
  
  let common = paths[0];
  for (const path of paths.slice(1)) {
    while (!ppath.contains(common, path) && !ppath.contains(path, common)) {
      common = ppath.dirname(common);
    }
  }
  return common;
}

// Usage
const commonPath = findCommonPath([
  '/project/src/components/Button.tsx' as PortablePath,
  '/project/src/utils/helpers.ts' as PortablePath,
  '/project/src/types/index.ts' as PortablePath
]);
// Result: '/project/src' as PortablePath

Integration Examples

File System Integration

import { xfs, ppath, type PortablePath } from '@yarnpkg/fslib';

// Combine path utilities with filesystem operations
async function processFileTree(basePath: PortablePath): Promise<void> {
  const files = await xfs.readdirPromise(basePath, { withFileTypes: true });
  
  for (const file of files) {
    const fullPath = ppath.join(basePath, file.name);
    
    if (file.isDirectory()) {
      console.log(`Directory: ${ppath.relative(ppath.cwd(), fullPath)}`);
      await processFileTree(fullPath);
    } else {
      const ext = ppath.extname(fullPath);
      console.log(`File: ${file.name} (${ext})`);
    }
  }
}

Cross-Platform Path Handling

import { npath, ppath, type PortablePath, type NativePath } from '@yarnpkg/fslib';

// Handle paths from different sources
function normalizePath(inputPath: string): PortablePath {
  // Assume input might be native or portable
  try {
    // Try to treat as native path and convert
    const asNative = inputPath as NativePath;
    return npath.toPortablePath(asNative);
  } catch {
    // Already portable or invalid
    return ppath.normalize(inputPath as PortablePath);
  }
}

// Usage with various input formats
const paths = [
  '/unix/style/path',
  'C:\\Windows\\Style\\Path',
  './relative/path',
  '../parent/directory'
];

const normalized = paths.map(normalizePath);

Related Documentation

  • Filesystem Abstractions - Core filesystem interfaces that use these path types
  • Filesystem Implementations - Concrete filesystems working with paths
  • Advanced Features - Advanced operations using path utilities

Install with Tessl CLI

npx tessl i tessl/npm-yarnpkg--fslib

docs

advanced-features.md

constants-and-utilities.md

filesystem-abstractions.md

filesystem-implementations.md

index.md

path-handling.md

tile.json