Building “.ignore” mechanism with 30 lines of code
Tags: javascript, programming, tutorial, beginners
Published: 2022-11-27 14:51:16

Recently we have seen `.Ignore` files a lot in many places, GitHub has `.gitignore` to ignore file that will not be committed also prettier `.prettierignore` to ignore files that will not be formatted and more others. So how can I build such a mechanism ?

**How it will work ?**

We will load the file and change all of it's content to `regex` so that we can make the comparing functionality more efficient.

**`fs` module**

We will be using `fs` module which is one of NodeJS core modules, `fs` have promises object which contains a promise version of core `fs` functions like `raedFile` and `writeFile` to help us work with `async/await` to make the code cleaner.

**Loading the file**

```
const fs = require("fs");
const loadIgnoreFile = async (file) => {
  let loadedFile = await fs.promises.readFile(path, { encoding: "utf8" });
};
```

**Change `*` to `.*` for pattern ignore**

In `.ignore` files, a person could want to ignore a pattern of files, for example all `*.json` files, but regex could understand * with a character before because * means that the preceding character can be repeater more than one time.
```
  //change all * to .*
  loadedFile = loadedFile.replace(/\*/g, ".*");
```


**File content to array**

```
  //change file to array
  loadedFile = loadedFile.split("\n");
```

**Resolve array items to paths**

For example, if a person wanted to ignore `dist` folder he could enter `dist`, `./dest` or `/dist` which can make the comparison operation more difficult. So we change what ever he entered to a full file path, so the three options of `dist` folder will be for example `/home/user/project/dist`.
```
  //resolve all files
  loadedFile = loadedFile.map((item) => join(resolve("."), item));
```

**Change paths to groups of regex**

A group in regex in something between two `()` for example (ABC) is a group. And then separate each group from other by or operator `|` and then to make the regex only restricted to that path we will add `^ $` to each regex path. So in our work if we have two paths, let us say `/home/user/project/dist` and `/home/user/project/node_mdules` they are at the end after converting them to regex will be `(^/home/user/project/dist&)|(^/home/user/project/node_mdules$)`

```
  //add (^filename$) to all content
  loadedFile = "(^" + loadedFile.join("$)|(^") + "$)";
```

**Returning the result in RegExp object**

```
  //change loaded file content to regex
  return new RegExp(loadedFile);
```

> We could also add some checks to see if the file exits and return a default regex if not before we go to all these steps.

**Final code**

```
const fs = require("fs");
const { resolve, join } = require("path");

//load ignore file
const loadIgnoreFile = async (  const path = ".ignore") => {
  const dfReg = "(.git$)|(node_modules$)";

  //check if .ignore exits
  const ptIgnoreExits = fs.existsSync(path);
  if (!ptIgnoreExits) return new RegExp(dfReg);

  //load .ignore
  let loadedFile = await fs.promises.readFile(path, { encoding: "utf8" });

  // add .git and node_modules to loaded file
  loadedFile += "\n.git\nnode_modules";

  //change all * to .*
  loadedFile = loadedFile.replace(/\*/g, ".*");

  //change .ignore to array
  loadedFile = loadedFile.split("\n");

  //resolve all files
  loadedFile = loadedFile.map((item) => join(resolve("."), item));

  //add (^filename$) to all content
  loadedFile = "(^" + loadedFile.join("$)|(^") + "$)";

  //change loaded file content to regex
  return new RegExp(loadedFile);
};

module.exports = loadIgnoreFile;
```

**Test it**

> This is a simple test and will not contain any test runners or any frameworks like jest or others

Create a file say `.ignore` and add to it some dummy names say `dist1` and `dist2` and put the `.ignore` along with this code in the same folder. Create a new file called `ignore.test.js` and import the `loadIgnore` function and run a function in `loadIgnore` called `test` since `loadIgnore` is actually a regex object as we see above, the `test` function will return a boolean value.

```
const loadIgnore = require('./loadIgnore.js');
const filePath = join(resolve("."), "dist1"))
console.log(loadIgnore.test(filePath));
```