crystal-asciidoctor

A Crystal port of the Asciidoctor document processor — AST model and parser

= 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.

Repository

crystal-asciidoctor

Owner
Statistic
  • 0
  • 0
  • 0
  • 0
  • 0
  • about 1 hour ago
  • February 28, 2026
License

MIT License

Links
Synced at

Sat, 28 Feb 2026 18:44:01 GMT

Languages