Menu
Public repository / master
AkurAI-Framework / crates/schema/src/error.rs
Latest change baca1a74b0ca9dcd770206285f8e51230b34d130 - feat(schema): add akurai-schema crate — JSON-shape validator for tool-UI matching by Ólafur Búi Ólafsson
//! [`SchemaError`] — a single validation failure with its JSON path and message.
use std::fmt;
/// A single validation failure.
///
/// `path` uses dot-notation for object fields (`"user.address.city"`) and
/// bracket-notation for array indices (`"tags[2]"`). The root value is
/// reported with an empty path string.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SchemaError {
/// Dot/bracket path to the offending value. Empty means the root.
pub path: String,
/// Human-readable reason.
pub message: String,
}
impl SchemaError {
pub(crate) fn new(path: impl Into<String>, message: impl Into<String>) -> Self {
Self {
path: path.into(),
message: message.into(),
}
}
/// Prepend a parent segment to the path.
pub(crate) fn prepend(mut self, segment: &str) -> Self {
if self.path.is_empty() {
self.path = segment.to_owned();
} else if self.path.starts_with('[') {
// array index — attach directly: "items[0]"
self.path = format!("{segment}{}", self.path);
} else {
self.path = format!("{segment}.{}", self.path);
}
self
}
}
impl fmt::Display for SchemaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.path.is_empty() {
write!(f, "{}", self.message)
} else {
write!(f, "{}: {}", self.path, self.message)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_with_path() {
let e = SchemaError::new("user.name", "expected string");
assert_eq!(e.to_string(), "user.name: expected string");
}
#[test]
fn display_without_path() {
let e = SchemaError::new("", "expected object");
assert_eq!(e.to_string(), "expected object");
}
#[test]
fn prepend_field_to_empty() {
let e = SchemaError::new("", "expected string").prepend("name");
assert_eq!(e.path, "name");
}
#[test]
fn prepend_field_to_existing() {
let e = SchemaError::new("city", "expected string").prepend("address");
assert_eq!(e.path, "address.city");
}
#[test]
fn prepend_array_index() {
let e = SchemaError::new("[1]", "expected string").prepend("tags");
assert_eq!(e.path, "tags[1]");
}
}