Processing Pipeline
This page explains how the Antora Tracer extension processes content during a build. It covers the internal pass structure, the graph lifecycle, and how components coordinate.
Build integration
The extension hooks into Antora’s event pipeline through two events:
-
contentClassified— fires once after content classification, before document conversion. The extension parses items, expands macros, substitutes links, and registers generated matrices in the content catalog. -
sitePublished— fires once after all pages are published. The extension writes the standalone traceability output directory (matrices, coverage, index).
The same RequirementsTraceabilityExtension class works standalone (via CLI) or within Antora — the event handlers are optional.
Pass structure within contentClassified
The extension runs four passes within the contentClassified event.
The order matters — each pass depends on the result of earlier ones.
Pass 1: Parse and populate the graph
DocumentParser scans every page and partial for [item] blocks and inline relationship macros.
Items and relationships are registered in the TraceabilityGraph.
Both pages and partials are processed here.
The graph must be complete before any subsequent pass can resolve cross-file references. This is why Pass 1 processes all files before moving on.
Pass 2: Expand relation macros (pages and partials)
traceability:outgoing[], traceability:incoming[], and traceability:links[] placeholders are replaced with formatted relationship lists.
The expansion queries the graph to enumerate relationships for each item.
This pass is opt-in: only files with :traceability-links: true get macro expansion.
Partials have the attribute forced on since they have no document attributes of their own.
Files without the attribute have the macro text stripped.
Display style (list, table, inline), sort order (target-id, target-title, relation-type), and collapsible sections are configurable via document attributes.
Pass 2b: Expand graph macros (pages and partials)
traceability:graph[], , and placeholders are replaced with rendered diagram image references.
The graph’s toDot() and toVegaLite() methods generate the item and coverage diagram source; toConfigDot() renders the configuration model.
This pass is opt-in via :traceability-graph: true.
It’s independent of Pass 2 — you can enable graph macros without link macros, and vice versa.
Pass 3: Substitute relationship links (pages and partials)
Inline relationship macros (``) are replaced with clickable xrefs to the target item’s source page. This is the mechanism that makes matrix cells clickable links to item definitions.
For page items: xref:page.html#ID.
For partial items: link:URL#ID (since partials don’t produce HTML pages).
This pass also runs injectTitleIds() (prepends ID to title for visible display) and unindentItemMacros().
Graph lifecycle
The traceability graph has a defined lifecycle — understanding which operations are valid in each state explains why pass ordering matters:
-
Creation: The extension initializes the graph synchronously in its constructor. Config/preset loading is a synchronous file read.
-
Population (Pass 1): Items and relationships are added. Validation runs on each
addRelationship()call — source exists, target exists, relation allowed by config. -
Quiescent (between Pass 1 and Pass 2): The graph is complete. All items and relationships from all files are loaded. Queries and macro expansion are safe.
-
Macro expansion (Pass 2/2b/3): The graph is read-only. Macros query the graph to generate output. No new items or relationships are added.
-
Finalization: Matrices are generated from each version’s graph during
contentClassifiedand registered in the content catalog as attachments; the standalone output directory is written atsitePublished.
Component interaction
The extension follows a dependency-injection pattern:
-
ConfigLoaderis created first (config/preset loading) -
TraceabilityGraphreceivesConfigLoaderfor validation -
DocumentParserreceivesConfigLoaderfor role validation -
MatrixGeneratorreceives bothTraceabilityGraphandConfigLoader -
Neo4jExporterreceivesTraceabilityGraph
Each component is independently testable without mocking frameworks. There is no service locator, DI container, or global state.
File state caching
The prepareFile() method computes file content, document attributes, and item block positions once per file, then feeds the same PreparedFile to all macro-expansion methods.
This eliminates redundant buffer conversions and regex scans.
Related
-
API Reference — component interfaces
-
Architecture — arc42 architecture with sequence and pass-pipeline diagrams
-
Architecture Decisions — design rationale behind these patterns