js_regex 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/js_regex.rb +1 -1
- data/lib/js_regex/converter.rb +5 -1
- data/lib/js_regex/converter/assertion_converter.rb +1 -1
- data/lib/js_regex/converter/backreference_converter.rb +9 -38
- data/lib/js_regex/converter/base.rb +2 -2
- data/lib/js_regex/converter/conditional_converter.rb +3 -4
- data/lib/js_regex/converter/context.rb +0 -7
- data/lib/js_regex/converter/group_converter.rb +33 -18
- data/lib/js_regex/converter/literal_converter.rb +3 -1
- data/lib/js_regex/converter/meta_converter.rb +3 -3
- data/lib/js_regex/converter/property_converter.rb +3 -7
- data/lib/js_regex/converter/set_converter.rb +11 -12
- data/lib/js_regex/converter/type_converter.rb +1 -1
- data/lib/js_regex/node.rb +10 -14
- data/lib/js_regex/second_pass.rb +69 -90
- data/lib/js_regex/version.rb +1 -1
- metadata +22 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 48540644a806114addad63fb0f3ff9ba7ad00a084b3b281b9132d2eddbe610ff
|
4
|
+
data.tar.gz: 775fd5d3f54c8b3c32b145414707c0b69c5c783cbd5270d9bc8d5e1564a6fec7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97810021249f6b512ebae5898f6ffe51ae95269f1e47909fb7b95fbe1e8aa6ba9696e4c7966bac27cbc7c1bd36668729aeb5d0ab4c243e85a88bb70fd6cbb203
|
7
|
+
data.tar.gz: 5681e9d950c14f7260596b46a382a9829c0be4326bd898acbdcf5a257936c0f543018b5c7b1435582d8ba976a680d3b08ac0189e85d82b49e621e5f8918b93a9
|
data/lib/js_regex.rb
CHANGED
data/lib/js_regex/converter.rb
CHANGED
@@ -38,7 +38,11 @@ class JsRegex
|
|
38
38
|
# count of all properties supported by Ruby is 92. 75% are below 300 chars.
|
39
39
|
#
|
40
40
|
# Set this to nil if you need full unicode matches and size doesn't matter.
|
41
|
-
|
41
|
+
attr_writer :surrogate_pair_limit
|
42
|
+
|
43
|
+
def in_surrogate_pair_limit?(&pair_count)
|
44
|
+
@surrogate_pair_limit.nil? || @surrogate_pair_limit >= pair_count.call
|
45
|
+
end
|
42
46
|
end
|
43
47
|
self.surrogate_pair_limit = 300
|
44
48
|
end
|
@@ -16,7 +16,7 @@ class JsRegex
|
|
16
16
|
def convert_data
|
17
17
|
case subtype
|
18
18
|
when :lookahead, :nlookahead
|
19
|
-
build_group(capturing: false)
|
19
|
+
build_group(head: pass_through, capturing: false)
|
20
20
|
when :nlookbehind
|
21
21
|
warn_of_unsupported_feature('negative lookbehind assertion')
|
22
22
|
else # :lookbehind, ...
|
@@ -12,57 +12,28 @@ class JsRegex
|
|
12
12
|
|
13
13
|
def convert_data
|
14
14
|
case subtype
|
15
|
-
when :name_ref
|
16
|
-
when :
|
17
|
-
when :number_rel_ref then convert_number_rel_ref
|
18
|
-
when :name_call then mark_name_call
|
19
|
-
when :number_call then mark_number_call
|
20
|
-
when :number_rel_call then mark_number_rel_call
|
15
|
+
when :name_ref, :number, :number_ref, :number_rel_ref then convert_ref
|
16
|
+
when :name_call, :number_call, :number_rel_call then convert_call
|
21
17
|
else # name_recursion_ref, number_recursion_ref, ...
|
22
18
|
warn_of_unsupported_feature
|
23
19
|
end
|
24
20
|
end
|
25
21
|
|
26
|
-
def
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
def convert_number_ref
|
31
|
-
convert_ref(context.new_capturing_group_position(expression.number))
|
32
|
-
end
|
33
|
-
|
34
|
-
def convert_number_rel_ref
|
35
|
-
convert_ref(context.new_capturing_group_position(absolute_position))
|
36
|
-
end
|
37
|
-
|
38
|
-
def convert_ref(position)
|
22
|
+
def convert_ref
|
23
|
+
position = context.new_capturing_group_position(target_position)
|
39
24
|
Node.new('\\', Node.new(position.to_s, type: :backref_num))
|
40
25
|
end
|
41
26
|
|
42
|
-
def
|
43
|
-
expression.number
|
27
|
+
def target_position
|
28
|
+
expression.referenced_expression.number
|
44
29
|
end
|
45
30
|
|
46
|
-
def
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
def mark_number_call
|
51
|
-
if expression.number.equal?(0)
|
31
|
+
def convert_call
|
32
|
+
if expression.respond_to?(:number) && expression.number.equal?(0)
|
52
33
|
return warn_of_unsupported_feature('whole-pattern recursion')
|
53
34
|
end
|
54
|
-
mark_call(expression.number)
|
55
|
-
end
|
56
|
-
|
57
|
-
def mark_number_rel_call
|
58
|
-
is_forward_referring = data.include?('+') # e.g. \g<+2>
|
59
|
-
mark_call(absolute_position - (is_forward_referring ? 1 : 0))
|
60
|
-
end
|
61
|
-
|
62
|
-
def mark_call(reference)
|
63
|
-
# increment group count as calls will be substituted with groups
|
64
35
|
context.increment_local_capturing_group_count
|
65
|
-
|
36
|
+
convert_expression(expression.referenced_expression.unquantified_clone)
|
66
37
|
end
|
67
38
|
end
|
68
39
|
end
|
@@ -35,7 +35,7 @@ class JsRegex
|
|
35
35
|
|
36
36
|
if qtf.possessive?
|
37
37
|
node.update(quantifier: qtf.text[0..-2])
|
38
|
-
return wrap_in_backrefed_lookahead(
|
38
|
+
return wrap_in_backrefed_lookahead(node)
|
39
39
|
else
|
40
40
|
node.update(quantifier: qtf)
|
41
41
|
end
|
@@ -44,7 +44,7 @@ class JsRegex
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def convert_subexpressions
|
47
|
-
Node.new(*expression.
|
47
|
+
Node.new(*expression.map { |subexp| convert_expression(subexp) })
|
48
48
|
end
|
49
49
|
|
50
50
|
def convert_expression(expression)
|
@@ -12,14 +12,13 @@ class JsRegex
|
|
12
12
|
|
13
13
|
def convert_data
|
14
14
|
case subtype
|
15
|
-
when :open
|
16
|
-
|
17
|
-
else warn_of_unsupported_feature
|
15
|
+
when :open then mark_conditional
|
16
|
+
else warn_of_unsupported_feature
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
21
20
|
def mark_conditional
|
22
|
-
reference = expression.
|
21
|
+
reference = expression.referenced_expression.number
|
23
22
|
node = Node.new('(?:', reference: reference, type: :conditional)
|
24
23
|
expression.branches.each do |branch|
|
25
24
|
node << Node.new('(?:', convert_expression(branch), ')')
|
@@ -11,13 +11,11 @@ class JsRegex
|
|
11
11
|
attr_reader :capturing_group_count,
|
12
12
|
:case_insensitive_root,
|
13
13
|
:in_atomic_group,
|
14
|
-
:named_group_positions,
|
15
14
|
:warnings
|
16
15
|
|
17
16
|
def initialize(case_insensitive_root: false)
|
18
17
|
self.added_capturing_groups_after_group = Hash.new(0)
|
19
18
|
self.capturing_group_count = 0
|
20
|
-
self.named_group_positions = {}
|
21
19
|
self.warnings = []
|
22
20
|
|
23
21
|
self.case_insensitive_root = case_insensitive_root
|
@@ -56,10 +54,6 @@ class JsRegex
|
|
56
54
|
capturing_group_count - total_added_capturing_groups
|
57
55
|
end
|
58
56
|
|
59
|
-
def store_named_group_position(name)
|
60
|
-
named_group_positions[name] = capturing_group_count + 1
|
61
|
-
end
|
62
|
-
|
63
57
|
private
|
64
58
|
|
65
59
|
attr_accessor :added_capturing_groups_after_group
|
@@ -67,7 +61,6 @@ class JsRegex
|
|
67
61
|
attr_writer :capturing_group_count,
|
68
62
|
:case_insensitive_root,
|
69
63
|
:in_atomic_group,
|
70
|
-
:named_group_positions,
|
71
64
|
:warnings
|
72
65
|
|
73
66
|
def total_added_capturing_groups
|
@@ -12,13 +12,12 @@ class JsRegex
|
|
12
12
|
|
13
13
|
def convert_data
|
14
14
|
case subtype
|
15
|
+
when :capture, :named then build_group
|
15
16
|
when :atomic then emulate_atomic_group
|
16
|
-
when :capture then build_group
|
17
17
|
when :comment then drop_without_warning
|
18
|
-
when :named then build_named_group
|
19
18
|
when :options, :options_switch then build_options_group
|
20
19
|
when :passive then build_passive_group
|
21
|
-
when :absence then
|
20
|
+
when :absence then build_absence_group_if_simple
|
22
21
|
else build_unsupported_group
|
23
22
|
end
|
24
23
|
end
|
@@ -34,12 +33,6 @@ class JsRegex
|
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
def build_named_group
|
38
|
-
# remember position, then drop name part without warning
|
39
|
-
context.store_named_group_position(expression.name)
|
40
|
-
build_group(head: '(', reference: expression.name)
|
41
|
-
end
|
42
|
-
|
43
36
|
def build_options_group
|
44
37
|
unless (encoding_options = data.scan(/[adu]/)).empty?
|
45
38
|
warn_of_unsupported_feature("encoding options #{encoding_options}")
|
@@ -56,25 +49,47 @@ class JsRegex
|
|
56
49
|
build_group(head: '(?:', capturing: false)
|
57
50
|
end
|
58
51
|
|
52
|
+
def build_absence_group_if_simple
|
53
|
+
if unmatchable_absence_group?
|
54
|
+
unmatchable_substitution
|
55
|
+
elsif expression.inner_match_length.fixed?
|
56
|
+
build_absence_group
|
57
|
+
else
|
58
|
+
warn_of_unsupported_feature('variable-length absence group content')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def unmatchable_absence_group?
|
63
|
+
expression.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
def unmatchable_substitution
|
67
|
+
'(?!)'
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_absence_group
|
71
|
+
head = "(?:(?:.|\\n){,#{expression.inner_match_length.min - 1}}|(?:(?!"
|
72
|
+
tail = ')(?:.|\n))*)'
|
73
|
+
build_group(head: head, tail: tail, capturing: false)
|
74
|
+
end
|
75
|
+
|
59
76
|
def build_unsupported_group(description = nil)
|
60
77
|
warn_of_unsupported_feature(description)
|
61
78
|
build_passive_group
|
62
79
|
end
|
63
80
|
|
64
81
|
def build_group(opts = {})
|
65
|
-
head = opts[:head] ||
|
66
|
-
|
67
|
-
|
68
|
-
end
|
82
|
+
head = opts[:head] || '('
|
83
|
+
tail = opts[:tail] || ')'
|
84
|
+
return Node.new(*wrap(head, tail)) if opts[:capturing].equal?(false)
|
69
85
|
|
70
86
|
context.capture_group
|
71
|
-
|
72
|
-
|
73
|
-
Node.new(*group_with_head(head), reference: ref, type: :captured_group)
|
87
|
+
ref = expression.number
|
88
|
+
Node.new(*wrap(head, tail), reference: ref, type: :captured_group)
|
74
89
|
end
|
75
90
|
|
76
|
-
def
|
77
|
-
[head,
|
91
|
+
def wrap(head, tail)
|
92
|
+
[head, convert_subexpressions, tail]
|
78
93
|
end
|
79
94
|
end
|
80
95
|
end
|
@@ -65,8 +65,10 @@ class JsRegex
|
|
65
65
|
HAS_CASE_PATTERN = /[\p{lower}\p{upper}]/
|
66
66
|
|
67
67
|
def handle_locally_case_insensitive_literal(literal)
|
68
|
-
|
68
|
+
literal =~ HAS_CASE_PATTERN ? case_insensitivize(literal) : literal
|
69
|
+
end
|
69
70
|
|
71
|
+
def case_insensitivize(literal)
|
70
72
|
literal.each_char.each_with_object(Node.new) do |chr, node|
|
71
73
|
node << (chr =~ HAS_CASE_PATTERN ? "[#{chr}#{chr.swapcase}]" : chr)
|
72
74
|
end
|
@@ -22,11 +22,11 @@ class JsRegex
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def convert_alternatives
|
25
|
-
kept_any =
|
25
|
+
kept_any = nil
|
26
26
|
|
27
|
-
convert_subexpressions.
|
27
|
+
convert_subexpressions.transform do |node|
|
28
28
|
dropped = !node.children.empty? && node.children.all?(&:dropped?)
|
29
|
-
node.children.unshift('|') if kept_any
|
29
|
+
node.children.unshift('|') if kept_any && !dropped
|
30
30
|
kept_any = true unless dropped
|
31
31
|
node
|
32
32
|
end
|
@@ -21,13 +21,10 @@ class JsRegex
|
|
21
21
|
end
|
22
22
|
|
23
23
|
if expression.negative?
|
24
|
-
if content.astral_part
|
25
|
-
return "[^#{content.to_s(format: :js)}]"
|
26
|
-
else
|
24
|
+
if content.astral_part?
|
27
25
|
warn_of_unsupported_feature('astral plane negation by property')
|
28
26
|
end
|
29
|
-
elsif Converter.
|
30
|
-
Converter.surrogate_pair_limit >= content.astral_part.size
|
27
|
+
elsif Converter.in_surrogate_pair_limit? { content.astral_part.size }
|
31
28
|
return content.to_s_with_surrogate_alternation
|
32
29
|
else
|
33
30
|
warn_of_unsupported_feature('large astral plane match of property')
|
@@ -36,8 +33,7 @@ class JsRegex
|
|
36
33
|
bmp_part = content.bmp_part
|
37
34
|
return drop if bmp_part.empty?
|
38
35
|
|
39
|
-
|
40
|
-
expression.negative? ? "[^#{string}]" : "[#{string}]"
|
36
|
+
"[#{'^' if expression.negative?}#{bmp_part}]"
|
41
37
|
end
|
42
38
|
end
|
43
39
|
end
|
@@ -31,37 +31,36 @@ class JsRegex
|
|
31
31
|
warn_of_unsupported_feature('nested case-sensitive set')
|
32
32
|
end
|
33
33
|
|
34
|
-
if Converter.
|
35
|
-
Converter.surrogate_pair_limit >= content.astral_part.size
|
34
|
+
if Converter.in_surrogate_pair_limit? { content.astral_part.size }
|
36
35
|
content.to_s_with_surrogate_alternation
|
37
36
|
else
|
38
37
|
warn_of_unsupported_feature('large astral plane match of set')
|
39
38
|
bmp_part = content.bmp_part
|
40
|
-
bmp_part.empty? ? drop : bmp_part.to_s(
|
39
|
+
bmp_part.empty? ? drop : bmp_part.to_s(in_brackets: true)
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
44
43
|
def directly_compatible?
|
45
|
-
if expression.case_insensitive?
|
44
|
+
if expression.case_insensitive? ^ context.case_insensitive_root
|
46
45
|
# casefolding needed
|
47
|
-
return
|
46
|
+
return
|
48
47
|
end
|
49
48
|
|
50
49
|
# check for children needing conversion (#each_expression is recursive)
|
51
|
-
expression.each_expression do |
|
52
|
-
case
|
50
|
+
expression.each_expression do |exp|
|
51
|
+
case exp.type
|
53
52
|
when :literal
|
54
53
|
# surrogate pair substitution needed if astral
|
55
|
-
next if
|
54
|
+
next if exp.text.ord <= 0xFFFF
|
56
55
|
when :set
|
57
56
|
# conversion needed for nested sets, intersections
|
58
|
-
next if
|
57
|
+
next if exp.token.equal?(:range)
|
59
58
|
when :type
|
60
|
-
next if TypeConverter::TYPES_SHARED_BY_RUBY_AND_JS.include?(
|
59
|
+
next if TypeConverter::TYPES_SHARED_BY_RUBY_AND_JS.include?(exp.token)
|
61
60
|
when :escape
|
62
|
-
next if EscapeConverter::ESCAPES_SHARED_BY_RUBY_AND_JS.include?(
|
61
|
+
next if EscapeConverter::ESCAPES_SHARED_BY_RUBY_AND_JS.include?(exp.token)
|
63
62
|
end
|
64
|
-
return
|
63
|
+
return
|
65
64
|
end
|
66
65
|
true
|
67
66
|
end
|
data/lib/js_regex/node.rb
CHANGED
@@ -14,25 +14,21 @@ class JsRegex
|
|
14
14
|
conditional
|
15
15
|
dropped
|
16
16
|
plain
|
17
|
-
|
18
|
-
]
|
17
|
+
].freeze
|
19
18
|
|
20
|
-
def initialize(*children,
|
21
|
-
raise ArgumentError, "bad type #{type}" unless TYPES.include?(type)
|
19
|
+
def initialize(*children, reference: nil, type: :plain)
|
22
20
|
self.children = children
|
23
|
-
self.quantifier = quantifier
|
24
21
|
self.reference = reference
|
25
22
|
self.type = type
|
26
23
|
end
|
27
24
|
|
28
|
-
def initialize_copy(
|
29
|
-
|
30
|
-
self.children = orig.children.map(&:clone)
|
31
|
-
self.quantifier = orig.quantifier && orig.quantifier.clone
|
25
|
+
def initialize_copy(*)
|
26
|
+
self.children = children.map(&:clone)
|
32
27
|
end
|
33
28
|
|
34
|
-
def
|
35
|
-
|
29
|
+
def transform(&block)
|
30
|
+
children.map!(&block)
|
31
|
+
self
|
36
32
|
end
|
37
33
|
|
38
34
|
def <<(node)
|
@@ -58,9 +54,9 @@ class JsRegex
|
|
58
54
|
end
|
59
55
|
|
60
56
|
def update(attrs)
|
61
|
-
self.children = attrs
|
62
|
-
self.quantifier = attrs
|
63
|
-
self.type = attrs
|
57
|
+
self.children = attrs.fetch(:children) if attrs.key?(:children)
|
58
|
+
self.quantifier = attrs.fetch(:quantifier) if attrs.key?(:quantifier)
|
59
|
+
self.type = attrs.fetch(:type) if attrs.key?(:type)
|
64
60
|
end
|
65
61
|
|
66
62
|
private
|
data/lib/js_regex/second_pass.rb
CHANGED
@@ -2,119 +2,98 @@
|
|
2
2
|
|
3
3
|
class JsRegex
|
4
4
|
#
|
5
|
-
# After conversion of a full Regexp::Expression tree, this
|
5
|
+
# After conversion of a full Regexp::Expression tree, this
|
6
6
|
# checks for Node instances that need further processing.
|
7
7
|
#
|
8
|
-
# E.g. subexpression calls (such as \g<1>) can be look-ahead,
|
9
|
-
# so the full Regexp must have been processed first, and only then can
|
10
|
-
# they be substituted with the conversion result of their targeted group.
|
11
|
-
#
|
12
8
|
module SecondPass
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
alternate_conditional_permutations(tree)
|
18
|
-
tree
|
19
|
-
end
|
20
|
-
|
21
|
-
def substitute_subexp_calls(tree)
|
22
|
-
crawl(tree) do |node|
|
23
|
-
if node.type == :subexp_call
|
24
|
-
called_group = find_group_by_reference(node.reference, in_node: tree)
|
25
|
-
node.update(children: called_group.children, type: :captured_group)
|
26
|
-
end
|
9
|
+
class << self
|
10
|
+
def call(tree)
|
11
|
+
alternate_conditional_permutations(tree)
|
12
|
+
tree
|
27
13
|
end
|
28
|
-
end
|
29
14
|
|
30
|
-
|
31
|
-
return if node.instance_of?(String)
|
32
|
-
yield(node)
|
33
|
-
node.children.each { |child| crawl(child, &block) }
|
34
|
-
end
|
15
|
+
private
|
35
16
|
|
36
|
-
|
37
|
-
|
38
|
-
|
17
|
+
def alternate_conditional_permutations(tree)
|
18
|
+
permutations = conditional_tree_permutations(tree)
|
19
|
+
return if permutations.empty?
|
39
20
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
def find_group_by_reference(ref, in_node: nil)
|
47
|
-
crawl(in_node) do |node|
|
48
|
-
return node if node.type == :captured_group && node.reference == ref
|
21
|
+
alternatives = permutations.map.with_index do |variant, i|
|
22
|
+
Node.new((i.zero? ? '(?:' : '|(?:'), variant, ')')
|
23
|
+
end
|
24
|
+
tree.update(children: alternatives)
|
49
25
|
end
|
50
|
-
Node.new('()')
|
51
|
-
end
|
52
|
-
|
53
|
-
def conditional_tree_permutations(tree)
|
54
|
-
all_conditions = conditions(tree)
|
55
|
-
return [] if all_conditions.empty?
|
56
26
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
truthy ?
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
truthy
|
72
|
-
|
73
|
-
|
27
|
+
def conditional_tree_permutations(tree)
|
28
|
+
all_conditions = conditions(tree)
|
29
|
+
return [] if all_conditions.empty?
|
30
|
+
|
31
|
+
captured_groups_per_branch = captured_group_count(tree)
|
32
|
+
|
33
|
+
condition_permutations(all_conditions).map.with_index do |truthy_conds, i|
|
34
|
+
tree_permutation = tree.clone
|
35
|
+
# find referenced groups and conditionals and make one-sided
|
36
|
+
crawl(tree_permutation) do |node|
|
37
|
+
truthy = truthy_conds.include?(node.reference)
|
38
|
+
|
39
|
+
if node.type.equal?(:captured_group) &&
|
40
|
+
all_conditions.include?(node.reference)
|
41
|
+
truthy ? min_quantify(node) : null_quantify(node)
|
42
|
+
elsif node.type.equal?(:conditional)
|
43
|
+
branches = node.children[1...-1]
|
44
|
+
if branches.count == 1
|
45
|
+
truthy || null_quantify(branches.first)
|
46
|
+
else
|
47
|
+
null_quantify(truthy ? branches.last : branches.first)
|
48
|
+
end
|
49
|
+
node.update(type: :plain)
|
50
|
+
elsif node.type.equal?(:backref_num)
|
51
|
+
new_num = node.children[0].to_i + captured_groups_per_branch * i
|
52
|
+
node.update(children: [new_num.to_s])
|
74
53
|
end
|
75
|
-
node.update(type: :plain)
|
76
|
-
elsif node.type.equal?(:backref_num)
|
77
|
-
new_num = node.children[0].to_i + captured_groups_per_branch * i
|
78
|
-
node.update(children: [new_num.to_s])
|
79
54
|
end
|
80
55
|
end
|
81
56
|
end
|
82
|
-
end
|
83
57
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
58
|
+
def crawl(node, &block)
|
59
|
+
return if node.instance_of?(String)
|
60
|
+
yield(node)
|
61
|
+
node.children.each { |child| crawl(child, &block) }
|
88
62
|
end
|
89
|
-
conditions
|
90
|
-
end
|
91
63
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
64
|
+
def conditions(tree)
|
65
|
+
conditions = []
|
66
|
+
crawl(tree) do |node|
|
67
|
+
conditions << node.reference if node.type.equal?(:conditional)
|
68
|
+
end
|
69
|
+
conditions
|
70
|
+
end
|
97
71
|
|
98
|
-
|
99
|
-
|
72
|
+
def captured_group_count(tree)
|
73
|
+
count = 0
|
74
|
+
crawl(tree) { |node| count += 1 if node.type.equal?(:captured_group) }
|
75
|
+
count
|
76
|
+
end
|
100
77
|
|
101
|
-
condition_permutations
|
102
|
-
|
78
|
+
def condition_permutations(conditions)
|
79
|
+
(0..(conditions.length)).inject([]) do |arr, n|
|
80
|
+
arr += conditions.combination(n).to_a
|
81
|
+
end
|
103
82
|
end
|
104
|
-
end
|
105
83
|
|
106
|
-
|
107
|
-
|
84
|
+
def min_quantify(node)
|
85
|
+
return if (qtf = node.quantifier).nil? || qtf.min > 0
|
108
86
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
87
|
+
if qtf.max.equal?(1) # any zero_or_one quantifier (?, ??, ?+)
|
88
|
+
node.update(quantifier: nil)
|
89
|
+
else
|
90
|
+
node.update(quantifier: "{1,#{qtf.max}}#{'?' if qtf.reluctant?}")
|
91
|
+
end
|
113
92
|
end
|
114
|
-
end
|
115
93
|
|
116
|
-
|
117
|
-
|
94
|
+
def null_quantify(node)
|
95
|
+
node.update(quantifier: '{0}')
|
96
|
+
end
|
118
97
|
end
|
119
98
|
end
|
120
99
|
end
|
data/lib/js_regex/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: js_regex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janosch Müller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: character_set
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: regexp_parser
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.5'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.5'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: regexp_property_values
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0.12'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: mutant-rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.8'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.8'
|
125
139
|
description: JsRegex converts Ruby's native regular expressions for JavaScript, taking
|
126
140
|
care of various incompatibilities and returning warnings for unsolvable differences.
|
127
141
|
email:
|
@@ -152,7 +166,7 @@ files:
|
|
152
166
|
- lib/js_regex/node.rb
|
153
167
|
- lib/js_regex/second_pass.rb
|
154
168
|
- lib/js_regex/version.rb
|
155
|
-
homepage: https://github.com/
|
169
|
+
homepage: https://github.com/jaynetics/js_regex
|
156
170
|
licenses:
|
157
171
|
- MIT
|
158
172
|
metadata: {}
|
@@ -171,8 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
185
|
- !ruby/object:Gem::Version
|
172
186
|
version: '0'
|
173
187
|
requirements: []
|
174
|
-
|
175
|
-
rubygems_version: 2.2.2
|
188
|
+
rubygems_version: 3.0.3
|
176
189
|
signing_key:
|
177
190
|
specification_version: 4
|
178
191
|
summary: Converts Ruby regexes to JavaScript regexes.
|