UNPKG

tiny-essentials

Version:

Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.

273 lines (242 loc) 7.46 kB
'use strict'; var fs = require('fs'); var promises = require('fs/promises'); var path = require('path'); var normalFuncs = require('./normalFuncs.cjs'); /*========================* * JSON Operations *========================*/ /** * Reads and parses a JSON file. * Throws an error if the file content is not valid JSON. * @param {string} filePath * @returns {Promise<any>} */ async function readJsonFileAsync(filePath) { if (!fs.existsSync(filePath)) throw new Error(`File not found: ${filePath}`); const content = await promises.readFile(filePath, 'utf-8'); return JSON.parse(content); } /** * Saves an object as JSON to a file. * Automatically creates the directory if it does not exist. * @param {string} filePath * @param {any} data * @param {number} [spaces=2] * @returns {Promise<void>} */ function writeJsonFileAsync(filePath, data, spaces = 2) { const json = JSON.stringify(data, null, spaces); return promises.writeFile(filePath, json, 'utf-8'); } /*========================* * Directory Management *========================*/ /** * Clears all contents inside a directory but keeps the directory. * @param {string} dirPath */ async function clearDirectoryAsync(dirPath) { if (!fs.existsSync(dirPath)) return; const files = await promises.readdir(dirPath); /** @type {Record<string, import('fs').Stats>} */ const dataList = {}; const promises$1 = []; for (const file of files) { const fullPath = path.join(dirPath, file); const lsResult = promises.lstat(fullPath); lsResult.then((statData) => { dataList[fullPath] = statData; return statData; }); promises$1.push(lsResult); } await Promise.all(promises$1); const promises2 = []; for (const fullPath in dataList) { const statData = dataList[fullPath]; if (statData.isDirectory()) { promises2.push(promises.rm(fullPath, { recursive: true, force: true })); } else { promises2.push(promises.unlink(fullPath)); } } await Promise.all(promises2); } /*========================* * File Checks *========================*/ /** * Checks whether a directory is empty. * @param {string} dirPath * @returns {Promise<boolean>} */ async function isDirEmptyAsync(dirPath) { const data = await promises.readdir(dirPath); return data.length === 0; } /*========================* * File Operations *========================*/ /** * Copies a file to a destination. * @param {string} src * @param {string} dest * @param {number} [mode] * @returns {Promise<void>} */ function ensureCopyFileAsync(src, dest, mode) { normalFuncs.ensureDirectory(path.dirname(dest)); return promises.copyFile(src, dest, mode); } /** * Deletes a file (If the file exists). * @param {string} filePath * @returns {Promise<boolean>} */ async function tryDeleteFileAsync(filePath) { if (normalFuncs.fileExists(filePath)) { await promises.unlink(filePath); return true; } return false; } /*========================* * Text Operations *========================*/ /** * Writes text to a file (Ensures that the directory exists, creating it recursively if needed). * @param {string} filePath * @param {string} content * @param {import('fs').WriteFileOptions} [ops='utf-8'] * @returns {Promise<void>} */ function writeTextFileAsync(filePath, content, ops = 'utf-8') { const dir = path.dirname(filePath); normalFuncs.ensureDirectory(dir); return promises.writeFile(filePath, content, ops); } /*========================* * Directory Listings *========================*/ /** * Lists all files and dirs in a directory (optionally recursive). * @param {string} dirPath * @param {boolean} [recursive=false] * @returns {Promise<{ files: string[]; dirs: string[] }>} */ async function listFilesAsync(dirPath, recursive = false) { /** @type {{ files: string[]; dirs: string[] }} */ const results = { files: [], dirs: [] }; if (!normalFuncs.dirExists(dirPath)) return results; const entries = await promises.readdir(dirPath); for (const entry of entries) { const fullPath = path.join(dirPath, entry); const statData = await promises.lstat(fullPath); if (statData.isDirectory()) { results.dirs.push(fullPath); if (recursive) { const results2 = await listFilesAsync(fullPath, true); results.files.push(...results2.files); results.dirs.push(...results2.dirs); } } else { results.files.push(fullPath); } } return results; } /** * Lists all directories in a directory (optionally recursive). * @param {string} dirPath * @param {boolean} [recursive=false] * @returns {Promise<string[]>} */ async function listDirsAsync(dirPath, recursive = false) { /** @type {string[]} */ const results = []; if (!normalFuncs.dirExists(dirPath)) return results; const entries = await promises.readdir(dirPath); for (const entry of entries) { const fullPath = path.join(dirPath, entry); const statData = await promises.lstat(fullPath); if (statData.isDirectory()) { results.push(fullPath); if (recursive) { results.push(...(await listDirsAsync(fullPath, true))); } } } return results; } /*========================* * File Info *========================*/ /** * Returns the size of a file in bytes. * @param {string} filePath * @returns {Promise<number>} */ async function fileSizeAsync(filePath) { if (!normalFuncs.fileExists(filePath)) return 0; const stats = await promises.stat(filePath); return stats.size; } /** * Returns the total size of a directory in bytes. * @param {string} dirPath * @returns {Promise<number>} */ async function dirSizeAsync(dirPath) { let total = 0; const { files } = await listFilesAsync(dirPath, true); const promises = []; for (const file of files) { const result = fileSizeAsync(file); result.then((item) => { total += item; return item; }); promises.push(result); } await Promise.all(promises); return total; } /*========================* * Backup Utilities *========================*/ /** * Restores the most recent backup of a file. * @param {string} filePath * @param {string} [ext='bak'] * @returns {Promise<void>} */ function restoreLatestBackupAsync(filePath, ext = 'bak') { const latestBackup = normalFuncs.getLatestBackupPath(filePath, ext); return ensureCopyFileAsync(latestBackup, filePath); } /** * Creates a backup copy of a file with .bak timestamp suffix. * @param {string} filePath * @param {string} [ext='bak'] * @returns {Promise<void>} */ async function backupFileAsync(filePath, ext = 'bak') { if (!normalFuncs.fileExists(filePath)) return; const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const backupPath = `${filePath}.${ext}.${timestamp}`; return ensureCopyFileAsync(filePath, backupPath); } exports.backupFileAsync = backupFileAsync; exports.clearDirectoryAsync = clearDirectoryAsync; exports.dirSizeAsync = dirSizeAsync; exports.ensureCopyFileAsync = ensureCopyFileAsync; exports.fileSizeAsync = fileSizeAsync; exports.isDirEmptyAsync = isDirEmptyAsync; exports.listDirsAsync = listDirsAsync; exports.listFilesAsync = listFilesAsync; exports.readJsonFileAsync = readJsonFileAsync; exports.restoreLatestBackupAsync = restoreLatestBackupAsync; exports.tryDeleteFileAsync = tryDeleteFileAsync; exports.writeJsonFileAsync = writeJsonFileAsync; exports.writeTextFileAsync = writeTextFileAsync;