jsonschema_rs 0.49.9-aarch64-linux → 0.50.0-aarch64-linux

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: a2656e11a6b0c73563c4654d5bddc77dfbafce7bd9533dc537502da4e07e50ba
4
- data.tar.gz: ede529f84246513d55bd47c7875a6894f91fb756d55764054f614228f7c81dab
3
+ metadata.gz: 25eabdf997035d336701b550d29389ed1f9b894beb03d77fc45a0b10ccb4d29c
4
+ data.tar.gz: d62cff75ffb98e41ce3977d518c2427f38b3625925b76c036b46c0f45b75de8e
5
5
  SHA512:
6
- metadata.gz: 72f5be7b2725263ef888a4b4ea585d76c84fb960403efe931bd4007bdc8583869184794211cc2af92c10a9ba61b7141b7791f0303ed7a9730160a80055f4475b
7
- data.tar.gz: 9d56ecadae2bd0db1fe0dfb319f9996b78236c08623223115cc7b5a2314c43e7da1ab08fa7e30da3cd4573b10c816c6150bc5f1fb60f4f91f68cf9165bd6b111
6
+ metadata.gz: 46b9f8e8fc9a227c31299f26f3542ca5885ec1f680956d723cbe6978fd4b280a87a24e9b0a277e103ba6290a1fe2392a28e7387f590e7801f254f3de9f0d37f2
7
+ data.tar.gz: fe336068954a246f515ea3adf1f9c269891fabeed2e286a7109df28f80d7ae2d100bebfa80cd62bb66251d472a800d87805dcec7d0fe95e440e988d55bf427d2
data/CHANGELOG.md CHANGED
@@ -2,6 +2,41 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.50.0] - 2026-08-20
6
+
7
+ ### Added
8
+
9
+ - `CanonicalSchema#union` and `CanonicalSchema#subtract`.
10
+ - `JSONSchema::Canonical::UnsupportedResult`, raised where the canonical form does not support a set operation's result.
11
+ - `JSONSchema::Canonical::IncompatibleOperands` where both operands read `#` and it names a different document on each side.
12
+ - `JSONSchema::Canonical::Containment`, `Satisfiability`, `Distinctness` and `Kind`: named constants for the symbols `covers`, `satisfiability`, `kind` and `ArrayView#distinctness` return, each with an `ALL` list.
13
+
14
+ ### Changed
15
+
16
+ - `CanonicalSchema#satisfiable?` is now `CanonicalSchema#satisfiability`, answering `:yes`, `:no`, or `:unknown` - `:yes` wherever a value can be exhibited, not only for the forms listing their members.
17
+ - `CanonicalSchema#covers` decides through the difference as well: `:no` where the argument keeps values the receiver rejects, `:yes` where nothing is left over.
18
+ - `CanonicalSchema#is_subset_of` is now `CanonicalSchema#covers`, answering `:yes`, `:no`, or `:unknown` for whether the receiver admits every value the argument admits.
19
+ - `CanonicalSchema#negate` raises where it used to return `nil`.
20
+ - `JSONSchema::Canonical::UnmodeledOperand` is now `JSONSchema::Canonical::UnsupportedOperand`, and means only that an operand is a `Raw` pass-through.
21
+
22
+ ### Fixed
23
+
24
+ - Combining nodes of two different documents repointing a `$ref` to `#` at the combined result instead of the document it was written in, including one named by a definition the result keeps.
25
+ - Intersecting a `$ref` whose target is `true` or `false`, which crashed the interpreter.
26
+ - A key constraint left un-narrowed once a run is out of intersections, which crashed the interpreter on the next read of it.
27
+ - `CanonicalSchema#covers` answering `:unknown` for a schema against itself, where that schema is a `$ref`.
28
+ - `CanonicalSchema#union` keeping a `$ref` beside the schema it names, where the other three operations read through it.
29
+ - `CanonicalSchema#covers` and `CanonicalSchema#subtract` cancelling two nodes written the same way whose `#` names a different document.
30
+ - Two results accepting the same values comparing unequal over the part of their documents neither reads.
31
+ - `additionalProperties` reaching a key the pattern map matches when a finite key constraint closes the map, which dropped values both operands accept.
32
+ - A recursive definition stopping every other pointer in the document from being read through.
33
+ - One `$defs` entry read past a wider schema written out at every use, rather than kept as the pointer it was.
34
+ - Set operations rejecting one document canonicalized twice, and a pruned result rejected against the document it came from, where the maps resolve every shared reference the same way.
35
+ - Set operations comparing a `$ref` as a pointer instead of reading through it, so a schema written with a `$ref` did not cancel against the same schema written out.
36
+ - `CanonicalSchema#subtract` asking for a complement where the difference is one of the operands or empty, declining on schemas it can subtract.
37
+ - Set operations keeping `$defs` entries the result no longer references, which then showed up in the emitted schema.
38
+ - `CanonicalSchema#union` declining over an approximated intersection, where the union itself is exact.
39
+
5
40
  ## [0.49.9] - 2026-08-10
