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
|
require_relative 'base'
require_relative 'escape_converter'
require_relative 'type_converter'
require 'character_set'
class JsRegex
module Converter
#
# 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.
#
class SetConverter < JsRegex::Converter::Base
private
def convert_data
return pass_through_with_escaping if directly_compatible?
content = CharacterSet.of_expression(expression)
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
def directly_compatible?
all_children_directly_compatible? && !casefolding_needed?
end
def all_children_directly_compatible?
# note that #each_expression is recursive
expression.each_expression.all? { |ch| child_directly_compatible?(ch) }
end
def child_directly_compatible?(exp)
case exp.type
when :literal
# surrogate pair substitution needed on ES2009 if astral
exp.text.ord <= 0xFFFF || context.enable_u_option
when :set
# conversion needed for nested sets, intersections
exp.token.equal?(:range)
when :type
TypeConverter.directly_compatible?(exp)
when :escape
EscapeConverter::ESCAPES_SHARED_BY_RUBY_AND_JS.include?(exp.token)
end
end
def casefolding_needed?
expression.case_insensitive? ^ context.case_insensitive_root
end
def pass_through_with_escaping
string = expression.to_s(:base)
LiteralConverter.escape_incompatible_bmp_literals(string)
end
end
end
end
|