if_test_foo 0.0.4 → 0.0.5

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.
@@ -0,0 +1,286 @@
1
+ module IntervalType
2
+ UNKNOWN = 0
3
+ LEFT_OPEN = 1
4
+ LEFT_CLOSED = 2
5
+ RIGHT_OPEN = 4
6
+ RIGHT_CLOSED = 8
7
+ end
8
+
9
+ class VersionInterval
10
+ attr_accessor :type, :start_cut, :end_cut
11
+
12
+ def initialize(type, start_cut, end_cut)
13
+ @type = type
14
+ @start_cut = start_cut
15
+ @end_cut = end_cut
16
+ end
17
+
18
+ def intersect(other_interval)
19
+ # this look odd -- we have to use it here though, because it may be that placeholders are present inside
20
+ # the version for which > and < would yield true
21
+ return EmptyInterval.new if !(@start_cut <= other_interval.end_cut) || !(other_interval.start_cut <= @end_cut)
22
+
23
+ start_cut_new = max(@start_cut, other_interval.start_cut)
24
+ end_cut_new = min(@end_cut, other_interval.end_cut)
25
+
26
+ # compute the boundaries for the intersection
27
+ type = compute_intersection_boundary(self, other_interval, start_cut_new, end_cut_new)
28
+ interval = VersionInterval.new(type, start_cut_new, end_cut_new)
29
+ half_open = !(interval.bit_set?(IntervalType::RIGHT_CLOSED) && interval.bit_set?(IntervalType::LEFT_CLOSED))
30
+
31
+ interval.singleton? && half_open ? EmptyInterval.new : interval
32
+ end
33
+
34
+ def union(other_interval)
35
+ return EmptyInterval.new if self.intersect(other_interval).instance_of?(EmptyInterval)
36
+
37
+ start_cut_new = min(@start_cut, other_interval.start_cut)
38
+ end_cut_new = max(@end_cut, other_interval.end_cut)
39
+
40
+ # compute the boundaries for the union
41
+ type = compute_union_boundary(self, other_interval, start_cut_new, end_cut_new)
42
+ VersionInterval.new(type, start_cut_new, end_cut_new)
43
+ end
44
+
45
+ def collapse(other_interval)
46
+ return EmptyInterval.new if self.intersect(other_interval).instance_of?(EmptyInterval)
47
+
48
+ frame = [@start_cut, other_interval.start_cut, @end_cut, other_interval.end_cut].reject { |cut| special(cut) }
49
+ min_cut = frame.reduce { |smallest, current| smallest < current ? smallest : current }
50
+ max_cut = frame.reduce { |biggest, current| biggest > current ? biggest : current }
51
+
52
+ # compute the boundaries for the union
53
+ type = compute_union_boundary(self, other_interval, min_cut, max_cut)
54
+ VersionInterval.new(type, min_cut, max_cut)
55
+ end
56
+
57
+ def special(cut)
58
+ cut.instance_of?(AboveAll) || cut.instance_of?(BelowAll)
59
+ end
60
+
61
+ def to_s
62
+ s = ""
63
+ s += bit_set?(IntervalType::LEFT_CLOSED) ? "[" : ""
64
+ s += bit_set?(IntervalType::LEFT_OPEN) ? "(" : ""
65
+ s += [@start_cut, @end_cut].join(",")
66
+ s += bit_set?(IntervalType::RIGHT_CLOSED) ? "]" : ""
67
+ s += bit_set?(IntervalType::RIGHT_OPEN) ? ")" : ""
68
+ s
69
+ end
70
+
71
+ # this function returns a human-readable descriptions of the version strings
72
+ def to_description_s
73
+ s = ""
74
+ if self.distinct?
75
+ s = "version #{@start_cut.to_s}"
76
+ elsif self.universal?
77
+ s = "all versions "
78
+ else
79
+ s = "all versions "
80
+ s += start_cut.instance_of?(BelowAll) ? "" : bit_set?(IntervalType::LEFT_OPEN) ? "after #{@start_cut.to_s} " : bit_set?(IntervalType::LEFT_CLOSED) ? "starting from #{@start_cut.to_s} " : ""
81
+ s += end_cut.instance_of?(AboveAll) ? "" : bit_set?(IntervalType::RIGHT_OPEN) ? "before #{@end_cut.to_s}" : bit_set?(IntervalType::RIGHT_CLOSED) ? "up to #{@end_cut.to_s}" : ""
82
+ end
83
+ s.strip
84
+ end
85
+
86
+ def to_nuget_s
87
+ to_maven_s
88
+ end
89
+
90
+ def to_maven_s
91
+ s = ""
92
+ # special case -- distinct version
93
+ if self.distinct?
94
+ s += "[#{@start_cut.to_s}]"
95
+ else
96
+ s += start_cut.instance_of?(BelowAll) ? "(," : bit_set?(IntervalType::LEFT_OPEN) ? "[#{@start_cut.to_s}," : bit_set?(IntervalType::LEFT_CLOSED) ? "[#{@start_cut.to_s}," : ""
97
+ s += end_cut.instance_of?(AboveAll) ? ")" : bit_set?(IntervalType::RIGHT_OPEN) ? "#{@end_cut.to_s})" : bit_set?(IntervalType::RIGHT_CLOSED) ? "#{@end_cut.to_s}]" : ""
98
+ end
99
+ s
100
+ end
101
+
102
+ def distinct?
103
+ bit_set?(IntervalType::LEFT_CLOSED) && bit_set?(IntervalType::RIGHT_CLOSED) && @start_cut == @end_cut
104
+ end
105
+
106
+ def subsumes?(other)
107
+ @start_cut <= other.start_cut && @end_cut >= other.end_cut
108
+ end
109
+
110
+ def universal?
111
+ (bit_set?(IntervalType::LEFT_OPEN) && bit_set?(IntervalType::RIGHT_OPEN) && @start_cut.instance_of?(BelowAll) && @end_cut.instance_of?(AboveAll)) || @start_cut.is_initial_version? && @end_cut.instance_of?(AboveAll)
112
+ end
113
+
114
+ def to_gem_s
115
+ get_canoncial_s
116
+ end
117
+
118
+ def to_ruby_s
119
+ get_canoncial_s
120
+ end
121
+
122
+ def to_npm_s
123
+ get_canoncial_s
124
+ end
125
+
126
+ def to_conan_s
127
+ get_canoncial_s
128
+ end
129
+
130
+ def to_go_s
131
+ get_canoncial_s
132
+ end
133
+
134
+ def to_pypi_s
135
+ get_canoncial_s(',', '==')
136
+ end
137
+
138
+ def to_packagist_s
139
+ get_canoncial_s(',')
140
+ end
141
+
142
+ def empty?
143
+ self.instance_of?(EmptyInterval)
144
+ end
145
+
146
+ def singleton?
147
+ @start_cut == @end_cut && @start_cut.value == @end_cut.value
148
+ end
149
+
150
+ def diff(other_interval, abs = true)
151
+ if self.distinct? && other_interval.distinct?
152
+ self.start_cut.diff(other_interval.start_cut, abs)
153
+ else
154
+ EmptyInterval.new()
155
+ end
156
+ end
157
+
158
+ def joinable?(other_interval)
159
+ other_interval.start_cut.is_successor_of?(self.end_cut) || universal?
160
+ end
161
+
162
+ def join(other_interval)
163
+ if self.joinable?(other_interval)
164
+ _join(self, other_interval)
165
+ elsif other_interval.joinable?(self)
166
+ _join(other_interval, self)
167
+ else
168
+ EmptyInterval.new()
169
+ end
170
+ end
171
+
172
+ def cross_total
173
+ if distinct?
174
+ @start_cut.cross_total
175
+ else
176
+ @start_cut.cross_total + @end_cut.cross_total
177
+ end
178
+ end
179
+
180
+ def ==(other_interval)
181
+ @start_cut == other_interval.start_cut && @end_cut == other_interval.end_cut && @type == other_interval.type
182
+ end
183
+
184
+ # inverts the given version interval -- note that this function amy return two version intervals
185
+ # e.g., (2,10] -> (-inf, 2], (10, +inf)
186
+ # left right
187
+ def invert
188
+ intervals = []
189
+ left_type = bit_set?(IntervalType::LEFT_OPEN) ? IntervalType::RIGHT_CLOSED : IntervalType::RIGHT_OPEN
190
+ left_type = left_type | IntervalType::LEFT_OPEN
191
+ right_type = bit_set?(IntervalType::RIGHT_OPEN) ? IntervalType::LEFT_CLOSED : IntervalType::LEFT_OPEN
192
+ right_type = right_type | IntervalType::RIGHT_OPEN
193
+
194
+ intervals << VersionInterval.new(left_type, BelowAll.new, @start_cut) unless @start_cut.instance_of?(BelowAll)
195
+ intervals << VersionInterval.new(right_type, @end_cut, AboveAll.new) unless @end_cut.instance_of?(AboveAll)
196
+ intervals
197
+ end
198
+
199
+ def bit_set?(interval_type)
200
+ @type & interval_type != 0
201
+ end
202
+
203
+ protected
204
+
205
+ # computes the boundary type for union operation
206
+ def compute_union_boundary(interval_a, interval_b, start_cut_new, end_cut_new)
207
+ compute_boundary(interval_a, interval_b, start_cut_new, end_cut_new, IntervalType::LEFT_CLOSED, IntervalType::RIGHT_CLOSED)
208
+ end
209
+
210
+ def compute_intersection_boundary(interval_a, interval_b, start_cut_new, end_cut_new)
211
+ compute_boundary(interval_a, interval_b,start_cut_new, end_cut_new, IntervalType::LEFT_OPEN, IntervalType::RIGHT_OPEN)
212
+ end
213
+
214
+ def compute_boundary(interval_a, interval_b, start_cut_new, end_cut_new, left_check, right_check)
215
+ start_cut_a = interval_a.start_cut
216
+ end_cut_a = interval_a.end_cut
217
+ type_a = interval_a.type
218
+
219
+ start_cut_b = interval_b.start_cut
220
+ end_cut_b = interval_b.end_cut
221
+ type_b = interval_b.type
222
+
223
+ left_fill = left_check == IntervalType::LEFT_OPEN ? IntervalType::LEFT_CLOSED : IntervalType::LEFT_OPEN
224
+ right_fill = right_check == IntervalType::RIGHT_OPEN ? IntervalType::RIGHT_CLOSED : IntervalType::RIGHT_OPEN
225
+
226
+ # compute the boundaries for the union
227
+ if start_cut_b == start_cut_a && start_cut_b == start_cut_b
228
+ one_left_closed = left_type(type_a) == left_check || left_type(type_b) == left_check
229
+ left_type = one_left_closed ? left_check : left_fill
230
+ else
231
+ left_type = start_cut_new == start_cut_a ? left_type(type_a) : left_type(type_b)
232
+ end
233
+
234
+ if end_cut_b == end_cut_a && end_cut_b == end_cut_b
235
+ one_right_closed = right_type(type_a) == right_check || right_type(type_b) == right_check
236
+ right_type = one_right_closed ? right_check : right_fill
237
+ else
238
+ right_type = end_cut_new == end_cut_a ? right_type(type_a) : right_type(type_b)
239
+ end
240
+
241
+ left_type | right_type
242
+ end
243
+
244
+ def _join(first_interval, second_interval)
245
+ if first_interval.joinable?(second_interval)
246
+ VersionInterval.new(first_interval.type, first_interval.start_cut.dup, second_interval.end_cut.dup)
247
+ else
248
+ EmptyInterval.new()
249
+ end
250
+ end
251
+
252
+ def get_canoncial_s(delimiter = " ", eq = '=')
253
+ if self.distinct?
254
+ "#{eq}#{@start_cut.to_s}"
255
+ else
256
+ first = start_cut.instance_of?(BelowAll) ? "" : bit_set?(IntervalType::LEFT_OPEN) ? ">#{@start_cut.to_s}" : bit_set?(IntervalType::LEFT_CLOSED) ? ">=#{@start_cut.to_s}" : ""
257
+ second = end_cut.instance_of?(AboveAll) ? "" : bit_set?(IntervalType::RIGHT_OPEN) ? "<#{@end_cut.to_s}" : bit_set?(IntervalType::RIGHT_CLOSED) ? "<=#{@end_cut.to_s}" : ""
258
+ !first.empty? && !second.empty? ? "#{first}#{delimiter}#{second}" : first + second
259
+ end
260
+ end
261
+
262
+ def max(cut_a, cut_b)
263
+ cut_a > cut_b ? cut_a : cut_b
264
+ end
265
+
266
+ def min(cut_a, cut_b)
267
+ cut_a < cut_b ? cut_a : cut_b
268
+ end
269
+
270
+ def right_type(type)
271
+ (IntervalType::RIGHT_OPEN | IntervalType::RIGHT_CLOSED) & type
272
+ end
273
+
274
+ def left_type(type)
275
+ (IntervalType::LEFT_OPEN | IntervalType::LEFT_CLOSED) & type
276
+ end
277
+ end
278
+
279
+ class EmptyInterval < VersionInterval
280
+ def initialize()
281
+ end
282
+
283
+ def to_s
284
+ "empty"
285
+ end
286
+ end
@@ -0,0 +1,37 @@
1
+ require_relative "version_cut"
2
+ require_relative "version_interval"
3
+
4
+ module VersionParser
5
+ def self.parse(versionstring)
6
+ if (versionstring == "=*")
7
+ # special case = All Versions
8
+ return VersionInterval.new(IntervalType::LEFT_OPEN | IntervalType::RIGHT_OPEN, BelowAll.new(), AboveAll.new())
9
+ end
10
+
11
+ version_items = versionstring.split(" ")
12
+ interval = VersionInterval.new(IntervalType::LEFT_OPEN | IntervalType::RIGHT_OPEN, BelowAll.new(), AboveAll.new())
13
+ version_items.each do
14
+ |version_item|
15
+ matches = version_item.match /(?<op>[><=]+) *(?<version>[a-zA-Z0-9\-_\.\*]+)/
16
+ version_string = matches[:version]
17
+ case matches[:op]
18
+ when ">="
19
+ new_interval = VersionInterval.new(IntervalType::LEFT_CLOSED | IntervalType::RIGHT_OPEN, VersionCut.new(version_string), AboveAll.new())
20
+ interval = interval.intersect(new_interval)
21
+ when "<="
22
+ new_interval = VersionInterval.new(IntervalType::LEFT_OPEN | IntervalType::RIGHT_CLOSED, BelowAll.new(), VersionCut.new(version_string))
23
+ interval = interval.intersect(new_interval)
24
+ when "<"
25
+ new_interval = VersionInterval.new(IntervalType::LEFT_OPEN | IntervalType::RIGHT_OPEN, BelowAll.new(), VersionCut.new(version_string))
26
+ interval = interval.intersect(new_interval)
27
+ when ">"
28
+ new_interval = VersionInterval.new(IntervalType::LEFT_OPEN | IntervalType::RIGHT_OPEN, VersionCut.new(version_string), AboveAll.new())
29
+ interval = interval.intersect(new_interval)
30
+ when "=", "=="
31
+ new_interval = VersionInterval.new(IntervalType::LEFT_CLOSED | IntervalType::RIGHT_CLOSED, VersionCut.new(version_string), VersionCut.new(version_string))
32
+ interval = interval.intersect(new_interval)
33
+ end
34
+ end
35
+ interval
36
+ end
37
+ end
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'version_parser'
4
+ require 'set'
5
+
6
+ # VersionRange is a utility class that helps managing consecutive version ranges automatically
7
+ # given that they are added in-order
8
+ # Note that join_if_possible should be only activated in case the ranges are added in consecutive order!!
9
+ class VersionRange
10
+ attr_reader :version_intervals, :join_if_possible
11
+
12
+ def initialize(join_if_possible = true)
13
+ @version_intervals = []
14
+ @version_interval_set = Set.new
15
+ @join_if_possible = join_if_possible
16
+ end
17
+
18
+ def add_all(version_range)
19
+ version_range.version_intervals.each { |interval| add(interval) }
20
+ end
21
+
22
+ def add(version_interval)
23
+ return if @version_interval_set.include?(version_interval)
24
+
25
+ if @join_if_possible
26
+ if @version_intervals.empty?
27
+ @version_intervals << version_interval
28
+ @version_interval_set.add(version_interval)
29
+ else
30
+ last = @version_intervals.last
31
+ # nothing to do
32
+ return if last.end_cut == version_interval.start_cut && last.end_cut.value == version_interval.start_cut.value
33
+
34
+ if last.joinable?(version_interval)
35
+ @version_intervals[@version_intervals.size - 1] = last.join(version_interval)
36
+ else
37
+ @version_intervals << version_interval
38
+ @version_interval_set.add(version_interval)
39
+ end
40
+ end
41
+ else
42
+ @version_intervals << version_interval
43
+ @version_interval_set.add(version_interval)
44
+ end
45
+ end
46
+
47
+ def <<(item)
48
+ add(item)
49
+ end
50
+
51
+ def size
52
+ @version_intervals.size
53
+ end
54
+
55
+ def to_s
56
+ @version_intervals.map(&:to_s).join(',')
57
+ end
58
+
59
+ def to_description_s
60
+ @version_intervals.map(&:to_description_s).join(', ').capitalize
61
+ end
62
+
63
+ def to_npm_s
64
+ @version_intervals.map(&:to_npm_s).join('||')
65
+ end
66
+
67
+ def to_conan_s
68
+ to_npm_s
69
+ end
70
+
71
+ def to_nuget_s
72
+ to_maven_s
73
+ end
74
+
75
+ def to_maven_s
76
+ @version_intervals.map(&:to_maven_s).join(',')
77
+ end
78
+
79
+ def to_gem_s
80
+ @version_intervals.map(&:to_gem_s).join('||')
81
+ end
82
+
83
+ def to_pypi_s
84
+ @version_intervals.map(&:to_pypi_s).join('||')
85
+ end
86
+
87
+ def to_go_s
88
+ @version_intervals.map(&:to_go_s).join('||')
89
+ end
90
+
91
+ def to_packagist_s
92
+ @version_intervals.map(&:to_packagist_s).join('||')
93
+ end
94
+
95
+ def to_version_s(package_type)
96
+ case package_type
97
+ when 'npm'
98
+ to_npm_s
99
+ when 'nuget'
100
+ to_nuget_s
101
+ when 'maven'
102
+ to_maven_s
103
+ when 'gem'
104
+ to_gem_s
105
+ when 'pypi'
106
+ to_pypi_s
107
+ when 'packagist'
108
+ to_packagist_s
109
+ when 'go'
110
+ to_go_s
111
+ when 'conan'
112
+ to_conan_s
113
+ else
114
+ ''
115
+ end
116
+ end
117
+
118
+ # inverts the given version interval -- note that this function amy return two version intervals
119
+ # e.g., (2,10], (12, 13], [15, +inf)
120
+ # 1) invert: (-inf, 2], (10, +inf), (-inf, 12], (13, +inf), (15)
121
+ # 2) collapse (-inf, 2], (10, 12], (13, 15)
122
+ #
123
+ # the collapsed inverted ranges can potentially contain fixed versions
124
+ def invert
125
+ inverted = @version_intervals.map(&:invert).flatten
126
+ version_intervals = collapse_intervals(inverted)
127
+ version_intervals_to_range(version_intervals)
128
+ end
129
+
130
+ def collapse
131
+ version_intervals = collapse_intervals(@version_intervals)
132
+ version_intervals_to_range(version_intervals)
133
+ end
134
+
135
+ def includes?(version_interval)
136
+ @version_interval_set.include?(version_interval)
137
+ end
138
+
139
+ def overlaps_with?(version_interval)
140
+ @version_interval_set.each do |interval|
141
+ return true unless interval.intersect(version_interval).instance_of? EmptyInterval
142
+ end
143
+ false
144
+ end
145
+
146
+ def first
147
+ @version_intervals.first
148
+ end
149
+
150
+ def empty?
151
+ @version_intervals.empty?
152
+ end
153
+
154
+ def any?
155
+ @version_intervals.any?
156
+ end
157
+
158
+ def universal?
159
+ @version_intervals.each do |version_interval|
160
+ return true if version_interval.universal?
161
+ end
162
+ false
163
+ end
164
+
165
+ private
166
+
167
+ def version_intervals_to_range(version_intervals)
168
+ ret = VersionRange.new(false)
169
+ version_intervals.each do |version_interval|
170
+ ret << version_interval
171
+ end
172
+ ret
173
+ end
174
+
175
+ def collapse_intervals(version_intervals)
176
+ interval_cp = []
177
+ interval_cp += version_intervals
178
+ ret = [interval_cp.shift]
179
+
180
+ interval_cp.each do |item|
181
+ last = ret.last
182
+ if last.intersect(item).instance_of?(EmptyInterval)
183
+ ret << item
184
+ else
185
+ ret.pop
186
+ ret << last.collapse(item)
187
+ end
188
+ end
189
+ ret
190
+ end
191
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../utils.rb'
4
+
5
+ # A prepropcessor -- convert different version strings to something that can be digested by the
6
+ # version parser
7
+ module VersionTranslator
8
+ def self.translate_npm(version_string)
9
+ version_string.split('||').map do |item|
10
+ add_missing_operator(single_space_after_operator(item.strip.gsub(/&&/, ' ')))
11
+ end
12
+ end
13
+
14
+ def self.translate_conan(version_string)
15
+ translate_npm(version_string)
16
+ end
17
+
18
+ def self.translate_go(version_string)
19
+ translate_gem(version_string)
20
+ end
21
+
22
+ def self.translate_gem(version_string)
23
+ version_string.split('||').map do |item|
24
+ add_missing_operator(single_space_after_operator(item.strip.gsub(/\s+/, ' ')))
25
+ end
26
+ end
27
+
28
+ def self.translate_packagist(version_string)
29
+ translate_pypi(version_string)
30
+ end
31
+
32
+ def self.translate_pypi(version_string)
33
+ version_string.split('||').map do |item|
34
+ add_missing_operator(single_space_after_operator(comma_to_space(item)))
35
+ end
36
+ end
37
+
38
+ def self.translate_nuget(version_string)
39
+ translate_maven(version_string)
40
+ end
41
+
42
+ def self.translate_maven(version_string)
43
+ lexing_maven_version_string(version_string).map { |item| translate_mvn_version_item(item) }
44
+ end
45
+
46
+ def self.add_missing_operator(version_string)
47
+ starts_with_operator?(version_string) ? version_string : "=#{version_string}"
48
+ end
49
+
50
+ def self.single_space_after_operator(version_string)
51
+ version_string.gsub(/([>=<]+) +/, '\1').gsub(/\s+/, ' ')
52
+ end
53
+
54
+ def self.starts_with_operator?(version_item)
55
+ version_item.match(/^[=><]/) ? true : false
56
+ end
57
+
58
+ def self.comma_to_space(version_string)
59
+ version_string.strip.gsub(/,/, ' ')
60
+ end
61
+
62
+ def self.lexing_maven_version_string(version_string)
63
+ open = false
64
+ substring = ''
65
+ ret = []
66
+ version_string.each_char do |c|
67
+ case c
68
+ when '(', '['
69
+ if open
70
+ puts "malformed maven version string #{version_string}"
71
+ exit(-1)
72
+ else
73
+ unless substring.empty?
74
+ ret << substring
75
+ substring = ''
76
+ end
77
+ open = true
78
+ substring += c
79
+ end
80
+ when ')', ']'
81
+ if !open
82
+ puts "malformed maven version string #{version_string}"
83
+ exit(-1)
84
+ else
85
+ open = false
86
+ substring += c
87
+ ret << substring
88
+ substring = ''
89
+ end
90
+ when ','
91
+ substring += c if open
92
+ when ' '
93
+ # nothing to do
94
+ substring += ''
95
+ else
96
+ substring += c
97
+ end
98
+ end
99
+ if open
100
+ puts "malformed maven version string #{version_string}"
101
+ exit(-1)
102
+ end
103
+ ret << substring unless substring.empty?
104
+ ret
105
+ end
106
+
107
+ def self.parenthesized?(version_item)
108
+ version_item.match(/^[\(\[]/) && version_item.match(/[\]\)]$/) ? true : false
109
+ end
110
+
111
+ def self.translate_mvn_version_item(version_item)
112
+ content = ''
113
+ parens_pattern = ''
114
+ if parenthesized?(version_item)
115
+ content = version_item[1, version_item.size - 2]
116
+ parens_pattern = version_item[0] + version_item[version_item.size - 1]
117
+ # special case -- unversal version range
118
+ return '=*' if content.strip == ','
119
+ else
120
+ # according to the doc, if there is a plain version string in maven, it means 'starting from version x'
121
+ # https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8903
122
+ content = "#{version_item},"
123
+ parens_pattern = '[)'
124
+ end
125
+
126
+ args = content.split(',')
127
+ first_non_empty_arg = args.find(&:range_present?)
128
+
129
+ if content.start_with?(',')
130
+ # {,y}
131
+ case parens_pattern
132
+ when '[]'
133
+ "<=#{first_non_empty_arg}"
134
+ when '()'
135
+ "<#{first_non_empty_arg}"
136
+ when '[)'
137
+ "<#{first_non_empty_arg}"
138
+ else
139
+ # par_pattern == "(]"
140
+ "<=#{first_non_empty_arg}"
141
+ end
142
+ elsif content.end_with?(',')
143
+ # {x,}
144
+ case parens_pattern
145
+ when '[]'
146
+ ">=#{first_non_empty_arg}"
147
+ when '()'
148
+ ">#{first_non_empty_arg}"
149
+ when '[)'
150
+ ">=#{first_non_empty_arg}"
151
+ else
152
+ # par_pattern == "(]"
153
+ ">#{first_non_empty_arg}"
154
+ end
155
+ elsif content[','].nil?
156
+ # [x,x]
157
+ "=#{content}"
158
+ else
159
+ case parens_pattern
160
+ when '[]'
161
+ ">=#{args[0]} <=#{args[1]}"
162
+ when '()'
163
+ ">#{args[0]} <#{args[1]}"
164
+ when '[)'
165
+ ">=#{args[0]} <#{args[1]}"
166
+ else
167
+ # par_pattern == "(]"
168
+ ">#{args[0]} <=#{args[1]}"
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SemverDialects
4
+ VERSION = '1.3.0'
5
+ end