Oct 18 '21 ~ 6 ~ 4 mins

Using Typescript to Auto-Generate Documentation

The public interfaces of AG Grid are ever-changing. How do we ensure that our documentation stays up to date?

As AG Grid is written in Typescript, we can leverage Abstract Syntax Trees to extract type definitions and JSDoc annotations. We then use these to auto-generate our documentation from the source code itself. In this way, our documentation stays up to date!

Interface Documentation

Throughout our documentation, to explain how to use different features we must reference grid methods and properties and their interfaces. This meant we had hardcoded many Interface definitions into our documentation so that these could be read.

However, over time, we noticed some were no longer accurate, as the underlying source code had been updated but the documentation version was missed. This is not a good user experience for you. We needed to come up with a better solution.

JSDoc Auto-Generated Sites

One potential option would be to use a JSDoc documentation generator. Unfortunately, this does not work so well if you want to merge the JSDoc output into a custom website. They are good when used in isolation but for AG Grid we wanted finer control.

Desired Solution

We want to be able to reference grid properties/interfaces by name and have these automatically rendered in our documentation. Any comments or additional notes would be applied in a single location via JSDoc attributes.

The benefits of this approach are:

  1. Documentation stays in sync with code.
  2. AG Grid developers are not manually updating documentation interfaces.
  3. JSDoc annotations will be accessible via IDEs giving developers access to the same definitions they would find in our documentation.

Read on to see how we achieved this.

Extracting Interface Definitions

The AG Grid documentation site is written in Gatsby and is a combination of Markdown and custom React components. With this setup it is convenient to access information from JSON files.If we can produce a JSON representation of our code interfaces then we will be able to extract the relevant definitions and transform it into Html via a custom component.

How do you take Typescript source files and extract all the interfaces to convert into JSON format?

The first step is to parse your code into an Abstract Syntax Tree (AST) via the Typescript method ts.createSourceFile. The output of this method is a tree representation of the code file, an AST.

const fs = require('fs');
const ts = require('typescript');

function parseFile(sourceFile) {
    const src = fs.readFileSync(sourceFile, 'utf8');
    return ts.createSourceFile('tempFile.ts', src, ts.ScriptTarget.Latest);
}

Abstract Syntax Trees

As an example, let's take a cut down version of the GridOptions interface and see how that parses. You might find it easier to interact with the example AST produced in this online Typescript AST Viewer.

AST of GridOptions

The AST is a tree structure that describes the code. We can traverse this tree looking for all the InterfaceDeclaration nodes and parse their children to extract the property definitions.

We convert this into a JSON file which looks something like the following. Note how we extract both the type and JSDoc annotation of each property.

  "GridOptions": {
    "meta": {},
    "type": {
      "rowData?": "any[] | null",
      "immutableData?": "boolean"
    },
    "docs": {
      "rowData?": "/** Set the data to be displayed as rows in the grid. */",
      "immutableData?": "/** Enables Immutable Data mode, for compatibility with immutable stores. */",
    }
  },

interface-documentation component

Once we have our interfaces in this format, we can load them into our React component. Our <interface-component> takes the name of the interface and looks it up from the reference file. It then formats the properties into a table.

<interface-documentation interfaceName='GridOptions' ></interface-documentation>

This results in the following.

Result of interface-documentation component When writing the documentation we also have the tools to supplement the <interface-component> with additional details, such as the 'See More' link or default values, as seen with the immutableData property.

Expandable Interface Details

Another feature we support via our <interface-component> is providing an expanding detail view for properties that reference other interfaces. In this way, we can bring detailed type information in a concise manner to our documentation. This can be especially useful when documenting the grid callbacks as they often receive parameters and return complex objects.

We are now able to accurately describe the properties for both inputs and outputs and guarantee that they will stay up to date if we change either of these interfaces in the source code. Another major benefit, of this new approach, is that we are using the real interface names which you can use in your implementations. (In previous versions of the documentation dummy names were used which did not correspond to exported interfaces that you could find in our code.)

Example of typed callback

Conclusion

As AG Grid developers, we love working with this new tool and have removed lots of duplicated / outdated interface definitions from our documentation. As a user, you should find that our documentation is accurate and will stay up to date going forward.

You will also notice, if you upgrade to the latest version, that the same definitions are directly available in your IDE due to us adding the JSDoc annotations. So you may not even need to visit the improved documentation in the first place!

As for now we will continue to work hard to ensure our documentation is the best it can be to help you get the most out of AG Grid.

Learn more about AG Grid's Angular Support here.


Headshot of Stephen Cooper

Hi, I'm Stephen. I'm a senior software engineer at AG Grid. If you like my content then please follow / contact me on 🦋 Bluesky or 𝕏 (X) and say hello!