Custom Exporter Extension
With relatively little effort, you can create your own exporter extension for Assembler.
That’s because Assembler exposes a configure function that sets and runs the assembly process.
All you need to do is provide the converter.
Extension skeleton
An exporter is an Antora extension. Thus, to start, you create the basic structure of an Antora extension.
module.exports.register = function ({ config }) {}
Next, you define a converter.
Converter
A converter for an exporter extension is an object that consists of the following properties:
- convert
-
An async function (or function that returns a Promise) that converts the assembly file to the target format. Typically, this function passes the AsciiDoc source (by way of stdin) to an external command such as
asciidoctor-pdfto convert it to the target format. You can use the providedrunCommandhelper function to invoke the external command. - getDefaultCommand
-
An optionally async function that returns the default command to use when no command is specified in the config. (optional)
- backend
-
The target backend; the backend that will be set during conversion (e.g.,
epub). (optional, default: the file extension without the leading dot) - format
-
The target format; only necessary if the exporter produces a backend variant (e.g.,
html-single); defaults to the backend if not specified. - extname
-
The file extension of the target format (e.g.,
.epub). - mediaType
-
The MIME type of the target format (e.g.,
application/epub+zip). - embedReferenceStyle
-
Controls whether images (for non-HTML filetypes) are rewritten relative to the export file (
relative) or the output directory (output-relative). Thedocdirattribute passed to the convert function is set accordingly. (optional, default:relative)This setting is not used when exporting to HTML (since images are linkable resources in that case). Instead, the
link_reference_stylekey on the Assembler configuration is used. The reference style for embeds is always specified by the converter. - loggerName
-
The name of the Antora logger to use when logging messages captured from stderr of the command (e.g.,
@antora/epub-extension). (optional, default:@antora/assembler [<backend>-exporter]) - xmlCompliant
-
Indicates that the converter either produces or uses XML during the conversion process; setting this property to
trueimplicitly sets the default value of thexml_idssetting on the assembly totrue.
Here’s an example of a converter object:
const converter = {
convert,
backend: 'ext',
extname: '.ext',
mediaType: 'application/ext',
}
The heart of the converter is the convert function.
Convert function
The convert function has the following API:
async function convert (file, conversionAttributes, buildConfig, helpers)
The function parameters are as follows:
-
file - the assembly file. You’re typically only interested in the
file.contentsproperty, which contains the AsciiDoc source buffer. -
conversionAttributes - an object of AsciiDoc attributes to pass to the converter. These attributes can be converted to CLI options by calling
.toArgs('-a', '-o'), where-ais the CLI attribute option flag and-o' is the CLI output option flag. You’ll want to honor both the `attributeOptionFlagandoutputOptionFlagif set on the configuration object. If you set theoutfilesuffixattribute (perhaps to an interim value), it will automatically update the file extension on theoutfileattribute. (You could name this parameterconvertAttributesif you prefer). -
buildConfig - a configuration object that provides both the command and the cwd.
-
helpers - an optional object that provides access to the built-in
logCommandandrunCommandhelper functions for convenience, if needed (e.g.,{ logCommand, runCommand }).
Note that each assembly file is only converted once. If you’re using multiple exporters, a new assembly file is created per exporter and subsequently converted.
The acceptable return values for the convert function are as follows:
-
contents as
undefined,null,Buffer, orStream -
file
-
can have the same identity as the
fileparameter (does not have to be a copy) -
if extname property matches that of export, used as is
-
otherwise, the file is coerced to the export file
-
-
runCommandresult-
contents or file may be passed using property by the same name
-
otherwise, if
output_option_flagisfalse, content is read from stdout property
-
If the contents is undefined, Assembler will lazy read the file from the location specified by the outfile attribute (if that file exists, otherwise the contents will be null).
If the contents is null, Assembler will not create or publish the export.
The convert function should pass the stderr key on the buildConfig object to the runCommand helper and return its result in order for the built-in stderr handling to work.
|
Default command
The optional getDefaultCommand has the following API:
async function getDefaultCommand (cwd, playbook)
If the converter object does not include the getDefaultCommand function, and the command property is not specified in the configuration, the command property on the buildConfig object will be null.
|
Registration
The final step is to register the exporter.
To do so, you then pass generator context (i.e., this), converter, and extension config to the configure function provided by Assembler.
require('@antora/assembler').configure(this, converter, config)
If that require fails due to Node.js path issues, you can use the require function provided on the Antora context instead.
this.require('@antora/assembler', { require }).configure(this, converter, config)
The general rule is that if a package is a direct dependency of your project, the top-level require function should be sufficient.
Otherwise, you can delegate to Antora to try to locate and require the package.
Complete extension
Here’s how it looks all together:
const converter = {
convert,
backend: 'ext',
extname: '.ext',
mediaType: 'application/ext',
}
module.exports.register = function ({ config }) {
require('@antora/assembler').configure(this, converter, config)
}
Refer to Custom Exporter Examples to find full working implementations.