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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +37 -1
- data/CITATION.cff +2 -2
- data/README.md +2 -2
- data/lib/prism/merge/smart_merger.rb +79 -8
- data/lib/prism/merge/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d39e0e854397866379ca524e10088fdaa4d31029358962472fec0c174e0780c4
|
|
4
|
+
data.tar.gz: 2805f8137670b5660f510cc6ca119447ac3e90967da0b0b09cc5cd7ca621fd51
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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:
|
|
11
|
-
affiliation:
|
|
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-
|
|
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.
|
|
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
|
-
|
|
139
|
+
result_obj = merge_result
|
|
143
140
|
{
|
|
144
|
-
content:
|
|
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:
|
|
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
|
|
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
|
data/lib/prism/merge/version.rb
CHANGED
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.
|
|
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.
|
|
318
|
-
changelog_uri: https://github.com/kettle-rb/prism-merge/blob/v2.0.
|
|
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.
|
|
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
|