Module: FastIgnore::FNMatchToRegex

Defined in:
lib/fast_ignore/fn_match_to_re.rb

Class Method Summary collapse

Class Method Details

.call(pattern) ⇒ Object

rubocop:disable Metrics/MethodLength, Metrics/AbcSize



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
# File 'lib/fast_ignore/fn_match_to_re.rb', line 7

def call(pattern) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
  re = '\\A'.dup

  in_character_group = false
  has_characters_in_group = false
  escape_next_character = false
  last_char_opened_character_group = false
  negated_character_group = false
  stars = 0

  pattern.each_char do |char| # rubocop:disable Metrics/BlockLength
    if escape_next_character
      re << Regexp.escape(char)
      escape_next_character = false
    elsif char == '\\' # single char, just needs to be escaped
      escape_next_character = true
    elsif in_character_group
      if char == '/'
        if negated_character_group
          has_characters_in_group = true
          re << char
        end
      elsif char == '^'
        if last_char_opened_character_group
          re << char
          negated_character_group = true
        else
          re << '\\^'
          has_characters_in_group = true
        end
        # not characters in group
      elsif char == ']'
        break unless has_characters_in_group

        re << ']'
        in_character_group = false
        has_characters_in_group = false
        negated_character_group = false
        last_char_opened_character_group = false
      elsif char == '-'
        has_characters_in_group = true
        re << char
      else
        has_characters_in_group = true
        re << Regexp.escape(char)
      end
      last_char_opened_character_group = false
    elsif char == '*'
      stars += 1
    elsif char == '/'
      re << if stars >= 2
        '(?:.*/)?'
      elsif stars.positive?
        '[^/]*/'
      else
        char
      end
      stars = 0
    else
      if stars.positive?
        re << '[^/]*'
        stars = 0
      end
      if char == '?'
        re << '[^/]'
      elsif char == '['
        re << '['
        in_character_group = true
        last_char_opened_character_group = true
      else
        re << Regexp.escape(char)
      end
    end
  end

  if in_character_group
    return /(?!)/ # impossible to match anything
  end

  if stars >= 2
    re << '.*'
  elsif stars.positive?
    re << '[^/]*'
  end
  re << '\\z'
  Regexp.new(re, Regexp::IGNORECASE)
end