fix(effect): expose parameter metadata in effect.list (#441)

This commit is contained in:
Nigel Ihza Firdausy 2026-10-10 23:41:07 +07:00
parent 1446e27d85
commit 4df4d9185b
1 changed files with 49 additions and 2 deletions

View File

@ -415,7 +415,24 @@ fn list(_: &mut Session, p: &Value) -> Result<Value> {
filter.as_ref().is_none_or(|f| effectcraft_effects::name_matches(e, f) || e.id.contains(f.as_str()) || e.category.to_ascii_lowercase().contains(f))
})
.map(|e| {
json!({"id": e.id, "name": e.name, "category": e.category, "gpu": e.gpu, "float": e.float, "params": e.params.iter().map(|p| json!({"id": p.id, "name": p.name, "default": p.default.to_json()})).collect::<Vec<_>>()})
json!({"id": e.id, "name": e.name, "category": e.category, "gpu": e.gpu, "float": e.float, "params": e.params.iter().map(|p| {
let mut out = json!({"id": p.id, "name": p.name, "type": p.default.kind_name(), "default": p.default.to_json()});
match &p.ui {
effectcraft_project::ParamUi::Popup { options } => {
// Engine/MCP popup values are zero-based; JSX exposes one-based values.
out["options"] = json!(options.iter().enumerate().map(|(value, label)| json!({"value": value, "label": label})).collect::<Vec<_>>());
}
effectcraft_project::ParamUi::Slider { min, max, slider_min, slider_max, decimals } => {
out["min"] = json!(min);
out["max"] = json!(max);
out["sliderMin"] = json!(slider_min);
out["sliderMax"] = json!(slider_max);
out["decimals"] = json!(decimals);
}
_ => {}
}
out
}).collect::<Vec<_>>()})
})
.collect();
Ok(json!(v))
@ -469,7 +486,7 @@ pub fn specs() -> Vec<CommandSpec> {
cmd!("effect.copy", "Copy Effects", [], None, "{layer?, effect? | effects?: [uid|name|index]} (default: the selected effects)", has_layers, copy),
cmd!("effect.paste", "Paste Effects", [], None, "{layers?} — adds the copied effects to the layers", has_layers, paste),
cmd!("effect.reset", "Reset Effect", [], None, "{layer?, effect}", has_layers, reset),
crate::query!("effect.list", "List Effects", "{filter?}", list),
crate::query!("effect.list", "List Effects", "{filter?} → [{params: [{id, name, type, default, options?, min?, max?, sliderMin?, sliderMax?, decimals?}]}]; popup indices are zero-based (JSX uses one-based values)", list),
crate::query!(
"effect.warning",
"Effect Warning",
@ -493,3 +510,33 @@ pub fn specs() -> Vec<CommandSpec> {
),
]
}
#[cfg(test)]
mod list_metadata_tests {
use super::*;
#[test]
fn effect_list_exposes_popup_labels_and_numeric_slider_limits() {
let mut s = Session::default();
let menus = s.execute("effect.list", json!({"filter": "ec.control.dropdown"})).unwrap();
assert_eq!(menus.as_array().map(Vec::len), Some(1));
let menu = &menus[0]["params"][0];
assert_eq!(menu["type"], "enum");
assert_eq!(menu["default"], 0);
assert_eq!(menu["options"], json!([
{"value": 0, "label": "Item 1"},
{"value": 1, "label": "Item 2"},
{"value": 2, "label": "Item 3"}
]));
let sliders = s.execute("effect.list", json!({"filter": "ec.control.slider"})).unwrap();
assert_eq!(sliders.as_array().map(Vec::len), Some(1));
let slider = &sliders[0]["params"][0];
assert_eq!(slider["type"], "scalar");
assert_eq!(slider["min"], -1_000_000.0);
assert_eq!(slider["max"], 1_000_000.0);
assert_eq!(slider["sliderMin"], 0.0);
assert_eq!(slider["sliderMax"], 100.0);
assert_eq!(slider["decimals"], 2);
assert!(slider["options"].is_null());
}
}