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.

42 changes: 38 additions & 4 deletions src/cli/interactive.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,42 @@
import { createInterface } from 'node:readline/promises';
import { stdin, stdout } from 'node:process';

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 = createInterface({
input: stdin,
output: stdout,
});

rl.setPrompt('> ');
rl.prompt();

rl.on('line', (cmd) => {
switch(cmd) {
case 'uptime':
const processUptime = process.uptime();
console.log(`Uptime: ${processUptime}`);
break;
case 'cwd':
const currDir = process.cwd();
console.log(currDir.split('/')[currDir.split('/').length-1]);
break;
case 'date':
const currentDate = new Date();
const ISOstring = currentDate.toISOString();
console.log(ISOstring);
break;
case 'exit':
console.log('Goodbye!');
process.exit(0);
default:
console.log('Unknown command');
}
})

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

interactive();
54 changes: 50 additions & 4 deletions src/cli/progress.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,54 @@
import { parseArgs } from 'node:util';
import { hexToAsnii, validateValueType } from '../utils/util.js';

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 moderatedArgv = process.argv.slice(2);
const { values } = parseArgs({
moderatedArgv,
options: {
duration: {
type: 'string',
default: '5000',
},
interval: {
type: 'string',
default: '100',
},
length: {
type: 'string',
default: '30',
},
},
strict: false,
allowPositionals: true
})
if (values.color) {
values.color = moderatedArgv[moderatedArgv.indexOf('--color') + 1];
}

validateValueType(values);

const fullWidth = parseInt(values.length);
const interv = parseInt(values.interval);
const steps = parseInt(values.duration) / parseInt(values.interval);
let currentStep = 0;

const progressFill = setInterval(() => {
currentStep++;
const progress = currentStep / steps;
const percent = Math.round(progress * 100);
const filledCnt = Math.round(fullWidth * progress);

const asni = hexToAsnii(values.color);
const filled = asni + '█'.repeat(filledCnt) + '\x1b[0m';
const empty = " ".repeat(fullWidth - filledCnt);
process.stdout.write(`\r[${filled}${empty}] ${percent}%`);

if (currentStep >= steps) {
clearInterval(progressFill);
process.stdout.write('\nDone!\n');
}
}, interv);
};

progress();
43 changes: 37 additions & 6 deletions src/cp/execCommand.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,41 @@
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 arg = process.argv.slice(2);

const cmdAndArgs = arg[0].split(" ");
console.log(cmdAndArgs, 'sdsd')
const [childCMD, ...childCMDComment] = cmdAndArgs;
let cmd;

console.log(childCMDComment);
if (childCMDComment.length) {
cmd = spawn(childCMD, [...childCMDComment], {
stdio: 'inherit',
env: process.env,
});
}

cmd = spawn(childCMD);

cmd.stdout.on('data', (data) => {
process.stdout.write(`${data} from child`);
});

cmd.stderr.on('data', (data) => {
console.log(data, 'p')
process.stderr.write(`Error look: ${data}`);
});

cmd.on('exit', (code, signal) => {
if (code !== null) {
process.exit(code);
} else {
cmd.close('close', (code) => {
process.exit(code);
})
}
});
};

execCommand();
80 changes: 75 additions & 5 deletions src/fs/findByExt.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,77 @@
const findByExt = async () => {
// Write your code here
// Recursively find all files with specific extension
// Parse --ext CLI argument (default: .txt)
import { parseArgs } from 'node:util';
import path from 'path';
import fs from 'fs';
const extFromCLI = process.argv.slice(2);
const { values } = parseArgs({
extFromCLI,
options: {
ext: {
type: 'string',
default: 'text'
}
}
});
let deepestPath = '';


const findByExt = async (paths, fileArr) => {
const dir = paths ? paths : './workspace';
isWorksapceExisted(dir);
const fileList = fileArr ? fileArr : [];

try {
const files = fs.readdirSync(dir, { withFileTypes: true });

if (!files || !files.length) {
throw new Error('File not found!')
}

for await (const file of files) {
const fullPath = file.parentPath + '/' + file.name;

const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
await findByExt(fullPath, fileList);
} else if (stat.isFile()
&& path.basename(fullPath).split('.')[path.basename(fullPath).split('.').length - 1] === values.ext) {
fileList.push(fullPath);
deepestPath = deepestPath.split('/').length > fullPath.split('/') ? deepestPath : fullPath;
}
}
} catch (error) {
console.error(Error(error));
}

return fileList;
};

