Skip to content

Commit b494ffd

Browse files
committed
initial commit, completed first task along with tests
0 parents  commit b494ffd

13 files changed

+7620
-0
lines changed

.eslintrc.cjs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* eslint-env node */
2+
module.exports = {
3+
extends: [
4+
'eslint:recommended',
5+
'plugin:@typescript-eslint/recommended',
6+
'plugin:prettier/recommended'
7+
],
8+
parser: '@typescript-eslint/parser',
9+
plugins: ['@typescript-eslint'],
10+
root: true,
11+
rules: {
12+
'@typescript-eslint/no-var-requires': 0
13+
}
14+
};

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.idea/
2+
**/node_modules/
3+
**/build/
4+
**/package-lock.json
5+
.vscode/
6+
coverage/

.prettierrc

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"semi": true,
3+
"trailingComma": "none",
4+
"singleQuote": true,
5+
"printWidth": 80,
6+
"endOfLine": "auto"
7+
}

README.md

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Solutions to John Crickett's Coding Challenges
2+
3+
## About
4+
5+
This repository contains my solutions to John Crickett's Coding Challenges. The challenges are available at [https://codingchallenges.fyi/challenges/intro](https://codingchallenges.fyi/challenges/intro).
6+
7+
Using Typescript as the language throughout the challenges.
8+
9+
Just trying to learn Typescript and improve my problem solving skills.
10+
11+
I am also trying to incorporate testing, documentation and a better GIT control.
12+
13+
## Structure
14+
15+
- `src` - Contains all the source code
16+
- `tests` - Contains all the test files
17+
18+
## Installation
19+
20+
The following command will build all the .ts files present in `src` folder into a new `build` folder.
21+
22+
```bash
23+
npm install
24+
npm run build
25+
```
26+
27+
## Testing
28+
29+
The following command will run all the tests present under the `tests` folder and create the coverage report in `coverage` folder.
30+
31+
All the relevant required test input files are present in tests folder itself.
32+
33+
```bash
34+
npm run test
35+
```

babel.config.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
presets: [
3+
['@babel/preset-env', { targets: { node: 'current' } }],
4+
'@babel/preset-typescript'
5+
]
6+
};

jest.config.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports = {
2+
roots: ['<rootDir>/src', '<rootDir>/tests'],
3+
testMatch: [
4+
'**/__tests__/**/*.+(ts|tsx|js)',
5+
'**/?(*.)+(spec|test).+(ts|tsx|js)'
6+
],
7+
transform: {
8+
'^.+\\.(ts|tsx)$': 'ts-jest'
9+
},
10+
verbose: true,
11+
coverageDirectory: './coverage',
12+
collectCoverage: true,
13+
detectOpenHandles: true,
14+
silent: false,
15+
};

package.json

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "cc_john",
3+
"version": "1.0.0",
4+
"description": "This repository contains my solutions to John Crickett's Coding Challenges",
5+
"scripts": {
6+
"lint": "eslint --ext .ts .",
7+
"prettier-format": "prettier --config .prettierrc **/*.ts --write",
8+
"test": "jest",
9+
"build": "tsc -p .",
10+
"watch": "tsc -p . --watch",
11+
"run": "node ./build/index.js"
12+
},
13+
"keywords": [],
14+
"author": "",
15+
"license": "ISC",
16+
"dependencies": {
17+
"ts-node": "^10.9.1",
18+
"typescript": "^5.1.6"
19+
},
20+
"devDependencies": {
21+
"@babel/core": "^7.22.9",
22+
"@babel/preset-env": "^7.22.9",
23+
"@babel/preset-typescript": "^7.22.5",
24+
"@types/jest": "^29.5.3",
25+
"@typescript-eslint/eslint-plugin": "^6.0.0",
26+
"@typescript-eslint/parser": "^6.0.0",
27+
"babel-jest": "^29.6.1",
28+
"eslint": "^8.45.0",
29+
"eslint-config-prettier": "^8.8.0",
30+
"eslint-plugin-prettier": "^5.0.0",
31+
"jest": "^29.6.1",
32+
"prettier": "^3.0.0",
33+
"ts-jest": "^29.1.1"
34+
}
35+
}

