Validate Markdown Files With MarkdownLint

Validate Markdown Files With MarkdownLint

How do you know that your Markdown content is valid? You use MarkdownLint! In this post, I step through how to install, configure, and use it, as well as how to use one-time rule overrides.


Before we dive in, I need to set the scene. When writing technical documentation, as with writing code, you need to use a range of tools to maintain a high level of quality. In this series, I’m going to introduce you to 4 tools that help you do just that. Each of them is usable from the command-line, whether manually or as part of your documentation build pipeline.

Whether you’re just starting as a technical writer, taking over from someone else, coming on to an existing team, or you’re a seasoned technical writing pro, you’ll have a further 5 tools to help you ensure that the quality of the documentation that you produce is of the highest possible quality.

In this 4-part series, I’m starting, by covering MarkdownLint, as Markdown is arguably the most prolific writing format used today. It might seem strange to start with Markdown, as it’s not as feature-rich as other formats, such as AsciiDoc, reStructuredText, or DocBook.

However, it has several advantages going for it. These include:

  1. It’s a format that is pretty trivial to learn
  2. It’s supported by a significant number of tools and services, including WordPress, GitHub, GitHub Pages, JetBrains, Octopress, Jekyll, and Ghost.

Sure, as Eric Holscher (the Read the Docs and Write the Docs lead) well says, it’s not a format that you want to use long-term for technical writing. However, it’s likely one that lets you get up and running quickly until you’re ready to migrate to something more suitable. So for those reasons, that’s why I’m starting with it.

What is Markdown Lint?

Written in Ruby, Markdown Lint is self-described as:

A tool to check markdown files and flag style issues.

It is distributed as a Ruby gem, and it can lint both individual as well as nested directories of Markdown files for compliance with a documented set of 38 rules. These rules cover most of the aspects of Markdown compliance that you would expect, such as:

  • Code block styles
  • Headers
  • Inline HTML
  • Line length
  • List styles
  • Multiple headers with the same content; and
  • Trailing spaces

I’ve been using it for a little while now, as part of my work managing the ownCloud documentation, after I realised that I didn’t have a tool for linting the project’s Markdown files. While most of the documentation is written in AsciiDoc and runs on the Antora platform, there are still a number of Markdown files, and these need to be checked as well.

They include the README file in each repository, along with the documentation which helps users get started and understand the project (among a series of other tasks).

I’m not sure why I hadn’t added a Markdown Lint to the toolchain earlier. Perhaps it was just a case of a simple oversight. The reason that I added it was that I needed to change the structure of one of the Markdown documents and wanted to be sure that the changes I was making were structurally correct.

It then occurred to me that having a Markdown linter would be handy for checking the remainder of the Markdown documents as well. That’s when I went looking and found Markdown Lint on GitHub.

There’s not much to it, which can be either an advantage or disadvantage, depending on your position.

How to Install It

Installing it is, relatively, trivial. If you have a reasonably recent Ruby installation on your development machine, installing Markdown Lint only requires you to run gem install mdl. This command installs it in your system path.

How to Run It

With it available, you can then lint individual files by running the following command:

mdl <path/to/your/markdown/file.md>

The command will display console output similar to the following:

docs/build-the-docs.md:8: MD013 Line length
docs/build-the-docs.md:14: MD013 Line length
docs/build-the-docs.md:29: MD013 Line length
docs/build-the-docs.md:16: MD024 Multiple headers with the same content
docs/build-the-docs.md:158: MD029 Ordered list item prefix

In the output, you can see the rules that don’t comply, with both the file name and line on which the rule was broken. This makes it relatively trivial to see where and know why the document isn’t fully compliant.

Taking rule MD013 in particular, this one is defined as:

This rule is triggered when there are lines that are longer than the configured line length (default: 80 characters). To fix this, split the line up into multiple lines.

While an arbitrary line-length of 80 chars may be required in some environments, or desirable in others, it’s not a rule I follow. The style guide that I’m progressively enforcing for the ownCloud docs is one-sentence-per-line.

A full discussion of this concept is outside the scope of this post. However, it means what it says. Sentences aren’t cut at an arbitrary length. As long or as short as they need to be, they written on individual lines.

In doing so, the prose is far more straightforward to both write and edit, as you don’t have to splice text (whether words or whole sentences) from the middle of a paragraph, or splice them into the middle of one. They can be moved, deleted, and added far simpler when they’re each written on a separate line.

How to Configure Markdown Lint

As a result, I didn’t want to use MD013’s default configuration. However, I did want to use all of the other rules. Gladly, Markdown Lint allows you to pick the rules that you want to apply (it runs all rules by default).

To do this, you can create what it refers to as a custom style. Custom styles allow you to pick and choose the rules that you want to apply, or to adjust existing rules to follow your needs better. To create a custom style, you create a new file which ends with .rb, such as owncloud.rb, in the root of your current project.

In there, you can specify whether you want to:

  1. Apply all rules.
  2. Apply or exclude a subset of rules.
  3. Apply or exclude those rules tagged with a specific value. Each rule’s description contains its tag value.
  4. Override some default rule values.

Let’s take the line length rule as an example.

If I wanted to exclude the rule, I’d add the following line:

exclude_rule 'MD013'

If I wanted to exclude the rule based on a tag, I’d add the following line:

exclude_tag :line_length

If I wanted to overwrite the line’s maximum length, such as setting it to 120 chars, instead of the default 80, I’d add the following line:

rule 'MD013', :line_length => 120

It’s worth noting that, when creating a custom style, you need to ensure that the configuration’s written from the least to the most specific. To do that, specify tags first, then specify rules. That way, the style should be interpreted as you intend.

Once the style is created, you tell Markdown Lint to use it with the --style option, such as in this example:

mdl --style owncloud.rb docs/build-the-docs.md

How to Create One-Time Rule Overrides

If you don’t want to create a custom style, you can specify rules and tags on the command line, instead of in a custom style.

For example, if you wanted to exclude rule MD013, you would call Markdown Lint with the -r or —rule option, as in the example below, (note that the rule’s prefixed by a tilde):

mdl -r ~MD013 docs/build-the-docs.md

If you only wanted to apply that rule, run it without the tilde before the rule name.

If you want to apply a tag, then you’d use the —tags or -t prefix, as in the example below. Note the absence of the preceding colon from the tag’s name.

mdl -t ~line_length docs/build-the-docs.md

In Conclusion

If you have a read through the documentation, you’ll find all the other Markdown Lint options and documentation. It’s a great tool, one that’s not too complicated and works very reliably.

I strongly encourage you to use it in your technical writing build pipeline (as well as with git hooks, or just manually, if you want to inspect one or more files).

Over To You!

Have you been using Markdown Lint for some time? What’s your experience with it? Do you use an alternative? If so, what is it and why do you recommend it? I’d love to know in the comments below.

Other Parts In This Series

CC Image Courtesy of othree on Flickr.


You might also be interested in...


Want more tutorials like this?

If so, enter your email address in the field below and click subscribe.

You can unsubscribe at any time by clicking the link in the footer of the emails you'll receive. Here's my privacy policy, if you'd like to know more. I use Mailchimp to send emails. You can learn more about their privacy practices here.


Join the discussion

comments powered by Disqus