Skip to content
Permalink
Browse files
Updated ESLint and JSDoc Exercise
The exercise was unclear.

Exercise is now based on the todo files which have been updated
  • Loading branch information
aa7401 committed Oct 12, 2019
1 parent a43b857 commit 9b23edb60ae797a6ec4ef3ea70ca1e2911982783
Show file tree
Hide file tree
Showing 22 changed files with 330 additions and 446 deletions.
@@ -53,6 +53,7 @@
"no-var": 2,
"prefer-arrow-callback": 1,
"prefer-const": 2,
"prefer-template": "error",
"quotes": [1, "single"],
"semi": [1, "never"],
"space-before-blocks": ["error", { "functions": "always", "keywords": "always", "classes": "always" }],
@@ -8,6 +8,7 @@ coverage/
docs/
sessions/
screenshots/*
out/

# sqlite databases
# *.db
@@ -56,22 +56,22 @@ The custom object prototype defined in the `list.js` module already contains the

Now much of the business logic has been moved to the separate module, are there any module imports in `index.js` that are no longer needed? Locate these and delete.

## 2 Linting
## 3 Linting

When using a language as flexible as JavaScript which contains so many legal (but terrible) features, it is important to use a linter. This will check your code against a set of rules. These ensure:

1. You are not using what are considered bad language features.
2. You are implementing optional syntax (such as indentation and semicolons) in a consistent manner.
3. You are writing code that is easy to maintain.

If you look over both your `index.js` and `accounts.js` files you should be feeling pretty comfortable that you are already writing clean, consistent and maintainable code, lets see how good your code really is!
Locate the `06_code_quality/todo/` directory and study the `index.js` file. You should be feeling pretty comfortable that you are looking at clean, consistent and maintainable code, lets see how good your code really is!

You should start by ensuring you have installed `eslint` which is considered the industry standard and that you have a copy of the approved configuration file `.eslintrc.json` in the root directory of your project. You can find this in the `TEACHING-MATERIALS` repository but make sure you take a copy of the latest version from the master repository!
You should start by ensuring you have installed `eslint` which is considered the industry standard and that you have a copy of the approved configuration file `.eslintrc.json` in the root directory of your project.

Try running the linter on your `index.js` routes file:
Now navigate to the `06_code_quality/` directory using terminal and run the linter on the `index.js` code in the `todo/` directory:

```shell
$ node_modules/.bin/eslint index.js
$ node_modules/.bin/eslint todo/index.js
```

You will see a list of issues that the linter has flagged in your code. Notice that some of these are flagged as errors (serious) and some as warnings (recommendations). Each message includes:
@@ -85,38 +85,38 @@ The latter can be used to quickly look up the rules in the [comprehensive docume
Instead of running separate checks on every file, we can specify the directory we want to check and it will automatically scan all the subdirectories. For example to scan all the files in the `modules/` directory we could run:

```shell
$ node_modules/.bin/eslint modules/
$ node_modules/.bin/eslint todo/
```

### 2.1 Test Your Understanding
### 3.1 Test Your Understanding

1. How could you run the linter to scan _all_ the files in your project (HINT: you need to start scanning in the _current directory_)?
2. Now you should locate and fix all the errors and warnings in your code.
3. If you are using VS Code, install `eslint` globally and then install the [eslint extension](https://github.com/Microsoft/vscode-eslint). After restarting your editor you should see any errors and warnings flagged in the editor.
1. Locate and fix all the errors and warnings in the `index.js`.
2. Install `eslint` globally and then install the [eslint extension](https://github.com/Microsoft/vscode-eslint). After restarting your editor you should see any errors and warnings flagged in the editor.
3. Use the `eslint` plugin to locate and fix all the errors in the `modules/list.js` file.

## 3 Documentation
## 4 Documentation

In this third and last topic we will be using the [JSDoc](http://usejsdoc.org) tool to build a detailed code documentation website by extracting special comments inserted into our source code.

The default set of documentation tools provided in JSDoc are not suitable for documenting Koa routes and so we will be using a plugin called [jsdoc-route-plugin](https://www.npmjs.com/package/jsdoc-route-plugin). This should have been installed by the package manifest however you should check that you are using the current version of the `package.json` file and update if needed, rerunning the `npm install` command to ensure all packages are installed. You should also check that you have the latest version of the `jsdoc.conf` configuration file.

Now everything is installed we can run the `jsdoc` tool to generate our documentation.
Now everything is installed we can run the `jsdoc` tool on the project in the `todo/` directory which will generate our documentation. The `-d` destination flag tells the tool where to save the documentation.

```shell
$ node_modules/.bin/jsdoc
$ ./node_modules/.bin/jsdoc -d ./docs/jsdoc/ modules/*
```

If you run this command you should see a new directory called `docs/` which will contain a `jsdoc/` directory. Inside this you will see some website files, opening the `index.html` file in your browser you should see the documentation pages for your website!

### 3.1 Test Your Understanding
### 4.1 Test Your Understanding

You will probably have noticed that only a couple of the functions include complete JSDoc comments and so the documentation website is incomplete. Your task is to use the existing comments for guidance and complete the task of documenting your code. You will find the [JSDoc](http://usejsdoc.org) and [jsdoc-route-plugin](https://www.npmjs.com/package/jsdoc-route-plugin) documentation helpful.

## 4 Improved Async Code
## 5 Improved Async Code

Since NodeJS has a single thread that handles all incoming requests it is vital that we push long-running tasks into their own threads, typically through the use of _callback functions_. In this section of the lab you will learn about the limitations of callbacks and explore more powerful ways to handle multi-threading.

## 4.1 Nested Callbacks
## 5.1 Nested Callbacks

Because the code to be run after a callback is run needs to be _inside_ the callback code it is very challenging to build a script that contains several long-running tasks you get into a situation where you nest callbacks inside callbacks (inside callbacks) which makes the code very difficult to write, debug and read and means its very difficult to split into separate functions, a situation commonly known as **Callback Hell**.

@@ -129,7 +129,7 @@ Open the file `nestedCallbacks.js` which asks for a _base_ currency code then pr

Callbacks are the simplest possible mechanism for asynchronous code in JavaScript. Unfortunately, raw callbacks sacrifice the control flow, exception handling, and function semantics familiar from synchronous code.

### 4.1 Test Your Knowledge
### 5.2 Test Your Knowledge

The callbacks are already nested 3 deep. To test your knowledge of deeply nested callbacks you are going to create a script that has 6 levels of nested callbacks!

@@ -1,115 +1,56 @@
#!/usr/bin/env node

/**
* Routes File
*/

