prism-merge 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1425ee625e5f45061e5faa4d942371f94498082aa00660a4e8b42d50c49b1368
4
- data.tar.gz: 45b4f7343c85a8b87b95929c4a17da4db132cb69dfdcfdf3a4078e2ea88f1838
3
+ metadata.gz: d39e0e854397866379ca524e10088fdaa4d31029358962472fec0c174e0780c4
4
+ data.tar.gz: 2805f8137670b5660f510cc6ca119447ac3e90967da0b0b09cc5cd7ca621fd51
5
5
  SHA512:
6
- metadata.gz: 45baf957dc196b7f81084a98ae8c52a3d9121e40d8b39355320825cf02b033b2381ae30ce54b439519808fc3dc859ba653e29b2042770497cbef5b53dd796a7c
7
- data.tar.gz: cb6bab2681c92c7900265fbc5fe136dc712bfe1d20cade3aa3145962f7966c4db66aa5d3f34b19887aa707ad362429edae8e7bdb5d371de46acd6ee3221f39c6
6
+ metadata.gz: dcc00673756cdb1619b0189b1dfb0a8048b7035c4eee228b46cf9ccc5d215211bb7d39a9721a40027e63f8507b75646643240ddab107004658f0686a9395f30d
7
+ data.tar.gz: 4c7e388e010b061286dc2e45cc90b482cec283893b9d3862f5153faaebc8b6250207b7952f8ee6463f1e012803e9774f77a4d4f1800c76e4d51697963b977e76
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,40 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [2.0.1] - 2026-02-22
34
+
35
+ - TAG: [v2.0.1][2.0.1t]
36
+ - COVERAGE: 98.80% -- 820/830 lines in 12 files
37
+ - BRANCH COVERAGE: 85.55% -- 450/526 branches in 12 files
38
+ - 93.51% documented
39
+
40
+ ### Added
41
+
42
+ - `SmartMerger#emit_dest_prefix_lines` preserves magic comments (e.g., `# frozen_string_literal: true`)
43
+ and blank lines that appear before the first AST node in the destination file
44
+ - `SmartMerger#emit_dest_gap_lines` preserves blank lines between consecutive top-level blocks
45
+ in the destination, preventing them from being silently stripped during merge
46
+
47
+ ### Changed
48
+
49
+ - `SmartMerger#merge_with_debug` now uses `merge_result` (returns `MergeResult` object)
50
+ instead of `merge` (returns `String`), so `statistics` and `decision_summary` are accessible
51
+ - `SmartMerger#build_result` now passes `template_analysis` and `dest_analysis` to
52
+ `MergeResult.new` for consistency with `SmartMergerBase` API
53
+
54
+ ### Removed
55
+
56
+ - Removed redundant `attr_reader :node_typing` from `SmartMerger` — already provided
57
+ by `SmartMergerBase`
58
+
59
+ ### Fixed
60
+
61
+ - Inter-node blank line stripping: blank lines between top-level blocks (e.g., between
62
+ `appraise` blocks in Appraisals, between `gem` calls in Gemfiles) are now preserved
63
+ from the destination source during merge
64
+ - Prefix line stripping: magic comments and blank lines before the first AST statement
65
+ (e.g., `# frozen_string_literal: true` in Appraisal.root.gemfile) are now preserved
66
+
33
67
  ## [2.0.0] - 2026-02-19
34
68
 
35
69
  - TAG: [v2.0.0][2.0.0t]
@@ -281,7 +315,9 @@ Please file a bug if you notice a violation of semantic versioning.
281
315
 
282
316
  - Initial release
283
317
 
284
- [Unreleased]: https://github.com/kettle-rb/prism-merge/compare/v2.0.0...HEAD
318
+ [Unreleased]: https://github.com/kettle-rb/prism-merge/compare/v2.0.1...HEAD
319
+ [2.0.1]: https://github.com/kettle-rb/prism-merge/compare/v2.0.0...v2.0.1
320
+ [2.0.1t]: https://github.com/kettle-rb/prism-merge/releases/tag/v2.0.1
285
321
  [2.0.0]: https://github.com/kettle-rb/prism-merge/compare/v1.1.6...v2.0.0
