From 6449a15de90fe8252fb288bd5eacb99dc2cd699a Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 4 May 2026 00:32:45 +0900 Subject: fix(compat): align repositories/version/platform parsing with Composer Three Composer-compat bugs surfaced by the github_issues_9290 fixture, fixed together since they form one resolution path: - RawPackageData.repositories now accepts a JSON object keyed by name, matching RepositoryFactory::createRepos which iterates either int- or string-keyed arrays via PHP foreach. - Version::parse fills every unspecified position of a `.x-dev` branch with 9999999, mirroring VersionParser::normalizeBranch. Previously `2.x-dev` parsed to 2.0.9999999.9999999-dev and failed to satisfy ^2.8. - is_platform_package limits the `php-` family to the closed set {64bit,ipv6,zts,debug} per PLATFORM_PACKAGE_REGEX. Vendor packages like `php-http/client-common` are no longer misclassified. Unblocks github_issues_7051, _8903, _9012, _9290. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/mozart-core/src/platform.rs | 43 ++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'crates/mozart-core/src/platform.rs') diff --git a/crates/mozart-core/src/platform.rs b/crates/mozart-core/src/platform.rs index 819d8c9..47ce2a0 100644 --- a/crates/mozart-core/src/platform.rs +++ b/crates/mozart-core/src/platform.rs @@ -16,17 +16,32 @@ pub struct PlatformPackage { /// Returns true if the package name is a Composer platform package. /// -/// Platform packages include: php, php-*, ext-*, lib-*, composer, -/// composer-plugin-api, composer-runtime-api. +/// Mirrors `Composer\Repository\PlatformRepository::PLATFORM_PACKAGE_REGEX`: +/// `php`, `php-64bit`, `php-ipv6`, `php-zts`, `php-debug`, `hhvm`, +/// `ext-`, `lib-`, `composer`, `composer-plugin-api`, +/// `composer-runtime-api`. The `php-` family is a closed set, NOT a wildcard +/// — `php-http/client-common` is a regular vendor package, not a platform +/// requirement. pub fn is_platform_package(name: &str) -> bool { let lower = name.to_lowercase(); - lower == "php" - || lower.starts_with("php-") - || lower.starts_with("ext-") - || lower.starts_with("lib-") - || lower == "composer" - || lower == "composer-plugin-api" - || lower == "composer-runtime-api" + match lower.as_str() { + "php" + | "php-64bit" + | "php-ipv6" + | "php-zts" + | "php-debug" + | "hhvm" + | "composer" + | "composer-plugin-api" + | "composer-runtime-api" => true, + _ => { + (lower.starts_with("ext-") || lower.starts_with("lib-")) + && lower[4..] + .chars() + .next() + .is_some_and(|c| c.is_ascii_alphanumeric()) + } + } } // ─── Detection ─────────────────────────────────────────────────────────────── @@ -377,6 +392,16 @@ mod tests { assert!(!is_platform_package("vendor/package")); } + #[test] + fn test_is_platform_package_php_prefix_vendor() { + // Vendor packages whose names happen to start with "php-" are NOT + // platform packages. Composer's PLATFORM_PACKAGE_REGEX limits the + // `php-` family to a closed set of suffixes (64bit/ipv6/zts/debug). + assert!(!is_platform_package("php-http/client-common")); + assert!(!is_platform_package("php-http/httplug")); + assert!(!is_platform_package("php-amqplib/php-amqplib")); + } + #[test] fn test_parse_platform_info_basic() { let output = "PHP_VERSION:8.2.1\nPHP_INT_SIZE:8\nPHP_DEBUG:0\nPHP_ZTS:0\nIPV6:1\nEXTENSIONS:\njson:8.2.1\nctype:8.2.1\n"; -- cgit v1.3.1