js_regex 3.11.1 → 3.13.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 +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 +12 -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
|
@@ -8,6 +8,8 @@ class JsRegex
|
|
8
8
|
class TypeConverter < JsRegex::Converter::Base
|
9
9
|
HEX_EXPANSION = '[0-9A-Fa-f]'
|
10
10
|
NONHEX_EXPANSION = '[^0-9A-Fa-f]'
|
11
|
+
I_MODE_HEX_EXPANSION = '[0-9A-F]'
|
12
|
+
I_MODE_NONHEX_EXPANSION = '[^0-9A-F]'
|
11
13
|
ES2018_HEX_EXPANSION = '\p{AHex}'
|
12
14
|
ES2018_NONHEX_EXPANSION = '\P{AHex}'
|
13
15
|
ES2018_XGRAPHEME_EXPANSION = '[\P{M}\P{Lm}](?:(?:[\u035C\u0361]\P{M}\p{M}*)|\u200d|\p{M}|\p{Lm}|\p{Emoji_Modifier})*'
|
@@ -28,7 +30,7 @@ class JsRegex
|
|
28
30
|
case subtype
|
29
31
|
when :hex then hex_expansion
|
30
32
|
when :nonhex then nonhex_expansion
|
31
|
-
when :linebreak then
|
33
|
+
when :linebreak then linebreak_expansion
|
32
34
|
when :xgrapheme then xgrapheme
|
33
35
|
when :digit, :space, :word
|
34
36
|
return pass_through if self.class.directly_compatible?(expression)
|
@@ -44,6 +46,8 @@ class JsRegex
|
|
44
46
|
def hex_expansion
|
45
47
|
if context.es_2018_or_higher? && context.enable_u_option
|
46
48
|
ES2018_HEX_EXPANSION
|
49
|
+
elsif context.case_insensitive_root
|
50
|
+
I_MODE_HEX_EXPANSION
|
47
51
|
else
|
48
52
|
HEX_EXPANSION
|
49
53
|
end
|
@@ -52,11 +56,17 @@ class JsRegex
|
|
52
56
|
def nonhex_expansion
|
53
57
|
if context.es_2018_or_higher? && context.enable_u_option
|
54
58
|
ES2018_NONHEX_EXPANSION
|
59
|
+
elsif context.case_insensitive_root
|
60
|
+
I_MODE_NONHEX_EXPANSION
|
55
61
|
else
|
56
62
|
NONHEX_EXPANSION
|
57
63
|
end
|
58
64
|
end
|
59
65
|
|
66
|
+
def linebreak_expansion
|
67
|
+
wrap_in_backrefed_lookahead(LINEBREAK_EXPANSION)
|
68
|
+
end
|
69
|
+
|
60
70
|
def negative_set_substitution
|
61
71
|
# ::of_expression returns an inverted set for negative expressions,
|
62
72
|
# so we need to un-invert before wrapping in [^ and ]. Kinda lame.
|
@@ -73,7 +83,7 @@ class JsRegex
|
|
73
83
|
|
74
84
|
def xgrapheme
|
75
85
|
if context.es_2018_or_higher? && context.enable_u_option
|
76
|
-
ES2018_XGRAPHEME_EXPANSION
|
86
|
+
wrap_in_backrefed_lookahead(ES2018_XGRAPHEME_EXPANSION)
|
77
87
|
else
|
78
88
|
warn_of_unsupported_feature
|
79
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.
|