Lint markdown

code • June 5, 2021

At Mapbox, we write a majority of documentation in markdown. We have a suite of markdown linters to help us stay consistent and improve the quality of our documentation.

Our suite includes remark plugins to lint markdown. We have built our own plugins and use many from the community:

When reviewing content, it’s easy to forget to check that links work and since it can be automated, you shouldn’t have to do it.

Our link checker:

I’m only scratching the surface with the intricacies of our link checker and for that reason our linter in private. Our linter is based off of David Clark’s remark-lint-no-dead-urls.

Assert frontmatter

For SEO, we assert that every page has a title and description that will be used by the title and meta description elements in the page’s head. We also assert:

We have several more properties that we assert that can disable or enable features on the page.

Lint JSX in markdown

Our static site generator, Batfish, uses jsxtreme-markdown to transform markdown into React components. This means that many our of markdown pages include JSX syntax.

We had difficulty with catching JavaScript errors in the embedded markdown files. This resulted in failed builds with cryptic error messages. We then had the idea to build a remark linter that will parse the markdown files with jsxtreme-markdown and then run eslint using the Node.js API on each file.

Our linter, affectionately known as xtreme-linter, will:

I love all our linters, but this one the most.

Check variables

Since we can use JSX in markdown, we also use variables for repeated information like access tokens and version numbers. We built a remark-linter that will scan markdown pages for variables and then assert that the variable exists in the repository’s local constants.json file.

We developed a remark linter, remark-lint-link-text, that warns against non-descriptive link text. The linter warns against the following link text:

Improve accessibility

Our newest remark linter helps check that all iframe elements and our React component DemoIframe have a title attribute and all img elements and our React component AppropriateImage have an alt attribute. While remark linters already exist to find missing alt text like remark-lint-no-empty-image-alt-text and @double-great/remark-lint-alt-text, we needed to extend it to our React components since we use them in our markdown files.

Assert heading level increment

Another remark linter that we love is remark-lint-heading-increment. This linter asserts that headings are always in order. This is especially helpful for longer pages and pages with a lots of sections.

A shared remark configuration

Finally, we bundle all the remark linters into a shared remark configuration. The shared configuration prevents us from having to repeat code in every repository and help streamline updates.

These linters help guide our contributors to writing better documentation and allows our team to focus more closely on the content during reviews.

Keep reading code