aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-11 02:05:34 +0900
committernsfisis <nsfisis@gmail.com>2026-05-11 02:05:34 +0900
commit4df5f8491320e5795718cf0222e80fa27e57c8ad (patch)
tree707e19f34dbdef18490ec3245d34389e3d189a57 /crates
parent8871b923fa3df1935c263db155cb8bc3d59705cd (diff)
downloadphp-mozart-4df5f8491320e5795718cf0222e80fa27e57c8ad.tar.gz
php-mozart-4df5f8491320e5795718cf0222e80fa27e57c8ad.tar.zst
php-mozart-4df5f8491320e5795718cf0222e80fa27e57c8ad.zip
refactor(package): rename traits and switch dep maps to IndexMap
Rename Package/CompletePackage to PackageInterface/CompletePackageInterface to mirror Composer's interface names, and split each into its own module under crates/mozart-core/src/package/. Switch dependency-link and metadata maps from BTreeMap to indexmap::IndexMap so serialized JSON preserves the original key ordering rather than sorting alphabetically — matching PHP associative-array semantics. The --sort-packages behaviour in `require` is preserved via sort_unstable_keys.
Diffstat (limited to 'crates')
-rw-r--r--crates/mozart-class-map-generator/Cargo.toml1
-rw-r--r--crates/mozart-class-map-generator/src/classmap.rs12
-rw-r--r--crates/mozart-core/src/autoload.rs66
-rw-r--r--crates/mozart-core/src/installer/installed_repo.rs9
-rw-r--r--crates/mozart-core/src/package.rs252
-rw-r--r--crates/mozart-core/src/package/complete_package_interface.rs17
-rw-r--r--crates/mozart-core/src/package/package_interface.rs33
-rw-r--r--crates/mozart-core/src/repository/browse_repos.rs19
-rw-r--r--crates/mozart-core/src/repository/installed.rs5
-rw-r--r--crates/mozart-core/src/repository/lockfile.rs160
-rw-r--r--crates/mozart-core/src/repository/packagist.rs20
-rw-r--r--crates/mozart-core/src/repository/vcs_bridge.rs3
-rw-r--r--crates/mozart-core/src/repository_utils.rs19
-rw-r--r--crates/mozart/src/commands/audit.rs44
-rw-r--r--crates/mozart/src/commands/browse.rs2
-rw-r--r--crates/mozart/src/commands/bump.rs16
-rw-r--r--crates/mozart/src/commands/check_platform_reqs.rs89
-rw-r--r--crates/mozart/src/commands/dependency.rs27
-rw-r--r--crates/mozart/src/commands/diagnose.rs2
-rw-r--r--crates/mozart/src/commands/exec.rs2
-rw-r--r--crates/mozart/src/commands/init.rs10
-rw-r--r--crates/mozart/src/commands/install.rs51
-rw-r--r--crates/mozart/src/commands/licenses.rs46
-rw-r--r--crates/mozart/src/commands/remove.rs43
-rw-r--r--crates/mozart/src/commands/require.rs52
-rw-r--r--crates/mozart/src/commands/show.rs28
-rw-r--r--crates/mozart/src/commands/suggests.rs39
-rw-r--r--crates/mozart/src/commands/update.rs13
-rw-r--r--crates/mozart/src/factory.rs2
29 files changed, 529 insertions, 553 deletions
diff --git a/crates/mozart-class-map-generator/Cargo.toml b/crates/mozart-class-map-generator/Cargo.toml
index 465b26c..e1bd1a3 100644
--- a/crates/mozart-class-map-generator/Cargo.toml
+++ b/crates/mozart-class-map-generator/Cargo.toml
@@ -5,6 +5,7 @@ edition.workspace = true
[dependencies]
anyhow.workspace = true
+indexmap.workspace = true
regex.workspace = true
[dev-dependencies]
diff --git a/crates/mozart-class-map-generator/src/classmap.rs b/crates/mozart-class-map-generator/src/classmap.rs
index e1631f4..17ca04a 100644
--- a/crates/mozart-class-map-generator/src/classmap.rs
+++ b/crates/mozart-class-map-generator/src/classmap.rs
@@ -133,18 +133,18 @@ pub fn path_to_static_expr(file: &Path, vendor_dir: &Path, project_dir: &Path) -
///
/// Returns `(dynamic_classmap, static_classmap, psr_violations)`.
pub fn scan_psr_for_classmap(
- psr4: &BTreeMap<String, Vec<String>>,
- psr0: &BTreeMap<String, Vec<String>>,
+ psr4: &indexmap::IndexMap<String, Vec<String>>,
+ psr0: &indexmap::IndexMap<String, Vec<String>>,
vendor_dir: &Path,
project_dir: &Path,
excluded: &[String],
) -> (
- BTreeMap<String, String>,
- BTreeMap<String, String>,
+ indexmap::IndexMap<String, String>,
+ indexmap::IndexMap<String, String>,
Vec<String>,
) {
- let mut dyn_map: BTreeMap<String, String> = BTreeMap::new();
- let mut static_map: BTreeMap<String, String> = BTreeMap::new();
+ let mut dyn_map = indexmap::IndexMap::new();
+ let mut static_map = indexmap::IndexMap::new();
let mut violations: Vec<String> = Vec::new();
// Helper: resolve a PHP path expression to an absolute path.
diff --git a/crates/mozart-core/src/autoload.rs b/crates/mozart-core/src/autoload.rs
index 7e8ead6..08a2859 100644
--- a/crates/mozart-core/src/autoload.rs
+++ b/crates/mozart-core/src/autoload.rs
@@ -8,7 +8,6 @@ use crate::repository::installed::InstalledPackages;
use crate::repository::lockfile::LockedPackage;
use indexmap::IndexSet;
use mozart_class_map_generator::{scan_classmap_dirs, scan_psr_for_classmap};
-use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
// Embed Composer PHP files from the submodule at compile time.
@@ -70,15 +69,15 @@ pub struct AutoloadConfig {
pub struct AutoloadData {
/// PSR-4: namespace prefix -> list of directory path expressions.
/// Each path is a PHP expression string like `$vendorDir . '/psr/log/src'`.
- pub psr4: BTreeMap<String, Vec<String>>,
+ pub psr4: indexmap::IndexMap<String, Vec<String>>,
/// PSR-0: namespace prefix -> list of directory path expressions.
/// (Empty in Phase 2.2, populated in 5.6.)
- pub psr0: BTreeMap<String, Vec<String>>,
+ pub psr0: indexmap::IndexMap<String, Vec<String>>,
/// Classmap entries: class name -> file path expression.
/// (Empty in Phase 2.2, populated in 5.6.)
- pub classmap: BTreeMap<String, String>,
+ pub classmap: indexmap::IndexMap<String, String>,
/// Files to include on every request: file_identifier -> path expression.
- pub files: BTreeMap<String, String>,
+ pub files: indexmap::IndexMap<String, String>,
}
/// Mirror of `Composer\ClassMapGenerator\ClassMap` — the return value
@@ -92,9 +91,9 @@ pub struct AutoloadData {
/// summary — once `generate` is refactored to expose the full classmap
/// these fields will hold the real entries.
pub struct ClassMap {
- map: BTreeMap<String, String>,
+ map: indexmap::IndexMap<String, String>,
psr_violations: Vec<String>,
- ambiguous_classes: BTreeMap<String, Vec<String>>,
+ ambiguous_classes: indexmap::IndexMap<String, Vec<String>>,
}
impl ClassMap {
@@ -126,7 +125,7 @@ impl ClassMap {
}
/// Read access to the underlying map (`getMap()` upstream).
- pub fn map(&self) -> &BTreeMap<String, String> {
+ pub fn map(&self) -> &indexmap::IndexMap<String, String> {
&self.map
}
@@ -136,7 +135,7 @@ impl ClassMap {
}
/// Read access to the ambiguous-class records.
- pub fn ambiguous_classes(&self) -> &BTreeMap<String, Vec<String>> {
+ pub fn ambiguous_classes(&self) -> &indexmap::IndexMap<String, Vec<String>> {
&self.ambiguous_classes
}
}
@@ -282,9 +281,9 @@ impl AutoloadGeneratorExt for AutoloadGenerator {
// for now and surface the limitation here rather than
// silently writing files.
return Ok(ClassMap {
- map: BTreeMap::new(),
+ map: indexmap::IndexMap::new(),
psr_violations: Vec::new(),
- ambiguous_classes: BTreeMap::new(),
+ ambiguous_classes: indexmap::IndexMap::new(),
});
}
@@ -297,7 +296,7 @@ impl AutoloadGeneratorExt for AutoloadGenerator {
// command code that only branches on `count()` / `has_*()` works
// today; refactoring `generate` to surface the full map is
// tracked as follow-up work.
- let mut map = BTreeMap::new();
+ let mut map = indexmap::IndexMap::new();
for i in 0..result.class_count {
map.insert(format!("__mozart_placeholder_{i}"), String::new());
}
@@ -308,7 +307,7 @@ impl AutoloadGeneratorExt for AutoloadGenerator {
} else {
Vec::new()
};
- let mut ambiguous_classes = BTreeMap::new();
+ let mut ambiguous_classes = indexmap::IndexMap::new();
if result.has_ambiguous_classes {
ambiguous_classes.insert("__mozart_placeholder".to_string(), Vec::new());
}
@@ -526,16 +525,16 @@ fn collect_autoloads(
dev_mode: bool,
) -> (AutoloadData, AutoloadData) {
let mut data = AutoloadData {
- psr4: BTreeMap::new(),
- psr0: BTreeMap::new(),
- classmap: BTreeMap::new(),
- files: BTreeMap::new(),
+ psr4: indexmap::IndexMap::new(),
+ psr0: indexmap::IndexMap::new(),
+ classmap: indexmap::IndexMap::new(),
+ files: indexmap::IndexMap::new(),
};
let mut static_data = AutoloadData {
- psr4: BTreeMap::new(),
- psr0: BTreeMap::new(),
- classmap: BTreeMap::new(),
- files: BTreeMap::new(),
+ psr4: indexmap::IndexMap::new(),
+ psr0: indexmap::IndexMap::new(),
+ classmap: indexmap::IndexMap::new(),
+ files: indexmap::IndexMap::new(),
};
// Process each installed package
@@ -703,7 +702,7 @@ fn generate_autoload_static(static_data: &AutoloadData, suffix: &str) -> String
// $prefixLengthsPsr4 — group by first character of namespace
if !static_data.psr4.is_empty() {
// Group namespaces by first character, sorted reverse
- let mut by_char: BTreeMap<char, Vec<(&String, usize)>> = BTreeMap::new();
+ let mut by_char: indexmap::IndexMap<_, Vec<_>> = indexmap::IndexMap::new();
let mut sorted_ns: Vec<&String> = static_data.psr4.keys().collect();
sorted_ns.sort_by(|a, b| b.cmp(a));
@@ -1278,11 +1277,11 @@ pub fn generate(config: &AutoloadConfig) -> anyhow::Result<GenerateResult> {
version_normalized: p.version_normalized.clone(),
source: None,
dist: None,
- require: std::collections::BTreeMap::new(),
- require_dev: std::collections::BTreeMap::new(),
- conflict: std::collections::BTreeMap::new(),
- provide: std::collections::BTreeMap::new(),
- replace: std::collections::BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: p.package_type.clone(),
autoload: p.autoload.clone(),
@@ -1295,7 +1294,7 @@ pub fn generate(config: &AutoloadConfig) -> anyhow::Result<GenerateResult> {
support: None,
funding: None,
time: None,
- extra_fields: std::collections::BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
})
.collect()
};
@@ -1370,7 +1369,6 @@ pub fn generate(config: &AutoloadConfig) -> anyhow::Result<GenerateResult> {
mod tests {
use super::*;
use crate::repository::installed::{InstalledPackageEntry, InstalledPackages};
- use std::collections::BTreeMap;
use tempfile::tempdir;
fn make_installed_pkg(name: &str, version: &str) -> InstalledPackageEntry {
@@ -1386,7 +1384,7 @@ mod tests {
aliases: vec![],
homepage: None,
support: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
@@ -1589,10 +1587,10 @@ mod tests {
#[test]
fn test_generate_autoload_psr4_empty() {
let data = AutoloadData {
- psr4: BTreeMap::new(),
- psr0: BTreeMap::new(),
- classmap: BTreeMap::new(),
- files: BTreeMap::new(),
+ psr4: indexmap::IndexMap::new(),
+ psr0: indexmap::IndexMap::new(),
+ classmap: indexmap::IndexMap::new(),
+ files: indexmap::IndexMap::new(),
};
let output = generate_autoload_psr4(&data);
assert!(output.contains("return array(\n);"));
diff --git a/crates/mozart-core/src/installer/installed_repo.rs b/crates/mozart-core/src/installer/installed_repo.rs
index 8361158..d7e4f83 100644
--- a/crates/mozart-core/src/installer/installed_repo.rs
+++ b/crates/mozart-core/src/installer/installed_repo.rs
@@ -17,7 +17,6 @@
//! or through a `provide` / `replace` link.
use indexmap::IndexSet;
-use std::collections::BTreeMap;
/// One installed package, in the shape `findPackagesWithReplacersAndProviders`
/// needs. Mirrors the fields of `Composer\Package\PackageInterface` that the
@@ -33,9 +32,9 @@ pub struct InstalledCandidate {
/// Original-case version, used in user-facing output.
pub pretty_version: String,
/// `provide` map: target package name → constraint string.
- pub provides: BTreeMap<String, String>,
+ pub provides: indexmap::IndexMap<String, String>,
/// `replace` map: target package name → constraint string.
- pub replaces: BTreeMap<String, String>,
+ pub replaces: indexmap::IndexMap<String, String>,
}
#[derive(Debug, Clone, Default)]
@@ -106,8 +105,8 @@ mod tests {
pretty_name: name.to_string(),
version: version.to_string(),
pretty_version: version.to_string(),
- provides: BTreeMap::new(),
- replaces: BTreeMap::new(),
+ provides: indexmap::IndexMap::new(),
+ replaces: indexmap::IndexMap::new(),
}
}
diff --git a/crates/mozart-core/src/package.rs b/crates/mozart-core/src/package.rs
index c6a3ae9..de88ffc 100644
--- a/crates/mozart-core/src/package.rs
+++ b/crates/mozart-core/src/package.rs
@@ -1,14 +1,18 @@
use serde::de::{Deserializer, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Serialize};
-use std::collections::BTreeMap;
use std::fmt;
use std::fs;
use std::path::Path;
pub mod archiver;
+mod complete_package_interface;
pub mod dumper;
+mod package_interface;
pub mod version;
+pub use complete_package_interface::*;
+pub use package_interface::*;
+
/// Package stability level.
/// Higher value = less stable.
/// Corresponds to `Composer\Package\BasePackage::STABILITY_*`.
@@ -62,8 +66,8 @@ pub struct Author {
/// Autoload rule sets (PSR-4, PSR-0, classmap, files).
#[derive(Debug, Clone, Default)]
pub struct AutoloadRules {
- pub psr4: BTreeMap<String, Vec<String>>,
- pub psr0: BTreeMap<String, Vec<String>>,
+ pub psr4: indexmap::IndexMap<String, Vec<String>>,
+ pub psr0: indexmap::IndexMap<String, Vec<String>>,
pub classmap: Vec<String>,
pub files: Vec<String>,
}
@@ -125,19 +129,19 @@ pub struct PackageData {
pub dist_sha1_checksum: Option<String>,
pub release_date: Option<String>,
- pub extra: BTreeMap<String, serde_json::Value>,
+ pub extra: indexmap::IndexMap<String, serde_json::Value>,
pub binaries: Vec<String>,
pub dev: bool,
pub stability: Stability,
pub notification_url: Option<String>,
// dependency links
- pub requires: BTreeMap<String, Link>,
- pub conflicts: BTreeMap<String, Link>,
- pub provides: BTreeMap<String, Link>,
- pub replaces: BTreeMap<String, Link>,
- pub dev_requires: BTreeMap<String, Link>,
- pub suggests: BTreeMap<String, String>,
+ pub requires: indexmap::IndexMap<String, Link>,
+ pub conflicts: indexmap::IndexMap<String, Link>,
+ pub provides: indexmap::IndexMap<String, Link>,
+ pub replaces: indexmap::IndexMap<String, Link>,
+ pub dev_requires: indexmap::IndexMap<String, Link>,
+ pub suggests: indexmap::IndexMap<String, String>,
// autoload
pub autoload: AutoloadRules,
@@ -157,7 +161,7 @@ pub struct CompletePackageData {
pub license: Vec<String>,
pub keywords: Vec<String>,
pub authors: Vec<Author>,
- pub scripts: BTreeMap<String, Vec<String>>,
+ pub scripts: indexmap::IndexMap<String, Vec<String>>,
pub support: Support,
pub funding: Vec<Funding>,
pub repositories: Vec<serde_json::Value>,
@@ -175,105 +179,55 @@ pub struct RootPackageData {
pub minimum_stability: Stability,
pub prefer_stable: bool,
- pub stability_flags: BTreeMap<String, Stability>,
- pub config: BTreeMap<String, serde_json::Value>,
- pub references: BTreeMap<String, String>,
+ pub stability_flags: indexmap::IndexMap<String, Stability>,
+ pub config: indexmap::IndexMap<String, serde_json::Value>,
+ pub references: indexmap::IndexMap<String, String>,
pub aliases: Vec<VersionAlias>,
}
-/// Accessor for `PackageData` fields.
-/// Corresponds to `Composer\Package\PackageInterface`.
-pub trait Package {
- fn name(&self) -> &str;
- fn pretty_name(&self) -> &str;
- fn version(&self) -> &str;
- fn pretty_version(&self) -> &str;
- fn package_type(&self) -> &str;
- fn target_dir(&self) -> Option<&str>;
- fn source_type(&self) -> Option<&str>;
- fn source_url(&self) -> Option<&str>;
- fn source_reference(&self) -> Option<&str>;
- fn dist_type(&self) -> Option<&str>;
- fn dist_url(&self) -> Option<&str>;
- fn dist_reference(&self) -> Option<&str>;
- fn dist_sha1_checksum(&self) -> Option<&str>;
- fn release_date(&self) -> Option<&str>;
- fn extra(&self) -> &BTreeMap<String, serde_json::Value>;
- fn binaries(&self) -> &[String];
- fn is_dev(&self) -> bool;
- fn stability(&self) -> Stability;
- fn notification_url(&self) -> Option<&str>;
- fn requires(&self) -> &BTreeMap<String, Link>;
- fn conflicts(&self) -> &BTreeMap<String, Link>;
- fn provides(&self) -> &BTreeMap<String, Link>;
- fn replaces(&self) -> &BTreeMap<String, Link>;
- fn dev_requires(&self) -> &BTreeMap<String, Link>;
- fn suggests(&self) -> &BTreeMap<String, String>;
- fn autoload(&self) -> &AutoloadRules;
- fn dev_autoload(&self) -> &AutoloadRules;
- fn is_default_branch(&self) -> bool;
-}
-
-/// Accessor for `CompletePackageData` fields.
-/// Corresponds to `Composer\Package\CompletePackageInterface`.
-pub trait CompletePackage: Package {
- fn description(&self) -> Option<&str>;
- fn homepage(&self) -> Option<&str>;
- fn license(&self) -> &[String];
- fn keywords(&self) -> &[String];
- fn authors(&self) -> &[Author];
- fn scripts(&self) -> &BTreeMap<String, Vec<String>>;
- fn support(&self) -> &Support;
- fn funding(&self) -> &[Funding];
- fn repositories(&self) -> &[serde_json::Value];
- fn abandoned(&self) -> Option<&str>;
- fn archive_name(&self) -> Option<&str>;
- fn archive_excludes(&self) -> &[String];
-}
-
/// Accessor for `RootPackageData` fields.
/// Corresponds to `Composer\Package\RootPackageInterface`.
-pub trait RootPackage: CompletePackage {
+pub trait RootPackage: CompletePackageInterface {
fn minimum_stability(&self) -> Stability;
fn prefer_stable(&self) -> bool;
- fn stability_flags(&self) -> &BTreeMap<String, Stability>;
- fn config(&self) -> &BTreeMap<String, serde_json::Value>;
- fn references(&self) -> &BTreeMap<String, String>;
+ fn stability_flags(&self) -> &indexmap::IndexMap<String, Stability>;
+ fn config(&self) -> &indexmap::IndexMap<String, serde_json::Value>;
+ fn references(&self) -> &indexmap::IndexMap<String, String>;
fn aliases(&self) -> &[VersionAlias];
}
/// Implements `Package` trait by delegating to an inner `PackageData` field.
macro_rules! delegate_package {
($type:ty => $($path:ident).+) => {
- impl Package for $type {
- fn name(&self) -> &str { &self.$($path).+.name }
- fn pretty_name(&self) -> &str { &self.$($path).+.pretty_name }
- fn version(&self) -> &str { &self.$($path).+.version }
- fn pretty_version(&self) -> &str { &self.$($path).+.pretty_version }
- fn package_type(&self) -> &str { &self.$($path).+.package_type }
- fn target_dir(&self) -> Option<&str> { self.$($path).+.target_dir.as_deref() }
- fn source_type(&self) -> Option<&str> { self.$($path).+.source_type.as_deref() }
- fn source_url(&self) -> Option<&str> { self.$($path).+.source_url.as_deref() }
- fn source_reference(&self) -> Option<&str> { self.$($path).+.source_reference.as_deref() }
- fn dist_type(&self) -> Option<&str> { self.$($path).+.dist_type.as_deref() }
- fn dist_url(&self) -> Option<&str> { self.$($path).+.dist_url.as_deref() }
- fn dist_reference(&self) -> Option<&str> { self.$($path).+.dist_reference.as_deref() }
- fn dist_sha1_checksum(&self) -> Option<&str> { self.$($path).+.dist_sha1_checksum.as_deref() }
- fn release_date(&self) -> Option<&str> { self.$($path).+.release_date.as_deref() }
- fn extra(&self) -> &BTreeMap<String, serde_json::Value> { &self.$($path).+.extra }
- fn binaries(&self) -> &[String] { &self.$($path).+.binaries }
- fn is_dev(&self) -> bool { self.$($path).+.dev }
- fn stability(&self) -> Stability { self.$($path).+.stability }
- fn notification_url(&self) -> Option<&str> { self.$($path).+.notification_url.as_deref() }
- fn requires(&self) -> &BTreeMap<String, Link> { &self.$($path).+.requires }
- fn conflicts(&self) -> &BTreeMap<String, Link> { &self.$($path).+.conflicts }
- fn provides(&self) -> &BTreeMap<String, Link> { &self.$($path).+.provides }
- fn replaces(&self) -> &BTreeMap<String, Link> { &self.$($path).+.replaces }
- fn dev_requires(&self) -> &BTreeMap<String, Link> { &self.$($path).+.dev_requires }
- fn suggests(&self) -> &BTreeMap<String, String> { &self.$($path).+.suggests }
- fn autoload(&self) -> &AutoloadRules { &self.$($path).+.autoload }
- fn dev_autoload(&self) -> &AutoloadRules { &self.$($path).+.dev_autoload }
- fn is_default_branch(&self) -> bool { self.$($path).+.is_default_branch }
+ impl PackageInterface for $type {
+ fn name(&self) -> &str { &self.$($path).+.name }
+ fn pretty_name(&self) -> &str { &self.$($path).+.pretty_name }
+ fn version(&self) -> &str { &self.$($path).+.version }
+ fn pretty_version(&self) -> &str { &self.$($path).+.pretty_version }
+ fn package_type(&self) -> &str { &self.$($path).+.package_type }
+ fn target_dir(&self) -> Option<&str> { self.$($path).+.target_dir.as_deref() }
+ fn source_type(&self) -> Option<&str> { self.$($path).+.source_type.as_deref() }
+ fn source_url(&self) -> Option<&str> { self.$($path).+.source_url.as_deref() }
+ fn source_reference(&self) -> Option<&str> { self.$($path).+.source_reference.as_deref() }
+ fn dist_type(&self) -> Option<&str> { self.$($path).+.dist_type.as_deref() }
+ fn dist_url(&self) -> Option<&str> { self.$($path).+.dist_url.as_deref() }
+ fn dist_reference(&self) -> Option<&str> { self.$($path).+.dist_reference.as_deref() }
+ fn dist_sha1_checksum(&self) -> Option<&str> { self.$($path).+.dist_sha1_checksum.as_deref() }
+ fn release_date(&self) -> Option<&str> { self.$($path).+.release_date.as_deref() }
+ fn extra(&self) -> &indexmap::IndexMap<String, serde_json::Value> { &self.$($path).+.extra }
+ fn binaries(&self) -> &[String] { &self.$($path).+.binaries }
+ fn is_dev(&self) -> bool { self.$($path).+.dev }
+ fn stability(&self) -> Stability { self.$($path).+.stability }
+ fn notification_url(&self) -> Option<&str> { self.$($path).+.notification_url.as_deref() }
+ fn requires(&self) -> &indexmap::IndexMap<String, Link> { &self.$($path).+.requires }
+ fn conflicts(&self) -> &indexmap::IndexMap<String, Link> { &self.$($path).+.conflicts }
+ fn provides(&self) -> &indexmap::IndexMap<String, Link> { &self.$($path).+.provides }
+ fn replaces(&self) -> &indexmap::IndexMap<String, Link> { &self.$($path).+.replaces }
+ fn dev_requires(&self) -> &indexmap::IndexMap<String, Link> { &self.$($path).+.dev_requires }
+ fn suggests(&self) -> &indexmap::IndexMap<String, String> { &self.$($path).+.suggests }
+ fn autoload(&self) -> &AutoloadRules { &self.$($path).+.autoload }
+ fn dev_autoload(&self) -> &AutoloadRules { &self.$($path).+.dev_autoload }
+ fn is_default_branch(&self) -> bool { self.$($path).+.is_default_branch }
}
};
}
@@ -281,24 +235,24 @@ macro_rules! delegate_package {
/// Implements `CompletePackage` trait by delegating to an inner `CompletePackageData` field.
macro_rules! delegate_complete_package {
($type:ty => $($path:ident).+) => {
- impl CompletePackage for $type {
- fn description(&self) -> Option<&str> { self.$($path).+.description.as_deref() }
- fn homepage(&self) -> Option<&str> { self.$($path).+.homepage.as_deref() }
- fn license(&self) -> &[String] { &self.$($path).+.license }
- fn keywords(&self) -> &[String] { &self.$($path).+.keywords }
- fn authors(&self) -> &[Author] { &self.$($path).+.authors }
- fn scripts(&self) -> &BTreeMap<String, Vec<String>> { &self.$($path).+.scripts }
- fn support(&self) -> &Support { &self.$($path).+.support }
- fn funding(&self) -> &[Funding] { &self.$($path).+.funding }
- fn repositories(&self) -> &[serde_json::Value] { &self.$($path).+.repositories }
- fn abandoned(&self) -> Option<&str> { self.$($path).+.abandoned.as_deref() }
- fn archive_name(&self) -> Option<&str> { self.$($path).+.archive_name.as_deref() }
- fn archive_excludes(&self) -> &[String] { &self.$($path).+.archive_excludes }
+ impl CompletePackageInterface for $type {
+ fn description(&self) -> Option<&str> { self.$($path).+.description.as_deref() }
+ fn homepage(&self) -> Option<&str> { self.$($path).+.homepage.as_deref() }
+ fn license(&self) -> &[String] { &self.$($path).+.license }
+ fn keywords(&self) -> &[String] { &self.$($path).+.keywords }
+ fn authors(&self) -> &[Author] { &self.$($path).+.authors }
+ fn scripts(&self) -> &indexmap::IndexMap<String, Vec<String>> { &self.$($path).+.scripts }
+ fn support(&self) -> &Support { &self.$($path).+.support }
+ fn funding(&self) -> &[Funding] { &self.$($path).+.funding }
+ fn repositories(&self) -> &[serde_json::Value] { &self.$($path).+.repositories }
+ fn abandoned(&self) -> Option<&str> { self.$($path).+.abandoned.as_deref() }
+ fn archive_name(&self) -> Option<&str> { self.$($path).+.archive_name.as_deref() }
+ fn archive_excludes(&self) -> &[String] { &self.$($path).+.archive_excludes }
}
};
}
-impl Package for PackageData {
+impl PackageInterface for PackageData {
fn name(&self) -> &str {
&self.name
}
@@ -341,7 +295,7 @@ impl Package for PackageData {
fn release_date(&self) -> Option<&str> {
self.release_date.as_deref()
}
- fn extra(&self) -> &BTreeMap<String, serde_json::Value> {
+ fn extra(&self) -> &indexmap::IndexMap<String, serde_json::Value> {
&self.extra
}
fn binaries(&self) -> &[String] {
@@ -356,22 +310,22 @@ impl Package for PackageData {
fn notification_url(&self) -> Option<&str> {
self.notification_url.as_deref()
}
- fn requires(&self) -> &BTreeMap<String, Link> {
+ fn requires(&self) -> &indexmap::IndexMap<String, Link> {
&self.requires
}
- fn conflicts(&self) -> &BTreeMap<String, Link> {
+ fn conflicts(&self) -> &indexmap::IndexMap<String, Link> {
&self.conflicts
}
- fn provides(&self) -> &BTreeMap<String, Link> {
+ fn provides(&self) -> &indexmap::IndexMap<String, Link> {
&self.provides
}
- fn replaces(&self) -> &BTreeMap<String, Link> {
+ fn replaces(&self) -> &indexmap::IndexMap<String, Link> {
&self.replaces
}
- fn dev_requires(&self) -> &BTreeMap<String, Link> {
+ fn dev_requires(&self) -> &indexmap::IndexMap<String, Link> {
&self.dev_requires
}
- fn suggests(&self) -> &BTreeMap<String, String> {
+ fn suggests(&self) -> &indexmap::IndexMap<String, String> {
&self.suggests
}
fn autoload(&self) -> &AutoloadRules {
@@ -385,7 +339,7 @@ impl Package for PackageData {
}
}
-impl CompletePackage for CompletePackageData {
+impl CompletePackageInterface for CompletePackageData {
fn description(&self) -> Option<&str> {
self.description.as_deref()
}
@@ -401,7 +355,7 @@ impl CompletePackage for CompletePackageData {
fn authors(&self) -> &[Author] {
&self.authors
}
- fn scripts(&self) -> &BTreeMap<String, Vec<String>> {
+ fn scripts(&self) -> &indexmap::IndexMap<String, Vec<String>> {
&self.scripts
}
fn support(&self) -> &Support {
@@ -431,13 +385,13 @@ impl RootPackage for RootPackageData {
fn prefer_stable(&self) -> bool {
self.prefer_stable
}
- fn stability_flags(&self) -> &BTreeMap<String, Stability> {
+ fn stability_flags(&self) -> &indexmap::IndexMap<String, Stability> {
&self.stability_flags
}
- fn config(&self) -> &BTreeMap<String, serde_json::Value> {
+ fn config(&self) -> &indexmap::IndexMap<String, serde_json::Value> {
&self.config
}
- fn references(&self) -> &BTreeMap<String, String> {
+ fn references(&self) -> &indexmap::IndexMap<String, String> {
&self.references
}
fn aliases(&self) -> &[VersionAlias] {
@@ -489,23 +443,23 @@ pub struct RawPackageData {
pub minimum_stability: Option<String>,
#[serde(default)]
- pub require: BTreeMap<String, String>,
+ pub require: indexmap::IndexMap<String, String>,
#[serde(
rename = "require-dev",
default,
- skip_serializing_if = "BTreeMap::is_empty"
+ skip_serializing_if = "indexmap::IndexMap::is_empty"
)]
- pub require_dev: BTreeMap<String, String>,
+ pub require_dev: indexmap::IndexMap<String, String>,
- #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
- pub conflict: BTreeMap<String, String>,
+ #[serde(default, skip_serializing_if = "indexmap::IndexMap::is_empty")]
+ pub conflict: indexmap::IndexMap<String, String>,
- #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
- pub provide: BTreeMap<String, String>,
+ #[serde(default, skip_serializing_if = "indexmap::IndexMap::is_empty")]
+ pub provide: indexmap::IndexMap<String, String>,
- #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
- pub replace: BTreeMap<String, String>,
+ #[serde(default, skip_serializing_if = "indexmap::IndexMap::is_empty")]
+ pub replace: indexmap::IndexMap<String, String>,
/// `repositories` accepts either a JSON array or a JSON object keyed by
/// repository name. Composer iterates `foreach ($repoConfigs as ...)` in
@@ -525,7 +479,7 @@ pub struct RawPackageData {
pub bin: Vec<String>,
#[serde(flatten)]
- pub extra_fields: BTreeMap<String, serde_json::Value>,
+ pub extra_fields: indexmap::IndexMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -539,7 +493,7 @@ pub struct RawAuthor {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RawAutoload {
#[serde(rename = "psr-4")]
- pub psr4: BTreeMap<String, String>,
+ pub psr4: indexmap::IndexMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -653,15 +607,15 @@ impl RawPackageData {
license: None,
authors: Vec::new(),
minimum_stability: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
repositories: Vec::new(),
autoload: None,
bin: Vec::new(),
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
@@ -696,9 +650,9 @@ impl RootPackageData {
pub fn from_raw(raw: RawPackageData) -> Self {
fn make_links(
source: &str,
- deps: BTreeMap<String, String>,
+ deps: indexmap::IndexMap<String, String>,
description: &str,
- ) -> BTreeMap<String, Link> {
+ ) -> indexmap::IndexMap<String, Link> {
deps.into_iter()
.map(|(target, constraint)| {
let normalized = target.to_lowercase();
@@ -745,7 +699,7 @@ impl RootPackageData {
})
.unwrap_or_default();
- let extra: BTreeMap<String, serde_json::Value> = raw
+ let extra: indexmap::IndexMap<String, serde_json::Value> = raw
.extra_fields
.get("extra")
.and_then(|v| v.as_object())
@@ -783,7 +737,7 @@ impl RootPackageData {
})
.unwrap_or_default();
- let scripts: BTreeMap<String, Vec<String>> = raw
+ let scripts: indexmap::IndexMap<String, Vec<String>> = raw
.extra_fields
.get("scripts")
.and_then(|v| v.as_object())
@@ -841,7 +795,7 @@ impl RootPackageData {
})
.unwrap_or_default();
- let config: BTreeMap<String, serde_json::Value> = raw
+ let config: indexmap::IndexMap<String, serde_json::Value> = raw
.extra_fields
.get("config")
.and_then(|v| v.as_object())
@@ -882,7 +836,7 @@ impl RootPackageData {
provides,
replaces,
dev_requires,
- suggests: BTreeMap::new(),
+ suggests: indexmap::IndexMap::new(),
autoload,
dev_autoload: AutoloadRules::default(),
is_default_branch: false,
@@ -908,9 +862,9 @@ impl RootPackageData {
complete: complete_data,
minimum_stability,
prefer_stable,
- stability_flags: BTreeMap::new(),
+ stability_flags: indexmap::IndexMap::new(),
config,
- references: BTreeMap::new(),
+ references: indexmap::IndexMap::new(),
aliases: Vec::new(),
}
}
@@ -976,7 +930,7 @@ mod tests {
security_advisories: None,
}];
- let mut psr4 = BTreeMap::new();
+ let mut psr4 = indexmap::IndexMap::new();
psr4.insert("Acme\\Full\\".to_string(), "src/".to_string());
raw.autoload = Some(RawAutoload { psr4 });
diff --git a/crates/mozart-core/src/package/complete_package_interface.rs b/crates/mozart-core/src/package/complete_package_interface.rs
new file mode 100644
index 0000000..c321309
--- /dev/null
+++ b/crates/mozart-core/src/package/complete_package_interface.rs
@@ -0,0 +1,17 @@
+use crate::package::{Author, Funding, PackageInterface, Support};
+
+/// ref: \Composer\Package\CompletePackageInterface
+pub trait CompletePackageInterface: PackageInterface {
+ fn description(&self) -> Option<&str>;
+ fn homepage(&self) -> Option<&str>;
+ fn license(&self) -> &[String];
+ fn keywords(&self) -> &[String];
+ fn authors(&self) -> &[Author];
+ fn scripts(&self) -> &indexmap::IndexMap<String, Vec<String>>;
+ fn support(&self) -> &Support;
+ fn funding(&self) -> &[Funding];
+ fn repositories(&self) -> &[serde_json::Value];
+ fn abandoned(&self) -> Option<&str>;
+ fn archive_name(&self) -> Option<&str>;
+ fn archive_excludes(&self) -> &[String];
+}
diff --git a/crates/mozart-core/src/package/package_interface.rs b/crates/mozart-core/src/package/package_interface.rs
new file mode 100644
index 0000000..7006657
--- /dev/null
+++ b/crates/mozart-core/src/package/package_interface.rs
@@ -0,0 +1,33 @@
+use crate::package::{AutoloadRules, Link, Stability};
+
+/// ref: \Composer\Package\PackageInterface
+pub trait PackageInterface {
+ fn name(&self) -> &str;
+ fn pretty_name(&self) -> &str;
+ fn version(&self) -> &str;
+ fn pretty_version(&self) -> &str;
+ fn package_type(&self) -> &str;
+ fn target_dir(&self) -> Option<&str>;
+ fn source_type(&self) -> Option<&str>;
+ fn source_url(&self) -> Option<&str>;
+ fn source_reference(&self) -> Option<&str>;
+ fn dist_type(&self) -> Option<&str>;
+ fn dist_url(&self) -> Option<&str>;
+ fn dist_reference(&self) -> Option<&str>;
+ fn dist_sha1_checksum(&self) -> Option<&str>;
+ fn release_date(&self) -> Option<&str>;
+ fn extra(&self) -> &indexmap::IndexMap<String, serde_json::Value>;
+ fn binaries(&self) -> &[String];
+ fn is_dev(&self) -> bool;
+ fn stability(&self) -> Stability;
+ fn notification_url(&self) -> Option<&str>;
+ fn requires(&self) -> &indexmap::IndexMap<String, Link>;
+ fn conflicts(&self) -> &indexmap::IndexMap<String, Link>;
+ fn provides(&self) -> &indexmap::IndexMap<String, Link>;
+ fn replaces(&self) -> &indexmap::IndexMap<String, Link>;
+ fn dev_requires(&self) -> &indexmap::IndexMap<String, Link>;
+ fn suggests(&self) -> &indexmap::IndexMap<String, String>;
+ fn autoload(&self) -> &AutoloadRules;
+ fn dev_autoload(&self) -> &AutoloadRules;
+ fn is_default_branch(&self) -> bool;
+}
diff --git a/crates/mozart-core/src/repository/browse_repos.rs b/crates/mozart-core/src/repository/browse_repos.rs
index 83a40f1..a174637 100644
--- a/crates/mozart-core/src/repository/browse_repos.rs
+++ b/crates/mozart-core/src/repository/browse_repos.rs
@@ -8,8 +8,8 @@
//! `CompletePackageInterface` (`getSupport()['source']`,
//! `getSourceUrl()`, `getHomepage()`).
-use super::super::package::Package as _;
-use super::super::package::{CompletePackage as _, RootPackageData};
+use super::super::package::PackageInterface as _;
+use super::super::package::{CompletePackageInterface as _, RootPackageData};
use super::cache::Cache;
use super::installed::{InstalledPackageEntry, InstalledPackages};
use super::lockfile::LockedPackage;
@@ -167,7 +167,6 @@ impl BrowseRepos {
mod tests {
use super::*;
use crate::package::RawPackageData;
- use std::collections::BTreeMap;
fn locked(
name: &str,
@@ -185,11 +184,11 @@ mod tests {
reference: None,
}),
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -202,7 +201,7 @@ mod tests {
support: support_source.map(|s| serde_json::json!({"source": s})),
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
@@ -240,7 +239,7 @@ mod tests {
aliases: vec![],
homepage: Some("https://vendor.example.com".to_string()),
support: Some(serde_json::json!({"source": "https://github.com/vendor/pkg"})),
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
};
let view = CompletePackageView::from(&entry);
assert_eq!(
diff --git a/crates/mozart-core/src/repository/installed.rs b/crates/mozart-core/src/repository/installed.rs
index 422f79f..4bee0e5 100644
--- a/crates/mozart-core/src/repository/installed.rs
+++ b/crates/mozart-core/src/repository/installed.rs
@@ -1,7 +1,6 @@
use crate::installer::HasSuggests;
use crate::package::to_json_pretty;
use serde::{Deserialize, Serialize};
-use std::collections::BTreeMap;
use std::fs;
use std::path::Path;
@@ -56,7 +55,7 @@ pub struct InstalledPackageEntry {
pub support: Option<serde_json::Value>,
#[serde(flatten)]
- pub extra_fields: BTreeMap<String, serde_json::Value>,
+ pub extra_fields: indexmap::IndexMap<String, serde_json::Value>,
}
impl HasSuggests for InstalledPackageEntry {
@@ -215,7 +214,7 @@ mod tests {
aliases: vec![],
homepage: None,
support: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
diff --git a/crates/mozart-core/src/repository/lockfile.rs b/crates/mozart-core/src/repository/lockfile.rs
index 146506d..cde7530 100644
--- a/crates/mozart-core/src/repository/lockfile.rs
+++ b/crates/mozart-core/src/repository/lockfile.rs
@@ -2,12 +2,12 @@ use super::packagist::{PackagistDist, PackagistSource, PackagistVersion};
use super::repository::RepositorySet;
use super::resolver::ResolvedPackage;
use crate::installer::HasSuggests;
-use crate::package::Package as _;
+use crate::package::PackageInterface as _;
use crate::package::{Link, RawPackageData, to_json_pretty};
use indexmap::IndexMap;
use indexmap::IndexSet;
use serde::{Deserialize, Serialize};
-use std::collections::{BTreeMap, VecDeque};
+use std::collections::VecDeque;
use std::fs;
use std::path::Path;
@@ -76,27 +76,27 @@ pub struct LockedPackage {
#[serde(skip_serializing_if = "Option::is_none")]
pub dist: Option<LockedDist>,
- #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
- pub require: BTreeMap<String, String>,
+ #[serde(default, skip_serializing_if = "indexmap::IndexMap::is_empty")]
+ pub require: indexmap::IndexMap<String, String>,
#[serde(
rename = "require-dev",
default,
- skip_serializing_if = "BTreeMap::is_empty"
+ skip_serializing_if = "indexmap::IndexMap::is_empty"
)]
- pub require_dev: BTreeMap<String, String>,
+ pub require_dev: indexmap::IndexMap<String, String>,
- #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
- pub conflict: BTreeMap<String, String>,
+ #[serde(default, skip_serializing_if = "indexmap::IndexMap::is_empty")]
+ pub conflict: indexmap::IndexMap<String, String>,
- #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
- pub provide: BTreeMap<String, String>,
+ #[serde(default, skip_serializing_if = "indexmap::IndexMap::is_empty")]
+ pub provide: indexmap::IndexMap<String, String>,
- #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
- pub replace: BTreeMap<String, String>,
+ #[serde(default, skip_serializing_if = "indexmap::IndexMap::is_empty")]
+ pub replace: indexmap::IndexMap<String, String>,
#[serde(skip_serializing_if = "Option::is_none")]
- pub suggest: Option<BTreeMap<String, String>>,
+ pub suggest: Option<indexmap::IndexMap<String, String>>,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub package_type: Option<String>,
@@ -133,7 +133,7 @@ pub struct LockedPackage {
/// Catch-all for extra fields we don't explicitly model
#[serde(flatten)]
- pub extra_fields: BTreeMap<String, serde_json::Value>,
+ pub extra_fields: indexmap::IndexMap<String, serde_json::Value>,
}
impl HasSuggests for LockedPackage {
@@ -231,9 +231,9 @@ impl LockFile {
];
// Collect relevant keys into a BTreeMap (auto-sorted by key)
- let mut filtered: BTreeMap<&str, &serde_json::Value> = BTreeMap::new();
- for key in &relevant_keys {
- if let Some(v) = obj.get(*key) {
+ let mut filtered = std::collections::BTreeMap::new();
+ for key in relevant_keys {
+ if let Some(v) = obj.get(key) {
filtered.insert(key, v);
}
}
@@ -396,7 +396,7 @@ pub fn locked_package_branch_aliases(pkg: &LockedPackage) -> Vec<LockAlias> {
}
fn check_requirement_set(
- requires: &BTreeMap<String, Link>,
+ requires: &IndexMap<String, Link>,
description: &str,
pool: &[LockedSearchEntry],
messages: &mut Vec<String>,
@@ -626,10 +626,10 @@ fn packagist_dist_to_locked(pd: &PackagistDist) -> LockedDist {
/// `dev` after stripping the reference are left out (matching the
/// `'dev' === VersionParser::parseStability(...)` guard in PHP).
fn extract_root_references(
- require: &BTreeMap<String, String>,
- require_dev: &BTreeMap<String, String>,
-) -> BTreeMap<String, String> {
- let mut out = BTreeMap::new();
+ require: &IndexMap<String, String>,
+ require_dev: &IndexMap<String, String>,
+) -> indexmap::IndexMap<String, String> {
+ let mut out = indexmap::IndexMap::new();
for (name, raw_constraint) in require.iter().chain(require_dev.iter()) {
if let Some(reference) = parse_inline_reference(raw_constraint) {
out.insert(name.to_lowercase(), reference);
@@ -730,7 +730,7 @@ fn rewrite_known_dist_url_reference(url: &str, reference: &str) -> String {
/// Convert a `PackagistVersion` to a `LockedPackage`.
fn packagist_version_to_locked_package(name: &str, pv: &PackagistVersion) -> LockedPackage {
- let mut extra_fields: BTreeMap<String, serde_json::Value> = BTreeMap::new();
+ let mut extra_fields = indexmap::IndexMap::new();
if let Some(extra) = &pv.extra {
extra_fields.insert("extra".to_string(), extra.clone());
@@ -808,8 +808,8 @@ fn packagist_version_to_locked_package(name: &str, pv: &PackagistVersion) -> Loc
/// declares `provide: { provided/pkg: 1.0.0 }`.
fn classify_dev_packages(
resolved: &[ResolvedPackage],
- require: &BTreeMap<String, String>,
- _require_dev: &BTreeMap<String, String>,
+ require: &IndexMap<String, String>,
+ _require_dev: &IndexMap<String, String>,
requires_by_name: &IndexMap<String, Vec<String>>,
providers_by_name: &IndexMap<String, Vec<String>>,
) -> IndexSet<String> {
@@ -874,7 +874,7 @@ fn is_platform_name(name: &str) -> bool {
///
/// Filters the map to include only platform package keys (`php`, `ext-*`, `lib-*`, etc.)
/// and returns them as a JSON object.
-fn extract_platform_requirements(requirements: &BTreeMap<String, String>) -> serde_json::Value {
+fn extract_platform_requirements(requirements: &IndexMap<String, String>) -> serde_json::Value {
let map: serde_json::Map<String, serde_json::Value> = requirements
.iter()
.filter(|(k, _)| is_platform_name(k))
@@ -920,12 +920,12 @@ pub async fn generate_lock_file(request: &LockFileGenerationRequest) -> anyhow::
// resolver picked a new commit at the same version label) still get
// their ref refreshed.
struct PreservedRelationships {
- require: BTreeMap<String, String>,
- require_dev: BTreeMap<String, String>,
- conflict: BTreeMap<String, String>,
- provide: BTreeMap<String, String>,
- replace: BTreeMap<String, String>,
- suggest: Option<BTreeMap<String, String>>,
+ require: indexmap::IndexMap<String, String>,
+ require_dev: indexmap::IndexMap<String, String>,
+ conflict: indexmap::IndexMap<String, String>,
+ provide: indexmap::IndexMap<String, String>,
+ replace: indexmap::IndexMap<String, String>,
+ suggest: Option<indexmap::IndexMap<String, String>>,
}
let mut preserved_rel: IndexMap<String, PreservedRelationships> = IndexMap::new();
if let Some(prev) = &request.previous_lock {
@@ -1229,11 +1229,11 @@ mod tests {
reference: Some("abc123".to_string()),
shasum: Some("".to_string()),
}),
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: Some("library".to_string()),
autoload: None,
@@ -1246,7 +1246,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
});
lock.write_to_file(&path).unwrap();
@@ -1320,15 +1320,15 @@ mod tests {
fn make_packagist_version(
version: &str,
version_normalized: &str,
- require: BTreeMap<String, String>,
+ require: indexmap::IndexMap<String, String>,
) -> PackagistVersion {
PackagistVersion {
version: version.to_string(),
version_normalized: version_normalized.to_string(),
require,
- replace: BTreeMap::new(),
- provide: BTreeMap::new(),
- conflict: BTreeMap::new(),
+ replace: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
dist: Some(super::super::packagist::PackagistDist {
dist_type: "zip".to_string(),
url: format!("https://example.com/{version}.zip"),
@@ -1340,7 +1340,7 @@ mod tests {
url: "https://github.com/example/pkg.git".to_string(),
reference: Some("deadbeef".to_string()),
}),
- require_dev: BTreeMap::new(),
+ require_dev: indexmap::IndexMap::new(),
suggest: None,
package_type: Some("library".to_string()),
autoload: Some(serde_json::json!({"psr-4": {"Example\\": "src/"}})),
@@ -1366,7 +1366,7 @@ mod tests {
#[test]
fn test_packagist_version_to_locked_package() {
- let pv = make_packagist_version("1.2.3", "1.2.3.0", BTreeMap::new());
+ let pv = make_packagist_version("1.2.3", "1.2.3.0", indexmap::IndexMap::new());
let locked = packagist_version_to_locked_package("example/pkg", &pv);
assert_eq!(locked.name, "example/pkg");
@@ -1414,13 +1414,13 @@ mod tests {
let pv = PackagistVersion {
version: "1.0.0".to_string(),
version_normalized: "1.0.0.0".to_string(),
- require: BTreeMap::new(),
- replace: BTreeMap::new(),
- provide: BTreeMap::new(),
- conflict: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
dist: None,
source: None,
- require_dev: BTreeMap::new(),
+ require_dev: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -1484,16 +1484,16 @@ mod tests {
},
];
- let mut require = BTreeMap::new();
+ let mut require = indexmap::IndexMap::new();
require.insert("vendor/a".to_string(), "^1.0".to_string());
- let mut require_dev = BTreeMap::new();
+ let mut require_dev = indexmap::IndexMap::new();
require_dev.insert("vendor/b".to_string(), "^1.0".to_string());
let mut metadata: IndexMap<String, PackagistVersion> = IndexMap::new();
// A requires C
- let mut a_require = BTreeMap::new();
+ let mut a_require = indexmap::IndexMap::new();
a_require.insert("vendor/c".to_string(), "^1.0".to_string());
metadata.insert(
"vendor/a".to_string(),
@@ -1501,7 +1501,7 @@ mod tests {
);
// B requires D
- let mut b_require = BTreeMap::new();
+ let mut b_require = indexmap::IndexMap::new();
b_require.insert("vendor/d".to_string(), "^1.0".to_string());
metadata.insert(
"vendor/b".to_string(),
@@ -1511,11 +1511,11 @@ mod tests {
// C and D have no deps
metadata.insert(
"vendor/c".to_string(),
- make_packagist_version("1.0.0", "1.0.0.0", BTreeMap::new()),
+ make_packagist_version("1.0.0", "1.0.0.0", indexmap::IndexMap::new()),
);
metadata.insert(
"vendor/d".to_string(),
- make_packagist_version("1.0.0", "1.0.0.0", BTreeMap::new()),
+ make_packagist_version("1.0.0", "1.0.0.0", indexmap::IndexMap::new()),
);
let requires_by_name: IndexMap<String, Vec<String>> = metadata
@@ -1577,16 +1577,16 @@ mod tests {
},
];
- let mut require = BTreeMap::new();
+ let mut require = indexmap::IndexMap::new();
require.insert("vendor/a".to_string(), "^1.0".to_string());
- let mut require_dev = BTreeMap::new();
+ let mut require_dev = indexmap::IndexMap::new();
require_dev.insert("vendor/b".to_string(), "^1.0".to_string());
let mut metadata: IndexMap<String, PackagistVersion> = IndexMap::new();
// A requires C
- let mut a_require = BTreeMap::new();
+ let mut a_require = indexmap::IndexMap::new();
a_require.insert("vendor/c".to_string(), "^1.0".to_string());
metadata.insert(
"vendor/a".to_string(),
@@ -1594,7 +1594,7 @@ mod tests {
);
// B also requires C
- let mut b_require = BTreeMap::new();
+ let mut b_require = indexmap::IndexMap::new();
b_require.insert("vendor/c".to_string(), "^1.0".to_string());
metadata.insert(
"vendor/b".to_string(),
@@ -1604,7 +1604,7 @@ mod tests {
// C has no deps
metadata.insert(
"vendor/c".to_string(),
- make_packagist_version("1.0.0", "1.0.0.0", BTreeMap::new()),
+ make_packagist_version("1.0.0", "1.0.0.0", indexmap::IndexMap::new()),
);
let requires_by_name: IndexMap<String, Vec<String>> = metadata
@@ -1636,7 +1636,7 @@ mod tests {
#[test]
fn test_extract_platform_requirements() {
- let mut requirements = BTreeMap::new();
+ let mut requirements = indexmap::IndexMap::new();
requirements.insert("php".to_string(), ">=8.1".to_string());
requirements.insert("ext-json".to_string(), "*".to_string());
requirements.insert("ext-mbstring".to_string(), "*".to_string());
@@ -1669,7 +1669,7 @@ mod tests {
#[test]
fn test_extract_platform_requirements_empty() {
- let requirements = BTreeMap::new();
+ let requirements = indexmap::IndexMap::new();
let platform = extract_platform_requirements(&requirements);
assert_eq!(platform, serde_json::json!({}));
}
@@ -1729,11 +1729,11 @@ mod tests {
version_normalized: None,
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -1746,7 +1746,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
},
LockedPackage {
name: "vendor/alpha".to_string(),
@@ -1754,11 +1754,11 @@ mod tests {
version_normalized: None,
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -1771,7 +1771,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
},
];
@@ -1892,11 +1892,11 @@ mod tests {
version_normalized: None,
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: Some("library".to_string()),
autoload: None,
@@ -1909,7 +1909,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
diff --git a/crates/mozart-core/src/repository/packagist.rs b/crates/mozart-core/src/repository/packagist.rs
index 199ff51..91b47df 100644
--- a/crates/mozart-core/src/repository/packagist.rs
+++ b/crates/mozart-core/src/repository/packagist.rs
@@ -55,13 +55,13 @@ pub struct PackagistVersion {
pub version: String,
pub version_normalized: String,
#[serde(default, deserialize_with = "deserialize_unset_as_default")]
- pub require: BTreeMap<String, String>,
+ pub require: indexmap::IndexMap<String, String>,
#[serde(default, deserialize_with = "deserialize_unset_as_default")]
- pub replace: BTreeMap<String, String>,
+ pub replace: indexmap::IndexMap<String, String>,
#[serde(default, deserialize_with = "deserialize_unset_as_default")]
- pub provide: BTreeMap<String, String>,
+ pub provide: indexmap::IndexMap<String, String>,
#[serde(default, deserialize_with = "deserialize_unset_as_default")]
- pub conflict: BTreeMap<String, String>,
+ pub conflict: indexmap::IndexMap<String, String>,
#[serde(default, deserialize_with = "deserialize_unset_as_none")]
pub dist: Option<PackagistDist>,
#[serde(default, deserialize_with = "deserialize_unset_as_none")]
@@ -72,10 +72,10 @@ pub struct PackagistVersion {
default,
deserialize_with = "deserialize_unset_as_default"
)]
- pub require_dev: BTreeMap<String, String>,
+ pub require_dev: indexmap::IndexMap<String, String>,
#[serde(default, deserialize_with = "deserialize_unset_as_none")]
- pub suggest: Option<BTreeMap<String, String>>,
+ pub suggest: Option<indexmap::IndexMap<String, String>>,
#[serde(
rename = "type",
@@ -160,17 +160,17 @@ impl PackagistVersion {
///
/// Returns a map from branch name (e.g. `"dev-master"`) to alias target
/// (e.g. `"2.x-dev"`). Returns an empty map when no aliases are declared.
- pub fn branch_aliases(&self) -> BTreeMap<String, String> {
+ pub fn branch_aliases(&self) -> indexmap::IndexMap<String, String> {
let Some(extra) = &self.extra else {
- return BTreeMap::new();
+ return indexmap::IndexMap::new();
};
let Some(branch_alias) = extra.get("branch-alias") else {
- return BTreeMap::new();
+ return indexmap::IndexMap::new();
};
let Some(map) = branch_alias.as_object() else {
- return BTreeMap::new();
+ return indexmap::IndexMap::new();
};
map.iter()
diff --git a/crates/mozart-core/src/repository/vcs_bridge.rs b/crates/mozart-core/src/repository/vcs_bridge.rs
index 18a8420..79c0c5b 100644
--- a/crates/mozart-core/src/repository/vcs_bridge.rs
+++ b/crates/mozart-core/src/repository/vcs_bridge.rs
@@ -10,7 +10,6 @@ use crate::repository::resolver::{parse_normalized, version_stability};
use crate::repository::vcs::DriverConfig;
use crate::vcs::repository::{VcsPackageVersion, VcsRepository};
use indexmap::IndexMap;
-use std::collections::BTreeMap;
/// Scan all VCS-type repositories and collect package versions.
///
@@ -191,7 +190,7 @@ pub fn vcs_to_packagist_version(vpkg: &VcsPackageVersion) -> PackagistVersion {
}
/// Extract a dependency map from composer.json JSON.
-fn extract_dep_map(json: &serde_json::Value, key: &str) -> BTreeMap<String, String> {
+fn extract_dep_map(json: &serde_json::Value, key: &str) -> indexmap::IndexMap<String, String> {
json.get(key)
.and_then(|v| v.as_object())
.map(|obj| {
diff --git a/crates/mozart-core/src/repository_utils.rs b/crates/mozart-core/src/repository_utils.rs
index b16a0d6..7a797c4 100644
--- a/crates/mozart-core/src/repository_utils.rs
+++ b/crates/mozart-core/src/repository_utils.rs
@@ -19,7 +19,7 @@ use std::collections::BTreeSet;
/// `package_name` only in that case.
pub trait Required {
fn package_name(&self) -> &str;
- fn requires(&self) -> &std::collections::BTreeMap<String, String>;
+ fn requires(&self) -> &indexmap::IndexMap<String, String>;
fn package_names(&self) -> Option<Vec<&str>> {
None
}
@@ -38,8 +38,8 @@ pub trait Required {
/// discovered, matching PHP's `$bucket[] = $candidate;` push pattern.
pub fn filter_required_packages<P, V>(
packages: &[P],
- requirer_requires: &std::collections::BTreeMap<String, V>,
- requirer_dev_requires: Option<&std::collections::BTreeMap<String, V>>,
+ requirer_requires: &indexmap::IndexMap<String, V>,
+ requirer_dev_requires: Option<&indexmap::IndexMap<String, V>>,
) -> Vec<usize>
where
P: Required,
@@ -78,24 +78,23 @@ where
#[cfg(test)]
mod tests {
use super::*;
- use std::collections::BTreeMap;
struct Pkg {
name: String,
- requires: BTreeMap<String, String>,
+ requires: indexmap::IndexMap<String, String>,
}
impl Required for Pkg {
fn package_name(&self) -> &str {
&self.name
}
- fn requires(&self) -> &BTreeMap<String, String> {
+ fn requires(&self) -> &indexmap::IndexMap<String, String> {
&self.requires
}
}
fn pkg(name: &str, requires: &[&str]) -> Pkg {
- let mut r = BTreeMap::new();
+ let mut r = indexmap::IndexMap::new();
for n in requires {
r.insert(n.to_string(), "*".to_string());
}
@@ -105,8 +104,8 @@ mod tests {
}
}
- fn root_requires(names: &[&str]) -> BTreeMap<String, String> {
- let mut m = BTreeMap::new();
+ fn root_requires(names: &[&str]) -> indexmap::IndexMap<String, String> {
+ let mut m = indexmap::IndexMap::new();
for n in names {
m.insert(n.to_string(), "*".to_string());
}
@@ -167,7 +166,7 @@ mod tests {
#[test]
fn empty_requires_yields_nothing() {
let packages = vec![pkg("a/a", &[]), pkg("b/b", &[])];
- let root: BTreeMap<String, String> = BTreeMap::new();
+ let root: indexmap::IndexMap<_, ()> = indexmap::IndexMap::new();
let kept = filter_required_packages(&packages, &root, None);
assert!(kept.is_empty());
}
diff --git a/crates/mozart/src/commands/audit.rs b/crates/mozart/src/commands/audit.rs
index 0b84ccf..f543cb4 100644
--- a/crates/mozart/src/commands/audit.rs
+++ b/crates/mozart/src/commands/audit.rs
@@ -194,8 +194,6 @@ fn load_locked_packages(working_dir: &Path, no_dev: bool) -> anyhow::Result<Vec<
#[cfg(test)]
mod tests {
- use std::collections::BTreeMap;
-
use super::*;
use mozart_core::repository::lockfile::{LockFile, LockedPackage};
@@ -242,7 +240,7 @@ mod tests {
aliases: vec![],
homepage: None,
support: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
});
installed.write(&vendor_dir).unwrap();
@@ -273,7 +271,7 @@ mod tests {
aliases: vec![],
homepage: None,
support: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
});
installed.upsert(mozart_core::repository::installed::InstalledPackageEntry {
name: "phpunit/phpunit".to_string(),
@@ -287,7 +285,7 @@ mod tests {
aliases: vec![],
homepage: None,
support: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
});
installed
.dev_package_names
@@ -315,11 +313,11 @@ mod tests {
version_normalized: Some("3.0.0.0".to_string()),
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -332,7 +330,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}],
packages_dev: None,
aliases: vec![],
@@ -370,11 +368,11 @@ mod tests {
version_normalized: None,
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -387,7 +385,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}],
packages_dev: Some(vec![LockedPackage {
name: "phpunit/phpunit".to_string(),
@@ -395,11 +393,11 @@ mod tests {
version_normalized: None,
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -412,7 +410,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}]),
aliases: vec![],
minimum_stability: "stable".to_string(),
diff --git a/crates/mozart/src/commands/browse.rs b/crates/mozart/src/commands/browse.rs
index e3eae22..957f4bc 100644
--- a/crates/mozart/src/commands/browse.rs
+++ b/crates/mozart/src/commands/browse.rs
@@ -4,7 +4,7 @@ use mozart_core::console::IoInterface;
use mozart_core::console_writeln;
use mozart_core::console_writeln_error;
use mozart_core::exit_code;
-use mozart_core::package::Package as _;
+use mozart_core::package::PackageInterface as _;
use mozart_core::repository::browse_repos::{BrowseRepos, CompletePackageView};
use mozart_core::repository::cache::{Cache, build_cache_config};
use mozart_core::repository::installed::InstalledPackages;
diff --git a/crates/mozart/src/commands/bump.rs b/crates/mozart/src/commands/bump.rs
index 351be01..2d6eea8 100644
--- a/crates/mozart/src/commands/bump.rs
+++ b/crates/mozart/src/commands/bump.rs
@@ -3,7 +3,7 @@ use clap::Args;
use indexmap::IndexMap;
use mozart_core::composer::LocalRepository;
use mozart_core::console::IoInterface;
-use mozart_core::package::{Link, Package as _};
+use mozart_core::package::PackageInterface as _;
use mozart_core::{console_writeln, console_writeln_error};
use std::collections::BTreeMap;
use std::path::Path;
@@ -151,7 +151,7 @@ pub async fn do_bump(
}
}
- let mut tasks: Vec<(&'static str, &BTreeMap<String, Link>)> = Vec::new();
+ let mut tasks = Vec::new();
if !dev_only {
tasks.push(("require", composer.package().requires()));
}
@@ -386,11 +386,11 @@ mod tests {
version_normalized: Some(format!("{version}.0")),
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -403,7 +403,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
diff --git a/crates/mozart/src/commands/check_platform_reqs.rs b/crates/mozart/src/commands/check_platform_reqs.rs
index 2dbcd3b..f6731d7 100644
--- a/crates/mozart/src/commands/check_platform_reqs.rs
+++ b/crates/mozart/src/commands/check_platform_reqs.rs
@@ -3,7 +3,6 @@ use mozart_core::console::IoInterface;
use mozart_core::console_writeln;
use mozart_core::console_writeln_error;
use mozart_core::installer::{InstalledCandidate, InstalledRepoLite};
-use std::collections::BTreeMap;
use std::path::Path;
#[derive(Args)]
@@ -75,7 +74,7 @@ pub async fn execute(
let installed_path = vendor_dir.join("composer/installed.json");
let mut installed_repo = InstalledRepoLite::new();
- let mut requires: BTreeMap<String, Vec<Link>> = BTreeMap::new();
+ let mut requires = indexmap::IndexMap::new();
if args.lock {
if !lock_path.exists() {
@@ -141,8 +140,8 @@ pub async fn execute(
pretty_name: pkg.name,
version: pkg.version.clone(),
pretty_version: pkg.version,
- provides: BTreeMap::new(),
- replaces: BTreeMap::new(),
+ provides: indexmap::IndexMap::new(),
+ replaces: indexmap::IndexMap::new(),
});
}
@@ -251,7 +250,7 @@ fn load_lock(
lock_path: &Path,
no_dev: bool,
repo: &mut InstalledRepoLite,
- requires: &mut BTreeMap<String, Vec<Link>>,
+ requires: &mut indexmap::IndexMap<String, Vec<Link>>,
) -> anyhow::Result<()> {
let lock = mozart_core::repository::lockfile::LockFile::read_from_file(lock_path)?;
@@ -282,7 +281,7 @@ fn load_installed(
installed: &mozart_core::repository::installed::InstalledPackages,
no_dev: bool,
repo: &mut InstalledRepoLite,
- requires: &mut BTreeMap<String, Vec<Link>>,
+ requires: &mut indexmap::IndexMap<String, Vec<Link>>,
) {
let dev_names: indexmap::IndexSet<String> = installed
.dev_package_names
@@ -334,10 +333,10 @@ fn add_root_as_candidate(
}
fn string_map_from_extra(
- extra: &BTreeMap<String, serde_json::Value>,
+ extra: &indexmap::IndexMap<String, serde_json::Value>,
key: &str,
-) -> BTreeMap<String, String> {
- let mut out: BTreeMap<String, String> = BTreeMap::new();
+) -> indexmap::IndexMap<String, String> {
+ let mut out = indexmap::IndexMap::new();
if let Some(val) = extra.get(key)
&& let Some(obj) = val.as_object()
{
@@ -351,7 +350,7 @@ fn string_map_from_extra(
}
fn push_platform_link(
- requires: &mut BTreeMap<String, Vec<Link>>,
+ requires: &mut indexmap::IndexMap<String, Vec<Link>>,
source: &str,
target: &str,
constraint: &str,
@@ -470,7 +469,6 @@ fn print_table(
mod tests {
use super::*;
use mozart_core::console::Console;
- use std::collections::BTreeMap;
use tempfile::tempdir;
fn test_console() -> std::sync::Arc<std::sync::Mutex<Box<dyn IoInterface>>> {
@@ -481,22 +479,26 @@ mod tests {
fn write_lock(
path: &Path,
- packages: &[(&str, BTreeMap<String, String>)],
- dev_packages: &[(&str, BTreeMap<String, String>)],
+ packages: &[(&str, indexmap::IndexMap<String, String>)],
+ dev_packages: &[(&str, indexmap::IndexMap<String, String>)],
) {
write_lock_with(path, packages, dev_packages, &[]);
}
fn write_lock_with(
path: &Path,
- packages: &[(&str, BTreeMap<String, String>)],
- dev_packages: &[(&str, BTreeMap<String, String>)],
- provides: &[(&str, BTreeMap<String, String>, BTreeMap<String, String>)], // (name, provide, replace)
+ packages: &[(&str, indexmap::IndexMap<String, String>)],
+ dev_packages: &[(&str, indexmap::IndexMap<String, String>)],
+ provides: &[(
+ &str,
+ indexmap::IndexMap<String, String>,
+ indexmap::IndexMap<String, String>,
+ )], // (name, provide, replace)
) {
let make_pkg = |name: &str,
- require: BTreeMap<String, String>,
- provide: BTreeMap<String, String>,
- replace: BTreeMap<String, String>| {
+ require: indexmap::IndexMap<String, String>,
+ provide: indexmap::IndexMap<String, String>,
+ replace: indexmap::IndexMap<String, String>| {
serde_json::json!({
"name": name,
"version": "1.0.0",
@@ -508,15 +510,34 @@ mod tests {
let mut pkgs_json: Vec<serde_json::Value> = packages
.iter()
- .map(|(name, req)| make_pkg(name, req.clone(), BTreeMap::new(), BTreeMap::new()))
+ .map(|(name, req)| {
+ make_pkg(
+ name,
+ req.clone(),
+ indexmap::IndexMap::new(),
+ indexmap::IndexMap::new(),
+ )
+ })
.collect();
for (name, prov, repl) in provides {
- pkgs_json.push(make_pkg(name, BTreeMap::new(), prov.clone(), repl.clone()));
+ pkgs_json.push(make_pkg(
+ name,
+ indexmap::IndexMap::new(),
+ prov.clone(),
+ repl.clone(),
+ ));
}
let dev_pkgs_json: Vec<serde_json::Value> = dev_packages
.iter()
- .map(|(name, req)| make_pkg(name, req.clone(), BTreeMap::new(), BTreeMap::new()))
+ .map(|(name, req)| {
+ make_pkg(
+ name,
+ req.clone(),
+ indexmap::IndexMap::new(),
+ indexmap::IndexMap::new(),
+ )
+ })
.collect();
let lock_json = serde_json::json!({
@@ -565,7 +586,7 @@ mod tests {
let dir = tempdir().unwrap();
let lock_path = dir.path().join("composer.lock");
- let mut pkg_require = BTreeMap::new();
+ let mut pkg_require = indexmap::IndexMap::new();
pkg_require.insert("php".to_string(), ">=8.1".to_string());
pkg_require.insert("ext-json".to_string(), "*".to_string());
pkg_require.insert("monolog/monolog".to_string(), "^3.0".to_string()); // not platform
@@ -573,7 +594,7 @@ mod tests {
write_lock(&lock_path, &[("vendor/pkg", pkg_require)], &[]);
let mut repo = InstalledRepoLite::new();
- let mut requires: BTreeMap<String, Vec<Link>> = BTreeMap::new();
+ let mut requires = indexmap::IndexMap::new();
load_lock(&lock_path, false, &mut repo, &mut requires).unwrap();
assert!(requires.contains_key("php"));
@@ -591,10 +612,10 @@ mod tests {
let dir = tempdir().unwrap();
let lock_path = dir.path().join("composer.lock");
- let mut prod_require = BTreeMap::new();
+ let mut prod_require = indexmap::IndexMap::new();
prod_require.insert("php".to_string(), ">=8.0".to_string());
- let mut dev_require = BTreeMap::new();
+ let mut dev_require = indexmap::IndexMap::new();
dev_require.insert("ext-xdebug".to_string(), "*".to_string());
write_lock(
@@ -604,13 +625,13 @@ mod tests {
);
let mut repo = InstalledRepoLite::new();
- let mut requires: BTreeMap<String, Vec<Link>> = BTreeMap::new();
+ let mut requires = indexmap::IndexMap::new();
load_lock(&lock_path, true, &mut repo, &mut requires).unwrap();
assert!(requires.contains_key("php"));
assert!(!requires.contains_key("ext-xdebug"));
let mut repo2 = InstalledRepoLite::new();
- let mut requires2: BTreeMap<String, Vec<Link>> = BTreeMap::new();
+ let mut requires2 = indexmap::IndexMap::new();
load_lock(&lock_path, false, &mut repo2, &mut requires2).unwrap();
assert!(requires2.contains_key("ext-xdebug"));
}
@@ -626,10 +647,10 @@ mod tests {
pretty_name: "vendor/pkg".into(),
version: "1.0.0".into(),
pretty_version: "1.0.0".into(),
- provides: BTreeMap::new(),
- replaces: BTreeMap::new(),
+ provides: indexmap::IndexMap::new(),
+ replaces: indexmap::IndexMap::new(),
});
- let mut polyfill_provides = BTreeMap::new();
+ let mut polyfill_provides = indexmap::IndexMap::new();
polyfill_provides.insert("ext-mbstring".to_string(), "*".to_string());
repo.add_candidate(InstalledCandidate {
name: "symfony/polyfill-mbstring".into(),
@@ -637,7 +658,7 @@ mod tests {
version: "1.30.0".into(),
pretty_version: "1.30.0".into(),
provides: polyfill_provides,
- replaces: BTreeMap::new(),
+ replaces: indexmap::IndexMap::new(),
});
let candidates = repo.find_with_replacers_and_providers("ext-mbstring");
@@ -652,7 +673,7 @@ mod tests {
#[test]
fn test_replacer_candidate_satisfies_require() {
- let mut replaces = BTreeMap::new();
+ let mut replaces = indexmap::IndexMap::new();
replaces.insert("ext-mbstring".to_string(), "1.0".to_string());
let mut repo = InstalledRepoLite::new();
@@ -661,7 +682,7 @@ mod tests {
pretty_name: "vendor/legacy-replacement".into(),
version: "2.0.0".into(),
pretty_version: "2.0.0".into(),
- provides: BTreeMap::new(),
+ provides: indexmap::IndexMap::new(),
replaces,
});
diff --git a/crates/mozart/src/commands/dependency.rs b/crates/mozart/src/commands/dependency.rs
index 70d1644..5766b08 100644
--- a/crates/mozart/src/commands/dependency.rs
+++ b/crates/mozart/src/commands/dependency.rs
@@ -9,7 +9,6 @@ use indexmap::IndexSet;
use mozart_core::console::IoInterface;
use mozart_core::console_format;
use mozart_core::console_writeln;
-use std::collections::BTreeMap;
use std::path::Path;
/// Inputs for [`do_execute`], collected from the `depends` / `prohibits` CLI args.
@@ -160,11 +159,11 @@ pub struct PackageInfo {
pub name: String,
pub version: String,
/// Runtime requirements (`require` section).
- pub require: BTreeMap<String, String>,
+ pub require: indexmap::IndexMap<String, String>,
/// Dev requirements (`require-dev`) — only non-empty for the root package.
- pub require_dev: BTreeMap<String, String>,
+ pub require_dev: indexmap::IndexMap<String, String>,
/// Conflict declarations (`conflict` section).
- pub conflict: BTreeMap<String, String>,
+ pub conflict: indexmap::IndexMap<String, String>,
/// Whether this is the root `composer.json` package.
pub is_root: bool,
}
@@ -218,9 +217,9 @@ pub fn load_packages(working_dir: &Path, locked: bool) -> Result<Vec<PackageInfo
packages.push(PackageInfo {
name: pp.name.clone(),
version: pp.version.clone(),
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
is_root: false,
});
}
@@ -230,7 +229,7 @@ pub fn load_packages(working_dir: &Path, locked: bool) -> Result<Vec<PackageInfo
&& let Ok(root) = mozart_core::package::read_from_file(&composer_json_path)
{
// Extract conflict from extra_fields if present
- let conflict: BTreeMap<String, String> = root
+ let conflict = root
.extra_fields
.get("conflict")
.and_then(|v| v.as_object())
@@ -267,7 +266,7 @@ fn load_from_lockfile(lock_path: &Path) -> Result<Vec<PackageInfo>> {
name: pkg.name.clone(),
version: pkg.version.clone(),
require: pkg.require.clone(),
- require_dev: BTreeMap::new(), // locked packages don't expose require-dev
+ require_dev: indexmap::IndexMap::new(), // locked packages don't expose require-dev
conflict: pkg.conflict.clone(),
is_root: false,
});
@@ -279,7 +278,7 @@ fn load_from_lockfile(lock_path: &Path) -> Result<Vec<PackageInfo>> {
name: pkg.name.clone(),
version: pkg.version.clone(),
require: pkg.require.clone(),
- require_dev: BTreeMap::new(),
+ require_dev: indexmap::IndexMap::new(),
conflict: pkg.conflict.clone(),
is_root: false,
});
@@ -325,7 +324,7 @@ fn load_from_installed(working_dir: &Path) -> Result<Vec<PackageInfo>> {
name: p.name.clone(),
version: p.version.clone(),
require,
- require_dev: BTreeMap::new(),
+ require_dev: indexmap::IndexMap::new(),
conflict,
is_root: false,
}
@@ -367,7 +366,7 @@ fn get_dependents_forward(
let needle_set: IndexSet<String> = needles.iter().map(|n| n.to_lowercase()).collect();
// Build name→PackageInfo lookup
- let pkg_map: BTreeMap<String, &PackageInfo> = packages
+ let pkg_map: indexmap::IndexMap<_, _> = packages
.iter()
.map(|p| (p.name.to_lowercase(), p))
.collect();
@@ -448,7 +447,7 @@ fn collect_direct_requires(packages: &[PackageInfo], needle: &str) -> Vec<Depend
fn recurse_dependents(
packages: &[PackageInfo],
needle: &str,
- pkg_map: &BTreeMap<String, &PackageInfo>,
+ pkg_map: &indexmap::IndexMap<String, &PackageInfo>,
visited: &mut IndexSet<String>,
_original_needles: &IndexSet<String>,
) -> Vec<DependencyResult> {
@@ -760,7 +759,7 @@ mod tests {
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect(),
- require_dev: BTreeMap::new(),
+ require_dev: indexmap::IndexMap::new(),
conflict: conflict
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
diff --git a/crates/mozart/src/commands/diagnose.rs b/crates/mozart/src/commands/diagnose.rs
index a1d655f..6b2817a 100644
--- a/crates/mozart/src/commands/diagnose.rs
+++ b/crates/mozart/src/commands/diagnose.rs
@@ -8,7 +8,7 @@ use mozart_core::console::IoInterface;
use mozart_core::console_writeln;
use mozart_core::factory::create_config;
use mozart_core::http::HttpDownloader;
-use mozart_core::package::CompletePackage as _;
+use mozart_core::package::CompletePackageInterface as _;
use std::borrow::Cow;
use std::path::Path;
diff --git a/crates/mozart/src/commands/exec.rs b/crates/mozart/src/commands/exec.rs
index f2a9c55..1078158 100644
--- a/crates/mozart/src/commands/exec.rs
+++ b/crates/mozart/src/commands/exec.rs
@@ -1,6 +1,6 @@
use crate::composer::Composer;
use clap::Args;
-use mozart_core::package::Package as _;
+use mozart_core::package::PackageInterface as _;
use mozart_core::{console::IoInterface, console_writeln};
use std::path::{Path, PathBuf};
diff --git a/crates/mozart/src/commands/init.rs b/crates/mozart/src/commands/init.rs
index 0e16054..4598d39 100644
--- a/crates/mozart/src/commands/init.rs
+++ b/crates/mozart/src/commands/init.rs
@@ -425,7 +425,7 @@ async fn build_interactive(
"Would you like to define your dev dependencies (require-dev) interactively [<comment>yes</comment>]?"
))
{
- let all_required: BTreeMap<String, String> = require
+ let all_required: indexmap::IndexMap<_, _> = require
.iter()
.chain(require_dev.iter())
.map(|(k, v)| (k.clone(), v.clone()))
@@ -493,7 +493,7 @@ async fn build_interactive(
/// Returns a map of package name → version constraint selected by the user.
async fn interactive_search_packages(
label: &str,
- already_required: &BTreeMap<String, String>,
+ already_required: &indexmap::IndexMap<String, String>,
preferred_stability: Stability,
repo_cache: &mozart_core::repository::cache::Cache,
io: &std::sync::Arc<std::sync::Mutex<Box<dyn IoInterface>>>,
@@ -749,8 +749,8 @@ fn get_git_config_value(key: &str) -> Option<String> {
get_git_config().get(key).cloned().filter(|v| !v.is_empty())
}
-fn parse_requirements(reqs: &[String]) -> anyhow::Result<BTreeMap<String, String>> {
- let mut map = BTreeMap::new();
+fn parse_requirements(reqs: &[String]) -> anyhow::Result<indexmap::IndexMap<String, String>> {
+ let mut map = indexmap::IndexMap::new();
for req in reqs {
let (name, version) =
validation::parse_require_string(req).map_err(|e| anyhow::anyhow!(e))?;
@@ -761,7 +761,7 @@ fn parse_requirements(reqs: &[String]) -> anyhow::Result<BTreeMap<String, String
fn build_autoload(path: &str, package_name: &str) -> Option<RawAutoload> {
let namespace = validation::namespace_from_package_name(package_name)?;
- let mut psr4 = BTreeMap::new();
+ let mut psr4 = indexmap::IndexMap::new();
psr4.insert(format!("{namespace}\\"), path.to_string());
Some(RawAutoload { psr4 })
}
diff --git a/crates/mozart/src/commands/install.rs b/crates/mozart/src/commands/install.rs
index 54256e2..709b934 100644
--- a/crates/mozart/src/commands/install.rs
+++ b/crates/mozart/src/commands/install.rs
@@ -2,7 +2,7 @@ use clap::Args;
use indexmap::IndexSet;
use mozart_core::console::IoInterface;
use mozart_core::console_format;
-use mozart_core::package::{Package as _, RootPackage as _, RootPackageData};
+use mozart_core::package::{PackageInterface as _, RootPackage as _, RootPackageData};
use mozart_core::repository::installed;
use mozart_core::repository::installer_executor::{
Action, ExecuteContext, FilesystemExecutor, InstallerExecutor, PackageOperation,
@@ -11,7 +11,6 @@ use mozart_core::repository::installer_executor::{
locked_to_installed_entry, previously_installed_alias_versions,
};
use mozart_core::repository::lockfile;
-use std::collections::BTreeMap;
use std::path::Path;
#[derive(Args)]
@@ -212,7 +211,7 @@ fn verify_lock_platform_problems(
/// `provide` is intentionally excluded — `getNames(false)` excludes it, and
/// virtual `provide` targets allow multiple co-installed providers.
fn verify_lock_same_name_problems(lock: &lockfile::LockFile, dev_mode: bool) -> Vec<String> {
- let mut providers: BTreeMap<String, Vec<String>> = BTreeMap::new();
+ let mut providers: indexmap::IndexMap<_, Vec<_>> = indexmap::IndexMap::new();
let mut all_pkgs: Vec<&lockfile::LockedPackage> = lock.packages.iter().collect();
if dev_mode {
@@ -397,8 +396,8 @@ fn combine_platform_requirements(
root: &RootPackageData,
lock: &lockfile::LockFile,
dev_mode: bool,
-) -> BTreeMap<String, String> {
- let mut combined: BTreeMap<String, String> = BTreeMap::new();
+) -> indexmap::IndexMap<String, String> {
+ let mut combined = indexmap::IndexMap::new();
if let Some(obj) = lock.platform.as_object() {
for (name, val) in obj {
@@ -434,7 +433,7 @@ fn combine_platform_requirements(
}
fn check_platform_requirements_against(
- combined: &BTreeMap<String, String>,
+ combined: &indexmap::IndexMap<String, String>,
platform: &[mozart_core::platform::PlatformPackage],
ignore_platform_reqs: bool,
ignore_platform_req: &[String],
@@ -1081,7 +1080,6 @@ pub async fn run(
#[cfg(test)]
mod tests {
use super::*;
- use std::collections::BTreeMap;
use tempfile::tempdir;
fn make_locked_package(name: &str, version: &str) -> lockfile::LockedPackage {
@@ -1091,11 +1089,11 @@ mod tests {
version_normalized: None,
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: Some("library".to_string()),
autoload: None,
@@ -1108,7 +1106,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
@@ -1125,7 +1123,7 @@ mod tests {
aliases: vec![],
homepage: None,
support: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
@@ -1506,9 +1504,10 @@ mod tests {
#[test]
fn check_platform_requirements_reports_missing_extension() {
- let combined: BTreeMap<String, String> = [("ext-foo".to_string(), "^10".to_string())]
- .into_iter()
- .collect();
+ let combined: indexmap::IndexMap<String, String> =
+ [("ext-foo".to_string(), "^10".to_string())]
+ .into_iter()
+ .collect();
let platform = vec![pp("php", "8.2.0")];
let problems = check_platform_requirements_against(&combined, &platform, false, &[]);
@@ -1521,7 +1520,7 @@ mod tests {
#[test]
fn check_platform_requirements_reports_unsatisfied_php() {
- let combined: BTreeMap<String, String> = [("php".to_string(), "^20".to_string())]
+ let combined: indexmap::IndexMap<String, String> = [("php".to_string(), "^20".to_string())]
.into_iter()
.collect();
let platform = vec![pp("php", "8.2.0")];
@@ -1536,9 +1535,10 @@ mod tests {
#[test]
fn check_platform_requirements_satisfied_returns_empty() {
- let combined: BTreeMap<String, String> = [("php".to_string(), "^8.0".to_string())]
- .into_iter()
- .collect();
+ let combined: indexmap::IndexMap<String, String> =
+ [("php".to_string(), "^8.0".to_string())]
+ .into_iter()
+ .collect();
let platform = vec![pp("php", "8.2.0")];
let problems = check_platform_requirements_against(&combined, &platform, false, &[]);
@@ -1547,9 +1547,10 @@ mod tests {
#[test]
fn check_platform_requirements_ignore_platform_reqs_short_circuits() {
- let combined: BTreeMap<String, String> = [("ext-foo".to_string(), "^10".to_string())]
- .into_iter()
- .collect();
+ let combined: indexmap::IndexMap<String, String> =
+ [("ext-foo".to_string(), "^10".to_string())]
+ .into_iter()
+ .collect();
let platform: Vec<mozart_core::platform::PlatformPackage> = vec![];
let problems = check_platform_requirements_against(&combined, &platform, true, &[]);
@@ -1558,7 +1559,7 @@ mod tests {
#[test]
fn check_platform_requirements_specific_ignore_filters_named_packages() {
- let combined: BTreeMap<String, String> = [
+ let combined: indexmap::IndexMap<String, String> = [
("ext-foo".to_string(), "^10".to_string()),
("ext-bar".to_string(), "^10".to_string()),
]
diff --git a/crates/mozart/src/commands/licenses.rs b/crates/mozart/src/commands/licenses.rs
index 73f2018..0e4ea0b 100644
--- a/crates/mozart/src/commands/licenses.rs
+++ b/crates/mozart/src/commands/licenses.rs
@@ -4,14 +4,13 @@ use indexmap::IndexMap;
use mozart_core::console::IoInterface;
use mozart_core::console::hyperlink;
use mozart_core::console_writeln;
-use mozart_core::package::Package as _;
+use mozart_core::package::PackageInterface as _;
use mozart_core::package_info;
use mozart_core::package_info::PackageUrls;
use mozart_core::package_sorter::sort_packages_alphabetically;
use mozart_core::repository_utils;
use mozart_core::repository_utils::Required;
use serde::Serialize as _;
-use std::collections::BTreeMap;
#[derive(Args)]
pub struct LicensesArgs {
@@ -38,7 +37,7 @@ struct LicenseEntry {
name: String,
version: String,
licenses: Vec<String>,
- requires: BTreeMap<String, String>,
+ requires: indexmap::IndexMap<String, String>,
support_source: Option<String>,
source_url: Option<String>,
homepage: Option<String>,
@@ -48,7 +47,7 @@ impl Required for LicenseEntry {
fn package_name(&self) -> &str {
&self.name
}
- fn requires(&self) -> &BTreeMap<String, String> {
+ fn requires(&self) -> &indexmap::IndexMap<String, String> {
&self.requires
}
}
@@ -144,7 +143,7 @@ fn read_root_licenses(composer_json_path: &std::path::Path) -> anyhow::Result<Ve
fn load_installed_entries<V>(
working_dir: &std::path::Path,
- root_requires: &BTreeMap<String, V>,
+ root_requires: &indexmap::IndexMap<String, V>,
no_dev: bool,
) -> anyhow::Result<Vec<LicenseEntry>> {
let vendor_dir = working_dir.join("vendor");
@@ -453,7 +452,6 @@ fn tally_licenses(entries: &[LicenseEntry]) -> Vec<(String, usize)> {
#[cfg(test)]
mod tests {
use super::*;
- use std::collections::BTreeMap;
fn entry(name: &str, licenses: &[&str]) -> LicenseEntry {
LicenseEntry {
@@ -461,7 +459,7 @@ mod tests {
name: name.to_lowercase(),
version: "1.0.0".to_string(),
licenses: licenses.iter().map(|s| s.to_string()).collect(),
- requires: BTreeMap::new(),
+ requires: indexmap::IndexMap::new(),
support_source: None,
source_url: None,
homepage: None,
@@ -547,7 +545,7 @@ mod tests {
#[test]
fn installed_to_entry_extracts_require_and_license() {
use mozart_core::repository::installed::InstalledPackageEntry;
- let mut extra = BTreeMap::new();
+ let mut extra = indexmap::IndexMap::new();
extra.insert("license".to_string(), serde_json::json!(["MIT"]));
extra.insert(
"require".to_string(),
@@ -587,7 +585,7 @@ mod tests {
aliases: vec![],
homepage: Some("https://example.com/".to_string()),
support: Some(serde_json::json!({"source": "https://github.com/v/p"})),
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
};
let e = installed_to_entry(&pkg);
assert_eq!(e.support_source.as_deref(), Some("https://github.com/v/p"));
@@ -630,7 +628,7 @@ mod tests {
aliases: vec![],
homepage: None,
support: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
});
installed.upsert(mozart_core::repository::installed::InstalledPackageEntry {
name: "b/b".to_string(),
@@ -644,11 +642,11 @@ mod tests {
aliases: vec![],
homepage: None,
support: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
});
installed.write(&vendor_dir).unwrap();
- let mut root_req = BTreeMap::new();
+ let mut root_req = indexmap::IndexMap::new();
root_req.insert("a/a".to_string(), "*".to_string());
let kept = load_installed_entries(working_dir, &root_req, true).unwrap();
@@ -679,11 +677,11 @@ mod tests {
version_normalized: None,
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -696,7 +694,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}],
packages_dev: Some(vec![LockedPackage {
name: "phpunit/phpunit".to_string(),
@@ -704,11 +702,11 @@ mod tests {
version_normalized: None,
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: None,
autoload: None,
@@ -721,7 +719,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}]),
aliases: vec![],
minimum_stability: "stable".to_string(),
diff --git a/crates/mozart/src/commands/remove.rs b/crates/mozart/src/commands/remove.rs
index 5bb3be3..938a5d1 100644
--- a/crates/mozart/src/commands/remove.rs
+++ b/crates/mozart/src/commands/remove.rs
@@ -154,7 +154,7 @@ pub async fn execute(
if args.dev {
if composer.require_dev.contains_key(&name) {
console_writeln!(io, "<info>Removing {name} from require-dev</info>");
- composer.require_dev.remove(&name);
+ composer.require_dev.shift_remove(&name);
packages_removed.push(name);
} else {
io.lock().unwrap().info(&console_format!(
@@ -163,11 +163,11 @@ pub async fn execute(
}
} else if composer.require.contains_key(&name) {
console_writeln!(io, "<info>Removing {name} from require</info>");
- composer.require.remove(&name);
+ composer.require.shift_remove(&name);
packages_removed.push(name);
} else if composer.require_dev.contains_key(&name) {
console_writeln!(io, "<info>Removing {name} from require-dev</info>");
- composer.require_dev.remove(&name);
+ composer.require_dev.shift_remove(&name);
packages_removed.push(name);
} else {
io.lock().unwrap().info(&console_format!(
@@ -682,7 +682,6 @@ mod tests {
use super::*;
use mozart_core::package::RawPackageData;
use mozart_core::repository::lockfile;
- use std::collections::BTreeMap;
fn make_locked_package(name: &str, version: &str) -> lockfile::LockedPackage {
lockfile::LockedPackage {
@@ -691,11 +690,11 @@ mod tests {
version_normalized: Some(format!("{}.0", version)),
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: Some("library".to_string()),
autoload: None,
@@ -708,7 +707,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
@@ -746,7 +745,7 @@ mod tests {
assert!(composer.require.contains_key("psr/log"));
- composer.require.remove("psr/log");
+ composer.require.shift_remove("psr/log");
assert!(
!composer.require.contains_key("psr/log"),
@@ -771,7 +770,7 @@ mod tests {
assert!(composer.require_dev.contains_key("phpunit/phpunit"));
- composer.require_dev.remove("phpunit/phpunit");
+ composer.require_dev.shift_remove("phpunit/phpunit");
assert!(
!composer.require_dev.contains_key("phpunit/phpunit"),
@@ -792,8 +791,8 @@ mod tests {
.insert("psr/log".to_string(), "^3.0".to_string());
let name = "nonexistent/package";
- let found_in_require = composer.require.remove(name).is_some();
- let found_in_require_dev = composer.require_dev.remove(name).is_some();
+ let found_in_require = composer.require.shift_remove(name).is_some();
+ let found_in_require_dev = composer.require_dev.shift_remove(name).is_some();
assert!(!found_in_require);
assert!(!found_in_require_dev);
@@ -814,9 +813,9 @@ mod tests {
.insert("phpunit/phpunit".to_string(), "^11.0".to_string());
let name = "psr/log";
- let removed_from_require = composer.require.remove(name).is_some();
+ let removed_from_require = composer.require.shift_remove(name).is_some();
let removed_from_dev = if !removed_from_require {
- composer.require_dev.remove(name).is_some()
+ composer.require_dev.shift_remove(name).is_some()
} else {
false
};
@@ -842,9 +841,9 @@ mod tests {
.insert("phpunit/phpunit".to_string(), "^11.0".to_string());
let name = "phpunit/phpunit";
- let removed_from_require = composer.require.remove(name).is_some();
+ let removed_from_require = composer.require.shift_remove(name).is_some();
let removed_from_dev = if !removed_from_require {
- composer.require_dev.remove(name).is_some()
+ composer.require_dev.shift_remove(name).is_some()
} else {
false
};
@@ -894,8 +893,8 @@ mod tests {
// A glob-style name: not a valid exact package name, not in require either.
let name = "vendor/*";
- let found =
- composer.require.remove(name).is_some() || composer.require_dev.remove(name).is_some();
+ let found = composer.require.shift_remove(name).is_some()
+ || composer.require_dev.shift_remove(name).is_some();
// Should NOT be found (falls through to "not required" warning), not panicked/bailed.
assert!(!found, "glob name should not match any package");
@@ -1001,7 +1000,7 @@ mod tests {
.write_to_file(&lock_path)
.expect("should write initial lock file");
- composer.require.remove("psr/log");
+ composer.require.shift_remove("psr/log");
package::write_to_file(&composer, &composer_path).unwrap();
let request2 = ResolveRequest {
@@ -1084,7 +1083,7 @@ mod tests {
std::fs::write(&composer_path, content).unwrap();
let mut composer: RawPackageData = serde_json::from_str(content).unwrap();
- composer.require.remove("psr/log");
+ composer.require.shift_remove("psr/log");
package::write_to_file(&composer, &composer_path).unwrap();
assert!(
diff --git a/crates/mozart/src/commands/require.rs b/crates/mozart/src/commands/require.rs
index 3d5fcd6..f92442c 100644
--- a/crates/mozart/src/commands/require.rs
+++ b/crates/mozart/src/commands/require.rs
@@ -1026,9 +1026,9 @@ pub async fn execute(
// Remove from the opposite section before inserting into the target.
for pkg in &inconsistent {
if args.dev {
- raw.require.remove(pkg.as_str());
+ raw.require.shift_remove(pkg.as_str());
} else {
- raw.require_dev.remove(pkg.as_str());
+ raw.require_dev.shift_remove(pkg.as_str());
}
}
@@ -1066,10 +1066,8 @@ pub async fn execute(
let sort_packages = args.sort_packages || config_sort_packages;
if sort_packages {
- let sorted_require: std::collections::BTreeMap<_, _> = raw.require.clone();
- raw.require = sorted_require;
- let sorted_dev: std::collections::BTreeMap<_, _> = raw.require_dev.clone();
- raw.require_dev = sorted_dev;
+ raw.require.sort_unstable_keys();
+ raw.require_dev.sort_unstable_keys();
}
// --- Write composer.json (unless --dry-run) ---
@@ -1129,7 +1127,6 @@ pub async fn execute(
#[cfg(test)]
mod tests {
use super::*;
- use std::collections::BTreeMap;
fn make_locked_package(name: &str, version: &str) -> lockfile::LockedPackage {
lockfile::LockedPackage {
@@ -1138,11 +1135,11 @@ mod tests {
version_normalized: Some(format!("{}.0", version)),
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: Some("library".to_string()),
autoload: None,
@@ -1155,7 +1152,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
@@ -1176,35 +1173,6 @@ mod tests {
}
}
- /// Verify that --sort-packages sorts both require and require-dev maps.
- #[test]
- fn test_sort_packages_sorts_both_sections() {
- use mozart_core::package::RawPackageData;
-
- let mut raw = RawPackageData::new("test/project".to_string());
- raw.require
- .insert("z/package".to_string(), "^1.0".to_string());
- raw.require
- .insert("a/package".to_string(), "^2.0".to_string());
- raw.require
- .insert("m/package".to_string(), "^3.0".to_string());
- raw.require_dev
- .insert("z/dev".to_string(), "^1.0".to_string());
- raw.require_dev
- .insert("a/dev".to_string(), "^2.0".to_string());
-
- let sorted_require: BTreeMap<String, String> = raw.require.clone();
- raw.require = sorted_require;
- let sorted_dev: BTreeMap<String, String> = raw.require_dev.clone();
- raw.require_dev = sorted_dev;
-
- let require_keys: Vec<_> = raw.require.keys().collect();
- assert_eq!(require_keys, vec!["a/package", "m/package", "z/package"]);
-
- let dev_keys: Vec<_> = raw.require_dev.keys().collect();
- assert_eq!(dev_keys, vec!["a/dev", "z/dev"]);
- }
-
/// Verify that compute_update_changes produces correct Install entries for new packages.
#[test]
fn test_require_change_report_new_packages() {
diff --git a/crates/mozart/src/commands/show.rs b/crates/mozart/src/commands/show.rs
index d0a2218..81eaaad 100644
--- a/crates/mozart/src/commands/show.rs
+++ b/crates/mozart/src/commands/show.rs
@@ -6,7 +6,6 @@ use mozart_core::console_writeln;
use mozart_core::console_writeln_error;
use mozart_core::matches_wildcard;
use mozart_core::platform::is_platform_package;
-use std::collections::BTreeMap;
use std::path::Path;
#[derive(Default, Args)]
@@ -255,15 +254,15 @@ struct PackageDetail {
support: Option<serde_json::Value>,
/// A13: autoload rules.
autoload: Option<serde_json::Value>,
- require: BTreeMap<String, String>,
- require_dev: BTreeMap<String, String>,
+ require: indexmap::IndexMap<String, String>,
+ require_dev: indexmap::IndexMap<String, String>,
/// A12: conflict links.
- conflict: BTreeMap<String, String>,
+ conflict: indexmap::IndexMap<String, String>,
/// A12: provide links.
- provide: BTreeMap<String, String>,
+ provide: indexmap::IndexMap<String, String>,
/// A12: replace links.
- replace: BTreeMap<String, String>,
- suggest: BTreeMap<String, String>,
+ replace: indexmap::IndexMap<String, String>,
+ suggest: indexmap::IndexMap<String, String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -1132,7 +1131,7 @@ async fn print_package_detail(
/// Print a named section of package links (requires, conflict, etc.).
fn print_links_section(
label: &str,
- links: &BTreeMap<String, String>,
+ links: &indexmap::IndexMap<String, String>,
io: std::sync::Arc<std::sync::Mutex<Box<dyn IoInterface>>>,
) {
if links.is_empty() {
@@ -2077,7 +2076,7 @@ fn get_installed_release_date(
fn get_installed_link_map(
pkg: &mozart_core::repository::installed::InstalledPackageEntry,
key: &str,
-) -> BTreeMap<String, String> {
+) -> indexmap::IndexMap<String, String> {
pkg.extra_fields
.get(key)
.and_then(|v| v.as_object())
@@ -2092,7 +2091,7 @@ fn get_installed_link_map(
/// Extract a map of `{package: reason}` from an installed package's suggest field.
fn get_installed_suggest_map(
pkg: &mozart_core::repository::installed::InstalledPackageEntry,
-) -> BTreeMap<String, String> {
+) -> indexmap::IndexMap<String, String> {
pkg.extra_fields
.get("suggest")
.and_then(|v| v.as_object())
@@ -2268,8 +2267,7 @@ mod tests {
#[test]
fn test_get_installed_description_present() {
- use std::collections::BTreeMap;
- let mut extra = BTreeMap::new();
+ let mut extra = indexmap::IndexMap::new();
extra.insert(
"description".to_string(),
serde_json::Value::String("A logging library".to_string()),
@@ -2293,7 +2291,6 @@ mod tests {
#[test]
fn test_get_installed_description_absent() {
- use std::collections::BTreeMap;
let pkg = mozart_core::repository::installed::InstalledPackageEntry {
name: "psr/log".to_string(),
version: "3.0.0".to_string(),
@@ -2306,15 +2303,14 @@ mod tests {
aliases: vec![],
homepage: None,
support: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
};
assert_eq!(get_installed_description(&pkg), "");
}
#[test]
fn test_get_installed_keywords() {
- use std::collections::BTreeMap;
- let mut extra = BTreeMap::new();
+ let mut extra = indexmap::IndexMap::new();
extra.insert(
"keywords".to_string(),
serde_json::json!(["log", "psr3", "logging"]),
diff --git a/crates/mozart/src/commands/suggests.rs b/crates/mozart/src/commands/suggests.rs
index b882f5c..ca8e5fe 100644
--- a/crates/mozart/src/commands/suggests.rs
+++ b/crates/mozart/src/commands/suggests.rs
@@ -235,11 +235,10 @@ fn build_root_info(root: Option<&mozart_core::package::RawPackageData>) -> RootI
mod tests {
use super::*;
use mozart_core::installer::{HasSuggests, InstalledRepoLite, RootInfo};
- use std::collections::BTreeMap;
fn make_locked_package(
name: &str,
- suggest: Option<BTreeMap<String, String>>,
+ suggest: Option<indexmap::IndexMap<String, String>>,
) -> mozart_core::repository::lockfile::LockedPackage {
mozart_core::repository::lockfile::LockedPackage {
name: name.to_string(),
@@ -247,11 +246,11 @@ mod tests {
version_normalized: None,
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest,
package_type: None,
autoload: None,
@@ -264,15 +263,15 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
fn make_installed_entry(
name: &str,
- suggest: Option<BTreeMap<String, String>>,
+ suggest: Option<indexmap::IndexMap<String, String>>,
) -> mozart_core::repository::installed::InstalledPackageEntry {
- let mut extra_fields: BTreeMap<String, serde_json::Value> = BTreeMap::new();
+ let mut extra_fields = indexmap::IndexMap::new();
if let Some(s) = suggest {
let map: serde_json::Map<String, serde_json::Value> = s
.into_iter()
@@ -322,7 +321,7 @@ mod tests {
#[test]
fn locked_package_implements_has_suggests() {
- let mut suggest = BTreeMap::new();
+ let mut suggest = indexmap::IndexMap::new();
suggest.insert("ext-intl".to_string(), "for i18n".to_string());
suggest.insert("ext-redis".to_string(), "for cache".to_string());
let pkg = make_locked_package("vendor/a", Some(suggest));
@@ -333,7 +332,7 @@ mod tests {
#[test]
fn installed_entry_reads_suggest_from_extra_fields() {
- let mut suggest = BTreeMap::new();
+ let mut suggest = indexmap::IndexMap::new();
suggest.insert("ext-redis".to_string(), "for cache".to_string());
let entry = make_installed_entry("vendor/cache", Some(suggest));
let pairs = entry.suggests();
@@ -413,15 +412,15 @@ mod tests {
license: None,
authors: vec![],
minimum_stability: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
repositories: vec![],
autoload: None,
bin: vec![],
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
};
root.require.insert("vendor/a".into(), "^1.0".into());
root.require_dev.insert("vendor/b".into(), "^2.0".into());
@@ -437,7 +436,7 @@ mod tests {
let console = console();
let mut reporter = SuggestedPackagesReporter::new(&console);
- let mut suggest = BTreeMap::new();
+ let mut suggest = indexmap::IndexMap::new();
suggest.insert("ext-intl".to_string(), "for i18n".to_string());
suggest.insert("vendor/optional".to_string(), "Optional".to_string());
let pkg = make_locked_package("vendor/a", Some(suggest));
@@ -452,7 +451,7 @@ mod tests {
let console = console();
let mut reporter = SuggestedPackagesReporter::new(&console);
- let mut suggest = BTreeMap::new();
+ let mut suggest = indexmap::IndexMap::new();
suggest.insert("vendor/already-here".to_string(), "".to_string());
suggest.insert("vendor/not-here".to_string(), "".to_string());
let pkg = make_locked_package("vendor/a", Some(suggest));
diff --git a/crates/mozart/src/commands/update.rs b/crates/mozart/src/commands/update.rs
index f482272..334e221 100644
--- a/crates/mozart/src/commands/update.rs
+++ b/crates/mozart/src/commands/update.rs
@@ -1803,7 +1803,6 @@ pub async fn run(
#[cfg(test)]
mod tests {
use super::*;
- use std::collections::BTreeMap;
fn make_locked_package(name: &str, version: &str) -> lockfile::LockedPackage {
lockfile::LockedPackage {
@@ -1812,11 +1811,11 @@ mod tests {
version_normalized: Some(format!("{}.0", version)),
source: None,
dist: None,
- require: BTreeMap::new(),
- require_dev: BTreeMap::new(),
- conflict: BTreeMap::new(),
- provide: BTreeMap::new(),
- replace: BTreeMap::new(),
+ require: indexmap::IndexMap::new(),
+ require_dev: indexmap::IndexMap::new(),
+ conflict: indexmap::IndexMap::new(),
+ provide: indexmap::IndexMap::new(),
+ replace: indexmap::IndexMap::new(),
suggest: None,
package_type: Some("library".to_string()),
autoload: None,
@@ -1829,7 +1828,7 @@ mod tests {
support: None,
funding: None,
time: None,
- extra_fields: BTreeMap::new(),
+ extra_fields: indexmap::IndexMap::new(),
}
}
diff --git a/crates/mozart/src/factory.rs b/crates/mozart/src/factory.rs
index 41f157a..581b53a 100644
--- a/crates/mozart/src/factory.rs
+++ b/crates/mozart/src/factory.rs
@@ -368,7 +368,7 @@ mod tests {
r#"{"name": "acme/app", "require": {"vendor/pkg": "^1.0"}}"#,
);
- use mozart_core::package::Package;
+ use mozart_core::package::PackageInterface;
let composer = Composer::require(io(), dir.path()).unwrap();
assert_eq!(composer.package().name(), "acme/app");
assert_eq!(