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
83 changes: 83 additions & 0 deletions notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# 📔 Node.js Study Notes - Fundamentals (2026 Edition)

## 🏗️ 1. Foundations (Path & Process)

* **`process.cwd()`**: Returns the "Current Working Directory". It's the robot saying: "I am standing exactly here".
* **`process.argv`**: The array that stores everything you type in the terminal after the command.
* **`path.resolve`**: Convert relative routes into absolute routes.
* **`path.join`**: Avoid errors by joining parts of routes in a secure way (handles `/` vs `\`).
* **`path.relative`**: Cleans the route and gives only the path relative to another (e.g., from workspace to file).
* **`path.extname`**: Returns the file extension (e.g., `.txt`).
* **`path.dirname`**: Returns the name of the parent directory. Useful to know where a file is sitting.

---

## 📂 2. File System (fs/promises)

* **`fs/promises`**: Using the asynchronous version of the FS module so we can use `await`.
* **`readdir`**: Lists everything inside a folder.
* **`stat`**: Checks metadata (if it's a file, directory, and its size).
* **`readFile` / `writeFile`**: Basic commands to read content and create/overwrite files.
* **`mkdir`**: Creates a new directory. Used with `{ recursive: true }` to create nested folders (a/b/c) all at once.
* **`Buffer`**: A way to handle raw binary data. We used `Buffer.from(content, "base64")` to turn encoded text back into real files.
* **`.toString("base64")`**: Converts file content into a base64 string for easy storage in JSON.

---

## ⌨️ 3. CLI & Terminal UI

* **`readline`**: A module used to read input from the terminal line by line. It’s the "listening ear" of the app.
* **`process.uptime()`**: Returns how many seconds the Node process has been running.
* **`.toISOString()`**: Returns a string in standard ISO format (YYYY-MM-DDTHH:mm:ss.sssZ).
* **`\r` (Carriage Return)**: Moves the cursor back to the start of the line without jumping to the next one. Essential for "in-place" updates like progress bars.
* **ANSI Escape Codes**: Special sequences (like `\x1b[38;2;...`) used to color and format terminal text.
* **Hex to RGB**: Converting `#RRGGBB` into three numbers (Red, Green, Blue) so the terminal can apply colors.

---

## 🧩 4. Dynamic Modules

* **`import()`**: A function-like expression that allows you to load a module asynchronously on the fly.
* **`pathToFileURL`**: Converts a system path into a URL (`file:///...`), necessary for dynamic imports on modern Node.js versions.

---

## 🛡️ 5. Hashing & Security

* **`createHash('sha256')`**: Creates a unique "digital fingerprint" (64 characters). If one bit changes, the hash changes completely.
* **`createReadStream`**: Opens a "river" of data. Instead of drinking the whole thing at once (avoiding memory crashes), we process it by "trickles" (chunks).
* **`pipeline`**: The "glue." It connects streams safely and handles errors automatically. It's the modern way to pipe data.

---

## 🌊 6. Streams & Transformations

* **Transform Stream**: A duplex stream that modifies or transforms the data as it passes through (e.g., adding line numbers or filtering).
* **`process.stdin` / `process.stdout`**: The standard input (keyboard) and output (screen) streams of the process.
* **`chunk`**: A small piece of data (usually a Buffer) being processed in the stream pipeline.
* **Backpressure**: A situation where data is produced faster than it can be consumed; Streams handle this automatically to save memory.

---

## 🤐 7. Compression (Zlib & Brotli)

* **`zlib`**: The built-in module for compression and decompression.
* **Brotli (`.br`)**: A modern, high-efficiency compression algorithm from Google, superior to Gzip for text assets.
* **`createBrotliCompress` / `createBrotliDecompress`**: Transform streams used to shrink or restore data.

---

## 🧵 8. Worker Threads (Parallelism)

* **Main Thread**: The primary execution path. It handles the event loop and delegates heavy CPU tasks.
* **Worker Thread**: An independent thread that runs alongside the main thread.
* **`parentPort`**: The communication channel (walkie-talkie) between the worker and the main thread.
* **Divide and Conquer**: Splitting a large problem into smaller chunks to be solved in parallel by multiple workers.

---

## 👶 9. Child Processes

* **`spawn`**: Launches a new process (like `ls`, `date`, or any terminal command).
* **`stdio: inherit / pipe`**: Connecting the child's input/output channels to the parent process.
* **Exit Code**: A number returned by the process when it finishes. `0` means success; anything else indicates an error.
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.

66 changes: 62 additions & 4 deletions src/cli/interactive.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,66 @@
import readline from "node:readline";

// Write your code here
// Use readline module for interactive CLI
// Support commands: uptime, cwd, date, exit
// Handle Ctrl+C and unknown commands

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,
// Requirement: Display a prompt "> "
prompt: "> ",
});

// Initial prompt display
rl.prompt();

