1use std::collections::HashSet;
4
5use semver_crate::{Version, VersionReq};
6use serde_json::{Number, Value};
7
8use crate::functions::{Function, number_value};
9use crate::interpreter::SearchResult;
10use crate::registry::register_if_enabled;
11use crate::{Context, Runtime, arg, defn};
12
13defn!(SemverParseFn, vec![arg!(string)], None);
18
19impl Function for SemverParseFn {
20 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
21 self.signature.validate(args, ctx)?;
22 let s = args[0].as_str().unwrap();
23
24 match Version::parse(s) {
25 Ok(v) => {
26 let pre = if v.pre.is_empty() {
27 Value::Null
28 } else {
29 Value::String(v.pre.to_string())
30 };
31 let build = if v.build.is_empty() {
32 Value::Null
33 } else {
34 Value::String(v.build.to_string())
35 };
36
37 let obj = serde_json::json!({
38 "major": v.major,
39 "minor": v.minor,
40 "patch": v.patch,
41 "pre": pre,
42 "build": build
43 });
44
45 Ok(obj)
46 }
47 Err(_) => Ok(Value::Null),
48 }
49 }
50}
51
52defn!(SemverMajorFn, vec![arg!(string)], None);
57
58impl Function for SemverMajorFn {
59 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
60 self.signature.validate(args, ctx)?;
61 let s = args[0].as_str().unwrap();
62
63 match Version::parse(s) {
64 Ok(v) => Ok(Value::Number(Number::from(v.major))),
65 Err(_) => Ok(Value::Null),
66 }
67 }
68}
69
70defn!(SemverMinorFn, vec![arg!(string)], None);
75
76impl Function for SemverMinorFn {
77 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
78 self.signature.validate(args, ctx)?;
79 let s = args[0].as_str().unwrap();
80
81 match Version::parse(s) {
82 Ok(v) => Ok(Value::Number(Number::from(v.minor))),
83 Err(_) => Ok(Value::Null),
84 }
85 }
86}
87
88defn!(SemverPatchFn, vec![arg!(string)], None);
93
94impl Function for SemverPatchFn {
95 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
96 self.signature.validate(args, ctx)?;
97 let s = args[0].as_str().unwrap();
98
99 match Version::parse(s) {
100 Ok(v) => Ok(Value::Number(Number::from(v.patch))),
101 Err(_) => Ok(Value::Null),
102 }
103 }
104}
105
106defn!(SemverCompareFn, vec![arg!(string), arg!(string)], None);
111
112impl Function for SemverCompareFn {
113 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
114 self.signature.validate(args, ctx)?;
115 let s1 = args[0].as_str().unwrap();
116 let s2 = args[1].as_str().unwrap();
117
118 let v1 = match Version::parse(s1) {
119 Ok(v) => v,
120 Err(_) => return Ok(Value::Null),
121 };
122 let v2 = match Version::parse(s2) {
123 Ok(v) => v,
124 Err(_) => return Ok(Value::Null),
125 };
126
127 let result = match v1.cmp(&v2) {
128 std::cmp::Ordering::Less => -1,
129 std::cmp::Ordering::Equal => 0,
130 std::cmp::Ordering::Greater => 1,
131 };
132
133 Ok(number_value(result as f64))
134 }
135}
136
137defn!(SemverSatisfiesFn, vec![arg!(string), arg!(string)], None);
142
143impl Function for SemverSatisfiesFn {
144 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
145 self.signature.validate(args, ctx)?;
146 let version_str = args[0].as_str().unwrap();
147 let req_str = args[1].as_str().unwrap();
148
149 let version = match Version::parse(version_str) {
150 Ok(v) => v,
151 Err(_) => return Ok(Value::Null),
152 };
153 let req = match VersionReq::parse(req_str) {
154 Ok(r) => r,
155 Err(_) => return Ok(Value::Null),
156 };
157
158 Ok(Value::Bool(req.matches(&version)))
159 }
160}
161
162defn!(SemverIsValidFn, vec![arg!(string)], None);
167
168impl Function for SemverIsValidFn {
169 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
170 self.signature.validate(args, ctx)?;
171 let s = args[0].as_str().unwrap();
172 let is_valid = Version::parse(s).is_ok();
173 Ok(Value::Bool(is_valid))
174 }
175}
176
177pub fn register_filtered(runtime: &mut Runtime, enabled: &HashSet<&str>) {
179 register_if_enabled(
180 runtime,
181 "semver_parse",
182 enabled,
183 Box::new(SemverParseFn::new()),
184 );
185 register_if_enabled(
186 runtime,
187 "semver_major",
188 enabled,
189 Box::new(SemverMajorFn::new()),
190 );
191 register_if_enabled(
192 runtime,
193 "semver_minor",
194 enabled,
195 Box::new(SemverMinorFn::new()),
196 );
197 register_if_enabled(
198 runtime,
199 "semver_patch",
200 enabled,
201 Box::new(SemverPatchFn::new()),
202 );
203 register_if_enabled(
204 runtime,
205 "semver_compare",
206 enabled,
207 Box::new(SemverCompareFn::new()),
208 );
209 register_if_enabled(
210 runtime,
211 "semver_satisfies",
212 enabled,
213 Box::new(SemverSatisfiesFn::new()),
214 );
215 register_if_enabled(
216 runtime,
217 "semver_is_valid",
218 enabled,
219 Box::new(SemverIsValidFn::new()),
220 );
221}