/** * @author Martin Karkowski * @email m.karkowski@zema.de * @create date 2020-11-06 08:53:03 * @modify date 2020-11-06 08:53:04 * @desc [description] */ import { BaseEncodingOptions, exists as __exists, lstat } 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?: (BaseEncodingOptions & { mode?: string | number; flag?: string | number; }) | "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex") { // 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: string = ''): 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 () => { }, _dirFunc); } }; // Function to Filter the Files and add it to the Array. await _walkRecursive(_dirPath, async () => { }, _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); } } }