OSD600 - Refactoring My SSG
Tags: opensource, git, rebase, amend
Published: 2021-10-15 06:46:46

#1. Lab5 requirement
As [my-ssg](https://github.com/hlavu/my-ssg) was updated with a lot of new features over the past few weeks and these features were written by different contributors, my-ssg's source code will  unavoidably contain duplicated logic, inconsistent naming conventions, etc...

This lab requires us to refactor the existing code so its structure and maintainability will be improved. Additionally, this is a good practice for using `git rebase` we have learned this week.

Here are some modifications I had applied to my-ssg:
 ![Applied modifications](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0qkab8ntpc49ci6yf1n.png)
 
#2. Refactoring process
First of all, I started looking at the `index.js` file where option declarations and input path validation are placed. This file seemed a bit *lengthy* back to the time so I decided to extract `checkInput()` and `trackDistFolder()` into a newly module.

Secondly, I realized that using *global variables* is **not necessary** and some *variable names and file names* are **not really good**. As a result, I changed global variables to scoped variables and renamed some variables/file names to get more meaningful names. 

During the refactor process, I encountered some errors and these errors made my **program exit inappropriately**. Therefore, whenever there is an error, I will display a log message and use `return` statement with a non-zero exit code to solve this situation. 

```
 try {
    await fsPromise.mkdir("./dist");
    console.log(chalk.bold.green("--- dist folder is created successfully! ---"));
  } catch (err) {
    console.log(chalk.bold.red("***Cannot create dist folder!***"));
    return process.exit(-1);
  }
```
Next, as I stated above, it is inevitable for the source code to not contain any logic repetition. Not surprisingly, I could find some here:

- Repeated logic and not clear variable names:
```
const sortedFile = files.filter((file) => path.extname(`${inputPath}/${file}`) === ".txt");

sortedFile.forEach((file) => { 
const fileName = fileModule.readFile(`${inputPath}/${file}`, cssLink, language, outputContainer);
const url = `./${encodeURI(fileName)}.html`;
body += `<a href=\"${url}\">${fileName}</a>\n`;
});

const sortedMDFile = files.filter((file) => path.extname(`${inputPath}/${file}`) === ".md");

sortedMDFile.forEach((file) => {
const fileName = fileModule.readFile(`${inputPath}/${file}`, cssLink, language, outputContainer);
const url = `./${encodeURI(fileName)}.html`;
body += `<a href=\"${url}\">${fileName}</a>\n`;
});

```

---> Solution: 
   ----> Create getBodyHTML(): 
```
function getBodyHTML(path, stylesheet, language, outputContainer, fileExtension){
  let fileName = fileExtension == ".txt" 
                 ? readFile(path, stylesheet, language, outputContainer) 
                 : readMDFile(path, stylesheet, language, outputContainer) ;
  let url = `./${encodeURI(fileName)}.html`;
  return `<a href=\"${url}\">${fileName}</a><br>\n`;
}
```

   ----> Rename variables:
```
const textFile = files.filter((file) => path.extname(`${pathToFile}/${file}`) === ".txt");
textFile.forEach((file) => {
      body += getBodyHTML(`${pathToFile}/${file}`, stylesheet, language, outputContainer, ".txt");
    });

 const mdFile = files.filter((file) => path.extname(`${pathToFile}/${file}`) === ".md");
    mdFile.forEach((file) => {
     body += getBodyHTML(`${pathToFile}/${file}`, stylesheet, language, outputContainer, ".md");
    });

```

- Since I just created the checkInput module, now I can use it after finishing reading a `.json` file instead of copying the same checking logic in `index.js` as before:

```
const fs = require("fs");
const check = require("./checkInput");

module.exports.readJson = (pathToFile) => {
  fs.readFile(pathToFile, "utf8", (err, json) => {
    if (err) {
      console.log(chalk.bold.red("***Cannot read the file!***"));
      return process.exit(-1);
    }
    const data = JSON.parse(json);

    const stylesheet = data.stylesheet || "https://cdn.jsdelivr.net/npm/water.css@2/out/water.css";
    const language = data.lang || "en-CA";

    check.checkInput(data.input, stylesheet, language, true);
  });
};
```

After all, my final commit is [92e007](https://github.com/hlavu/my-ssg/commit/92e007db2f50f22d3b7407c63e1cee614aa04c4e)

#3. Rebasing
Overall, `git rebase -i` is a very helpful command. It helped me to **squash** multiple commits into a single one. Meanwhile, `git commit --amend` allowed me to **adding** or **modifying** the commit message so it will be more meaningful and understandable.