export const toPosixPath = (p: string) => p.replace(/\\/g, '/') export const toWindowsPath = (p: string) => p.replace(/\//g, '\\') export const normalizePath = (p: string) => { const parts = p.replace(/\\/g, '/').split('/') const stack: string[] = [] for (const part of parts) { if (!part || part === '.') continue if (part === '..') { stack.pop() continue } stack.push(part) } return stack.join('/') } export const joinPaths = (...paths: string[]) => { return paths.map(normalizePath).join('/').replace(/\/+/g, '/') } export const getDirectoryName = (filePath: string) => { const normalized = normalizePath(filePath) const lastSlash = normalized.lastIndexOf('/') return lastSlash === -1 ? '' : normalized.slice(0, lastSlash) } export const getFileName = (filePath: string) => { const normalized = normalizePath(filePath) const lastSlash = normalized.lastIndexOf('/') return lastSlash === -1 ? normalized : normalized.slice(lastSlash + 1) } export const getFileExtension = (filePath: string) => { const fileName = getFileName(filePath) const lastDot = fileName.lastIndexOf('.') return lastDot === -1 ? '' : fileName.slice(lastDot + 1) } export const removeExtension = (filePath: string) => { const ext = getFileExtension(filePath) if (!ext) return filePath return filePath.slice(0, -(ext.length + 1)) } export const isAbsolutePath = (p: string) => { return p.startsWith('/') || /^[A-Za-z]:/.test(p) } export const isHiddenPath = (p: string) => { const normalized = normalizePath(p) return normalized.split('/').some(part => part.startsWith('.')) }