Skip to content

Releases: kettle-rb/ast-merge

v4.0.6

19 Feb 10:57
v4.0.6
8693f36

Choose a tag to compare

4.0.6 - 2026-02-19

  • TAG: v4.0.6
  • COVERAGE: 96.37% -- 2552/2648 lines in 50 files
  • BRANCH COVERAGE: 87.22% -- 812/931 branches in 50 files
  • 98.81% documented

Added

  • AGENTS.md

Changed

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

v4.0.5

01 Feb 09:09
v4.0.5
f8c9264

Choose a tag to compare

4.0.5 - 2026-02-01

  • TAG: v4.0.5
  • COVERAGE: 96.37% -- 2552/2648 lines in 50 files
  • BRANCH COVERAGE: 87.22% -- 812/931 branches in 50 files
  • 98.81% documented

Added

  • More shared examples for ConflictResolverBase

Changed

  • tree_haver v5.0.3
  • improve robustness of tests

Fixed

  • Documentation fixes related to gem family section

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

v4.0.4

20 Jan 11:55
v4.0.4
105c034

Choose a tag to compare

4.0.4 - 2026-01-20

  • TAG: v4.0.4
  • COVERAGE: 96.37% -- 2552/2648 lines in 50 files
  • BRANCH COVERAGE: 87.22% -- 812/931 branches in 50 files
  • 98.81% documented

Added

  • RSpec Split Loading Pattern: New files for granular RSpec dependency tag loading
    • lib/ast/merge/rspec/setup.rb - Loads only registry and helper classes (no RSpec configuration)
    • lib/ast/merge/rspec/dependency_tags_helpers.rb - DependencyTags helper module
    • lib/ast/merge/rspec/dependency_tags_config.rb - RSpec.configure block with exclusion filters
    • Enables registering known gems before RSpec.configure runs (solving catch-22 problem)
    • Required for ast-merge test suite to preserve SimpleCov coverage
    • Required for merge gems that register other merge gems as dependencies
  • Ast::Merge::RSpec::MergeGemRegistry.force_check_availability!: Deferred availability checking for accurate test coverage
    • Called automatically in before(:suite) hook AFTER SimpleCov is loaded
    • Prevents premature gem loading that would bypass coverage instrumentation
    • Ensures accurate coverage reporting in merge gem test suites

Changed

  • RSpec Dependency Tags: Fixed exclusion filter setup to properly skip tests when optional gems unavailable
    • Exclusion filters now set during RSpec.configure (not in before(:suite) which runs too late)
    • Fixed RSpec API usage: config.filter_run_excluding tag => true (not [tag] = true)
    • ast-merge uses split loading pattern in spec/spec_helper.rb and spec/config/tree_haver.rb
    • markdown-merge uses split pattern (registers :commonmarker_merge, :markly_merge)
    • markly-merge uses split pattern (registers :prism_merge)
    • commonmarker-merge uses simple pattern (no registrations needed)

Fixed

  • Test coverage accuracy: Fixed premature gem loading that bypassed SimpleCov instrumentation
    • MergeGemRegistry.registered_gems now returns ONLY explicitly registered gems, not all KNOWN_GEMS
    • RSpec exclusion filters are configured in before(:suite) hook after force_check_availability! runs
    • This ensures gems are loaded AFTER SimpleCov sets up coverage instrumentation
    • Previously, commonmarker-merge reported only 11 lines covered when it should have been far more
  • RSpec Dependency Tags: Tests with tags like :markdown_merge, :markly_merge now properly skip when those gems aren't available
    • Fixed 141 test failures caused by tests running without required gems loaded
    • Removed require statements from integration specs - dependency tags handle gem loading
    • Fixed tag usage: Tests using Markdown::Merge::PartialTemplateMerger with :markly backend now correctly tagged with both :markdown_merge and :markly_merge
  • Thread-Safety Spec: Fixed JRuby concurrency test failure in NodeTyping::Normalizer#canonical_type
    • Changed from unsynchronized Array to thread-safe Queue for collecting results from concurrent threads
    • Eliminates ConcurrencyError: Detected invalid array contents due to unsynchronized modifications

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

v4.0.3

20 Jan 06:53
v4.0.3
27580c8

Choose a tag to compare

4.0.3 - 2026-01-19

  • TAG: v4.0.3
  • COVERAGE: 97.30% -- 2739/2815 lines in 53 files
  • BRANCH COVERAGE: 89.84% -- 893/994 branches in 53 files
  • 98.81% documented

