Generate Leanpub TOC from Asciidoc files

Posted at — Oct 9, 2020

I just released the first version of my Taming Thymeleaf book on leanpub. Since I am using Asciidoctor to generate the PDF, there is no automatic table of contents generation for the landing page. Luckily, leanpub allows to enter some HTML to manually create the TOC.

A perfect opportunity to use my rusty Groovy skills once more to generate this HTML.

I have my Asciidoc files all in a _chapters directory grouped per chapter:

chapter-01.adoc
chapter-02.adoc
chapter-03.adoc
chapter-04.adoc
chapter-05.adoc
...

Asciidoc uses == and === indicate chapter titles. This is an example from chapter-01.adoc:

== What are Spring Boot and Thymeleaf?

=== Spring Framework

Spring Boot is based upon the https://projects.spring.io/spring-framework/[Spring Framework], which is at its core
a dependency-injection container. Spring makes it easy to define everything in your application as loosely coupled
components which Spring will tie together at run time. Spring also has a programming model that allows you to make
abstractions from specific deployment environments.

This Groovy script loops over all files and searches for the level 1 (==) and level 2 (===) Asciidoc headings:

println('<ul class="toc no-parts">')
int chapterNumber = 1;
def files = new File('_chapters').listFiles(new FilenameFilter() {
    @Override
    boolean accept(File dir, String name) {
        return name.startsWith('chapter-')
    }
})
files.sort().each { File file ->
    def lines = file.readLines()
    println('<li>')
    int sectionNumber = 1;
    lines.forEach({ it ->
        if (it.startsWith("== ")) {
            println("<span class=\"section-number\">${chapterNumber++}. </span>${it - "== "}")
            println('<ul>')
        }
        if (it.startsWith("=== ")) {
            println("""
<li>
                <span class="section-number">${chapterNumber}.${sectionNumber++} </span>${it - "=== "}
            </li>
""")
        }
    }
    )
    println('</ul>')
    println('</li>')
}
println('</ul>')

The resulting HTML is something like:

<ul class="toc no-parts">
    <li>
        <span class="section-number">1. </span>What are Spring Boot and Thymeleaf?
        <ul>
            <li>
                <span class="section-number">2.1 </span>Spring Framework
            </li>
            <li>
                <span class="section-number">2.2 </span>Spring Boot
            </li>
            <li>
                <span class="section-number">2.3 </span>Thymeleaf
            </li>
        </ul>
    </li>
    <li>
        <span class="section-number">2. </span>Getting started
        <ul>
            <li>
                <span class="section-number">3.1 </span>Prerequisites
            </li>
            <li>
                <span class="section-number">3.2 </span>Spring Initializer
            </li>
            <li>
                <span class="section-number">3.3 </span>Summary
            </li>
        </ul>
    </li>
    ...
</ul>

See https://leanpub.com/taming-thymeleaf for the full generated Table of Contents.

If you want to be notified in the future about new articles, as well as other interesting things I'm working on, join my mailing list!
I send emails quite infrequently, and will never share your email address with anyone else.