await findByExt();
const listArr = await findByExt();

for (const path of listArr) {
const paths = relativePaths(path);
paths.forEach((el) => {
console.log(`\n${el}`)
})
}

async function isWorksapceExisted(path) {
const errorMsg = 'FS operation failed';
try {
fs.accessSync(path);
} catch (error) {
if (error.code === 'ENOENT') {
console.error(Error(errorMsg));
}
console.error(Error(error));
}
}

function relativePaths(path) {
const deepestPathSet = new Set();
let pathStepByStep = '';
for (let i = 0; i < path.split('/').length - 1; i++) {
pathStepByStep = pathStepByStep + deepestPath.split('/')[i] + '/';
deepestPathSet.add(pathStepByStep)
}
return deepestPathSet;
}
53 changes: 49 additions & 4 deletions src/fs/merge.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,53 @@
import path from 'path';
import fs from 'fs';

// need to redo

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 dir = './src/cp';
const argvs = process.argv.slice(2);
let listFiles = [];

try {
if (argvs[0] === '--files' && argvs[1]) {
listFiles = process.argv[1].split(',');

for (const file of listFiles) {
console.log(dir, file.name)
fs.accessSync(path.join(dir, file.name));
}
} else {
const files = fs.readdirSync(dir, { withFileTypes: true });

listFiles = files
.filter((file) => {
const fullPath = file.parentPath + '/' + file.name;
const stat = fs.statSync(fullPath);
console.log(fullPath)
if (stat.isFile()
&& path.basename(fullPath).split('.')[path.basename(fullPath).split('.').length - 1] === 'js') {
return file;
}
}).sort();

if (listFiles.length === 0) {
console.error(Error('No text file found!'));
}
}

for (const file of listFiles) {
const content = fs.readFileSync(path.join(dir, file.name), 'utf-8');
process.stdout.write(content + '\n');

}
} catch (error) {
console.error(Error(error));
}
};

await merge();

processFiles().catch(err => {
console.error(err.message);
process.exit(1);
});
61 changes: 57 additions & 4 deletions src/fs/restore.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,61 @@
import fs, { constants } from 'node: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
const dir = process.cwd();
const jsonDir = dir + '/snapshot.json';
isJSONEXist(jsonDir);

try {
await fs.mkdir(dir + '/workspace_restored');
} catch (error) {
if (error === 'ENOENT') {
console.error(Error('FS operation failed'));
}
}

try {
const data = await fs.readFile('./snapshot.json', 'utf8');
const content = JSON.parse(data);

for (const entry of content.entries) {
let pathFromJSON = content.rootPath;

pathFromJSON = pathFromJSON.split('/workspace')[0] +'/workspace_restored/' + entry.path;

if (entry.type === 'directory') {
await fs.mkdir(pathFromJSON);
} else if (entry.type === 'file') {
const base64String = entry.content;
const buffer = Buffer.from(base64String, 'base64');
await fs.writeFile(pathFromJSON, buffer);

}
}

} catch (error) {
if (error === 'ENOENT') {
console.error(Error('FS operation failed'));
} else if (error === 'EACCES') {
console.error(Error("Access Denied!"));
} else {
console.error(Error(error))
}
}
};

await restore();


async function isJSONEXist(path) {
const errorMsg = 'FS operation failed';
try {
await fs.access(path, constants.R_OK);
} catch (error) {
if (error.code === 'ENOENT') {
console.error(Error(errorMsg));
} else if (error.code === 'EACCES') {
console.error(Error('Access Denied!'));
}
console.error(Error(error));
}
}
Loading