aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/semver/range.v
blob: fd0a76999c10758e4f1b3b9b91b21b21c62dfeca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
module semver

// * Private functions.
const (
	comparator_sep     = ' '
	comparator_set_sep = ' || '
	hyphen_range_sep   = ' - '
	x_range_symbols    = 'Xx*'
)

enum Operator {
	gt
	lt
	ge
	le
	eq
}

struct Comparator {
	ver Version
	op  Operator
}

struct ComparatorSet {
	comparators []Comparator
}

struct Range {
	comparator_sets []ComparatorSet
}

struct InvalidComparatorCountError {
	msg  string
	code int
}

struct InvalidComparatorFormatError {
	msg  string
	code int
}

fn (r Range) satisfies(ver Version) bool {
	mut final_result := false
	for set in r.comparator_sets {
		final_result = final_result || set.satisfies(ver)
	}
	return final_result
}

fn (set ComparatorSet) satisfies(ver Version) bool {
	for comp in set.comparators {
		if !comp.satisfies(ver) {
			return false
		}
	}
	return true
}

fn (c Comparator) satisfies(ver Version) bool {
	if c.op == .gt {
		return ver.gt(c.ver)
	}
	if c.op == .lt {
		return ver.lt(c.ver)
	}
	if c.op == .ge {
		return ver.ge(c.ver)
	}
	if c.op == .le {
		return ver.le(c.ver)
	}
	if c.op == .eq {
		return ver.eq(c.ver)
	}
	return false
}

fn parse_range(input string) ?Range {
	raw_comparator_sets := input.split(semver.comparator_set_sep)
	mut comparator_sets := []ComparatorSet{}
	for raw_comp_set in raw_comparator_sets {
		if can_expand(raw_comp_set) {
			s := expand_comparator_set(raw_comp_set) or { return err }
			comparator_sets << s
		} else {
			s := parse_comparator_set(raw_comp_set) or { return err }
			comparator_sets << s
		}
	}
	return Range{comparator_sets}
}

fn parse_comparator_set(input string) ?ComparatorSet {
	raw_comparators := input.split(semver.comparator_sep)
	if raw_comparators.len > 2 {
		return IError(&InvalidComparatorFormatError{
			msg: 'Invalid format of comparator set for input "$input"'
		})
	}
	mut comparators := []Comparator{}
	for raw_comp in raw_comparators {
		c := parse_comparator(raw_comp) or {
			return IError(&InvalidComparatorFormatError{
				msg: 'Invalid comparator "$raw_comp" in input "$input"'
			})
		}
		comparators << c
	}
	return ComparatorSet{comparators}
}

fn parse_comparator(input string) ?Comparator {
	mut op := Operator.eq
	mut raw_version := ''
	if input.starts_with('>=') {
		op = .ge
		raw_version = input[2..]
	} else if input.starts_with('<=') {
		op = .le
		raw_version = input[2..]
	} else if input.starts_with('>') {
		op = .gt
		raw_version = input[1..]
	} else if input.starts_with('<') {
		op = .lt
		raw_version = input[1..]
	} else if input.starts_with('=') {
		raw_version = input[1..]
	} else {
		raw_version = input
	}
	version := coerce_version(raw_version) or { return none }
	return Comparator{version, op}
}

fn parse_xrange(input string) ?Version {
	mut raw_ver := parse(input).complete()
	for typ in versions {
		if raw_ver.raw_ints[typ].index_any(semver.x_range_symbols) == -1 {
			continue
		}
		match typ {
			ver_major {
				raw_ver.raw_ints[ver_major] = '0'
				raw_ver.raw_ints[ver_minor] = '0'
				raw_ver.raw_ints[ver_patch] = '0'
			}
			ver_minor {
				raw_ver.raw_ints[ver_minor] = '0'
				raw_ver.raw_ints[ver_patch] = '0'
			}
			ver_patch {
				raw_ver.raw_ints[ver_patch] = '0'
			}
			else {}
		}
	}
	if !raw_ver.is_valid() {
		return none
	}
	return raw_ver.to_version()
}

fn can_expand(input string) bool {
	return input[0] == `~` || input[0] == `^` || input.contains(semver.hyphen_range_sep)
		|| input.index_any(semver.x_range_symbols) > -1
}

fn expand_comparator_set(input string) ?ComparatorSet {
	match input[0] {
		`~` { return expand_tilda(input[1..]) }
		`^` { return expand_caret(input[1..]) }
		else {}
	}
	if input.contains(semver.hyphen_range_sep) {
		return expand_hyphen(input)
	}
	return expand_xrange(input)
}

fn expand_tilda(raw_version string) ?ComparatorSet {
	min_ver := coerce_version(raw_version) or { return none }
	mut max_ver := min_ver
	if min_ver.minor == 0 && min_ver.patch == 0 {
		max_ver = min_ver.increment(.major)
	} else {
		max_ver = min_ver.increment(.minor)
	}
	return make_comparator_set_ge_lt(min_ver, max_ver)
}

fn expand_caret(raw_version string) ?ComparatorSet {
	min_ver := coerce_version(raw_version) or { return none }
	mut max_ver := min_ver
	if min_ver.major == 0 {
		max_ver = min_ver.increment(.minor)
	} else {
		max_ver = min_ver.increment(.major)
	}
	return make_comparator_set_ge_lt(min_ver, max_ver)
}

fn expand_hyphen(raw_range string) ?ComparatorSet {
	raw_versions := raw_range.split(semver.hyphen_range_sep)
	if raw_versions.len != 2 {
		return none
	}
	min_ver := coerce_version(raw_versions[0]) or { return none }
	raw_max_ver := parse(raw_versions[1])
	if raw_max_ver.is_missing(ver_major) {
		return none
	}
	mut max_ver := raw_max_ver.coerce() or { return none }
	if raw_max_ver.is_missing(ver_minor) {
		max_ver = max_ver.increment(.minor)
		return make_comparator_set_ge_lt(min_ver, max_ver)
	}
	return make_comparator_set_ge_le(min_ver, max_ver)
}

fn expand_xrange(raw_range string) ?ComparatorSet {
	min_ver := parse_xrange(raw_range) or { return none }
	if min_ver.major == 0 {
		comparators := [
			Comparator{min_ver, Operator.ge},
		]
		return ComparatorSet{comparators}
	}
	mut max_ver := min_ver
	if min_ver.minor == 0 {
		max_ver = min_ver.increment(.major)
	} else {
		max_ver = min_ver.increment(.minor)
	}
	return make_comparator_set_ge_lt(min_ver, max_ver)
}

fn make_comparator_set_ge_lt(min Version, max Version) ComparatorSet {
	comparators := [
		Comparator{min, Operator.ge},
		Comparator{max, Operator.lt},
	]
	return ComparatorSet{comparators}
}

fn make_comparator_set_ge_le(min Version, max Version) ComparatorSet {
	comparators := [
		Comparator{min, Operator.ge},
		Comparator{max, Operator.le},
	]
	return ComparatorSet{comparators}
}