Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion gems/prism-merge/lib/prism/merge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,12 @@ def ruby_dsl_signature_for(node, require_aliases: nil)
when :git_source, :gem, :eval_gemfile, :platform, :group, :task
[:ruby_dsl_call, call.name, ruby_dsl_first_argument(call)]
when :desc
[:ruby_dsl_desc, call.slice]
argument = call.arguments&.arguments
if call.receiver.nil? && call.block.nil? && argument&.one? && argument.first.is_a?(::Prism::StringNode)
[:ruby_dsl_desc, argument.first.unescaped]
else
[:ruby_dsl_desc, call.slice]
end
end
end

Expand Down
2 changes: 2 additions & 0 deletions gems/prism-merge/lib/prism/merge/node_emission_support.rb
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,8 @@ def emit_node(result:, node:, analysis:, source:, matched_template_node: nil)
last_filtered_leading_line = nil

if source == :destination
emitted_dest_lines = result.line_metadata.filter_map { |metadata| metadata[:dest_line] }.to_set
leading_comments = leading_comments.reject { |comment| emitted_dest_lines.include?(comment.location.start_line) }
leading_comments, = collapse_matched_template_leading_prefix(
leading_comments,
matched_template_node
Expand Down
34 changes: 34 additions & 0 deletions gems/prism-merge/spec/fixtures_integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,40 @@ def json_ready(value)
expect(result[:output]).to include('gem "rake"')
end

it 'keeps Rake descriptions stable across formatting differences and repeated merges' do
template = <<~RUBY
desc "Default tasks aggregator"
task :default do
puts :template
end

desc "Generate YARD documentation"
task :yard do
puts :yard
end
RUBY
destination = <<~RUBY
desc("Default tasks aggregator")
task :default do
puts :destination
end

# Alef-generated content
task :alef do
puts :alef
end
RUBY
options = { preference: :destination, add_template_only_nodes: true,
signature_generator: PRISM_MERGE.ruby_dsl_signature_generator }
once = PRISM_MERGE.merge_ruby(template, destination, 'ruby', **options).fetch(:output)
twice = PRISM_MERGE.merge_ruby(template, once, 'ruby', **options).fetch(:output)

expect(twice).to eq(once)
expect(once.scan('Default tasks aggregator').size).to eq(1)
expect(once.scan('Generate YARD documentation').size).to eq(1)
expect(once).to include('puts :destination', '# Alef-generated content', 'puts :alef', 'task :yard')
end

it 'adds template-only top-level nodes at their template anchor' do
result = PRISM_MERGE.merge_ruby(
<<~RUBY,
Expand Down
25 changes: 25 additions & 0 deletions gems/prism-merge/spec/reproducible_merge_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,31 @@
end
end

it 'emits destination comments attached to adjacent nodes only once on repeated merges' do
template = <<~RUBY
begin
require "stone_checksums"
rescue LoadError
puts :missing
end
RUBY
destination = template + <<~RUBY
# This file is auto-generated by alef — DO NOT EDIT.
# alef:hash:123
# To regenerate: alef generate
# To verify freshness: alef verify

require "bundler"
RUBY
options = { preference: :destination, add_template_only_nodes: true,
signature_generator: Prism::Merge.ruby_dsl_signature_generator }
once = Prism::Merge.merge_ruby(template, destination, 'ruby', **options).fetch(:output)
twice = Prism::Merge.merge_ruby(template, once, 'ruby', **options).fetch(:output)

expect(once).to eq(destination)
expect(twice).to eq(once)
end

describe 'Ruby merge with comment-only destination (regression)' do
# A scaffold reduced to just its magic comment merges into a full template.
# The destination pragma arrives as an unmatched statement node because the
Expand Down
Loading