Replace Generator Functions
Antora’s site generator is implemented as a sequence of steps.
Each step is performed by a function.
These functions are known as generator functions.
Generator functions may contain functions for key substeps a generator function may perform, such as convertDocument
.
The generator retrieves these functions from the generator context. These functions can also be retrieved and replaced programmatically by an Antora extension. As such, these generator functions are designed to be replaceable, providing a more powerful way to extend Antora.
Replacing functions in an extension does put the code at greater risk of breaking between major versions of Antora. |
Get the functions
Like with context variables, generator functions are available from the generator context.
The generator functions can be retrieved by calling the getFunctions
method inside the listener of the contextStarted
event, or at any point thereafter.
This method returns an object of key-value pairs, where the keys are the function names and the values are the function objects.
The built-in generator functions are not available until the contextStarted event is emitted.
|
Here’s an example that shows how to retrieve the aggregateContent
function in an extension, assuming this
is bound to the generator content.
this.once('contextStarted', () => {
const { aggregateContent } = this.getFunctions()
})
One reason to retrieve a generator function is to use it as a utility.
For example, if you need your extension to load AsciiDoc as Antora does, you might retrieve the loadAsciiDoc
function for this purpose.
Here’s an example:
this.once('contentClassified', (contentCatalog, siteAsciiDocConfig) => {
const { loadAsciiDoc } = this.getFunctions()
const page = contentCatalog.resolvePage('ROOT::index.adoc')
const scopedAsciiDocConfig = contentCatalog.getComponentVersion(page.src.component, page.src.version).asciidoc
const doc = loadAsciiDoc(page, contentCatalog, scopedAsciiDocConfig || siteAsciiDocConfig)
const sections = doc.findBy({ context: 'section' }, (it) => it !== doc.getHeader())
console.log(sections.map((it) => it.getTitle()))
})
Another reason to retrieve a generator function is to decorate (aka wrap) it. In this case, you’ll need to replace the original function with the decorated one. Alternately, you can replace the original function with your own implementation.
Replace a function
Replacing generator functions gives you the ability to override steps in Antora’s site generator.
The generator functions can be replaced by passing functions to the replaceFunctions
method.
This method accepts the same object signature that the getFunctions
method returns, where the keys are the function names and the values are the function objects.
You only have to pass functions to replaceFunctions
that you want to replace.
The generator will default to using the built-in functions for any function that’s not replaced.
Here’s an example that shows how to replace the publishFiles
function in an extension:
module.exports.register = function () {
this.replaceFunctions({
async publishFiles () {
console.log('Not publishing today')
return []
}
})
}
When the functions are replaced matters.
If you replace a function directly in the register
method (before the contextStarted
event is emitted), it will stop Antora from requiring and registering the corresponding built-in function.
If you replace a function in the contextStarted
listener, the function will replace the corresponding built-in function that has already been required and registered.
The contextStarted
event gives you the opportunity to delegate to (i.e., wrap) a built-in function, as shown here:
module.exports.register = function () {
this.once('contextStarted', () => {
const { publishFiles: publishFilesDelegate } = this.getFunctions()
this.replaceFunctions({
async publishFiles (playbook, catalogs) {
console.log('It\'s publish time!')
return publishFilesDelegate.call(this, playbook, catalogs)
}
})
})
}
When replacing a function, you must adhere to the function’s signature as defined in Function reference. Like with the register function and event listener functions, the generator functions are automatically bound to the generator context.
Function reference
The list of functions that can be replaced by an extension, shown along with their signatures, are as follows:
-
aggregateContent(playbook): Promise<Object>
-
buildNavigation(contentCatalog, siteAsciiDocConfig): NavigationCatalog
-
classifyContent(playbook, contentAggregate, siteAsciiDocConfig): ContentCatalog
-
convertDocument(file, contentCatalog, siteAsciiDocConfig): File
-
convertDocuments(contentCatalog, siteAsciiDocConfig): void
-
createPageComposer(playbook, contentCatalog, uiCatalog, env): Function
-
extractAsciiDocMetadata(doc): Object
-
loadAsciiDoc(file, contentCatalog, config): Document
-
loadUi(uiCatalog): Promise<UiCatalog>
-
mapSite(playbook, publishablePages): File[]
-
produceRedirects(playbook, contentCatalog): File[]
-
publishFiles(playbook, catalogs): Promise<Object[]>
-
resolveAsciiDocConfig(playbook): Object
To learn more about these functions, consult the Antora source code.