json_schema_tools/
key_order.rs1use super::{constants::*, path::Path};
2use serde_json::Value;
3use std::cmp::Ordering;
4
5#[derive(Clone, Debug, Eq, PartialEq)]
6pub struct KeyOrderMismatch<'a> {
7 pub path: Path<'a>,
8 pub first: &'a str,
9 pub second: &'a str,
10}
11
12pub fn check_key_order(value: &Value) -> Vec<KeyOrderMismatch> {
13 super::util::nodes_with_path(value)
14 .iter()
15 .filter(|(path, _)| !path.allows_arbitrary_keys())
16 .filter_map(|(path, value)| {
17 value.as_object().and_then(|fields| {
18 let keys = fields.keys().map(|key| Key(key)).collect::<Vec<_>>();
19
20 keys.windows(2)
21 .find(|window| window[0] >= window[1])
22 .map(|bad_window| KeyOrderMismatch {
23 path: path.clone(),
24 first: bad_window[0].0,
25 second: bad_window[1].0,
26 })
27 })
28 })
29 .collect()
30}
31
32#[derive(Clone, Copy, Eq, PartialEq)]
33struct Key<'a>(&'a str);
34
35impl<'a> PartialOrd for Key<'a> {
36 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
37 if self == other {
38 Some(Ordering::Equal)
39 } else {
40 match (self.0, other.0) {
41 (ID_KEY, _) => Some(Ordering::Less),
42 (_, ID_KEY) => Some(Ordering::Greater),
43 (TITLE_KEY, _) => Some(Ordering::Less),
44 (_, TITLE_KEY) => Some(Ordering::Greater),
45 (DESCRIPTION_KEY, _) => Some(Ordering::Less),
46 (_, DESCRIPTION_KEY) => Some(Ordering::Greater),
47 (COMMENT_KEY, _) => Some(Ordering::Less),
48 (_, COMMENT_KEY) => Some(Ordering::Greater),
49 (TYPE_KEY, _) => Some(Ordering::Less),
50 (_, TYPE_KEY) => Some(Ordering::Greater),
51 (ADDITIONAL_PROPERTIES_KEY, _) => Some(Ordering::Less),
52 (_, ADDITIONAL_PROPERTIES_KEY) => Some(Ordering::Greater),
53 (PROPERTIES_KEY, _) => Some(Ordering::Less),
54 (_, PROPERTIES_KEY) => Some(Ordering::Greater),
55 (REQUIRED_KEY, _) => Some(Ordering::Less),
56 (_, REQUIRED_KEY) => Some(Ordering::Greater),
57 (EXAMPLES_KEY, _) => Some(Ordering::Greater),
58 (_, EXAMPLES_KEY) => Some(Ordering::Less),
59 (_, _) => None,
60 }
61 }
62 }
63}