use crate::types::PolicyDiagnostic;
use core_policy::Policy;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn validate_policy(policy_toml: &str) -> Result<(), JsValue> {
let _: Policy = toml::from_str(policy_toml)
.map_err(|e| JsValue::from_str(&format!("Invalid policy TOML: {}", e)))?;
Ok(())
}
#[wasm_bindgen]
pub fn validate_policy_detailed(policy_toml: &str) -> Result<JsValue, JsValue> {
let policy: Policy = match toml::from_str(policy_toml) {
Ok(p) => p,
Err(e) => {
let msg = e.to_string();
let (line, col) = parse_toml_error_position(&msg);
let diagnostic = PolicyDiagnostic {
valid: false,
message: Some(msg),
line,
column: col,
};
return Ok(serde_wasm_bindgen::to_value(&diagnostic)?);
}
};
if policy.rules().is_empty() {
let diagnostic = PolicyDiagnostic {
valid: false,
message: Some("Policy is empty: must contain at least one rule".to_string()),
line: Some(0), column: None,
};
return Ok(serde_wasm_bindgen::to_value(&diagnostic)?);
}
for (i, rule) in policy.rules().iter().enumerate() {
if rule.peer_id.is_empty() {
let diagnostic = PolicyDiagnostic {
valid: false,
message: Some(format!("Rule #{} has empty peer_id", i + 1)),
line: None, column: None,
};
return Ok(serde_wasm_bindgen::to_value(&diagnostic)?);
}
}
let diagnostic = PolicyDiagnostic {
valid: true,
message: None,
line: None,
column: None,
};
Ok(serde_wasm_bindgen::to_value(&diagnostic)?)
}
fn parse_toml_error_position(msg: &str) -> (Option<u32>, Option<u32>) {
if let Some(line_idx) = msg.find("line ") {
if let Some(col_idx) = msg.find("column ") {
let line_str = &msg[line_idx + 5..];
let line_end = line_str.find(',').unwrap_or(line_str.len());
let line = line_str[..line_end].trim().parse::<u32>().ok();
let col_str = &msg[col_idx + 7..];
let col_end = col_str
.find(|c: char| !c.is_numeric())
.unwrap_or(col_str.len());
let col = col_str[..col_end].trim().parse::<u32>().ok();
return (line, col);
}
}
(None, None)
}