AGENTS.md - commonmarker-merge Development Guide
π― Project Overview
commonmarker-merge is a format-specific implementation of the *-merge gem family for Markdown files using the Commonmarker parser. It provides intelligent Markdown file merging using AST analysis.
Core Philosophy: Intelligent Markdown merging that preserves structure, formatting, and links while applying updates from templates.
Repository: https://github.com/kettle-rb/commonmarker-merge
Current Version: 1.0.1
Required Ruby: >= 3.2.0 (currently developed against Ruby 4.0.1)
ποΈ Architecture: Format-Specific Implementation
What commonmarker-merge Provides
-
Commonmarker::Merge::SmartMergerβ Markdown-specific SmartMerger implementation -
Commonmarker::Merge::FileAnalysisβ Markdown file analysis with section extraction -
Commonmarker::Merge::NodeWrapperβ Wrapper for Commonmarker AST nodes -
Commonmarker::Merge::PartialTemplateMergerβ Section-level partial merges -
Commonmarker::Merge::MergeResultβ Markdown-specific merge result -
Commonmarker::Merge::ConflictResolverβ Markdown conflict resolution -
Commonmarker::Merge::FreezeNodeβ Markdown freeze block support -
Commonmarker::Merge::DebugLoggerβ Commonmarker-specific debug logging
Key Dependencies
| Gem | Role |
|---|---|
ast-merge (~> 4.0) |
Base classes and shared infrastructure |
tree_haver (~> 5.0) |
Unified parser adapter (wraps Commonmarker) |
commonmarker |
CommonMark Markdown parser (MRI only) |
version_gem (~> 1.1) |
Version management |
Parser Backend
commonmarker-merge uses the Commonmarker parser exclusively via TreeHaverβs :commonmarker backend:
| Backend | Parser | Platform | Notes |
|---|---|---|---|
:commonmarker |
Commonmarker | MRI only | CommonMark parser, native extension |
π Project Structure
lib/commonmarker/merge/
βββ smart_merger.rb # Main SmartMerger implementation
βββ partial_template_merger.rb # Section-level merging
βββ file_analysis.rb # Markdown file analysis
βββ node_wrapper.rb # AST node wrapper
βββ merge_result.rb # Merge result object
βββ conflict_resolver.rb # Conflict resolution
βββ freeze_node.rb # Freeze block support
βββ debug_logger.rb # Debug logging
βββ version.rb
spec/commonmarker/merge/
βββ smart_merger_spec.rb
βββ partial_template_merger_spec.rb
βββ file_analysis_spec.rb
βββ integration/
π§ Development Workflows
Running Tests
# Full suite
bundle exec rspec
# Single file (disable coverage threshold check)
K_SOUP_COV_MIN_HARD=false bundle exec rspec spec/commonmarker/merge/smart_merger_spec.rb
# Commonmarker backend tests
bundle exec rspec --tag commonmarker
Coverage Reports
cd /home/pboling/src/kettle-rb/ast-merge/vendor/commonmarker-merge
bin/rake coverage && bin/kettle-soup-cover -d
π Project Conventions
API Conventions
SmartMerger API
-
mergeβ Returns a String (the merged Markdown content) -
merge_resultβ Returns a MergeResult object -
to_son MergeResult returns the merged content as a string
PartialTemplateMerger API
-
mergeβ Merges a template section into a specific location in destination - Used by
ast-merge-recipefor section-level updates
Markdown-Specific Features
Heading-Based Sections:
# Section 1
Content for section 1
## Subsection 1.1
Nested content
# Section 2
Content for section 2
Freeze Blocks:
<!-- commonmarker-merge:freeze -->
Custom content that should not be overridden
<!-- commonmarker-merge:unfreeze -->
Standard content that merges normally
Link Reference Preservation:
[link text][ref]
[ref]: https://example.com
π§ͺ Testing Patterns
TreeHaver Dependency Tags
Available tags:
-
:commonmarkerβ Requires Commonmarker backend -
:markdown_parsingβ Requires Markdown parser
β CORRECT:
RSpec.describe Commonmarker::Merge::SmartMerger, :commonmarker do
# Skipped if Commonmarker not available
end
β WRONG:
before do
skip "Requires Commonmarker" unless defined?(CommonMarker) # DO NOT DO THIS
end
π‘ Key Insights
- Heading-based structure: Sections matched by heading text
-
.textstrips formatting: When matching by text, backticks and other formatting are removed - Link references preserved: Reference-style links maintained during merge
- PartialTemplateMerger: Supports injecting template sections into specific locations
-
Freeze blocks use HTML comments:
<!-- commonmarker-merge:freeze --> - MRI only: Commonmarker requires native extensions, MRI only
π« Common Pitfalls
- Commonmarker requires MRI: Does not work on JRuby or TruffleRuby
-
NEVER use manual skip checks β Use dependency tags (
:commonmarker) - Text matching strips formatting β Match on plain text, not markdown syntax
- Do NOT load vendor gems β They are not part of this project; they do not exist in CI
-
Use
tmp/for temporary files β Never use/tmpor other system directories
π§ Markdown-Specific Notes
Node Types
document # Root node
heading # # Heading
paragraph # Regular text
code_block # ```code```
list # - item or 1. item
link # [text](url)
image # 
Text Matching Behavior
Source: ### The `*-merge` Gem Family
.text: "The *-merge Gem Family\n"
# Backticks, bold, italic stripped in .text
Merge Behavior
- Headings: Matched by heading text (stripped of formatting)
- Sections: Content from heading to next same-level heading
- Paragraphs: Position-based within sections
- Code blocks: Matched by language and content
- Lists: Can be merged or replaced
- Links: Reference-style links preserved
- Freeze blocks: Protect customizations from template updates