# frozen_string_literal: true module Gitlab module Suggestions class FileSuggestion include Gitlab::Utils::StrongMemoize SuggestionForDifferentFileError = Class.new(StandardError) attr_reader :file_path attr_reader :blob attr_reader :suggestions def initialize(file_path, suggestions) @file_path = file_path @suggestions = suggestions.sort_by(&:from_line_index) @blob = suggestions.first&.diff_file&.new_blob end def line_conflict? strong_memoize(:line_conflict) do _line_conflict? end end def new_content @new_content ||= _new_content end private def blob_data_lines blob.load_all_data! blob.data.lines end def current_content @current_content ||= blob.nil? ? [''] : blob_data_lines end def _new_content current_content.tap do |content| # NOTE: We need to cater for line number changes when the range is more than one line. offset = 0 suggestions.each do |suggestion| range = line_range(suggestion, offset) content[range] = suggestion.to_content offset += range.count - 1 end end.join end def line_range(suggestion, offset = 0) (suggestion.from_line_index - offset)..(suggestion.to_line_index - offset) end def _line_conflict? has_conflict = false suggestions.each_with_object([]) do |suggestion, ranges| range_in_test = line_range(suggestion) if has_range_conflict?(range_in_test, ranges) has_conflict = true break end ranges << range_in_test end has_conflict end def has_range_conflict?(range_in_test, ranges) ranges.any? do |range| range.overlaps?(range_in_test) end end end end end