ocpi_tariffs/lint/
tariff.rs1#[cfg(test)]
2mod test;
3
4pub(crate) mod v211;
5pub(crate) mod v221;
6pub mod v2x;
7
8use std::{borrow::Cow, fmt};
9
10use crate::{
11 country, currency, datetime, from_warning_all, json, money, number, string, tariff, warning,
12 Versioned as _,
13};
14
15pub(crate) fn lint(tariff: &tariff::Versioned<'_>) -> Report {
20 let mut warnings = warning::Set::new();
21
22 {
23 let walker = json::walk::DepthFirst::new(tariff.as_element());
27
28 for elem in walker.filter(|&elem| elem.value().is_null()) {
29 warnings.insert(Warning::NeedlessNullField, elem);
30 }
31 }
32
33 match tariff.version() {
34 crate::Version::V221 => v221::lint(tariff.as_element(), warnings),
35 crate::Version::V211 => v211::lint(tariff.as_element(), warnings),
36 }
37}
38
39#[derive(Debug)]
41pub struct Report {
42 pub warnings: warning::Set<Warning>,
44}
45
46#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
47pub enum Warning {
48 Country(country::Warning),
49
50 CpoCountryCodeShouldBeAlpha2,
52
53 Currency(currency::Warning),
54
55 DateTime(datetime::Warning),
56
57 Elements(v2x::elements::Warning),
58
59 MinPriceIsGreaterThanMax,
61
62 Money(money::Warning),
63
64 NeedlessNullField,
66
67 Number(number::Warning),
68
69 FieldRequired {
71 field_name: Cow<'static, str>,
72 },
73
74 String(string::Warning),
75
76 StartDateTimeIsAfterEndDateTime,
78}
79
80from_warning_all!(
81 country::Warning => Warning::Country,
82 currency::Warning => Warning::Currency,
83 datetime::Warning => Warning::DateTime,
84 number::Warning => Warning::Number,
85 money::Warning => Warning::Money,
86 string::Warning => Warning::String,
87 v2x::elements::Warning => Warning::Elements
88);
89
90impl crate::Warning for Warning {
91 fn id(&self) -> warning::Id {
92 match self {
93 Self::CpoCountryCodeShouldBeAlpha2 => {
94 warning::Id::from_static("cpo_country_code_should_be_alpha2")
95 }
96 Self::Country(kind) => kind.id(),
97 Self::Currency(kind) => kind.id(),
98 Self::DateTime(kind) => kind.id(),
99 Self::Elements(kind) => kind.id(),
100 Self::MinPriceIsGreaterThanMax => {
101 warning::Id::from_static("min_price_is_greater_than_max")
102 }
103 Self::Number(kind) => kind.id(),
104 Self::Money(kind) => kind.id(),
105 Self::NeedlessNullField => warning::Id::from_static("needless_null_field"),
106 Self::StartDateTimeIsAfterEndDateTime => {
107 warning::Id::from_static("start_date_time_is_after_end_date_time")
108 }
109 Self::String(kind) => kind.id(),
110 Self::FieldRequired { field_name } => {
111 warning::Id::from_string(format!("field_required({field_name})"))
112 }
113 }
114 }
115}
116
117impl fmt::Display for Warning {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 match self {
120 Self::CpoCountryCodeShouldBeAlpha2 => {
121 f.write_str("The value should be an alpha-2 ISO 3166-1 country code")
122 }
123 Self::Country(kind) => fmt::Display::fmt(kind, f),
124 Self::Currency(kind) => fmt::Display::fmt(kind, f),
125 Self::DateTime(kind) => fmt::Display::fmt(kind, f),
126 Self::Elements(kind) => fmt::Display::fmt(kind, f),
127 Self::MinPriceIsGreaterThanMax => {
128 f.write_str("The `min_price` is greater than `max_price`.")
129 }
130 Self::Number(kind) => fmt::Display::fmt(kind, f),
131 Self::Money(kind) => fmt::Display::fmt(kind, f),
132 Self::NeedlessNullField => write!(f, "Null field: the field can simply be removed."),
133 Self::StartDateTimeIsAfterEndDateTime => {
134 f.write_str("The `start_date_time` is after the `end_date_time`.")
135 }
136 Self::String(kind) => fmt::Display::fmt(kind, f),
137 Self::FieldRequired { field_name } => {
138 write!(f, "Field is required: `{field_name}`")
139 }
140 }
141 }
142}