286
322
  [2.0.0t]: https://github.com/kettle-rb/prism-merge/releases/tag/v2.0.0
287
323
  [1.1.6]: https://github.com/kettle-rb/prism-merge/compare/v1.1.5...v1.1.6
data/CITATION.cff CHANGED
@@ -7,8 +7,8 @@ type: software
7
7
  authors:
8
8
  - given-names: Peter Hurn
9
9
  family-names: Boling
10
- email: peter@railsbling.com
11
- affiliation: railsbling.com
10
+ email: floss@galtzo.com
11
+ affiliation: galtzo.com
12
12
  orcid: 'https://orcid.org/0009-0008-8519-441X'
13
13
  identifiers:
14
14
  - type: url
data/README.md CHANGED
@@ -80,7 +80,7 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
80
80
  | [markly-merge][markly-merge] | [![Version][markly-merge-gem-i]][markly-merge-gem] <br/> [![CI][markly-merge-ci-i]][markly-merge-ci] | Markdown | [Markly][markly] (via tree_haver) | Smart merge for Markdown (CommonMark via cmark-gfm C) |
81
81
  | [prism-merge][prism-merge] | [![Version][prism-merge-gem-i]][prism-merge-gem] <br/> [![CI][prism-merge-ci-i]][prism-merge-ci] | Ruby | [Prism][prism] (`prism` std lib gem) | Smart merge for Ruby source files |
82
82
  | [psych-merge][psych-merge] | [![Version][psych-merge-gem-i]][psych-merge-gem] <br/> [![CI][psych-merge-ci-i]][psych-merge-ci] | YAML | [Psych][psych] (`psych` std lib gem) | Smart merge for YAML files |
83
- | [rbs-merge][rbs-merge] | [![Version][rbs-merge-gem-i]][rbs-merge-gem] <br/> [![CI][rbs-merge-ci-i]][rbs-merge-ci] | RBS | [tree-sitter-bash][ts-rbs] (via tree_haver), [RBS][rbs] (`rbs` std lib gem) | Smart merge for Ruby type signatures |
83
+ | [rbs-merge][rbs-merge] | [![Version][rbs-merge-gem-i]][rbs-merge-gem] <br/> [![CI][rbs-merge-ci-i]][rbs-merge-ci] | RBS | [tree-sitter-rbs][ts-rbs] (via tree_haver), [RBS][rbs] (`rbs` std lib gem) | Smart merge for Ruby type signatures |
84
84
  | [toml-merge][toml-merge] | [![Version][toml-merge-gem-i]][toml-merge-gem] <br/> [![CI][toml-merge-ci-i]][toml-merge-ci] | TOML | [Parslet + toml][toml], [Citrus + toml-rb][toml-rb], [tree-sitter-toml][ts-toml] (all via tree_haver) | Smart merge for TOML files |
85
85
 
86
86
  #### Backend Platform Compatibility
@@ -1564,7 +1564,7 @@ Thanks for RTFM. ☺️
1564
1564
  [📌gitmoji]: https://gitmoji.dev
1565
1565
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1566
1566
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1567
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.802-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1567
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.830-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1568
1568
  [🔐security]: SECURITY.md
1569
1569
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1570
1570
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -46,9 +46,6 @@ module Prism
46
46
  # result = merger.merge
47
47
  #
48
48
  class SmartMerger < ::Ast::Merge::SmartMergerBase
49
- # @return [Hash{Symbol,String => #call}, nil] Node typing configuration
50
- attr_reader :node_typing
51
-
52
49
  # @return [Integer, Float] Maximum recursion depth for body merging
53
50
  attr_reader :max_recursion_depth
54
51
 
@@ -139,9 +136,9 @@ module Prism
139
136
  #
