Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
// Keep ASCII letters and digits only, then uppercase. Filtering first matters:
// "ß".to_uppercase() is "SS", which would make the SKU depend on how each
// language's Unicode tables treat one letter.
fn clean(part: &str) -> String {
part.chars()
.filter(|c| c.is_ascii_alphanumeric())
.map(|c| c.to_ascii_uppercase())
.collect()
}
/// A deterministic SKU: the cleaned prefix and attributes, joined by hyphens.
/// Each attribute is cut to `segment_length` characters (0 keeps it whole).
///
/// # Panics
/// Panics on a negative segment length, no attributes, or a part with no
/// letters or digits.
pub fn generate_sku(prefix: &str, attributes: &[String], segment_length: i64) -> String {
if segment_length < 0 {
panic!("segmentLength must be 0 or more, received {}", segment_length);
}
if attributes.is_empty() {
panic!("a SKU needs at least one attribute");
}
let mut parts: Vec<String> = Vec::new();
if !prefix.is_empty() {
let cleaned = clean(prefix);
if cleaned.is_empty() {
panic!("prefix (\"{}\") has no letters or digits", prefix);
}
parts.push(cleaned);
}
for (index, attribute) in attributes.iter().enumerate() {
let cleaned = clean(attribute);
if cleaned.is_empty() {
panic!(
"attribute {} (\"{}\") has no letters or digits",
index + 1,
attribute
);
}
// Cleaned text is ASCII, so byte length is character count.
if segment_length > 0 && cleaned.len() > segment_length as usize {
parts.push(cleaned[..segment_length as usize].to_string());
} else {
parts.push(cleaned);
}
}
parts.join("-")
}
pub fn fune_vector(args: &[Value]) -> Value {
let attributes: Vec<String> = args[1]
.as_arr()
.iter()
.map(|v| v.as_str().to_string())
.collect();
Value::Str(generate_sku(args[0].as_str(), &attributes, args[2].as_i64()))
}