And so, I wrote my own Typescript Documentation Generator...
Tags: typescript, node, documentation, news
Published: 2021-01-08 00:57:24

TL;DR: For a project [fussel178](https://github.com/fussel178) and I ([pklaschka](https://github.com/pklaschka)) were working on, we needed a documentation generator for a Typescript Monorepo. 

## The "Status Quo"
While the existing solution, TypeDoc, is a great tool, it didn't really fit our needs, and documentation on how to customize the output isn't easy to come by. Don't get me wrong: It's a great project that does a lot more than my own solution, but it simply didn't fit our project's needs. Still, for many projects, it works great, and I can highly recommend checking it out:

{% github Typestrong/typedoc no-readme %}

## So... let's build it ourselves :stuck_out_tongue_winking_eye:
After spending a day searching for alternatives (unsuccessfully), I decided to "just" build my own solution. And thus, *fliegdoc* found its beginning :wink:

{% github fliegwerk/fliegdoc %}

## What *fliegdoc* is
*fliegdoc* documents only the exported members (!) of a TypeScript library, i.e., one or more (in the case of a monorepo) npm packages.

It first converts the source file's AST to a kind of "documentation-ready" AST, which then gets passed to a theme, converting it to HTML (but, if the theme gets adjusted, also any other format).

The generated web page then includes the project's root `README.md`, and the API References for the project's modules, i.e., packages.

Therefore, it can very easily be used to document mono-repo structures, including more than one package.

### Demo
Since the project's exposed APIs themselves are documented using the project itself, you can visit the [project documentation](https://fliegwerk.github.io/fliegdoc/) to see the generated results.

### How to use it
Let's consider a Lerna-based monorepo with (for simplicity) two packages, resulting in a folder structure that looks something like this:

```
.
├── packages/
│   ├── package-1/
│   │   ├── src/
│   │   │   └── main.ts
│   │   ├── package.json
│   │   └── tsconfig.json
│   └── package-2/
│       ├── src/
│       │   └── main.ts
│       ├── package.json
│       └── tsconfig.json
├── package.json
├── lerna.json
├── README.md
└── tsconfig.json
```

Since *fliegdoc* generates the documentation for the entire repository, we add `fliegdoc` as a `devDependency` of the root `package.json`:

```sh
$ npm i -D fliegdoc
```

Next, we add two scripts in our root `package.json`:

```json
{
  "scripts": {
    "docs:build": "fliegdoc build",
    "docs:serve": "fliegdoc serve"
  }
}
```

If our repository followed an easy structure, with just one root `tsconfig.json`, `package.json`, `README.md`, and a `main.ts` in a root `src` folder, that all we'd need to do. However, we are within a monorepo that ... makes things a bit more complicated.

> "Things should be made as simple as possible but not any simpler" (Albert Einstein)

To configure *fliegdoc* to work with this repo structure, we create a `fliegdoc.config.js`:

```js
module.exports = {
  modules: [
    {
      package: "./packages/package-1/package.json",
      tsconfig: "./packages/package-1/tsconfig.json",
      mainFile: "main.ts",
    },
    {
      package: "./packages/package-2/package.json",
      tsconfig: "./packages/package-2/tsconfig.json",
      mainFile: "main.ts",
    },
  ]
};
```

While we *could* configure many other parameters, we can already successfully generate the documentation for the repo with this config.

{% details Further configuration options %}
Among others, see https://fliegwerk.github.io/fliegdoc/fliegdoc/#FliegdocConfig for a full reference:
- `readme = './README.md'`: The path to the repo's `README.md`
- `outDir = './docs'`: The directory into which the docs get generated
- `baseUrl = '/'`: the root URL of the documentation. Useful when you want to deploy your projects to subdirectories on your server, e.g., on GitHub pages (where `/[repo-name]/` gets prefixed to the URL, compared to `/`).
{% enddetails %}

We can now run

```sh
$ npm run docs:serve
```

*fliegdoc*, when running `fliegdoc serve`, does a few things:

1. Read the config and apply its overrides to the default configuration
2. Go through the modules specified in the config and parse the exported members of their `mainFile`
3. Build a "documentation-ready syntax tree", consisting only of abstracted elements interesting for the docs, from the parsed AST
4. Serve a site that consists of pages for
   - the project's `README.md`
   - API references for the `modules`

When instead of `docs:serve`, we run the `docs:build` script, the only difference will be that in step (4.), the site won't just be served on an HTTP server, but instead, the HTML files get built and outputted to a folder `./docs`, which then can get deployed to, e.g., GitHub Pages, Netlify, or a "classic" web server.

## What *fliegdoc* isn't
It isn't an "all-around" documentation generator for Typescript. It specializes heavily (!) in documenting package modules and has a focus on being easy to understand (the "basic" project was developed in only one day).

## Conclusion
While the project is still in a rather early stage of development, and documentation is, right now, WIP (the irony :rofl:), it already serves its purpose in multiple of my own projects, without problems.

Perhaps, its use-case also fits your project, in which case, please feel free to share any feature requests should you decide to use it.

It was certainly interesting to dive a bit deeper into the ASTs and other "lower-level" Typescript things apart from everything else.

## Author
{% user pklaschka %}

Pablo Klaschka is the first chairman and co-founder of fliegwerk, a group of students developing Open-Source projects.