diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-22 16:17:03 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-22 16:17:03 +0900 |
| commit | 6490fe43676919bc1dcc8659ec4e52da225f92e6 (patch) | |
| tree | 287d552b381112275cd9aa1fb1b0db67065ed973 | |
| parent | bae2d1f87f6984b9e8929dc538d9c1d37a26e638 (diff) | |
| download | php-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.rs | 23 |
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")); |
