Conditional Content in AsciiDoc

Using AsciiDoc attributes it’s possible to have conditional content, which will appear under some conditions but be absent in others.

We’ll use the following AsciiDoc conditionals:

These conditionals are applied by the AsciiDoc preprocessor.

🚀 TL;DR Show me the code. Look at the 13-asciidoc-conditional-content branch. This site is deployed here.

Iterating & Preprocessing Versions

The frontmatter of the AsciiDoc documents looks something like this:

= What is Gatsby?
Some Fictional Dude <some-fictional-dude@gmail.com>
v2.0, 29 October 2023: Rewritten for version 2
:description: An explanation of Gatsby.
:page-version: 0.1, 0.2, 0.3, 1.0, 1.1, 1.2
:page-order: 10
:page-permalink: d2b6d682

The page-version attribute specifies the versions of the documentation in which a particular page is present. So, for example, the page with title “What is Gatsby?” will appear in versions 0.1, 0.2, 0.3, 1.0, 1.1 and 1.2 of the documentation.

In previous versions of the site we implicitly converted the AsciiDoc source into HTML. However, now that we want to use the preprocessor directives we need to be more intentional.

We’re going to use the conditional directives to create customised content which depends on the documentation version. In order to do this we will need to process each page separately for each version of the documentation. In gatsby-node.js we’ll iterate over each of the nodes in allAsciidoc.nodes, and for each node extract the relevant versions from the page-version attribute.

The extractVersions() function, implemented in src/utils/versions.js, returns an array of versions for a specific node. For each version the preprocessAsciidoc() function, implemented in src/utils/asciidoc.js, then

  1. accepts the raw AsciiDoc content (set up in the previous post) and a version number;
  2. dynamically inserts a version attribute into the frontmatter, and assigns to it the specific version number; and
  3. converts the raw AsciiDoc content into HTML, evaluating the preprocessor directives.

Some examples of how those directive might be used:

ifdef::version[]
The `version` attribute is defined.
endif::[]
ifndef::title[]
The `title` attribute is **not** defined.
endif::[]
ifeval::[{version} == 0.1]
This is the first version of the documentation.
endif::[]

Rendered Conditional Content

The rendered HTML is then inserted into the page template defined in src/templates/article.js.

Below is an image showing the “What is Gatsby?” page for version 0.1 (the first version) of the documentation. In the first paragraph on the page the version attribute is used to dynamically insert the version number. There is an ifdef conditional which causes this paragraph to only be rendered if the version attribute is defined. The second paragraph states that this is the first version of the documentation . An ifeval conditional is used to ensure that this paragraph is only rendered if the value of version is 0.1. Finally, an ifndef directive is used to only render the third paragraph if the title attribute is not defined.

'What is Gatsby?' page for first version of the documentation.

The next image shows the “What is Gatsby?” page for version 1.2 (the latest version) of the documentation. Most of the content is the same except for the second paragraph. The content of this paragraph has changed because the ifdef conditional which was true previously no longer applies. A second ifdef conditional now checks if the value version is 1.2.

'What is Gatsby?' page for last version of the documentation.

Conclusion

Inserting conditional content into a site via the ifdef, ifndef and ifeval preprocessor directives can provide a lot of flexibility. They make it possible to only maintain a single file for a page and create different versions of the rendered content depending on whether or not various attributes are defined and what values they contain.

There is a little work required to get the site set up to leverage the preprocessor directives, but it is time and energy well spent.

🚀 TL;DR Show me the code. Look at the 13-asciidoc-conditional-content branch. This site is deployed here.