schemadoc_diff/checker/
mod.rs1pub mod added_required_body_property_check;
2pub mod added_required_parameter_check;
3pub mod added_required_request_body_check;
4pub mod removed_media_type_check;
5pub mod removed_operation_check;
6pub mod removed_response_property_check;
7pub mod removed_schema_enum_value_check;
8pub mod updated_schema_type_check;
9
10use crate::path_pointer::PathPointer;
11use crate::schema_diff::HttpSchemaDiff;
12
13use crate::visitor::{DiffVisitor, MergedVisitor};
14
15use crate::checker::added_required_body_property_check::AddedRequiredBodyPropertyCheck;
16use crate::checker::added_required_parameter_check::AddedRequiredParameterCheck;
17use crate::checker::added_required_request_body_check::AddedRequiredRequestBodyCheck;
18use crate::checker::removed_media_type_check::RemovedMediaTypeCheck;
19use crate::checker::removed_operation_check::RemovedOperationCheck;
20use crate::checker::removed_response_property_check::RemovedResponsePropertyCheck;
21use crate::checker::removed_schema_enum_value_check::RemovedSchemaEnumValueCheck;
22use crate::checker::updated_schema_type_check::UpdatedSchemaTypeCheck;
23
24#[derive(Debug)]
25pub struct ValidationIssue {
26 pub path: PathPointer,
27 pub breaking: bool,
28 pub kind: &'static str,
29}
30
31impl ValidationIssue {
32 pub fn new(path: PathPointer, kind: &'static str, breaking: bool) -> Self {
33 Self {
34 path,
35 kind,
36 breaking,
37 }
38 }
39}
40
41pub trait HasBreakingChange {
42 fn has_breaking_changes(&self) -> bool;
43}
44
45impl HasBreakingChange for &[ValidationIssue] {
46 fn has_breaking_changes(&self) -> bool {
47 self.iter().any(|x| x.breaking)
48 }
49}
50
51impl HasBreakingChange for &[&ValidationIssue] {
52 fn has_breaking_changes(&self) -> bool {
53 self.iter().any(|x| x.breaking)
54 }
55}
56
57trait ValidationIssuer<'s> {
58 fn id(&self) -> &'static str;
59 fn visitor(&self) -> &dyn DiffVisitor<'s>;
60 fn issues(&self) -> Option<Vec<ValidationIssue>>;
61}
62
63pub fn validate(
64 diff: &HttpSchemaDiff,
65 checkers: &[&str],
66) -> Vec<ValidationIssue> {
67 let removed_operation = Box::<RemovedOperationCheck>::default();
68 let removed_media_type = Box::<RemovedMediaTypeCheck>::default();
69 let changed_schema_type = Box::<UpdatedSchemaTypeCheck>::default();
70 let removed_schema_enum_value =
71 Box::<RemovedSchemaEnumValueCheck>::default();
72 let added_required_parameter =
73 Box::<AddedRequiredParameterCheck>::default();
74 let removed_response_property =
75 Box::<RemovedResponsePropertyCheck>::default();
76 let added_required_request_body =
77 Box::<AddedRequiredRequestBodyCheck>::default();
78 let added_required_body_property =
79 Box::<AddedRequiredBodyPropertyCheck>::default();
80
81 let available_issuers: Vec<&dyn ValidationIssuer> = vec![
82 &*removed_operation,
83 &*removed_media_type,
84 &*changed_schema_type,
85 &*added_required_parameter,
86 &*removed_response_property,
87 &*removed_schema_enum_value,
88 &*added_required_request_body,
89 &*added_required_body_property,
90 ];
91
92 let issuers: Vec<_> = if checkers.contains(&"*") {
93 available_issuers
94 } else {
95 available_issuers
96 .into_iter()
97 .filter(|issuer| checkers.contains(&issuer.id()))
98 .collect()
99 };
100
101 let visitors: Vec<_> = issuers.iter().map(|v| v.visitor()).collect();
102
103 {
104 let visitor = MergedVisitor::new(visitors.as_slice());
105 crate::visitor::dispatch_visitor(diff, &visitor);
106 }
107
108 let results: Vec<_> = issuers
109 .into_iter()
110 .filter_map(|v| v.issues())
111 .flatten()
112 .collect();
113
114 results
115}