/** * Path Utilities - Cross-platform path manipulation helpers * * Provides functions for normalizing and comparing file system paths * across different operating systems (Windows, macOS, Linux). */ /** * Normalize a path by converting backslashes to forward slashes * * This ensures consistent path representation across platforms: * - Windows: C:\Users\foo\bar -> C:/Users/foo/bar * - Unix: /home/foo/bar -> /home/foo/bar (unchanged) * * @param p - Path string to normalize * @returns Normalized path with forward slashes * * @example * ```typescript * normalizePath("C:\\Users\\foo\\bar"); // "C:/Users/foo/bar" * normalizePath("/home/foo/bar"); // "/home/foo/bar" * ``` */ export function normalizePath(p: string): string { return p.replace(/\\/g, '/'); } /** * Compare two paths for equality after normalization * * Handles null/undefined values and normalizes paths before comparison. * Useful for checking if two paths refer to the same location regardless * of platform-specific path separators. * * @param p1 - First path to compare (or null/undefined) * @param p2 - Second path to compare (or null/undefined) * @returns true if paths are equal (or both null/undefined), false otherwise * * @example * ```typescript * pathsEqual("C:\\foo\\bar", "C:/foo/bar"); // true * pathsEqual("/home/user", "/home/user"); // true * pathsEqual("/home/user", "/home/other"); // false * pathsEqual(null, undefined); // false * pathsEqual(null, null); // true * ``` */ export function pathsEqual(p1: string | undefined | null, p2: string | undefined | null): boolean { if (!p1 || !p2) return p1 === p2; return normalizePath(p1) === normalizePath(p2); } /** * Sanitize a filename to be safe for cross-platform file system usage * * Removes or replaces characters that are invalid on various file systems * and prevents Windows reserved device names (CON, PRN, AUX, NUL, COM1-9, LPT1-9). * * @param filename - The filename to sanitize (without path, just the name) * @param fallback - Fallback name if sanitization results in empty string (default: 'file') * @returns A sanitized filename safe for all platforms * * @example * ```typescript * sanitizeFilename("my file.txt"); // "my_file.txt" * sanitizeFilename("nul.txt"); // "_nul.txt" (Windows reserved) * sanitizeFilename("con"); // "_con" (Windows reserved) * sanitizeFilename("file?.txt"); // "file.txt" * sanitizeFilename(""); // "file" * sanitizeFilename("", "unnamed"); // "unnamed" * ``` */ export function sanitizeFilename(filename: string, fallback: string = 'file'): string { if (!filename || typeof filename !== 'string') { return fallback; } // Remove or replace invalid characters: // - Path separators: / \ // - Windows invalid chars: : * ? " < > | // - Control characters and other problematic chars let safeName = filename .replace(/[/\\:*?"<>|]/g, '') // Remove invalid chars .replace(/\s+/g, '_') // Replace spaces with underscores .replace(/\.+$/g, '') // Remove trailing dots (Windows issue) .replace(/^\.+/g, '') // Remove leading dots .trim(); // If empty after sanitization, use fallback if (!safeName || safeName.length === 0) { return fallback; } // Handle Windows reserved device names (case-insensitive) // Reserved names: CON, PRN, AUX, NUL, COM1-9, LPT1-9 const windowsReserved = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i; if (windowsReserved.test(safeName)) { safeName = `_${safeName}`; } return safeName; }