Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 48 additions & 5 deletions src/cli/interactive.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,51 @@
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
});

rl.setPrompt('> ');
rl.prompt();
rl.on('line', (input) => {
const command = input.trim();

switch (command) {
case 'uptime':
console.log('Uptime:', process.uptime(), 's');
break;

case 'cwd':
console.log(process.cwd());
break;

case 'date':
console.log(new Date().toISOString());
break;

case 'exit':
rl.close();
return;

case '':
break;

default:
console.log('Unknown command');
}

rl.prompt();
});

rl.on('SIGINT', () => {
rl.close();
});

rl.on('close', () => {
console.log('Goodbye!');
process.exit(0);
});
};

interactive();
interactive();
69 changes: 65 additions & 4 deletions src/cli/progress.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,69 @@
const progress = () => {
// Write your code here
// Simulate progress bar from 0% to 100% over ~5 seconds
// Update in place using \r every 100ms
// Format: [████████████████████ ] 67%

const args = process.argv.slice(2);

let duration = 5000;
let interval = 100;
let length = 30;
let percent = 0;
let color = null;
let colorCode = null;

const colorIndex = args.indexOf('--color');
if (colorIndex !== -1) {
color = args[colorIndex + 1];
}
if (color && !/^#[0-9A-Fa-f]{6}$/.test(color)) {
color = null;
}
if (color) {
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);

colorCode = `\x1b[38;2;${r};${g};${b}m`;
}

const durationIndex = args.indexOf('--duration');
if (durationIndex !== -1) {
duration = Number(args[durationIndex + 1]);
}

const intervalIndex = args.indexOf('--interval');
if (intervalIndex !== -1) {
interval = Number(args[intervalIndex + 1]);
}


const lengthIndex = args.indexOf('--length');
if (lengthIndex !== -1) {
length = Number(args[lengthIndex + 1]);
}

const steps = Math.ceil(duration / interval);
const increment = 100 / steps;


const timer = setInterval(() => {
percent += increment;
if (percent > 100) percent = 100;

const filled = Math.floor((length * percent) / 100);
const empty = length - filled;
const filledPart = '█'.repeat(filled);
const emptyPart = ' '.repeat(empty);
const coloredFilled = colorCode ? `${colorCode}${filledPart}\x1b[0m`: filledPart;
const bar = coloredFilled + emptyPart;

process.stdout.write(`\r[${bar}] ${Math.floor(percent)}%`);

if (percent >= 100) {
clearInterval(timer);
process.stdout.write('\nDone!\n');
}
}, interval);
};

progress();

// Temporary comment
21 changes: 15 additions & 6 deletions src/cp/execCommand.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { spawn } from 'node:child_process';

const execCommand = () => {
// Write your code here
// Take command from CLI argument
// Spawn child process
// Pipe child stdout/stderr to parent stdout/stderr
// Pass environment variables
// Exit with same code as child
const command = process.argv[2];

const child = spawn(command, {
shell: true,
env: process.env
});

child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);

child.on('close', (code) => {
process.exit(code);
});
};

execCommand();
64 changes: 60 additions & 4 deletions src/fs/findByExt.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,63 @@
import fs from 'node:fs/promises';
import path from 'node:path';

const findByExt = async () => {
// Write your code here
// Recursively find all files with specific extension
// Parse --ext CLI argument (default: .txt)

const index = process.argv.indexOf('--ext');
const ext = process.argv[index + 1];
let extension;

if (index !== -1) {
extension = ext.startsWith('.') ? ext : '.' + ext;
} else {
extension = '.txt';
}

const workspacePath = path.resolve('src/workspace');

try {
const stats = await fs.stat(workspacePath);

if (!stats.isDirectory()) {
throw new Error('FS operation failed');
}
let result = []
await walk(workspacePath, workspacePath, extension, result);

result.sort();
for (const file of result) {
console.log(file);
}

} catch (err) {
if (err.code === 'ENOENT') {
throw new Error('FS operation failed');
}
throw err;
}

async function walk(currentPath, basePath, extension, result) {
const entries = await fs.readdir(currentPath, { withFileTypes: true });

for (const dirent of entries) {

const fullPath = path.join(currentPath, dirent.name);
const relativePath = path.relative(basePath, fullPath);

if (dirent.isDirectory()) {
await walk(fullPath, basePath, extension, result);

} else if (dirent.isFile()) {
if (path.extname(dirent.name) === extension){
result.push(relativePath)
}
}
}
}
};

await findByExt();




await findByExt().catch(console.error);
66 changes: 61 additions & 5 deletions src/fs/merge.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,64 @@
import fs from 'node:fs/promises';
import path from 'node: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

const index = process.argv.indexOf('--files')

let files;
if (index !== -1) {
files = process.argv[index + 1].split(',');
}

const workspacePath = path.resolve('src/workspace/parts');

try{
const stats = await fs.stat(workspacePath);

if (!stats.isDirectory()) {
throw new Error('FS operation failed');
}
if(!files){
const entries = await fs.readdir(workspacePath, { withFileTypes: true });

files = [];
for (const dirent of entries) {
if(dirent.isFile() && path.extname(dirent.name) === '.txt'){
files.push(dirent.name)
}
}
files.sort()

if(files.length === 0){
throw new Error('FS operation failed');
}
} else {
if(files.length === 0 || (files.length === 1 && files[0] === '')){
throw new Error('FS operation failed');
}
for (const file of files){
try {
await fs.access(path.join(workspacePath, file));
} catch {
throw new Error('FS operation failed');
}
}
}
let mergedContent = ''
for (const file of files){
const content = await fs.readFile(path.join(workspacePath, file), 'utf8')
mergedContent += content
}
await fs.writeFile(path.resolve('src/workspace', 'merged.txt'), mergedContent)


} catch (err) {
if (err.code === 'ENOENT') {
throw new Error('FS operation failed');
}
throw err;
}

};

await merge();
await merge().catch(console.error);
54 changes: 48 additions & 6 deletions src/fs/restore.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,50 @@
import fs from 'node:fs/promises';
import path from 'node:path';


const restore = async () => {
// Write your code here
// Read snapshot.json
// Treat snapshot.rootPath as metadata only
// Recreate directory/file structure in workspace_restored
};
const snapshotPath = path.resolve('src/snapshot.json');
const workspaceRestoredPath = path.resolve('src/workspace_restored');

try{
await fs.stat(snapshotPath);
}

catch(err){
if (err.code === 'ENOENT') {
throw new Error('FS operation failed');
}
throw err;
};

try {
await fs.stat(workspaceRestoredPath);
throw new Error('FS operation failed');
} catch (err) {
if (err.code === 'ENOENT') {
await fs.mkdir(workspaceRestoredPath);
} else {
throw err;
}
}

const data = await fs.readFile(snapshotPath);
const snapshot = JSON.parse(data);

for(const entry of snapshot.entries){
if(entry.type === 'directory'){
await fs.mkdir(path.join(workspaceRestoredPath, entry.path), { recursive: true });
}
else if (entry.type === 'file'){
const targetPath = path.join(workspaceRestoredPath, entry.path);
await fs.mkdir(path.dirname(targetPath), { recursive: true });
const buffer = Buffer.from(entry.content, 'base64');
await fs.writeFile(targetPath, buffer);
}
}
}

restore().catch(console.error);



await restore();
Loading