/** * @author Martin Karkowski * @email m.karkowski@zema.de * @create date 2020-11-06 08:53:03 * @modify date 2021-11-11 11:17:29 * @desc [description] */ import { exists as __exists, lstat, ObjectEncodingOptions } from "fs"; import { mkdir, readdir, rmdir, unlink, writeFile } from "fs/promises"; import { type } from "os"; import { join } from "path"; import { promisify } from "util"; export const exists = promisify(__exists); const _lstat = promisify(lstat); // Based on the OS select the Path Element. export const FOLDER_SPLIT = type() === "Linux" ? "/" : "\\"; /** * Function to create a File * @param fileName Read the File. * @param content content which should be stored * @param options The options to write the file. See original docu: https://nodejs.org/dist/latest-v8.x/docs/api/fs.html#fs_fs_writefile_file_data_options_callback */ export async function createFile( fileName: string, content: string, options?: | (ObjectEncodingOptions & { mode?: string | number; flag?: string | number; }) | "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex" ): Promise { // Adapt the File Pathes fileName = type() === "Linux" ? fileName.replace(/\\\\/g, "/") : fileName.replace(/\//g, "\\"); // Split the Path into different segements. const pathParts = fileName.split(FOLDER_SPLIT); // Pop the File. pathParts.pop(); // Create the Path / Directories await createPath(pathParts.join(FOLDER_SPLIT)); // Wirte the File. await writeFile(fileName, content, options); return fileName; } /** * Function to create a File * @param path Read the File. * @param content content which should be stored * @param options The options to write the file. See original docu: https://nodejs.org/dist/latest-v8.x/docs/api/fs.html#fs_fs_writefile_file_data_options_callback */ export async function createPath(path: string) { await mkdir(path, { recursive: true }); return path; } export async function deletePath(_dir_path: string): Promise { if (!(await exists(_dir_path))) { throw new URIError("path doesnt exits."); } const _totalPath = _dir_path; /** Sort the Pathes according to their length. For instance: * _pathes = ['C:\\Test\\Sub', 'C:\\Test\\Sub\\SubSub'] * * => After Sorting : * _pathes = ['C:\\Test\\Sub\\SubSub', 'C:\\Test\\Sub'] * * This garantuees to delete all Sub Folders in a correct sequence. */ const _pathes = (await listFolders(_totalPath)).sort( (a: string, b: string) => { return b.split(FOLDER_SPLIT).length - a.split(FOLDER_SPLIT).length; } ); const _files = await listFiles(_totalPath); /** Delete all Files. */ for (const _file of _files) { await unlink(_file); } /** Delete all Folders. */ for (const _path of _pathes) { await rmdir(_path); } await rmdir(_dir_path); } /** * Creates a relative Path based on the Folder where * 'node ...' was typed. * @param _dirPath the path to Check * @param _currentPath the current Path. */ export function relativePath( _dirPath: string, _currentPath = process.cwd() ): string { return join(_currentPath, _dirPath); } /** * Returns a List of File-Names. * * @export * @param {string} _dir_path Path where the system should look * @param {string} [type=''] specified ending of the File. For Instance '.conf' * @returns {Array} List containing all Files */ export async function listFiles( _dir_path: string, type = "" ): Promise { if (!exists(_dir_path)) { throw new URIError("path doesnt exits."); } const _dirPath = _dir_path; const _files = new Array(); /** Define a Function to Handle the Files. */ const _fileFunc = async function (err, file_name) { if (err) { throw err; } // Check the File Ending. if (file_name.endsWith(type)) { _files.push(file_name); } }; /** Define a Function to Handle the Dirs => Recursive call. */ const _dirFunc = async function (err, _path) { if (err) { throw err; } else { await _walkRecursive(_path, _fileFunc, _dirFunc); } }; // Function to Filter the Files and add it to the Array. await _walkRecursive(_dirPath, _fileFunc, _dirFunc); // Return the File. return _files; } /** * Lists all Subfolders in the given Path * * @export * @param {string} _dir_path Start path * @returns {Array} Array containing all Pathes to the Subfolders */ export async function listFolders(_dir_path: string): Promise> { if (!(await exists(_dir_path))) { throw new URIError("path doesnt exits."); } const _dirPath = _dir_path; const _pathes = new Array(); /** Define a Function to Handle the Dirs => Recursive call. */ const _dirFunc = async function (err, _path) { if (err) { throw err; } else { _pathes.push(_path); await _walkRecursive( _path, async () => { // no callback }, _dirFunc ); } }; // Function to Filter the Files and add it to the Array. await _walkRecursive( _dirPath, async () => { // no callback }, _dirFunc ); // Return the File. return _pathes; } /** * Internal Function to walk through a directory and * call different functions on a found subdir or file. * * @param {string} dir_path start path * @param {(err, data) => void} filecallback function which is called on a file * @param {(err, data) => void} foldercallback function which is called on a folder */ async function _walkRecursive( dir_path: string, filecallback: (err, data) => Promise, foldercallback: (err, data) => Promise ) { for (const name of await readdir(dir_path)) { // Create the FilePath const filePath = join(dir_path, name); // Determine the Type const stat = await _lstat(filePath); if (stat.isFile()) { // It is a File => Store it. await filecallback(null, filePath); } else if (stat.isDirectory()) { // It is a Directory. await foldercallback(null, filePath); } } }