aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/package/version
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-15 20:02:11 +0900
committernsfisis <nsfisis@gmail.com>2026-05-15 20:02:11 +0900
commitc7df5b68ef4bae43f9dfe51c1c8c766bbddffcc7 (patch)
tree954b12348512999a974d0e0d3b782c6187ba27e3 /crates/shirabe/src/package/version
parent73671d8aa6bc1d5a42fd0e7571f93dcde539cce9 (diff)
downloadphp-shirabe-c7df5b68ef4bae43f9dfe51c1c8c766bbddffcc7.tar.gz
php-shirabe-c7df5b68ef4bae43f9dfe51c1c8c766bbddffcc7.tar.zst
php-shirabe-c7df5b68ef4bae43f9dfe51c1c8c766bbddffcc7.zip
feat(port): port VersionBumper.php
Diffstat (limited to 'crates/shirabe/src/package/version')
-rw-r--r--crates/shirabe/src/package/version/version_bumper.rs115
1 files changed, 115 insertions, 0 deletions
diff --git a/crates/shirabe/src/package/version/version_bumper.rs b/crates/shirabe/src/package/version/version_bumper.rs
index 48c027e..8717d19 100644
--- a/crates/shirabe/src/package/version/version_bumper.rs
+++ b/crates/shirabe/src/package/version/version_bumper.rs
@@ -1 +1,116 @@
//! ref: composer/src/Composer/Package/Version/VersionBumper.php
+
+use anyhow::Result;
+use indexmap::IndexMap;
+use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_semver::constraint::constraint_interface::ConstraintInterface;
+use shirabe_semver::intervals::Intervals;
+use crate::package::dumper::array_dumper::ArrayDumper;
+use crate::package::loader::array_loader::ArrayLoader;
+use crate::package::package_interface::PackageInterface;
+use crate::package::version::version_parser::VersionParser;
+use crate::util::platform::Platform;
+
+#[derive(Debug)]
+pub struct VersionBumper;
+
+impl VersionBumper {
+ pub fn bump_requirement(
+ &self,
+ constraint: &dyn ConstraintInterface,
+ package: &dyn PackageInterface,
+ ) -> Result<String> {
+ let parser = VersionParser::new();
+ let pretty_constraint = constraint.get_pretty_string();
+ if pretty_constraint.starts_with("dev-") {
+ return Ok(pretty_constraint);
+ }
+
+ let mut version = package.get_version();
+ if package.get_version().starts_with("dev-") {
+ let loader = ArrayLoader::new(&parser);
+ let dumper = ArrayDumper::new();
+ let extra = loader.get_branch_alias(dumper.dump(package));
+
+ if extra.is_none() || extra.as_deref() == Some(VersionParser::DEFAULT_BRANCH_ALIAS) {
+ return Ok(pretty_constraint);
+ }
+
+ version = extra.unwrap();
+ }
+
+ let intervals = Intervals::get(constraint)?;
+
+ if !intervals.branches.names.is_empty() {
+ return Ok(pretty_constraint);
+ }
+
+ let major = Preg::replace(r"{^([1-9][0-9]*|0\.\d+).*}", "$1", version.clone())?;
+ let version_without_suffix = Preg::replace(r"{(?:\.(?:0|9999999))+(-dev)?$}", "", version.clone())?;
+ let new_pretty_constraint = format!("^{}", version_without_suffix);
+
+ if !Preg::is_match(r"{^\^\d+(\.\d+)*$}", &new_pretty_constraint)? {
+ return Ok(pretty_constraint);
+ }
+
+ let pattern = format!(
+ r#"{{
+ (?<=,|\ |\||^) # leading separator
+ (?P<constraint>
+ \^v?{major}(?:\.\d+)* # e.g. ^2.anything
+ | ~v?{major}(?:\.\d+){{1,3}} # e.g. ~2.2 or ~2.2.2 or ~2.2.2.2
+ | v?{major}(?:\.[*x])+ # e.g. 2.* or 2.*.* or 2.x.x.x etc
+ | >=v?\d(?:\.\d+)* # e.g. >=2 or >=1.2 etc
+ | \* # full wildcard
+ )
+ (?=,|$|\ |\||@) # trailing separator
+ }}x"#,
+ major = major
+ );
+
+ let mut matches: IndexMap<String, Vec<(String, i64)>> = IndexMap::new();
+ if Preg::is_match_all_with_offsets(&pattern, &pretty_constraint, &mut matches)? {
+ let mut modified = pretty_constraint.clone();
+ let constraint_matches = matches.get("constraint").cloned().unwrap_or_default();
+ for match_ in constraint_matches.iter().rev() {
+ let match_str = &match_.0;
+ let match_offset = match_.1;
+ let suffix = if match_str.matches('.').count() == 2
+ && version_without_suffix.matches('.').count() == 1
+ {
+ ".0"
+ } else {
+ ""
+ };
+ let replacement = if match_str.starts_with('~') && match_str.matches('.').count() != 1 {
+ let mut version_bits: Vec<String> =
+ version_without_suffix.split('.').map(String::from).collect();
+ let needed_len = match_str.matches('.').count() + 1;
+ while version_bits.len() < needed_len {
+ version_bits.push("0".to_string());
+ }
+ let dots_in_match = match_str.matches('.').count();
+ format!("~{}", version_bits[..dots_in_match + 1].join("."))
+ } else if match_str == "*" || match_str.starts_with(">=") {
+ format!(">={}{}", version_without_suffix, suffix)
+ } else {
+ format!("{}{}", new_pretty_constraint, suffix)
+ };
+ let offset = match_offset as usize;
+ let length = Platform::strlen(match_str) as usize;
+ modified = shirabe_php_shim::substr_replace(&modified, &replacement, offset, length);
+ }
+
+ let new_constraint = parser.parse_constraints(&modified)?;
+ if Intervals::is_subset_of(new_constraint.as_ref(), constraint)?
+ && Intervals::is_subset_of(constraint, new_constraint.as_ref())?
+ {
+ return Ok(pretty_constraint);
+ }
+
+ return Ok(modified);
+ }
+
+ Ok(pretty_constraint)
+ }
+}