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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c6bfe5a3631b78df8e258b46c12f9c89eeabefa5ce0967760cd7cc9c152ca8e
4
- data.tar.gz: d05300ee0f1496adbfa455533af89d8a42af7808af14fdb1f6c569bfcde5913f
3
+ metadata.gz: 054de046ea7e8e7244c80e8c8385270ffd821f0fdd690b8a15a79ea1c1d2a6f4
4
+ data.tar.gz: d6d3dbd4d191e16008bfd586ff22a10a8240275ac328c0a080af910d99b650a1
5
5
  SHA512:
6
- metadata.gz: e7ed1e47c10c775151a4ccfbae673c9d122354841a20b7d18aed2e545b81ce9c87584026b2d7433c83be42d30c5e1c9ca823f7f31186cea4278273d3698c2a12
7
- data.tar.gz: 9d1e0e0f2ae0865e69262c8eefef4999cbcf877a270eb642ee7f115a3ff77c10c0ca8c6fdb60093fba5244e54bca0de58c1514ad28a1c6c21378e3c64d00b378
6
+ metadata.gz: 93e7c0a574cadfb867c598a9adbcbd9b18585204912865e589691246ce879bec7b7d48a02872c599447db3f2feeda80236d08b1030aecd1d6bf0568792ac859a
7
+ data.tar.gz: e766f2ce0305ed0e6b10372d58f07fb0137e51a4a62a607b1f0272ac4b431c820fdb9ca2b8d2ce18de30d4bd33ca6cd8c49846d5c8efa79c081324342b990e87
@@ -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(/[gimsuy]/) + required_options
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, :bos then '^'
14
- when :eol, :eos then '$'
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
- Node.new("\\#{position}", reference: position, type: :backref)
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
- # an empty passive group (?:) is appended as literal digits may follow
83
- Node.new('(?=(', *content, '))', backref_node, '(?:)')
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
- return false if !context.u? &&
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 LINEBREAK_EXPANSION
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
@@ -1,3 +1,3 @@
1
1
  class JsRegex
2
- VERSION = '3.12.0'
2
+ VERSION = '3.13.0'
3
3
  end
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.12.0
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: 2024-11-02 00:00:00.000000000 Z
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: 3.0.0
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: 3.0.0
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.16
108
+ rubygems_version: 3.5.22
115
109
  signing_key:
116
110
  specification_version: 4
117
111
  summary: Converts Ruby regexes to JavaScript regexes.