rl.on("line", (line) => {
const command = line.trim().toLowerCase();

switch (command) {
case "uptime":
// Requirement: prints process uptime in seconds (e.g. Uptime: 12.34s)
process.stdout.write(`Uptime: ${process.uptime().toFixed(2)}s\n`);
break;

case "cwd":
// Requirement: prints the current working directory
process.stdout.write(`${process.cwd()}\n`);
break;

case "date":
// Requirement: prints the current date and time in ISO format
process.stdout.write(`${new Date().toISOString()}\n`);
break;

case "exit":
// Requirement: prints "Goodbye!" and terminates
process.stdout.write("Goodbye!\n");
rl.close();
break;

default:
// Requirement: On unknown command, print "Unknown command"
process.stdout.write("Unknown command\n");
break;
}

if (command !== "exit") {
rl.prompt();
}
});

// Requirement: On Ctrl+C or end of input, print "Goodbye!" and exit
rl.on("SIGINT", () => {
process.stdout.write("\nGoodbye!\n");
rl.close();
});

rl.on("close", () => {
process.exit(0);
});
};

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

// Helper function to get argument values or return a default
const getArg = (flag, defaultValue) => {
const index = args.indexOf(flag);
return index !== -1 && args[index + 1] ? args[index + 1] : defaultValue;
};

// Parsing arguments with their default values
const duration = parseInt(getArg("--duration", "5000"));
const interval = parseInt(getArg("--interval", "100"));
const length = parseInt(getArg("--length", "30"));
const hexColor = getArg("--color", null);

// Helper to convert #RRGGBB to ANSI escape code for 24-bit color
const getAnsiColor = (hex) => {
if (!hex || !/^#[0-9A-Fa-f]{6}$/.test(hex)) return "";
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return `\x1b[38;2;${r};${g};${b}m`;
};

const colorStart = getAnsiColor(hexColor);
const colorReset = "\x1b[0m";

let percentage = 0;
const increment = 100 / (duration / interval);

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

const filledLength = Math.floor((percentage / 100) * length);
const emptyLength = length - filledLength;

const filledPart = "█".repeat(filledLength);
const emptyPart = " ".repeat(emptyLength);

// Building the bar: Apply color only to the filled part if color exists
const formattedBar = `${colorStart}${filledPart}${colorReset}${emptyPart}`;

process.stdout.write(`\r[${formattedBar}] ${Math.round(percentage)}%`);

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

progress();
52 changes: 46 additions & 6 deletions src/cp/execCommand.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,50 @@
import { spawn } from "node:child_process";

// 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 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
// 1. Get the command string from the arguments
const commandArg = process.argv[2];

if (!commandArg) {
process.stderr.write("Please provide a command string, (e.g., 'ls -la')\n");
process.exit(1);
}

// 2. Parse the command and its arguments
// Example: "ls -la" -> command: "ls", args: ["-la"]
const [command, ...args] = commandArg.split(" ");

// 3. Spawn the child process
// We pass 'process.env' so the child has the same environment variables
const child = spawn(command, args, {
env: process.env,
shell: true, // Use shell to correctly parse strings on Mac/Windows
});

// 4. Pipe the outputs
// This connects the child's mouth (stdout) to the parent's mouth (stdout)
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);

//

// 5. Handle the exit
child.on("close", (code) => {
// Requirement: parent process exits with the same exit code
process.exit(code);
});

// Handle errors if the command doesn't exist
child.on("error", (err) => {
process.stderr.write(`Failed to start process: ${err.message}\n`);
process.exit(1);
});
};

execCommand();
55 changes: 52 additions & 3 deletions src/fs/findByExt.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,56 @@
import { readdir, stat } from "node:fs/promises";
import { resolve, join, relative, extname } from "node:path";

// Write your code here
// Recursively find all files with specific extension
// Parse --ext CLI argument (default: .txt)

const findByExt = async () => {
// Write your code here
// Recursively find all files with specific extension
// Parse --ext CLI argument (default: .txt)
try {
const workspacePath = resolve(process.cwd(), "workspace");

// Pre-validation: Ensure the workspace directory exists
try {
await stat(workspacePath);
} catch {
throw new Error("FS operation failed");
}

const args = process.argv;
const extIndex = args.indexOf("--ext");
let targetExt = ".txt";

if (extIndex !== -1 && args[extIndex + 1]) {
const providedValue = args[extIndex + 1];
targetExt = providedValue.startsWith(".")
? providedValue
: `.${providedValue}`;
}

const results = [];

const scan = async (currentPath) => {
const folderContents = await readdir(currentPath);
for (const item of folderContents) {
const fullPath = join(currentPath, item);
const itemStat = await stat(fullPath);

if (itemStat.isFile()) {
if (extname(fullPath) === targetExt) {
results.push(relative(workspacePath, fullPath));
}
} else if (itemStat.isDirectory()) {
await scan(fullPath);
}
}
};

await scan(workspacePath);
results.sort();
results.forEach((filePath) => process.stdout.write(`${filePath}\n`));
} catch (error) {
throw new Error("FS operation failed");
}
};

await findByExt();
Loading