aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart/src/commands/validate.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-22 22:14:10 +0900
committernsfisis <nsfisis@gmail.com>2026-02-22 22:14:10 +0900
commit1d33728151b282949e7e14646e722d7775de4453 (patch)
treea011da3218b60bfbb8a539c2bcc7ff99bce87124 /crates/mozart/src/commands/validate.rs
parent0833b8972c20e48dd33e9f985cd225e4a9abf5e2 (diff)
downloadphp-mozart-1d33728151b282949e7e14646e722d7775de4453.tar.gz
php-mozart-1d33728151b282949e7e14646e722d7775de4453.tar.zst
php-mozart-1d33728151b282949e7e14646e722d7775de4453.zip
fix(validate): use CamelCase-to-dash name suggestion and propagate dependency exit codes
- Replace simple to_lowercase() with sanitize_package_name_component() for uppercase name suggestions (e.g. MyCompany/MyLibrary → my-company/my-library) - Return error/warning counts from validate_dependencies() and merge them into the final exit code, matching Composer behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'crates/mozart/src/commands/validate.rs')
-rw-r--r--crates/mozart/src/commands/validate.rs43
1 files changed, 36 insertions, 7 deletions
diff --git a/crates/mozart/src/commands/validate.rs b/crates/mozart/src/commands/validate.rs
index 49fdc9a..2cd460c 100644
--- a/crates/mozart/src/commands/validate.rs
+++ b/crates/mozart/src/commands/validate.rs
@@ -135,23 +135,34 @@ pub async fn execute(
output_result(&file, &result, check_publish, check_lock, &lock_errors);
// Validate dependencies' composer.json files
- if args.with_dependencies {
+ let (dep_errors, dep_warnings) = if args.with_dependencies {
let vendor_dir = file.parent().unwrap_or(Path::new(".")).join("vendor");
if vendor_dir.exists() {
- validate_dependencies(&vendor_dir, args, console);
+ validate_dependencies(&vendor_dir, args, console)
} else {
console
.info("No vendor directory found. Run `mozart install` to install dependencies.");
+ (0, 0)
}
- }
+ } else {
+ (0, 0)
+ };
- let exit_code = compute_exit_code(
+ let mut exit_code = compute_exit_code(
&result,
&lock_errors,
check_publish,
check_lock,
args.strict,
);
+
+ // Merge dependency validation results into exit code (matching Composer behavior)
+ if dep_errors > 0 {
+ exit_code = exit_code.max(2);
+ } else if dep_warnings > 0 && args.strict {
+ exit_code = exit_code.max(1);
+ }
+
if exit_code != 0 {
return Err(mozart_core::exit_code::bail_silent(exit_code));
}
@@ -205,7 +216,11 @@ fn check_name(obj: &serde_json::Map<String, serde_json::Value>, result: &mut Val
Some(name) => {
// Uppercase characters are a publish error
if name.chars().any(|c| c.is_ascii_uppercase()) {
- let suggested = name.to_lowercase();
+ let suggested = name
+ .split('/')
+ .map(mozart_core::validation::sanitize_package_name_component)
+ .collect::<Vec<_>>()
+ .join("/");
result.publish_errors.push(format!(
"Name \"{name}\" does not match the best practice (e.g. lower-cased/with-dashes). \
We suggest using \"{suggested}\" instead. As such you will not be able to submit it to Packagist."
@@ -386,14 +401,14 @@ fn validate_dependencies(
vendor_dir: &Path,
args: &ValidateArgs,
console: &mozart_core::console::Console,
-) {
+) -> (u32, u32) {
let mut dep_errors = 0u32;
let mut dep_warnings = 0u32;
let mut dep_count = 0u32;
// Walk vendor/<vendor>/<package>/composer.json
let Ok(vendors) = std::fs::read_dir(vendor_dir) else {
- return;
+ return (0, 0);
};
for vendor_entry in vendors.flatten() {
@@ -474,6 +489,8 @@ fn validate_dependencies(
dep_warnings
));
}
+
+ (dep_errors, dep_warnings)
}
// ─── Lock file freshness ─────────────────────────────────────────────────────
@@ -704,6 +721,18 @@ mod tests {
}
#[test]
+ fn test_validate_uppercase_name_camel_case_to_dashes() {
+ let json = r#"{"name": "MyCompany/MyLibrary", "license": "MIT"}"#;
+ let result = parse_and_validate(json, &make_args());
+ assert!(!result.publish_errors.is_empty());
+ assert!(
+ result.publish_errors[0].contains("my-company/my-library"),
+ "expected CamelCase-to-dashes conversion, got: {}",
+ result.publish_errors[0]
+ );
+ }
+
+ #[test]
fn test_validate_valid_name_no_publish_error() {
let json = r#"{"name": "vendor/package", "license": "MIT"}"#;
let result = parse_and_validate(json, &make_args());