From b77a30ff9e34d889a03ab2e6c814ffffcd17ab5a Mon Sep 17 00:00:00 2001 From: amgstrider Date: Sun, 4 May 2025 19:03:04 +0400 Subject: [PATCH 01/16] Feat: greeting and farewel messages --- common/colors.js | 15 +++++++++++++++ package.json | 3 ++- src/index.js | 30 +++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 common/colors.js diff --git a/common/colors.js b/common/colors.js new file mode 100644 index 0000000..873e8fe --- /dev/null +++ b/common/colors.js @@ -0,0 +1,15 @@ +const COLORS = { + RED: '\x1b[31m', + GREEN: '\x1b[32m', + YELLOW: '\x1b[33m', + BLUE: '\x1b[34m', + MAGENTA: '\x1b[35m', + CYAN: '\x1b[36m', + WHITE: '\x1b[37m', + RESET: '\x1b[0m', +}; + +export default function logColoredMessage(message, color = 'white') { + const currentColor = COLORS[color.toUpperCase()] ?? COLORS.WHITE; + console.log(`${currentColor}${message}${COLORS.RESET}\n`) +}; \ No newline at end of file diff --git a/package.json b/package.json index 1a81b81..e581595 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node src/index.js -- --username=your_username" }, "repository": { "type": "git", diff --git a/src/index.js b/src/index.js index 2934828..aebfe38 100644 --- a/src/index.js +++ b/src/index.js @@ -1 +1,29 @@ -console.log(1) \ No newline at end of file +import logColoredMessage from "../../node-nodejs-basics/src/common/colors.js"; + + +const fileManager = async () => { + const argsArray = (process.argv).slice(2); + const userName = argsArray.find((arg) => arg.startsWith('--username'))?.split('=')[1] || 'guest'; + logColoredMessage(`Welcome to the File Manager, ${userName}!`, 'magenta'); + + process.stdin.on('data', (chunk) => { + const command = chunk.toString().trim(); + + if(command === '.exit') { + process.exit(); + } + }) + + + + process.on('SIGINT', () => { + process.exit(); + }); + + process.on('exit', () => { + logColoredMessage(`Thank you for using File Manager, ${userName}, goodbye!`, 'magenta'); + }); + +}; + +await fileManager(); \ No newline at end of file From 26b050aa3965c1e2858498232d8755cf392c09d0 Mon Sep 17 00:00:00 2001 From: amgstrider Date: Sun, 4 May 2025 21:16:31 +0400 Subject: [PATCH 02/16] feat: to upper directory --- package.json | 1 + src/index.js | 27 ++++++++++++++++++++++----- utils/to-upper-directory.js | 13 +++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 utils/to-upper-directory.js diff --git a/package.json b/package.json index e581595..d791bdc 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "", "main": "index.js", + "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node src/index.js -- --username=your_username" diff --git a/src/index.js b/src/index.js index aebfe38..047fa72 100644 --- a/src/index.js +++ b/src/index.js @@ -1,17 +1,34 @@ import logColoredMessage from "../../node-nodejs-basics/src/common/colors.js"; - +import os from "os"; +import toUpperDirectory from "../utils/to-upper-directory.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); const userName = argsArray.find((arg) => arg.startsWith('--username'))?.split('=')[1] || 'guest'; + const homeDir = os.homedir() + let currentDir = homeDir; logColoredMessage(`Welcome to the File Manager, ${userName}!`, 'magenta'); + logColoredMessage(`You are currently in ${currentDir}`, 'green'); process.stdin.on('data', (chunk) => { - const command = chunk.toString().trim(); - - if(command === '.exit') { - process.exit(); + const input = chunk.toString().trim().split(' '); + const command = input[0]; + const options = input.slice(1); + + switch (command) { + case ('up'): + if (currentDir === homeDir) { + logColoredMessage(`\nAlready in home directory: ${currentDir}`, 'red'); + } else { + currentDir = toUpperDirectory(currentDir); + } + break; + case ('.exit'): + process.exit(); + default: + logColoredMessage(`Invalid input`, 'red'); } + logColoredMessage(`\nYou are currently in ${currentDir}`, 'green'); }) diff --git a/utils/to-upper-directory.js b/utils/to-upper-directory.js new file mode 100644 index 0000000..79ecea9 --- /dev/null +++ b/utils/to-upper-directory.js @@ -0,0 +1,13 @@ +import path from 'path'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; + +export default function toUpperDirectory(currentDirectory) { + try { + const newDirectory = currentDirectory.split(path.sep).slice(0, -1).join(path.sep); + return newDirectory; + } catch { + logColoredMessage('Operation failed', 'red'); + return currentDirectory; + } + +} \ No newline at end of file From 7d930e23c5961498aa6e9940b1492b23cc1a771c Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 20:24:31 +0400 Subject: [PATCH 03/16] feat: change directory --- src/index.js | 12 +++++++++--- utils/change-directory.js | 26 ++++++++++++++++++++++++++ utils/is-directory.js | 14 ++++++++++++++ utils/to-upper-directory.js | 1 + 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 utils/change-directory.js create mode 100644 utils/is-directory.js diff --git a/src/index.js b/src/index.js index 047fa72..1ce7d0b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import logColoredMessage from "../../node-nodejs-basics/src/common/colors.js"; import os from "os"; import toUpperDirectory from "../utils/to-upper-directory.js"; +import { changeDirectory } from "../utils/change-directory.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -10,12 +11,14 @@ const fileManager = async () => { logColoredMessage(`Welcome to the File Manager, ${userName}!`, 'magenta'); logColoredMessage(`You are currently in ${currentDir}`, 'green'); - process.stdin.on('data', (chunk) => { + process.stdin.on('data', async (chunk) => { const input = chunk.toString().trim().split(' '); const command = input[0]; const options = input.slice(1); switch (command) { + case ('.exit'): + process.exit(); case ('up'): if (currentDir === homeDir) { logColoredMessage(`\nAlready in home directory: ${currentDir}`, 'red'); @@ -23,8 +26,11 @@ const fileManager = async () => { currentDir = toUpperDirectory(currentDir); } break; - case ('.exit'): - process.exit(); + case ('cd'): + if (options[0]) { + currentDir = await changeDirectory(currentDir, options[0]); + break; + } default: logColoredMessage(`Invalid input`, 'red'); } diff --git a/utils/change-directory.js b/utils/change-directory.js new file mode 100644 index 0000000..d1f0593 --- /dev/null +++ b/utils/change-directory.js @@ -0,0 +1,26 @@ +import path from 'path'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import { isDirectory } from './is-directory.js'; + +export async function changeDirectory(currentDirectory, destinationDirectory) { + const relativePath = path.join(currentDirectory, destinationDirectory); + + try { + const isRelativePath = await isDirectory(relativePath); + const isAbsolutePath = await isDirectory(destinationDirectory); + + if (isRelativePath) { + return relativePath; + } + + if (isAbsolutePath) { + return destinationDirectory; + } else { + throw new Error("Path doesn't exist"); + } + } catch (err) { + logColoredMessage(err, 'red'); + logColoredMessage('Operation failed', 'red'); + return currentDirectory; + } +} \ No newline at end of file diff --git a/utils/is-directory.js b/utils/is-directory.js new file mode 100644 index 0000000..2b82a31 --- /dev/null +++ b/utils/is-directory.js @@ -0,0 +1,14 @@ +import fs from 'fs'; + +export async function isDirectory(pathToCheck) { + try { + const pathStat = await fs.promises.stat(pathToCheck); + if(pathStat.isDirectory()) { + return true; + } else { + return false; + } + } catch { + return false; + } +} \ No newline at end of file diff --git a/utils/to-upper-directory.js b/utils/to-upper-directory.js index 79ecea9..f4cb50d 100644 --- a/utils/to-upper-directory.js +++ b/utils/to-upper-directory.js @@ -6,6 +6,7 @@ export default function toUpperDirectory(currentDirectory) { const newDirectory = currentDirectory.split(path.sep).slice(0, -1).join(path.sep); return newDirectory; } catch { + logColoredMessage(err, 'red'); logColoredMessage('Operation failed', 'red'); return currentDirectory; } From 0251b7d6cd9d25be199fcc5e1c9c6407433059dd Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 21:17:35 +0400 Subject: [PATCH 04/16] feat: list --- src/index.js | 13 ++++++++++--- utils/is-file.js | 14 +++++++++++++ utils/list.js | 39 +++++++++++++++++++++++++++++++++++++ utils/to-upper-directory.js | 2 +- 4 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 utils/is-file.js create mode 100644 utils/list.js diff --git a/src/index.js b/src/index.js index 1ce7d0b..dec0252 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ import logColoredMessage from "../../node-nodejs-basics/src/common/colors.js"; import os from "os"; import toUpperDirectory from "../utils/to-upper-directory.js"; import { changeDirectory } from "../utils/change-directory.js"; +import list from "../utils/list.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -17,8 +18,7 @@ const fileManager = async () => { const options = input.slice(1); switch (command) { - case ('.exit'): - process.exit(); + case ('up'): if (currentDir === homeDir) { logColoredMessage(`\nAlready in home directory: ${currentDir}`, 'red'); @@ -29,8 +29,15 @@ const fileManager = async () => { case ('cd'): if (options[0]) { currentDir = await changeDirectory(currentDir, options[0]); - break; + } else { + logColoredMessage(`Invalid input`, 'red'); } + break; + case ('ls'): + await list(currentDir); + break; + case ('.exit'): + process.exit(); default: logColoredMessage(`Invalid input`, 'red'); } diff --git a/utils/is-file.js b/utils/is-file.js new file mode 100644 index 0000000..e15a847 --- /dev/null +++ b/utils/is-file.js @@ -0,0 +1,14 @@ +import fs from 'fs'; + +export async function isFile(pathToCheck) { + try { + const pathStat = await fs.promises.stat(pathToCheck); + if(pathStat.isFile()) { + return true; + } else { + return false; + } + } catch { + return false; + } +} \ No newline at end of file diff --git a/utils/list.js b/utils/list.js new file mode 100644 index 0000000..3f2395c --- /dev/null +++ b/utils/list.js @@ -0,0 +1,39 @@ +import fs from 'fs'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import { isDirectory } from './is-directory.js'; +import { isFile } from './is-file.js'; + +function sortByName(a, b) { + return a.Name.localeCompare(b.Name); +} + +export default async function list(currentDirectory) { + try { + const contents = await fs.promises.readdir(currentDirectory); + + const directories = []; + const files = []; + + for (const content of contents) { + const contentPath = `${currentDirectory}/${content}`; + if (await isDirectory(contentPath)) { + directories.push({ Name: content, Type: 'directory' }); + } + + if (await isFile(contentPath)) { + files.push({ Name: content, Type: 'file' }); + } + } + + directories.sort(sortByName); + files.sort(sortByName); + + const allContents = directories.concat(files); + + console.table(allContents); + + } catch (err) { + logColoredMessage(err, 'red'); + logColoredMessage('Operation failed', 'red'); + } +} \ No newline at end of file diff --git a/utils/to-upper-directory.js b/utils/to-upper-directory.js index f4cb50d..aa23fb0 100644 --- a/utils/to-upper-directory.js +++ b/utils/to-upper-directory.js @@ -5,7 +5,7 @@ export default function toUpperDirectory(currentDirectory) { try { const newDirectory = currentDirectory.split(path.sep).slice(0, -1).join(path.sep); return newDirectory; - } catch { + } catch (err) { logColoredMessage(err, 'red'); logColoredMessage('Operation failed', 'red'); return currentDirectory; From 92fd506c076e646ad104b46e85cd9fbbb94eeb24 Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 21:19:35 +0400 Subject: [PATCH 05/16] refactor: toUpperDirectory --- utils/to-upper-directory.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utils/to-upper-directory.js b/utils/to-upper-directory.js index aa23fb0..615e140 100644 --- a/utils/to-upper-directory.js +++ b/utils/to-upper-directory.js @@ -3,8 +3,12 @@ import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; export default function toUpperDirectory(currentDirectory) { try { - const newDirectory = currentDirectory.split(path.sep).slice(0, -1).join(path.sep); - return newDirectory; + const directoriesArray = currentDirectory.split(path.sep); + if (directoriesArray.length === 1) { + return currentDirectory; + } + const newDirectory = directoriesArray.slice(0, -1).join(path.sep); + return newDirectory; } catch (err) { logColoredMessage(err, 'red'); logColoredMessage('Operation failed', 'red'); From 3abf9eabce808c8dba5ed61e0050af100db2f3d6 Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 21:30:26 +0400 Subject: [PATCH 06/16] feat: cat --- src/index.js | 8 ++++++++ utils/showFileContent.js | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 utils/showFileContent.js diff --git a/src/index.js b/src/index.js index dec0252..aa8cab1 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,7 @@ import os from "os"; import toUpperDirectory from "../utils/to-upper-directory.js"; import { changeDirectory } from "../utils/change-directory.js"; import list from "../utils/list.js"; +import showFileContent from "../utils/showFileContent.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -36,6 +37,13 @@ const fileManager = async () => { case ('ls'): await list(currentDir); break; + case ('cat'): + if (options[0]) { + await showFileContent(currentDir, options[0]); + } else { + logColoredMessage(`Invalid input`, 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/showFileContent.js b/utils/showFileContent.js new file mode 100644 index 0000000..83d810b --- /dev/null +++ b/utils/showFileContent.js @@ -0,0 +1,40 @@ + + +import path from 'path'; +import fs from 'fs'; +import logColoredMessage from "../../node-nodejs-basics/src/common/colors.js"; +import { isFile } from './is-file.js'; + +export default async function showFileContent(currentPath, targetPath) { + const filePath = path.resolve(currentPath, targetPath); + const notFile = !(await isFile(filePath)); + + if (notFile) { + logColoredMessage(`${targetPath} is not a file`, 'red'); + logColoredMessage(`Invalid input`, 'red'); + return; + } + try { + const readable = fs.createReadStream(filePath, 'utf-8'); + const fileContentPromise = new Promise((resolve, reject) => { + let fileContent = ''; + + readable.on('data', (chunk) => { + fileContent += chunk; + }); + + readable.on('end', () => { + resolve(fileContent); + }); + + readable.on('error', (error) => { + reject(error); + }); + }); + + const fileContent = await fileContentPromise; + logColoredMessage(fileContent, 'yellow'); + } catch { + logColoredMessage(`Invalid input`, 'red'); + } +} \ No newline at end of file From 8db40b3ba6bd6226df4d6172b5f0f7b73964d13e Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 21:32:57 +0400 Subject: [PATCH 07/16] feat: add --- src/index.js | 8 ++++++++ utils/createFile.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 utils/createFile.js diff --git a/src/index.js b/src/index.js index aa8cab1..ca96408 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,7 @@ import toUpperDirectory from "../utils/to-upper-directory.js"; import { changeDirectory } from "../utils/change-directory.js"; import list from "../utils/list.js"; import showFileContent from "../utils/showFileContent.js"; +import createFile from "../utils/createFile.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -44,6 +45,13 @@ const fileManager = async () => { logColoredMessage(`Invalid input`, 'red'); } break; + case ('add'): + if (options[0]) { + await createFile(currentDir, options[0]); + } else { + logColoredMessage(`Invalid input`, 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/createFile.js b/utils/createFile.js new file mode 100644 index 0000000..614b6e7 --- /dev/null +++ b/utils/createFile.js @@ -0,0 +1,15 @@ +import path from 'path'; +import fs from 'fs'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; + + +export default async function createFile(currentPath, fileName) { + const filePath = path.resolve(currentPath, fileName); + + try { + await fs.promises.writeFile(filePath, '', { flag: 'wx' }); + logColoredMessage(`File ${fileName} created`, 'yellow'); + } catch (err) { + logColoredMessage(`Invalid input`, 'red'); + } +} \ No newline at end of file From 8d582ac5bf5dddcf934c4bd41d0a33ae732d1c6b Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 21:43:45 +0400 Subject: [PATCH 08/16] feat: mkdir --- src/index.js | 8 ++++++++ utils/createFolder.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 utils/createFolder.js diff --git a/src/index.js b/src/index.js index ca96408..6e88f67 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ import { changeDirectory } from "../utils/change-directory.js"; import list from "../utils/list.js"; import showFileContent from "../utils/showFileContent.js"; import createFile from "../utils/createFile.js"; +import createFolder from "../utils/createFolder.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -52,6 +53,13 @@ const fileManager = async () => { logColoredMessage(`Invalid input`, 'red'); } break; + case ('mkdir'): + if (options[0]) { + await createFolder(currentDir, options[0]); + } else { + logColoredMessage(`Invalid input`, 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/createFolder.js b/utils/createFolder.js new file mode 100644 index 0000000..1a36d69 --- /dev/null +++ b/utils/createFolder.js @@ -0,0 +1,15 @@ +import path from 'path'; +import fs from 'fs'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; + + +export default async function createFolder(currentPath, folderName) { + const folderPath = path.resolve(currentPath, folderName); + + try { + await fs.promises.mkdir(folderPath); + logColoredMessage(`Folder ${folderPath} created`, 'yellow'); + } catch (err) { + logColoredMessage(`Invalid input`, 'red'); + } +} \ No newline at end of file From 8914c4195a795aa0bad8c9497c12322f58c8dfed Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 21:48:29 +0400 Subject: [PATCH 09/16] feat: rename file --- src/index.js | 8 ++++++++ utils/renameFile.js | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 utils/renameFile.js diff --git a/src/index.js b/src/index.js index 6e88f67..3b47d94 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ import list from "../utils/list.js"; import showFileContent from "../utils/showFileContent.js"; import createFile from "../utils/createFile.js"; import createFolder from "../utils/createFolder.js"; +import renameFile from "../utils/renameFile.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -60,6 +61,13 @@ const fileManager = async () => { logColoredMessage(`Invalid input`, 'red'); } break; + case ('rn'): + if (options[0] && options[1]) { + await renameFile(currentDir, options[0], options[1]); + } else { + logColoredMessage(`Invalid input`, 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/renameFile.js b/utils/renameFile.js new file mode 100644 index 0000000..912ef69 --- /dev/null +++ b/utils/renameFile.js @@ -0,0 +1,25 @@ +import fs from 'fs'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import path from 'path'; +import { isFile } from './is-file.js'; + +export default async function renameFile(currentDirectory, pathToFile, newFilename) { + const normalizedPathToFile = path.normalize(pathToFile); + const isPathCorrect = await isFile(normalizedPathToFile); + let pathToFileResolved = path.resolve(currentDirectory, pathToFile); + + if (isPathCorrect) { + pathToFileResolved = pathToFile; + } + + const parsedPath = path.parse(pathToFileResolved); + parsedPath.base = newFilename; + const pathToRenamedFile = path.format(parsedPath); + + try { + await fs.promises.rename(pathToFileResolved, pathToRenamedFile); + logColoredMessage(`File ${pathToFile} renamed to ${newFilename}`, 'yellow') + } catch (err) { + logColoredMessage(`Invalid input`, 'red'); + } +} \ No newline at end of file From 2b4f6c53519ad1939303450ebf51134e1e04751d Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 22:03:50 +0400 Subject: [PATCH 10/16] feat: copy file --- src/index.js | 8 ++++++++ utils/copyFile.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 utils/copyFile.js diff --git a/src/index.js b/src/index.js index 3b47d94..49fd19f 100644 --- a/src/index.js +++ b/src/index.js @@ -7,6 +7,7 @@ import showFileContent from "../utils/showFileContent.js"; import createFile from "../utils/createFile.js"; import createFolder from "../utils/createFolder.js"; import renameFile from "../utils/renameFile.js"; +import copyFile from "../utils/copyFile.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -68,6 +69,13 @@ const fileManager = async () => { logColoredMessage(`Invalid input`, 'red'); } break; + case ('cp'): + if (options[0] && options[1]) { + await copyFile(currentDir, options[0], options[1]); + } else { + logColoredMessage(`Invalid input`, 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/copyFile.js b/utils/copyFile.js new file mode 100644 index 0000000..b250abb --- /dev/null +++ b/utils/copyFile.js @@ -0,0 +1,49 @@ + +import path from 'path'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import fs from 'fs'; +import { isFile } from './is-file.js'; +import { isDirectory } from './is-directory.js'; + + +export default async function copyFile(currentDirectory, pathToFile, destinationDirectory) { + try { + const normalizedFilePath = path.normalize(pathToFile); + + let resolvedPathToFile = path.resolve(currentDirectory, normalizedFilePath); + if (await isFile(normalizedFilePath)) { + resolvedPathToFile = normalizedFilePath; + } + + + const normalizedDirectoryPath = path.normalize(destinationDirectory); + let resolvedPathToDirectory = path.resolve(currentDirectory, normalizedDirectoryPath); + if (await isDirectory(normalizedDirectoryPath)) { + resolvedPathToDirectory = normalizedDirectoryPath; + } + const parsedFilePath = path.parse(resolvedPathToFile); + const destinationFilePath = path.resolve(resolvedPathToDirectory, parsedFilePath.base); + + const isOriginalFileExist = await isFile(resolvedPathToFile); + const isDirectoryExist = await isDirectory(resolvedPathToDirectory); + const isDestinationFileExist = await isFile(destinationFilePath); + if (!isOriginalFileExist || !isDirectoryExist || isDestinationFileExist) { + logColoredMessage(`Invalid input`, 'red'); + return; + } + + const readStream = fs.createReadStream(resolvedPathToFile); + const writeStream = fs.createWriteStream(destinationFilePath); + readStream.pipe(writeStream); + const copyPromise = new Promise((resolve, reject) => { + readStream.on('end', () => { + resolve(); + }) + }); + + await copyPromise; + logColoredMessage(`File ${resolvedPathToFile} copied to ${resolvedPathToDirectory}`, 'yellow'); + } catch (err) { + logColoredMessage(`Invalid input`, 'red'); + } +} \ No newline at end of file From 323bde8b849055f4f63eeab215baeb6bb6666f6c Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 22:08:32 +0400 Subject: [PATCH 11/16] feat: move file --- src/index.js | 7 +++++++ utils/copyFile.js | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 49fd19f..8f3ef47 100644 --- a/src/index.js +++ b/src/index.js @@ -76,6 +76,13 @@ const fileManager = async () => { logColoredMessage(`Invalid input`, 'red'); } break; + case ('mv'): + if (options[0] && options[1]) { + await copyFile(currentDir, options[0], options[1], { deleteSource: true }); + } else { + logColoredMessage(`Invalid input`, 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/copyFile.js b/utils/copyFile.js index b250abb..030e4f4 100644 --- a/utils/copyFile.js +++ b/utils/copyFile.js @@ -6,10 +6,9 @@ import { isFile } from './is-file.js'; import { isDirectory } from './is-directory.js'; -export default async function copyFile(currentDirectory, pathToFile, destinationDirectory) { +export default async function copyFile(currentDirectory, pathToFile, destinationDirectory, options = { deleteSource: false }) { try { const normalizedFilePath = path.normalize(pathToFile); - let resolvedPathToFile = path.resolve(currentDirectory, normalizedFilePath); if (await isFile(normalizedFilePath)) { resolvedPathToFile = normalizedFilePath; @@ -42,6 +41,9 @@ export default async function copyFile(currentDirectory, pathToFile, destination }); await copyPromise; + if (options.deleteSource) { + fs.promises.unlink(resolvedPathToFile); + } logColoredMessage(`File ${resolvedPathToFile} copied to ${resolvedPathToDirectory}`, 'yellow'); } catch (err) { logColoredMessage(`Invalid input`, 'red'); From ffdec9d066bb217232c683ae6cebca2a3f66e2d6 Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 22:10:20 +0400 Subject: [PATCH 12/16] feat: remove file --- src/index.js | 8 ++++++++ utils/removeFile.js | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 utils/removeFile.js diff --git a/src/index.js b/src/index.js index 8f3ef47..ee7aa2d 100644 --- a/src/index.js +++ b/src/index.js @@ -8,6 +8,7 @@ import createFile from "../utils/createFile.js"; import createFolder from "../utils/createFolder.js"; import renameFile from "../utils/renameFile.js"; import copyFile from "../utils/copyFile.js"; +import removeFile from "../utils/removeFile.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -83,6 +84,13 @@ const fileManager = async () => { logColoredMessage(`Invalid input`, 'red'); } break; + case ('rm'): + if (options[0]) { + await removeFile(currentDir, options[0]); + } else { + logColoredMessage(`Invalid input`, 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/removeFile.js b/utils/removeFile.js new file mode 100644 index 0000000..8a7d550 --- /dev/null +++ b/utils/removeFile.js @@ -0,0 +1,20 @@ + +import path from 'path'; +import fs from 'fs'; +import logColoredMessage from "../../node-nodejs-basics/src/common/colors.js"; +import { isFile } from './is-file.js'; + +export default async function removeFile(currentDirectory, pathToFile) { + let resolvedPathToFile = path.resolve(currentDirectory, pathToFile); + if (await isFile(pathToFile)) { + resolvedPathToFile = pathToFile; + } + + try { + await fs.promises.unlink(resolvedPathToFile); + logColoredMessage(`File ${pathToFile} removed`, 'yellow'); + } catch { + logColoredMessage('Operation failed', 'red'); + } + +} From f701fc3fd6fcb1f07af6aa65198806834d1d90d9 Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 22:15:18 +0400 Subject: [PATCH 13/16] feat: os commands --- src/index.js | 8 ++++++++ utils/handleOSCommands.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 utils/handleOSCommands.js diff --git a/src/index.js b/src/index.js index ee7aa2d..4638b97 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,7 @@ import createFolder from "../utils/createFolder.js"; import renameFile from "../utils/renameFile.js"; import copyFile from "../utils/copyFile.js"; import removeFile from "../utils/removeFile.js"; +import handleOSCommands from "../utils/handleOSCommands.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -91,6 +92,13 @@ const fileManager = async () => { logColoredMessage(`Invalid input`, 'red'); } break; + case ('os'): + if (options[0] && options[0].startsWith('--')) { + handleOSCommands(options[0]); + } else { + logColoredMessage('Invalid input', 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/handleOSCommands.js b/utils/handleOSCommands.js new file mode 100644 index 0000000..7930f7b --- /dev/null +++ b/utils/handleOSCommands.js @@ -0,0 +1,32 @@ +import os from 'os'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; + +export default function handleOSCommands(arg) { + const command = arg.slice(2); + switch (command) { + case 'EOL': + const eol = os.EOL; + logColoredMessage(`The end of a line in the current OS is: ${JSON.stringify(eol)}`, 'yellow'); + break; + case 'cpus': + const cpus = os.cpus(); + logColoredMessage(`The number of CPUs is: ${cpus.length}`, 'yellow'); + logColoredMessage(`The model of the CPU is: ${cpus[0].model}`, 'yellow'); + logColoredMessage(`The clock rate of the CPU is: ${(cpus[0].speed/1000).toFixed(2)} GHz`, 'yellow'); + break; + case 'homedir': + const homedir = os.homedir(); + logColoredMessage(`The home directory is: ${homedir}`, 'yellow'); + break; + case 'username': + const username = os.userInfo().username; + logColoredMessage(`The current system username is: ${username}`, 'yellow'); + break; + case 'architecture': + const architecture = os.arch(); + logColoredMessage(`The architecture is: ${architecture}`, 'yellow'); + break; + default: + logColoredMessage('Invalid input', 'red'); + } +} \ No newline at end of file From a16249f9b7c36638e62fb3d17e58db67bbbcb493 Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 22:20:05 +0400 Subject: [PATCH 14/16] feat: hash --- src/index.js | 8 ++++++++ utils/calculateHash.js | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 utils/calculateHash.js diff --git a/src/index.js b/src/index.js index 4638b97..bf2e86c 100644 --- a/src/index.js +++ b/src/index.js @@ -10,6 +10,7 @@ import renameFile from "../utils/renameFile.js"; import copyFile from "../utils/copyFile.js"; import removeFile from "../utils/removeFile.js"; import handleOSCommands from "../utils/handleOSCommands.js"; +import calculateHash from "../utils/calculateHash.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -99,6 +100,13 @@ const fileManager = async () => { logColoredMessage('Invalid input', 'red'); } break; + case ('hash'): + if (options[0]) { + await calculateHash(currentDir, options[0]); + } else { + logColoredMessage('Invalid input', 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/calculateHash.js b/utils/calculateHash.js new file mode 100644 index 0000000..8313401 --- /dev/null +++ b/utils/calculateHash.js @@ -0,0 +1,41 @@ + +import path from 'path'; +import crypto from 'crypto'; +import fs from 'fs'; +import { isFile } from './is-file.js'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; + + +export default async function calculateHash(currentDirectory, pathToFile) { + try { + + const normalizedFilePath = path.normalize(pathToFile); + let resolvedPathToFile = path.resolve(currentDirectory, normalizedFilePath); + if (await isFile(normalizedFilePath)) { + resolvedPathToFile = normalizedFilePath; + } + + const readStream = fs.createReadStream(resolvedPathToFile); + const hash = crypto.createHash('sha256'); + const hashPromise = new Promise((resolve, reject) => { + readStream.on('data', (chunk) => { + hash.update(chunk); + }); + readStream.on('end', () => { + resolve(hash.digest('hex')); + }); + readStream.on('error', (error) => { + reject(error); + }); + + }); + + const fileHash = await hashPromise; + + logColoredMessage(`File hash is: ${fileHash}`, 'yellow'); + } catch { + logColoredMessage('Invalid input', 'red'); + } + +} + From bb927ea5e0de728e9279fedb15ca043a1b89ab97 Mon Sep 17 00:00:00 2001 From: amgstrider Date: Mon, 5 May 2025 22:27:10 +0400 Subject: [PATCH 15/16] feat: compress decompress --- src/index.js | 31 +++++++++++++++++----- utils/compressFile.js | 59 +++++++++++++++++++++++++++++++++++++++++ utils/decompressFile.js | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 7 deletions(-) create mode 100644 utils/compressFile.js create mode 100644 utils/decompressFile.js diff --git a/src/index.js b/src/index.js index bf2e86c..43f3e47 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,8 @@ import copyFile from "../utils/copyFile.js"; import removeFile from "../utils/removeFile.js"; import handleOSCommands from "../utils/handleOSCommands.js"; import calculateHash from "../utils/calculateHash.js"; +import compressFile from "../utils/compressFile.js"; +import decompressFile from "../utils/decompressFile.js"; const fileManager = async () => { const argsArray = (process.argv).slice(2); @@ -100,13 +102,28 @@ const fileManager = async () => { logColoredMessage('Invalid input', 'red'); } break; - case ('hash'): - if (options[0]) { - await calculateHash(currentDir, options[0]); - } else { - logColoredMessage('Invalid input', 'red'); - } - break; + case ('hash'): + if (options[0]) { + await calculateHash(currentDir, options[0]); + } else { + logColoredMessage('Invalid input', 'red'); + } + break; + case ('compress'): + if (options[0] && options[1]) { + await compressFile(currentDir, options[0], options[1]); + } else { + logColoredMessage(`Invalid input`, 'red'); + } + + break; + case ('decompress'): + if (options[0] && options[1]) { + await decompressFile(currentDir, options[0], options[1]); + } else { + logColoredMessage(`Invalid input`, 'red'); + } + break; case ('.exit'): process.exit(); default: diff --git a/utils/compressFile.js b/utils/compressFile.js new file mode 100644 index 0000000..4c1f73b --- /dev/null +++ b/utils/compressFile.js @@ -0,0 +1,59 @@ +import fs from 'fs'; +import zlib from 'zlib'; +import path from 'path'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import { isDirectory } from './is-directory.js'; +import { isFile } from './is-file.js'; + + +export default async function compressFile(currentDirectory, inputFilePath, destinationPath) { + try { + let resolvedPathToFile = path.resolve(currentDirectory, inputFilePath); + if (await isFile(inputFilePath)) { + resolvedPathToFile = inputFilePath; + } + + let resolvedDestinationPath = path.resolve(currentDirectory, destinationPath); + if (await isDirectory(destinationPath)) { + resolvedDestinationPath = destinationPath; + } + + const resolvedDestinationFile = path.resolve(resolvedDestinationPath, path.basename(resolvedPathToFile) + '.br'); + + if (await isFile(resolvedDestinationFile)) { + logColoredMessage('Invalid input', 'red'); + return; + } + + if (!(await isFile(resolvedPathToFile))) { + logColoredMessage('Invalid input', 'red'); + return; + } + + const readStream = fs.createReadStream(resolvedPathToFile); + const writeStream = fs.createWriteStream(resolvedDestinationFile); + + const brotliStream = zlib.createBrotliCompress(); + + readStream.pipe(brotliStream).pipe(writeStream); + + const fileCompressed = new Promise((resolve, reject) => { + + writeStream.on('finish', () => { + resolve(); + }); + + writeStream.on('error', (error) => { + reject(error); + } + ); + } + ); + + await fileCompressed; + logColoredMessage(`File ${resolvedPathToFile} compressed to ${resolvedDestinationFile}`, 'yellow'); + + } catch (error) { + logColoredMessage('Invalid input', 'red'); + } +} diff --git a/utils/decompressFile.js b/utils/decompressFile.js new file mode 100644 index 0000000..8a463b9 --- /dev/null +++ b/utils/decompressFile.js @@ -0,0 +1,56 @@ +import fs from 'fs'; +import zlib from 'zlib'; +import path from 'path'; +import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import { isFile } from './is-file.js'; +import { isDirectory } from './is-directory.js'; + +export default async function decompressFile(currentDirectory, inputFilePath, destinationPath) { + try { + let resolvedPathToFile = path.resolve(currentDirectory, inputFilePath); + if (await isFile(inputFilePath)) { + resolvedPathToFile = inputFilePath; + } + + let resolvedDestinationPath = path.resolve(currentDirectory, destinationPath); + if (await isDirectory(destinationPath)) { + resolvedDestinationPath = destinationPath; + } + + const resolvedDestinationFile = path.resolve(resolvedDestinationPath, path.basename(resolvedPathToFile).slice(0, -3)); + + if (await isFile(resolvedDestinationFile)) { + logColoredMessage('Invalid input', 'red'); + return; + } + + if (!(await isFile(resolvedPathToFile))) { + logColoredMessage('Invalid input', 'red'); + return; + } + + const readStream = fs.createReadStream(resolvedPathToFile); + const writeStream = fs.createWriteStream(resolvedDestinationFile); + + const brotliStream = zlib.createBrotliDecompress(); + + readStream.pipe(brotliStream).pipe(writeStream); + + const fileCompressed = new Promise((resolve, reject) => { + + writeStream.on('finish', () => { + resolve(); + }); + + writeStream.on('error', () => { + reject(); + }); + }); + + await fileCompressed; + logColoredMessage(`File ${resolvedPathToFile} decompressed to ${resolvedDestinationFile}`, 'yellow'); + + } catch { + logColoredMessage('Invalid input', 'red'); + } +} From a457435af4f7afaeb571e6cb5f53785cd041d85d Mon Sep 17 00:00:00 2001 From: amgstrider Date: Thu, 8 May 2025 17:07:34 +0400 Subject: [PATCH 16/16] fix: import path for colors.js --- src/index.js | 2 +- utils/calculateHash.js | 2 +- utils/change-directory.js | 2 +- utils/compressFile.js | 2 +- utils/copyFile.js | 2 +- utils/createFile.js | 2 +- utils/createFolder.js | 2 +- utils/decompressFile.js | 2 +- utils/handleOSCommands.js | 2 +- utils/list.js | 2 +- utils/removeFile.js | 2 +- utils/renameFile.js | 2 +- utils/showFileContent.js | 2 +- utils/to-upper-directory.js | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/index.js b/src/index.js index 43f3e47..ce7adf6 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import logColoredMessage from "../../node-nodejs-basics/src/common/colors.js"; +import logColoredMessage from "../common/colors.js"; import os from "os"; import toUpperDirectory from "../utils/to-upper-directory.js"; import { changeDirectory } from "../utils/change-directory.js"; diff --git a/utils/calculateHash.js b/utils/calculateHash.js index 8313401..d10e680 100644 --- a/utils/calculateHash.js +++ b/utils/calculateHash.js @@ -3,7 +3,7 @@ import path from 'path'; import crypto from 'crypto'; import fs from 'fs'; import { isFile } from './is-file.js'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; export default async function calculateHash(currentDirectory, pathToFile) { diff --git a/utils/change-directory.js b/utils/change-directory.js index d1f0593..3f29468 100644 --- a/utils/change-directory.js +++ b/utils/change-directory.js @@ -1,5 +1,5 @@ import path from 'path'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; import { isDirectory } from './is-directory.js'; export async function changeDirectory(currentDirectory, destinationDirectory) { diff --git a/utils/compressFile.js b/utils/compressFile.js index 4c1f73b..bad801e 100644 --- a/utils/compressFile.js +++ b/utils/compressFile.js @@ -1,7 +1,7 @@ import fs from 'fs'; import zlib from 'zlib'; import path from 'path'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; import { isDirectory } from './is-directory.js'; import { isFile } from './is-file.js'; diff --git a/utils/copyFile.js b/utils/copyFile.js index 030e4f4..1766743 100644 --- a/utils/copyFile.js +++ b/utils/copyFile.js @@ -1,6 +1,6 @@ import path from 'path'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; import fs from 'fs'; import { isFile } from './is-file.js'; import { isDirectory } from './is-directory.js'; diff --git a/utils/createFile.js b/utils/createFile.js index 614b6e7..ef66e40 100644 --- a/utils/createFile.js +++ b/utils/createFile.js @@ -1,6 +1,6 @@ import path from 'path'; import fs from 'fs'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; export default async function createFile(currentPath, fileName) { diff --git a/utils/createFolder.js b/utils/createFolder.js index 1a36d69..1c87f7e 100644 --- a/utils/createFolder.js +++ b/utils/createFolder.js @@ -1,6 +1,6 @@ import path from 'path'; import fs from 'fs'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; export default async function createFolder(currentPath, folderName) { diff --git a/utils/decompressFile.js b/utils/decompressFile.js index 8a463b9..992bba3 100644 --- a/utils/decompressFile.js +++ b/utils/decompressFile.js @@ -1,7 +1,7 @@ import fs from 'fs'; import zlib from 'zlib'; import path from 'path'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; import { isFile } from './is-file.js'; import { isDirectory } from './is-directory.js'; diff --git a/utils/handleOSCommands.js b/utils/handleOSCommands.js index 7930f7b..d76d343 100644 --- a/utils/handleOSCommands.js +++ b/utils/handleOSCommands.js @@ -1,5 +1,5 @@ import os from 'os'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; export default function handleOSCommands(arg) { const command = arg.slice(2); diff --git a/utils/list.js b/utils/list.js index 3f2395c..4ffb4f2 100644 --- a/utils/list.js +++ b/utils/list.js @@ -1,5 +1,5 @@ import fs from 'fs'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; import { isDirectory } from './is-directory.js'; import { isFile } from './is-file.js'; diff --git a/utils/removeFile.js b/utils/removeFile.js index 8a7d550..d5a5e6b 100644 --- a/utils/removeFile.js +++ b/utils/removeFile.js @@ -1,7 +1,7 @@ import path from 'path'; import fs from 'fs'; -import logColoredMessage from "../../node-nodejs-basics/src/common/colors.js"; +import logColoredMessage from "../common/colors.js"; import { isFile } from './is-file.js'; export default async function removeFile(currentDirectory, pathToFile) { diff --git a/utils/renameFile.js b/utils/renameFile.js index 912ef69..94b7693 100644 --- a/utils/renameFile.js +++ b/utils/renameFile.js @@ -1,5 +1,5 @@ import fs from 'fs'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; import path from 'path'; import { isFile } from './is-file.js'; diff --git a/utils/showFileContent.js b/utils/showFileContent.js index 83d810b..42c27ef 100644 --- a/utils/showFileContent.js +++ b/utils/showFileContent.js @@ -2,7 +2,7 @@ import path from 'path'; import fs from 'fs'; -import logColoredMessage from "../../node-nodejs-basics/src/common/colors.js"; +import logColoredMessage from "../common/colors.js"; import { isFile } from './is-file.js'; export default async function showFileContent(currentPath, targetPath) { diff --git a/utils/to-upper-directory.js b/utils/to-upper-directory.js index 615e140..43d555a 100644 --- a/utils/to-upper-directory.js +++ b/utils/to-upper-directory.js @@ -1,5 +1,5 @@ import path from 'path'; -import logColoredMessage from '../../node-nodejs-basics/src/common/colors.js'; +import logColoredMessage from "../common/colors.js"; export default function toUpperDirectory(currentDirectory) { try {