Releases: kettle-rb/ast-merge
v4.0.6
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
- Updated documentation on hostile takeover of RubyGems
- appraisal2 v3.0.6
- kettle-test v1.0.10
- stone_checksums v1.0.3
- tree_haver v5.0.5
- tree_stump v0.2.0
- fork no longer required, updates all applied upstream
- Updated documentation on hostile takeover of RubyGems
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v4.0.5
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
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v4.0.4
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 modulelib/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
- Called automatically in
Changed
- RSpec Dependency Tags: Fixed exclusion filter setup to properly skip tests when optional gems unavailable
- Exclusion filters now set during
RSpec.configure(not inbefore(:suite)which runs too late) - Fixed RSpec API usage:
config.filter_run_excluding tag => true(not[tag] = true) ast-mergeuses split loading pattern inspec/spec_helper.rbandspec/config/tree_haver.rbmarkdown-mergeuses split pattern (registers:commonmarker_merge,:markly_merge)markly-mergeuses split pattern (registers:prism_merge)commonmarker-mergeuses simple pattern (no registrations needed)
- Exclusion filters now set during
Fixed
- Test coverage accuracy: Fixed premature gem loading that bypassed SimpleCov instrumentation
MergeGemRegistry.registered_gemsnow returns ONLY explicitly registered gems, not all KNOWN_GEMS- RSpec exclusion filters are configured in
before(:suite)hook afterforce_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_mergenow properly skip when those gems aren't available- Fixed 141 test failures caused by tests running without required gems loaded
- Removed
requirestatements from integration specs - dependency tags handle gem loading - Fixed tag usage: Tests using
Markdown::Merge::PartialTemplateMergerwith:marklybackend now correctly tagged with both:markdown_mergeand:markly_merge
- Thread-Safety Spec: Fixed JRuby concurrency test failure in
NodeTyping::Normalizer#canonical_type- Changed from unsynchronized
Arrayto thread-safeQueuefor collecting results from concurrent threads - Eliminates
ConcurrencyError: Detected invalid array contents due to unsynchronized modifications
- Changed from unsynchronized
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v4.0.3
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_mergeare 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::DependencyTagsis 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
- Ensures
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v4.0.2
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::Runnertarget file override: Accepttarget_filesparameter to override recipe targetsRunner.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-recipefile arguments: Accept target files on command lineast-merge-recipe recipe.yml file1.md file2.md- Override recipe targets- Updated help text and banner to document new usage
bin/update_gem_family_sectionfile arguments: Accept target files on command linebin/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-fixoption to skip the formatting fix step
Changed
bin/update_gem_family_section: Refactored to useOptionParserfor clean option handling- Consistent with
bin/fix_readme_formattingstyle - Properly separates options from file arguments
- Consistent with
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v4.0.1
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 tagsregister(tag_name, require_path:, merger_class:, test_source:, category:)- Register a merge gemavailable?(tag_name)- Check if a merge gem is available and functionalregistered_gems- Get all registered gem tag namesgems_by_category(category)- Filter gems by category (:markdown, :data, :code, :config, :other)summary- Get availability status of all registered gems- Automatically defines
*_available?methods onDependencyTagsat 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::AstNodenow inherits fromTreeHaver::Base::Node- Ensures synthetic nodes stay in sync with the canonical Node API
- Inherits
Comparable,Enumerablefrom 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_SOURCESconstant *_available?methods are now defined dynamically when gems registerany_markdown_merge_available?now queries registry by category- RSpec exclusion filters are configured dynamically from registry
Ast::Merge::Testing::TestableNodenow delegates toTreeHaver::RSpec::TestableNode- The TestableNode implementation has been moved to tree_haver for sharing across all merge gems
spec/support/testable_node.rbnow requires and re-exports the tree_haver version- Backward compatible: existing tests continue to work unchanged
spec/ast/merge/node_wrapper_base_spec.rbrefactored to useTestableNodeinstead of mocks- Real TreeHaver::Node behavior for most tests
- Mocks only retained for edge case testing (e.g., invalid end_line before start_line)
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v4.0.0
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 outputRecipe::Preset#rehydrate_link_references- option to convert inline links to reference styleRecipe::Runner::Result#problems- access document problems found during mergeexe/ast-merge-recipe --show-problems- flag to display document problems in CLI outputAst::Merge::DiffMapperBase- Abstract base class for mapping unified git diffs to AST node pathsDiffHunkstruct for representing diff hunks with line numbers and contentDiffLinestruct for individual diff lines with type (:context,:addition,:removal)DiffMappingstruct for mapping changes to AST paths with operation typeDiffParseResultstruct 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:modifyfrom hunk content- Abstract
#map_hunk_to_pathsfor format-specific implementations - Abstract
#create_analysisfor format-specific file analysis
Ast::Merge::ConflictResolverBase- New options for advanced merge control:recursive: true | false | Integer- Control recursive merging of nested structurestrue(default): Unlimited depth recursive mergingfalse: Disabled, replace entire matched nodesInteger > 0: Maximum recursion depth0: Invalid, raisesArgumentError
remove_template_missing_nodes: false- Whentrue, 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
- Auto-detects format from file extension (
Changed
- BREAKING: Upgrade to tree_haver v5.0.0
- BREAKING: Refactored navigation classes into
Ast::Merge::NavigablenamespaceAst::Merge::NavigableStatement→Ast::Merge::Navigable::StatementAst::Merge::InjectionPoint→Ast::Merge::Navigable::InjectionPointAst::Merge::InjectionPointFinder→Ast::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::SmartMergerwithnormalize_whitespace: :link_refsandrehydrate_link_references: true - The
:link_refsmode 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
- Now uses
Fixed
Ast::Merge::PartialTemplateMergerBase#normalize_matchernow preservessame_or_shallowerkey from boundary configAst::Merge::PartialTemplateMergerBase#mergenow passesboundary_same_or_shallowertoInjectionPointFinder#find
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v3.1.0
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
#linesaccessor #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
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v3.0.0
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
TestableNodespec helper class that wraps a mock in a realTreeHaver::Node, providing consistent API testing without relying on fragile mocksRecipe::Preset#match_refineraccessor method (was missing, causing errors in Recipe::Runner)- Minimal reproduction specs for
to_commonmarknormalization behavior:spec/integration/link_reference_preservation_spec.rb- tests link ref preservationspec/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#textnow requires nodes to conform to TreeHaver Node API (must have#textmethod)- Removed conditional fallbacks for
to_plaintext,to_commonmark,slice - Nodes must now implement
#textdirectly (all TreeHaver backends already do)
- Removed conditional fallbacks for
- BREAKING:
ContentMatchRefiner#extract_contentnow requires nodes to conform to TreeHaver Node API- Removed conditional fallbacks for
text_content,string_content,content,to_s - Custom
content_extractorproc still supported for non-standard nodes
- Removed conditional fallbacks for
- Signature generators and typing scripts now receive TreeHaver nodes directly (no NavigableStatement wrapping)
- Removed NavigableStatement wrapping from
FileAnalyzable#generate_signatureandNodeTyping.process
Removed
- BREAKING:
Ast::Merge::PartialTemplateMergerremoved. UseMarkdown::Merge::PartialTemplateMergerdirectly.- The base class
Ast::Merge::PartialTemplateMergerBaseremains for other parsers to extend - Migration: change
Ast::Merge::PartialTemplateMerger.new(parser: :markly, ...)to
Markdown::Merge::PartialTemplateMerger.new(backend: :markly, ...)
- The base class
Fixed
- Source-based rendering:
Markdown::Merge::PartialTemplateMerger#node_to_textnow prefers extracting
original source text usinganalysis.source_rangeinstead ofto_commonmark. This preserves:- Link reference definitions (no conversion to inline links)
- Table column padding/alignment
- Original formatting exactly as written
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v2.0.10
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_mergeandnot_rbs_merge
Changed
- Upgraded to
tree_haverv3.2.4 (major new features, and bug fixes, see release notes)
Fixed
PartialTemplateMerger#build_merged_contentpreviously always injected an extra newline between parts, now join is context-aware
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?