Roll your own comments cleaner
Tags: npm, node, javascript, typescript
Published: 2020-03-31 01:34:17

---
title: Roll your own comments cleaner
published: true
description: How to write and implements a basic file editor in Node.
tags: NPM, Node, JavaScript, TypeScript
---

##### [Update](#update) - You actually don't need to do this. But it's still probably worth knowing for non-TypeScript projects, or other file manipulation.

If you need to strip comments from your code before publishing a package, or pushing to production, you might be inclined to spin up **Gulp**, or install an **NPM** dependency to do the work for you. But you may not need to.

It’s actually quite easy! _(once you know how)_

I recently had the need while building an NPM package. The project is written in [TypeScript](https://www.typescriptlang.org/), and the problem arose when I needed to specify the `compilerOptions` for the TypeScript compiler _(funnily enough)_.

When you’re ready to compile your TypeScript you’ll run the `tsc` command, or something that ends up calling `tsc`. When that runs TypeScript looks for a `tsconfig.json` file. In this file you can specify that comments should be removed. 

End of story right, we need comments removed and that’s what `removeComments` does. Note so fast.

The problem with `removeComments` is the comments _(a.k.a documentation)_ are not only removed from the generated JavaScript files, but also the declaration files. This might not always be a problem. But for me it was. I didn’t want the comments in the JavaScript, but keeping them in the declaration file is part of the projects documentation strategy.

So, what do we need? 
1. We need to run `tsc` and compile our code.
2. Grab the compiled JavaScript file and remove all the comments.

This is a small project with no dependencies. So it seems, shall we say... undesirable to add Gulp or what-not for this little task. But how else do we do it? 🤔

---

### Here’s what I learned.

The Node-CLI has a [print](https://nodejs.org/api/cli.html#cli_p_print_script) command that we use to execute an exported function from a JavaScript file somewhere in our directory. We’ll use it like this;

```json
/** package.json **/
{
 ...
 "scripts": {
    "prepare": "tsc && node -p \"require('./cleaner').clean()\""
 }
 ...
}
```

When I call `npm run prepare` in the terminal the TypeScript compiler _(tsc)_ will fire, and then node will look for a file called **cleaner.js** at the same directory level as **package.json**. If it finds one, it will attempt to call an exported function named **clean**.

Lets add the **cleaner** file, and export the **clean** function. 

```javascript
// cleaner.js

const fs = require(“fs”); // comes with node.

module.exports.cleaner = function () {
  try {
    let file, data, nocomments;
    const filePath = "dist/index.js";
    const regex = new RegExp(/((^\/\*\*\n(\D\W.+\n)+))/, "gm");

    fs.accessSync(filePath, fs.constants.F_OK);
    
    file = fs.openSync(filePath, "r+", fs.constants.O_RDWR);
    data = fs.readFileSync(file, "utf8");
    nocomments = data.replace(regex, "");
    
    fs.writeFileSync(filePath, nocomments);
    return "Comments Removed";
  } catch (error) {
    return error;  
  }
}
```

**And that's it!**

When the `clean` function executes it locates our newly generated JavaScript file, reads in its content, replaces all the comments with _nothing_, and then writes the new version back to file.

There's probably a bit going on here you're not familiar with; what's all this `fs` stuff? I didn't know either. But I found this good post that explains it all, so I'll point you there.

 - [Node.js File System API, Beginner Friendly Guid](https://areknawo.com/node-js-file-system-api-beginner-friendly-guide/)
 - Oh, and [NPM: Short Scale Units](https://www.npmjs.com/package/short-scale-units), incase you give any **F**_s_ about my little project.

---

This is a pretty specific solution. I now all the comments are block style, so the `RegExp` has been designed to match that pattern.

```javascript
/**
 * My block style comment explaining important stuff
 * @param tag explaining the param stuff.
 * @return tag explaining the return stuff.
 */
```

And I know the compiler will output an `index.js` file to a generated `dist/` directory. But I think this gives a good outline of the type of solution you have available, with no added dependencies.

---

### Update

##### [Thanks to these Redditors](https://www.reddit.com/r/typescript/comments/frj1hn/when_compiling_can_you_specify_that_you_want/?utm_source=share&utm_medium=web2x)

I since learned how to get the same desired outcome for a TypeScript project without needing to roll your own comments remover.

The `tsconfig.json` file has an available property named `extends`. We can use that and the command chaining we already used here to remove the comments from the output JavaScript, but leave them in the declaration files.

1. We'll change our run command in **package.json** to
    ```
    "prepare": "tsc && tsc -p ./tsconfig.nocomments.json"
    ```

2. We'll create the new config file, and extend it from the main `tsconfig`.
    ```json
    {
      "extends": "./tsconfig.json",
      "compilerOptions": {
        "declaration": false,
        "removeComments": true
      }
    }
    ```

The main, default `tsconfig` file runs first generating declaration and JavaScript files with comments in place. Then our next call to `tsc` specifies a path to the new config file _(`tsconfig.nocomments`)_, and that one does not create a new declaration file, but does create a new JavaScript file with _no_ comments; which replaces the existing file.


So while you don't need to _roll your own comments cleaner_ in a TypeScript project, the strategy outlined here can still be used for non TypeScript projects, or to do some other manipulation of a files content.