Skip to content

Commit d6594b6

Browse files
committed
Add solutions for 7,8 chapters
1 parent 9fced9a commit d6594b6

10 files changed

+409
-2
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import chalk from 'chalk';
2+
3+
class ColorConsole {
4+
log(text) {
5+
console.log(text);
6+
};
7+
}
8+
9+
10+
class RedConsole extends ColorConsole {
11+
log(text) {
12+
console.log(chalk.red(text));
13+
}
14+
}
15+
16+
class BlueConsole extends ColorConsole {
17+
log(text) {
18+
console.log(chalk.blue(text));
19+
}
20+
}
21+
22+
class GreenConsole extends ColorConsole {
23+
log(text) {
24+
console.log(chalk.green(text));
25+
}
26+
}
27+
28+
function createColorConsole(color) {
29+
switch(color) {
30+
case 'blue':
31+
return new BlueConsole();
32+
case 'green':
33+
return new GreenConsole();
34+
case 'red':
35+
default:
36+
return new RedConsole()
37+
}
38+
}
39+
40+
// =========== USAGE ==============
41+
42+
const readConsole = createColorConsole('red');
43+
const greenConsole = createColorConsole('green');
44+
const blueConsole = createColorConsole('blue');
45+
46+
readConsole.log("I'M RED");
47+
greenConsole.log("I'M GREEN");
48+
blueConsole.log("I'M BLUE");
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { request } from 'https';
2+
import { URL } from 'url';
3+
4+
class BuildRequest {
5+
constructor() {
6+
this.body = '';
7+
}
8+
9+
setMethod(method) {
10+
if (!method) {
11+
throw new Error('Provided wrong http method');
12+
}
13+
14+
this.method = method;
15+
return this;
16+
}
17+
18+
setUrl(urlStr) {
19+
this.url = new URL(urlStr);
20+
return this;
21+
}
22+
23+
setQueryParams(query) {
24+
Object.entries(query).forEach(([key, val]) => this.url.searchParams.set(key, val));
25+
return this;
26+
}
27+
28+
setHeaders(headers) {
29+
this.headers = headers;
30+
return this;
31+
}
32+
33+
setBody(body) {
34+
this.body = JSON.stringify(body) || '';
35+
return this;
36+
}
37+
38+
validateRequestParams() {
39+
return this.url && this.method;
40+
}
41+
setPort(port) {
42+
this.port = port;
43+
return this;
44+
}
45+
46+
invoke() {
47+
const options = {
48+
host: this.url.host,
49+
path: `${this.url.pathname}?${this.url.searchParams.toString()}`,
50+
method: this.method,
51+
headers: {
52+
Accept: 'application/json',
53+
...this.headers,
54+
}
55+
};
56+
57+
if (!this.validateRequestParams()) throw Error('Please provide at least method and url');
58+
59+
return new Promise((resolve, reject) => {
60+
const req = request(options, (res) => {
61+
let resAccum = '';
62+
res.on('data', (chunk) => {
63+
resAccum += chunk.toString();
64+
});
65+
res.on('end', () => resolve(JSON.parse(resAccum)));
66+
res.on('error', reject);
67+
});
68+
69+
req.on('error', reject);
70+
req.write(this.body);
71+
req.end();
72+
})
73+
}
74+
}
75+
76+
new BuildRequest()
77+
.setMethod('GET')
78+
.setUrl('https://api.urbandictionary.com/v0/define')
79+
.setQueryParams({ term: 'wat' })
80+
.invoke()
81+
.then((res) => {
82+
console.log('REQUEST finished', res);
83+
})
84+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
class Queue {
2+
constructor(executor) {
3+
const queue = [];
4+
let resolveQueue = [];
5+
6+
const enqueue = (item) => {
7+
queue.push(item);
8+
if (resolveQueue.length) {
9+
const resolve = resolveQueue.shift();
10+
resolve(queue.shift());
11+
}
12+
}
13+
14+
executor(enqueue);
15+
16+
this.dequeue = () => {
17+
if (queue.length) {
18+
const item = queue.shift();
19+
if (resolveQueue.length) {
20+
const resolve = resolveQueue.shift();
21+
resolve(queue.shift());
22+
}
23+
return Promise.resolve(item);
24+
}
25+
26+
return new Promise((resolve, reject) => {
27+
resolveQueue.push(resolve);
28+
});
29+
}
30+
}
31+
}
32+
33+
34+
const queue = new Queue((enqueue) => {
35+
enqueue(1);
36+
enqueue(3);
37+
38+
setTimeout(() => enqueue(6), 2000);
39+
setTimeout(() => enqueue(3), 0);
40+
})
41+
42+
console.log(await queue.dequeue());
43+
console.log(await queue.dequeue());
44+
console.log(await queue.dequeue());
45+
console.log(await queue.dequeue());
46+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import axios from 'axios';
2+
3+
const cache = {};
4+
5+
const axiosWithCache = new Proxy(axios, {
6+
get: (target, prop) => {
7+
if (prop !== 'get') return target[prop];
8+
9+
return async (url, config) => {
10+
if (cache[url]) {
11+
console.log(`Get request ${url} is found in cache`);
12+
return Promise.resolve(cache[url]);
13+
}
14+
15+
const { data } = await target.get(url, config);
16+
// request object is too big to store
17+
cache[url] = { data };
18+
return cache[url];
19+
}
20+
}
21+
})
22+
23+
// TESTING
24+
console.log(await axiosWithCache.get('https://api.urbandictionary.com/v0/define?term=wat', {}));
25+
console.log(await axiosWithCache.get('https://api.urbandictionary.com/v0/define?term=help', {}));
26+
console.log(await axiosWithCache.get('https://api.urbandictionary.com/v0/define?term=wat', {}));
27+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import chalk from 'chalk';
2+
3+
const logMethods = ['log', 'debug', 'info', 'error'];
4+
5+
const consoleWithTimestamp = new Proxy(console, {
6+
get: (target, prop) => {
7+
if (!logMethods.includes(prop)) return target[prop];
8+
9+
return (...args) => {
10+
const timestamp = chalk.green(new Date().toLocaleString());
11+
target[prop](timestamp, ...args);
12+
}
13+
}
14+
});
15+
16+
// TESTING
17+
consoleWithTimestamp.log('Foo', 'And', 'Bar', 'Went', 'To', 'A', 'Bar');
18+
consoleWithTimestamp.error('ERROR');
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import chalk from 'chalk';
2+
3+
const decorateConsole = (console) => {
4+
console.red = msg => console.log(chalk.red(msg));
5+
console.yellow = msg => console.log(chalk.yellow(msg));
6+
console.green = msg => console.log(chalk.green(msg));
7+
}
8+
9+
decorateConsole(console);
10+
11+
console.red('I AM RED');
12+
console.green('I AM GREEN');
13+
console.yellow('I AM YELLOW');
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { resolve } from 'path'
2+
3+
// In-Memory Cache
4+
class Cache {
5+
constructor() {
6+
this.cache = new Map();
7+
}
8+
9+
async putEntry(key, value) {
10+
return Promise.resolve(this.cache.set(key, value));
11+
}
12+
13+
async getValue(key, options, callback) {
14+
const val = await Promise.resolve(this.cache.get(key));
15+
if (!val) {
16+
const err = new Error(`ENOENT, open "${key}"`)
17+
err.code = 'ENOENT'
18+
err.errno = 34
19+
err.path = key
20+
throw err;
21+
}
22+
return val;
23+
}
24+
}
25+
26+
// FS Adapter
27+
const createFSAdapter = cache => ({
28+
readFile(filename, options, callback) {
29+
if (typeof options === 'function') {
30+
callback = options
31+
options = {}
32+
} else if (typeof options === 'string') {
33+
options = { encoding: options }
34+
}
35+
36+
cache.getValue(resolve(filename))
37+
.then(val => callback(null, val))
38+
.catch(callback);
39+
},
40+
41+
writeFile(filename, contents, options, callback) {
42+
if (typeof options === 'function') {
43+
callback = options
44+
options = {}
45+
} else if (typeof options === 'string') {
46+
options = { encoding: options }
47+
}
48+
49+
cache.putEntry(resolve(filename), contents)
50+
.then((res) => callback(null, res))
51+
.catch(callback)
52+
}
53+
})
54+
55+
const cache = new Cache();
56+
const fs = createFSAdapter(cache)
57+
58+
fs.writeFile('file.txt', 'Hello!', () => {
59+
fs.readFile('file.txt', { encoding: 'utf8' }, (err, res) => {
60+
if (err) {
61+
return console.error(err)
62+
}
63+
console.log('Read result', res)
64+
})
65+
})
66+
67+
// try to read a missing file
68+
fs.readFile('missing.txt', { encoding: 'utf8' }, (err, res) => {
69+
console.error(err)
70+
})
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Buffer } from 'buffer';
2+
3+
function createLazyBuffer(size) {
4+
let actualBuffer = null;
5+
6+
// use {} as a placeholder
7+
return new Proxy({}, {
8+
get: (target, prop) => {
9+
if (actualBuffer) {
10+
return actualBuffer[prop].bind(actualBuffer);
11+
}
12+
13+
if (prop !== 'write') {
14+
// since Buffer has only method properties
15+
return () => {
16+
throw new Error(`${prop} method cannot be called. Please write to buffer first`);
17+
}
18+
}
19+
20+
// If it's first write
21+
actualBuffer = Buffer.allocUnsafe(size);
22+
return (data) => {
23+
actualBuffer.write(data);
24+
}
25+
},
26+
});
27+
}
28+
29+
// TESTING
30+
const buffer = createLazyBuffer(20);
31+
32+
try {
33+
console.log('Log buffer:', buffer.toString()); // throws an error
34+
} catch(e) {
35+
console.error('Error', e);
36+
}
37+
38+
buffer.write('Hello to buffer');
39+
40+
console.log('Log buffer:', buffer.toString()); // success

0 commit comments

Comments
 (0)