citum_engine/api/
warnings.rs1use crate::processor::Processor;
16use crate::reference::Bibliography;
17use citum_schema::locale::{GeneralTerm, TermForm};
18use citum_schema::reference::{
19 ClassExtension, CollectionType, ContributorRole as ReferenceRole, MonographComponentType,
20 MonographType, ReferenceClass, SerialComponentType,
21};
22use citum_schema::template::ContributorRole as TemplateRole;
23
24use super::{Warning, WarningLevel};
25
26pub fn unknown_reference_class_warnings(bibliography: &Bibliography) -> Vec<Warning> {
28 bibliography
29 .iter()
30 .filter_map(|(ref_id, reference)| {
31 let ReferenceClass::Unknown(class) = reference.class() else {
32 return None;
33 };
34 Some(Warning {
35 level: WarningLevel::Warning,
36 code: "unknown_reference_class".to_string(),
37 citation_id: None,
38 ref_id: Some(ref_id.clone()),
39 message: format!(
40 "Reference '{ref_id}' uses unknown class '{class}'; rendering will use only fields this engine understands."
41 ),
42 })
43 })
44 .collect()
45}
46
47pub fn unknown_reference_field_warnings(bibliography: &Bibliography) -> Vec<Warning> {
53 bibliography
54 .iter()
55 .filter_map(|(ref_id, reference)| {
56 let unknown = reference.unknown_fields()?;
57 if unknown.is_empty() {
58 return None;
59 }
60 let keys: Vec<&str> = unknown.keys().map(String::as_str).collect();
61 Some(Warning {
62 level: WarningLevel::Warning,
63 code: "unknown_reference_field".to_string(),
64 citation_id: None,
65 ref_id: Some(ref_id.clone()),
66 message: format!(
67 "Reference '{ref_id}' has unknown field(s): {}; these fields are ignored during rendering.",
68 keys.join(", ")
69 ),
70 })
71 })
72 .collect()
73}
74
75pub fn unknown_enum_warnings(processor: &Processor) -> Vec<Warning> {
80 let mut warnings = Vec::new();
81
82 for (ref_id, reference) in &processor.bibliography {
84 match reference.extension() {
85 ClassExtension::Monograph(r) => {
86 if let MonographType::Unknown(s) = &r.r#type {
87 warnings.push(Warning {
88 level: WarningLevel::Warning,
89 code: "unknown_enum_variant".to_string(),
90 citation_id: None,
91 ref_id: Some(ref_id.clone()),
92 message: format!("Reference '{ref_id}' uses unknown monograph type '{s}'; rendering will use default monograph formatting."),
93 });
94 }
95 }
96 ClassExtension::Collection(r) => {
97 if let CollectionType::Unknown(s) = &r.r#type {
98 warnings.push(Warning {
99 level: WarningLevel::Warning,
100 code: "unknown_enum_variant".to_string(),
101 citation_id: None,
102 ref_id: Some(ref_id.clone()),
103 message: format!("Reference '{ref_id}' uses unknown collection type '{s}'; rendering will use default collection formatting."),
104 });
105 }
106 }
107 ClassExtension::CollectionComponent(r) => {
108 if let MonographComponentType::Unknown(s) = &r.r#type {
109 warnings.push(Warning {
110 level: WarningLevel::Warning,
111 code: "unknown_enum_variant".to_string(),
112 citation_id: None,
113 ref_id: Some(ref_id.clone()),
114 message: format!("Reference '{ref_id}' uses unknown monograph component type '{s}'; rendering will use default chapter formatting."),
115 });
116 }
117 }
118 ClassExtension::SerialComponent(r) => {
119 if let SerialComponentType::Unknown(s) = &r.r#type {
120 warnings.push(Warning {
121 level: WarningLevel::Warning,
122 code: "unknown_enum_variant".to_string(),
123 citation_id: None,
124 ref_id: Some(ref_id.clone()),
125 message: format!("Reference '{ref_id}' uses unknown serial component type '{s}'; rendering will use default article formatting."),
126 });
127 }
128 }
129 _ => {}
130 }
131
132 for contributor in reference.all_contributor_entries() {
133 if let ReferenceRole::Unknown(s) = &contributor.role {
134 warnings.push(Warning {
135 level: WarningLevel::Warning,
136 code: "unknown_enum_variant".to_string(),
137 citation_id: None,
138 ref_id: Some(ref_id.clone()),
139 message: format!("Reference '{ref_id}' uses unknown contributor role '{s}'; this role may be ignored during rendering."),
140 });
141 }
142 }
143 }
144
145 if let Some(templates) = &processor.style.templates {
147 for (name, template) in templates {
148 scan_template_for_unknowns(template, &format!("template '{name}'"), &mut warnings);
149 }
150 }
151 if let Some(citation) = &processor.style.citation
152 && let Some(template) = &citation.template
153 {
154 scan_template_for_unknowns(template, "citation layout", &mut warnings);
155 }
156 if let Some(bib) = &processor.style.bibliography
157 && let Some(template) = &bib.template
158 {
159 scan_template_for_unknowns(template, "bibliography layout", &mut warnings);
160 }
161
162 warnings
163}
164
165fn scan_template_for_unknowns(
166 components: &[citum_schema::template::TemplateComponent],
167 location: &str,
168 warnings: &mut Vec<Warning>,
169) {
170 use citum_schema::template::TemplateComponent;
171 for component in components {
172 match component {
173 TemplateComponent::Term(t) => {
174 if let GeneralTerm::Unknown(s) = &t.term {
175 warnings.push(Warning {
176 level: WarningLevel::Warning,
177 code: "unknown_enum_variant".to_string(),
178 citation_id: None,
179 ref_id: None,
180 message: format!("Style {location} uses unknown locale term key '{s}'; this term may render as empty."),
181 });
182 }
183 if let Some(TermForm::Unknown(s)) = &t.form {
184 warnings.push(Warning {
185 level: WarningLevel::Warning,
186 code: "unknown_enum_variant".to_string(),
187 citation_id: None,
188 ref_id: None,
189 message: format!("Style {location} uses unknown term form '{s}'; falling back to long form."),
190 });
191 }
192 }
193 TemplateComponent::Contributor(c) => {
194 if let TemplateRole::Unknown(s) = &c.contributor {
195 warnings.push(Warning {
196 level: WarningLevel::Warning,
197 code: "unknown_enum_variant".to_string(),
198 citation_id: None,
199 ref_id: None,
200 message: format!("Style {location} uses unknown contributor role '{s}'; this role may be ignored."),
201 });
202 }
203 }
204 TemplateComponent::Date(d) => {
205 if let citum_schema::template::DateForm::Unknown(s) = &d.form {
206 warnings.push(Warning {
207 level: WarningLevel::Warning,
208 code: "unknown_enum_variant".to_string(),
209 citation_id: None,
210 ref_id: None,
211 message: format!("Style {location} uses unknown date form '{s}'; falling back to year only."),
212 });
213 }
214 }
215 TemplateComponent::Group(g) => {
216 scan_template_for_unknowns(&g.group, location, warnings);
217 }
218 _ => {}
219 }
220 }
221}