5. Building Block View
Level 1: Modules
| Module | Artifact | Responsibility |
|---|---|---|
Client |
|
Typed access to the Confluence Cloud REST API. Generated from Atlassian’s OpenAPI v2 specification, plus one hand-maintained v1 API for attachment upload. Contains no documentation logic. |
Publisher |
|
The domain core: parses the local site into a page tree, resolves links, transforms content into Confluence Storage Format, and drives the Confluence calls. Usable standalone as a library. |
Maven plugin |
|
Adapter to the build. Maps plugin parameters onto a |
Sample |
|
This documentation. Builds an Antora site and publishes it with the plugin — the end-to-end test of the whole chain. |
The dependency direction is strictly one way: plugin → publisher → client. Nothing in the publisher references a Maven type, which is what keeps the library usable outside a build.
Level 2: Inside wiki-publisher
Publisher
The entry point and the only component that knows the overall workflow. It resolves the parser implementation, runs the two publishing phases (see 6. Runtime View), builds the link index across all mappers, and collects per-mapper failures.
Parser resolution deserves a note, because it is a place where flexibility and safety collide:
the class named by Configuration.parserClass is loaded without running its static
initializers and is only instantiated after it has been verified to implement Parser. A wrong
class name therefore fails the build instead of executing unrelated code.
final var type = Class.forName(className, false, loader); // no initialization
if (!Parser.class.isAssignableFrom(type)) { // check before instantiation
throw new IllegalStateException(...);
}
final var parser = type.asSubclass(Parser.class).getDeclaredConstructor().newInstance();
parser.init(config);
Parser and AntoraParser
Parser is the seam towards the source format. Implementations need a public no-argument
constructor and receive their configuration through init(Configuration).
AntoraParser is the built-in implementation. resolvePages reads the navigation panel of
index.html and turns the data-depth attributes into a Page tree; loadContent extracts the
article.doc element of a single page. Every href from the HTML passes through SafePaths
before it becomes a file path — see 8. Cross-cutting Concepts.
LinkResolver
Holds one index over the page trees of all mappers, keyed by title and space key. resolve
classifies an href into one of five kinds:
PAGE-
A published Confluence page, possibly in another space (
foreign). ANCHOR-
A position within the current page.
ATTACHMENT-
A local file that has to be published as an attachment.
EXTERNAL-
Points outside the documentation and is left untouched.
UNRESOLVED-
Points into the documentation but cannot be mapped — reported, and the link text is kept without a link.
Transformer and ConfluenceTransformer
Converts an HTML fragment into Confluence Storage Format: rewrites links using the
LinkResolver, converts admonition blocks into Confluence macros, maps images onto
ri:attachment references, normalises code blocks, and collects the attachments a page needs.
ConfluenceClient
The only component that talks to Confluence. Beyond create/update it owns the two mechanisms that protect the target space:
-
Change detection through the page property
page-content-hash, written after every successful update and read before the next one. -
Orphan handling in
syncPageStructure: everything below the root page that the current run did not touch is an orphan, reported always and trashed only whendeleteOrphansis set.
Level 2: Inside wiki-client
| Part | Note |
|---|---|
Generated v2 APIs |
|
|
The exception to the generated world. Needed because REST v2 cannot create attachments, and it
requires |
Patched OpenAPI spec |
The bundled specification is not upstream verbatim: in four |
The patch to the OpenAPI specification must be re-applied whenever the spec is refreshed
from Atlassian. It is documented in the wiki-client README — without it, the generated sources
do not compile.
|