class JsRegex::Converter::SetConverter

Template class implementation.

Unlike other converters, this one does not recurse on subexpressions, since many are unsupported by JavaScript. If it detects incompatible children, it uses the ‘character_set` gem to establish the codepoints matched by the whole set and build a completely new set string.

Constants

CONVERTIBLE_ESCAPE_TOKENS
SET_SPECIFIC_ESCAPES_PATTERN

Private Instance Methods

casefolding_needed?() click to toggle source
# File lib/js_regex/converter/set_converter.rb, line 37
def casefolding_needed?
  expression.case_insensitive? ^ context.case_insensitive_root
end
convert_data() click to toggle source
# File lib/js_regex/converter/set_converter.rb, line 19
def convert_data
  simple_conversion || full_recalculation
end
full_recalculation() click to toggle source
# File lib/js_regex/converter/set_converter.rb, line 74
def full_recalculation
  # Fetch codepoints as if the set was case-sensitive, then re-add
  # case-insensitivity if needed.
  # This way we preserve the casing of the original set in cases where the
  # whole regexp is case-insensitive, e.g. /[ABc]/i => /[ABc]/i.
  content = original_case_character_set
  if expression.case_insensitive? && !context.case_insensitive_root
    content = content.case_insensitive
  elsif !expression.case_insensitive? && context.case_insensitive_root
    warn_of_unsupported_feature('nested case-sensitive set')
  end
  if context.es_2015_or_higher?
    context.enable_u_option if content.astral_part?
    content.to_s(format: 'es6', in_brackets: true)
  else
    content.to_s_with_surrogate_ranges
  end
end
original_case_character_set() click to toggle source
# File lib/js_regex/converter/set_converter.rb, line 93
def original_case_character_set
  neutral_set = expression.dup
  neutral_set.each_expression(true) { |exp| exp.options[:i] = false }
  CharacterSet.of_expression(neutral_set)
end
simple_conversion() click to toggle source
# File lib/js_regex/converter/set_converter.rb, line 23
def simple_conversion
  return false if casefolding_needed?

  result = "[#{'^' if expression.negative?}".dup

  expression.expressions.each do |subexp|
    return false unless (child_res = simple_convert_child(subexp))

    result << child_res.to_s
  end

  result << ']'
end
simple_convert_child(exp) click to toggle source
# File lib/js_regex/converter/set_converter.rb, line 41
def simple_convert_child(exp)
  case exp.type
  when :literal
    return false if !context.u? &&
      exp.text =~ LiteralConverter::ASTRAL_PLANE_CODEPOINT_PATTERN &&
      !context.enable_u_option

    LiteralConverter.escape_incompatible_bmp_literals(exp.text)
  when :set
    # full conversion is needed for nested sets and intersections
    exp.token.equal?(:range) && exp.expressions.map do |op|
      simple_convert_child(op) or return false
    end.join('-')
  when :type
    TypeConverter.directly_compatible?(exp, context) &&
      exp.text
  when :escape
    return exp.text if SET_SPECIFIC_ESCAPES_PATTERN.match?(exp.text)

    case exp.token
    when *CONVERTIBLE_ESCAPE_TOKENS
      EscapeConverter.new.convert(exp, context)
    when :literal
      exp.char.ord <= 0xFFFF &&
        LiteralConverter.escape_incompatible_bmp_literals(exp.char)
    end
  end
end