/** * XFile Tools Module ... * a module for handle all file/folder manipulating task in node js ... * * Maintainer * * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) */ // //#region Module Imports ... const fs = require('fs'); const os = require('os'); const Path = require('path'); const http = require('http'); const https = require('https'); const XValueTools = require('./x-value.tools'); //#endregion // //#region Constants ... /** * current os path separators ... */ const PathSeparator = Path.sep; /** * current directory ... */ const CurrentDir = __dirname; //#endregion // //#region Actions ... // //#region Global ... /** * retrieve a path status ... * * @param {string} path a path value to check ... * @returns an stat object ... */ function getStatus(path = '') { // if (!XValueTools.isValidArg(path)) { return undefined; } // return fs.statSync(path); } /** * retrieve user's Home path ... * * @returns {string} a path ... */ function getHomePath() { return os.homedir(); } //#endregion // //#region Path ... /** * retrieve the base name of specific address path ... * * @param {string} path address of file or folder ... * @returns string ... */ function basename(path = '') { // if (!XValueTools.isValidArg(path)) { return ''; } // const result = Path.basename(path); return result; } /** * join several path segments together ... * * @param {...string} path path params ... * @returns a joined paths ... */ function joinPath(...path) { return Path.join(...path); } /** * resolve a relative path to absolute ... * * @param {string[]} path a path value to check ... * @returns {string} */ function resolvePath(...path) { return Path.resolve(...path); } //#endregion // //#region File ... /** * determines a path destination is a file or not ... * * @param {string} path a path value to check ... * @returns a boolean value ... */ function isFileExists(path = '') { // if (!XValueTools.isValidArg(path)) { return false; } // try { const stat = getStatus(path); if (!stat) { return false; } // return stat.isFile(); } catch { return false; } } /** * remove a file ... * * @param {string} path a file path ... * @returns {Promise} action done or not ... */ function removeFile(path = '') { return new Promise((resolve) => { // if (!isFileExists(path)) { resolve(false); } // fs.unlink(path, (err) => { // if (err) { resolve(false); return; } // resolve(true); }); }); } /** * copy a file to destination path ... * * @param {string} source source file path ... * @param {string} dest dest folder path ... * @returns {Promise} action done or not ... */ function copyFile( source = '', dest = '' ) { return new Promise((resolve) => { // if ( !isFileExists(source) || !isDirectoryExists(dest) ) { resolve(false); return; } // const destFilePath = Path.join(dest, Path.basename(source)); fs.copyFile(source, destFilePath, (err) => { // if (err) { resolve(false); return; } // resolve(true); }); }); } /** * reading specified file content ... * * @param {string} path a file path ... * @returns {Promise} file content ... */ function readFile(path = '') { return new Promise((resolve) => { // if (!isFileExists(path)) { resolve(''); return; } // fs.readFile(path, 'utf8', (err, content) => { // if (err) { resolve(undefined); return; } // resolve(content); }); }); } /** * write content to a file ... * * @param {string} path a file path ... * @param {string} content the content which going to write to the file ... * @param {bool} overwrite determines file overwrite if exists ... * @returns {Promise} action done or not ... */ function writeFile( path = '', content = '', overwrite = true ) { return new Promise((resolve) => { // if (isFileExists(path) && !overwrite) { // resolve(false); return; } // // Normalize Content ... content = XValueTools.isValidArg(content) ? content : ''; // fs.writeFile(path, content, (err) => { // if (err) { // resolve(false); return; } // resolve(true); }); }); } /** * create a file ... * * @param {string} path file path ... * @param {string} fileName file name ... * @returns {Promise} action done or not ... */ function createFile( path = '', fileName = '' ) { return new Promise((resolve) => { // const filePath = Path.join(path, fileName); if ( isFileExists(filePath) || !XValueTools.isValidArg(path) || !XValueTools.isValidArg(fileName) ) { // resolve(false); return; } // fs.writeFile(filePath, '', (err) => { // if (err) { // resolve(false); return; } // resolve(true); }); }); } /** * remove a file name extension ... * * @param {string} name * @returns {string} name without extension ... */ function removeFileExtension(name = '') { return name.substring(0, name.lastIndexOf('.')) || name; } /** * retrieve a file extension ... * * @param {string} path a path which locate a file ... * @returns {string} */ function getFileExtension(path = '') { // let result = ""; // // Validate Arg ... if ( !XValueTools.isValidArg(path) || !isFileExists(path) ) { return result; } // // Retrieve just file name ... const fileName = basename(path); result = fileName.replace( removeFileExtension(fileName), "" ); // return result; } /** * retrieve all files list recursively from specific path ... * * @param {string} path a source folder path ... * @param {string[]} extensions which file extensions need to be listed, live empty for all files ... * @returns {Promise} */ async function getRecursiveFilesList( path = "", extensions = [] ) { // let result = []; // // Validate Args ... if ( !XValueTools.isValidArg(path) || !isDirectoryExists(path) ) { return result; } // const contents = await getDirectoryContents(path); for (const item of contents) { // const itemPath = joinPath( path, item ); // const isItemFile = isFileExists(itemPath); if (isItemFile) { // const itemFileExtension = getFileExtension(itemPath); const isFileInSupportedExtensions = extensions === undefined || extensions.length === 0 ? true : extensions.includes(itemFileExtension) ; if (isFileInSupportedExtensions) { result.push(itemPath); } } else if (isDirectoryExists(itemPath)) { // const itemPathFiles = await getRecursiveFilesList(itemPath, extensions); result.push(...itemPathFiles); } } // return result; } /** * Extract Specific files from a folder and it's content ... * * @param {string} path Folder Path ... * @returns */ async function extractFiles(path = "", ext = [], excludeWorkspaceFolders = []) { // const result = []; // if (!ext || ext.length == 0) { return result; } // const pathContent = await getDirectoryContents(path); if (!pathContent || pathContent.length == 0) { return result; } // // Loop through Content ... for (const c of pathContent) { // // Prepare full path ... const cPath = joinPath(path, c); // // check content path is file or not ... const isCFile = isFileExists(cPath); const isCDirectory = isDirectoryExists(cPath); if (isCFile) { // // Check it is MQL file or not ... const cExt = getFileExtension(cPath); if (ext.includes(cExt)) { result.push(cPath); } } else if (isCDirectory) { // const destFolderName = basename(cPath); const isExcluded = excludeWorkspaceFolders.includes(destFolderName); if (isExcluded) { continue; } // const cFiles = await extractFiles(cPath, ext); if (cFiles && cFiles.length > 0) { result.push(...cFiles); } } } // return result; } //#endregion // //#region Directory ... /** * create a directory ... * * @param {string} path destination path including dir name ... * @param {boolean} recursive create directories recursively ... * @returns action done or not ... */ function createDirectory( path = '', recursive = true ) { // let result = false; // if ( isDirectoryExists(path) || !XValueTools.isValidArg(path) ) { return false; } // try { // fs.mkdirSync(path, { recursive: recursive }); result = true; return result; } catch { return false; } } /** * remove a directory ... * * @param {string} path destination path including dir name ... * @param {boolean} recursive removes directories recursively ... * @returns {Promise} action done or not ... */ function removeDirectory( path = '', recursive = false ) { return new Promise((resolve) => { // if (!isDirectoryExists(path)) { resolve(false); return; } // fs.rm(path, { recursive }, (err) => { // if (err) { resolve(false); return; } // resolve(true); }); }); } /** * determines a path destination is a directory or not ... * * @param {string} path a folder path ... * @returns represent destnation path is Directory or not ... */ function isDirectoryExists(path = '') { // if (!XValueTools.isValidArg(path)) { return false; } // try { // const isExists = fs.existsSync(path); if (!isExists) { return false; } // const stat = getStatus(path); if (!stat) { return false; } // const result = stat.isDirectory(); return result; } catch { return false; } } /** * retrieve a directory content ... * * @param {string} path a folder path ... * @returns {Promise} a collection of folder files ... */ function getDirectoryContents(path = '') { return new Promise((resolve) => { // if (!isDirectoryExists(path)) { resolve([]); return; } // fs.readdir(path, (err, content) => { // if (err) { resolve([]); return; } // resolve(content); }); }); } /** * retrieve a directory files ... * * @param {string} path a folder path ... * @returns {Promise} a collection of folder files ... */ function getDirectoryFiles( path = '', containsHiddenFiles = false ) { return new Promise((resolve) => { // if (!isDirectoryExists(path)) { resolve([]); return; } // fs.readdir(path, (err, content) => { // if (err) { resolve([]); return; } // if (!containsHiddenFiles) { content = content.filter(c => !c.startsWith('.')); } // const result = []; content .forEach(c => { // const cPath = Path.join(path, c); if (isFileExists(cPath)) { result.push(c); } }); // resolve(result); }); }); } /** * retrieve a directory folders ... * * @param {string} path a folder path ... * @returns {Promise} a collection of folder names ... */ function getDirectoryFolders(path = '') { return new Promise((resolve) => { // if (!isDirectoryExists(path)) { resolve([]); return; } // fs.readdir(path, (err, content) => { // if (err) { resolve([]); return; } // const result = []; content.forEach(c => { // const cPath = Path.join(path, c); if (isDirectoryExists(cPath)) { result.push(c); } }); // resolve(result); }); }); } /** * copy a folder with all of it's content to dest ... * * @param {string} source source folder path ... * @param {string} dest dest folder path ... * @returns {Promise} action done or not ... */ async function copyFolder( source = '', dest = '' ) { // if ( !isDirectoryExists(source) || !XValueTools.isValidArg(dest) || !XValueTools.isValidArg(source) ) { return false; } // const folderName = Path.basename(source); const destPath = Path.join(dest, folderName); // // Create Dest Path folder if not exists ... if (!isDirectoryExists(destPath)) { // let result = createDirectory(destPath, true); if (!result) { return false; } } // // Files ... const files = await getDirectoryFiles(source); if (files && files.constructor === Array && files.length > 0) { // const filesPromises = files.map(file => copyFile(Path.join(source, file), destPath)); const filesResult = (await Promise.all(filesPromises)).every(r => !!r); if (!filesResult) { return false; } } // // Folders ... const folders = await getDirectoryFolders(source); if (folders && folders.constructor === Array && folders.length > 0) { // const folderPromises = folders.map(folder => copyFolder(Path.join(source, folder), destPath)); const filesResult = (await Promise.all(folderPromises)).every(r => !!r); if (!filesResult) { return false; } } // return true; } //#endregion // //#region Downloader ... /** * download a file from specific url and store it ... * * @param {string} filepath the file name and path which required to put download file on it ... * @param {string} url the web url for downloading ... */ function download(filepath, url) { // // Validate Args ... if ( !XValueTools.isValidArg(url) || !XValueTools.isValidURL(url) || !XValueTools.isValidArg(filepath) ) { return; } // var file = fs.createWriteStream(filepath); // if (url.startsWith('https:')) { https.get(url, function (response) { response.pipe(file); }); } else if (url.startsWith('http:')) { http.get(url, function (response) { response.pipe(file); }); } } //#endregion // //#region JSON ... /** * read and parse a JSON content from a file ... * * @param {string} path source file path ... * @returns {any} */ function readJSON(path = "") { // // Validate Args ... if (!isFileExists(path)) { return undefined; } // let result = undefined; try { result = require(path); } catch { result = undefined; } // return result; } /** * write a JSON Object content into a file ... * * @param {string} path dest file path ... * @param {any} content an object which required to write to file ... * @returns {Promise} */ async function writeJSON( path = "", content = undefined ) { // let result = false; // // Validate Args ... if (!XValueTools.isValidArg(path)) { return result; } // // Normallize Content ... if (content === undefined) { content = {}; } // const contentString = XValueTools.beautifyJSON(content); // result = await writeFile( path, contentString, true ); // return result; } //#endregion //#endregion // //#region Module Exports ... module.exports = { // CurrentDir, PathSeparator, // getStatus, getHomePath, // basename, joinPath, resolvePath, // download, // readJSON, writeJSON, // copyFile, readFile, writeFile, createFile, removeFile, isFileExists, getFileExtension, removeFileExtension, getRecursiveFilesList, extractFiles, // copyFolder, createDirectory, removeDirectory, isDirectoryExists, getDirectoryFiles, getDirectoryFolders, getDirectoryContents, }; //#endregion