jsonschema_rs 0.49.1 → 0.49.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d150c4402ac7014d11674fba8a3e7ae36638e1a671010b4b8494ede16c03858
4
- data.tar.gz: 4af066e13c47db2d317113d3a6454eae0e2ad60f16c52b31648da7889055bef3
3
+ metadata.gz: 1f9c13c1388f5e57ffff9783a04a15144954e15c0078414321bb7f699a7ebe6a
4
+ data.tar.gz: 866810b923d5654fc09def7495882a7e82bed9ac248594304885df21a9fb2699
5
5
  SHA512:
6
- metadata.gz: 75713f7e5827481f37962d21c00ed968c8386f020ad1ec054f33d742b7036ad13354741f62e35eba0b82eb161be1b189a83f71e3a99f3fceacd917c2f56d334c
7
- data.tar.gz: a7e7405400ba4dbf94954510ab490372c52258c16c61fe423285d73edcf8837e839601d462fe163bc289a040312d5bb32b9c25a7cd78323bf55b96de52abb613
6
+ metadata.gz: 31bb5ae7145e6dec76c88ad04e38f354abd7cb8853df576e260503d783c324da7cdd921e5472a647354247cd8b370fa79c6ea1c8e653164349b35f13f8ef81e4
7
+ data.tar.gz: ea2c1a7ec8afed706a4d05504b3f69e58c2ee574b373b64eb828ff1f6c2b977b539bbe4aa45966250e4ea6bab234f9e86cfbd974b72d34c4bc3738f94c3836cd
data/CHANGELOG.md CHANGED
@@ -2,6 +2,66 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.49.4] - 2026-08-04
6
+
7
+ ### Added
8
+
9
+ - Canonicalization of `not` a string format, which the string leaf carries as barred formats.
10
+ - Canonicalization of `not` an existential demand, which an array fails exactly when no element matches.
11
+ - Canonicalization of `not` a string value set, which the string leaf carries as excluded values.
12
+ - Canonicalization of `unevaluatedItems` beside `contains`, where the elements it matches are evaluated and the tail admits either.
13
+ - Canonicalization of `unevaluated*` beside `anyOf` or `oneOf`, where every branch evaluating the same keys or indexes pins what is left over.
14
+ - Canonicalization of `not` an array element schema, which an array fails exactly when one element violates it.
15
+ - `CanonicalSchema#intersect`, the values both schemas admit.
16
+ - `CanonicalSchema#negate`, the values a schema rejects.
17
+ - `CanonicalSchema#definition`, one reference target by URI.
18
+
19
+ ### Fixed
20
+
21
+ - An integer past `i64` admitted by a fractional bound `f64` rounds it onto, such as `-10000000000000000000000000` under `{"maximum": -10000000000000000000000000.1}`.
22
+ - An integer past `2^53` admitted by a bound `f64` rounds onto it, such as `9007199254740992` under `{"minimum": 9007199254740993}`.
23
+ - A `contains` subschema beside both `minContains` and `maxContains` overwriting a sibling keyword of the same name, such as `items`.
24
+
25
+ ### Performance
26
+
27
+ - `CanonicalSchema` hashing and equality cost the node instead of the whole document.
28
+
29
+ ## [0.49.3] - 2026-08-02
30
+
31
+ ### Added
32
+
33
+ - Canonicalization of a recursive schema with no finite witness, which now folds to `false`.
34
+ - 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`.
35
+ - Canonicalization of `minContains` under `uniqueItems`, where a demand asking for more matches than its own schema has distinct values now folds to `false`.
36
+ - Canonicalization of a Draft 4 `patternProperties` coverage closed by `additionalProperties: false`, spelled as the closed map it was parsed from.
37
+ - Canonicalization of a `oneOf` whose branches repeat, where a repeated branch can never contribute exactly one match.
38
+ - Canonicalization of a `$ref` whose target is an empty schema, which now folds to `false`.
39
+ - Canonicalization of `unevaluatedItems` beside `allOf`, where every branch must pass and so the indexes they evaluate are known without the instance.
40
+ - Canonicalization of `unevaluatedProperties` beside `allOf`, where every branch must pass and so what they evaluate is known without the instance.
41
+ - Canonicalization of a Draft 4 `type` list holding `integer` beside other types with `enum`, which previously modeled only when spelled as an `allOf`.
42
+ - Canonicalization of `patternProperties` patterns matching finitely many keys, such as `^a$` and `^(a|b)$`.
43
+ - Canonicalization of `unevaluatedProperties` and `unevaluatedItems` when no in-place applicator sits beside them.
44
+
45
+ ### Fixed
46
+
47
+ - `additionalItems` values that are not schemas silently ignored beside an array-form `items` (they should fail the build like `additionalProperties`).
48
+ - `additionalItems` beside a boolean `items` rejecting every instance, such as `{"additionalItems": false, "items": false}`.
49
+ - Draft 4 rejecting a size bound at or past `2^64`, such as `{"maxItems": 18446744073709551616}`.
50
+ - An integer past the `f64` range admitted by a fractional bound it exceeds, such as `1e400` under `{"exclusiveMaximum": 0.1}`.
51
+ - 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.
52
+ - Canonicalization reusing one definition's body for a same-named definition in another resource, when the name spells a canonical URI.
53
+ - `unevaluatedItems` counting `prefixItems` as evaluating elements before Draft 2020-12, where it is not a keyword.
54
+
55
+ ### Performance
56
+
57
+ - Up to 70% faster `evaluate`.
58
+
59
+ ## [0.49.2] - 2026-07-28
60
+
61
+ ### Performance
62
+
63
+ - Faster serialization of canonicalized schemas.
64
+
5
65
  ## [0.49.1] - 2026-07-25
6
66
 
7
67
  ### Fixed
@@ -226,7 +286,10 @@
226
286
 
227
287
  - Initial public release
228
288
 
229
- [Unreleased]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.1...HEAD
289
+ [Unreleased]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.4...HEAD
290
+ [0.49.4]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.3...ruby-v0.49.4
291
+ [0.49.3]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.2...ruby-v0.49.3
292
+ [0.49.2]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.1...ruby-v0.49.2
230
293
  [0.49.1]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.0...ruby-v0.49.1
231
294
  [0.49.0]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.48.5...ruby-v0.49.0
232
295
  [0.48.5]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.48.2...ruby-v0.48.5
data/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "jsonschema-rb"
3
- version = "0.49.1"
3
+ version = "0.49.4"
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.1", default-features = false, features = ["magnus", "arbitrary-precision", "resolve-http", "resolve-file", "tls-ring", "macros"] }
16
+ jsonschema = { version = "0.49.4", 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 }
@@ -693,9 +693,9 @@ dependencies = [
693
693
 
694
694
  [[package]]
695
695
  name = "jsonschema"
696
- version = "0.49.1"
696
+ version = "0.49.4"
697
697
  source = "registry+https://github.com/rust-lang/crates.io-index"
698
- checksum = "9cc9116a0f75b7336e55eb2a2a0ddef86c37cadf02924a571751aa123d5a0290"
698
+ checksum = "257549c093d8f3d043337ba0d507e8eeace2447dfae3f0ee37eb0f57d3df7655"
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.1"
729
+ version = "0.49.4"
730
730
  source = "registry+https://github.com/rust-lang/crates.io-index"
731
- checksum = "b78efbcc1da165d63e1944fa687b3c2c09e8e418e9481e25aeada6062160c1bf"
731
+ checksum = "b043434e5e987e02043a6fd8d0c2686c8db4fe31a37b373ef9b2a9b1f27b96c6"
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.1"
739
+ version = "0.49.4"
740
740
  source = "registry+https://github.com/rust-lang/crates.io-index"
741
- checksum = "10c6550900b4a6be61392b8ddeb62b5c057975371ce93fca76d92542015f98bf"
741
+ checksum = "892e0b0739e173cce25aef424366940b20eebe7dd29304a4b8484bbd1461cc8b"
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.1"
758
+ version = "0.49.4"
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.1"
771
+ version = "0.49.4"
772
772
  source = "registry+https://github.com/rust-lang/crates.io-index"
773
- checksum = "628a1f02bda4651d9a6088ee6386a92f0ee96255b0c99e9dfe1be91bf83bd838"
773
+ checksum = "474790e948498099d61ec85c10dc72d459d61298b7975eda7fb163af1934b134"
774
774
  dependencies = [
775
775
  "regex-syntax",
776
776
  ]
777
777
 
778
778
  [[package]]
779
779
  name = "jsonschema-value"
780
- version = "0.49.1"
780
+ version = "0.49.4"
781
781
  source = "registry+https://github.com/rust-lang/crates.io-index"
782
- checksum = "75d94a372f8d81d070fd405065c6b1168d8248d1d6adad073ac708de254698c6"
782
+ checksum = "8212315eb8e0bc44959d1af653cd5ec515771a3cdca966cfc0a10999bff144b9"
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.1"
1135
+ version = "0.49.4"
1136
1136
  source = "registry+https://github.com/rust-lang/crates.io-index"
1137
- checksum = "978badf4419c9d0e1bc6e7466e99277f829d768257670c46d88121ca75e34bf7"
1137
+ checksum = "2bf1a74e036be2546c0c81cdfad6b2def6a25bf31c4e34a468037058d3bd05c6"
1138
1138
  dependencies = [
1139
1139
  "ahash",
1140
1140
  "fluent-uri",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "jsonschema-rb-ext"
3
- version = "0.49.1"
3
+ version = "0.49.4"
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.1", default-features = false, features = ["magnus", "arbitrary-precision", "resolve-http", "resolve-file", "tls-ring", "macros"] }
13
+ jsonschema = { version = "0.49.4", 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.1"
16
+ referencing = "0.49.4"
17
17
  serde = { version = "1", features = ["derive"] }
18
18
  serde_json = { version = "1", features = ["arbitrary_precision"] }
19
19
  zmij = "1"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSONSchema
4
- VERSION = "0.49.1"
4
+ VERSION = "0.49.4"
5
5
  end
data/sig/jsonschema.rbs CHANGED
@@ -32,12 +32,21 @@ module JSONSchema
32
32
  class InvalidPattern < CanonicalizationError
33
33
  end
34
34
 
35
+ class IncompatibleOperands < CanonicalizationError
36
+ end
37
+
38
+ class UnmodeledOperand < CanonicalizationError
39
+ end
40
+
35
41
  # A schema reduced to canonical form: schemas accepting the same values share one form.
36
42
  class CanonicalSchema
37
43
  def to_json_schema: () -> untyped
38
44
  def draft: () -> JSONSchema::draft
39
45
  def kind: () -> kind
40
46
  def view: () -> view
47
+ def intersect: (CanonicalSchema other) -> CanonicalSchema
48
+ def negate: () -> CanonicalSchema?
49
+ def definition: (String uri) -> CanonicalSchema?
41
50
  def definitions: () -> Hash[String, CanonicalSchema]
42
51
  def satisfiable?: () -> bool
43
52
  def inspect: () -> String
@@ -77,6 +86,7 @@ module JSONSchema
77
86
  def formats: () -> Array[String]
78
87
  def content_media_types: () -> Array[String]
79
88
  def content_encodings: () -> Array[String]
89
+ def excluded: () -> Array[String]
80
90
  def inspect: () -> String
81
91
  def deconstruct_keys: (untyped keys) -> Hash[Symbol, untyped]
82
92
  end
data/src/canonical.rs CHANGED
@@ -47,6 +47,8 @@ macro_rules! canonical_error_class {
47
47
  canonical_error_class!(CANONICALIZATION_ERROR_CLASS, "CanonicalizationError");
48
48
  canonical_error_class!(INVALID_SCHEMA_TYPE_CLASS, "InvalidSchemaType");
49
49
  canonical_error_class!(INVALID_PATTERN_CLASS, "InvalidPattern");
50
+ canonical_error_class!(INCOMPATIBLE_OPERANDS_CLASS, "IncompatibleOperands");
51
+ canonical_error_class!(UNMODELED_OPERAND_CLASS, "UnmodeledOperand");
50
52
 
51
53
  fn canonicalization_error(ruby: &Ruby, error: CanonicalizationError) -> Error {
52
54
  if let CanonicalizationError::ValidationError(validation_error) = error {
@@ -60,6 +62,12 @@ fn canonicalization_error(ruby: &Ruby, error: CanonicalizationError) -> Error {
60
62
  CanonicalizationError::InvalidPattern { .. } => {
61
63
  Error::new(ruby.get_inner(&INVALID_PATTERN_CLASS), message)
62
64
  }
65
+ CanonicalizationError::IncompatibleOperands(_) => {
66
+ Error::new(ruby.get_inner(&INCOMPATIBLE_OPERANDS_CLASS), message)
67
+ }
68
+ CanonicalizationError::UnmodeledOperand => {
69
+ Error::new(ruby.get_inner(&UNMODELED_OPERAND_CLASS), message)
70
+ }
63
71
  // `ValidationError` returns above; future variants fall back to the base canonical error.
64
72
  _ => Error::new(ruby.get_inner(&CANONICALIZATION_ERROR_CLASS), message),
65
73
  }
@@ -141,8 +149,10 @@ impl RbCanonicalSchema {
141
149
  max_length: view.max_length,
142
150
  patterns: view.patterns,
143
151
  formats: view.formats,
152
+ excluded_formats: view.excluded_formats,
144
153
  content_media_types: view.content_media_types,
145
154
  content_encodings: view.content_encodings,
155
+ excluded: view.excluded,
146
156
  })
147
157
  .as_value(),
148
158
  CanonicalView::Number(view) => ruby
@@ -182,11 +192,38 @@ impl RbCanonicalSchema {
182
192
  additional_properties: view.additional_properties,
183
193
  })
184
194
  .as_value(),
195
+ CanonicalView::Not(schema) => ruby.obj_wrap(NotView { schema: *schema }).as_value(),
196
+ CanonicalView::AllOf(branches) => ruby.obj_wrap(AllOfView { branches }).as_value(),
185
197
  CanonicalView::AnyOf(branches) => ruby.obj_wrap(AnyOfView { branches }).as_value(),
198
+ CanonicalView::OneOf(branches) => ruby.obj_wrap(OneOfView { branches }).as_value(),
199
+ CanonicalView::Reference(uri) => ruby.obj_wrap(ReferenceView { uri }).as_value(),
186
200
  CanonicalView::Raw(schema) => ruby.obj_wrap(RawView { schema }).as_value(),
187
201
  }
188
202
  }
189
203
 
204
+ fn intersect(ruby: &Ruby, rb_self: &Self, other: &Self) -> Result<Value, Error> {
205
+ rb_self
206
+ .inner
207
+ .intersect(&other.inner)
208
+ .map(|inner| ruby.obj_wrap(RbCanonicalSchema { inner }).as_value())
209
+ .map_err(|error| canonicalization_error(ruby, error))
210
+ }
211
+
212
+ fn negate(ruby: &Ruby, rb_self: &Self) -> Option<Value> {
213
+ rb_self
214
+ .inner
215
+ .negate()
216
+ .map(|inner| ruby.obj_wrap(RbCanonicalSchema { inner }).as_value())
217
+ }
218
+
219
+ #[allow(clippy::needless_pass_by_value)]
220
+ fn definition(ruby: &Ruby, rb_self: &Self, uri: String) -> Option<Value> {
221
+ rb_self
222
+ .inner
223
+ .definition(&uri)
224
+ .map(|inner| ruby.obj_wrap(RbCanonicalSchema { inner }).as_value())
225
+ }
226
+
190
227
  fn definitions(ruby: &Ruby, rb_self: &Self) -> Result<RHash, Error> {
191
228
  let hash = ruby.hash_new();
192
229
  for (uri, target) in rb_self.inner.definitions() {
@@ -359,8 +396,10 @@ pub struct StringView {
359
396
  max_length: Option<serde_json::Number>,
360
397
  patterns: Vec<String>,
361
398
  formats: Vec<String>,
399
+ excluded_formats: Vec<String>,
362
400
  content_media_types: Vec<String>,
363
401
  content_encodings: Vec<String>,
402
+ excluded: Vec<String>,
364
403
  }
365
404
 
366
405
  impl DataTypeFunctions for StringView {}
@@ -382,6 +421,10 @@ impl StringView {
382
421
  strings_to_ruby(ruby, &rb_self.formats)
383
422
  }
384
423
 
424
+ fn excluded_formats(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
425
+ strings_to_ruby(ruby, &rb_self.excluded_formats)
426
+ }
427
+
385
428
  fn content_media_types(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
386
429
  strings_to_ruby(ruby, &rb_self.content_media_types)
387
430
  }
@@ -390,15 +433,21 @@ impl StringView {
390
433
  strings_to_ruby(ruby, &rb_self.content_encodings)
391
434
  }
392
435
 
436
+ fn excluded(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
437
+ strings_to_ruby(ruby, &rb_self.excluded)
438
+ }
439
+
393
440
  fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
394
441
  Ok(format!(
395
- "#<JSONSchema::Canonical::StringView min_length={} max_length={} patterns={} formats={} content_media_types={} content_encodings={}>",
442
+ "#<JSONSchema::Canonical::StringView min_length={} max_length={} patterns={} formats={} excluded_formats={} content_media_types={} content_encodings={} excluded={}>",
396
443
  Self::min_length(ruby, rb_self)?.inspect(),
397
444
  Self::max_length(ruby, rb_self)?.inspect(),
398
445
  Self::patterns(ruby, rb_self)?.inspect(),
399
446
  Self::formats(ruby, rb_self)?.inspect(),
447
+ Self::excluded_formats(ruby, rb_self)?.inspect(),
400
448
  Self::content_media_types(ruby, rb_self)?.inspect(),
401
- Self::content_encodings(ruby, rb_self)?.inspect()
449
+ Self::content_encodings(ruby, rb_self)?.inspect(),
450
+ Self::excluded(ruby, rb_self)?.inspect()
402
451
  ))
403
452
  }
404
453
 
@@ -408,6 +457,10 @@ impl StringView {
408
457
  hash.aset(ruby.sym_new("max_length"), Self::max_length(ruby, rb_self)?)?;
409
458
  hash.aset(ruby.sym_new("patterns"), Self::patterns(ruby, rb_self)?)?;
410
459
  hash.aset(ruby.sym_new("formats"), Self::formats(ruby, rb_self)?)?;
460
+ hash.aset(
461
+ ruby.sym_new("excluded_formats"),
462
+ Self::excluded_formats(ruby, rb_self)?,
463
+ )?;
411
464
  hash.aset(
412
465
  ruby.sym_new("content_media_types"),
413
466
  Self::content_media_types(ruby, rb_self)?,
@@ -416,6 +469,7 @@ impl StringView {
416
469
  ruby.sym_new("content_encodings"),
417
470
  Self::content_encodings(ruby, rb_self)?,
418
471
  )?;
472
+ hash.aset(ruby.sym_new("excluded"), Self::excluded(ruby, rb_self)?)?;
419
473
  Ok(hash)
420
474
  }
421
475
  }
@@ -836,6 +890,147 @@ impl AnyOfView {
836
890
  }
837
891
  }
838
892
 
893
+ /// A value matches iff exactly one branch matches.
894
+ #[derive(magnus::TypedData)]
895
+ #[magnus(class = "JSONSchema::Canonical::OneOfView", free_immediately)]
896
+ pub struct OneOfView {
897
+ branches: Vec<CanonicalSchema>,
898
+ }
899
+
900
+ impl DataTypeFunctions for OneOfView {}
901
+
902
+ impl OneOfView {
903
+ fn branches(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
904
+ let array = ruby.ary_new_capa(rb_self.branches.len());
905
+ for branch in &rb_self.branches {
906
+ array.push(
907
+ ruby.obj_wrap(RbCanonicalSchema {
908
+ inner: branch.clone(),
909
+ })
910
+ .as_value(),
911
+ )?;
912
+ }
913
+ Ok(array.as_value())
914
+ }
915
+
916
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
917
+ let kinds = ruby.ary_new_capa(rb_self.branches.len());
918
+ for branch in &rb_self.branches {
919
+ kinds.push(ruby.sym_new(branch.kind().as_str()).as_value())?;
920
+ }
921
+ Ok(format!(
922
+ "#<JSONSchema::Canonical::OneOfView branches={}>",
923
+ kinds.as_value().inspect()
924
+ ))
925
+ }
926
+
927
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
928
+ let hash = ruby.hash_new();
929
+ hash.aset(ruby.sym_new("branches"), Self::branches(ruby, rb_self)?)?;
930
+ Ok(hash)
931
+ }
932
+ }
933
+
934
+ /// A value matches iff every branch matches.
935
+ #[derive(magnus::TypedData)]
936
+ #[magnus(class = "JSONSchema::Canonical::AllOfView", free_immediately)]
937
+ pub struct AllOfView {
938
+ branches: Vec<CanonicalSchema>,
939
+ }
940
+
941
+ impl DataTypeFunctions for AllOfView {}
942
+
943
+ impl AllOfView {
944
+ fn branches(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
945
+ let array = ruby.ary_new_capa(rb_self.branches.len());
946
+ for branch in &rb_self.branches {
947
+ array.push(
948
+ ruby.obj_wrap(RbCanonicalSchema {
949
+ inner: branch.clone(),
950
+ })
951
+ .as_value(),
952
+ )?;
953
+ }
954
+ Ok(array.as_value())
955
+ }
956
+
957
+ fn inspect(ruby: &Ruby, rb_self: &Self) -> Result<String, Error> {
958
+ let kinds = ruby.ary_new_capa(rb_self.branches.len());
959
+ for branch in &rb_self.branches {
960
+ kinds.push(ruby.sym_new(branch.kind().as_str()).as_value())?;
961
+ }
962
+ Ok(format!(
963
+ "#<JSONSchema::Canonical::AllOfView branches={}>",
964
+ kinds.as_value().inspect()
965
+ ))
966
+ }
967
+
968
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
969
+ let hash = ruby.hash_new();
970
+ hash.aset(ruby.sym_new("branches"), Self::branches(ruby, rb_self)?)?;
971
+ Ok(hash)
972
+ }
973
+ }
974
+
975
+ /// The complement of `schema`, preserving a symbolic ref under `not`, conditionals, and `oneOf`.
976
+ #[derive(magnus::TypedData)]
977
+ #[magnus(class = "JSONSchema::Canonical::NotView", free_immediately)]
978
+ pub struct NotView {
979
+ schema: CanonicalSchema,
980
+ }
981
+
982
+ impl DataTypeFunctions for NotView {}
983
+
984
+ impl NotView {
985
+ fn schema(ruby: &Ruby, rb_self: &Self) -> Value {
986
+ ruby.obj_wrap(RbCanonicalSchema {
987
+ inner: rb_self.schema.clone(),
988
+ })
989
+ .as_value()
990
+ }
991
+
992
+ fn inspect(rb_self: &Self) -> String {
993
+ format!(
994
+ "#<JSONSchema::Canonical::NotView schema={}>",
995
+ rb_self.schema.kind().as_str()
996
+ )
997
+ }
998
+
999
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
1000
+ let hash = ruby.hash_new();
1001
+ hash.aset(ruby.sym_new("schema"), Self::schema(ruby, rb_self))?;
1002
+ Ok(hash)
1003
+ }
1004
+ }
1005
+
1006
+ /// A symbolic JSON Schema reference.
1007
+ #[derive(magnus::TypedData)]
1008
+ #[magnus(class = "JSONSchema::Canonical::ReferenceView", free_immediately)]
1009
+ pub struct ReferenceView {
1010
+ uri: String,
1011
+ }
1012
+
1013
+ impl DataTypeFunctions for ReferenceView {}
1014
+
1015
+ impl ReferenceView {
1016
+ fn uri(rb_self: &Self) -> String {
1017
+ rb_self.uri.clone()
1018
+ }
1019
+
1020
+ fn inspect(rb_self: &Self) -> String {
1021
+ format!(
1022
+ "#<JSONSchema::Canonical::ReferenceView uri={:?}>",
1023
+ rb_self.uri
1024
+ )
1025
+ }
1026
+
1027
+ fn deconstruct_keys(ruby: &Ruby, rb_self: &Self, _keys: Value) -> Result<RHash, Error> {
1028
+ let hash = ruby.hash_new();
1029
+ hash.aset(ruby.sym_new("uri"), rb_self.uri.clone())?;
1030
+ Ok(hash)
1031
+ }
1032
+ }
1033
+
839
1034
  /// Exactly one admitted value.
840
1035
  #[derive(magnus::TypedData)]
841
1036
  #[magnus(class = "JSONSchema::Canonical::ConstView", free_immediately)]
@@ -938,6 +1133,8 @@ pub(crate) fn init_canonical(ruby: &Ruby, module: &RModule) -> Result<(), Error>
938
1133
  canonical_module.define_error("CanonicalizationError", ruby.exception_standard_error())?;
939
1134
  canonical_module.define_error("InvalidSchemaType", base_error)?;
940
1135
  canonical_module.define_error("InvalidPattern", base_error)?;
1136
+ canonical_module.define_error("IncompatibleOperands", base_error)?;
1137
+ canonical_module.define_error("UnmodeledOperand", base_error)?;
941
1138
 
942
1139
  let canonical_schema = canonical_module.define_class("CanonicalSchema", ruby.class_object())?;
943
1140
  canonical_schema.define_method(
@@ -957,6 +1154,9 @@ pub(crate) fn init_canonical(ruby: &Ruby, module: &RModule) -> Result<(), Error>
957
1154
  method!(<RbCanonicalSchema as typed_data::Hash>::hash, 0),
958
1155
  )?;
959
1156
  canonical_schema.define_method("view", method!(RbCanonicalSchema::view, 0))?;
1157
+ canonical_schema.define_method("intersect", method!(RbCanonicalSchema::intersect, 1))?;
1158
+ canonical_schema.define_method("negate", method!(RbCanonicalSchema::negate, 0))?;
1159
+ canonical_schema.define_method("definition", method!(RbCanonicalSchema::definition, 1))?;
960
1160
  canonical_schema.define_method("definitions", method!(RbCanonicalSchema::definitions, 0))?;
961
1161
  canonical_schema.define_method("satisfiable?", method!(RbCanonicalSchema::satisfiable, 0))?;
962
1162
 
@@ -997,6 +1197,7 @@ pub(crate) fn init_canonical(ruby: &Ruby, module: &RModule) -> Result<(), Error>
997
1197
  string_view.define_method("max_length", method!(StringView::max_length, 0))?;
998
1198
  string_view.define_method("patterns", method!(StringView::patterns, 0))?;
999
1199
  string_view.define_method("formats", method!(StringView::formats, 0))?;
1200
+ string_view.define_method("excluded_formats", method!(StringView::excluded_formats, 0))?;
1000
1201
  string_view.define_method(
1001
1202
  "content_media_types",
1002
1203
  method!(StringView::content_media_types, 0),
@@ -1005,6 +1206,7 @@ pub(crate) fn init_canonical(ruby: &Ruby, module: &RModule) -> Result<(), Error>
1005
1206
  "content_encodings",
1006
1207
  method!(StringView::content_encodings, 0),
1007
1208
  )?;
1209
+ string_view.define_method("excluded", method!(StringView::excluded, 0))?;
1008
1210
  string_view.define_method("inspect", method!(StringView::inspect, 0))?;
1009
1211
  string_view.define_method("deconstruct_keys", method!(StringView::deconstruct_keys, 1))?;
1010
1212
 
@@ -1074,6 +1276,29 @@ pub(crate) fn init_canonical(ruby: &Ruby, module: &RModule) -> Result<(), Error>
1074
1276
  any_of_view.define_method("inspect", method!(AnyOfView::inspect, 0))?;
1075
1277
  any_of_view.define_method("deconstruct_keys", method!(AnyOfView::deconstruct_keys, 1))?;
1076
1278
 
1279
+ let one_of_view = canonical_module.define_class("OneOfView", ruby.class_object())?;
1280
+ one_of_view.define_method("branches", method!(OneOfView::branches, 0))?;
1281
+ one_of_view.define_method("inspect", method!(OneOfView::inspect, 0))?;
1282
+ one_of_view.define_method("deconstruct_keys", method!(OneOfView::deconstruct_keys, 1))?;
1283
+
1284
+ let all_of_view = canonical_module.define_class("AllOfView", ruby.class_object())?;
1285
+ all_of_view.define_method("branches", method!(AllOfView::branches, 0))?;
1286
+ all_of_view.define_method("inspect", method!(AllOfView::inspect, 0))?;
1287
+ all_of_view.define_method("deconstruct_keys", method!(AllOfView::deconstruct_keys, 1))?;
1288
+
1289
+ let not_view = canonical_module.define_class("NotView", ruby.class_object())?;
1290
+ not_view.define_method("schema", method!(NotView::schema, 0))?;
1291
+ not_view.define_method("inspect", method!(NotView::inspect, 0))?;
1292
+ not_view.define_method("deconstruct_keys", method!(NotView::deconstruct_keys, 1))?;
1293
+
1294
+ let reference_view = canonical_module.define_class("ReferenceView", ruby.class_object())?;
1295
+ reference_view.define_method("uri", method!(ReferenceView::uri, 0))?;
1296
+ reference_view.define_method("inspect", method!(ReferenceView::inspect, 0))?;
1297
+ reference_view.define_method(
1298
+ "deconstruct_keys",
1299
+ method!(ReferenceView::deconstruct_keys, 1),
1300
+ )?;
1301
+
1077
1302
  let raw_view = canonical_module.define_class("RawView", ruby.class_object())?;
1078
1303
  raw_view.define_method("schema", method!(RawView::schema, 0))?;
1079
1304
  raw_view.define_method("inspect", method!(RawView::inspect, 0))?;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonschema_rs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.49.1
4
+ version: 0.49.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Dygalo