jsonschema_rs 0.44.0 → 0.45.0

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: 51236b02371703841ea00783cfc0a9d5b97281a27a527c390795ab02f5e88aac
4
- data.tar.gz: 87fb69c295b4a82d16d20fab2368aa9eb7b90167f2135b411ee8b0279db0399d
3
+ metadata.gz: 8edaf1942b912082da745998a2b61bcb9d01b15078b788c5c459631c539f6a83
4
+ data.tar.gz: f6f35c2591c66ffe57bee54a12fd7b065fae77a96b7070abd82aae967cda8d39
5
5
  SHA512:
6
- metadata.gz: abc58a0cf0669380c5c3035a76586e45d952584cf5742878a451a10dab18ebfb5a7210bf80f022da8a3b302ead4364337554544537f7432e46161343b8cf7888
7
- data.tar.gz: 991fdcf4e5661180a09918c7bce74c3afd9adf73543b8f1ba4d0f2c046e2feccb4cb9bb757e3f315c126665d67455eaecd938d24338b8dd18c0f30b4b897ca59
6
+ metadata.gz: 0b44497016a6e8c454bff10e8d94b668045d981f68e4970bfc366c6c4a28bd92406fb557dcb508b78ad34278a05494184f9da3c8cff567d221a70710d928b0b4
7
+ data.tar.gz: c56077fb3714d3ff419de02fc7dd1bb876388987f9ae65f50b7b93a4ddba95e4a249df0f4c4fa2aeaebad9dfd1c6fba4e8ac08eb311f9305452f02c345465e88
data/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.45.0] - 2026-03-08
6
+
7
+ ### Added
8
+
9
+ - `JSONSchema.bundle(schema, ...)`: produce a Compound Schema Document with all external `$ref` targets embedded in a draft-appropriate container (`definitions` for Draft 4/6/7, `$defs` for Draft 2019-09/2020-12; [Appendix B](https://json-schema.org/draft/2020-12/json-schema-core#appendix-B)). [#791](https://github.com/Stranger6667/jsonschema/issues/791).
10
+ - `ValidationError#absolute_keyword_location` to get the absolute keyword location URI of the schema node that produced the error.
11
+
12
+ ## [0.44.1] - 2026-03-03
13
+
14
+ ### Fixed
15
+
16
+ - `hostname` format now applies legacy RFC 1034 semantics in Draft 4/6 and keeps IDNA A-label validation in Draft 7+.
17
+
5
18
  ## [0.44.0] - 2026-03-02
6
19
 
7
20
  ### Added
@@ -53,7 +66,9 @@
53
66
 
54
67
  - Initial public release
55
68
 
56
- [Unreleased]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.44.0...HEAD
69
+ [Unreleased]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.45.0...HEAD
70
+ [0.45.0]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.44.1...ruby-v0.45.0
71
+ [0.44.1]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.44.0...ruby-v0.44.1
57
72
  [0.44.0]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.43.0...ruby-v0.44.0
58
73
  [0.43.0]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.42.2...ruby-v0.43.0
59
74
  [0.42.2]: https://github.com/Stranger6667/jsonschema/compare/ruby-v0.42.1...ruby-v0.42.2
data/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "jsonschema-rb"
3
- version = "0.44.0"
3
+ version = "0.45.0"
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.44.0", default-features = false, features = ["arbitrary-precision", "resolve-http", "resolve-file", "tls-ring"] }
16
+ jsonschema = { version = "0.45.0", default-features = false, features = ["arbitrary-precision", "resolve-http", "resolve-file", "tls-ring"] }
17
17
  magnus = { version = "0.8", features = ["rb-sys"] }
18
18
  rb-sys = "0.9"
19
19
  serde = { workspace = true }
data/README.md CHANGED
@@ -49,6 +49,7 @@ end
49
49
  - 🌐 Remote reference fetching (network/file)
50
50
  - 🔧 Custom keywords and format validators
51
51
  - ✨ Meta-schema validation for schema documents
52
+ - 📦 Schema bundling into Compound Schema Documents
52
53
  - ♦️ Supports Ruby 3.2, 3.4 and 4.0
53
54
 
54
55
  ### Supported drafts
@@ -267,6 +268,30 @@ dump_a == dump_b # => true
267
268
 
268
269
  Main use case: deduplicating equivalent JSON Schemas.
269
270
 
271
+ ## Schema Bundling
272
+
273
+ 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.
274
+
275
+ ```ruby
276
+ address_schema = {
277
+ "$schema" => "https://json-schema.org/draft/2020-12/schema",
278
+ "$id" => "https://example.com/address.json",
279
+ "type" => "object",
280
+ "properties" => { "street" => { "type" => "string" }, "city" => { "type" => "string" } },
281
+ "required" => ["street", "city"]
282
+ }
283
+
284
+ schema = {
285
+ "$schema" => "https://json-schema.org/draft/2020-12/schema",
286
+ "type" => "object",
287
+ "properties" => { "home" => { "$ref" => "https://example.com/address.json" } },
288
+ "required" => ["home"]
289
+ }
290
+
291
+ registry = JSONSchema::Registry.new([["https://example.com/address.json", address_schema]])
292
+ bundled = JSONSchema.bundle(schema, registry: registry)
293
+ ```
294
+
270
295
  ## Meta-Schema Validation
271
296
 
272
297
  Validate that a JSON Schema document is itself valid:
@@ -603,9 +603,9 @@ dependencies = [
603
603
 
604
604
  [[package]]
605
605
  name = "ipnet"
606
- version = "2.11.0"
606
+ version = "2.12.0"
607
607
  source = "registry+https://github.com/rust-lang/crates.io-index"
608
- checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
608
+ checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
609
609
 
610
610
  [[package]]
611
611
  name = "iri-string"
@@ -666,9 +666,9 @@ dependencies = [
666
666
 
667
667
  [[package]]
668
668
  name = "jsonschema"
669
- version = "0.44.0"
669
+ version = "0.45.0"
670
670
  source = "registry+https://github.com/rust-lang/crates.io-index"
671
- checksum = "267fb27be492e66ab147d2ce0233d88ae465b93c3565016e73998729bf3fe60f"
671
+ checksum = "6f29616f6e19415398eb186964fb7cbbeef572c79bede3622a8277667924bbe3"
672
672
  dependencies = [
673
673
  "ahash",
674
674
  "bytecount",
@@ -696,7 +696,7 @@ dependencies = [
696
696
 
697
697
  [[package]]
698
698
  name = "jsonschema-rb-ext"
699
- version = "0.44.0"
699
+ version = "0.45.0"
700
700
  dependencies = [
701
701
  "jsonschema",
702
702
  "magnus",
@@ -1043,9 +1043,9 @@ dependencies = [
1043
1043
 
1044
1044
  [[package]]
1045
1045
  name = "referencing"
1046
- version = "0.44.0"
1046
+ version = "0.45.0"
1047
1047
  source = "registry+https://github.com/rust-lang/crates.io-index"
1048
- checksum = "12ecd0f3daefd4faff2e0821310c18e6e9d1fd00550bbd7e5a59d78184a071bc"
1048
+ checksum = "b8a618c14f8ba29d8193bb55e2bf13e4fb2b1115313ecb7ae94b43100c7ac7d5"
1049
1049
  dependencies = [
1050
1050
  "ahash",
1051
1051
  "fluent-uri",
@@ -1428,9 +1428,9 @@ dependencies = [
1428
1428
 
1429
1429
  [[package]]
1430
1430
  name = "tokio"
1431
- version = "1.49.0"
1431
+ version = "1.50.0"
1432
1432
  source = "registry+https://github.com/rust-lang/crates.io-index"
1433
- checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
1433
+ checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
1434
1434
  dependencies = [
1435
1435
  "bytes",
1436
1436
  "libc",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "jsonschema-rb-ext"
3
- version = "0.44.0"
3
+ version = "0.45.0"
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.44.0", default-features = false, features = ["arbitrary-precision", "resolve-http", "resolve-file", "tls-ring"] }
13
+ jsonschema = { version = "0.45.0", default-features = false, features = ["arbitrary-precision", "resolve-http", "resolve-file", "tls-ring"] }
14
14
  magnus = { version = "0.8", features = ["rb-sys"] }
15
15
  rb-sys = "0.9"
16
- referencing = "0.44.0"
16
+ referencing = "0.45.0"
17
17
  serde = { version = "1", features = ["derive"] }
18
18
  serde_json = { version = "1", features = ["arbitrary_precision"] }
19
19
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSONSchema
4
- VERSION = "0.44.0"
4
+ VERSION = "0.45.0"
5
5
  end
data/sig/jsonschema.rbs CHANGED
@@ -41,6 +41,19 @@ module JSONSchema
41
41
  ?http_options: HttpOptions?
42
42
  ) -> Validator
43
43
 
44
+ # Bundle a JSON Schema into a Compound Schema Document.
45
+ # All externally-referenced schemas reachable via $ref are embedded in a
46
+ # draft-appropriate container (definitions for Draft 4/6/7, $defs for
47
+ # Draft 2019-09/2020-12).
48
+ # Original $ref values are preserved unchanged.
49
+ def self.bundle: (
50
+ untyped schema,
51
+ ?draft: draft?,
52
+ ?retriever: (^(String) -> untyped)?,
53
+ ?registry: Registry?,
54
+ ?base_uri: String?
55
+ ) -> Hash[String, untyped]
56
+
44
57
  # Detect the JSON Schema draft for a schema and return the corresponding validator class.
45
58
  # Draft is detected automatically from the `$schema` field. Defaults to Draft202012Validator.
46
59
  def self.validator_cls_for: (untyped schema) -> (singleton(Draft4Validator) | singleton(Draft6Validator) | singleton(Draft7Validator) | singleton(Draft201909Validator) | singleton(Draft202012Validator))
data/src/lib.rs CHANGED
@@ -60,6 +60,7 @@ define_rb_intern!(static ID_AT_SCHEMA_PATH_POINTER: "@schema_path_pointer");
60
60
  define_rb_intern!(static ID_AT_EVALUATION_PATH_POINTER: "@evaluation_path_pointer");
61
61
  define_rb_intern!(static ID_AT_KIND: "@kind");
62
62
  define_rb_intern!(static ID_AT_INSTANCE: "@instance");
63
+ define_rb_intern!(static ID_AT_ABSOLUTE_KEYWORD_LOCATION: "@absolute_keyword_location");
63
64
  define_rb_intern!(static ID_CAUSE: "cause");
64
65
 
65
66
  define_rb_intern!(static ID_SYM_MESSAGE: "message");
@@ -72,6 +73,7 @@ define_rb_intern!(static ID_SYM_INSTANCE: "instance");
72
73
  define_rb_intern!(static ID_SYM_INSTANCE_PATH_POINTER: "instance_path_pointer");
73
74
  define_rb_intern!(static ID_SYM_SCHEMA_PATH_POINTER: "schema_path_pointer");
74
75
  define_rb_intern!(static ID_SYM_EVALUATION_PATH_POINTER: "evaluation_path_pointer");
76
+ define_rb_intern!(static ID_SYM_ABSOLUTE_KEYWORD_LOCATION: "absolute_keyword_location");
75
77
 
76
78
  struct BuiltValidator {
77
79
  validator: jsonschema::Validator,
@@ -373,11 +375,11 @@ fn into_ruby_error(
373
375
  mask,
374
376
  );
375
377
 
376
- let (instance, kind, instance_path, schema_path, evaluation_path) = error.into_parts();
378
+ let parts = error.into_parts();
377
379
 
378
- let instance_path_ptr = ruby.into_value(instance_path.as_str());
379
- let schema_path_ptr = ruby.into_value(schema_path.as_str());
380
- let evaluation_path_ptr = ruby.into_value(evaluation_path.as_str());
380
+ let instance_path_ptr = ruby.into_value(parts.instance_path.as_str());
381
+ let schema_path_ptr = ruby.into_value(parts.schema_path.as_str());
382
+ let evaluation_path_ptr = ruby.into_value(parts.evaluation_path.as_str());
381
383
 
382
384
  let into_path_segment = |segment: LocationSegment<'_>| -> Value {
383
385
  match segment {
@@ -386,8 +388,8 @@ fn into_ruby_error(
386
388
  }
387
389
  };
388
390
 
389
- let kind_obj = ValidationErrorKind::new(ruby, &kind, mask)?;
390
- let rb_instance = ser::value_to_ruby(ruby, instance.as_ref())?;
391
+ let kind_obj = ValidationErrorKind::new(ruby, &parts.kind, mask)?;
392
+ let rb_instance = ser::value_to_ruby(ruby, parts.instance.as_ref())?;
391
393
 
392
394
  let exc_class = ruby.get_inner(&VALIDATION_ERROR_CLASS);
393
395
 
@@ -400,21 +402,27 @@ fn into_ruby_error(
400
402
  )?;
401
403
  exc.ivar_set(
402
404
  *ID_AT_INSTANCE_PATH,
403
- ruby.ary_from_iter(instance_path.into_iter().map(&into_path_segment)),
405
+ ruby.ary_from_iter(parts.instance_path.into_iter().map(&into_path_segment)),
404
406
  )?;
405
407
  exc.ivar_set(
406
408
  *ID_AT_SCHEMA_PATH,
407
- ruby.ary_from_iter(schema_path.into_iter().map(&into_path_segment)),
409
+ ruby.ary_from_iter(parts.schema_path.into_iter().map(&into_path_segment)),
408
410
  )?;
409
411
  exc.ivar_set(
410
412
  *ID_AT_EVALUATION_PATH,
411
- ruby.ary_from_iter(evaluation_path.into_iter().map(&into_path_segment)),
413
+ ruby.ary_from_iter(parts.evaluation_path.into_iter().map(&into_path_segment)),
412
414
  )?;
413
415
  exc.ivar_set(*ID_AT_INSTANCE_PATH_POINTER, instance_path_ptr)?;
414
416
  exc.ivar_set(*ID_AT_SCHEMA_PATH_POINTER, schema_path_ptr)?;
415
417
  exc.ivar_set(*ID_AT_EVALUATION_PATH_POINTER, evaluation_path_ptr)?;
416
418
  exc.ivar_set(*ID_AT_KIND, ruby.into_value(kind_obj))?;
417
419
  exc.ivar_set(*ID_AT_INSTANCE, rb_instance)?;
420
+ let absolute_location = if let Some(uri) = parts.absolute_keyword_location {
421
+ ruby.into_value(uri.as_str())
422
+ } else {
423
+ ruby.qnil().as_value()
424
+ };
425
+ exc.ivar_set(*ID_AT_ABSOLUTE_KEYWORD_LOCATION, absolute_location)?;
418
426
 
419
427
  if is_custom {
420
428
  if let Some(cause) = CUSTOM_KEYWORD_CAUSE.with(|cell| cell.borrow_mut().take()) {
@@ -838,6 +846,22 @@ fn validator_for(ruby: &Ruby, args: &[Value]) -> Result<Validator, Error> {
838
846
  })
839
847
  }
840
848
 
849
+ fn bundle(ruby: &Ruby, args: &[Value]) -> Result<Value, Error> {
850
+ let parsed_args = scan_args::<(Value,), (), (), (), _, ()>(args)?;
851
+ let (schema,) = parsed_args.required;
852
+ let kw = extract_kwargs(ruby, parsed_args.keywords)?;
853
+
854
+ let json_schema = to_schema_value(ruby, schema)?;
855
+ let parsed = build_parsed_options(ruby, kw, None)?;
856
+ match parsed.options.bundle(&json_schema) {
857
+ Ok(bundled) => ser::value_to_ruby(ruby, &bundled),
858
+ Err(e @ jsonschema::ReferencingError::Unretrievable { .. }) => {
859
+ Err(referencing_error(ruby, e.to_string()))
860
+ }
861
+ Err(e) => Err(Error::new(ruby.exception_runtime_error(), e.to_string())),
862
+ }
863
+ }
864
+
841
865
  /// to_string(object) -> String
842
866
  ///
843
867
  /// Serialize a Ruby value to canonical JSON.
@@ -1315,6 +1339,7 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
1315
1339
  &*ID_SYM_INSTANCE_PATH_POINTER,
1316
1340
  &*ID_SYM_SCHEMA_PATH_POINTER,
1317
1341
  &*ID_SYM_EVALUATION_PATH_POINTER,
1342
+ &*ID_SYM_ABSOLUTE_KEYWORD_LOCATION,
1318
1343
  ] {
1319
1344
  let _: Value = validation_error_rclass.funcall("attr_reader", (sym_id.to_symbol(),))?;
1320
1345
  }
@@ -1331,6 +1356,7 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
1331
1356
  // Module-level functions
1332
1357
  module.define_singleton_method("validator_cls_for", function!(validator_cls_for, 1))?;
1333
1358
  module.define_singleton_method("validator_for", function!(validator_for, -1))?;
1359
+ module.define_singleton_method("bundle", function!(bundle, -1))?;
1334
1360
  module.define_singleton_method("valid?", function!(is_valid, -1))?;
1335
1361
  module.define_singleton_method("validate!", function!(validate, -1))?;
1336
1362
  module.define_singleton_method("each_error", function!(each_error, -1))?;
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.44.0
4
+ version: 0.45.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Dygalo