Module: Ruby::Merge::MagicCommentSupport

Defined in:
lib/ruby/merge/magic_comment_support.rb

Overview

Ruby magic comment detection and file-header prefix handling.

Constant Summary collapse

MAGIC_COMMENT_PATTERNS =
{
  frozen_string_literal: /^frozen_string_literal:\s*(true|false)$/i,
  encoding: /^(encoding|coding):\s*\S+$/i,
  warn_indent: /^warn_indent:\s*(true|false)$/i,
  shareable_constant_value: /^shareable_constant_value:\s*\S+$/i
}.freeze

Class Method Summary collapse

Class Method Details

.comment_only_prefix_info(lines) ⇒ Object



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
# File 'lib/ruby/merge/magic_comment_support.rb', line 26

def comment_only_prefix_info(lines)
  entries = []
  suppressed_line_nums = Set.new
  duplicate_magic_line_nums = Set.new

  if shebang_line?(lines.first)
    entries << { line_num: 1, text: lines.first.to_s, kind: :shebang }
    suppressed_line_nums << 1
  end

  header_magic_types = header_magic_comment_types_for_lines(lines)
  seen_magic_types = Set.new

  header_magic_types.keys.sort.each do |line_num|
    magic_type = header_magic_types[line_num]
    suppressed_line_nums << line_num
    entries << { line_num: line_num, text: lines[line_num - 1].to_s.chomp, kind: :magic }

    if seen_magic_types.include?(magic_type)
      duplicate_magic_line_nums << line_num
    else
      seen_magic_types << magic_type
    end
  end

  if header_magic_types.any?
    blank_line_num = header_magic_types.keys.max + 1

    while blank_line_num <= lines.length && lines[blank_line_num - 1].to_s.rstrip.empty?
      entries << { line_num: blank_line_num, text: lines[blank_line_num - 1].to_s, kind: :blank }
      suppressed_line_nums << blank_line_num
      blank_line_num += 1
    end
  end

  {
    entries: entries,
    suppressed_line_nums: suppressed_line_nums,
    duplicate_magic_line_nums: duplicate_magic_line_nums,
    header_magic_comment_types: header_magic_types
  }
end

.header_magic_comment_types_for_lines(lines) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/ruby/merge/magic_comment_support.rb', line 69

def header_magic_comment_types_for_lines(lines)
  types = {}
  index = shebang_line?(lines.first) ? 1 : 0
  previous_line_num = shebang_line?(lines.first) ? 1 : nil

  while index < lines.length
    line_num = index + 1
    stripped = lines[index].to_s.rstrip
    break if stripped.empty?

    expected_line_num = previous_line_num ? previous_line_num + 1 : 1
    break unless line_num == expected_line_num

    magic_type = magic_comment_type_for_text(stripped)
    break unless magic_type

    types[line_num] = magic_type
    previous_line_num = line_num
    index += 1
  end

  types
end

.magic_comment_type_for_text(text) ⇒ Object



16
17
18
19
20
21
22
23
24
# File 'lib/ruby/merge/magic_comment_support.rb', line 16

def magic_comment_type_for_text(text)
  stripped = DocCommentSupport.normalize_comment_content(text)

  MAGIC_COMMENT_PATTERNS.each do |type, pattern|
    return type if stripped.match?(pattern)
  end

  nil
end

.prefix_comment_line_numbers_for_comments(comments) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/ruby/merge/magic_comment_support.rb', line 93

def prefix_comment_line_numbers_for_comments(comments)
  prefix_line_nums = Set.new
  previous_line_num = nil
  index = 0

  if shebang_comment?(comments.first)
    prefix_line_nums << 1
    previous_line_num = 1
    index = 1
  end

  while index < comments.length
    comment = comments[index]
    line_num = comment.location.start_line
    expected_line_num = previous_line_num ? previous_line_num + 1 : 1
    break unless line_num == expected_line_num
    break unless magic_comment_type_for_text(comment.slice)

    prefix_line_nums << line_num
    previous_line_num = line_num
    index += 1
  end

  prefix_line_nums
end

.shebang_comment?(comment) ⇒ Boolean

Returns:

  • (Boolean)


123
124
125
# File 'lib/ruby/merge/magic_comment_support.rb', line 123

def shebang_comment?(comment)
  comment&.slice&.start_with?('#!')
end

.shebang_line?(line) ⇒ Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/ruby/merge/magic_comment_support.rb', line 119

def shebang_line?(line)
  line.to_s.start_with?('#!')
end