souporserious

Better library DX using JSDoc links

3 min read

Documentation can often be hard to find. Getting lost searching for links to file issues or view examples is tedious. In this post, we look at automating helpful, quick links using JSDoc and Babel.

JSDoc is a format for annotating code that adds rich meta information. In a simple example, we can add a description for our function along with parameter and return types:

1/**
2 * Get the width for a single line of text
3 * @param {String} text - the string of text to be measured
4 * @return {Number} the width of the text passed in
5 */
6function getTextWidth(text) {
7 return context.measureText(text).width
8}

These annotations are used to generate documentation sites automatically. Even IDE’s like VS Code can utilize this information as you’re typing to provide the same rich documentation inline.

We can take things a step further by adding additional comments in our build step using Babel. If you’d like to follow along, there’s a complete example here using the utility above.

First, we’ll start by creating a simple Babel plugin with a visitor for all function declarations and get its leading comment and the position we want to insert the new comment at. We’ll determine this position by finding the first JSDoc tag (the @ symbol):

1module.exports = function () {
2 return {
3 name: 'add-comment',
4 visitor: {
5 FunctionDeclaration(path, state) {
6 const [leadingComment] = path.node.leadingComments
7 if (leadingComment) {
8 const lines = leadingComment.value.split('\n')
9 const endIndex = lines.findIndex((line) => line.startsWith(' * @'))
10 }
11 },
12 },
13 }
14}

Note, you can tailor this further to visit additional AST nodes like classes or JSX components. You would also want a better comment parser as this example is oversimplified.

Now we can work on sourcing additional helpful information. Similar to the last article, we can use our package.json as a source of truth for the repository URL. With this URL and Babel’s state of the current file, we can generate a direct link to this function’s GitHub source code:

1const { repository } = require('./package.json')
2
3module.exports = function () {
4 return {
5 name: 'add-comment',
6 visitor: {
7 FunctionDeclaration(path, state) {
8 const filePath = state.filename.split('src')[1]
9 const [leadingComment] = path.node.leadingComments
10 if (leadingComment) {
11 const lines = leadingComment.value.split('\n')
12 const endIndex = lines.findIndex((line) => line.startsWith(' * @'))
13 leadingComment.value = lines
14 .slice(0, endIndex)
15 .concat([
16 `* `,
17 `* [Edit on GitHub](${repository.url}blob/main${filePath})`,
18 `* `,
19 ])
20 .concat(lines.slice(endIndex, lines.length))
21 .join('\n')
22 }
23 },
24 },
25 }
26}

And that’s it! As a fun exercise, try using additional information from Babel to link directly to the line number (hint: the returned path should be helpful for this 😉).

Conclusion

We looked at how adding simple comments with some meta-information about our functions can significantly increase code usability and give developers the proper avenues for learning about our library code. Easy access to documentation makes it easier to report bugs, view examples, and get developers into the pit of success sooner!

Updated:
  • javascript
  • documentation
  • jsdoc
Previous post
Bundling TypeScript with Esbuild for NPM
Next post
Generate TypeScript Docs Using TS Morph
© 2022 Travis Arnold