js_regex 3.13.0 → 3.14.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 +4 -4
- data/lib/js_regex/conversion.rb +2 -0
- data/lib/js_regex/converter/anchor_converter.rb +2 -0
- data/lib/js_regex/converter/assertion_converter.rb +2 -0
- data/lib/js_regex/converter/backreference_converter.rb +60 -4
- data/lib/js_regex/converter/base.rb +11 -2
- data/lib/js_regex/converter/conditional_converter.rb +2 -0
- data/lib/js_regex/converter/context.rb +28 -2
- data/lib/js_regex/converter/escape_converter.rb +3 -1
- data/lib/js_regex/converter/freespace_converter.rb +2 -0
- data/lib/js_regex/converter/group_converter.rb +6 -10
- data/lib/js_regex/converter/keep_converter.rb +2 -0
- data/lib/js_regex/converter/literal_converter.rb +5 -3
- data/lib/js_regex/converter/meta_converter.rb +2 -0
- data/lib/js_regex/converter/property_converter.rb +2 -0
- data/lib/js_regex/converter/set_converter.rb +3 -1
- data/lib/js_regex/converter/subexpression_converter.rb +2 -0
- data/lib/js_regex/converter/type_converter.rb +31 -2
- data/lib/js_regex/converter/unsupported_token_converter.rb +2 -0
- data/lib/js_regex/converter.rb +2 -0
- data/lib/js_regex/error.rb +2 -0
- data/lib/js_regex/node.rb +8 -1
- data/lib/js_regex/second_pass.rb +49 -14
- data/lib/js_regex/target.rb +2 -0
- data/lib/js_regex/version.rb +3 -1
- data/lib/js_regex.rb +2 -0
- metadata +5 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81da8ab5dab32613d0486bb8b1d0c9926b1cd5dcf5cbf1dae7f7c7b86b695718
|
4
|
+
data.tar.gz: ad87e55f4c1834b237d8f18318fae065625e1e94f7645158ec4a7450967e5b69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b6e9d0eea5aa5656d3eaae3dd0ad769a21ef8a32d7304237afbe965266e8a8e8229c256a9110ce1573b2faf52ef112f354fcf84af61183b1f5aeb79035869f5
|
7
|
+
data.tar.gz: e546194d186650cc46aed54b73d92e6320251cb2954e213859fe3e5d4e06e04f502f8e0b5fe7a331db12578b59678484e184485ce4397dd61391677fe4766cd2
|
data/lib/js_regex/conversion.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'base'
|
2
4
|
|
3
5
|
class JsRegex
|
@@ -19,20 +21,41 @@ class JsRegex
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def convert_name_ref
|
22
|
-
if
|
23
|
-
|
24
|
-
|
24
|
+
# Check if this is a multiplexed named group reference
|
25
|
+
if expression.referenced_expressions.count > 1
|
26
|
+
convert_multiplexed_name_ref
|
25
27
|
else
|
28
|
+
# Always use numeric backrefs since we convert all named groups to numbered
|
29
|
+
# (see comment in GroupConverter)
|
26
30
|
convert_to_plain_num_ref
|
27
31
|
end
|
28
32
|
end
|
29
33
|
|
30
34
|
def convert_to_plain_num_ref
|
31
35
|
position = new_position
|
36
|
+
|
37
|
+
# Check if this backreference refers to a group that was recursively called
|
38
|
+
original_group = target_position
|
39
|
+
if (recursive_position = context.get_recursive_group_position(original_group))
|
40
|
+
# Use the position of the group created by the recursive call
|
41
|
+
position = recursive_position
|
42
|
+
end
|
43
|
+
|
32
44
|
text = "\\#{position}#{'(?:)' if expression.x?}"
|
33
45
|
Node.new(text, reference: position, type: :backref)
|
34
46
|
end
|
35
47
|
|
48
|
+
def convert_multiplexed_name_ref
|
49
|
+
# Create alternation of all groups with the same name
|
50
|
+
positions = expression.referenced_expressions.map do |ref_exp|
|
51
|
+
context.new_capturing_group_position(ref_exp.number)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Build alternation like (?:\1|\2)
|
55
|
+
alternation = positions.map { |pos| "\\#{pos}" }.join('|')
|
56
|
+
Node.new("(?:#{alternation})")
|
57
|
+
end
|
58
|
+
|
36
59
|
def new_position
|
37
60
|
context.new_capturing_group_position(target_position)
|
38
61
|
end
|
@@ -48,6 +71,10 @@ class JsRegex
|
|
48
71
|
end
|
49
72
|
|
50
73
|
context.count_recursion(expression)
|
74
|
+
|
75
|
+
# Track groups before the wrapper group is added
|
76
|
+
groups_before_wrapper = context.capturing_group_count
|
77
|
+
|
51
78
|
context.increment_local_capturing_group_count
|
52
79
|
target_copy = expression.referenced_expression.unquantified_clone
|
53
80
|
# avoid "Duplicate capture group name" error in JS
|
@@ -55,9 +82,38 @@ class JsRegex
|
|
55
82
|
context.start_subexp_recursion
|
56
83
|
result = convert_expression(target_copy)
|
57
84
|
context.end_subexp_recursion
|
58
|
-
|
85
|
+
|
86
|
+
# Track all groups created during this recursive call
|
87
|
+
# This handles both the directly called group and any nested groups within it
|
88
|
+
# Get all group numbers from the referenced expression
|
89
|
+
original_groups = collect_group_numbers(expression.referenced_expression)
|
90
|
+
|
91
|
+
# The first new group number is groups_before_wrapper + 1
|
92
|
+
# (the wrapper group from increment_local_capturing_group_count doesn't appear in output)
|
93
|
+
first_new_group = groups_before_wrapper + 1
|
94
|
+
|
95
|
+
# Map each original group to its corresponding new group
|
96
|
+
# For example, if we recursively called group 1 which contains group 2,
|
97
|
+
# and this created groups 3 and 4, then:
|
98
|
+
# - group 1 -> group 3
|
99
|
+
# - group 2 -> group 4
|
100
|
+
original_groups.each_with_index do |old_group_num, index|
|
101
|
+
new_group_num = first_new_group + index
|
102
|
+
context.track_recursive_group_call(old_group_num, new_group_num)
|
103
|
+
end
|
104
|
+
|
105
|
+
# wrap in passive group if it is a full-pattern recursion
|
59
106
|
expression.reference == 0 ? Node.new('(?:', result, ')') : result
|
60
107
|
end
|
108
|
+
|
109
|
+
def collect_group_numbers(exp)
|
110
|
+
return [] if exp.terminal?
|
111
|
+
|
112
|
+
numbers = []
|
113
|
+
numbers << exp.number if exp.capturing?
|
114
|
+
exp.each_expression { |sub| numbers += collect_group_numbers(sub) }
|
115
|
+
numbers
|
116
|
+
end
|
61
117
|
end
|
62
118
|
end
|
63
119
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class JsRegex
|
2
4
|
module Converter
|
3
5
|
#
|
@@ -44,7 +46,9 @@ class JsRegex
|
|
44
46
|
end
|
45
47
|
|
46
48
|
def convert_subexpressions
|
47
|
-
|
49
|
+
# mark alternation and conditional branches for processing in second pass
|
50
|
+
type = expression.is?(:sequence) ? :branch : :plain
|
51
|
+
Node.new(*expression.map { |subexp| convert_expression(subexp) }, type: type)
|
48
52
|
end
|
49
53
|
|
50
54
|
def convert_expression(expression)
|
@@ -78,10 +82,15 @@ class JsRegex
|
|
78
82
|
def wrap_in_backrefed_lookahead(content)
|
79
83
|
number = context.capturing_group_count + 1
|
80
84
|
backref_node = Node.new("\\#{number}", reference: number, type: :backref)
|
85
|
+
backrefed_group = Node.new('(', *content, ')', reference: number, type: :captured_group)
|
81
86
|
context.increment_local_capturing_group_count
|
82
87
|
# The surrounding group is added so that quantifiers apply to the whole.
|
83
88
|
# Without it, `(?:)` would need to be appended as literal digits may follow.
|
84
|
-
Node.new('(?:(?=
|
89
|
+
Node.new('(?:(?=', backrefed_group, ')', backref_node, ')')
|
90
|
+
end
|
91
|
+
|
92
|
+
def unmatchable_substitution
|
93
|
+
'(?!)'
|
85
94
|
end
|
86
95
|
end
|
87
96
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class JsRegex
|
2
4
|
module Converter
|
3
5
|
#
|
@@ -18,8 +20,10 @@ class JsRegex
|
|
18
20
|
self.capturing_group_count = 0
|
19
21
|
self.fail_fast = fail_fast
|
20
22
|
self.recursions_per_expression = {}
|
23
|
+
self.recursion_stack = []
|
21
24
|
self.required_options_hash = {}
|
22
25
|
self.warnings = []
|
26
|
+
self.recursive_group_map = {}
|
23
27
|
|
24
28
|
self.case_insensitive_root = case_insensitive_root
|
25
29
|
self.target = target
|
@@ -71,11 +75,12 @@ class JsRegex
|
|
71
75
|
end
|
72
76
|
|
73
77
|
def recursions(exp)
|
74
|
-
|
78
|
+
# Count recursions in the current stack path only
|
79
|
+
recursion_stack.count { |e| recursion_id(e) == recursion_id(exp) }
|
75
80
|
end
|
76
81
|
|
77
82
|
def count_recursion(exp)
|
78
|
-
|
83
|
+
recursion_stack.push(exp)
|
79
84
|
end
|
80
85
|
|
81
86
|
def recursion_id(exp)
|
@@ -84,10 +89,18 @@ class JsRegex
|
|
84
89
|
|
85
90
|
def start_subexp_recursion
|
86
91
|
self.in_subexp_recursion = true
|
92
|
+
self.recursion_start_group_count = capturing_group_count
|
87
93
|
end
|
88
94
|
|
89
95
|
def end_subexp_recursion
|
90
96
|
self.in_subexp_recursion = false
|
97
|
+
# Pop the last recursion from stack when exiting
|
98
|
+
recursion_stack.pop if recursion_stack.any?
|
99
|
+
end
|
100
|
+
|
101
|
+
# Get the number of groups at the start of the current recursion
|
102
|
+
def recursion_start_group_count
|
103
|
+
self.recursion_start_group_count || 0
|
91
104
|
end
|
92
105
|
|
93
106
|
# takes and returns 1-indexed group positions.
|
@@ -104,11 +117,23 @@ class JsRegex
|
|
104
117
|
capturing_group_count - total_added_capturing_groups
|
105
118
|
end
|
106
119
|
|
120
|
+
# Track that a group was created by a recursive call
|
121
|
+
def track_recursive_group_call(original_group_num, new_group_num)
|
122
|
+
recursive_group_map[original_group_num] = new_group_num
|
123
|
+
end
|
124
|
+
|
125
|
+
# Get the group number created by a recursive call
|
126
|
+
def get_recursive_group_position(original_group_num)
|
127
|
+
recursive_group_map[original_group_num]
|
128
|
+
end
|
129
|
+
|
107
130
|
private
|
108
131
|
|
109
132
|
attr_accessor :added_capturing_groups_after_group,
|
110
133
|
:recursions_per_expression,
|
134
|
+
:recursion_stack,
|
111
135
|
:required_options_hash,
|
136
|
+
:recursive_group_map,
|
112
137
|
:target
|
113
138
|
|
114
139
|
attr_writer :capturing_group_count,
|
@@ -116,6 +141,7 @@ class JsRegex
|
|
116
141
|
:fail_fast,
|
117
142
|
:in_atomic_group,
|
118
143
|
:in_subexp_recursion,
|
144
|
+
:recursion_start_group_count,
|
119
145
|
:warnings
|
120
146
|
|
121
147
|
def total_added_capturing_groups
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'base'
|
2
4
|
require_relative 'literal_converter'
|
3
5
|
|
@@ -38,7 +40,7 @@ class JsRegex
|
|
38
40
|
case subtype
|
39
41
|
when :codepoint_list
|
40
42
|
convert_codepoint_list
|
41
|
-
when :control, :meta_sequence
|
43
|
+
when :control, :meta_sequence, :utf8_hex
|
42
44
|
unicode_escape_codepoint
|
43
45
|
when :literal
|
44
46
|
LiteralConverter.convert_data(expression.char, context)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'base'
|
2
4
|
|
3
5
|
class JsRegex
|
@@ -22,12 +24,10 @@ class JsRegex
|
|
22
24
|
end
|
23
25
|
|
24
26
|
def build_named_group
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
build_group
|
30
|
-
end
|
27
|
+
# Always convert named groups to numbered groups. ES2018+ supports named
|
28
|
+
# groups, but can not handle repeated names in multiplexing or conditional
|
29
|
+
# expansion scenarios.
|
30
|
+
build_group
|
31
31
|
end
|
32
32
|
|
33
33
|
def emulate_atomic_group
|
@@ -69,10 +69,6 @@ class JsRegex
|
|
69
69
|
expression.empty?
|
70
70
|
end
|
71
71
|
|
72
|
-
def unmatchable_substitution
|
73
|
-
'(?!)'
|
74
|
-
end
|
75
|
-
|
76
72
|
def build_absence_group
|
77
73
|
head = "(?:(?:.|\\n){,#{expression.inner_match_length.min - 1}}|(?:(?!"
|
78
74
|
tail = ')(?:.|\n))*)'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'base'
|
2
4
|
|
3
5
|
class JsRegex
|
@@ -6,8 +8,8 @@ class JsRegex
|
|
6
8
|
# Template class implementation.
|
7
9
|
#
|
8
10
|
class LiteralConverter < JsRegex::Converter::Base
|
9
|
-
ASTRAL_PLANE_CODEPOINT_PATTERN = /[\u{10000}-\u{10FFFF}]
|
10
|
-
LITERAL_REQUIRING_ESCAPE_PATTERN = /[\/\f\n\r\t\v]
|
11
|
+
ASTRAL_PLANE_CODEPOINT_PATTERN = /[\u{10000}-\u{10FFFF}]/.freeze
|
12
|
+
LITERAL_REQUIRING_ESCAPE_PATTERN = /[\/\f\n\r\t\v]/.freeze
|
11
13
|
|
12
14
|
class << self
|
13
15
|
def convert_data(data, context)
|
@@ -59,7 +61,7 @@ class JsRegex
|
|
59
61
|
result
|
60
62
|
end
|
61
63
|
|
62
|
-
HAS_CASE_PATTERN = /[\p{lower}\p{upper}]
|
64
|
+
HAS_CASE_PATTERN = /[\p{lower}\p{upper}]/.freeze
|
63
65
|
|
64
66
|
def handle_locally_case_insensitive_literal(literal)
|
65
67
|
literal =~ HAS_CASE_PATTERN ? case_insensitivize(literal) : literal
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'base'
|
2
4
|
require_relative 'escape_converter'
|
3
5
|
require_relative 'type_converter'
|
@@ -76,7 +78,7 @@ class JsRegex
|
|
76
78
|
end
|
77
79
|
|
78
80
|
SET_LITERALS_REQUIRING_ESCAPE_PATTERN = Regexp.union(%w<( ) [ ] { } / - |>)
|
79
|
-
SET_SPECIFIC_ESCAPES_PATTERN = /[\^\-]
|
81
|
+
SET_SPECIFIC_ESCAPES_PATTERN = /[\^\-]/.freeze
|
80
82
|
CONVERTIBLE_ESCAPE_TOKENS = %i[control meta_sequence bell escape octal] +
|
81
83
|
EscapeConverter::ESCAPES_SHARED_BY_RUBY_AND_JS
|
82
84
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'base'
|
2
4
|
|
3
5
|
class JsRegex
|
@@ -10,10 +12,37 @@ class JsRegex
|
|
10
12
|
NONHEX_EXPANSION = '[^0-9A-Fa-f]'
|
11
13
|
I_MODE_HEX_EXPANSION = '[0-9A-F]'
|
12
14
|
I_MODE_NONHEX_EXPANSION = '[^0-9A-F]'
|
15
|
+
LINEBREAK_EXPANSION = '(?:\r\n|[\n\v\f\r\u0085\u2028\u2029])'
|
13
16
|
ES2018_HEX_EXPANSION = '\p{AHex}'
|
14
17
|
ES2018_NONHEX_EXPANSION = '\P{AHex}'
|
15
|
-
|
16
|
-
|
18
|
+
# partially taken from https://unicode.org/reports/tr51/#EBNF_and_Regex
|
19
|
+
ES2018_XGRAPHEME_EXPANSION = <<-'REGEXP'.gsub(/\s+/, '')
|
20
|
+
(?:
|
21
|
+
\r\n
|
22
|
+
|
|
23
|
+
\p{RI}\p{RI}
|
24
|
+
|
|
25
|
+
\p{Emoji}
|
26
|
+
(?:
|
27
|
+
\p{EMod}
|
28
|
+
|
|
29
|
+
\uFE0F\u20E3?
|
30
|
+
|
|
31
|
+
[\u{E0020}-\u{E007E}]+\u{E007F}
|
32
|
+
)?
|
33
|
+
(?:
|
34
|
+
\u200D
|
35
|
+
(?:
|
36
|
+
\p{RI}\p{RI}
|
37
|
+
|
|
38
|
+
\p{Emoji}(?:\p{EMod}|\uFE0F\u20E3?|[\u{E0020}-\u{E007E}]+\u{E007F})?
|
39
|
+
)
|
40
|
+
)*
|
41
|
+
|
|
42
|
+
[\P{M}\P{Lm}](?:\u200d|\p{M}|\p{Lm}|\p{Emoji_Modifier})*
|
43
|
+
)
|
44
|
+
REGEXP
|
45
|
+
|
17
46
|
|
18
47
|
def self.directly_compatible?(expression, _context = nil)
|
19
48
|
case expression.token
|
data/lib/js_regex/converter.rb
CHANGED
data/lib/js_regex/error.rb
CHANGED
data/lib/js_regex/node.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class JsRegex
|
2
4
|
#
|
3
5
|
# Converter#convert result. Represents a branch or leaf node with an optional
|
@@ -10,6 +12,7 @@ class JsRegex
|
|
10
12
|
|
11
13
|
TYPES = %i[
|
12
14
|
backref
|
15
|
+
branch
|
13
16
|
captured_group
|
14
17
|
conditional
|
15
18
|
dropped
|
@@ -47,7 +50,7 @@ class JsRegex
|
|
47
50
|
case type
|
48
51
|
when :dropped
|
49
52
|
''
|
50
|
-
when :backref, :captured_group, :plain
|
53
|
+
when :backref, :branch, :captured_group, :plain
|
51
54
|
children.join << quantifier.to_s
|
52
55
|
else
|
53
56
|
raise TypeError.new(
|
@@ -63,6 +66,10 @@ class JsRegex
|
|
63
66
|
self
|
64
67
|
end
|
65
68
|
|
69
|
+
def optional?
|
70
|
+
quantifier && quantifier.min == 0
|
71
|
+
end
|
72
|
+
|
66
73
|
private
|
67
74
|
|
68
75
|
TypeError = Class.new(::TypeError).extend(JsRegex::Error)
|
data/lib/js_regex/second_pass.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class JsRegex
|
2
4
|
#
|
3
5
|
# After conversion of a full Regexp::Expression tree, this
|
@@ -8,6 +10,7 @@ class JsRegex
|
|
8
10
|
def call(tree)
|
9
11
|
substitute_root_level_keep_mark(tree)
|
10
12
|
alternate_conditional_permutations(tree)
|
13
|
+
handle_non_participating_backrefs(tree)
|
11
14
|
tree
|
12
15
|
end
|
13
16
|
|
@@ -26,12 +29,49 @@ class JsRegex
|
|
26
29
|
tree.update(children: [lookbehind, *post])
|
27
30
|
end
|
28
31
|
|
32
|
+
def handle_non_participating_backrefs(tree)
|
33
|
+
level = 0
|
34
|
+
completed_group_numbers = {}
|
35
|
+
group_branches = {}
|
36
|
+
branch_stack = []
|
37
|
+
|
38
|
+
crawl(tree, true) do |node, event|
|
39
|
+
case [node.type, event]
|
40
|
+
when [:branch, :enter]
|
41
|
+
branch_stack.push(node)
|
42
|
+
when [:branch, :exit]
|
43
|
+
branch_stack.pop
|
44
|
+
when [:captured_group, :enter]
|
45
|
+
level += 1
|
46
|
+
when [:captured_group, :exit]
|
47
|
+
unless node.optional? # ignore optional groups
|
48
|
+
group_branches[node.reference] = branch_stack.last
|
49
|
+
end
|
50
|
+
number = level
|
51
|
+
number += 1 while completed_group_numbers[number]
|
52
|
+
completed_group_numbers[number] = true
|
53
|
+
level -= 1
|
54
|
+
when [:backref, :exit]
|
55
|
+
ref_branch = group_branches[node.reference]
|
56
|
+
current_branch = branch_stack.last
|
57
|
+
|
58
|
+
# make bad backrefs non-matchable
|
59
|
+
references_other_branch =
|
60
|
+
ref_branch && current_branch && ref_branch != current_branch
|
61
|
+
forward_reference = !completed_group_numbers[node.reference]
|
62
|
+
if references_other_branch || forward_reference
|
63
|
+
node.update(type: :plain, children: ['(?!)'])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
29
69
|
def alternate_conditional_permutations(tree)
|
30
70
|
permutations = conditional_tree_permutations(tree)
|
31
71
|
return if permutations.empty?
|
32
72
|
|
33
73
|
alternatives = permutations.map.with_index do |variant, i|
|
34
|
-
Node.new((i.zero? ? '(?:' : '|(?:'), variant, ')')
|
74
|
+
Node.new((i.zero? ? '(?:' : '|(?:'), variant, ')', type: :branch)
|
35
75
|
end
|
36
76
|
tree.update(children: alternatives)
|
37
77
|
end
|
@@ -48,13 +88,16 @@ class JsRegex
|
|
48
88
|
crawl(tree_permutation) do |node|
|
49
89
|
build_permutation(node, conds, truthy_conds, caps_per_branch, i)
|
50
90
|
end
|
91
|
+
tree_permutation
|
51
92
|
end
|
52
93
|
end
|
53
94
|
|
54
|
-
def crawl(node, &block)
|
95
|
+
def crawl(node, trace = false, &block)
|
55
96
|
return if node.instance_of?(String)
|
56
|
-
|
57
|
-
|
97
|
+
|
98
|
+
trace ? yield(node, :enter) : yield(node)
|
99
|
+
node.children.each { |child| crawl(child, trace, &block) }
|
100
|
+
trace && yield(node, :exit)
|
58
101
|
end
|
59
102
|
|
60
103
|
def conditions(tree)
|
@@ -90,11 +133,6 @@ class JsRegex
|
|
90
133
|
# backref numbers need to be incremented for subsequent "branches"
|
91
134
|
adapt_backref_to_permutation(node, caps_per_branch, i)
|
92
135
|
when :captured_group
|
93
|
-
# Remove name, c.f. :backref handling.
|
94
|
-
node.update(children: [
|
95
|
-
node.children.first.sub(/\?<.*>/, ''),
|
96
|
-
*node.children[1..-1]
|
97
|
-
])
|
98
136
|
# if the group is referenced by any condition, modulate its quantity
|
99
137
|
if conds.include?(node.reference)
|
100
138
|
adapt_referenced_group_to_permutation(node, truthy)
|
@@ -124,8 +162,9 @@ class JsRegex
|
|
124
162
|
end
|
125
163
|
|
126
164
|
def min_quantify(node)
|
127
|
-
return
|
165
|
+
return unless node.optional?
|
128
166
|
|
167
|
+
qtf = node.quantifier
|
129
168
|
if qtf.max.equal?(1) # any zero_or_one quantifier (?, ??, ?+)
|
130
169
|
node.update(quantifier: nil)
|
131
170
|
else
|
@@ -135,10 +174,6 @@ class JsRegex
|
|
135
174
|
end
|
136
175
|
end
|
137
176
|
|
138
|
-
def guarantees_at_least_one_match?(quantifier)
|
139
|
-
quantifier.nil? || quantifier.min > 0
|
140
|
-
end
|
141
|
-
|
142
177
|
def null_quantify(node)
|
143
178
|
null_quantifier = Regexp::Expression::Quantifier.construct(text: '{0}')
|
144
179
|
node.update(quantifier: null_quantifier)
|
data/lib/js_regex/target.rb
CHANGED
data/lib/js_regex/version.rb
CHANGED
data/lib/js_regex.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: js_regex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janosch Müller
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: character_set
|
@@ -30,14 +29,14 @@ dependencies:
|
|
30
29
|
requirements:
|
31
30
|
- - "~>"
|
32
31
|
- !ruby/object:Gem::Version
|
33
|
-
version: '2.
|
32
|
+
version: '2.11'
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
37
36
|
requirements:
|
38
37
|
- - "~>"
|
39
38
|
- !ruby/object:Gem::Version
|
40
|
-
version: '2.
|
39
|
+
version: '2.11'
|
41
40
|
- !ruby/object:Gem::Dependency
|
42
41
|
name: regexp_property_values
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -90,7 +89,6 @@ homepage: https://github.com/jaynetics/js_regex
|
|
90
89
|
licenses:
|
91
90
|
- MIT
|
92
91
|
metadata: {}
|
93
|
-
post_install_message:
|
94
92
|
rdoc_options: []
|
95
93
|
require_paths:
|
96
94
|
- lib
|
@@ -105,8 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
103
|
- !ruby/object:Gem::Version
|
106
104
|
version: '0'
|
107
105
|
requirements: []
|
108
|
-
rubygems_version: 3.
|
109
|
-
signing_key:
|
106
|
+
rubygems_version: 3.6.7
|
110
107
|
specification_version: 4
|
111
108
|
summary: Converts Ruby regexes to JavaScript regexes.
|
112
109
|
test_files: []
|