src/1/index.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { myWC } from './wc';
2+
3+
const main = async () => {
4+
const result = await myWC(process.argv, process.stdin);
5+
console.log(result);
6+
};
7+
8+
main();

src/1/wc.ts

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
const fs = require('fs');
2+
3+
async function readStream(stream: NodeJS.ReadStream): Promise<Buffer> {
4+
const chunks = [];
5+
for await (const chunk of stream) {
6+
chunks.push(Buffer.from(chunk));
7+
}
8+
return Buffer.concat(chunks);
9+
}
10+
11+
function byteCount(filename: string): number {
12+
return fs.statSync(filename).size;
13+
}
14+
15+
function lineCount(text: string): number {
16+
return text.split(/\r\n|\r|\n/).length - 1;
17+
}
18+
19+
function wordCount(text: string): number {
20+
if (text.length <= 0) {
21+
return 0;
22+
}
23+
return text.trim().split(/\s+/).length;
24+
}
25+
26+
/**
27+
* This function is the unix wc command implementation
28+
*
29+
* @async
30+
* @param {string[]} argv - The first two are reserved arguments consering the
31+
* node call to the file
32+
* @param {?NodeJS.ReadStream} [stream] - This can be a file read stream or the
33+
* stdin stream
34+
* @returns {Promise<string>}
35+
*/
36+
async function myWC(
37+
argv: string[],
38+
stream?: NodeJS.ReadStream
39+
): Promise<string> {
40+
// Option is given, file is given
41+
if (argv.length === 4) {
42+
// console.log('file + option');
43+
const option = argv[2];
44+
const filename = argv[3];
45+
if (fs.existsSync(filename)) {
46+
const fileContents = fs.readFileSync(filename, 'utf8').toString();
47+
switch (option) {
48+
case '-c':
49+
return byteCount(filename).toString() + ' ' + filename;
50+
case '-l':
51+
return lineCount(fileContents).toString() + ' ' + filename;
52+
case '-w':
53+
return wordCount(fileContents).toString() + ' ' + filename;
54+
default:
55+
throw new Error('Invalid option');
56+
}
57+
}
58+
if (typeof stream === 'undefined') {
59+
throw new Error('Invalid file');
60+
}
61+
}
62+
63+
// Only filename is given
64+
if (argv.length === 3) {
65+
// console.log('only option');
66+
const filename = argv[2];
67+
if (fs.existsSync(filename)) {
68+
const fileContents = fs.readFileSync(filename, 'utf8');
69+
const line = lineCount(fileContents).toString();
70+
const word = wordCount(fileContents).toString();
71+
const bytes = byteCount(filename).toString();
72+
return line + ' ' + word + ' ' + bytes + ' ' + filename;
73+
}
74+
if (typeof stream === 'undefined') {
75+
throw new Error('Invalid file');
76+
}
77+
}
78+
79+
// Checking for stream
80+
if (typeof stream !== 'undefined') {
81+
// console.log('stream');
82+
try {
83+
// If option is given
84+
const buffer = await readStream(stream);
85+
const fileContents = buffer.toString();
86+
if (argv.length === 3) {
87+
const option = argv[2];
88+
switch (option) {
89+
case '-c':
90+
return buffer.length.toString();
91+
case '-l':
92+
return lineCount(fileContents).toString();
93+
case '-w':
94+
return wordCount(fileContents).toString();
95+
default:
96+
throw new Error('Invalid option');
97+
}
98+
}
99+
100+
// If no option is given
101+
if (argv.length == 2) {
102+
const line = lineCount(fileContents).toString();
103+
const word = wordCount(fileContents).toString();
104+
const bytes = buffer.length.toString();
105+
return line + ' ' + word + ' ' + bytes;
106+
}
107+
} catch (err) {
108+
// If the error is not an expected TypeError
109+
if (!(err instanceof TypeError)) {
110+
throw err;
111+
}
112+
}
113+
}
114+
throw new Error('Invalid input or file');
115+
}
116+
117+
export { myWC };

tests/1/test1.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)