js_regex 3.1.1 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.
|