Welcome to mirror list, hosted at ThFree Co, Russian Federation.

file_suggestion.rb « suggestions « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 73b9800f0b8ca0f2dfa6cb6e689e35e8894e9352 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# frozen_string_literal: true

module Gitlab
  module Suggestions
    class FileSuggestion
      include Gitlab::Utils::StrongMemoize

      SuggestionForDifferentFileError = Class.new(StandardError)

      def initialize
        @suggestions = []
      end

      def add_suggestion(new_suggestion)
        if for_different_file?(new_suggestion)
          raise SuggestionForDifferentFileError,
                'Only add suggestions for the same file.'
        end

        suggestions << new_suggestion
      end

      def line_conflict?
        strong_memoize(:line_conflict) do
          _line_conflict?
        end
      end

      def new_content
        @new_content ||= _new_content
      end

      def file_path
        @file_path ||= _file_path
      end

      private

      attr_accessor :suggestions

      def blob
        first_suggestion&.diff_file&.new_blob
      end

      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|
          suggestions.each do |suggestion|
            range = line_range(suggestion)
            content[range] = suggestion.to_content
          end
        end.join
      end

      def line_range(suggestion)
        suggestion.from_line_index..suggestion.to_line_index
      end

      def for_different_file?(suggestion)
        file_path && file_path != suggestion_file_path(suggestion)
      end

      def suggestion_file_path(suggestion)
        suggestion&.diff_file&.file_path
      end

      def first_suggestion
        suggestions.first
      end

      def _file_path
        suggestion_file_path(first_suggestion)
      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