aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart-core/src
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-03 12:25:45 +0900
committernsfisis <nsfisis@gmail.com>2026-05-03 12:25:45 +0900
commitab2772b8c85139df7d5e625ac5262d385e5ab4c0 (patch)
treeca2bbabecdb6068cbf646153d959c72edddec933 /crates/mozart-core/src
parent7badb54195131da9c3561c351138c0ba083e38e4 (diff)
downloadphp-mozart-ab2772b8c85139df7d5e625ac5262d385e5ab4c0.tar.gz
php-mozart-ab2772b8c85139df7d5e625ac5262d385e5ab4c0.tar.zst
php-mozart-ab2772b8c85139df7d5e625ac5262d385e5ab4c0.zip
fix(resolver): seed root package into pool as fixed entry
Composer's RootPackageRepository puts a clone of the root package into the pool as a fixed entry — its `require` / `require-dev` cleared, but its name, version, provides, and replaces preserved. That way a transitive `require` pointing back at the root resolves through the pool the same way any other reference would, and legal circular dependencies (root requires A, A requires root) work. Mozart had no such seed: the rule generator only knew about the root through the explicit root-require / root-provide / root-replace tables, so a transitive consumer requiring the root by name failed with no provider. Plumb root_version through ResolveRequest (RawPackageData gains a matching `Option<String>` field), build a fixed PoolPackageInput for the root with provides/replaces lifted from request.root_provide / root_replace, and skip the root by name when collecting the resolver's output so it doesn't leak into the lock file. Falls back to `1.0.0+no-version-set` (Composer's RootPackage::DEFAULT_PRETTY_VERSION) when the root composer.json omits `version`. Unblocks circular_dependency2, conflict_against_replaced_package_problem, and provider_conflicts installer fixtures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/mozart-core/src')
-rw-r--r--crates/mozart-core/src/package.rs8
1 files changed, 8 insertions, 0 deletions
diff --git a/crates/mozart-core/src/package.rs b/crates/mozart-core/src/package.rs
index 02ec935..8bda13d 100644
--- a/crates/mozart-core/src/package.rs
+++ b/crates/mozart-core/src/package.rs
@@ -461,6 +461,13 @@ pub struct RawPackageData {
#[serde(default = "default_root_package_name")]
pub name: String,
+ /// Root project's version, when explicitly set. Composer falls back to
+ /// `1.0.0+no-version-set` when this is missing; we keep the raw `Option`
+ /// here and let the resolver apply that default so the in-memory shape
+ /// stays close to the JSON input.
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub version: Option<String>,
+
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
@@ -554,6 +561,7 @@ impl RawPackageData {
pub fn new(name: String) -> Self {
Self {
name,
+ version: None,
description: None,
package_type: None,
homepage: None,