New branches growing from the tree!
Tags: opensource
Published: 2020-10-08 04:09:59

## Introduction
Lately, I have been working on my newly-built CLI [link-checker-tool](https://github.com/phast184/link-checker-tool) which allows us to display the status of all URLs in a file or to check whether a single URL is available or not. However, I would like to add more features to my CLI to improve it more for users. 

## _[Add -j, --json flag to output json format result of an URL ](https://github.com/phast184/link-checker-tool/issues/8)_
To be honest, it seems a pretty good idea for a feature to add. Moreover, the idea to implement the feature is not difficult at all. Here is how I did it.
#### Firstly, let's add the flag in yargs
```
.alias('j', 'json')
.nargs(['f', 'u', 'a', 'j'], 1)
//...
.describe('j', 'Output json result of an URL')
```
#### Secondly, we need to implement a function that takes an URL as a parameter and output JSON format

```
const jsonResult = async (url) => {

    let result = {
        url: url,
        status: ''
    }
    try{
        const response = await axios.head(url);
        result.status = response.status;
    }
    catch(err)
    {
        if (err.response)
        {
            result.status = err.response.status;
        }
        else{
            result.status = 'unknown';
        }
    }
    console.log(result);
}
```

I will explain a bit about the concept I did here:
1. Since the ouput must be json format, we have to create a `result` object.
2. We use an error handler here to help our app avoid being crashed if there is any error.
3. Call a header request from `axios`. If the request is successful, `result.status = response.status;`
4. if there is error happening and the `err.response` is not empty, `result.status = err.response.status;`
5. Otherwise, set `result.status = 'unknown';`

## _[Add --all, --good, and --bad flags. ](https://github.com/phast184/link-checker-tool/issues/9)_

The idea is when reading a file, if we put a `--good` or `--bad` flag, it will display only good/bad URLs according to the flag we input. And `--all` is the default flag which help output all the valid URLs in a file.

#### Like we did above, we have to add those flags first
```
//...
.alias('g', 'good')
.alias('b', 'bad')
.alias('a', 'all')
//...
```

#### Next, I need to modify my `checkURL` function a bit

```
const checkURL = async (url, flag = "all") => {
    try {
        const response = await axios.head(url);
        if ((flag == "all") || (flag == "good"))
            console.log(chalk.green("[GOOD]" + "[" + response.status + "]" + " " + url))
    }
    catch (err) {
        if (err.response) {
            if (err.response.status == 404 || err.response.status == 400) {
                if ((flag == "all") || (flag == "bad"))
                    console.log(chalk.red("[BAD]" + "[" + err.response.status + "]" + " " + url))
            }
            else
                if (flag == "all")
                    console.log(chalk.gray("[UNKOWN]" + "[" + err.response.status + "]" + " " + url))
        }
        else {
            if (flag == "all")
                console.log(chalk.gray("[UNKOWN][ENOTFOUND] " + url));
        }
    }
}
```
_Explanation:_
1. I have added a second parameter `flag = "all"` which show the option of the flag `good`, `bad`, `all`, while `all` is the default one.
2. Since `all` output all valid URLs in the file, we have to set it for all conditions.
3. Under a `good`/ `bad` condition only prints out good/bad URLs  

#### Lastly, change `handleArgument` a bit.
```
const handleArgument = (argv) => {
//...
 else if (argv.f || argv.all || argv.good || argv.bad) {
        let fileName = argv.f || argv.a || argv.good || argv.bad;
        console.log(fileInteraction(fileName, argv))
        for (i = 0; i < argv._.length; i++) {
            fileInteraction(argv._[i], argv)
        }
//...
}
```
1. Since `all`, `good`, `bad`, `f` technically do the samething, I put them all as one condition.
2. `let fileName = argv.f || argv.a || argv.good || argv.bad;`