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.

1 change: 1 addition & 0 deletions source.txt.save
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

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

const onExit = () => {
console.log('Goodbye!');
process.exit(0);
};

rl.prompt();

rl.on('line', (line) => {
const input = line.trim();
switch (input) {
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':
onExit();
return;
default:
console.log('Unknown command');
}
rl.prompt();
});

rl.on('SIGINT', onExit);
rl.on('close', onExit);
};

interactive();
interactive();
41 changes: 36 additions & 5 deletions src/cli/progress.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@
function getArg(name, defaultValue) {
const idx = process.argv.indexOf(`--${name}`);
if (idx !== -1 && process.argv[idx + 1]) {
return process.argv[idx + 1];
}
return defaultValue;
}

const totalDuration = Number(getArg('duration', 5000));
const interval = Number(getArg('interval', 100));
const barLength = Number(getArg('length', 30));
const color = getArg('color', null);

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%
let elapsed = 0;

const timer = setInterval(() => {
elapsed += interval;
let percent = Math.min((elapsed / totalDuration) * 100, 100);
let filledLength = Math.round((percent / 100) * barLength);
let bar = '█'.repeat(filledLength) + ' '.repeat(barLength - filledLength);

let output = `[${bar}] ${Math.round(percent)}%`;
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);
output = `\x1b[38;2;${r};${g};${b}m${output}\x1b[0m`;
}

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

progress();
progress();
27 changes: 20 additions & 7 deletions src/cp/execCommand.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import { spawn } from '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 commandStr = process.argv[2];
if (!commandStr) {
console.error('No command provided');
process.exit(1);
}

const [command, ...args] = commandStr.split(' ');

const child = spawn(command, args, {
stdio: ['inherit', 'inherit', 'inherit'],
env: process.env,
shell: true,
});

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

execCommand();
execCommand();
49 changes: 46 additions & 3 deletions src/fs/findByExt.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,50 @@
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const findByExt = async () => {
// Write your code here
// Recursively find all files with specific extension
// Parse --ext CLI argument (default: .txt)
const extArgIndex = process.argv.indexOf('--ext');
let ext = '.txt';
if (extArgIndex !== -1 && process.argv[extArgIndex + 1]) {
let rawExt = process.argv[extArgIndex + 1];
ext = rawExt.startsWith('.') ? rawExt : `.${rawExt}`;
}

const workspace = path.join(__dirname, '../../workspace');

const result = [];
async function search(dir) {
let entries;
try {
entries = await fs.readdir(dir, { withFileTypes: true });
} catch (e) {
throw new Error('FS operation failed');
}
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
const relPath = path.relative(workspace, fullPath);
if (entry.isDirectory()) {
await search(fullPath);
} else if (entry.isFile() && path.extname(entry.name) === ext) {
result.push(relPath);
}
}
}

try {
await fs.access(workspace);
} catch (e) {
throw new Error('FS operation failed');
}

await search(workspace);

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

await findByExt();
71 changes: 67 additions & 4 deletions src/fs/merge.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,71 @@
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 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 workspace = path.join(__dirname, '../../workspace');
const partsDir = path.join(workspace, 'parts');
const mergedFile = path.join(workspace, 'merged.txt');

const filesArgIndex = process.argv.indexOf('--files');
let filesToMerge = null;
if (filesArgIndex !== -1 && process.argv[filesArgIndex + 1]) {
filesToMerge = process.argv[filesArgIndex + 1].split(',').map(f => f.trim());
}

try {
await fs.access(partsDir);
} catch (e) {
console.error(e);
throw new Error('FS operation failed');
}

let files;
if (filesToMerge) {
files = filesToMerge;
for (const file of files) {
const filePath = path.join(partsDir, file);
try {
await fs.access(filePath);
} catch (e) {
throw new Error('FS operation failed');
}
}
} else {
let entries;
try {
entries = await fs.readdir(partsDir, { withFileTypes: true });
} catch (e) {
throw new Error('FS operation failed');
}
files = entries
.filter(entry => entry.isFile() && entry.name.endsWith('.txt'))
.map(entry => entry.name)
.sort();
if (files.length === 0) {
throw new Error('FS operation failed');
}
}

let mergedContent = '';
for (const file of files) {
const filePath = path.join(partsDir, file);
try {
const content = await fs.readFile(filePath, 'utf8');
mergedContent += content;
} catch (e) {
throw new Error('FS operation failed');
}
}

try {
await fs.writeFile(mergedFile, mergedContent, 'utf8');
} catch (e) {
throw new Error('FS operation failed');
}
};

await merge();
56 changes: 51 additions & 5 deletions src/fs/restore.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,54 @@
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 restore = async () => {
// Write your code here
// Read snapshot.json
// Treat snapshot.rootPath as metadata only
// Recreate directory/file structure in workspace_restored
const baseDir = path.join(__dirname, '../../');
const snapshotPath = path.join(baseDir, 'snapshot.json');
const restoredDir = path.join(baseDir, 'workspace_restored');

try {
await fs.access(snapshotPath);
} catch {
throw new Error('FS operation failed');
}

try {
await fs.access(restoredDir);
throw new Error('FS operation failed');
} catch {
// If error, directory does not exist, continue
}

let snapshot;
try {
const data = await fs.readFile(snapshotPath, 'utf8');
snapshot = JSON.parse(data);
} catch {
throw new Error('FS operation failed');
}

for (const entry of snapshot.entries) {
const entryPath = path.join(restoredDir, entry.path);
if (entry.type === 'directory') {
try {
await fs.mkdir(entryPath, { recursive: true });
} catch {
throw new Error('FS operation failed');
}
} else if (entry.type === 'file') {
await fs.mkdir(path.dirname(entryPath), { recursive: true });
try {
const content = Buffer.from(entry.content, 'base64');
await fs.writeFile(entryPath, content);
} catch {
throw new Error('FS operation failed');
}
}
}
};

await restore();
await restore();
Loading