crystal-asciidoctor
= crystal-asciidoctor :description: A Crystal port of the Asciidoctor document processor. :repo_url: https://github.com/aloli/crystal-asciidoctor
A Crystal port of the https://github.com/asciidoctor/asciidoctor[Asciidoctor] document processor.
This shard provides a complete AsciiDoc processing pipeline in Crystal: an Abstract Syntax Tree (AST) model, a parser, a substitution engine, and three output converters (HTML5, DocBook 5, Manpage), faithfully ported from the Ruby implementation.
== Status
Beta -- The core pipeline (parse → substitute → convert) is functional. Extensions API and syntax highlighting integration are not yet implemented.
=== Implemented
[cols="3,2,2"] |=== | Component | Crystal module | Ruby source
| Abstract node (base class) | Asciidoctor::AbstractNode | abstract_node.rb | Abstract block | Asciidoctor::AbstractBlock | abstract_block.rb | API (load / convert) | Asciidoctor.load, Asciidoctor.convert | load.rb, convert.rb | Attribute list parser | Asciidoctor::AttributeList | attribute_list.rb | Block | Asciidoctor::Block | block.rb | Callouts | Asciidoctor::Callouts | callouts.rb | CLI (options / invoker) | Asciidoctor::Cli::Options, Asciidoctor::Cli::Invoker | cli/options.rb, cli/invoker.rb | Constants | Asciidoctor::* | asciidoctor.rb | Content model (enum) | Asciidoctor::ContentModel | (symbols in Ruby) | Converter base | Asciidoctor::Converter::Base | converter.rb | Converter DocBook 5 | Asciidoctor::Converter::DocBook5Converter | converter/docbook5.rb | Converter HTML5 | Asciidoctor::Converter::Html5Converter | converter/html5.rb | Converter Manpage | Asciidoctor::Converter::ManPageConverter | converter/manpage.rb | Document | Asciidoctor::Document | document.rb | Document catalog | Asciidoctor::Catalog | (part of document.rb) | Helpers | Asciidoctor::Helpers | helpers.rb | Inline | Asciidoctor::Inline | inline.rb | List / ListItem | Asciidoctor::List, Asciidoctor::ListItem | list.rb | Logging | Asciidoctor::Logger | logging.rb | Parser | Asciidoctor::Parser | parser.rb | Reader / PreprocessorReader | Asciidoctor::Reader | reader.rb | Regular expressions | Asciidoctor::*Rx | rx.rb | Safe mode | Asciidoctor::SafeMode | (constants in asciidoctor.rb) | Section | Asciidoctor::Section | section.rb | Source location | Asciidoctor::SourceLocation | (part of abstract_block.rb) | Substitution (flags enum) | Asciidoctor::Substitution | substitutors.rb | Substitutors (inline engine) | Asciidoctor::Substitutors | substitutors.rb | Table / Column / Cell | Asciidoctor::Table, Table::Column, Table::Cell | table.rb |===
=== Not yet implemented
- Extensions API
- Syntax highlighting integration
- Template-based converter
== Installation
Add the dependency to your shard.yml:
[source,yaml]
dependencies: crystal-asciidoctor: github: aloli/crystal-asciidoctor
Run shards install.
== Usage
=== High-level API
[source,crystal]
require "crystal-asciidoctor"
Convert an AsciiDoc string to HTML5
html = Asciidoctor.convert("= Hello\n\nA bold paragraph.") puts html
Convert to DocBook 5
docbook = Asciidoctor.convert("= Hello\n\nA paragraph.", {"backend" => "docbook5"}) puts docbook
Load a document (parse without converting)
doc = Asciidoctor.load("= My Document\n\n== Section One\n\nParagraph.") puts doc.doctitle # => "My Document"
=== Low-level parsing
[source,crystal]
require "crystal-asciidoctor"
source = <<-ASCIIDOC = My Document Author Name
== Introduction
This is a paragraph.
== Details
Another paragraph with bold text. ASCIIDOC
doc = Asciidoctor::Document.new reader = Asciidoctor::Reader.new(source.lines) Asciidoctor::Parser.parse(reader, doc)
Access the document title
puts doc.doctitle # => "My Document"
Traverse the tree
doc.find_by(context: :paragraph).each do |block| puts block.as(Asciidoctor::Block).source end
Access sections
doc.blocks.each do |block| if block.is_a?(Asciidoctor::Section) puts "Section: #{block.title} (level #{block.level})" end end
=== Building the AST manually
[source,crystal]
require "crystal-asciidoctor"
Create a document with an HTML5 converter
doc = Asciidoctor::Document.new converter = Asciidoctor::Converter::Html5Converter.new doc.converter = converter
Create a section
section = Asciidoctor::Section.new(document: doc, parent: doc, level: 1) section.title = "Introduction" section.id = "introduction" section.numeral = "1" doc << section
Create a paragraph block
para = Asciidoctor::Block.new( parent_block: section, context: :paragraph, content_model: Asciidoctor::ContentModel::Simple, source: "Hello, AsciiDoc!" ) section << para
Convert to HTML
puts converter.convert_section(section)
== Development
[source,sh]
Run all tests (468 examples)
crystal spec
Run only integration tests
crystal spec spec/integration/
Type-check without codegen
crystal build --no-codegen src/crystal-asciidoctor.cr
== Contributing
. Fork it ({repo_url}/fork) . Create your feature branch (git checkout -b my-new-feature) . Commit your changes (git commit -am 'Add some feature') . Push to the branch (git push origin my-new-feature) . Create a new Pull Request
== License
This project is licensed under the MIT License -- see the LICENSE file for details.
== Acknowledgements
This project is a Crystal port of https://github.com/asciidoctor/asciidoctor[Asciidoctor], originally written in Ruby by Dan Allen, Sarah White, and the Asciidoctor community. The AST model, parser, and converters follow the same architecture and naming conventions as the original.
crystal-asciidoctor
- 0
- 0
- 0
- 0
- 0
- about 1 hour ago
- February 28, 2026
MIT License
Sat, 28 Feb 2026 18:44:01 GMT