aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart/src
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-05 19:38:29 +0900
committernsfisis <nsfisis@gmail.com>2026-05-05 19:38:29 +0900
commit884d9ab32bbca7a8ec5c7ee7d42cbde0e7e6babf (patch)
treee04e25f506f0174572b4634601ab9b317220d9e5 /crates/mozart/src
parent49b0884701a84731652fc934d428932ff6029bd4 (diff)
downloadphp-mozart-884d9ab32bbca7a8ec5c7ee7d42cbde0e7e6babf.tar.gz
php-mozart-884d9ab32bbca7a8ec5c7ee7d42cbde0e7e6babf.tar.zst
php-mozart-884d9ab32bbca7a8ec5c7ee7d42cbde0e7e6babf.zip
refactor(core): replace ComposerConfig with typed Config struct
Config uses serde with kebab-case field mapping; known properties are strongly-typed fields and unknown keys flow into an extra BTreeMap. resolve_references is moved to the new config module.
Diffstat (limited to 'crates/mozart/src')
-rw-r--r--crates/mozart/src/commands/archive.rs13
-rw-r--r--crates/mozart/src/commands/config.rs139
-rw-r--r--crates/mozart/src/commands/dump_autoload.rs20
-rw-r--r--crates/mozart/src/commands/exec.rs7
-rw-r--r--crates/mozart/src/commands/run_script.rs21
5 files changed, 71 insertions, 129 deletions
diff --git a/crates/mozart/src/commands/archive.rs b/crates/mozart/src/commands/archive.rs
index a075ade..4386e16 100644
--- a/crates/mozart/src/commands/archive.rs
+++ b/crates/mozart/src/commands/archive.rs
@@ -104,15 +104,10 @@ pub async fn execute(
let (config_archive_format, config_archive_dir) = match composer.as_ref() {
Some(c) => {
let cfg = c.config();
- let fmt = cfg
- .get("archive-format")
- .and_then(|v| v.as_str())
- .map(|s| s.to_string());
- let dir = cfg
- .get("archive-dir")
- .and_then(|v| v.as_str())
- .map(|s| s.to_string());
- (fmt, dir)
+ (
+ Some(cfg.archive_format.clone()),
+ Some(cfg.archive_dir.clone()),
+ )
}
None => (None, None),
};
diff --git a/crates/mozart/src/commands/config.rs b/crates/mozart/src/commands/config.rs
index 71a5981..40336f3 100644
--- a/crates/mozart/src/commands/config.rs
+++ b/crates/mozart/src/commands/config.rs
@@ -60,7 +60,7 @@ pub struct ConfigArgs {
pub source: bool,
}
-pub use mozart_core::composer::{ComposerConfig, resolve_references};
+use mozart_core::config::{Config, resolve_references};
/// Classification of config key value types for validation and normalization.
#[derive(Debug)]
@@ -754,17 +754,17 @@ fn execute_read(
console: &mozart_core::console::Console,
) -> anyhow::Result<()> {
// Build the effective config for config-section keys.
- let mut config = ComposerConfig::defaults();
+ let mut config = Config::default();
if args.global {
let global_config_path = composer_home().join("config.json");
let overrides = load_config_section(&global_config_path)?;
- config.merge(&overrides);
+ config.merge(&overrides)?;
} else {
let wd = cli.working_dir()?;
let composer_json = wd.join("composer.json");
let overrides = load_config_section(&composer_json)?;
- config.merge(&overrides);
+ config.merge(&overrides)?;
}
resolve_references(&mut config);
@@ -772,27 +772,13 @@ fn execute_read(
// If --absolute is requested, resolve *-dir values to absolute paths.
if args.absolute {
let wd = cli.working_dir()?;
- let keys: Vec<String> = config.values.keys().cloned().collect();
- for key in keys {
- if key.ends_with("-dir")
- && let Some(serde_json::Value::String(s)) = config.values.get(&key).cloned()
- {
- let p = std::path::Path::new(&s);
- if p.is_relative() {
- let abs = wd.join(p);
- config.values.insert(
- key,
- serde_json::Value::String(abs.to_string_lossy().into_owned()),
- );
- }
- }
- }
+ config.make_dirs_absolute(&wd);
}
if args.list {
- for (key, value) in &config.values {
+ for (key, value) in config.entries() {
console.write_stdout(
- &format!("[{}] {}", key, render_value(value)),
+ &format!("[{}] {}", key, render_value(&value)),
mozart_core::console::Verbosity::Quiet,
);
}
@@ -853,8 +839,10 @@ fn execute_read(
// 4. Standard config key lookup
match config.get(key) {
Some(value) => {
- console
- .write_stdout(&render_value(value), mozart_core::console::Verbosity::Quiet);
+ console.write_stdout(
+ &render_value(&value),
+ mozart_core::console::Verbosity::Quiet,
+ );
}
None => {
return Err(anyhow!("Setting \"{}\" does not exist.", key));
@@ -872,7 +860,7 @@ mod tests {
#[test]
fn test_defaults_contain_expected_keys() {
- let cfg = ComposerConfig::defaults();
+ let cfg = Config::default();
let required_keys = [
"process-timeout",
@@ -908,127 +896,109 @@ mod tests {
];
for key in &required_keys {
- assert!(cfg.values.contains_key(*key), "defaults missing key: {key}");
+ assert!(cfg.get(*key).is_some(), "defaults missing key: {key}");
}
}
#[test]
fn test_defaults_values_correct() {
- let cfg = ComposerConfig::defaults();
+ let cfg = Config::default();
- assert_eq!(cfg.values["process-timeout"], serde_json::json!(300));
- assert_eq!(cfg.values["preferred-install"], serde_json::json!("dist"));
- assert_eq!(cfg.values["vendor-dir"], serde_json::json!("vendor"));
- assert_eq!(
- cfg.values["github-protocols"],
- serde_json::json!(["https", "ssh", "git"])
- );
- assert_eq!(cfg.values["secure-http"], serde_json::json!(true));
- assert_eq!(cfg.values["lock"], serde_json::json!(true));
- assert_eq!(cfg.values["autoloader-suffix"], serde_json::Value::Null);
+ assert_eq!(cfg.process_timeout, 300);
+ assert_eq!(cfg.preferred_install, serde_json::json!("dist"));
+ assert_eq!(cfg.vendor_dir, "vendor");
+ assert_eq!(cfg.github_protocols, vec!["https", "ssh", "git"]);
+ assert_eq!(cfg.secure_http, true);
+ assert_eq!(cfg.lock, true);
+ assert_eq!(cfg.autoloader_suffix, None);
}
#[test]
fn test_merge_overrides_existing_key() {
- let mut cfg = ComposerConfig::defaults();
+ let mut cfg = Config::default();
let mut overrides = BTreeMap::new();
overrides.insert("vendor-dir".to_string(), serde_json::json!("packages"));
overrides.insert("sort-packages".to_string(), serde_json::json!(true));
- cfg.merge(&overrides);
+ cfg.merge(&overrides).unwrap();
- assert_eq!(cfg.values["vendor-dir"], serde_json::json!("packages"));
- assert_eq!(cfg.values["sort-packages"], serde_json::json!(true));
+ assert_eq!(cfg.vendor_dir, "packages");
+ assert_eq!(cfg.sort_packages, true);
}
#[test]
fn test_merge_adds_new_key() {
- let mut cfg = ComposerConfig::defaults();
+ let mut cfg = Config::default();
let mut overrides = BTreeMap::new();
overrides.insert("custom-key".to_string(), serde_json::json!("custom-value"));
- cfg.merge(&overrides);
+ cfg.merge(&overrides).unwrap();
- assert_eq!(cfg.values["custom-key"], serde_json::json!("custom-value"));
+ assert_eq!(cfg.extra["custom-key"], serde_json::json!("custom-value"));
}
#[test]
fn test_merge_empty_overrides_leaves_defaults_intact() {
- let mut cfg = ComposerConfig::defaults();
- let original_vendor = cfg.values["vendor-dir"].clone();
+ let mut cfg = Config::default();
+ let original_vendor = cfg.vendor_dir.clone();
- cfg.merge(&BTreeMap::new());
+ cfg.merge(&BTreeMap::new()).unwrap();
- assert_eq!(cfg.values["vendor-dir"], original_vendor);
+ assert_eq!(cfg.vendor_dir, original_vendor);
}
#[test]
fn test_reference_resolution_bin_dir() {
- let mut cfg = ComposerConfig::defaults();
+ let mut cfg = Config::default();
// bin-dir default is "{$vendor-dir}/bin"; vendor-dir default is "vendor"
resolve_references(&mut cfg);
- assert_eq!(cfg.values["bin-dir"], serde_json::json!("vendor/bin"));
+ assert_eq!(cfg.bin_dir, "vendor/bin");
}
#[test]
fn test_reference_resolution_custom_vendor_dir() {
- let mut cfg = ComposerConfig::defaults();
+ let mut cfg = Config::default();
- // Override vendor-dir before resolving
- cfg.values
- .insert("vendor-dir".to_string(), serde_json::json!("lib"));
+ cfg.vendor_dir = "lib".to_string();
resolve_references(&mut cfg);
- assert_eq!(cfg.values["bin-dir"], serde_json::json!("lib/bin"));
+ assert_eq!(cfg.bin_dir, "lib/bin");
}
#[test]
fn test_reference_resolution_cache_dirs() {
- let mut cfg = ComposerConfig::defaults();
+ let mut cfg = Config::default();
// Inject a predictable home so the test is environment-independent.
- cfg.values.insert(
- "cache-dir".to_string(),
- serde_json::json!("/home/user/.cache/composer"),
- );
+ cfg.cache_dir = "/home/user/.cache/composer".to_string();
resolve_references(&mut cfg);
- assert_eq!(
- cfg.values["cache-files-dir"],
- serde_json::json!("/home/user/.cache/composer/files")
- );
- assert_eq!(
- cfg.values["cache-repo-dir"],
- serde_json::json!("/home/user/.cache/composer/repo")
- );
- assert_eq!(
- cfg.values["cache-vcs-dir"],
- serde_json::json!("/home/user/.cache/composer/vcs")
- );
+ assert_eq!(cfg.cache_files_dir, "/home/user/.cache/composer/files");
+ assert_eq!(cfg.cache_repo_dir, "/home/user/.cache/composer/repo");
+ assert_eq!(cfg.cache_vcs_dir, "/home/user/.cache/composer/vcs");
}
#[test]
fn test_reference_resolution_no_change_for_non_string() {
- let mut cfg = ComposerConfig::defaults();
- let before = cfg.values["process-timeout"].clone();
+ let mut cfg = Config::default();
+ let before = cfg.process_timeout;
resolve_references(&mut cfg);
- // Numeric values should be untouched.
- assert_eq!(cfg.values["process-timeout"], before);
+ assert_eq!(cfg.process_timeout, before);
}
#[test]
fn test_get_existing_key() {
- let cfg = ComposerConfig::defaults();
+ let cfg = Config::default();
let value = cfg.get("vendor-dir");
assert!(value.is_some());
- assert_eq!(value.unwrap(), &serde_json::json!("vendor"));
+ assert_eq!(value.unwrap(), serde_json::json!("vendor"));
}
#[test]
fn test_get_nonexistent_key_returns_none() {
- let cfg = ComposerConfig::defaults();
+ let cfg = Config::default();
assert!(cfg.get("does-not-exist").is_none());
}
@@ -1118,17 +1088,14 @@ mod tests {
.unwrap();
let overrides = load_config_section(&composer_json).unwrap();
- let mut cfg = ComposerConfig::defaults();
- cfg.merge(&overrides);
+ let mut cfg = Config::default();
+ cfg.merge(&overrides).unwrap();
resolve_references(&mut cfg);
- assert_eq!(cfg.values["vendor-dir"], serde_json::json!("custom_vendor"));
- assert_eq!(cfg.values["sort-packages"], serde_json::json!(true));
+ assert_eq!(cfg.vendor_dir, "custom_vendor");
+ assert_eq!(cfg.sort_packages, true);
// bin-dir should have resolved against the overridden vendor-dir
- assert_eq!(
- cfg.values["bin-dir"],
- serde_json::json!("custom_vendor/bin")
- );
+ assert_eq!(cfg.bin_dir, "custom_vendor/bin");
}
#[test]
diff --git a/crates/mozart/src/commands/dump_autoload.rs b/crates/mozart/src/commands/dump_autoload.rs
index c7af429..a86cf21 100644
--- a/crates/mozart/src/commands/dump_autoload.rs
+++ b/crates/mozart/src/commands/dump_autoload.rs
@@ -78,23 +78,11 @@ pub async fn execute(
}
}
- let optimize = args.optimize
- || composer_config
- .get("optimize-autoloader")
- .and_then(|v| v.as_bool())
- .unwrap_or(false);
- let classmap_authoritative = args.classmap_authoritative
- || composer_config
- .get("classmap-authoritative")
- .and_then(|v| v.as_bool())
- .unwrap_or(false);
+ let optimize = args.optimize || composer_config.optimize_autoloader;
+ let classmap_authoritative =
+ args.classmap_authoritative || composer_config.classmap_authoritative;
let apcu_prefix = args.apcu_prefix.clone();
- let apcu = apcu_prefix.is_some()
- || args.apcu
- || composer_config
- .get("apcu-autoloader")
- .and_then(|v| v.as_bool())
- .unwrap_or(false);
+ let apcu = apcu_prefix.is_some() || args.apcu || composer_config.apcu_autoloader;
let do_optimize = optimize || classmap_authoritative;
if args.strict_psr && !do_optimize {
diff --git a/crates/mozart/src/commands/exec.rs b/crates/mozart/src/commands/exec.rs
index f802721..9d79bee 100644
--- a/crates/mozart/src/commands/exec.rs
+++ b/crates/mozart/src/commands/exec.rs
@@ -117,12 +117,7 @@ pub async fn execute(
fn resolve_bin_dir(working_dir: &Path, composer: &Composer) -> PathBuf {
// bin-dir's `{$vendor-dir}` placeholder is already resolved by Composer::load.
- let bin_dir = composer
- .config()
- .get("bin-dir")
- .and_then(|v| v.as_str())
- .unwrap_or("vendor/bin");
- working_dir.join(bin_dir)
+ working_dir.join(&composer.config().bin_dir)
}
/// Returns a vec of (name, is_local) tuples for all available binaries.
diff --git a/crates/mozart/src/commands/run_script.rs b/crates/mozart/src/commands/run_script.rs
index 4292809..7e5cbe4 100644
--- a/crates/mozart/src/commands/run_script.rs
+++ b/crates/mozart/src/commands/run_script.rs
@@ -110,12 +110,14 @@ pub async fn execute(
let timeout = match args.timeout {
Some(0) => None,
Some(secs) => Some(Duration::from_secs(secs)),
- None => composer
- .config()
- .get("process-timeout")
- .and_then(|v| v.as_u64())
- .filter(|s| *s != 0)
- .map(Duration::from_secs),
+ None => {
+ let t = composer.config().process_timeout;
+ if t != 0 {
+ Some(Duration::from_secs(t))
+ } else {
+ None
+ }
+ }
};
let dev_mode = !args.no_dev;
@@ -445,12 +447,7 @@ fn wait_with_timeout(
fn resolve_bin_dir(working_dir: &Path, composer: &mozart_core::composer::Composer) -> PathBuf {
// bin-dir's `{$vendor-dir}` placeholder is already resolved by Composer::load.
- let bin_dir = composer
- .config()
- .get("bin-dir")
- .and_then(|v| v.as_str())
- .unwrap_or("vendor/bin");
- working_dir.join(bin_dir)
+ working_dir.join(&composer.config().bin_dir)
}
fn is_php_callback(entry: &str) -> bool {