140
137
  # @return [Hash] Hash with :content, :debug, and :statistics keys
141
138
  def merge_with_debug
142
- result = merge
139
+ result_obj = merge_result
143
140
  {
144
- content: result.to_s,
141
+ content: result_obj.to_s,
145
142
  debug: {
146
143
  template_statements: @template_analysis&.statements&.size || 0,
147
144
  dest_statements: @dest_analysis&.statements&.size || 0,
@@ -149,7 +146,7 @@ module Prism
149
146
  add_template_only_nodes: @add_template_only_nodes,
150
147
  freeze_token: @freeze_token,
151
148
  },
152
- statistics: result.respond_to?(:statistics) ? result.statistics : {},
149
+ statistics: result_obj.respond_to?(:statistics) ? result_obj.statistics : result_obj.decision_summary,
153
150
  }
154
151
  end
155
152
 
@@ -180,9 +177,12 @@ module Prism
180
177
  nil
181
178
  end
182
179
 
183
- # Build the result (no-arg constructor for Prism)
180
+ # Build the result with analysis references
184
181
  def build_result
185
- MergeResult.new
182
+ MergeResult.new(
183
+ template_analysis: @template_analysis,
184
+ dest_analysis: @dest_analysis,
185
+ )
186
186
  end
187
187
 
188
188
  # @return [Class] The template parse error class for Ruby
@@ -240,6 +240,10 @@ module Prism
240
240
 
241
241
  # Phase 2: Process dest nodes in their original order
242
242
  # This preserves dest-only nodes in their original position relative to matched nodes
243
+
244
+ # Emit prefix lines from the dest source (magic comments, blank lines before first node)
245
+ last_output_dest_line = emit_dest_prefix_lines(@result, @dest_analysis)
246
+
243
247
  @dest_analysis.statements.each do |dest_node|
244
248
  dest_signature = @dest_analysis.generate_signature(dest_node)
245
249
 
@@ -250,6 +254,9 @@ module Prism
250
254
  node_range = dest_node.location.start_line..dest_node.location.end_line
251
255
  next if output_dest_line_ranges.any? { |range| range.cover?(node_range.begin) && range.cover?(node_range.end) }
252
256
 
257
+ # Emit inter-node gap lines from the dest source (blank lines between blocks)
258
+ last_output_dest_line = emit_dest_gap_lines(@result, @dest_analysis, last_output_dest_line, dest_node)
259
+
253
260
  if dest_signature && template_by_signature.key?(dest_signature)
254
261
  # Matched node - merge with template version
255
262
  template_node = template_by_signature[dest_signature]
@@ -277,6 +284,12 @@ module Prism
277
284
  output_dest_line_ranges << node_range
278
285
  output_signatures << dest_signature if dest_signature
279
286
  end
287
+
288
+ # Update last_output_dest_line to track trailing blank line from add_node_to_result
289
+ last_output_dest_line = dest_node.location.end_line
290
+ trailing_line = last_output_dest_line + 1
291
+ trailing_content = @dest_analysis.line_at(trailing_line)
292
+ last_output_dest_line = trailing_line if trailing_content && trailing_content.strip.empty?
280
293
  end
281
294
 
282
295
  @result
@@ -596,6 +609,64 @@ module Prism
596
609
  }
597
610
  end
598
611
 