'use strict'

/* MODULE IMPORTS */
const bcrypt = require('bcrypt-promise')
const Koa = require('koa')
const Router = require('koa-router')
const views = require('koa-views')
const staticDir = require('koa-static')
const stat = require('koa-static')
const bodyParser = require('koa-bodyparser')
const koaBody = require('koa-body')({multipart: true, uploadDir: '.'})
const session = require('koa-session')
const sqlite = require('sqlite-async')
const fs = require('fs-extra')
const mime = require('mime-types')
//const jimp = require('jimp')

/* IMPORT CUSTOM MODULES */
const User = require('./modules/accounts')
const handlebars = require('koa-hbs-renderer')

const app = new Koa()
const router = new Router()

/* CONFIGURING THE MIDDLEWARE */
app.keys = ['darkSecret']
app.use(staticDir('public'))
app.use(stat('public'))
app.use(bodyParser())
app.use(session(app))
app.use(views(`${__dirname}/views`, { extension: 'handlebars' }, {map: { handlebars: 'handlebars' }}))
app.use(handlebars({ paths: { views: `${__dirname}/views` } }))
app.use(router.routes())

const port = 8080

const defaultPort = 8080
const port = process.env.PORT || defaultPort
const dbName = 'website.db'
const saltRounds = 10
const todo = require('./modules/todo')

/**
* The secure home page.
*
* @name Home Page
* @route {GET} /
* @authentication This route requires cookie-based authentication.
*/
router.get('/', async ctx => {
try {
if(ctx.session.authorised !== true) return ctx.redirect('/login?msg=you need to log in')
const data = {}
if(ctx.query.msg) data.msg = ctx.query.msg
await ctx.render('index')
data.items = todo.getAll()
ctx.render('home', data)
} catch(err) {
await ctx.render('error', {message: err.message})
console.log(err.message)
ctx.render('home', {msg: err.message})
}
})

/**
* The user registration page.
*
* @name Register Page
* @route {GET} /register
*/
router.get('/register', async ctx => await ctx.render('register'))

/**
* The script to process new user registrations.
*
* @name Register Script
* @route {POST} /register
*/
router.post('/register', koaBody, async ctx => {
router.post('/', ctx => {
try {
// extract the data from the request
const body = ctx.request.body
console.log(body)
const {path, type} = ctx.request.files.avatar
// call the functions in the module
const user = await new User(dbName)
await user.register(body.user, body.pass)
// await user.uploadPicture(path, type)
// redirect to the home page
ctx.redirect(`/?msg=new user "${body.name}" added`)
todo.add(body.item, body.qty)
ctx.redirect('/')
} catch(err) {
await ctx.render('error', {message: err.message})
console.log(err.message)
ctx.redirect(`/?msg=${err.message}`)
}
})

router.get('/login', async ctx => {
const data = {}
if(ctx.query.msg) data.msg = ctx.query.msg
if(ctx.query.user) data.user = ctx.query.user
await ctx.render('login', data)
})

router.post('/login', async ctx => {
router.get('/delete/:key', ctx => {
try {
const body = ctx.request.body
const user = await new User(dbName)
await user.login(body.user, body.pass)
ctx.session.authorised = true
return ctx.redirect('/?msg=you are now logged in...')
console.log(`key: ${ctx.params.key}`)
todo.delete(ctx.params.key)
ctx.redirect('/msg=item deleted')
} catch(err) {
await ctx.render('error', {message: err.message})
console.log(err.message)
ctx.redirect(`/${err.message}`)
}
})

router.get('/logout', async ctx => {
ctx.session.authorised = null
ctx.redirect('/?msg=you are now logged out')
})

app.use(router.routes())
module.exports = app.listen(port, async() => console.log(`listening on port ${port}`))
module.exports = app.listen(port, () => console.log(`listening on port ${port}`))
@@ -0,0 +1,20 @@

'use strict';

module.exports = {
displayName: 'test',
verbose: true,
collectCoverage: true,
coverageThreshold: {
global: {
branches: 0,
functions: 0,
lines: 0,
statements: 0
}
},
testPathIgnorePatterns: [
'/node_modules/',
'/__tests__/fixtures/',
]
}

This file was deleted.

This file was deleted.

@@ -0,0 +1,26 @@

'use strict'

let data = []

module.exports.clear = () => {
data = []
}

module.exports.add = (item, qty) => {
qty = Number(qty)
if(isNaN(qty)) throw new Error('qty must be a number')
data.push({item: item, qty: qty})
}

module.exports.getAll = () => {
for(const key in data) data[key].key = key
return data
}

module.exports.delete = key => {
console.log(`delete key ${key}`)
return
}

module.exports.countItems = () => data.length

0 comments on commit 9b23edb

Please sign in to comment.