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
56 changes: 56 additions & 0 deletions implement-shell-tools/cat/customCat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { program } from "commander";
import { promises as fs } from "node:fs";
import process from "node:process";

program
.name("custom-cat")
.description("my-own-version-of-cat")
.option("-n, --line", "Adding a number before each roll")
.option(
"-b, --nonBlank",
"Only adding a number before roll that is non blank",
)
.argument("<path...>", "The file path to process");

program.parse();

const options = program.opts();

const argumentArray = program.args;
if (argumentArray.length < 1) {
console.log(
`We need at least 1 path of file to process but we got ${argumentArray.length}`,
);
process.exit(1);
}

const pathsArray = argumentArray;

let count = 1;

for (let path of pathsArray) {
try {
const context = await fs.readFile(path, "utf-8");
const lines = context.trimEnd().split("\n");
if (options.nonBlank) {
lines.forEach((line) => {
if (line.trim().length != 0) {
console.log(` ${count} ${line}`);
count++;
} else {
console.log(line);
}
});
} else if (options.line) {
lines.forEach((line) => {
console.log(` ${count} ${line}`);
count++;
});
} else {
console.log(context.trimEnd());
}
} catch (error) {
console.error(error.message);
process.exitCode = 1;
}
}
72 changes: 72 additions & 0 deletions implement-shell-tools/ls/customLs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { program } from "commander";
import { promises as fs } from "node:fs";
import process from "node:process";

program
.name("Custom-ls")
.description("Custom-ls-that-works-like-ls")
.option("-1, --oneFile", "Showing one file per line")
.option("-a, --showHidden", "Showing hidden files")
.argument("[path]", "The file path to process");

program.parse();

const argumentsArray = program.args;

const path = argumentsArray[0] || "./";

async function formatFileName(base, fileName) {
try {
const fullPath = `${base.endsWith("/") ? base : base + "/"}${fileName}`;
const stats = await fs.stat(fullPath);
if (stats.isDirectory() && process.stdout.isTTY) {
return `\x1b[1;34m${fileName}\x1b[0m`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea to use colour output, the only caveat we should output the color only if we are in terminal mode. I.e. right now if I pass it into a pipe, it will output these codes as well

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I attempted to add process.stdout.isTTY in the conditional check.

}
return fileName;
} catch (error) {
return fileName;
}
}

try {
const files = await fs.readdir(path);

const sortedFiles = files.sort((a, b) => {
const cleanA = a.replace(/^\./, "");
const cleanB = b.replace(/^\./, "");
return cleanA.localeCompare(cleanB, undefined, { sensitivity: "base" });
});

const options = program.opts();

let renderingFiles = [];

if (options.showHidden) {
renderingFiles = [".", "..", ...sortedFiles];
} else {
renderingFiles = sortedFiles.filter((file) => !/^\./.test(file));
}

if (options.oneFile) {
for (let file of renderingFiles) {
console.log(await formatFileName(path, file));
}
} else {
const formatted = await Promise.all(
renderingFiles.map((fileName) => {
return formatFileName(path, fileName);
}),
);
console.log(formatted.join(" "));
}
} catch (error) {
const stats = await fs.stat(path).catch(() => null);
if (stats && stats.isFile()) {
console.log(path);
} else {
console.error(
`Can't access to this path: ${path} - No such file or directory`,
);
process.exit(1);
}
}
21 changes: 21 additions & 0 deletions implement-shell-tools/package-lock.json

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

6 changes: 6 additions & 0 deletions implement-shell-tools/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"dependencies": {
"commander": "^14.0.3"
},
"type": "module"
}
88 changes: 88 additions & 0 deletions implement-shell-tools/wc/customWc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { program } from "commander";
import { promises as fs } from "node:fs";
import process from "node:process";

program
.name("Custom-wc")
.description("Custom-wc-that-works-like-wc")
.option("-l, --lines", "Counting lines in the file")
.option("-w, --words", "Counting words in the file")
.option("-c, --characters", "Counting characters in the file")
.argument("<path...>", "Path of file to process");

program.parse();

const argumentArray = program.args;
if (argumentArray.length === 0) {
console.log(`We need at least one file path to process`);
process.exit(1);
}

const pathArray = argumentArray;
const options = program.opts();

function padStartNumbers(...args) {
const space = 8;
const numberStringArray = [];
for (let index = 0; index < args.length; index++) {
numberStringArray.push(String(args[index]).padStart(space, " "));
}
return numberStringArray.join("");
}

const totalRowNumbers = [];

let totalOfLines = 0;
let totalOfWords = 0;
let totalOfCharacters = 0;

for (let path of pathArray) {
let numberOfLines = 0;
let numberOfWords = 0;
let numberOfCharacters = 0;

try {
const file = await fs.readFile(path, "utf-8");
numberOfLines = file.split("\n").length - 1;
const words = file.match(/\S+/g);
numberOfWords = words ? words.length : 0;
numberOfCharacters = file.length;

const rowNumbers = [];

if (options.lines) rowNumbers.push(numberOfLines);
if (options.words) rowNumbers.push(numberOfWords);
if (options.characters) rowNumbers.push(numberOfCharacters);

if (rowNumbers.length === 0) {
console.log(
`${padStartNumbers(numberOfLines, numberOfWords, numberOfCharacters)} ${path}`,
);
} else {
if (pathArray.length === 1 && rowNumbers.length === 1) {
console.log(`${rowNumbers[0]} ${path}`);
} else {
console.log(`${padStartNumbers(...rowNumbers)} ${path}`);
}
}
totalOfLines += numberOfLines;
totalOfWords += numberOfWords;
totalOfCharacters += numberOfCharacters;
} catch (error) {
console.error(error.message);
process.exitCode = 1;
}
}

if (pathArray.length > 1) {
if (options.lines) totalRowNumbers.push(totalOfLines);
if (options.words) totalRowNumbers.push(totalOfWords);
if (options.characters) totalRowNumbers.push(totalOfCharacters);
if (totalRowNumbers.length > 0) {
console.log(`${padStartNumbers(...totalRowNumbers)} total`);
} else {
console.log(
`${padStartNumbers(totalOfLines, totalOfWords, totalOfCharacters)} total`,
);
}
}
Loading