Added

  • Ast::Merge::RSpec::MergeGemRegistry.register_known_gems: Selective registration of known merge gems for RSpec dependency tags
    • Allows test suites to explicitly register only the merge gems they need, avoiding overhead of registering all known gems
    • Usage in spec/config/tree_haver.rb: MergeGemRegistry.register_known_gems(:prism_merge, :commonmarker_merge)
    • Enables proper RSpec tag-based test skipping for optional merge gem dependencies
    • Example: Tests tagged with :prism_merge are automatically skipped when prism-merge isn't available

Changed

  • Upgrade to tree_haver v5.0.2
  • RSpec dependency tag load order pattern: Merge gems now load tree_haver and dependency tags early via spec/config/tree_haver.rb
    • Ensures TreeHaver::RSpec::DependencyTags is loaded before gems register themselves
    • Pattern: Load tree_haver/rspec → Load ast/merge/rspec → Register known gems → Load library
    • Applied to markdown-merge and markly-merge; other merge gems should follow this pattern

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

v4.0.2

12 Jan 12:39
v4.0.2
73cec7a

Choose a tag to compare

4.0.2 - 2026-01-12

  • TAG: v4.0.2
  • COVERAGE: 97.30% -- 2739/2815 lines in 53 files
  • BRANCH COVERAGE: 89.84% -- 893/994 branches in 53 files
  • 98.81% documented

