Skip to content

Commit

Permalink
Content updates (#2036)
Browse files Browse the repository at this point in the history
Closes #2021
  • Loading branch information
Chalarangelo authored Oct 6, 2023
2 parents f56dc2c + fb1b4d9 commit 36ba419
Show file tree
Hide file tree
Showing 21 changed files with 110 additions and 126 deletions.
2 changes: 1 addition & 1 deletion content/collections/js/node.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ description: >-
The Node.js snippet collection contains JavaScript utilities for Node.js
18.x. It includes helper functions related to server-side code and
filesystem operations, while general-purpose helpers can be found in the
JavaScript snippet collection.
JavaScript snippet collection. All snippets can be used with the ESM syntax.
shortDescription: >-
Discover a collection of server-side JavaScript utility functions for
Node.js 18.x.
Expand Down
2 changes: 2 additions & 0 deletions content/languages/javascript.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ references:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError
Boolean: >-
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean
Boolean(): >-
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/Boolean
Blob: https://developer.mozilla.org/en-US/docs/Web/API/Blob
console.assert(): https://developer.mozilla.org/en-US/docs/Web/API/console/assert
console.clear(): https://developer.mozilla.org/en-US/docs/Web/API/console/clear
Expand Down
7 changes: 6 additions & 1 deletion content/redirects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1906,4 +1906,9 @@
- from: /js/s/take-array-elements
to: /js/s/take-n-elements-from-array-start-or-end
status: 301!

- from: /js/s/is-even
to: /js/s/number-is-even-odd
status: 301!
- from: /js/s/is-odd
to: /js/s/number-is-even-odd
status: 301!
5 changes: 3 additions & 2 deletions content/snippets/js/s/convert-to-absolute-path.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ Converts a tilde path to an absolute path.
- Use `String.prototype.replace()` with a regular expression and `os.homedir()` to replace the `~` in the start of the path with the home directory.

```js
const untildify = str =>
str.replace(/^~($|\/|\\)/, `${require('os').homedir()}$1`);
import { homedir } from 'os';

const untildify = str => str.replace(/^~($|\/|\\)/, `${homedir()}$1`);
```

```js
Expand Down
4 changes: 2 additions & 2 deletions content/snippets/js/s/create-directory-if-not-exists.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Creates a directory, if it does not exist.
- Use `fs.existsSync()` to check if the directory exists, `fs.mkdirSync()` to create it.

```js
const fs = require('fs');
import { existsSync, mkdirSync } from 'fs';

const createDirIfNotExists = dir =>
!fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined;
!existsSync(dir) ? mkdirSync(dir) : undefined;
```

```js
Expand Down
4 changes: 2 additions & 2 deletions content/snippets/js/s/hash-node.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ Returns a promise.
- Use `setTimeout()` to prevent blocking on a long operation. Return a `Promise` to give it a familiar interface.

```js
const crypto = require('crypto');
import { createHash } from 'crypto';

const hashNode = val =>
new Promise(resolve =>
setTimeout(
() => resolve(crypto.createHash('sha256').update(val).digest('hex')),
() => resolve(createHash('sha256').update(val).digest('hex')),
0
)
);
Expand Down
2 changes: 1 addition & 1 deletion content/snippets/js/s/is-duplex-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const isDuplexStream = val =>
```

```js
const Stream = require('stream');
import Stream from 'stream';

isDuplexStream(new Stream.Duplex()); // true
```
21 changes: 0 additions & 21 deletions content/snippets/js/s/is-even.md

This file was deleted.

21 changes: 0 additions & 21 deletions content/snippets/js/s/is-odd.md

This file was deleted.

4 changes: 2 additions & 2 deletions content/snippets/js/s/is-readable-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const isReadableStream = val =>
```

```js
const fs = require('fs');
import { createReadStream } from 'fs';

isReadableStream(fs.createReadStream('test.txt')); // true
isReadableStream(createReadStream('test.txt')); // true
```
4 changes: 2 additions & 2 deletions content/snippets/js/s/is-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const isStream = val =>
```

```js
const fs = require('fs');
import { createReadStream } from 'fs';

isStream(fs.createReadStream('test.txt')); // true
isStream(createReadStream('test.txt')); // true
```
21 changes: 0 additions & 21 deletions content/snippets/js/s/is-travis-ci.md

This file was deleted.

4 changes: 2 additions & 2 deletions content/snippets/js/s/is-writable-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const isWritableStream = val =>
```

```js
const fs = require('fs');
import { createWriteStream } from 'fs';

isWritableStream(fs.createWriteStream('test.txt')); // true
isWritableStream(createWriteStream('test.txt')); // true
```
4 changes: 2 additions & 2 deletions content/snippets/js/s/json-to-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Writes a JSON object to a file.
- Use `fs.writeFileSync()`, template literals and `JSON.stringify()` to write a `json` object to a `.json` file.

```js
const fs = require('fs');
import { writeFileSync } from 'fs';

const JSONToFile = (obj, filename) =>
fs.writeFileSync(`${filename}.json`, JSON.stringify(obj, null, 2));
writeFileSync(`${filename}.json`, JSON.stringify(obj, null, 2));
```

```js
Expand Down
66 changes: 31 additions & 35 deletions content/snippets/js/s/nodejs-static-file-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ dateModified: 2022-06-05
One of the simplest beginner backend projects you can create is a static file server. In its simplest form, a static file server will listen for requests and try to match the requested URL to a file on the local filesystem. Here's a minimal example of that in action:

```js
const fs = require('fs');
const http = require('http');
import { readFile } from 'fs';
import { createServer } from 'http';

http.createServer((req, res) => {
fs.readFile(__dirname + req.url, (err, data) => {
createServer((req, res) => {
readFile(__dirname + req.url, (err, data) => {
if (err) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('404: File not found');
Expand All @@ -42,15 +42,15 @@ First and foremost, we don't necessarily want to serve files from the same direc
Here's a short snippet on how to resolve a file path using the `path` module:

```js
const fs = require('fs');
const path = require('path');
import { readFile } from 'fs';
import { join } from 'path';

const directoryName = './public';
const requestUrl = 'index.html';

const filePath = path.join(directoryName, requestUrl);
const filePath = join(directoryName, requestUrl);

fs.readFile(filePath, (err, data) => {
readFile(filePath, (err, data) => {
// ...
});
```
Expand All @@ -60,28 +60,26 @@ fs.readFile(filePath, (err, data) => {
Our next concern is security. Obviously, we don't want users prying around our machine unauthorized. Currently, it's not impossible to get access to files outside of the specified root directory (e.g. `GET /../../../`). To address this, we can use the `path` module again to check if the requested file is inside the root directory.

```js
const path = require('path');
import { join, normalize, resolve } from 'path';

const directoryName = './public';
const root = path.normalize(path.resolve(directoryName));
const root = normalize(resolve(directoryName));

const requestUrl = 'index.html';

const filePath = path.join(root, fileName);
const isPathUnderRoot = path
.normalize(path.resolve(filePath))
.startsWith(root);
const filePath = join(root, fileName);
const isPathUnderRoot = normalize(resolve(filePath)).startsWith(root);
```

Similarly, we can ensure that users don't get access to sensitive files by checking the file type. For this to work, we can specify an array or object of supported file types and check the file's extension using the `path` module once again.

```js
const path = require('path');
import { extname } from 'path';

const types = ['html', 'css', 'js', 'json'];

const requestUrl = 'index.html';
const extension = path.extname(requestUrl).slice(1);
const extension = extname(requestUrl).slice(1);

const isTypeSupported = types.includes(extension);
```
Expand All @@ -95,22 +93,22 @@ This is where things get a little tricky. To provide this functionality, we need
To implement this, we can use the `fs` module to check if one of them exists and handle things appropriately. A special case would also need to be added for the root url (`/`) to match it to the `index.html` file.

```js
const fs = require('fs');
const path = require('path');
import { accessSync, constants } from 'fs';
import { join, normalize, resolve, extname } from 'path';

const directoryName = './public';
const root = path.normalize(path.resolve(directoryName));
const root = normalize(resolve(directoryName));

const extension = path.extname(req.url).slice(1);
const extension = extname(req.url).slice(1);
let fileName = requestUrl;

if (requestUrl === '/') fileName = 'index.html';
else if (!extension) {
try {
fs.accessSync(path.join(root, requestUrl + '.html'), fs.constants.F_OK);
accessSync(join(root, requestUrl + '.html'), constants.F_OK);
fileName = requestUrl + '.html';
} catch (e) {
fileName = path.join(requestUrl, 'index.html');
fileName = join(requestUrl, 'index.html');
}
}
```
Expand All @@ -120,9 +118,9 @@ else if (!extension) {
After implementing all of the above, we can put everything together to create a static file server with all the functionality we need. I'll throw in a couple of finishing touches, such as logging requests to the console and handling a few more file types, and here's the final product:

```js
const fs = require('fs');
const http = require('http');
const path = require('path');
import { readFile, accessSync, constants } from 'fs';
import { createServer } from 'http';
import { join, normalize, resolve, extname } from 'path';

const port = 8000;
const directoryName = './public';
Expand All @@ -139,12 +137,12 @@ const types = {
xml: 'application/xml',
};

const root = path.normalize(path.resolve(directoryName));
const root = normalize(resolve(directoryName));

const server = http.createServer((req, res) => {
const server = createServer((req, res) => {
console.log(`${req.method} ${req.url}`);

const extension = path.extname(req.url).slice(1);
const extension = extname(req.url).slice(1);
const type = extension ? types[extension] : types.html;
const supportedExtension = Boolean(type);

Expand All @@ -158,25 +156,23 @@ const server = http.createServer((req, res) => {
if (req.url === '/') fileName = 'index.html';
else if (!extension) {
try {
fs.accessSync(path.join(root, req.url + '.html'), fs.constants.F_OK);
accessSync(join(root, req.url + '.html'), constants.F_OK);
fileName = req.url + '.html';
} catch (e) {
fileName = path.join(req.url, 'index.html');
fileName = join(req.url, 'index.html');
}
}

const filePath = path.join(root, fileName);
const isPathUnderRoot = path
.normalize(path.resolve(filePath))
.startsWith(root);
const filePath = join(root, fileName);
const isPathUnderRoot = normalize(resolve(filePath)).startsWith(root);

if (!isPathUnderRoot) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('404: File not found');
return;
}

fs.readFile(filePath, (err, data) => {
readFile(filePath, (err, data) => {
if (err) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('404: File not found');
Expand Down
40 changes: 40 additions & 0 deletions content/snippets/js/s/number-is-even-odd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: How can I check if a number is even or odd using JavaScript?
shortTitle: Check if a number is even or odd
type: question
language: javascript
tags: [math]
author: chalarangelo
cover: by-the-lighthouse
excerpt: Check if a number is even or odd using JavaScript using the modulo operator or bitwise AND operator.
dateModified: 2023-10-06
---

### Using the modulo operator

The modulo operator (`%`) returns the remainder of a division operation. Given that, we can check if a number is even or odd by dividing it by `2` and checking the remainder. If the remainder is `0`, the number is even, otherwise it's odd.

```js
const isEven = num => num % 2 === 0;
const isOdd = num => num % 2 === 1;

isEven(3); // false
isOdd(3); // true
```

### Using the bitwise AND operator

The bitwise AND operator (`&`) returns `1` if both bits are `1`, otherwise it returns `0`. The binary representation of an even number always ends with `0`, while the binary representation of an odd number always ends with `1`. As such, applying the bitwise AND operator to a number and `1` will return `0` for even numbers and `1` for odd numbers. In order to convert this result to a boolean, we can use the `Boolean()` function.

```js
const isEven = num => !Boolean(num & 1);
const isOdd = num => Boolean(num & 1);

isEven(3); // false
isOdd(3); // true
```

#### Notes

- While both approaches work, the modulo operator is more readable and should be preferred.
- Apart from these two approaches, other bitwise operators, such as the bitwise XOR operator (`^`), can also be used to check if a number is even or odd.
Loading

0 comments on commit 36ba419

Please sign in to comment.