Explanation
How adocfmt keeps your document safe
This page explains how adocfmt makes sure that formatting does not change what your document shows, and what it does when it cannot be sure. It gives the reasons behind the guarantees.
Asciidoctor is the reference
AsciiDoc has no formal specification. Asciidoctor is its reference implementation. It renders a document: it converts the AsciiDoc source into the HTML page that your readers see. So formatting is correct when the page that Asciidoctor renders shows the same before and after.
adocfmt does not use Asciidoctor to read your document. It has its own parser, which decides what each block is, such as a section title, a list or a code block. The rules format each block according to that decision. A line that no rule rewrites keeps its content and loses only its trailing whitespace, which Asciidoctor ignores anyway. So a block that the parser misreads cannot change the page unless a rule rewrites it.
Where a rule does rewrite a block, the tests hold it to Asciidoctor. They format the test inputs of the Asciidoctor test suite and adocfmt’s own test cases, render each one before and after with Asciidoctor, and compare the results. A rule that changes the rendered page, the content of a code or literal block, or a comment fails the tests. The tests also compare how the parser reads each line with how Asciidoctor reads it, so a misread line shows up before any rule rewrites its block. The testing strategy describes these checks and what they cannot see.
Decision record 0005 explains why adocfmt reads your document with its own parser.
Why includes and conditionals are left alone
An include is a line such as include::intro.adoc[], which Asciidoctor replaces with the lines of another file.
A conditional is a pair of lines such as ifdef::draft[] and endif::[].
Asciidoctor keeps the lines between them only if the draft attribute is set.
Asciidoctor decides which lines these directives add or drop only when it renders the document.
That depends on the included file and on the attributes you render with, for example -a draft on the Asciidoctor command line.
adocfmt sees neither, so no rule except trailing whitespace removal changes a line whose meaning depends on such a directive.
For example, the block delimiters rule shortens the fence of a block to four characters, but not around an include:
| Before | After |
|---|---|
-------- include::snippet.adoc[] -------- -------- code -------- | -------- include::snippet.adoc[] -------- ---- code ---- |
The included file may contain a ---- line.
In a block fenced with four dashes, that line would end the block early.
The formatting rules that treat such lines differently list them under Left alone.
Why a document with findings is refused whole
When the parser meets structure it cannot read reliably, such as a block with no closing delimiter, it reports a finding. adocfmt then refuses the whole document: it leaves the file as it is and exits with an error. For what each finding means and how to fix it, see Refusal findings.
Formatting only the parts the parser could read would hide the problem. A refusal fails the run, where a warning would be easy to miss in a commit hook or a CI run. Decision record 0003 gives the full reasoning.
Why there are no options
adocfmt has no formatting options, so every document is formatted by the same rules in the same way. Every option would multiply the combinations in which each rule has to stay correct and be tested. Decision record 0004 gives the full reasoning.