DEV Community

Sam
Sam

Posted on • Edited on

Roll your own comments cleaner

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, 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 command that we use to execute an exported function from a JavaScript file somewhere in our directory. We’ll use it like this;

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

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.

// 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;  
  }
}
Enter fullscreen mode Exit fullscreen mode

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.


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

/**
 * My block style comment explaining important stuff
 * @param tag explaining the param stuff.
 * @return tag explaining the return stuff.
 */
Enter fullscreen mode Exit fullscreen mode

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

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.

    {
      "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.

Top comments (2)

Collapse
 
devorein profile image
Safwan Shaheer

What a wonderful article. That saved me a lot of time, thank you.
One suggestion could be to replace tns with tsc in Update section 1st item.

Collapse
 
mudlabs profile image
Sam

Cheers. At the time I was doing a lot of work with NativeScript, that’s probably why I wrote tns.