diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a4835a..50f3575 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,6 +15,7 @@ jobs: matrix: ruby: - '3.2.2' + - '3.4.5' steps: - uses: actions/checkout@v4 @@ -23,5 +24,9 @@ jobs: with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - - name: Run the default task - run: bundle exec rake + - name: Run setup + run: bin/setup + - name: Run tests + run: bundle exec rake test + - name: Run lint + run: bundle exec rake standard diff --git a/.standard.yml b/.standard.yml index 8825305..1c922d7 100644 --- a/.standard.yml +++ b/.standard.yml @@ -1,3 +1,3 @@ # For available configuration options, see: # https://github.com/standardrb/standard -ruby_version: 2.6 +ruby_version: 3.2 diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..5184db8 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +ruby 3.4.5 \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f02577a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,15 @@ +# Build Commands +- Setup: bin/setup +- Test all: rake test +- Test single: ruby -I test test/dast_document_test.rb --name +- Lint: rake standard + +# Code Style +- frozen_string_literal: true at file top +- require_relative for internal requires +- StandardRB linting (ruby 2.6+) +- RBS type signatures required +- Minitest for testing +- Nokogiri for HTML parsing +- Use &. safe navigation, then chaining +- Descriptive test method names \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 09fb4d2..eea7df3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,52 @@ -## [Unreleased] +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.3.0] - 2025-12-19 + +### Added +- Comprehensive edge case tests for DastDocument rendering: + - Empty documents, invalid node types, and missing data handling. + - Text formatting with multiple marks, unknown marks, and newlines. + - Advanced node types: blockquotes, links, unordered lists. + - Block rendering edge cases: multiple blocks, missing components/view contexts. + - HTML output validation via `to_html` method. + +### Changed +- Bump required Ruby version from >= 3.2.2 to >= 3.4.5 +- Update Nokogiri dependency from >= 1.13.4 to >= 1.18.9 +- Add REXML >= 3.3.9 as runtime dependency + +### Security +- Address multiple CVEs in Nokogiri (e.g., libxml2/libxslt vulnerabilities) +- Address REXML DoS vulnerabilities by requiring Ruby >= 3.4.5 or REXML >= 3.3.9 + +## [1.2.0] - 2024-02-22 + +### Added +- Support for ordered lists and horizontal rules in HTML output. +- AGENTS.md file with project information and build commands. + +### Changed +- Major library rewrite to support passing blocks and custom components for enhanced rendering flexibility. +- Removed requirement for "Component" suffix in block names, simplifying component naming conventions. +- Improved newline handling in text content for more accurate HTML rendering. +- Code cleanup and refactoring for better maintainability. +- Added RuboCop configuration for improved code style and linting. + +### Fixed +- Added null checks to prevent runtime errors during document processing. +- Corrected data passing in block rendering to ensure components receive accurate content. +- Minor adjustments to block rendering functionality for improved reliability. +- Fixed broken test case to maintain test suite integrity. ## [0.1.0] - 2024-01-31 -- Initial release +### Added +- Initial release with basic HTML rendering and structured document support. + +[1.3.0]: https://github.com/paradem/dast_document/releases/tag/v1.3.0 +[1.2.0]: https://github.com/paradem/dast_document/releases/tag/v1.2.0 diff --git a/Gemfile.lock b/Gemfile.lock index 863c957..91a2de2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,8 +1,10 @@ PATH remote: . specs: - dast_document (0.1.0) - nokogiri (>= 1.13.4) + dast_document (1.3.0) + nokogiri (>= 1.18.9) + ostruct (>= 0.6.0) + rexml (>= 3.3.9) GEM remote: https://rubygems.org/ @@ -11,22 +13,23 @@ GEM json (2.7.1) language_server-protocol (3.17.0.3) lint_roller (1.1.0) - mini_portile2 (2.8.5) + mini_portile2 (2.8.9) minitest (5.21.2) - nokogiri (1.16.0) + nokogiri (1.18.10) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.16.0-arm64-darwin) + nokogiri (1.18.10-arm64-darwin) racc (~> 1.4) + ostruct (0.6.3) parallel (1.24.0) parser (3.3.0.5) ast (~> 2.4.1) racc - racc (1.7.3) + racc (1.8.1) rainbow (3.1.1) rake (13.1.0) regexp_parser (2.9.0) - rexml (3.2.6) + rexml (3.4.4) rubocop (1.59.0) json (~> 2.3) language_server-protocol (>= 3.17.0) diff --git a/README.md b/README.md index fa49d90..b9d1e2c 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,118 @@ # DastDocument -TODO: Delete this and the text below, and describe your gem - -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/dast_document`. To experiment with that code, run `bin/console` for an interactive prompt. +A Ruby gem for rendering DatoCMS DAST (DatoCMS Abstract Syntax Tree) documents into HTML. Supports rich text elements (headings, paragraphs, lists) and embedded blocks with custom components. + +## Table of Contents + +- [Installation](#installation) +- [Usage](#usage) + - [Basic Document Rendering](#basic-document-rendering) + - [Text Formatting and Marks](#text-formatting-and-marks) + - [Links and Blockquotes](#links-and-blockquotes) + - [Blocks and Custom Components](#blocks-and-custom-components) + - [Edge Cases and Error Handling](#edge-cases-and-error-handling) + - [Supported Node Types](#supported-node-types) +- [Development](#development) +- [Contributing](#contributing) +- [License](#license) ## Installation -TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org. - Install the gem and add to the application's Gemfile by executing: - $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG + $ bundle add dast_document If bundler is not being used to manage dependencies, install the gem by executing: - $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG + $ gem install dast_document ## Usage -TODO: Write usage instructions here +### Basic Document Rendering + +Basic usage for rendering a DAST document into HTML: + +```ruby +require 'dast_document' + +dast = { "value" => { "document" => { "type" => "root", "children" => [ + { "type" => "paragraph", "children" => [{ "type" => "span", "value" => "Hello world!" }] }, + { "type" => "heading", "level" => 1, "value" => "Title" }, + { "type" => "list", "style" => "numbered", "children" => [ + { "type" => "listItem", "children" => [{ "type" => "paragraph", "children" => [{ "type" => "span", "value" => "Item 1" }] }] } + ] } +] } }, "blocks" => [] } +document = DastDocument::Document.new(dast) +html = document.to_html +# Output:

