diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..755c365b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,17 @@ +{ + "name": "node-nodejs-fundamentals", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "node-nodejs-fundamentals", + "version": "1.0.0", + "license": "ISC", + "engines": { + "node": ">=24.10.0", + "npm": ">=10.9.2" + } + } + } +} diff --git a/src/cli/interactive.js b/src/cli/interactive.js index d0e3e0d9..600d0215 100644 --- a/src/cli/interactive.js +++ b/src/cli/interactive.js @@ -1,8 +1,44 @@ +import readline from "readline"; const interactive = () => { // Write your code here // Use readline module for interactive CLI // Support commands: uptime, cwd, date, exit // Handle Ctrl+C and unknown commands + + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + prompt: "> ", + }); + console.log("Welcome! Type a command"); + rl.prompt(); + + rl.on("line", (line) => { + const command = line.trim(); + + switch (command) { + case "uptime": + console.log(`Uptime: ${process.uptime().toFixed(2)}s`); + break; + case "cwd": + console.log(process.cwd()); + break; + case "date": + console.log(new Date().toISOString()); + break; + case "exit": + rl.close(); + return; + default: + console.log("Unknown command"); + } + + rl.prompt(); + }); + rl.on("close", () => { + console.log("Goodbye!"); + process.exit(0); + }); }; interactive(); diff --git a/src/cli/progress.js b/src/cli/progress.js index 3e060763..a9ff5a35 100644 --- a/src/cli/progress.js +++ b/src/cli/progress.js @@ -3,6 +3,48 @@ const progress = () => { // Simulate progress bar from 0% to 100% over ~5 seconds // Update in place using \r every 100ms // Format: [████████████████████ ] 67% + const args = process.argv; + + const durationIndex = args.indexOf("--duration"); + const duration = + durationIndex !== -1 ? Number(args[durationIndex + 1]) : 5000; + + const intervalIndex = args.indexOf("--interval"); + const interval = intervalIndex !== -1 ? Number(args[intervalIndex + 1]) : 100; + + const lengthlIndex = args.indexOf("--length"); + const length = lengthlIndex !== -1 ? Number(args[lengthlIndex + 1]) : 30; + + const colorIndex = args.indexOf("--color"); + const color = colorIndex !== -1 ? args[colorIndex + 1] : ""; + console.log(color); + + const steps = Math.floor(duration / interval); + + let currentStep = 0; + + const timer = setInterval(() => { + currentStep++; + + const percent = Math.floor((currentStep / steps) * 100); + + const filled = Math.floor((percent / 100) * length); + + const bar = + "[" + + "█".repeat(filled) + + " ".repeat(length - filled) + + "] " + + percent + + "%"; + + process.stdout.write("\r" + bar); + + if (currentStep >= steps) { + clearInterval(timer); + console.log("\nDone!"); + } + }, interval); }; progress(); diff --git a/src/fs/findByExt.js b/src/fs/findByExt.js index 24f06cb8..9993434c 100644 --- a/src/fs/findByExt.js +++ b/src/fs/findByExt.js @@ -1,7 +1,44 @@ +import path from "path"; +import fs from "fs/promises"; + const findByExt = async () => { // Write your code here // Recursively find all files with specific extension // Parse --ext CLI argument (default: .txt) + + try { + await fs.stat("./workspace"); + } catch (e) { + throw new Error("FS operation failed"); + } + console.log(process.argv); + let files = []; + const extIndex = process.argv.indexOf("--ext"); + const ext = extIndex !== -1 ? process.argv[extIndex + 1] : "txt"; + // console.log(extIndex); + // console.log(ext); + + const scan = async (currPath) => { + const entries = await fs.readdir(currPath, { withFileTypes: true }); + // console.log(entries); + for (const item of entries) { + const fullPath = path.join(currPath, item.name); + const relativePath = path + .relative("./workspace", fullPath) + .replace(/\\/g, "/"); + + if (item.isDirectory()) { + await scan(fullPath); // рекурсивно сканируем + } + + if (item.isFile() && path.extname(item.name).slice(1) === ext) { + files.push(relativePath); // сохраняем путь файла с нужным расширением + } + } + }; + + await scan("./workspace"); + files.sort().forEach((f) => console.log(f)); }; await findByExt(); diff --git a/src/fs/merge.js b/src/fs/merge.js index cb8e0d8f..3384e059 100644 --- a/src/fs/merge.js +++ b/src/fs/merge.js @@ -1,8 +1,37 @@ +import fs from "fs/promises"; +import path from "path"; + const merge = async () => { // Write your code here // Default: read all .txt files from workspace/parts in alphabetical order // Optional: support --files filename1,filename2,... to merge specific files in provided order // Concatenate content and write to workspace/merged.txt + let filesToMerge = []; + let result = ""; + const folderPath = "./workspace/parts"; + try { + await fs.access(folderPath); + + const extIndex = process.argv.indexOf("--files"); + if (extIndex !== -1) { + filesToMerge = process.argv[extIndex + 1].split(","); + } else { + let entries = await fs.readdir(folderPath, { withFileTypes: true }); + + let step1 = entries.filter((e) => e.isFile() && e.name.endsWith(".txt")); + let step2 = step1.map((e) => e.name); + filesToMerge = step2.sort(); + } + if (filesToMerge.length === 0) throw new Error(); + for (const file of filesToMerge) { + const entry = await fs.readFile(path.join(folderPath, file), "utf8"); + result += entry; + console.log(result); + } + await fs.writeFile("./workspace/merged.txt", result); + } catch { + throw new Error("FS operation failed"); + } }; await merge(); diff --git a/src/fs/restore.js b/src/fs/restore.js index 96ae1ffb..c7448b74 100644 --- a/src/fs/restore.js +++ b/src/fs/restore.js @@ -1,8 +1,44 @@ +import path from "path"; +import fs from "fs/promises"; + const restore = async () => { // Write your code here // Read snapshot.json // Treat snapshot.rootPath as metadata only // Recreate directory/file structure in workspace_restored + + try { + await fs.stat("./snapshot.json"); + } catch { + throw new Error("FS operation failed"); + } + + try { + await fs.stat("./workspace_restored"); + // throw new Error("FS operation failed"); + } catch (e) { + if (e.message === "FS operation failed") { + throw e; + } + await fs.mkdir("./workspace_restored"); + } + + try { + const data = await fs.readFile("./snapshot.json", "utf-8"); + const snapshot = JSON.parse(data); + for (const item of snapshot.entries) { + const filePath = path.join("./workspace_restored", item.path); + console.log(filePath); + if (item.type === "directory") { + await fs.mkdir(filePath, { recursive: true }); + } + if (item.type === "file") { + await fs.writeFile(filePath, item.content, "base64"); + } + } + } catch (e) { + console.log(e); + } }; await restore(); diff --git a/src/fs/snapshot.js b/src/fs/snapshot.js index 050103d3..cf34a1c0 100644 --- a/src/fs/snapshot.js +++ b/src/fs/snapshot.js @@ -1,9 +1,72 @@ +import path from "path"; +import fs from "fs/promises"; + +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + const snapshot = async () => { - // Write your code here - // Recursively scan workspace directory - // Write snapshot.json with: - // - rootPath: absolute path to workspace - // - entries: flat array of relative paths and metadata + const workspacePath = path.join(__dirname, "workspace"); + const stats = await fs.stat(workspacePath); + const rootPath = path.resolve(workspacePath); + if (!stats.isDirectory()) { + throw new Error("FS operation failed"); + } + + const entries = []; + + const scan = async (currentPath) => { + try { + let data = await fs.readdir(currentPath, { withFileTypes: true }); + for (const item of data) { + const fullPath = path.join(currentPath, item.name); + const relativePath = path.relative(rootPath, fullPath); + + if (item.isDirectory()) { + console.log("DIR:", item.name); + entries.push({ + path: relativePath, + type: "directory", + }); + console.log(entries); + await scan(fullPath); + } + if (item.isFile()) { + const buffer = await fs.readFile(fullPath); + const size = buffer.length; + const content = buffer.toString("base64"); + console.log("FILE:", item.name); + entries.push({ + path: relativePath, + type: "file", + size, + content, + }); + } + } + } catch (err) { + console.log(err); + } + + // console.log(path.basename()); + // const workspacePath = path.join(process.cwd(), "home"); + // Write your code here + // Recursively scan workspace directory + // Write snapshot.json with: + // - rootPath: absolute path to workspace + // - entries: flat array of relative paths and metadata + }; + + await scan(workspacePath); + const result = { + rootPath, + entries, + }; + console.log(result); + const snapshotPath = path.join(path.dirname(workspacePath), "snapshot.json"); + + await fs.writeFile(snapshotPath, JSON.stringify(result, null, 2)); }; await snapshot();