ubertech-za / asciidoctor-wrapper
PHP wrapper for Asciidoctor with configurable styling and theming support
Requires
- php: ^8.2
- ext-json: *
Requires (Dev)
- laravel/pint: ^1.0
- mockery/mockery: ^1.6
- orchestra/testbench: ^9.0
- pestphp/pest: ^3.0
- phpstan/phpstan: ^1.11
Suggests
- illuminate/config: Required for Laravel configuration (^10.0|^11.0|^12.0)
- illuminate/filesystem: Required for file operations (^10.0|^11.0|^12.0)
- illuminate/support: Required for Laravel integration (^10.0|^11.0|^12.0)
This package is auto-updated.
Last update: 2025-09-16 20:46:56 UTC
README
⚠️ BETA SOFTWARE NOTICE This package is currently in beta and is being prepared for testing in upcoming projects. Please expect possible breaking changes in future releases. We do not recommend using this package in production environments without thorough testing.
A Laravel package that provides a PHP wrapper around AsciiDoctor and AsciiDoctor-PDF with advanced theming, styling, and configuration management.
Overview
This package bridges the gap between PHP applications and the powerful AsciiDoctor ecosystem, providing:
- Configurable AsciiDoctor Integration: Support for both
asciidoctor
andasciidoctor-pdf
executables - Advanced Theming System: Create, extend, and manage themes with JSON configuration
- Style Object Composition: Programmatically build themes using fluent APIs
- Theme Inheritance: Extend built-in AsciiDoctor themes or custom themes
- Laravel Integration: Service providers, facades, and configuration management
- Type Safety: Full PHP 8.2+ type declarations and comprehensive testing
Installation
Install the package via Composer:
composer require ubertech-za/asciidoctor-wrapper
Prerequisites
You need to have AsciiDoctor installed on your system:
# Install AsciiDoctor (Ruby required) gem install asciidoctor # Install AsciiDoctor-PDF for PDF generation gem install asciidoctor-pdf
Alternatively, use Docker:
docker pull asciidoctor/docker-asciidoctor
Laravel Integration
Configuration
Publish the configuration file:
php artisan vendor:publish --tag=asciidoctor-config
Configure your executables in config/asciidoctor.php
:
return [ 'executables' => [ 'asciidoctor' => env('ASCIIDOCTOR_PATH', 'asciidoctor'), 'asciidoctor_pdf' => env('ASCIIDOCTOR_PDF_PATH', 'asciidoctor-pdf'), ], 'default_theme' => env('ASCIIDOCTOR_DEFAULT_THEME', 'default'), 'themes_path' => env('ASCIIDOCTOR_THEMES_PATH', storage_path('asciidoc/themes')), 'templates_path' => env('ASCIIDOCTOR_TEMPLATES_PATH', storage_path('asciidoc/templates')), 'fonts_path' => env('ASCIIDOCTOR_FONTS_PATH', storage_path('asciidoc/fonts')), 'output_path' => env('ASCIIDOCTOR_OUTPUT_PATH', storage_path('asciidoc/documents')), // ... additional configuration ];
Environment Variables
Add to your .env
file:
ASCIIDOCTOR_PATH=/usr/local/bin/asciidoctor ASCIIDOCTOR_PDF_PATH=/usr/local/bin/asciidoctor-pdf ASCIIDOCTOR_DEFAULT_THEME=default-with-font-fallbacks ASCIIDOCTOR_THEMES_PATH=/path/to/themes ASCIIDOCTOR_TEMPLATES_PATH=/path/to/templates ASCIIDOCTOR_FONTS_PATH=/path/to/your/fonts ASCIIDOCTOR_OUTPUT_PATH=/path/to/output ASCIIDOCTOR_CACHE_ENABLED=true ASCIIDOCTOR_CACHE_TTL=3600
Usage
Basic Usage
use UbertechZa\AsciidoctorWrapper\Facades\Asciidoctor; // Convert AsciiDoc to HTML $result = Asciidoctor::convert( input: 'document.adoc', output: 'document.html', format: 'html5' ); // Convert to PDF $result = Asciidoctor::convert( input: 'document.adoc', output: 'document.pdf', format: 'pdf' ); if ($result['success']) { echo "Conversion successful!"; } else { echo "Error: " . $result['error']; }
Using the Wrapper Class Directly
use UbertechZa\AsciidoctorWrapper\AsciidoctorWrapper; $wrapper = new AsciidoctorWrapper( asciidoctorPath: '/usr/local/bin/asciidoctor', asciidoctorPdfPath: '/usr/local/bin/asciidoctor-pdf' ); $result = $wrapper->convert('input.adoc', 'output.pdf', 'pdf');
Theme System
Creating Themes with the Theme Builder
use UbertechZa\AsciidoctorWrapper\Builder\ThemeBuilder; $theme = app(ThemeBuilder::class) ->name('modern-theme') ->extending('default') ->withColors([ 'primary' => '#2563eb', 'secondary' => '#64748b', 'accent' => '#059669', 'text' => '#0f172a', 'background' => '#ffffff' ]) ->withFont('heading', 'Inter', '16pt', 'bold') ->withFont('body', 'Inter', '11pt', 'normal') ->withFont('mono', 'JetBrains Mono', '9pt', 'normal') ->withElementStyle('document', [ 'color' => '#0f172a', 'font' => ['family' => 'Inter', 'size' => '11pt'] ]) ->withElementStyle('heading1', [ 'color' => '#2563eb', 'font' => ['family' => 'Inter', 'size' => '24pt', 'weight' => 'bold'] ]) ->build(); // Use the theme $result = Asciidoctor::convert('input.adoc', 'output.pdf', 'pdf', $theme);
Loading Themes from JSON
Create a theme file at resources/asciidoctor/themes/my-theme.json
:
{ "name": "my-theme", "extends": "default", "colors": { "primary": "#2563eb", "secondary": "#64748b", "accent": "#059669", "text": "#0f172a", "background": "#ffffff" }, "fonts": { "heading": { "family": "Inter", "size": "16pt", "weight": "bold" }, "body": { "family": "Inter", "size": "11pt", "weight": "normal" }, "mono": { "family": "JetBrains Mono", "size": "9pt", "weight": "normal" } }, "styles": { "document": { "color": "#0f172a", "font": { "family": "Inter", "size": "11pt" } }, "heading1": { "color": "#2563eb", "font": { "family": "Inter", "size": "24pt", "weight": "bold" } } } }
Load and use the theme:
use UbertechZa\AsciidoctorWrapper\StyleManager; $styleManager = app(StyleManager::class); $theme = $styleManager->loadFromJson(resource_path('asciidoctor/themes/my-theme.json')); $result = Asciidoctor::convert('input.adoc', 'output.pdf', 'pdf', $theme);
Theme Inheritance
Themes can extend other themes:
{ "name": "dark-theme", "extends": "modern-theme", "colors": { "text": "#ffffff", "background": "#1a1a1a" } }
Built-in themes can also be extended:
{ "name": "custom-default", "extends": "default", "colors": { "primary": "#ff6b35" } }
Font Management
Custom Fonts Configuration
The package supports custom fonts for PDF generation. Fonts are automatically loaded from the configured fonts directory and made available to asciidoctor-pdf themes.
Setting Up Custom Fonts
- Configure the fonts directory in
config/asciidoctor.php
:
'fonts_path' => env('ASCIIDOCTOR_FONTS_PATH', storage_path('asciidoc/fonts')),
- Add font files to your fonts directory:
storage/asciidoc/fonts/
├── MyFont-Regular.ttf
├── MyFont-Bold.ttf
├── MyFont-Italic.ttf
├── MyFont-BoldItalic.ttf
├── MonoFont-Regular.ttf
└── MonoFont-Bold.ttf
- Use fonts in themes - the package automatically generates the font catalog:
$theme = app(ThemeBuilder::class) ->name('custom-font-theme') ->extending('default-with-font-fallbacks') ->withColors([ 'primary' => '#2563eb', 'text' => '#0f172a' ]) ->build();
Font Catalog Generation
When using custom fonts, the package automatically:
- Scans the
fonts_path
directory for TTF files - Generates a proper font catalog in the theme YAML
- Sets the
pdf-fontsdir
attribute for asciidoctor-pdf - Maps fonts to appropriate theme elements (base, heading, code)
Example generated theme YAML:
extends: default-with-font-fallbacks font: catalog: merge: true MyFont: normal: MyFont-Regular.ttf bold: MyFont-Bold.ttf italic: MyFont-Italic.ttf bold_italic: MyFont-BoldItalic.ttf MonoFont: normal: MonoFont-Regular.ttf bold: MonoFont-Bold.ttf base: font_family: MyFont font_size: 11 font_color: 0f172a heading: font_family: MyFont font_color: 2563eb font_style: bold code: font_family: MonoFont font_size: 9
Font Environment Variable
Set the fonts directory via environment variable:
# Use absolute path ASCIIDOCTOR_FONTS_PATH=/usr/share/fonts/custom # Or relative to Laravel storage ASCIIDOCTOR_FONTS_PATH=/path/to/laravel/storage/asciidoc/fonts
Supported Font Formats
- TTF (TrueType) - Primary supported format
- OTF (OpenType) - Also supported by asciidoctor-pdf
Font Naming Convention
For automatic detection of font variants, use this naming pattern:
FontName-Regular.ttf
(normal weight)FontName-Bold.ttf
(bold weight)FontName-Italic.ttf
(italic style)FontName-BoldItalic.ttf
(bold italic)
Supported Output Formats
html
/html5
- HTML outputdocbook
/docbook5
- DocBook XMLmanpage
- Unix manual pagespdf
- PDF documents (requires asciidoctor-pdf)docx
- Microsoft Word documents
// Generate multiple formats $formats = ['html5', 'pdf', 'docx']; foreach ($formats as $format) { $result = Asciidoctor::convert( input: 'document.adoc', output: "document.{$format}", format: $format, theme: $theme ); }
Advanced Configuration
Custom Attributes
$result = Asciidoctor::convert( input: 'document.adoc', output: 'document.html', format: 'html5', attributes: [ 'source-highlighter' => 'rouge', 'icons' => 'font', 'sectanchors' => true, 'toc' => 'left', 'toclevels' => 3 ] );
Safe Mode
$result = Asciidoctor::convert( input: 'document.adoc', output: 'document.html', format: 'html5', safeMode: 'safe' // unsafe, safe, server, secure );
Style Objects
Color Styles
use UbertechZa\AsciidoctorWrapper\Style\ColorStyle; $colors = new ColorStyle( primary: '#2563eb', secondary: '#64748b', accent: '#059669', text: '#0f172a', background: '#ffffff' ); // Validate colors if ($colors->isValidHex('#2563eb')) { echo "Valid hex color!"; }
Font Styles
use UbertechZa\AsciidoctorWrapper\Style\FontStyle; $font = new FontStyle( family: 'Inter', size: '12pt', weight: 'bold', style: 'normal' ); // Convert to array for processing $fontArray = $font->toArray();
Element Styles
use UbertechZa\AsciidoctorWrapper\Style\ElementStyle; $heading = new ElementStyle( color: '#2563eb', backgroundColor: '#ffffff', font: new FontStyle('Inter', '18pt', 'bold'), margin: '1em 0', padding: '0.5em' );
Testing and Validation
Check Executable Availability
$wrapper = app(AsciidoctorWrapper::class); if ($wrapper->isAsciidoctorAvailable()) { echo "AsciiDoctor is available!"; } if ($wrapper->isAsciidoctorPdfAvailable()) { echo "AsciiDoctor-PDF is available!"; } $formats = $wrapper->getSupportedFormats(); // ['html', 'html5', 'docbook', 'docbook5', 'manpage', 'pdf', 'docx']
Theme Validation
use UbertechZa\AsciidoctorWrapper\StyleManager; $styleManager = app(StyleManager::class); $theme = $styleManager->loadFromJson('theme.json'); if ($styleManager->validateTheme($theme)) { echo "Theme is valid!"; } else { $errors = $styleManager->getValidationErrors(); foreach ($errors as $error) { echo "Error: {$error}\n"; } }
Artisan Commands
The package doesn't include Artisan commands by default, but you can create your own:
<?php namespace App\Console\Commands; use Illuminate\Console\Command; use UbertechZa\AsciidoctorWrapper\Facades\Asciidoctor; use UbertechZa\AsciidoctorWrapper\Builder\ThemeBuilder; class ConvertToAsciidoc extends Command { protected $signature = 'asciidoc:convert {input} {output} {--format=html5} {--theme=}'; protected $description = 'Convert AsciiDoc files to various formats'; public function handle() { $input = $this->argument('input'); $output = $this->argument('output'); $format = $this->option('format'); $themeName = $this->option('theme'); $theme = null; if ($themeName) { $theme = app(ThemeBuilder::class)->name($themeName)->build(); } $result = Asciidoctor::convert($input, $output, $format, $theme); if ($result['success']) { $this->info("✅ Successfully converted {$input} to {$output}"); } else { $this->error("❌ Conversion failed: " . $result['error']); } } }
Error Handling
The wrapper returns structured results:
$result = Asciidoctor::convert('input.adoc', 'output.pdf', 'pdf'); if ($result['success']) { echo "Success! Output: " . $result['output']; } else { echo "Error: " . $result['error']; echo "Exit Code: " . $result['exit_code']; if (!empty($result['stderr'])) { echo "STDERR: " . $result['stderr']; } }
Performance and Caching
Theme Caching
Enable theme caching in your configuration:
'cache' => [ 'enabled' => env('ASCIIDOCTOR_CACHE_ENABLED', true), 'path' => storage_path('app/asciidoctor/cache'), 'ttl' => env('ASCIIDOCTOR_CACHE_TTL', 3600), ],
Best Practices
- Reuse Theme Objects: Create themes once and reuse them for multiple conversions
- Validate Early: Use
validateTheme()
during development to catch issues - Cache Compiled Themes: Enable caching for production environments
- Monitor Resources: AsciiDoctor can be memory-intensive for large documents
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature
- Run tests:
composer test
- Commit changes:
git commit -am 'Add amazing feature'
- Push to branch:
git push origin feature/amazing-feature
- Create a Pull Request
Development Setup
git clone https://github.com/ubertech-za/asciidoctor-wrapper.git cd asciidoctor-wrapper composer install composer test
Testing
Run the test suite:
composer test # Run with coverage composer test-coverage # Run specific test vendor/bin/pest tests/Unit/StyleManagerTest.php # Run integration tests vendor/bin/pest tests/Feature/
License
This package is open-sourced software licensed under the MIT license.
Changelog
Please see CHANGELOG for more information on what has changed recently.
Credits
- UberTech ZA Team
- All Contributors
This package is inspired by the excellent work of:
- AsciiDoctor Project - The core document processing engine
- AsciiDoctor-PDF - PDF generation capabilities
Support
- Issues: GitHub Issues
- Documentation: Package Documentation
- Discussions: GitHub Discussions
Made by Uber Technologies cc