1mod resolved_spec;
2mod spec_error;
3mod unresolved_parser;
4mod unresolved_spec;
5mod version_types;
6
7pub use resolved_spec::*;
8pub use spec_error::*;
9pub use unresolved_parser::*;
10pub use unresolved_spec::*;
11pub use version_types::*;
12
13use regex::Regex;
14use std::sync::OnceLock;
15
16pub fn is_alias_name<T: AsRef<str>>(value: T) -> bool {
22 let value = value.as_ref();
23
24 value.chars().enumerate().all(|(i, c)| {
25 if i == 0 {
26 char::is_ascii_alphabetic(&c)
27 } else {
28 char::is_ascii_alphanumeric(&c)
29 || c == '-'
30 || c == '_'
31 || c == '/'
32 || c == '.'
33 || c == '*'
34 }
35 })
36}
37
38pub fn is_calver<T: AsRef<str>>(value: T) -> bool {
40 get_calver_regex().is_match(value.as_ref())
41}
42
43pub fn is_semver<T: AsRef<str>>(value: T) -> bool {
45 get_semver_regex().is_match(value.as_ref())
46}
47
48pub fn clean_version_string<T: AsRef<str>>(value: T) -> String {
50 let mut version = value.as_ref().trim();
51
52 #[allow(clippy::assigning_clones)]
54 if (version.starts_with('v') || version.starts_with('V'))
55 && version.as_bytes()[1].is_ascii_digit()
56 {
57 version = &version[1..];
58 }
59
60 version.to_owned()
61}
62
63pub fn clean_version_req_string<T: AsRef<str>>(value: T) -> String {
66 value
67 .as_ref()
68 .trim()
69 .replace(".*", "")
70 .replace(".x", "")
71 .replace(".X", "")
72 .replace("-*", "")
73 .replace("&&", ",")
74}
75
76static CALVER_REGEX: OnceLock<Regex> = OnceLock::new();
77
78pub fn get_calver_regex() -> &'static Regex {
81 CALVER_REGEX.get_or_init(|| {
82 Regex::new(r"^(?<year>[0-9]{1,4})-(?<month>((0?[1-9]{1})|10|11|12))(-(?<day>(0?[1-9]{1}|[1-3]{1}[0-9]{1})))?((_|\.)(?<micro>[0-9]+))?(?<pre>-[a-zA-Z]{1}[-0-9a-zA-Z.]+)?$").unwrap()
83 })
84}
85
86static SEMVER_REGEX: OnceLock<Regex> = OnceLock::new();
87
88pub fn get_semver_regex() -> &'static Regex {
91 SEMVER_REGEX.get_or_init(|| {
93 Regex::new(r"^(?<major>[0-9]+).(?<minor>[0-9]+).(?<patch>[0-9]+)(?<pre>-[-0-9a-zA-Z.]+)?(?<build>\+[-0-9a-zA-Z.]+)?$")
94 .unwrap()
95 })
96}