aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-22 16:17:03 +0900
committernsfisis <nsfisis@gmail.com>2026-02-22 16:17:03 +0900
commit6490fe43676919bc1dcc8659ec4e52da225f92e6 (patch)
tree287d552b381112275cd9aa1fb1b0db67065ed973
parentbae2d1f87f6984b9e8929dc538d9c1d37a26e638 (diff)
downloadphp-mozart-6490fe43676919bc1dcc8659ec4e52da225f92e6.tar.gz
php-mozart-6490fe43676919bc1dcc8659ec4e52da225f92e6.tar.zst
php-mozart-6490fe43676919bc1dcc8659ec4e52da225f92e6.zip
fix(constraint): handle single pipe OR separator in version constraints
Composer uses `|` (single pipe) as the standard OR separator, but split_or() only recognized `||` (double pipe). This caused disjunctive constraints like `^6.0|^7.0|^8.0` to be parsed as only `^6.0`, breaking dependency resolution for packages like laravel/tinker. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
-rw-r--r--crates/mozart-constraint/src/lib.rs23
1 files changed, 19 insertions, 4 deletions
diff --git a/crates/mozart-constraint/src/lib.rs b/crates/mozart-constraint/src/lib.rs
index e41818c..7c417ec 100644
--- a/crates/mozart-constraint/src/lib.rs
+++ b/crates/mozart-constraint/src/lib.rs
@@ -365,23 +365,28 @@ impl VersionConstraint {
}
}
-/// Split on `||` (pipe-OR), but not inside version strings.
+/// Split on `|` or `||` (pipe-OR). Composer accepts both forms.
fn split_or(s: &str) -> Vec<&str> {
let mut parts = Vec::new();
let mut start = 0;
let bytes = s.as_bytes();
let mut i = 0;
while i < bytes.len() {
- if i + 1 < bytes.len() && bytes[i] == b'|' && bytes[i + 1] == b'|' {
+ if bytes[i] == b'|' {
parts.push(s[start..i].trim());
- i += 2;
+ i += 1;
+ // Skip second pipe if `||`
+ if i < bytes.len() && bytes[i] == b'|' {
+ i += 1;
+ }
start = i;
} else {
i += 1;
}
}
parts.push(s[start..].trim());
- parts
+ // Filter out empty parts (e.g. from leading/trailing pipes)
+ parts.into_iter().filter(|p| !p.is_empty()).collect()
}
/// Parse an AND group (space or comma separated constraints).
@@ -1605,6 +1610,16 @@ mod tests {
}
#[test]
+ fn test_single_pipe_or() {
+ // Single pipe `|` is the standard Composer OR separator
+ assert!(satisfies("^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "6.0.0"));
+ assert!(satisfies("^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "9.0.0"));
+ assert!(satisfies("^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "11.5.0"));
+ assert!(!satisfies("^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "5.9.9"));
+ assert!(!satisfies("^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "12.0.0"));
+ }
+
+ #[test]
fn test_combined_real_world_symfony_pattern() {
// ">=5.4 <7.0" — typical Symfony range
assert!(satisfies(">=5.4 <7.0", "5.4.0"));