Added

  • Recipe::Runner target file override: Accept target_files parameter to override recipe targets
    • Runner.new(recipe, target_files: ["file1.md", "file2.md"]) - Process only specified files
    • Paths are expanded relative to base_dir
    • When not specified, falls back to recipe's configured targets
  • exe/ast-merge-recipe file arguments: Accept target files on command line
    • ast-merge-recipe recipe.yml file1.md file2.md - Override recipe targets
    • Updated help text and banner to document new usage
  • bin/update_gem_family_section file arguments: Accept target files on command line
    • bin/update_gem_family_section vendor/my-gem/README.md - Process specific file(s)
    • If no files specified, defaults to README.md + vendor/*/README.md
    • Added --skip-fix option to skip the formatting fix step

Changed

  • bin/update_gem_family_section: Refactored to use OptionParser for clean option handling
    • Consistent with bin/fix_readme_formatting style
    • Properly separates options from file arguments

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

v4.0.1

12 Jan 05:17
v4.0.1
3631859

Choose a tag to compare

4.0.1 - 2026-01-11

  • TAG: v4.0.1
  • COVERAGE: 96.45% -- 2553/2647 lines in 51 files
  • BRANCH COVERAGE: 87.41% -- 812/929 branches in 51 files
  • 98.80% documented

Added

  • Ast::Merge::RSpec::MergeGemRegistry - Fully dynamic merge gem registration for RSpec dependency tags
    • register(tag_name, require_path:, merger_class:, test_source:, category:) - Register a merge gem
    • available?(tag_name) - Check if a merge gem is available and functional
    • registered_gems - Get all registered gem tag names
    • gems_by_category(category) - Filter gems by category (:markdown, :data, :code, :config, :other)
    • summary - Get availability status of all registered gems
    • Automatically defines *_available? methods on DependencyTags at registration time
    • External merge gems can now get full RSpec tag support without modifying ast-merge

Changed

  • Upgrade to tree_haver v5.0.1
  • Ast::Merge::AstNode now inherits from TreeHaver::Base::Node
    • Ensures synthetic nodes stay in sync with the canonical Node API
    • Inherits Comparable, Enumerable from base class
    • Retains all existing methods and behavior (Point, Location, signature, etc.)
    • Constructor calls super(self, source: source) to properly initialize base class
  • RSpec Dependency Tags refactored to use MergeGemRegistry
    • Removed hardcoded merge gem availability checks
    • Removed MERGE_GEM_TEST_SOURCES constant
    • *_available? methods are now defined dynamically when gems register
    • any_markdown_merge_available? now queries registry by category
    • RSpec exclusion filters are configured dynamically from registry
  • Ast::Merge::Testing::TestableNode now delegates to TreeHaver::RSpec::TestableNode
    • The TestableNode implementation has been moved to tree_haver for sharing across all merge gems
    • spec/support/testable_node.rb now requires and re-exports the tree_haver version
    • Backward compatible: existing tests continue to work unchanged
  • spec/ast/merge/node_wrapper_base_spec.rb refactored to use TestableNode instead of mocks
    • Real TreeHaver::Node behavior for most tests
    • Mocks only retained for edge case testing (e.g., invalid end_line before start_line)

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

v4.0.0

11 Jan 12:04
v4.0.0
44360a1

Choose a tag to compare

4.0.0 - 2026-01-11

  • TAG: v4.0.0
  • COVERAGE: 96.52% -- 2555/2647 lines in 51 files
  • BRANCH COVERAGE: 87.62% -- 814/929 branches in 51 files
  • 98.80% documented

Added

  • Recipe::Preset#normalize_whitespace - option to collapse excessive blank lines in merged output
  • Recipe::Preset#rehydrate_link_references - option to convert inline links to reference style
  • Recipe::Runner::Result#problems - access document problems found during merge
  • exe/ast-merge-recipe --show-problems - flag to display document problems in CLI output
  • Ast::Merge::DiffMapperBase - Abstract base class for mapping unified git diffs to AST node paths
    • DiffHunk struct for representing diff hunks with line numbers and content
    • DiffLine struct for individual diff lines with type (:context, :addition, :removal)
    • DiffMapping struct for mapping changes to AST paths with operation type
    • DiffParseResult struct for parsed diff with file paths and hunks
    • #parse_diff(diff_text) - Parse unified git diff format into structured hunks
    • #determine_operation(hunk) - Detect :add, :remove, or :modify from hunk content
    • Abstract #map_hunk_to_paths for format-specific implementations
    • Abstract #create_analysis for format-specific file analysis
  • Ast::Merge::ConflictResolverBase - New options for advanced merge control:
    • recursive: true | false | Integer - Control recursive merging of nested structures
      • true (default): Unlimited depth recursive merging
      • false: Disabled, replace entire matched nodes
      • Integer > 0: Maximum recursion depth
      • 0: Invalid, raises ArgumentError
    • remove_template_missing_nodes: false - When true, removes destination nodes not present in template
    • #should_recurse?(depth) - Helper to check if recursion should continue at given depth
    • #validate_recursive! - Validation for recursive parameter
  • exe/ast-merge-diff - CLI executable for applying git diffs via AST-aware merging
    • Auto-detects format from file extension (.yml, .yaml, .json, .rb, etc.)
    • --diff FILE - Path to unified diff file (use - for stdin, default: stdin)
    • --original FILE - Original file for AST path mapping (required)
    • --destination FILE - Destination file to merge into (required)
    • --format FORMAT - Override format auto-detection
    • --dry-run - Preview changes without writing
    • --verbose - Detailed output
    • --add-only - Only apply additions from diff
    • --remove-only - Only apply removals from diff
    • Uses bundler/inline with dynamic gem loading based on detected format

Changed

  • BREAKING: Upgrade to tree_haver v5.0.0
  • BREAKING: Refactored navigation classes into Ast::Merge::Navigable namespace
    • Ast::Merge::NavigableStatementAst::Merge::Navigable::Statement
    • Ast::Merge::InjectionPointAst::Merge::Navigable::InjectionPoint
    • Ast::Merge::InjectionPointFinderAst::Merge::Navigable::InjectionPointFinder
    • Each class is now in its own file under lib/ast/merge/navigable/
    • Uses autoload for lazy loading
  • bin/fix_readme_formatting - Rewritten to use SmartMerger API
    • Now uses Markdown::Merge::SmartMerger with normalize_whitespace: :link_refs and rehydrate_link_references: true
    • The :link_refs mode collapses excessive blank lines AND removes blank lines between consecutive link reference definitions
    • Merges empty template with destination to apply cleanup transformations
    • Reports duplicate link definitions, link ref spacing fixes, and other problems from MergeResult#problems
    • Removed custom regex-based link rehydration and whitespace normalization

Fixed

  • Ast::Merge::PartialTemplateMergerBase#normalize_matcher now preserves same_or_shallower key from boundary config
  • Ast::Merge::PartialTemplateMergerBase#merge now passes boundary_same_or_shallower to InjectionPointFinder#find

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

v3.1.0

08 Jan 11:58
v3.1.0
a84a92c

Choose a tag to compare

3.1.0 - 2026-01-08

  • TAG: v3.1.0
  • COVERAGE: 96.89% -- 2465/2544 lines in 47 files
  • BRANCH COVERAGE: 89.62% -- 794/886 branches in 47 files
  • 98.75% documented

Added

  • Ast::Merge::EmitterBase - Abstract base class for format-specific emitters
    • Provides common infrastructure for converting AST structures back to text
    • Tracks indentation level with configurable indent_size (default: 2 spaces)
    • Manages output lines collection with #lines accessor
    • #emit_blank_line - Emit an empty line
    • #emit_leading_comments - Emit comments from CommentTracker
    • #emit_raw_lines - Emit lines without modification (preserves exact formatting)
    • #to_s - Get output as a single string with trailing newline
    • #clear - Reset emitter state
    • #indent / #dedent - Increase/decrease indentation level
    • Subclass hooks: #initialize_subclass_state, #clear_subclass_state, #emit_tracked_comment
    • Used by jsonc-merge, json-merge, bash-merge, toml-merge, and psych-merge emitters

Changed

  • tree_haver v4.0.0

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

v3.0.0

06 Jan 05:11
v3.0.0
d650175

Choose a tag to compare

3.0.0 - 2026-01-05

  • TAG: v3.0.0
  • COVERAGE: 96.93% -- 2462/2540 lines in 47 files
  • BRANCH COVERAGE: 89.62% -- 794/886 branches in 47 files
  • 98.72% documented

Added

  • TestableNode spec helper class that wraps a mock in a real TreeHaver::Node, providing consistent API testing without relying on fragile mocks
  • Recipe::Preset#match_refiner accessor method (was missing, causing errors in Recipe::Runner)
  • Minimal reproduction specs for to_commonmark normalization behavior:
    • spec/integration/link_reference_preservation_spec.rb - tests link ref preservation
    • spec/integration/table_formatting_preservation_spec.rb - tests table padding preservation
  • Ast::Merge::PartialTemplateMergerBase - Abstract base class for parser-agnostic partial template merging
    • #build_position_based_signature_generator - Creates signature generators that match elements by position
    • Position counters reset per document key, enabling tables at same position to match regardless of structure

Changed

  • BREAKING: NavigableStatement#text now requires nodes to conform to TreeHaver Node API (must have #text method)
    • Removed conditional fallbacks for to_plaintext, to_commonmark, slice
    • Nodes must now implement #text directly (all TreeHaver backends already do)
  • BREAKING: ContentMatchRefiner#extract_content now requires nodes to conform to TreeHaver Node API
    • Removed conditional fallbacks for text_content, string_content, content, to_s
    • Custom content_extractor proc still supported for non-standard nodes
  • Signature generators and typing scripts now receive TreeHaver nodes directly (no NavigableStatement wrapping)
  • Removed NavigableStatement wrapping from FileAnalyzable#generate_signature and NodeTyping.process

Removed

  • BREAKING: Ast::Merge::PartialTemplateMerger removed. Use Markdown::Merge::PartialTemplateMerger directly.
    • The base class Ast::Merge::PartialTemplateMergerBase remains for other parsers to extend
    • Migration: change Ast::Merge::PartialTemplateMerger.new(parser: :markly, ...) to
      Markdown::Merge::PartialTemplateMerger.new(backend: :markly, ...)

Fixed

  • Source-based rendering: Markdown::Merge::PartialTemplateMerger#node_to_text now prefers extracting
    original source text using analysis.source_range instead of to_commonmark. This preserves:
    • Link reference definitions (no conversion to inline links)
    • Table column padding/alignment
    • Original formatting exactly as written

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

v2.0.10

05 Jan 04:17
v2.0.10
6b93724

Choose a tag to compare

2.0.10 - 2026-01-04

  • TAG: v2.0.10
  • COVERAGE: 97.10% -- 2642/2721 lines in 48 files
  • BRANCH COVERAGE: 89.57% -- 893/997 branches in 48 files
  • 98.72% documented

Added

  • Dependency tags for rbs_merge and not_rbs_merge

Changed

  • Upgraded to tree_haver v3.2.4 (major new features, and bug fixes, see release notes)

Fixed

  • PartialTemplateMerger#build_merged_content previously always injected an extra newline between parts, now join is context-aware

Official Discord 👉️ Live Chat on Discord

Many paths lead to being a sponsor or a backer of this project. Are you on such a path?

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon