Having fun with ESDoc plugins

David Barral
Trabe
Published in
4 min readJun 25, 2018
Photo by Stefan Steinbauer on Unsplash

My team uses ESDoc to generate the documentation of JS projects. We use custom plugins to fit the generated docs to our needs. In this post I’ll share some of our plugins to show that the ESDoc output can easily be fine tuned.

To follow the examples it’s best to have some prior knowledge about how ESDoc plugins work. I wrote a post about this, but you can skip it an go into the examples if you feel confident enough.

Importing from the root package

ESDoc will generate a recommended import line for a method using the full path:

import {sum} from "awesome-math/src/sum.js";

In our code we prefer to reexport everything from the main entry point to avoid problems with future refactorings, so we encourage the use of:

import {sum} from ‘awesome-math’ 

We can fix the ESDOC output by creating a custom plugin that uses the onHandleDocs handler to rewrite the importPath of variables, functions and classes.

Disguise a variable as a function

ESDoc infers the documentation using the code’s AST. Only function expressions and declarations are considered functions. This will not play nicely when functions are wrapped by high order functions like curry.

To solve this we use a custom tag: function, to mark the code.

On the onHandleDocs step we look for the tag. If present, the doc entry is set to kind function, effectively fooling ESDoc. Notice that unsupported tags can be found in the doc.unknown array.

Injecting references

It’s useful to link external sources to the documentation but it’s tedious to write full urls each and every time we add a new link. To ease this, we use a plugin to inject references from a table in the code comments.

We grab the table via config at the onStart handler to modify the ESDoc comments of each source file using simple text replacement at onHandleCode.

Injecting code examples

Sometimes both code comments and tutorials use the same examples. By injecting this examples using a plugin we can share the code snippets. Also we can treat them as normal code so they can be linted, prettified and even executed.

We add examples to the source code by replacing text in the code comments as we did in the previous plugin. To handle the tutorial files we use onHandleDocs and replace text in the markdown files. We decorate the injected examples with comments in the source files and code fences in the tutorial markdowns.

Gotcha: dependencies

The examples plugin has a little problem. If you try it you’ll notice that it’s not working with the tutorials. The problem is subtle. The tutorial files are generated at runtime by the esdoc-integrate-manual-plugin (included in the esdoc-standard-plugin). Our plugin depends on the esdoc-integrate-manual-plugin but, depending on the execution order it may be executed before. To ensure the correct order we use another plugin.

Using the onHandlePlugins it’s possible to reorder the plugins collection to ensure that our custom plugins are executed after the ESDoc ones. Magic!

Adding markup to the layout: Google analytics

Sometimes the ESDoc generated markup must be modified. For example, adding extra markup, removing unneeded pieces, changing texts, translating, etc. In this case we want to track some publicly available docs using a Google Analytics Tracking code.

Using the onHandleContent handler we can modify the head tag and append the Analytics tracking snippet. The tracking code will be passed as a plugin option.

In this example we used a simple text replacement but I encourage you to use some library like cheerio if you are going to heavily modify the HTML.

Zipping the documents

Sometimes we distribute our documentation as a zip package. Instead of using a custom npm script, we can use a plugin to let ESDoc handle the zipping after generating all the documentation.

We use the onComplete handler for this task and rely on the archiver library to do the compression. The zip file is named using the package.json name an version keys.

Gotcha: your plugin is broken

If you play with the above examples or write your own plugins you can run into this error:

../esdoc-plugins-example/node_modules/esdoc/out/src/Util/InvalidCodeLogger.js:72const start = Math.max(error.loc.line — 3, 1);TypeError: Cannot read property ‘line’ of undefined

Do not despair, your plugin is broken. You just have a syntax or runtime error. ESDoc has some bugs and cannot output where the error is.

Sum up

The examples shown in this post can be tailored to fit your own needs. Most of them can be approached differently and implemented using other lifecycle steps. Just try new things and see what happens. With some effort the ESDoc output can be fine tuned and most of its shortcomings avoided.

--

--

David Barral
Trabe
Editor for

Co-founder @Trabe. Developer drowning in a sea of pointless code.