1mod fafb_json;
23
24use wasm_bindgen::prelude::*;
25
26#[wasm_bindgen]
28pub fn sdk_version() -> String {
29 env!("CARGO_PKG_VERSION").to_string()
30}
31
32#[wasm_bindgen]
34pub fn score_faf(yaml: String) -> Result<String, JsValue> {
35 faf_kernel::score(&yaml)
36 .map(|r| r.to_json())
37 .map_err(|e| JsValue::from_str(&e))
38}
39
40#[wasm_bindgen]
42pub fn validate_faf(yaml: String) -> bool {
43 use serde_yaml_ng::Value;
44 matches!(
45 serde_yaml_ng::from_str::<Value>(&yaml),
46 Ok(Value::Mapping(_))
47 )
48}
49
50#[wasm_bindgen]
52pub fn compile_fafb(yaml: String) -> Result<Vec<u8>, JsValue> {
53 fafb_json::compile_fafb(&yaml).map_err(|e| JsValue::from_str(&e))
54}
55
56#[wasm_bindgen]
58pub fn decompile_fafb(bytes: &[u8]) -> Result<String, JsValue> {
59 fafb_json::decompile_fafb(bytes).map_err(|e| JsValue::from_str(&e))
60}
61
62#[wasm_bindgen]
64pub fn score_fafb(bytes: &[u8]) -> Result<String, JsValue> {
65 fafb_json::score_fafb(bytes).map_err(|e| JsValue::from_str(&e))
66}
67
68#[wasm_bindgen]
70pub fn fafb_info(bytes: &[u8]) -> Result<String, JsValue> {
71 fafb_json::fafb_info(bytes).map_err(|e| JsValue::from_str(&e))
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_sdk_version_is_3x() {
80 assert!(sdk_version().starts_with("3."));
81 }
82
83 #[test]
84 fn test_validate_faf_accepts_mapping() {
85 assert!(validate_faf("project:\n name: test".to_string()));
86 }
87
88 #[test]
89 fn test_validate_faf_rejects_non_mapping() {
90 assert!(!validate_faf("just a string".to_string()));
91 assert!(!validate_faf("- list\n- items".to_string()));
92 assert!(!validate_faf("42".to_string()));
93 }
94
95 #[test]
96 fn test_validate_faf_rejects_broken_yaml() {
97 assert!(!validate_faf("[invalid: yaml: {{{".to_string()));
98 }
99
100 #[test]
101 fn test_score_faf_is_always_33() {
102 let result = score_faf("project:\n name: test".to_string()).unwrap();
104 assert!(result.contains("\"score\":"));
105 assert!(result.contains("\"tier\":"));
106 assert!(result.contains("\"total\":33"));
107 }
108
109 #[test]
110 fn test_canonical_tiers_not_medals() {
111 let result = score_faf("project:\n name: test".to_string()).unwrap();
113 assert!(!result.contains("🥇") && !result.contains("🥈") && !result.contains("🥉"));
114 }
115
116 #[test]
117 fn test_compile_decompile_fafb_roundtrip_v2() {
118 let yaml = "faf_version: 2.5.0\nproject:\n name: test\n".to_string();
119 let bytes = compile_fafb(yaml).unwrap();
120 assert_eq!(&bytes[0..4], b"FAFB");
121 assert_eq!(bytes[4], 2); let json = decompile_fafb(&bytes).unwrap();
123 assert!(json.contains("\"sections\":"));
124 assert!(json.contains("\"version\":\"2.0\""));
125 }
126
127 #[test]
128 fn test_score_fafb_from_compiled() {
129 let yaml = "faf_version: 2.5.0\nproject:\n name: test\n".to_string();
130 let bytes = compile_fafb(yaml).unwrap();
131 let score = score_fafb(&bytes).unwrap();
132 assert!(score.contains("\"score\":"));
133 assert!(score.contains("\"total\":33"));
134 }
135
136 #[test]
137 fn test_fafb_info_from_compiled() {
138 let yaml = "faf_version: 2.5.0\nproject:\n name: test\n".to_string();
139 let bytes = compile_fafb(yaml).unwrap();
140 let info = fafb_info(&bytes).unwrap();
141 assert!(info.contains("\"section_count\":"));
142 assert!(!info.contains("\"content\":"));
143 }
144}