612
+ # Emit prefix lines from the destination source that appear before the first node.
613
+ # This preserves magic comments (e.g., `# frozen_string_literal: true`) and blank
614
+ # lines that precede any AST statements.
615
+ #
616
+ # @param result [MergeResult] The merge result
617
+ # @param analysis [FileAnalysis] The destination file analysis
618
+ # @return [Integer] The last line number emitted (0 if none)
619
+ def emit_dest_prefix_lines(result, analysis)
620
+ return 0 if analysis.statements.empty?
621
+
622
+ first_node = analysis.statements.first
623
+ # Find the first line of content: either leading comment or node start
624
+ leading_comments = first_node.location.respond_to?(:leading_comments) ? first_node.location.leading_comments : []
625
+ first_content_line = leading_comments.any? ? leading_comments.first.location.start_line : first_node.location.start_line
626
+
627
+ return 0 if first_content_line <= 1
628
+
629
+ # Emit lines before the first node (magic comments, blank lines)
630
+ last_emitted = 0
631
+ (1...first_content_line).each do |line_num|
632
+ line = analysis.line_at(line_num)&.chomp || ""
633
+ result.add_line(line, decision: MergeResult::DECISION_KEPT_DEST, dest_line: line_num)
634
+ last_emitted = line_num
635
+ end
636
+ last_emitted
637
+ end
638
+
639
+ # Emit blank/gap lines from the destination source between the last output line
640
+ # and the next node (including its leading comments). This preserves blank lines
641
+ # that separate top-level blocks.
642
+ #
643
+ # @param result [MergeResult] The merge result
644
+ # @param analysis [FileAnalysis] The destination file analysis
645
+ # @param last_output_line [Integer] The last dest line number that was output
646
+ # @param next_node [Prism::Node] The next node about to be output
647
+ # @return [Integer] The updated last output line number
648
+ def emit_dest_gap_lines(result, analysis, last_output_line, next_node)
649
+ return last_output_line if last_output_line == 0
650
+
651
+ # Find where the next node's content starts (leading comment or node itself)
652
+ leading_comments = next_node.location.respond_to?(:leading_comments) ? next_node.location.leading_comments : []
653
+ next_start_line = leading_comments.any? ? leading_comments.first.location.start_line : next_node.location.start_line
654
+
655
+ # Emit gap lines (blank lines between last output and next node)
656
+ gap_start = last_output_line + 1
657
+ return last_output_line if gap_start >= next_start_line
658
+
659
+ (gap_start...next_start_line).each do |line_num|
660
+ line = analysis.line_at(line_num)&.chomp || ""
661
+ # Only emit blank lines in the gap (don't re-emit content)
662
+ next unless line.strip.empty?
663
+
664
+ result.add_line(line, decision: MergeResult::DECISION_KEPT_DEST, dest_line: line_num)
665
+ end
666
+
667
+ last_output_line
668
+ end
669
+
599
670
  # Add a node to the result, including its leading and trailing comments.
600
671
  #
601
672
  # @param result [MergeResult] The merge result
@@ -5,7 +5,7 @@ module Prism
5
5
  # Version information for Prism::Merge
6
6
  module Version
7
7
  # Current version of the prism-merge gem
8
- VERSION = "2.0.0"
8
+ VERSION = "2.0.1"
9
9
  end
10
10
  VERSION = Version::VERSION # traditional location
11
11
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prism-merge
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -314,10 +314,10 @@ licenses:
314
314
  - MIT
315
315
  metadata:
316
316
  homepage_uri: https://prism-merge.galtzo.com/
317
- source_code_uri: https://github.com/kettle-rb/prism-merge/tree/v2.0.0
318
- changelog_uri: https://github.com/kettle-rb/prism-merge/blob/v2.0.0/CHANGELOG.md
317
+ source_code_uri: https://github.com/kettle-rb/prism-merge/tree/v2.0.1
318
+ changelog_uri: https://github.com/kettle-rb/prism-merge/blob/v2.0.1/CHANGELOG.md
319
319
  bug_tracker_uri: https://github.com/kettle-rb/prism-merge/issues
320
- documentation_uri: https://www.rubydoc.info/gems/prism-merge/2.0.0
320
+ documentation_uri: https://www.rubydoc.info/gems/prism-merge/2.0.1
321
321
  funding_uri: https://github.com/sponsors/pboling
322
322
  wiki_uri: https://github.com/kettle-rb/prism-merge/wiki
323
323
  news_uri: https://www.railsbling.com/tags/prism-merge
metadata.gz.sig CHANGED
Binary file