js_regex 3.12.0 → 3.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/js_regex/conversion.rb +1 -1
- data/lib/js_regex/converter/anchor_converter.rb +13 -2
- data/lib/js_regex/converter/backreference_converter.rb +5 -2
- data/lib/js_regex/converter/base.rb +3 -2
- data/lib/js_regex/converter/context.rb +10 -0
- data/lib/js_regex/converter/escape_converter.rb +2 -2
- data/lib/js_regex/converter/group_converter.rb +1 -1
- data/lib/js_regex/converter/set_converter.rb +14 -5
- data/lib/js_regex/converter/type_converter.rb +6 -2
- data/lib/js_regex/version.rb +1 -1
- metadata +7 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 054de046ea7e8e7244c80e8c8385270ffd821f0fdd690b8a15a79ea1c1d2a6f4
|
4
|
+
data.tar.gz: d6d3dbd4d191e16008bfd586ff22a10a8240275ac328c0a080af910d99b650a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93e7c0a574cadfb867c598a9adbcbd9b18585204912865e589691246ce879bec7b7d48a02872c599447db3f2feeda80236d08b1030aecd1d6bf0568792ac859a
|
7
|
+
data.tar.gz: e766f2ce0305ed0e6b10372d58f07fb0137e51a4a62a607b1f0272ac4b431c820fdb9ca2b8d2ce18de30d4bd33ca6cd8c49846d5c8efa79c081324342b990e87
|
data/lib/js_regex/conversion.rb
CHANGED
@@ -37,7 +37,7 @@ class JsRegex
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def convert_options(input, custom_options, required_options)
|
40
|
-
options = custom_options.to_s.scan(/[
|
40
|
+
options = custom_options.to_s.scan(/[dgimsuvy]/) + required_options
|
41
41
|
if input.is_a?(Regexp) && (input.options & Regexp::IGNORECASE).nonzero?
|
42
42
|
options << 'i'
|
43
43
|
end
|
@@ -10,8 +10,10 @@ class JsRegex
|
|
10
10
|
|
11
11
|
def convert_data
|
12
12
|
case subtype
|
13
|
-
when :bol
|
14
|
-
when :
|
13
|
+
when :bol then convert_bol
|
14
|
+
when :bos then '^'
|
15
|
+
when :eol then '(?=$|\n)'
|
16
|
+
when :eos then '$'
|
15
17
|
when :eos_ob_eol then '(?=\n?$)'
|
16
18
|
when :word_boundary then convert_boundary
|
17
19
|
when :nonword_boundary then convert_nonboundary
|
@@ -20,6 +22,15 @@ class JsRegex
|
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
25
|
+
def convert_bol
|
26
|
+
if context.es_2018_or_higher?
|
27
|
+
'(?<=^|\n(?!$))'
|
28
|
+
else
|
29
|
+
# TODO: warn in v4.0.0, or drop ES2009 & ES2015 support
|
30
|
+
'^'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
23
34
|
def convert_boundary
|
24
35
|
if context.es_2018_or_higher? && context.enable_u_option
|
25
36
|
BOUNDARY_EXPANSION
|
@@ -29,7 +29,8 @@ class JsRegex
|
|
29
29
|
|
30
30
|
def convert_to_plain_num_ref
|
31
31
|
position = new_position
|
32
|
-
|
32
|
+
text = "\\#{position}#{'(?:)' if expression.x?}"
|
33
|
+
Node.new(text, reference: position, type: :backref)
|
33
34
|
end
|
34
35
|
|
35
36
|
def new_position
|
@@ -43,7 +44,7 @@ class JsRegex
|
|
43
44
|
def convert_call
|
44
45
|
if context.recursions(expression) >= 5
|
45
46
|
warn_of("Recursion for '#{expression}' curtailed at 5 levels")
|
46
|
-
return
|
47
|
+
return drop
|
47
48
|
end
|
48
49
|
|
49
50
|
context.count_recursion(expression)
|
@@ -51,7 +52,9 @@ class JsRegex
|
|
51
52
|
target_copy = expression.referenced_expression.unquantified_clone
|
52
53
|
# avoid "Duplicate capture group name" error in JS
|
53
54
|
target_copy.token = :capture if target_copy.is?(:named, :group)
|
55
|
+
context.start_subexp_recursion
|
54
56
|
result = convert_expression(target_copy)
|
57
|
+
context.end_subexp_recursion
|
55
58
|
# wrap in group if it is a full-pattern recursion
|
56
59
|
expression.reference == 0 ? Node.new('(?:', result, ')') : result
|
57
60
|
end
|
@@ -79,8 +79,9 @@ class JsRegex
|
|
79
79
|
number = context.capturing_group_count + 1
|
80
80
|
backref_node = Node.new("\\#{number}", reference: number, type: :backref)
|
81
81
|
context.increment_local_capturing_group_count
|
82
|
-
#
|
83
|
-
|
82
|
+
# The surrounding group is added so that quantifiers apply to the whole.
|
83
|
+
# Without it, `(?:)` would need to be appended as literal digits may follow.
|
84
|
+
Node.new('(?:(?=(', *content, '))', backref_node, ')')
|
84
85
|
end
|
85
86
|
end
|
86
87
|
end
|
@@ -10,6 +10,7 @@ class JsRegex
|
|
10
10
|
:case_insensitive_root,
|
11
11
|
:fail_fast,
|
12
12
|
:in_atomic_group,
|
13
|
+
:in_subexp_recursion,
|
13
14
|
:warnings
|
14
15
|
|
15
16
|
def initialize(case_insensitive_root: false, fail_fast: false, target: nil)
|
@@ -81,6 +82,14 @@ class JsRegex
|
|
81
82
|
[exp.class, exp.starts_at]
|
82
83
|
end
|
83
84
|
|
85
|
+
def start_subexp_recursion
|
86
|
+
self.in_subexp_recursion = true
|
87
|
+
end
|
88
|
+
|
89
|
+
def end_subexp_recursion
|
90
|
+
self.in_subexp_recursion = false
|
91
|
+
end
|
92
|
+
|
84
93
|
# takes and returns 1-indexed group positions.
|
85
94
|
# new is different from old if capturing groups were added in between.
|
86
95
|
def new_capturing_group_position(old_position)
|
@@ -106,6 +115,7 @@ class JsRegex
|
|
106
115
|
:case_insensitive_root,
|
107
116
|
:fail_fast,
|
108
117
|
:in_atomic_group,
|
118
|
+
:in_subexp_recursion,
|
109
119
|
:warnings
|
110
120
|
|
111
121
|
def total_added_capturing_groups
|
@@ -42,10 +42,10 @@ class JsRegex
|
|
42
42
|
unicode_escape_codepoint
|
43
43
|
when :literal
|
44
44
|
LiteralConverter.convert_data(expression.char, context)
|
45
|
+
when :bell, :escape, :hex, :octal
|
46
|
+
hex_escape_codepoint
|
45
47
|
when *ESCAPES_SHARED_BY_RUBY_AND_JS
|
46
48
|
pass_through
|
47
|
-
when :bell, :escape, :octal
|
48
|
-
hex_escape_codepoint
|
49
49
|
else
|
50
50
|
warn_of_unsupported_feature
|
51
51
|
end
|
@@ -84,7 +84,7 @@ class JsRegex
|
|
84
84
|
tail = opts[:tail] || ')'
|
85
85
|
return Node.new(*wrap(head, tail)) if opts[:capturing].equal?(false)
|
86
86
|
|
87
|
-
context.capture_group
|
87
|
+
context.capture_group unless context.in_subexp_recursion
|
88
88
|
ref = expression.number
|
89
89
|
Node.new(*wrap(head, tail), reference: ref, type: :captured_group)
|
90
90
|
end
|
@@ -41,11 +41,7 @@ class JsRegex
|
|
41
41
|
def simple_convert_child(exp)
|
42
42
|
case exp.type
|
43
43
|
when :literal
|
44
|
-
|
45
|
-
exp.text =~ LiteralConverter::ASTRAL_PLANE_CODEPOINT_PATTERN &&
|
46
|
-
!context.enable_u_option
|
47
|
-
|
48
|
-
LiteralConverter.escape_incompatible_bmp_literals(exp.text)
|
44
|
+
simple_convert_literal_child(exp)
|
49
45
|
when :set
|
50
46
|
# full conversion is needed for nested sets and intersections
|
51
47
|
exp.token.equal?(:range) && exp.expressions.map do |op|
|
@@ -67,6 +63,19 @@ class JsRegex
|
|
67
63
|
end
|
68
64
|
end
|
69
65
|
|
66
|
+
def simple_convert_literal_child(exp)
|
67
|
+
if !context.u? &&
|
68
|
+
exp.text =~ LiteralConverter::ASTRAL_PLANE_CODEPOINT_PATTERN &&
|
69
|
+
!context.enable_u_option
|
70
|
+
false
|
71
|
+
elsif SET_LITERALS_REQUIRING_ESCAPE_PATTERN.match?(exp.text)
|
72
|
+
"\\#{exp.text}"
|
73
|
+
else
|
74
|
+
LiteralConverter.escape_incompatible_bmp_literals(exp.text)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
SET_LITERALS_REQUIRING_ESCAPE_PATTERN = Regexp.union(%w<( ) [ ] { } / - |>)
|
70
79
|
SET_SPECIFIC_ESCAPES_PATTERN = /[\^\-]/
|
71
80
|
CONVERTIBLE_ESCAPE_TOKENS = %i[control meta_sequence bell escape octal] +
|
72
81
|
EscapeConverter::ESCAPES_SHARED_BY_RUBY_AND_JS
|
@@ -30,7 +30,7 @@ class JsRegex
|
|
30
30
|
case subtype
|
31
31
|
when :hex then hex_expansion
|
32
32
|
when :nonhex then nonhex_expansion
|
33
|
-
when :linebreak then
|
33
|
+
when :linebreak then linebreak_expansion
|
34
34
|
when :xgrapheme then xgrapheme
|
35
35
|
when :digit, :space, :word
|
36
36
|
return pass_through if self.class.directly_compatible?(expression)
|
@@ -63,6 +63,10 @@ class JsRegex
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
def linebreak_expansion
|
67
|
+
wrap_in_backrefed_lookahead(LINEBREAK_EXPANSION)
|
68
|
+
end
|
69
|
+
|
66
70
|
def negative_set_substitution
|
67
71
|
# ::of_expression returns an inverted set for negative expressions,
|
68
72
|
# so we need to un-invert before wrapping in [^ and ]. Kinda lame.
|
@@ -79,7 +83,7 @@ class JsRegex
|
|
79
83
|
|
80
84
|
def xgrapheme
|
81
85
|
if context.es_2018_or_higher? && context.enable_u_option
|
82
|
-
ES2018_XGRAPHEME_EXPANSION
|
86
|
+
wrap_in_backrefed_lookahead(ES2018_XGRAPHEME_EXPANSION)
|
83
87
|
else
|
84
88
|
warn_of_unsupported_feature
|
85
89
|
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.13.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: 2025-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: character_set
|
@@ -28,22 +28,16 @@ dependencies:
|
|
28
28
|
name: regexp_parser
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 2.6.2
|
34
|
-
- - "<"
|
31
|
+
- - "~>"
|
35
32
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
33
|
+
version: '2.10'
|
37
34
|
type: :runtime
|
38
35
|
prerelease: false
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
40
37
|
requirements:
|
41
|
-
- - "
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: 2.6.2
|
44
|
-
- - "<"
|
38
|
+
- - "~>"
|
45
39
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
40
|
+
version: '2.10'
|
47
41
|
- !ruby/object:Gem::Dependency
|
48
42
|
name: regexp_property_values
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
105
|
- !ruby/object:Gem::Version
|
112
106
|
version: '0'
|
113
107
|
requirements: []
|
114
|
-
rubygems_version: 3.5.
|
108
|
+
rubygems_version: 3.5.22
|
115
109
|
signing_key:
|
116
110
|
specification_version: 4
|
117
111
|
summary: Converts Ruby regexes to JavaScript regexes.
|