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 +4 -4
- data/CHANGELOG.md +16 -1
- data/Cargo.toml +2 -2
- data/README.md +25 -0
- data/ext/jsonschema/Cargo.lock +9 -9
- data/ext/jsonschema/Cargo.toml +3 -3
- data/lib/jsonschema/version.rb +1 -1
- data/sig/jsonschema.rbs +13 -0
- data/src/lib.rs +35 -9
- 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: 8edaf1942b912082da745998a2b61bcb9d01b15078b788c5c459631c539f6a83
|
|
4
|
+
data.tar.gz: f6f35c2591c66ffe57bee54a12fd7b065fae77a96b7070abd82aae967cda8d39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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.
|
|
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.
|
|
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:
|
data/ext/jsonschema/Cargo.lock
CHANGED
|
@@ -603,9 +603,9 @@ dependencies = [
|
|
|
603
603
|
|
|
604
604
|
[[package]]
|
|
605
605
|
name = "ipnet"
|
|
606
|
-
version = "2.
|
|
606
|
+
version = "2.12.0"
|
|
607
607
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
608
|
-
checksum = "
|
|
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.
|
|
669
|
+
version = "0.45.0"
|
|
670
670
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
671
|
-
checksum = "
|
|
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.
|
|
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.
|
|
1046
|
+
version = "0.45.0"
|
|
1047
1047
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1048
|
-
checksum = "
|
|
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.
|
|
1431
|
+
version = "1.50.0"
|
|
1432
1432
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1433
|
-
checksum = "
|
|
1433
|
+
checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
|
|
1434
1434
|
dependencies = [
|
|
1435
1435
|
"bytes",
|
|
1436
1436
|
"libc",
|
data/ext/jsonschema/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "jsonschema-rb-ext"
|
|
3
|
-
version = "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.
|
|
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.
|
|
16
|
+
referencing = "0.45.0"
|
|
17
17
|
serde = { version = "1", features = ["derive"] }
|
|
18
18
|
serde_json = { version = "1", features = ["arbitrary_precision"] }
|
|
19
19
|
|
data/lib/jsonschema/version.rb
CHANGED
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
|
|
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))?;
|