Module: Taro::Types::Shared::Pattern

Included in:
Taro::Types::ScalarType
Defined in:
lib/taro/types/shared/pattern.rb

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

NOT_ESCAPED =
/(?<!\\)(?:\\\\)*\K/
ADVANCED_RUBY_REGEXP_SYNTAX_REGEXP =

This is not 100% accurate, e.g. /[?+]/ is a false positive, but it should be good enough so we don’t need regexp_parser or js_regex as a dependency.

/
  #{NOT_ESCAPED}
  (?:
      (?<a special group or lookaround> \(\?[^:] )
    | (?<a Ruby-specific escape> \\[a-zA-Z&&[^bBdDsSwWAzfhnrv]] )
    | (?<an advanced quantifier> [?*+}][?+] )
    | (?<a nested set> \[[^\]]*(?<!\\)\[ )
    | (?<a set intersection> && )
  )
/x

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



6
7
8
# File 'lib/taro/types/shared/pattern.rb', line 6

def self.included(base)
  base.extend(ClassMethods)
end

.to_es262(regexp) ⇒ Object



22
23
24
25
26
27
# File 'lib/taro/types/shared/pattern.rb', line 22

def self.to_es262(regexp)
  validate(regexp).source.gsub(
    /#{NOT_ESCAPED}\\[Ahz]/,
    { '\\A' => '^', '\\h' => '[0-9a-fA-F]', '\\z' => '$' }
  )
end

.validate(regexp) ⇒ Object



29
30
31
32
33
34
# File 'lib/taro/types/shared/pattern.rb', line 29

def self.validate(regexp)
  validate_no_flags(regexp)
  validate_not_empty(regexp)
  validate_no_advanced_syntax(regexp)
  regexp
end

.validate_no_advanced_syntax(regexp) ⇒ Object



46
47
48
49
50
51
52
53
# File 'lib/taro/types/shared/pattern.rb', line 46

def self.validate_no_advanced_syntax(regexp)
  return unless (match = regexp.source.match(ADVANCED_RUBY_REGEXP_SYNTAX_REGEXP))

  feature = match.named_captures.find { |k, v| break k if v }
  raise Taro::ArgumentError, <<~MSG
    pattern uses non-JS syntax #{match} (#{feature}) at index #{match.begin(0)}
  MSG
end

.validate_no_flags(regexp) ⇒ Object



36
37
38
39
# File 'lib/taro/types/shared/pattern.rb', line 36

def self.validate_no_flags(regexp)
  (flags = regexp.inspect[%r{/\w+\z}]) &&
    raise(Taro::ArgumentError, "pattern flags (#{flags}) are not supported")
end

.validate_not_empty(regexp) ⇒ Object



41
42
43
44
# File 'lib/taro/types/shared/pattern.rb', line 41

def self.validate_not_empty(regexp)
  regexp.source.empty? &&
    raise(Taro::ArgumentError, 'pattern cannot be empty')
end

Instance Method Details

#patternObject



2
3
4
# File 'lib/taro/types/shared/pattern.rb', line 2

def pattern
  self.class.pattern
end