forked from 1b-agent/fieldcraft-upstream
engine: refuse unknown command parameters, suggest a valid name, document heat loads and thermal materials
Every command with a schema now refuses a top-level key it does not take, naming the key and the accepted ones (#316). A bad definition name's error suggests the nearest valid one (#320). The load and material params docs list the heat loads and the thermal block. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
35ee88aa18
commit
7dd4043afe
4 files changed
+107
-4
No files matched your search
+35
-1
@@ -294,10 +294,30 @@ pub fn check_name(what: &str, name: &str) -> Result<()> {
|
||||
Ok(())
|
||||
} else {
|
||||
let shown: String = name.chars().take(MAX_NAME_LEN).collect();
|
||||
Err(Error::Invalid(format!("{what} name `{shown}` must be 1 to {MAX_NAME_LEN} characters: a letter, then letters, digits, `_` or `-`")))
|
||||
let rule = format!("{what} name `{shown}` must be 1 to {MAX_NAME_LEN} characters: a letter, then letters, digits, `_` or `-`");
|
||||
Err(Error::Invalid(match suggest_name(name) {
|
||||
Some(fixed) => format!("{rule} (try `{fixed}`)"),
|
||||
None => rule,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// The valid name closest to `name`: spaces and other characters become `_`, a leading
|
||||
/// non-letter gets an `N` before it, and it is cut to [`MAX_NAME_LEN`]. `None` when nothing of it
|
||||
/// is usable (empty, or no letter or digit at all).
|
||||
pub fn suggest_name(name: &str) -> Option<String> {
|
||||
let trimmed = name.trim();
|
||||
if !trimmed.chars().any(|c| c.is_ascii_alphanumeric()) {
|
||||
return None;
|
||||
}
|
||||
let mut fixed: String = trimmed.chars().map(|c| if c.is_ascii_alphanumeric() || c == '-' { c } else { '_' }).collect();
|
||||
if !fixed.starts_with(|c: char| c.is_ascii_alphabetic()) {
|
||||
fixed.insert(0, 'N');
|
||||
}
|
||||
fixed.truncate(MAX_NAME_LEN);
|
||||
Some(fixed)
|
||||
}
|
||||
|
||||
/// Check that a value is a finite number, naming it in the error.
|
||||
pub(crate) fn finite(what: &str, v: f64) -> Result<f64> {
|
||||
if v.is_finite() { Ok(v) } else { Err(Error::Invalid(format!("{what} must be a finite number, got {v}"))) }
|
||||
@@ -412,3 +432,17 @@ impl Model {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod name_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn a_bad_name_suggests_a_fixed_one() {
|
||||
let e = check_name("load", "Hot air").unwrap_err().to_string();
|
||||
assert!(e.contains("try `Hot_air`"), "{e}");
|
||||
assert_eq!(suggest_name("1st load"), Some("N1st_load".into()));
|
||||
assert_eq!(suggest_name(" "), None);
|
||||
assert!(check_name("load", &suggest_name(&"x ".repeat(80)).unwrap()).is_ok());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user