Skip to content

Releases: kettle-rb/prism-merge

v2.0.4

22 Feb 17:33
v2.0.4
41f0c08

Choose a tag to compare

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_lines now 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 so add_node_to_result and
    merge_node_body_recursively skip 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_merge now checks whether the output source's
    analysis had a trailing blank before advancing last_output_dest_line, so
    emit_dest_gap_lines correctly emits dest gap lines that the template lacked.

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.3

22 Feb 15:35
v2.0.3
cc96573

Choose a tag to compare

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_recursively assembled its output (opening line, merged body,
    closing end) without emitting the trailing blank line that separates
    consecutive blocks. add_node_to_result already handles this for non-recursive
    nodes, but the recursive path was missing the same logic. Now emits a trailing
    blank line after the closing end when the source has one.

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.2

22 Feb 15:09
v2.0.2
58d79d7

Choose a tag to compare

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.,
    gemspec add_dependency lines 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 iterated trailing_comments and re-emitted any
    comment on the same line — duplicating the entire line. Now skips trailing
    comments whose start_line falls within the node's own line range. This was the
    root cause of every add_dependency / add_development_dependency being
    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_generator as @raw_signature_generator and pass it
    (instead of the already-effective generator) to inner SmartMerger instances.
    This ensures build_effective_signature_generator wraps it only once when
    node_typing is also configured.

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.1

22 Feb 12:19
v2.0.1
98c274e

Choose a tag to compare

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_lines preserves magic comments (e.g., # frozen_string_literal: true)
    and blank lines that appear before the first AST node in the destination file
  • SmartMerger#emit_dest_gap_lines preserves blank lines between consecutive top-level blocks
    in the destination, preventing them from being silently stripped during merge

Changed

  • SmartMerger#merge_with_debug now uses merge_result (returns MergeResult object)
    instead of merge (returns String), so statistics and decision_summary are accessible
  • SmartMerger#build_result now passes template_analysis and dest_analysis to
    MergeResult.new for consistency with SmartMergerBase API

Removed

  • Removed redundant attr_reader :node_typing from SmartMerger — already provided
    by SmartMergerBase

Fixed

  • Inter-node blank line stripping: blank lines between top-level blocks (e.g., between
    appraise blocks in Appraisals, between gem calls 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: true in Appraisal.root.gemfile) are now preserved

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.0

19 Feb 12:48
v2.0.0
f3ea2ac

Choose a tag to compare

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 #errors method for compatibility with SmartMergerBase
    • Returns @parse_result.errors for consistency with other FileAnalysis classes
    • Enables SmartMergerBase to properly create parse errors when valid? is false
  • 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 **options for forward compatibility
    • Now passes node_typing explicitly to SmartMergerBase instead of storing locally
    • Accepts additional options that may be added to base class in future
  • FileAnalysis: Added **options for forward compatibility
    • Accepts additional options that may be added in future
    • Consistent with other *-merge gems' FileAnalysis classes
  • MergeResult: Added **options for forward compatibility
  • ParseError: Updated constructor to accept base class signature
    • Now accepts optional message, errors:, content:, and parse_result: keywords
    • Compatible with Ast::Merge::ParseError signature while preserving parse_result attribute
    • Enables SmartMergerBase to create parse errors without Prism-specific knowledge
  • Updated documentation on hostile takeover of RubyGems
  • BREAKING: Error classes now inherit from Ast::Merge base classes:
    • Prism::Merge::Error now inherits from Ast::Merge::Error (was StandardError)
    • Prism::Merge::ParseError now inherits from Ast::Merge::ParseError (was Prism::Merge::Error)
    • ParseError#errors attribute added (array of error objects from parse_result.errors)
    • Code using e.parse_result.errors should now use e.errors directly
    • parse_result attribute is still available for Prism-specific access

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

v1.1.6

05 Dec 09:57
v1.1.6
712e0de

Choose a tag to compare

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_body to include content after the last statement up to the closing line, ensuring freeze blocks at the end of block bodies are preserved

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

v1.1.5

05 Dec 07:04
v1.1.5
92d6f8e

Choose a tag to compare

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 with freeze_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_token to nested mergers and ensures extract_node_body includes 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.

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

v1.1.4

05 Dec 04:58
v1.1.4
12e59b2

Choose a tag to compare

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::Node or FreezeNode to 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, returning nil was 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 ConflictResolver that 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.

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

v1.1.3

05 Dec 01:16
v1.1.3
23afbb3

Choose a tag to compare

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_node method was using node.slice which loses leading indentation. Now uses source_analysis.line_at to get full lines from the source file, preserving original indentation.

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

v1.1.2

05 Dec 00:32
v1.1.2
e5ac631

Choose a tag to compare

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-matched
  • mergeable_statement? private method to determine if a node type can generate signatures for merging
  • max_recursion_depth option (defaults to Float::INFINITY) as a safety valve for edge cases

Fixed

  • Fixed infinite recursion when merging CallNode blocks (like git_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.

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