UNPKG

decocms

Version:

CLI for managing deco.chat apps & projects

162 lines 5.27 kB
import { promises as fs } from "fs"; import { dirname, join, relative } from "path"; import { createReadStream, createWriteStream } from "fs"; import { pipeline } from "stream/promises"; /** * Ensure that a directory exists, creating it if necessary (recursive) * Node.js equivalent of Deno's ensureDir */ export async function ensureDir(dirPath) { try { await fs.mkdir(dirPath, { recursive: true }); } catch (error) { // If directory already exists, that's fine if (error.code !== "EEXIST") { throw error; } } } /** * Copy a file from source to destination, creating directories as needed */ async function copyFile(src, dest) { await ensureDir(dirname(dest)); await pipeline(createReadStream(src), createWriteStream(dest)); } /** * Copy a directory recursively from source to destination */ async function copyDir(src, dest, options = {}) { await ensureDir(dest); const entries = await fs.readdir(src, { withFileTypes: true }); for (const entry of entries) { const srcPath = join(src, entry.name); const destPath = join(dest, entry.name); if (entry.isDirectory()) { await copyDir(srcPath, destPath, options); } else if (entry.isFile()) { if (!options.overwrite) { try { await fs.access(destPath); continue; // File exists and overwrite is false, skip } catch { // File doesn't exist, proceed with copy } } await copyFile(srcPath, destPath); } } } /** * Copy a file or directory from source to destination * Node.js equivalent of Deno's copy */ export async function copy(src, dest, options = {}) { const srcStat = await fs.stat(src); if (srcStat.isDirectory()) { await copyDir(src, dest, options); } else if (srcStat.isFile()) { if (!options.overwrite) { try { await fs.access(dest); return; // File exists and overwrite is false, skip } catch { // File doesn't exist, proceed with copy } } await copyFile(src, dest); } else { throw new Error(`Source ${src} is neither a file nor a directory`); } } /** * Recursively walk a directory tree and yield entries * Node.js equivalent of Deno's walk */ export async function* walk(root, options = {}) { const { maxDepth = Infinity, includeFiles = true, includeDirs = false, followSymlinks = false, exts, match, skip, } = options; async function* walkRecursive(dir, depth) { if (depth > maxDepth) return; let entries; try { entries = await fs.readdir(dir, { withFileTypes: true }); } catch (_error) { // Skip directories we can't read return; } for (const entry of entries) { const entryPath = join(dir, entry.name); const relativePath = relative(root, entryPath); let isFile = entry.isFile(); let isDirectory = entry.isDirectory(); const isSymlink = entry.isSymbolicLink(); // Handle symlinks if (isSymlink && followSymlinks) { try { const stat = await fs.stat(entryPath); isFile = stat.isFile(); isDirectory = stat.isDirectory(); } catch { continue; // Skip broken symlinks } } else if (isSymlink && !followSymlinks) { continue; // Skip symlinks when not following them } const walkEntry = { path: entryPath, name: entry.name, isFile, isDirectory, isSymlink, }; // Apply filters if (skip && skip.some((pattern) => pattern.test(relativePath))) { continue; } if (match && !match.some((pattern) => pattern.test(relativePath))) { continue; } if (exts && isFile) { const ext = entryPath.substring(entryPath.lastIndexOf(".") + 1); if (!exts.includes(ext)) { continue; } } // Yield files if requested if (isFile && includeFiles) { yield walkEntry; } // Yield directories if requested if (isDirectory && includeDirs) { yield walkEntry; } // Recurse into directories if (isDirectory) { yield* walkRecursive(entryPath, depth + 1); } } } yield* walkRecursive(root, 0); } /** * Collect all walk entries into an array * Convenience function for when you need all entries at once */ export async function walkArray(root, options = {}) { const entries = []; for await (const entry of walk(root, options)) { entries.push(entry); } return entries; } //# sourceMappingURL=fs.js.map