6
41
 
7
42
  ### Added
@@ -387,7 +422,8 @@
387
422
 
388
423
  - Initial public release
389
424
 
390
- [Unreleased]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.9...HEAD
425
+ [Unreleased]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.50.0...HEAD
426
+ [0.50.0]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.9...ruby-v0.50.0
391
427
  [0.49.9]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.8...ruby-v0.49.9
392
428
  [0.49.8]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.7...ruby-v0.49.8
393
429
  [0.49.7]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.49.6...ruby-v0.49.7
data/README.md CHANGED
@@ -50,6 +50,7 @@ end
50
50
  - 🔧 Custom keywords and format validators
51
51
  - ✨ Meta-schema validation for schema documents
52
52
  - 📦 Schema bundling into Compound Schema Documents
53
+ - 🧮 Experimental schema canonicalization
53
54
  - ♦️ Supports Ruby 3.2, 3.4 and 4.0
54
55
 
55
56
  ### Supported drafts
@@ -291,6 +292,83 @@ dump_a == dump_b # => true
291
292
 
292
293
  Main use case: deduplicating equivalent JSON Schemas.
293
294
 
295
+ ## Schema Canonicalization
296
+
297
+ > **Experimental**: the canonicalization API may change in minor releases.
298
+
299
+ `JSONSchema.canonicalize` reduces a schema to a normal form without changing the values it accepts. Schemas that accept the same values reduce to equal `CanonicalSchema` objects, and contradictions reduce to `false`:
300
+
301
+ ```ruby
302
+ canonical = JSONSchema.canonicalize(
303
+ { "allOf" => [{ "type" => "integer", "minimum" => 0 }, { "minimum" => 10, "maximum" => 100 }] }
304
+ )
305
+ canonical.to_json_schema
306
+ # => {"$schema"=>"https://json-schema.org/draft/2020-12/schema",
307
+ # "type"=>"integer", "minimum"=>10, "maximum"=>100}
308
+
309
+ # However they were written, equivalent schemas compare equal
310
+ canonical == JSONSchema.canonicalize({ "type" => "integer", "maximum" => 100, "minimum" => 10 })
311
+ # => true
312
+
313
+ # A schema no value can satisfy collapses
314
+ JSONSchema.canonicalize({ "type" => "integer", "minimum" => 10, "maximum" => 5 }).satisfiability
315
+ # => :no, which is JSONSchema::Canonical::Satisfiability::NO
316
+ ```
317
+
318
+ A canonical schema *is* the set of values it accepts, so canonical schemas combine as sets. Every emitted schema carries `$schema`, left out of the comments below:
319
+
320
+ ```ruby
321
+ positive = JSONSchema.canonicalize({ "type" => "integer", "minimum" => 0 })
322
+ bounded = JSONSchema.canonicalize({ "type" => "integer", "maximum" => 100 })
323
+
324
+ # Every value both admit
325
+ positive.intersect(bounded).to_json_schema
326
+ # => {"type"=>"integer", "minimum"=>0, "maximum"=>100}
327
+
328
+ # Every value either admits
329
+ positive.union(bounded).to_json_schema
330
+ # => {"type"=>"integer"}
331
+
332
+ # Every value `positive` admits and `bounded` rejects
333
+ positive.subtract(bounded).to_json_schema
334
+ # => {"type"=>"integer", "minimum"=>101}
335
+
336
+ # Every value `positive` rejects, across the types it never admitted
337
+ positive.negate.to_json_schema
338
+ # => {"anyOf"=>[{"type"=>["null", "boolean", "string", "array", "object"]},
339
+ # {"type"=>"integer", "maximum"=>-1},
340
+ # {"type"=>"number", "not"=>{"multipleOf"=>1}}]}
341
+
342
+ positive.covers(bounded) # => :no - `bounded` takes negative integers, `positive` does not
343
+ positive.satisfiability # => :yes
344
+ ```
345
+
346
+ ### Comparing two versions of a schema
347
+
348
+ The difference answers what editing a schema did to the values it takes: it accepts exactly what the old schema took and the new one turns away, and is unsatisfiable exactly when nothing was lost.
349
+
350
+ ```ruby
351
+ old = JSONSchema.canonicalize({ "type" => "string" })
352
+ new = JSONSchema.canonicalize({ "type" => "string", "maxLength" => 50 })
353
+
354
+ # What `new` stopped accepting, as a schema
355
+ old.subtract(new).to_json_schema
356
+ # => {"$schema"=>"https://json-schema.org/draft/2020-12/schema",
357
+ # "type"=>"string", "minLength"=>51}
358
+
359
+ # Nothing is accepted that was not accepted before, so the change only narrows
360
+ new.subtract(old).satisfiability
361
+ # => :no
362
+ ```
363
+
364
+ Compare a request schema new-against-old and a response schema old-against-new: narrowing a request turns away payloads a caller used to send, widening a response returns values a caller never agreed to read.
365
+
366
+ `:no` on the difference proves nothing was lost. `:unknown` proves nothing either way.
367
+
368
+ `JSONSchema::Canonical::Containment`, `Satisfiability`, `Distinctness` and `Kind` hold these symbols as constants, each with an `ALL` list.
369
+
370
+ Both operands must share one setup - the same draft, format policy, regular-expression engine and definitions - or `IncompatibleOperands` is raised. `UnsupportedOperand` means an operand is a `Raw` pass-through, and `UnsupportedResult` that the canonical form does not support the result. All three live under `JSONSchema::Canonical`.
371
+
294
372
  ## Schema Bundling
