class Capybara::Selector::RegexpDisassembler

@api private

def alternated_substrings

def alternated_substrings
  @alternated_substrings ||= begin
    or_strings = process(alternation: true)
    remove_or_covered(or_strings)
    or_strings.any?(&:empty?) ? [] : or_strings
  end
end

def collapse(strs)

def collapse(strs)
  strs.map do |substrings|
    substrings.slice_before(&:nil?).map(&:join).reject(&:empty?).uniq
  end
end

def combine(strs)

def combine(strs)
  suffixes = [[]]
  strs.reverse_each do |str|
    if str.is_a? Set
      prefixes = str.flat_map { |s| combine(s) }
      suffixes = prefixes.product(suffixes).map { |pair| pair.flatten(1) }
    else
      suffixes.each { |arr| arr.unshift str }
    end
  end
  suffixes
end

def extract_strings(expression, alternation: false)

def extract_strings(expression, alternation: false)
  Expression.new(expression).extract_strings(alternation)
end

def initialize(regexp)

def initialize(regexp)
  @regexp = regexp
end

def process(alternation:)

def process(alternation:)
  strs = extract_strings(Regexp::Parser.parse(@regexp), alternation: alternation)
  strs = collapse(combine(strs).map(&:flatten))
  strs.each { |str| str.map!(&:upcase) } if @regexp.casefold?
  strs
end

def remove_and_covered(strings)

def remove_and_covered(strings)
  # delete_if is documented to modify the array after every block iteration - this doesn't appear to be true
  # uniq the strings to prevent identical strings from removing each other
  strings.uniq!
  # If we have "ab" and "abcd" required - only need to check for "abcd"
  strings.delete_if do |sub_string|
    strings.any? do |cover_string|
      next if sub_string.equal? cover_string
      cover_string.include?(sub_string)
    end
  end
end

def remove_or_covered(or_series)

def remove_or_covered(or_series)
  # If we are going to match `("a" and "b") or ("ade" and "bce")` it only makes sense to match ("a" and "b")
  # Ensure minimum sets of strings are being or'd
  or_series.each { |strs| remove_and_covered(strs) }
  # Remove any of the alternated string series that fully contain any other string series
  or_series.delete_if do |and_strs|
    or_series.any? do |and_strs2|
      next if and_strs.equal? and_strs2
      remove_and_covered(and_strs + and_strs2) == and_strs
    end
  end
end

def substrings

def substrings
  @substrings ||= begin
    strs = process(alternation: false).first
    remove_and_covered(strs)
  end
end