Hello world!

Title

  1. Item 1

+``` + +Note: Newlines in text content are automatically converted to `
` tags (e.g., "line1\n\nline2" becomes "line1
line2"). + +### Text Formatting and Marks + +Apply rich text formatting using marks on spans: + +```ruby +dast = { "value" => { "document" => { "type" => "root", "children" => [ + { "type" => "paragraph", "children" => [ + { "type" => "span", "value" => "Bold and italic", "marks" => ["emphasis", "underline"] } + ] } +] } }, "blocks" => [] } +document = DastDocument::Document.new(dast) +html = document.to_html +# Output:

Bold and italic

+``` + +Unknown marks fall back to using the mark name as the HTML tag. + +### Links and Blockquotes + +Render links and blockquotes: + +```ruby +dast = { "value" => { "document" => { "type" => "root", "children" => [ + { "type" => "link", "url" => "https://example.com" }, + { "type" => "blockquote", "attribution" => "Author Name", "children" => [ + { "type" => "paragraph", "children" => [{ "type" => "span", "value" => "Quote text" }] } + ] } +] } }, "blocks" => [] } +document = DastDocument::Document.new(dast) +html = document.to_html +# Output:

Quote text

Author Name
+``` + +### Blocks and Custom Components + +For blocks with custom components, provide a view context and component module: + +```ruby +# Assuming Rails view context and component module +document = DastDocument::Document.new(dast, view_context: self, component_module: Components) +``` + +If a component is missing or view context lacks a render method, error messages are displayed in the HTML output (e.g., "Can't render block ComponentName no component defined"). + +### Edge Cases and Error Handling + +The gem handles malformed or missing data gracefully: +- Empty documents or missing node types are skipped without errors. +- Invalid inputs (e.g., non-integer heading levels) are rendered as-is or with defaults. +- Unknown node types are ignored, ensuring robust rendering. + +### Supported Node Types + +| Node Type | Description | Example Output | +|----------------|--------------------------------------|----------------| +| paragraph | Text paragraph | `

Text

` | +| heading | Headings (levels 1-6) | `

Title

` | +| list | Ordered/unordered lists | `
  1. Item
` or `