295
373
 
296
374
  Produce a Compound Schema Document ([Appendix B](https://json-schema.org/draft/2020-12/json-schema-core#appendix-B)) by embedding all external `$ref` targets into a draft-appropriate container. The result validates identically to the original.
Binary file
Binary file
Binary file
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSONSchema
4
- VERSION = "0.49.9"
4
+ VERSION = "0.50.0"
5
5
  end
data/sig/jsonschema.rbs CHANGED
@@ -17,11 +17,64 @@ module JSONSchema
17
17
 
18
18
  # Structural discriminant of a canonical schema, one per view class.
19
19
  type kind = :multi_type | :typed_group | :string | :integer | :number | :array
20
- | :object | :const | :enum | :any_of | :true | :false | :raw
20
+ | :object | :const | :enum | :not | :all_of | :any_of | :one_of
21
+ | :reference | :true | :false | :raw
22
+
23
+ # What an array requires of its elements: all distinct, some repeated, or neither.
24
+ type distinctness = :unconstrained | :all_distinct | :some_repeated
25
+
26
+ # Whether one schema admits every value another does.
27
+ type containment = :yes | :no | :unknown
28
+
29
+ # Whether any value satisfies a schema.
30
+ type satisfiability = :yes | :no | :unknown
21
31
 
22
32
  type view = TrueView | FalseView | MultiTypeView | TypedGroupView | StringView
23
- | IntegerView | NumberView | ArrayView | ObjectView | AnyOfView
24
- | ConstView | EnumView | RawView
33
+ | IntegerView | NumberView | ArrayView | ObjectView | NotView
34
+ | AllOfView | AnyOfView | OneOfView | ReferenceView | ConstView
35
+ | EnumView | RawView
36
+
37
+ module Containment
38
+ YES: :yes
39
+ NO: :no
40
+ UNKNOWN: :unknown
41
+ ALL: Array[containment]
42
+ end
43
+
44
+ module Satisfiability
45
+ YES: :yes
46
+ NO: :no
47
+ UNKNOWN: :unknown
48
+ ALL: Array[satisfiability]
49
+ end
50
+
51
+ module Distinctness
52
+ UNCONSTRAINED: :unconstrained
53
+ ALL_DISTINCT: :all_distinct
54
+ SOME_REPEATED: :some_repeated
55
+ ALL: Array[distinctness]
56
+ end
57
+
58
+ module Kind
59
+ MULTI_TYPE: :multi_type
60
+ TYPED_GROUP: :typed_group
61
+ STRING: :string
62
+ INTEGER: :integer
63
+ NUMBER: :number
64
+ ARRAY: :array
65
+ OBJECT: :object
66
+ CONST: :const
67
+ ENUM: :enum
68
+ NOT: :not
69
+ ALL_OF: :all_of
70
+ ANY_OF: :any_of
71
+ ONE_OF: :one_of
72
+ REFERENCE: :reference
73
+ TRUE: :true
74
+ FALSE: :false
75
+ RAW: :raw
76
+ ALL: Array[kind]
77
+ end
25
78
 
26
79
  class CanonicalizationError < StandardError
27
80
  end
@@ -35,7 +88,10 @@ module JSONSchema
35
88
  class IncompatibleOperands < CanonicalizationError
36
89
  end
37
90
 
38
- class UnmodeledOperand < CanonicalizationError
91
+ class UnsupportedOperand < CanonicalizationError
92
+ end
93
+
94
+ class UnsupportedResult < CanonicalizationError
39
95
  end
40
96
 
41
97
  # A schema reduced to canonical form: schemas accepting the same values share one form.
@@ -45,11 +101,13 @@ module JSONSchema
45
101
  def kind: () -> kind
46
102
  def view: () -> view
47
103
  def intersect: (CanonicalSchema other) -> CanonicalSchema
48
- def is_subset_of: (CanonicalSchema other) -> bool?
49
- def negate: () -> CanonicalSchema?
104
+ def union: (CanonicalSchema other) -> CanonicalSchema
105
+ def subtract: (CanonicalSchema other) -> CanonicalSchema
106
+ def covers: (CanonicalSchema other) -> containment
107
+ def negate: () -> CanonicalSchema
50
108
  def definition: (String uri) -> CanonicalSchema?
51
109
  def definitions: () -> Hash[String, CanonicalSchema]
52
- def satisfiable?: () -> bool
110
+ def satisfiability: () -> satisfiability
53
111
  def inspect: () -> String
54
112
  def ==: (untyped other) -> bool
55
113
  def eql?: (untyped other) -> bool
@@ -121,7 +179,7 @@ module JSONSchema
121
179
  class ArrayView
122
180
  def min_items: () -> Integer?
123
181
  def max_items: () -> Integer?
124
- def distinctness: () -> (:unconstrained | :all_distinct | :some_repeated)
182
+ def distinctness: () -> distinctness
125
183
  def prefix_items: () -> Array[CanonicalSchema]
126
184
  def items: () -> CanonicalSchema?
127
185
  def contains: () -> Array[ContainsView]
@@ -129,7 +187,7 @@ module JSONSchema
129
187
  def deconstruct_keys: (untyped keys) -> Hash[Symbol, untyped]
130
188
  end
131
189
 
132
- # One `contains` demand of an array; an absent minimum spells the default of one.
190
+ # One `contains` requirement of an array; an absent minimum means the default of one.
133
191
  class ContainsView
134
192
  def schema: () -> CanonicalSchema
135
193
  def min_contains: () -> Integer?
@@ -168,6 +226,34 @@ module JSONSchema
168
226
  def deconstruct_keys: (untyped keys) -> Hash[Symbol, untyped]
169
227
  end
170
228
 
229
+ # The complement of an opaque schema.
230
+ class NotView
231
+ def schema: () -> CanonicalSchema
232
+ def inspect: () -> String
233
+ def deconstruct_keys: (untyped keys) -> Hash[Symbol, untyped]
234
+ end
235
+
236
+ # A value matches iff every branch matches.
237
+ class AllOfView
238
+ def branches: () -> Array[CanonicalSchema]
239
+ def inspect: () -> String
240
+ def deconstruct_keys: (untyped keys) -> Hash[Symbol, untyped]
241
+ end
242
+
243
+ # A value matches iff exactly one branch matches.
244
+ class OneOfView
245
+ def branches: () -> Array[CanonicalSchema]
246
+ def inspect: () -> String
247
+ def deconstruct_keys: (untyped keys) -> Hash[Symbol, untyped]
248
+ end
249
+
250
+ # The target a `$ref` names.
251
+ class ReferenceView
252
+ def uri: () -> String
253
+ def inspect: () -> String
254
+ def deconstruct_keys: (untyped keys) -> Hash[Symbol, untyped]
255
+ end
256
+
171
257
  # A value matches iff at least one branch matches.
172
258
  class AnyOfView
173
259
  def branches: () -> Array[CanonicalSchema]
@@ -189,7 +275,7 @@ module JSONSchema
189
275
  def deconstruct_keys: (untyped keys) -> Hash[Symbol, untyped]
190
276
  end
191
277
 
192
- # A schema the canonical form does not model structurally, kept verbatim.
278
+ # A schema the canonical form does not support structurally, kept verbatim.
193
279
  class RawView
194
280
  def schema: () -> untyped
195
281
  def inspect: () -> String
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonschema_rs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.49.9
4
+ version: 0.50.0
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Dmitry Dygalo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-09 00:00:00.000000000 Z
11
+ date: 2026-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal