aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-semver
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-16 23:36:37 +0900
committernsfisis <nsfisis@gmail.com>2026-05-16 23:36:37 +0900
commitbeecbec6becfaaabcffd5bd9c596c055e64778c1 (patch)
tree17774fb0c7ed2b45b72a11b53040862d1c3094af /crates/shirabe-semver
parentc1b57fb510961e02134df4883327155199d73087 (diff)
downloadphp-shirabe-beecbec6becfaaabcffd5bd9c596c055e64778c1.tar.gz
php-shirabe-beecbec6becfaaabcffd5bd9c596c055e64778c1.tar.zst
php-shirabe-beecbec6becfaaabcffd5bd9c596c055e64778c1.zip
feat(port): port Semver.php
Diffstat (limited to 'crates/shirabe-semver')
-rw-r--r--crates/shirabe-semver/src/semver.rs74
1 files changed, 74 insertions, 0 deletions
diff --git a/crates/shirabe-semver/src/semver.rs b/crates/shirabe-semver/src/semver.rs
index 2d26366..8fecf27 100644
--- a/crates/shirabe-semver/src/semver.rs
+++ b/crates/shirabe-semver/src/semver.rs
@@ -1 +1,75 @@
//! ref: composer/vendor/composer/semver/src/Semver.php
+
+use std::sync::OnceLock;
+
+use crate::comparator::Comparator;
+use crate::constraint::constraint::Constraint;
+use crate::version_parser::VersionParser;
+
+pub struct Semver;
+
+impl Semver {
+ pub const SORT_ASC: i64 = 1;
+ pub const SORT_DESC: i64 = -1;
+
+ fn version_parser() -> &'static VersionParser {
+ static VERSION_PARSER: OnceLock<VersionParser> = OnceLock::new();
+ VERSION_PARSER.get_or_init(VersionParser::new)
+ }
+
+ pub fn satisfies(version: String, constraints: String) -> anyhow::Result<bool> {
+ let version_parser = Self::version_parser();
+ let provider = Constraint::new("==".to_string(), version_parser.normalize(version)?);
+ let parsed_constraints = version_parser.parse_constraints(constraints)?;
+ Ok(parsed_constraints.matches(&provider))
+ }
+
+ pub fn satisfied_by(versions: Vec<String>, constraints: String) -> anyhow::Result<Vec<String>> {
+ let mut result = Vec::new();
+ for version in versions.iter() {
+ if Self::satisfies(version.clone(), constraints.clone())? {
+ result.push(version.clone());
+ }
+ }
+ Ok(result)
+ }
+
+ pub fn sort(versions: Vec<String>) -> anyhow::Result<Vec<String>> {
+ Self::usort(versions, Self::SORT_ASC)
+ }
+
+ pub fn rsort(versions: Vec<String>) -> anyhow::Result<Vec<String>> {
+ Self::usort(versions, Self::SORT_DESC)
+ }
+
+ fn usort(versions: Vec<String>, direction: i64) -> anyhow::Result<Vec<String>> {
+ let version_parser = Self::version_parser();
+
+ let mut normalized: Vec<(String, usize)> = versions
+ .iter()
+ .enumerate()
+ .map(|(key, version)| -> anyhow::Result<(String, usize)> {
+ let normalized_version = version_parser.normalize(version.clone())?;
+ let normalized_version =
+ version_parser.normalize_default_branch(normalized_version);
+ Ok((normalized_version, key))
+ })
+ .collect::<anyhow::Result<Vec<_>>>()?;
+
+ normalized.sort_by(|left, right| {
+ if left.0 == right.0 {
+ return std::cmp::Ordering::Equal;
+ }
+ let is_less = Comparator::less_than(left.0.clone(), right.0.clone());
+ let cmp_value = if is_less { -direction } else { direction };
+ cmp_value.cmp(&0)
+ });
+
+ let sorted: Vec<String> = normalized
+ .into_iter()
+ .map(|(_, key)| versions[key].clone())
+ .collect();
+
+ Ok(sorted)
+ }
+}