1use std::collections::HashMap;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum Severity {
6 Error,
7 Warning,
8}
9
10impl Severity {
11 pub fn as_str(&self) -> &'static str {
12 match self {
13 Severity::Error => "error",
14 Severity::Warning => "warning",
15 }
16 }
17}
18
19struct ErrorRegistryEntry {
20 severity: Severity,
21 message_template: &'static str,
22}
23
24fn error_registry() -> HashMap<&'static str, ErrorRegistryEntry> {
27 let mut m = HashMap::new();
28 m.insert(
29 "E001",
30 ErrorRegistryEntry {
31 severity: Severity::Error,
32 message_template: "Type mismatch: expected {expected}, got {actual}",
33 },
34 );
35 m.insert(
36 "E002",
37 ErrorRegistryEntry {
38 severity: Severity::Error,
39 message_template: "Required property \"{property}\" is missing",
40 },
41 );
42 m.insert(
43 "E003",
44 ErrorRegistryEntry {
45 severity: Severity::Error,
46 message_template: "Additional property \"{property}\" is not allowed",
47 },
48 );
49 m.insert(
50 "E004",
51 ErrorRegistryEntry {
52 severity: Severity::Error,
53 message_template: "String constraint violation: {constraint}",
54 },
55 );
56 m.insert(
57 "E005",
58 ErrorRegistryEntry {
59 severity: Severity::Error,
60 message_template: "Number constraint violation: {constraint}",
61 },
62 );
63 m.insert(
64 "E006",
65 ErrorRegistryEntry {
66 severity: Severity::Error,
67 message_template: "Array constraint violation: {constraint}",
68 },
69 );
70 m.insert(
71 "E007",
72 ErrorRegistryEntry {
73 severity: Severity::Error,
74 message_template: "Object constraint violation: {constraint}",
75 },
76 );
77 m.insert(
78 "E008",
79 ErrorRegistryEntry {
80 severity: Severity::Error,
81 message_template: "Format validation failed: expected {format}, got \"{value}\"",
82 },
83 );
84 m.insert(
85 "E009",
86 ErrorRegistryEntry {
87 severity: Severity::Error,
88 message_template: "Value {value} does not match {constraint}",
89 },
90 );
91 m.insert(
92 "E010",
93 ErrorRegistryEntry {
94 severity: Severity::Error,
95 message_template: "Composition constraint \"{keyword}\" not satisfied",
96 },
97 );
98 m.insert(
99 "E011",
100 ErrorRegistryEntry {
101 severity: Severity::Error,
102 message_template: "Failed to resolve $ref: \"{ref}\"",
103 },
104 );
105 m.insert(
106 "E012",
107 ErrorRegistryEntry {
108 severity: Severity::Error,
109 message_template: "Invalid protocol: {reason}",
110 },
111 );
112 m.insert(
113 "W001",
114 ErrorRegistryEntry {
115 severity: Severity::Warning,
116 message_template: "Field \"{field}\" is deprecated: {reason}",
117 },
118 );
119 m.insert(
120 "W002",
121 ErrorRegistryEntry {
122 severity: Severity::Warning,
123 message_template: "Unknown extension property: \"{property}\"",
124 },
125 );
126 m
127}
128
129fn format_template(template: &str, context: &HashMap<&str, String>) -> String {
132 let mut result = template.to_string();
133 for (key, value) in context {
134 let placeholder = format!("{{{}}}", key);
135 result = result.replace(&placeholder, value);
136 }
137 result
138}
139
140use crate::types::ValidationError;
141
142pub fn create_error(code: &str, path: &str, context: HashMap<&str, String>) -> ValidationError {
145 let registry = error_registry();
146 match registry.get(code) {
147 Some(entry) => ValidationError {
148 code: code.to_string(),
149 path: path.to_string(),
150 message: format_template(entry.message_template, &context),
151 severity: entry.severity.as_str().to_string(),
152 suggestion: None,
153 },
154 None => ValidationError {
155 code: code.to_string(),
156 path: path.to_string(),
157 message: format!("Unknown error code: {}", code),
158 severity: "error".to_string(),
159 suggestion: None,
160 },
161 }
162}