Skip to content

Commit ff64716

Browse files
authored
support const keyword (#27)
1 parent 5d27055 commit ff64716

24 files changed

+409
-5
lines changed

src/diff_walker.rs

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use std::collections::BTreeSet;
1+
use std::collections::{BTreeMap, BTreeSet};
22

33
use schemars::schema::{
4-
InstanceType, NumberValidation, RootSchema, Schema, SchemaObject, SingleOrVec,
5-
SubschemaValidation,
4+
InstanceType, NumberValidation, ObjectValidation, RootSchema, Schema, SchemaObject,
5+
SingleOrVec, SubschemaValidation,
66
};
77
use serde_json::Value;
88

@@ -77,6 +77,37 @@ impl DiffWalker {
7777
}
7878
}
7979

80+
fn diff_const(&mut self, json_path: &str, lhs: &mut SchemaObject, rhs: &mut SchemaObject) {
81+
Self::normalize_const(lhs);
82+
Self::normalize_const(rhs);
83+
match (&lhs.const_value, &rhs.const_value) {
84+
(Some(value), None) => self.changes.push(Change {
85+
path: json_path.to_owned(),
86+
change: ChangeKind::ConstRemove {
87+
removed: value.clone(),
88+
},
89+
}),
90+
(None, Some(value)) => self.changes.push(Change {
91+
path: json_path.to_owned(),
92+
change: ChangeKind::ConstAdd {
93+
added: value.clone(),
94+
},
95+
}),
96+
(Some(l), Some(r)) if l != r => {
97+
if l.is_object() && r.is_object() {}
98+
self.changes.push(Change {
99+
path: json_path.to_owned(),
100+
change: ChangeKind::ConstRemove { removed: l.clone() },
101+
});
102+
self.changes.push(Change {
103+
path: json_path.to_owned(),
104+
change: ChangeKind::ConstAdd { added: r.clone() },
105+
});
106+
}
107+
_ => (),
108+
}
109+
}
110+
80111
fn diff_properties(
81112
&mut self,
82113
json_path: &str,
@@ -384,6 +415,33 @@ impl DiffWalker {
384415
is_split
385416
}
386417

418+
fn normalize_const(schema_object: &mut SchemaObject) {
419+
fn do_normalize(value: Value) -> SchemaObject {
420+
match value {
421+
Value::Object(obj) => {
422+
let properties = obj
423+
.into_iter()
424+
.map(|(k, v)| (k, Schema::Object(do_normalize(v))))
425+
.collect::<BTreeMap<_, _>>();
426+
SchemaObject {
427+
object: Some(Box::new(ObjectValidation {
428+
properties,
429+
..Default::default()
430+
})),
431+
..Default::default()
432+
}
433+
}
434+
_ => SchemaObject {
435+
const_value: Some(value),
436+
..Default::default()
437+
},
438+
}
439+
}
440+
if let Some(value) = schema_object.const_value.take() {
441+
*schema_object = do_normalize(value)
442+
}
443+
}
444+
387445
fn do_diff(
388446
&mut self,
389447
json_path: &str,
@@ -399,6 +457,7 @@ impl DiffWalker {
399457
if !comparing_any_of {
400458
self.diff_instance_types(json_path, lhs, rhs);
401459
}
460+
self.diff_const(json_path, lhs, rhs);
402461
// If we split the types, we don't want to compare type-specific properties
403462
// because they are already compared in the `Self::diff_any_of`
404463
if !is_lhs_split && !is_rhs_split {

src/types.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ pub enum ChangeKind {
2626
/// The type in question.
2727
removed: JsonSchemaType,
2828
},
29+
/// A const value has been added as an allowed value.
30+
ConstAdd {
31+
/// The value of the added const.
32+
added: serde_json::Value,
33+
},
34+
/// A const has been removed as an allowed value.
35+
ConstRemove {
36+
/// The value of the removed const.
37+
removed: serde_json::Value,
38+
},
2939
/// A property has been added and (depending on additionalProperties) is now additionally
3040
/// allowed.
3141
PropertyAdd {
@@ -117,6 +127,8 @@ impl ChangeKind {
117127
match self {
118128
Self::TypeAdd { .. } => false,
119129
Self::TypeRemove { .. } => true,
130+
Self::ConstAdd { .. } => true,
131+
Self::ConstRemove { .. } => false,
120132
Self::PropertyAdd {
121133
lhs_additional_properties,
122134
..
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "anyOf": [{ "type": "number" }, { "type": "string" }] },
3+
"rhs": { "anyOf": [{ "const": 1 }, { "const": "1" }] }
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "anyOf": [{ "type": "number" }, { "type": "string" }, { "const": 1 }] },
3+
"rhs": { "anyOf": [{ "const": 1 }, { "const": "1" }] }
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "anyOf": [{ "type": "object" }, { "type": "string" }, { "const": { "key": "value" } }] },
3+
"rhs": { "anyOf": [{ "properties": { "key": { "const": "value" } } }, { "const": "1" }] }
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "const": { "key": "value" } },
3+
"rhs": { "properties": { "key": { "const": "value" } } }
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "const": "foo" },
3+
"rhs": { "const": 1 }
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "const": "foo" },
3+
"rhs": { "const": "bar" }
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "type": "integer" },
3+
"rhs": { "const": "foo" }
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "type": "number" },
3+
"rhs": { "const": "foo" }
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "type": "object" },
3+
"rhs": { "const": { "key": "value" } }
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"lhs": { "type": "string" },
3+
"rhs": { "const": 1 }
4+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
source: tests/test.rs
3+
expression: diff
4+
info:
5+
lhs:
6+
anyOf:
7+
- type: number
8+
- type: string
9+
rhs:
10+
anyOf:
11+
- const: 1
12+
- const: "1"
13+
input_file: tests/fixtures/const/const_in_any_of_1.json
14+
---
15+
[
16+
Change {
17+
path: ".<anyOf:0>",
18+
change: ConstAdd {
19+
added: Number(1),
20+
},
21+
},
22+
Change {
23+
path: ".<anyOf:1>",
24+
change: ConstAdd {
25+
added: String("1"),
26+
},
27+
},
28+
]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
source: tests/test.rs
3+
expression: diff
4+
info:
5+
lhs:
6+
anyOf:
7+
- type: number
8+
- type: string
9+
- const: 1
10+
rhs:
11+
anyOf:
12+
- const: 1
13+
- const: "1"
14+
input_file: tests/fixtures/const/const_in_any_of_2.json
15+
---
16+
[
17+
Change {
18+
path: ".<anyOf:1>",
19+
change: ConstAdd {
20+
added: String("1"),
21+
},
22+
},
23+
]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
source: tests/test.rs
3+
expression: diff
4+
info:
5+
lhs:
6+
anyOf:
7+
- type: object
8+
- type: string
9+
- const:
10+
key: value
11+
rhs:
12+
anyOf:
13+
- properties:
14+
key:
15+
const: value
16+
- const: "1"
17+
input_file: tests/fixtures/const/const_in_any_of_3.json
18+
---
19+
[
20+
Change {
21+
path: ".<anyOf:1>",
22+
change: ConstAdd {
23+
added: String("1"),
24+
},
25+
},
26+
]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
source: tests/test.rs
3+
expression: diff
4+
info:
5+
lhs:
6+
const:
7+
key: value
8+
rhs:
9+
properties:
10+
key:
11+
const: value
12+
input_file: tests/fixtures/const/const_in_properties.json
13+
---
14+
[]
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
source: tests/test.rs
3+
expression: diff
4+
info:
5+
lhs:
6+
const: foo
7+
rhs:
8+
const: 1
9+
input_file: tests/fixtures/const/const_string_to_const_number.json
10+
---
11+
[
12+
Change {
13+
path: "",
14+
change: TypeRemove {
15+
removed: String,
16+
},
17+
},
18+
Change {
19+
path: "",
20+
change: TypeAdd {
21+
added: Number,
22+
},
23+
},
24+
Change {
25+
path: "",
26+
change: TypeAdd {
27+
added: Integer,
28+
},
29+
},
30+
Change {
31+
path: "",
32+
change: ConstRemove {
33+
removed: String("foo"),
34+
},
35+
},
36+
Change {
37+
path: "",
38+
change: ConstAdd {
39+
added: Number(1),
40+
},
41+
},
42+
]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
source: tests/test.rs
3+
expression: diff
4+
info:
5+
lhs:
6+
const: foo
7+
rhs:
8+
const: bar
9+
input_file: tests/fixtures/const/const_string_to_other_const_string.json
10+
---
11+
[
12+
Change {
13+
path: "",
14+
change: ConstRemove {
15+
removed: String("foo"),
16+
},
17+
},
18+
Change {
19+
path: "",
20+
change: ConstAdd {
21+
added: String("bar"),
22+
},
23+
},
24+
]
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
source: tests/test.rs
3+
expression: diff
4+
info:
5+
lhs:
6+
type: integer
7+
rhs:
8+
const: foo
9+
input_file: tests/fixtures/const/integer_to_const_string.json
10+
---
11+
[
12+
Change {
13+
path: "",
14+
change: TypeRemove {
15+
removed: Integer,
16+
},
17+
},
18+
Change {
19+
path: "",
20+
change: TypeAdd {
21+
added: String,
22+
},
23+
},
24+
Change {
25+
path: "",
26+
change: ConstAdd {
27+
added: String("foo"),
28+
},
29+
},
30+
]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
source: tests/test.rs
3+
expression: diff
4+
info:
5+
lhs:
6+
type: number
7+
rhs:
8+
const: foo
9+
input_file: tests/fixtures/const/number_to_const_string.json
10+
---
11+
[
12+
Change {
13+
path: "",
14+
change: TypeRemove {
15+
removed: Number,
16+
},
17+
},
18+
Change {
19+
path: "",
20+
change: TypeRemove {
21+
removed: Integer,
22+
},
23+
},
24+
Change {
25+
path: "",
26+
change: TypeAdd {
27+
added: String,
28+
},
29+
},
30+
Change {
31+
path: "",
32+
change: ConstAdd {
33+
added: String("foo"),
34+
},
35+
},
36+
]

0 commit comments

Comments
 (0)