AsciidoctorJ Documentation

repository·main·Indexed 20 days ago

https://github.com/asciidoctor/asciidoctorj

Official Java bindings for Asciidoctor that allow developers to convert AsciiDoc content to formats like HTML and PDF or analyze document structures from the JVM. Includes references for the AsciidoctorJ CLI, the Abstract Syntax Tree (AST) class hierarchy, the Table API, and the AsciidoctorModule for registering extensions.

Tokens
43K
Snippets
141
Records
200
Agent score
71%

What's inside AsciidoctorJ

  1. What is AsciidoctorJ

    main
    AsciidoctorJ provides Java bindings for Asciidoctor, an implementation of the AsciiDoc format. It uses JRuby to run the Ruby-based Asciidoctor engine on the JVM. AsciidoctorJ bundles all necessary Ruby gems and wraps the functionality into a native Java API, allowing you to use Asciidoctor in Java applications without manually managing Ruby runtimes or gems. It is also available as a standalone distribution that can be downloaded and executed directly.
  2. What is a Preprocessor and how does it work

    main

    Preprocessors allow you to manipulate raw Asciidoctor source text before the parser and converter process it. This is useful for tasks like making hidden comments visible in draft versions or transforming specific syntax patterns into standard AsciiDoc blocks.

    Key Concepts

    • Timing: Preprocessors run on the raw input before Asciidoctor parses the document into an Abstract Syntax Tree (AST).
    • Independence: Multiple preprocessors can be registered. Because the execution order is undefined, each preprocessor should be designed to be independent of others.
    • Mechanism: A preprocessor typically accesses the raw input via a PreprocessorReader, modifies the content, and returns a new reader containing the processed content to replace the original input.
  3. What is a Postprocessor and when is it used

    main

    Postprocessors are extension points called after Asciidoctor has completed the conversion of a document to its target format. They allow you to modify the final output (e.g., inserting a custom copyright notice into an HTML footer) before the result is returned to the user.

    Important Limitations:

    • String-based formats only: Postprocessors currently only support target formats that are string-based (like HTML). You cannot write Postprocessors for binary formats such as PDF or EPUB.
  4. Use positional and named attributes in block macros

    main

    Block macros can support attributes that are either passed by their position within the brackets or by explicitly naming them.

    For example, if a macro defines provider and repo as positional attributes:

    • Positional: gist::target[github, myrepo[] (where github is the first attribute and myrepo is the second).
    • Named: gist::target[provider="gitlab", repo="project/repo"].

    When implementing this in a BlockMacroProcessor, you can extract these values from the macro's attributes to compute the final output content.

    // Positional attributes
    gist::mygithubaccount/8810011364687d7bec2c[github, myrepo]
    
    // Named attributes
    gist::mygithubaccount/8810011364687d7bec2c[provider="gitlab", repo="gitlab-org/gitlab-foss"]
  5. Access document metadata via the Catalog

    main

    During conversion, you can access document-wide metadata through the Catalog object, which is available via Document.getCatalog(). This is useful for rendering elements like footnotes or anchors.

    Available catalog methods:

    • getFootnotes(): Returns a list of footnotes. Note that these are only available after Document.getContent() has been called.
    • getRefs(): Returns a map of IDs to document elements. This is used to resolve inline anchors and link to specific document targets (like sections or explicitly assigned IDs).
  6. Shutdown and destroy an Asciidoctor instance

    main

    Asciidoctor instances manage a Ruby runtime that consumes resources. You must explicitly release these resources using the shutdown() method. Once shutdown() is called, all subsequent method calls on that instance will fail.

    Because Asciidoctor implements java.io.AutoCloseable, the recommended way to ensure resources are freed is to use a try-with-resources block, which automatically calls shutdown().

    // Explicit shutdown
    String html = asciidoctor.convert("content", options);
    asciidoctor.shutdown();
    
    // Recommended: Automatic shutdown using try-with-resources
    try (Asciidoctor asciidoctor = Asciidoctor.Factory.create()) {
        String html = asciidoctor.convert("content", options);
    }
  7. How to adapt a custom syntax highlighter

    main

    To implement a custom syntax highlighter adapter for AsciidoctorJ (HTML rendering), you must implement a subset of the following core tasks:

    1. Resource Management: Include the necessary stylesheets and scripts into the resulting HTML document.
    2. File-based Assets: Create stylesheet and script resources on the filesystem if the document is rendered to a file and uses the :linkcss and :copycss attributes.
    3. Block Formatting: Wrap source block elements in <pre/> and <code> elements with specific attributes. For example, converting puts "Hello World" to <pre class="highlightme"><code class="language">puts "Hello World"</code></pre>.
    4. Text Tokenization: Format the source text itself by mapping it to <span> elements (e.g., converting puts "Hello World" to <span class="id">puts</span> <span class="stringliteral">"Hello World"</span>).
  8. When external stylesheets are written to the filesystem

    main

    External stylesheets are not written for every conversion. They are only written to the target directory when the following conditions are met:

    1. The conversion target is a file (not a stream or a string).
    2. The AsciiDoc attributes :linkcss and :copycss are both set.
    3. The highlighter implements org.asciidoctor.syntaxhighlighter.StylesheetWriter and isWriteStylesheet() returns true.
  9. Implement a Block extension in Ruby

    main

    When writing a Ruby extension for AsciidoctorJ, your class should inherit from Asciidoctor::Extensions::BlockProcessor.

    You can use the option method to define the :contexts (e.g., [:paragraph]) and the :content_model (e.g., :simple). The process method is then responsible for transforming the input using the parent, reader, and attributes arguments, typically returning a new Asciidoctor::Block object.

    require 'asciidoctor'
    require 'asciidoctor/extensions'
    
    class YellRubyBlock < Asciidoctor::Extensions::BlockProcessor
      option :contexts, [:paragraph]
      option :content_model, :simple
    
      def process(parent, reader, attributes)
        lines = reader.lines.map { |line| line.upcase.gsub(/\.( |$)/, '!\1') }
        Asciidoctor::Block.new(parent, :paragraph, :source => lines, :attributes => attributes)
      end
    end
  10. How block macros work

    main

    A block macro is a specific type of block in AsciiDoc used to trigger custom processing. The syntax structure is:

    macro-name::target[attributes]

    • Macro name: The identifier (e.g., gist).
    • Two colons: :: separates the name from the target.
    • Target: The specific resource identifier (e.g., mygithubaccount/8810011364687d7bec2c).
    • Attributes: Optional parameters enclosed in square brackets [].