Releases: kettle-rb/prism-merge
v2.0.4
2.0.4 - 2026-02-22
- TAG: v2.0.4
- COVERAGE: 98.34% -- 891/906 lines in 12 files
- BRANCH COVERAGE: 84.34% -- 501/594 branches in 12 files
- 93.51% documented
Fixed
- Always preserve destination magic comments (
# frozen_string_literal: true,
# encoding: UTF-8, etc.) at the top of merged output, regardless of merge
preference. Magic comments are file-level metadata managed by Prism and must
not be lost when the template side lacks them (e.g. after filtering).
emit_dest_prefix_linesnow detects contiguous magic comments from the first
destination node's leading comments, emits them before any template-only nodes
(Phase 1), and records the emitted line numbers soadd_node_to_resultand
merge_node_body_recursivelyskip them to prevent duplication. - Non-top-of-file magic comments (e.g. used as documentation) are left alone and
treated as regular comments. - Fix blank line preservation between magic comments and subsequent comments when
template preference is used. Gap lines between a stripped magic comment and the
next remaining comment are now correctly emitted from the template source. - Fix inter-node gap line preservation when a matched node is output from the
template source.perform_mergenow checks whether the output source's
analysis had a trailing blank before advancinglast_output_dest_line, so
emit_dest_gap_linescorrectly emits dest gap lines that the template lacked.
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v2.0.3
2.0.3 - 2026-02-22
- TAG: v2.0.3
- COVERAGE: 98.81% -- 829/839 lines in 12 files
- BRANCH COVERAGE: 85.71% -- 456/532 branches in 12 files
- 93.51% documented
Fixed
- Fix blank lines between blocks being stripped during recursive body merging.
merge_node_body_recursivelyassembled its output (opening line, merged body,
closingend) without emitting the trailing blank line that separates
consecutive blocks.add_node_to_resultalready handles this for non-recursive
nodes, but the recursive path was missing the same logic. Now emits a trailing
blank line after the closingendwhen the source has one.
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v2.0.2
2.0.2 - 2026-02-22
- TAG: v2.0.2
- COVERAGE: 98.80% -- 823/833 lines in 12 files
- BRANCH COVERAGE: 85.61% -- 452/528 branches in 12 files
- 93.51% documented
Fixed
- Fix node duplication when merging files with inline trailing comments (e.g.,
gemspecadd_dependencylines with# ruby >= 3.2.0).add_node_to_result
output the full source line (which already includes inline comments via
analysis.line_at), then also iteratedtrailing_commentsand re-emitted any
comment on the same line — duplicating the entire line. Now skips trailing
comments whosestart_linefalls within the node's own line range. This was the
root cause of everyadd_dependency/add_development_dependencybeing
duplicated in gemspec and gemfile merges when inline comments were present. - Prevent potential double-wrapping in
merge_node_body_recursively— store the
raw (unwrapped)signature_generatoras@raw_signature_generatorand pass it
(instead of the already-effective generator) to innerSmartMergerinstances.
This ensuresbuild_effective_signature_generatorwraps it only once when
node_typingis also configured.
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v2.0.1
2.0.1 - 2026-02-22
- TAG: v2.0.1
- COVERAGE: 98.80% -- 820/830 lines in 12 files
- BRANCH COVERAGE: 85.55% -- 450/526 branches in 12 files
- 93.51% documented
Added
SmartMerger#emit_dest_prefix_linespreserves magic comments (e.g.,# frozen_string_literal: true)
and blank lines that appear before the first AST node in the destination fileSmartMerger#emit_dest_gap_linespreserves blank lines between consecutive top-level blocks
in the destination, preventing them from being silently stripped during merge
Changed
SmartMerger#merge_with_debugnow usesmerge_result(returnsMergeResultobject)
instead ofmerge(returnsString), sostatisticsanddecision_summaryare accessibleSmartMerger#build_resultnow passestemplate_analysisanddest_analysisto
MergeResult.newfor consistency withSmartMergerBaseAPI
Removed
- Removed redundant
attr_reader :node_typingfromSmartMerger— already provided
bySmartMergerBase
Fixed
- Inter-node blank line stripping: blank lines between top-level blocks (e.g., between
appraiseblocks in Appraisals, betweengemcalls in Gemfiles) are now preserved
from the destination source during merge - Prefix line stripping: magic comments and blank lines before the first AST statement
(e.g.,# frozen_string_literal: truein Appraisal.root.gemfile) are now preserved
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v2.0.0
2.0.0 - 2026-02-19
- TAG: v2.0.0
- COVERAGE: 97.26% -- 780/802 lines in 12 files
- BRANCH COVERAGE: 82.07% -- 412/502 branches in 12 files
- 93.59% documented
Added
- Many new features inherited from
ast-merge, and updated behaviors. - FileAnalysis: Added
#errorsmethod for compatibility with SmartMergerBase- Returns
@parse_result.errorsfor consistency with other FileAnalysis classes - Enables SmartMergerBase to properly create parse errors when
valid?is false
- Returns
- AGENTS.md
Changed
- appraisal2 v3.0.6
- kettle-test v1.0.10
- stone_checksums v1.0.3
- ast-merge v4.0.6
- tree_haver v5.0.5
- tree_stump v0.2.0
- fork no longer required, updates all applied upstream
- SmartMerger: Added
**optionsfor forward compatibility- Now passes
node_typingexplicitly toSmartMergerBaseinstead of storing locally - Accepts additional options that may be added to base class in future
- Now passes
- FileAnalysis: Added
**optionsfor forward compatibility- Accepts additional options that may be added in future
- Consistent with other
*-mergegems' FileAnalysis classes
- MergeResult: Added
**optionsfor forward compatibility - ParseError: Updated constructor to accept base class signature
- Now accepts optional
message,errors:,content:, andparse_result:keywords - Compatible with
Ast::Merge::ParseErrorsignature while preservingparse_resultattribute - Enables SmartMergerBase to create parse errors without Prism-specific knowledge
- Now accepts optional
- Updated documentation on hostile takeover of RubyGems
- BREAKING: Error classes now inherit from
Ast::Mergebase classes:Prism::Merge::Errornow inherits fromAst::Merge::Error(wasStandardError)Prism::Merge::ParseErrornow inherits fromAst::Merge::ParseError(wasPrism::Merge::Error)ParseError#errorsattribute added (array of error objects fromparse_result.errors)- Code using
e.parse_result.errorsshould now usee.errorsdirectly parse_resultattribute is still available for Prism-specific access
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v1.1.6
1.1.6 - 2025-12-05
- TAG: v1.1.6
- COVERAGE: 98.31% -- 929/945 lines in 9 files
- BRANCH COVERAGE: 87.08% -- 391/449 branches in 9 files
- 100.00% documented
Fixed
- Fixed duplicate content when freeze blocks precede nodes with leading comments: When a freeze block appeared before a node that had leading comments attached from earlier in the file, the merge would output duplicate content. Fixed by:
- Filtering out comments inside freeze blocks from being attached as leading comments to subsequent nodes
- Not including leading comments in anchor ranges when other nodes exist between the comments and the node
- Extending
extract_node_bodyto include content after the last statement up to the closing line, ensuring freeze blocks at the end of block bodies are preserved
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v1.1.5
1.1.5 - 2025-12-04
- TAG: v1.1.5
- COVERAGE: 98.26% -- 906/922 lines in 9 files
- BRANCH COVERAGE: 87.27% -- 384/440 branches in 9 files
- 100.00% documented
Changed
- Recursive merge now preserves freeze blocks: When recursively merging nested block bodies (e.g.,
Gem::Specification.new do ... end), freeze blocks inside the body are now properly preserved. Previously, nested mergers were created withfreeze_token: nil, causing freeze blocks to be lost.
Fixed
- Fixed freeze blocks lost in nested block bodies: Freeze blocks inside class, module, or call-with-block bodies were being lost during recursive merge. The fix passes
freeze_tokento nested mergers and ensuresextract_node_bodyincludes leading comments/freeze markers that appear between the node's opening line and the first statement. - Fixed duplicate freeze markers in output: Freeze/unfreeze marker comments were incorrectly attached as leading comments to subsequent nodes, causing duplicate markers in merged output. These markers are now filtered from leading comments since they belong to FreezeNode boundaries.
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v1.1.4
1.1.4 - 2025-12-04
- TAG: v1.1.4
- COVERAGE: 98.26% -- 902/918 lines in 9 files
- BRANCH COVERAGE: 87.59% -- 381/435 branches in 9 files
- 100.00% documented
Added
- Custom signature generator fallthrough support: Custom signature generators can now return a
Prism::NodeorFreezeNodeto fall through to the default signature computation. This allows custom generators to only override specific node types while delegating others to the built-in logic. Previously, returningnilwas the only way to skip custom handling, but that prevented proper matching for unhandled node types. - Variable assignment node signatures: Added signature support for all variable write node types:
LocalVariableWriteNode→[:local_var, name]InstanceVariableWriteNode→[:ivar, name]ClassVariableWriteNode→[:cvar, name]GlobalVariableWriteNode→[:gvar, name]MultiWriteNode→[:multi_write, [target_names]]
Removed
- Removed pre-prism code in
ConflictResolverthat compared template node line numbers against destination freeze block line numbers (cross-file line comparison makes no sense)
Fixed
- Fixed template-only nodes not being added when destination has freeze blocks: When
add_template_only_nodes: true, template nodes with no matching signature in destination were incorrectly skipped if the destination contained freeze blocks. The bug was caused by comparing template node line numbers against destination freeze block line numbers, which is a meaningless cross-file comparison. Template-only nodes are now correctly added regardless of freeze block presence.
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v1.1.3
1.1.3 - 2025-12-04
- TAG: v1.1.3
- COVERAGE: 96.71% -- 881/911 lines in 9 files
- BRANCH COVERAGE: 82.86% -- 348/420 branches in 9 files
- 100.00% documented
Fixed
- Fixed indentation loss when adding nodes to merge result - the
add_nodemethod was usingnode.slicewhich loses leading indentation. Now usessource_analysis.line_atto get full lines from the source file, preserving original indentation.
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?
v1.1.2
1.1.2 - 2025-12-04
- TAG: v1.1.2
- COVERAGE: 96.66% -- 868/898 lines in 9 files
- BRANCH COVERAGE: 82.84% -- 338/408 branches in 9 files
- 100.00% documented
Added
body_has_mergeable_statements?private method to check if a block body contains statements that can be signature-matchedmergeable_statement?private method to determine if a node type can generate signatures for mergingmax_recursion_depthoption (defaults toFloat::INFINITY) as a safety valve for edge cases
Fixed
- Fixed infinite recursion when merging
CallNodeblocks (likegit_source) that have matching signatures but non-mergeable body content (e.g., just string literals). The fix detects when a block body contains only literals/expressions with no signature-matchable statements and treats the node atomically instead of recursing.
Many paths lead to being a sponsor or a backer of this project. Are you on such a path?