jsonschema_rs 0.49.0 → 0.49.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -1
- data/Cargo.toml +2 -2
- data/ext/jsonschema/Cargo.lock +13 -13
- data/ext/jsonschema/Cargo.toml +3 -3
- data/lib/jsonschema/version.rb +1 -1
- data/sig/jsonschema.rbs +5 -1
- data/src/canonical.rs +191 -4
- data/src/options.rs +39 -26
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48dc9cf6305e242c8a686a6e1439fcc2d05ce1b2738bfdf1eb42394e05f16d03
|
|
4
|
+
data.tar.gz: 9e828ed439bb3180094d3c2cdc1cbc0723ea71d385c2861278c7347493dfd900
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d41807f218f18e5435a4ec6e01326f5459076c78afd126844dcd03a982e1006514ec613333eac241853e8b83859410ab723f53ffa185f959cfd6209f8a4c6399
|
|
7
|
+
data.tar.gz: 768c332d2d735999f58bde2a4947568d9e4e7c7cbf818e6ed8ae4177d890810490cf2494b5bfcea547fe7a0c7827775ba83192e465f77207581a9e40d6d21f1f
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.49.3] - 2026-08-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Canonicalization of a recursive schema with no finite witness, which now folds to `false`.
|
|
10
|
+
- Canonicalization of `$dynamicRef` and `$recursiveRef`, which resolve through the dynamic scope and stay symbolic like any other reference. A dangling `$dynamicRef` errors rather than staying `Raw`.
|
|
11
|
+
- Canonicalization of `minContains` under `uniqueItems`, where a demand asking for more matches than its own schema has distinct values now folds to `false`.
|
|
12
|
+
- Canonicalization of a Draft 4 `patternProperties` coverage closed by `additionalProperties: false`, spelled as the closed map it was parsed from.
|
|
13
|
+
- Canonicalization of a `oneOf` whose branches repeat, where a repeated branch can never contribute exactly one match.
|
|
14
|
+
- Canonicalization of a `$ref` whose target is an empty schema, which now folds to `false`.
|
|
15
|
+
- Canonicalization of `unevaluatedItems` beside `allOf`, where every branch must pass and so the indexes they evaluate are known without the instance.
|
|
16
|
+
- Canonicalization of `unevaluatedProperties` beside `allOf`, where every branch must pass and so what they evaluate is known without the instance.
|
|
17
|
+
- Canonicalization of a Draft 4 `type` list holding `integer` beside other types with `enum`, which previously modeled only when spelled as an `allOf`.
|
|
18
|
+
- Canonicalization of `patternProperties` patterns matching finitely many keys, such as `^a$` and `^(a|b)$`.
|
|
19
|
+
- Canonicalization of `unevaluatedProperties` and `unevaluatedItems` when no in-place applicator sits beside them.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `additionalItems` values that are not schemas silently ignored beside an array-form `items` (they should fail the build like `additionalProperties`).
|
|
24
|
+
- `additionalItems` beside a boolean `items` rejecting every instance, such as `{"additionalItems": false, "items": false}`.
|
|
25
|
+
- Draft 4 rejecting a size bound at or past `2^64`, such as `{"maxItems": 18446744073709551616}`.
|
|
26
|
+
- An integer past the `f64` range admitted by a fractional bound it exceeds, such as `1e400` under `{"exclusiveMaximum": 0.1}`.
|
|
27
|
+
- A `$ref` at the root of an `$id`-bearing subresource dropped as a self-reference when its pointer matched the one that reached that subresource.
|
|
28
|
+
- Canonicalization reusing one definition's body for a same-named definition in another resource, when the name spells a canonical URI.
|
|
29
|
+
- `unevaluatedItems` counting `prefixItems` as evaluating elements before Draft 2020-12, where it is not a keyword.
|
|
30
|
+
|
|
31
|
+
### Performance
|
|
32
|
+
|
|
33
|
+
- Up to 70% faster `evaluate`.
|
|
34
|
+
|
|
35
|
+
## [0.49.2] - 2026-07-28
|
|
36
|
+
|
|
37
|
+
### Performance
|
|
38
|
+
|
|
39
|
+
- Faster serialization of canonicalized schemas.
|
|
40
|
+
|
|
41
|
+
## [0.49.1] - 2026-07-25
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- `JSONSchema.canonicalize` rejecting `pattern_options` (it should take the same regex configuration as validators).
|
|
46
|
+
- `InvalidPattern` failures raising the base `CanonicalizationError` (they should raise `JSONSchema::Canonical::InvalidPattern`).
|
|
47
|
+
|
|
5
48
|
## [0.49.0] - 2026-07-25
|
|
6
49
|
|
|
7
50
|
### Added
|
|
@@ -219,7 +262,10 @@
|
|
|
219
262
|
|
|
220
263
|
- Initial public release
|
|
221
264
|
|
|
222
|
-
[Unreleased]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.
|
|
265
|
+
[Unreleased]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.3...HEAD
|
|
266
|
+
[0.49.3]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.2...ruby-v0.49.3
|
|
267
|
+
[0.49.2]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.1...ruby-v0.49.2
|
|
268
|
+
[0.49.1]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.0...ruby-v0.49.1
|
|
223
269
|
[0.49.0]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.48.5...ruby-v0.49.0
|
|
224
270
|
[0.48.5]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.48.2...ruby-v0.48.5
|
|
225
271
|
[0.48.2]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.48.1...ruby-v0.48.2
|
data/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "jsonschema-rb"
|
|
3
|
-
version = "0.49.
|
|
3
|
+
version = "0.49.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Dmitry Dygalo <dmitry@dygalo.dev>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -13,7 +13,7 @@ publish = false
|
|
|
13
13
|
crate-type = ["cdylib"]
|
|
14
14
|
|
|
15
15
|
[dependencies]
|
|
16
|
-
jsonschema = { version = "0.49.
|
|
16
|
+
jsonschema = { version = "0.49.3", default-features = false, features = ["magnus", "arbitrary-precision", "resolve-http", "resolve-file", "tls-ring", "macros"] }
|
|
17
17
|
magnus = { version = "0.8", features = ["rb-sys"] }
|
|
18
18
|
rb-sys = "0.9"
|
|
19
19
|
serde = { workspace = true }
|
data/ext/jsonschema/Cargo.lock
CHANGED
|
@@ -693,9 +693,9 @@ dependencies = [
|
|
|
693
693
|
|
|
694
694
|
[[package]]
|
|
695
695
|
name = "jsonschema"
|
|
696
|
-
version = "0.49.
|
|
696
|
+
version = "0.49.3"
|
|
697
697
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
698
|
-
checksum = "
|
|
698
|
+
checksum = "508004a5500f2e1f68af048f70feea2de86d35ab115d85716530860822aef397"
|
|
699
699
|
dependencies = [
|
|
700
700
|
"ahash",
|
|
701
701
|
"bytecount",
|
|
@@ -726,9 +726,9 @@ dependencies = [
|
|
|
726
726
|
|
|
727
727
|
[[package]]
|
|
728
728
|
name = "jsonschema-macros"
|
|
729
|
-
version = "0.49.
|
|
729
|
+
version = "0.49.3"
|
|
730
730
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
731
|
-
checksum = "
|
|
731
|
+
checksum = "f4e131231bc18676df289bd7634d4353d5b36bced191928bfa2a2dcae91e44a0"
|
|
732
732
|
dependencies = [
|
|
733
733
|
"jsonschema-macros-core",
|
|
734
734
|
"proc-macro2",
|
|
@@ -736,9 +736,9 @@ dependencies = [
|
|
|
736
736
|
|
|
737
737
|
[[package]]
|
|
738
738
|
name = "jsonschema-macros-core"
|
|
739
|
-
version = "0.49.
|
|
739
|
+
version = "0.49.3"
|
|
740
740
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
741
|
-
checksum = "
|
|
741
|
+
checksum = "75803a5014f912d5a8f3c8cc24531d19ea06dfadda75ddf1d15af629f7c8468c"
|
|
742
742
|
dependencies = [
|
|
743
743
|
"fancy-regex",
|
|
744
744
|
"indexmap",
|
|
@@ -755,7 +755,7 @@ dependencies = [
|
|
|
755
755
|
|
|
756
756
|
[[package]]
|
|
757
757
|
name = "jsonschema-rb-ext"
|
|
758
|
-
version = "0.49.
|
|
758
|
+
version = "0.49.3"
|
|
759
759
|
dependencies = [
|
|
760
760
|
"jsonschema",
|
|
761
761
|
"magnus",
|
|
@@ -768,18 +768,18 @@ dependencies = [
|
|
|
768
768
|
|
|
769
769
|
[[package]]
|
|
770
770
|
name = "jsonschema-regex"
|
|
771
|
-
version = "0.49.
|
|
771
|
+
version = "0.49.3"
|
|
772
772
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
773
|
-
checksum = "
|
|
773
|
+
checksum = "5a8b30cafa78358ae6cd1494a7d6410b89530e28bf567f862c869c667e900d9f"
|
|
774
774
|
dependencies = [
|
|
775
775
|
"regex-syntax",
|
|
776
776
|
]
|
|
777
777
|
|
|
778
778
|
[[package]]
|
|
779
779
|
name = "jsonschema-value"
|
|
780
|
-
version = "0.49.
|
|
780
|
+
version = "0.49.3"
|
|
781
781
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
782
|
-
checksum = "
|
|
782
|
+
checksum = "5526bd381d230af94908d07e6835a33fd82a465e12f5f1e9c81f5c2aa23b3c21"
|
|
783
783
|
dependencies = [
|
|
784
784
|
"ahash",
|
|
785
785
|
"bytecount",
|
|
@@ -1132,9 +1132,9 @@ dependencies = [
|
|
|
1132
1132
|
|
|
1133
1133
|
[[package]]
|
|
1134
1134
|
name = "referencing"
|
|
1135
|
-
version = "0.49.
|
|
1135
|
+
version = "0.49.3"
|
|
1136
1136
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1137
|
-
checksum = "
|
|
1137
|
+
checksum = "7af3eb523cce0df0af3c30d624b829b2dabd233172b5bc2615fcd03ceae8f746"
|
|
1138
1138
|
dependencies = [
|
|
1139
1139
|
"ahash",
|
|
1140
1140
|
"fluent-uri",
|
data/ext/jsonschema/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "jsonschema-rb-ext"
|
|
3
|
-
version = "0.49.
|
|
3
|
+
version = "0.49.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
publish = false
|
|
6
6
|
|
|
@@ -10,10 +10,10 @@ name = "jsonschema_rb"
|
|
|
10
10
|
path = "../../src/lib.rs"
|
|
11
11
|
|
|
12
12
|
[dependencies]
|
|
13
|
-
jsonschema = { version = "0.49.
|
|
13
|
+
jsonschema = { version = "0.49.3", default-features = false, features = ["magnus", "arbitrary-precision", "resolve-http", "resolve-file", "tls-ring", "macros"] }
|
|
14
14
|
magnus = { version = "0.8", features = ["rb-sys"] }
|
|
15
15
|
rb-sys = "0.9"
|
|
16
|
-
referencing = "0.49.
|
|
16
|
+
referencing = "0.49.3"
|
|
17
17
|
serde = { version = "1", features = ["derive"] }
|
|
18
18
|
serde_json = { version = "1", features = ["arbitrary_precision"] }
|
|
19
19
|
zmij = "1"
|
data/lib/jsonschema/version.rb
CHANGED
data/sig/jsonschema.rbs
CHANGED
|
@@ -29,6 +29,9 @@ module JSONSchema
|
|
|
29
29
|
class InvalidSchemaType < CanonicalizationError
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
class InvalidPattern < CanonicalizationError
|
|
33
|
+
end
|
|
34
|
+
|
|
32
35
|
# A schema reduced to canonical form: schemas accepting the same values share one form.
|
|
33
36
|
class CanonicalSchema
|
|
34
37
|
def to_json_schema: () -> untyped
|
|
@@ -164,7 +167,8 @@ module JSONSchema
|
|
|
164
167
|
def self.canonicalize: (
|
|
165
168
|
untyped schema,
|
|
166
169
|
?draft: draft?,
|
|
167
|
-
?validate_formats: bool
|
|
170
|
+
?validate_formats: bool?,
|
|
171
|
+
?pattern_options: (RegexOptions | FancyRegexOptions)?
|
|
168
172
|
) -> Canonical::CanonicalSchema
|
|
169
173
|
|
|
170
174
|
# Create a validator with auto-detected draft version.
|
data/src/canonical.rs
CHANGED
|
@@ -14,13 +14,17 @@ use magnus::{
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
use crate::{
|
|
17
|
-
options::parse_draft_symbol,
|
|
17
|
+
options::{extract_pattern_options, parse_draft_symbol, RbPatternOptions},
|
|
18
18
|
ser::{to_schema_value, value_to_ruby},
|
|
19
19
|
static_id::define_rb_intern,
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
define_rb_intern!(static CANONICAL_KW_DRAFT: "draft");
|
|
23
23
|
define_rb_intern!(static CANONICAL_KW_VALIDATE_FORMATS: "validate_formats");
|
|
24
|
+
define_rb_intern!(static CANONICAL_KW_PATTERN_OPTIONS: "pattern_options");
|
|
25
|
+
|
|
26
|
+
type CanonicalKwArgs =
|
|
27
|
+
magnus::scan_args::KwArgs<(), (Option<Value>, Option<bool>, Option<Value>), ()>;
|
|
24
28
|
|
|
25
29
|
macro_rules! canonical_error_class {
|
|
26
30
|
($static_name:ident, $class_name:literal) => {
|
|
@@ -42,6 +46,7 @@ macro_rules! canonical_error_class {
|
|
|
42
46
|
|
|
43
47
|
canonical_error_class!(CANONICALIZATION_ERROR_CLASS, "CanonicalizationError");
|
|
44
48
|
canonical_error_class!(INVALID_SCHEMA_TYPE_CLASS, "InvalidSchemaType");
|
|
49
|
+
canonical_error_class!(INVALID_PATTERN_CLASS, "InvalidPattern");
|
|
45
50
|
|
|
46
51
|
fn canonicalization_error(ruby: &Ruby, error: CanonicalizationError) -> Error {
|
|
47
52
|
if let CanonicalizationError::ValidationError(validation_error) = error {
|
|
@@ -52,6 +57,9 @@ fn canonicalization_error(ruby: &Ruby, error: CanonicalizationError) -> Error {
|
|
|
52
57
|
CanonicalizationError::InvalidSchemaType(_) => {
|
|
53
58
|
Error::new(ruby.get_inner(&INVALID_SCHEMA_TYPE_CLASS), message)
|
|
54
59
|
}
|
|
60
|
+
CanonicalizationError::InvalidPattern { .. } => {
|
|
61
|
+
Error::new(ruby.get_inner(&INVALID_PATTERN_CLASS), message)
|
|
62
|
+
}
|
|
55
63
|
// `ValidationError` returns above; future variants fall back to the base canonical error.
|
|
56
64
|
_ => Error::new(ruby.get_inner(&CANONICALIZATION_ERROR_CLASS), message),
|
|
57
65
|
}
|
|
@@ -174,7 +182,11 @@ impl RbCanonicalSchema {
|
|
|
174
182
|
additional_properties: view.additional_properties,
|
|
175
183
|
})
|
|
176
184
|
.as_value(),
|
|
185
|
+
CanonicalView::Not(schema) => ruby.obj_wrap(NotView { schema: *schema }).as_value(),
|
|
186
|
+
CanonicalView::AllOf(branches) => ruby.obj_wrap(AllOfView { branches }).as_value(),
|
|
177
187
|
CanonicalView::AnyOf(branches) => ruby.obj_wrap(AnyOfView { branches }).as_value(),
|
|
188
|
+
CanonicalView::OneOf(branches) => ruby.obj_wrap(OneOfView { branches }).as_value(),
|
|
189
|
+
CanonicalView::Reference(uri) => ruby.obj_wrap(ReferenceView { uri }).as_value(),
|
|
178
190
|
CanonicalView::Raw(schema) => ruby.obj_wrap(RawView { schema }).as_value(),
|
|
179
191
|
}
|
|
180
192
|
}
|
|
@@ -828,6 +840,147 @@ impl AnyOfView {
|
|
|
828
840
|
}
|
|
829
841
|
}
|
|
830
842
|
|
|
843
|
+
/// A value matches iff exactly one branch matches.
|
|
844
|
+
#[derive(magnus::TypedData)]
|
|
845
|
+
#[magnus(class = "JSONSchema::Canonical::OneOfView", free_immediately)]
|
|
846
|
+
pub struct OneOfView {
|
|
847
|
+
branches: Vec<CanonicalSchema>,
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
impl DataTypeFunctions for OneOfView {}
|
|
851
|
+
|
|
852
|
+
impl OneOfView {
|
|
853
|
+
fn branches(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
|
|
854
|
+
let array = ruby.ary_new_capa(rb_self.branches.len());
|
|
855
|
+
for branch in &rb_self.branches {
|
|
856
|
+
array.push(
|
|
857
|
+
ruby.obj_wrap(RbCanonicalSchema {
|
|
858
|
+
inner: branch.clone(),
|
|
859
|
+
})
|
|
860
|
+
.as_value(),
|
|
861
|
+
)?;
|
|
862
|
+
}
|
|
863
|
+
Ok(array.as_value())
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
|
|
867
|
+
let kinds = ruby.ary_new_capa(rb_self.branches.len());
|
|
868
|
+
for branch in &rb_self.branches {
|
|
869
|
+
kinds.push(ruby.sym_new(branch.kind().as_str()).as_value())?;
|
|
870
|
+
}
|
|
871
|
+
Ok(format!(
|
|
872
|
+
"#<JSONSchema::Canonical::OneOfView branches={}>",
|
|
873
|
+
kinds.as_value().inspect()
|
|
874
|
+
))
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
|
|
878
|
+
let hash = ruby.hash_new();
|
|
879
|
+
hash.aset(ruby.sym_new("branches"), Self::branches(ruby, rb_self)?)?;
|
|
880
|
+
Ok(hash)
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/// A value matches iff every branch matches.
|
|
885
|
+
#[derive(magnus::TypedData)]
|
|
886
|
+
#[magnus(class = "JSONSchema::Canonical::AllOfView", free_immediately)]
|
|
887
|
+
pub struct AllOfView {
|
|
888
|
+
branches: Vec<CanonicalSchema>,
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
impl DataTypeFunctions for AllOfView {}
|
|
892
|
+
|
|
893
|
+
impl AllOfView {
|
|
894
|
+
fn branches(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
|
|
895
|
+
let array = ruby.ary_new_capa(rb_self.branches.len());
|
|
896
|
+
for branch in &rb_self.branches {
|
|
897
|
+
array.push(
|
|
898
|
+
ruby.obj_wrap(RbCanonicalSchema {
|
|
899
|
+
inner: branch.clone(),
|
|
900
|
+
})
|
|
901
|
+
.as_value(),
|
|
902
|
+
)?;
|
|
903
|
+
}
|
|
904
|
+
Ok(array.as_value())
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
|
|
908
|
+
let kinds = ruby.ary_new_capa(rb_self.branches.len());
|
|
909
|
+
for branch in &rb_self.branches {
|
|
910
|
+
kinds.push(ruby.sym_new(branch.kind().as_str()).as_value())?;
|
|
911
|
+
}
|
|
912
|
+
Ok(format!(
|
|
913
|
+
"#<JSONSchema::Canonical::AllOfView branches={}>",
|
|
914
|
+
kinds.as_value().inspect()
|
|
915
|
+
))
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
|
|
919
|
+
let hash = ruby.hash_new();
|
|
920
|
+
hash.aset(ruby.sym_new("branches"), Self::branches(ruby, rb_self)?)?;
|
|
921
|
+
Ok(hash)
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/// The complement of `schema`, preserving a symbolic ref under `not`, conditionals, and `oneOf`.
|
|
926
|
+
#[derive(magnus::TypedData)]
|
|
927
|
+
#[magnus(class = "JSONSchema::Canonical::NotView", free_immediately)]
|
|
928
|
+
pub struct NotView {
|
|
929
|
+
schema: CanonicalSchema,
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
impl DataTypeFunctions for NotView {}
|
|
933
|
+
|
|
934
|
+
impl NotView {
|
|
935
|
+
fn schema(ruby: &Ruby, rb_self: &Self) -> Value {
|
|
936
|
+
ruby.obj_wrap(RbCanonicalSchema {
|
|
937
|
+
inner: rb_self.schema.clone(),
|
|
938
|
+
})
|
|
939
|
+
.as_value()
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
fn inspect(rb_self: &Self) -> String {
|
|
943
|
+
format!(
|
|
944
|
+
"#<JSONSchema::Canonical::NotView schema={}>",
|
|
945
|
+
rb_self.schema.kind().as_str()
|
|
946
|
+
)
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
|
|
950
|
+
let hash = ruby.hash_new();
|
|
951
|
+
hash.aset(ruby.sym_new("schema"), Self::schema(ruby, rb_self))?;
|
|
952
|
+
Ok(hash)
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
/// A symbolic JSON Schema reference.
|
|
957
|
+
#[derive(magnus::TypedData)]
|
|
958
|
+
#[magnus(class = "JSONSchema::Canonical::ReferenceView", free_immediately)]
|
|
959
|
+
pub struct ReferenceView {
|
|
960
|
+
uri: String,
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
impl DataTypeFunctions for ReferenceView {}
|
|
964
|
+
|
|
965
|
+
impl ReferenceView {
|
|
966
|
+
fn uri(rb_self: &Self) -> String {
|
|
967
|
+
rb_self.uri.clone()
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
fn inspect(rb_self: &Self) -> String {
|
|
971
|
+
format!(
|
|
972
|
+
"#<JSONSchema::Canonical::ReferenceView uri={:?}>",
|
|
973
|
+
rb_self.uri
|
|
974
|
+
)
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
|
|
978
|
+
let hash = ruby.hash_new();
|
|
979
|
+
hash.aset(ruby.sym_new("uri"), rb_self.uri.clone())?;
|
|
980
|
+
Ok(hash)
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
831
984
|
/// Exactly one admitted value.
|
|
832
985
|
#[derive(magnus::TypedData)]
|
|
833
986
|
#[magnus(class = "JSONSchema::Canonical::ConstView", free_immediately)]
|
|
@@ -892,12 +1045,16 @@ fn canonicalize(ruby: &Ruby, args: &[Value]) -> Result<Value, Error> {
|
|
|
892
1045
|
let parsed = scan_args::<(Value,), (), (), (), _, ()>(args)?;
|
|
893
1046
|
let (schema_arg,) = parsed.required;
|
|
894
1047
|
let keywords: RHash = parsed.keywords;
|
|
895
|
-
let base_kwargs:
|
|
1048
|
+
let base_kwargs: CanonicalKwArgs = get_kwargs(
|
|
896
1049
|
keywords,
|
|
897
1050
|
&[],
|
|
898
|
-
&[
|
|
1051
|
+
&[
|
|
1052
|
+
*CANONICAL_KW_DRAFT,
|
|
1053
|
+
*CANONICAL_KW_VALIDATE_FORMATS,
|
|
1054
|
+
*CANONICAL_KW_PATTERN_OPTIONS,
|
|
1055
|
+
],
|
|
899
1056
|
)?;
|
|
900
|
-
let (draft_val, validate_formats) = base_kwargs.optional;
|
|
1057
|
+
let (draft_val, validate_formats, pattern_options) = base_kwargs.optional;
|
|
901
1058
|
|
|
902
1059
|
let schema_value = to_schema_value(ruby, schema_arg)?;
|
|
903
1060
|
let mut options = jsonschema::canonical::options();
|
|
@@ -907,6 +1064,12 @@ fn canonicalize(ruby: &Ruby, args: &[Value]) -> Result<Value, Error> {
|
|
|
907
1064
|
if let Some(validate_formats) = validate_formats {
|
|
908
1065
|
options = options.should_validate_formats(validate_formats);
|
|
909
1066
|
}
|
|
1067
|
+
if let Some(val) = pattern_options {
|
|
1068
|
+
match extract_pattern_options(ruby, val)? {
|
|
1069
|
+
RbPatternOptions::Fancy(inner) => options = options.with_pattern_options(inner),
|
|
1070
|
+
RbPatternOptions::Regex(inner) => options = options.with_pattern_options(inner),
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
910
1073
|
options
|
|
911
1074
|
.canonicalize(&schema_value)
|
|
912
1075
|
.map(|inner| ruby.obj_wrap(RbCanonicalSchema { inner }).as_value())
|
|
@@ -919,6 +1082,7 @@ pub(crate) fn init_canonical(ruby: &Ruby, module: &RModule) -> Result<(), Error>
|
|
|
919
1082
|
let base_error =
|
|
920
1083
|
canonical_module.define_error("CanonicalizationError", ruby.exception_standard_error())?;
|
|
921
1084
|
canonical_module.define_error("InvalidSchemaType", base_error)?;
|
|
1085
|
+
canonical_module.define_error("InvalidPattern", base_error)?;
|
|
922
1086
|
|
|
923
1087
|
let canonical_schema = canonical_module.define_class("CanonicalSchema", ruby.class_object())?;
|
|
924
1088
|
canonical_schema.define_method(
|
|
@@ -1055,6 +1219,29 @@ pub(crate) fn init_canonical(ruby: &Ruby, module: &RModule) -> Result<(), Error>
|
|
|
1055
1219
|
any_of_view.define_method("inspect", method!(AnyOfView::inspect, 0))?;
|
|
1056
1220
|
any_of_view.define_method("deconstruct_keys", method!(AnyOfView::deconstruct_keys, 1))?;
|
|
1057
1221
|
|
|
1222
|
+
let one_of_view = canonical_module.define_class("OneOfView", ruby.class_object())?;
|
|
1223
|
+
one_of_view.define_method("branches", method!(OneOfView::branches, 0))?;
|
|
1224
|
+
one_of_view.define_method("inspect", method!(OneOfView::inspect, 0))?;
|
|
1225
|
+
one_of_view.define_method("deconstruct_keys", method!(OneOfView::deconstruct_keys, 1))?;
|
|
1226
|
+
|
|
1227
|
+
let all_of_view = canonical_module.define_class("AllOfView", ruby.class_object())?;
|
|
1228
|
+
all_of_view.define_method("branches", method!(AllOfView::branches, 0))?;
|
|
1229
|
+
all_of_view.define_method("inspect", method!(AllOfView::inspect, 0))?;
|
|
1230
|
+
all_of_view.define_method("deconstruct_keys", method!(AllOfView::deconstruct_keys, 1))?;
|
|
1231
|
+
|
|
1232
|
+
let not_view = canonical_module.define_class("NotView", ruby.class_object())?;
|
|
1233
|
+
not_view.define_method("schema", method!(NotView::schema, 0))?;
|
|
1234
|
+
not_view.define_method("inspect", method!(NotView::inspect, 0))?;
|
|
1235
|
+
not_view.define_method("deconstruct_keys", method!(NotView::deconstruct_keys, 1))?;
|
|
1236
|
+
|
|
1237
|
+
let reference_view = canonical_module.define_class("ReferenceView", ruby.class_object())?;
|
|
1238
|
+
reference_view.define_method("uri", method!(ReferenceView::uri, 0))?;
|
|
1239
|
+
reference_view.define_method("inspect", method!(ReferenceView::inspect, 0))?;
|
|
1240
|
+
reference_view.define_method(
|
|
1241
|
+
"deconstruct_keys",
|
|
1242
|
+
method!(ReferenceView::deconstruct_keys, 1),
|
|
1243
|
+
)?;
|
|
1244
|
+
|
|
1058
1245
|
let raw_view = canonical_module.define_class("RawView", ruby.class_object())?;
|
|
1059
1246
|
raw_view.define_method("schema", method!(RawView::schema, 0))?;
|
|
1060
1247
|
raw_view.define_method("inspect", method!(RawView::inspect, 0))?;
|
data/src/options.rs
CHANGED
|
@@ -741,32 +741,9 @@ pub fn make_options_from_kwargs(
|
|
|
741
741
|
}
|
|
742
742
|
|
|
743
743
|
if let Some(val) = pattern_options_val {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
po = po.backtrack_limit(limit);
|
|
748
|
-
}
|
|
749
|
-
if let Some(limit) = fancy_opts.size_limit {
|
|
750
|
-
po = po.size_limit(limit);
|
|
751
|
-
}
|
|
752
|
-
if let Some(limit) = fancy_opts.dfa_size_limit {
|
|
753
|
-
po = po.dfa_size_limit(limit);
|
|
754
|
-
}
|
|
755
|
-
opts = opts.with_pattern_options(po);
|
|
756
|
-
} else if let Ok(regex_opts) = <&RegexOptions>::try_convert(val) {
|
|
757
|
-
let mut po = jsonschema::PatternOptions::regex();
|
|
758
|
-
if let Some(limit) = regex_opts.size_limit {
|
|
759
|
-
po = po.size_limit(limit);
|
|
760
|
-
}
|
|
761
|
-
if let Some(limit) = regex_opts.dfa_size_limit {
|
|
762
|
-
po = po.dfa_size_limit(limit);
|
|
763
|
-
}
|
|
764
|
-
opts = opts.with_pattern_options(po);
|
|
765
|
-
} else {
|
|
766
|
-
return Err(Error::new(
|
|
767
|
-
ruby.exception_type_error(),
|
|
768
|
-
"pattern_options must be a RegexOptions or FancyRegexOptions instance",
|
|
769
|
-
));
|
|
744
|
+
match extract_pattern_options(ruby, val)? {
|
|
745
|
+
RbPatternOptions::Fancy(inner) => opts = opts.with_pattern_options(inner),
|
|
746
|
+
RbPatternOptions::Regex(inner) => opts = opts.with_pattern_options(inner),
|
|
770
747
|
}
|
|
771
748
|
}
|
|
772
749
|
|
|
@@ -953,6 +930,42 @@ impl RegexOptions {
|
|
|
953
930
|
}
|
|
954
931
|
}
|
|
955
932
|
|
|
933
|
+
/// A `pattern_options` argument converted into [`jsonschema::PatternOptions`].
|
|
934
|
+
pub(crate) enum RbPatternOptions {
|
|
935
|
+
Fancy(jsonschema::PatternOptions<jsonschema::FancyRegex>),
|
|
936
|
+
Regex(jsonschema::PatternOptions<jsonschema::Regex>),
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
pub(crate) fn extract_pattern_options(ruby: &Ruby, val: Value) -> Result<RbPatternOptions, Error> {
|
|
940
|
+
if let Ok(fancy_opts) = <&FancyRegexOptions>::try_convert(val) {
|
|
941
|
+
let mut po = jsonschema::PatternOptions::fancy_regex();
|
|
942
|
+
if let Some(limit) = fancy_opts.backtrack_limit {
|
|
943
|
+
po = po.backtrack_limit(limit);
|
|
944
|
+
}
|
|
945
|
+
if let Some(limit) = fancy_opts.size_limit {
|
|
946
|
+
po = po.size_limit(limit);
|
|
947
|
+
}
|
|
948
|
+
if let Some(limit) = fancy_opts.dfa_size_limit {
|
|
949
|
+
po = po.dfa_size_limit(limit);
|
|
950
|
+
}
|
|
951
|
+
Ok(RbPatternOptions::Fancy(po))
|
|
952
|
+
} else if let Ok(regex_opts) = <&RegexOptions>::try_convert(val) {
|
|
953
|
+
let mut po = jsonschema::PatternOptions::regex();
|
|
954
|
+
if let Some(limit) = regex_opts.size_limit {
|
|
955
|
+
po = po.size_limit(limit);
|
|
956
|
+
}
|
|
957
|
+
if let Some(limit) = regex_opts.dfa_size_limit {
|
|
958
|
+
po = po.dfa_size_limit(limit);
|
|
959
|
+
}
|
|
960
|
+
Ok(RbPatternOptions::Regex(po))
|
|
961
|
+
} else {
|
|
962
|
+
Err(Error::new(
|
|
963
|
+
ruby.exception_type_error(),
|
|
964
|
+
"pattern_options must be a RegexOptions or FancyRegexOptions instance",
|
|
965
|
+
))
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
956
969
|
#[magnus::wrap(class = "JSONSchema::FancyRegexOptions", free_immediately, size)]
|
|
957
970
|
pub struct FancyRegexOptions {
|
|
958
971
|
pub backtrack_limit: Option<usize>,
|