corvus_json_schema 0.1.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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +390 -0
  3. data/Cargo.toml +8 -0
  4. data/LICENSE +201 -0
  5. data/README.md +111 -0
  6. data/VERSIONHISTORY.md +7 -0
  7. data/ext/corvus_json_schema/Cargo.toml +18 -0
  8. data/ext/corvus_json_schema/extconf.rb +6 -0
  9. data/ext/corvus_json_schema/rustfmt.toml +2 -0
  10. data/ext/corvus_json_schema/src/lib.rs +643 -0
  11. data/ext/corvus_json_schema/vendor/corvus-json-schema/Cargo.toml +35 -0
  12. data/ext/corvus_json_schema/vendor/corvus-json-schema/LICENSE +201 -0
  13. data/ext/corvus_json_schema/vendor/corvus-json-schema/README.md +139 -0
  14. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/compiler.rs +1118 -0
  15. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/dialect.rs +108 -0
  16. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/document.rs +905 -0
  17. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/eval/plan/fused.rs +1187 -0
  18. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/eval/plan.rs +1728 -0
  19. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/eval.rs +1451 -0
  20. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/formats.rs +1021 -0
  21. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/instance.rs +228 -0
  22. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/lib.rs +189 -0
  23. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/loader.rs +403 -0
  24. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/metaschemas.rs +29 -0
  25. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/node.rs +417 -0
  26. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/numbers.rs +244 -0
  27. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/options.rs +108 -0
  28. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/pattern.rs +1591 -0
  29. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/results.rs +316 -0
  30. data/ext/corvus_json_schema/vendor/corvus-json-schema/src/uri.rs +274 -0
  31. data/lib/corvus_json_schema/version.rb +5 -0
  32. data/lib/corvus_json_schema.rb +65 -0
  33. metadata +94 -0
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # corvus_json_schema
2
+
3
+ A JSON Schema evaluator for Ruby (draft 4, 6, 7, 2019-09 and 2020-12), a native extension over the
4
+ [corvus-json-schema](https://crates.io/crates/corvus-json-schema) Rust crate, the Rust port of the Corvus.Text.Json V5
5
+ standalone evaluator.
6
+
7
+ - **Conformant**: passes the JSON-Schema-Test-Suite (required, optional and `optional/format`, every draft) except
8
+ `draft4/optional/zeroTerminatedFloats.json`, which the other Corvus evaluators also exclude (a JSON parser reads
9
+ `1.0` as an integer).
10
+ - **Fast**: values are read in place from Ruby's own objects (nothing is converted or copied), and JSON text is
11
+ validated without creating Ruby objects for it.
12
+ - **Precompiled**: native gems for Linux (x86_64 and aarch64, glibc and musl), macOS (x86_64 and arm64) and Windows
13
+ (x64), for Ruby 3.3, 3.4 and 4.0. On other platforms the source gem builds the extension, which needs a Rust
14
+ toolchain (1.85 or later) and libclang.
15
+
16
+ ## Install
17
+
18
+ ```sh
19
+ gem install corvus_json_schema
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```ruby
25
+ require "corvus_json_schema"
26
+
27
+ validator = CorvusJsonSchema.compile({
28
+ "type" => "object", "required" => ["id"], "properties" => { "id" => { "type" => "integer" } }
29
+ })
30
+ validator.valid?({ "id" => 3 }) # => true: a Hash, read in place
31
+ validator.valid?({ id: "3" }) # => false: Symbol keys are read as their names
32
+ validator.valid_json?('{"id": 3}') # => true: JSON text, parsed in Rust
33
+
34
+ collector = CorvusJsonSchema::Collector.new(:detailed)
35
+ validator.evaluate({ "id" => "3" }, collector) # => false
36
+ collector.results
37
+ # => [..., { is_match: false, message: "The value was expected to be of type 'integer'",
38
+ # evaluation_location: "/properties/id/type", schema_location: "/properties/id/type",
39
+ # instance_location: "/id" }, ...]
40
+ ```
41
+
42
+ `CorvusJsonSchema.compile(schema, **options)` takes the schema as a Hash, an Array, `true` or `false`, or JSON text.
43
+ Its options:
44
+
45
+ | Option | Default | Meaning |
46
+ | --- | --- | --- |
47
+ | `default_dialect` | `:draft202012` | The dialect of a schema without `$schema`: `:draft4`, `:draft6`, `:draft7`, `:draft201909` or `:draft202012`. |
48
+ | `assert_format` | `nil` | Whether `format` is asserted; `nil` follows the schema's vocabularies. |
49
+ | `assert_format_in_legacy_drafts` | `false` | Assert `format` in drafts 4 to 7 when `assert_format` is `nil`. |
50
+ | `assert_content` | `true` | Assert `contentEncoding` and `contentMediaType` in drafts 4 to 7. |
51
+ | `formats` | `nil` | A Hash of format name to a callable that takes the string and returns whether it is valid. |
52
+ | `resolver` | `nil` | A callable that takes an absolute URI and returns the document (a Hash or JSON text), or `nil` when it has none. |
53
+ | `base_uri` | `nil` | The schema's base URI, when it has no `$id`. |
54
+ | `entry_point` | `nil` | A reference to the subschema to validate against, such as `"#/$defs/item"`. |
55
+ | `max_depth` | `128` | The deepest the evaluator recurses in place before it raises `DepthError`. |
56
+
57
+ A `Validator` is immutable and can be shared between threads.
58
+
59
+ - `valid?(value)` and `valid_json?(text)` return whether the instance is valid, evaluating only as far as the answer
60
+ needs.
61
+ - `evaluate(value, collector)` evaluates every keyword and replaces the collector's results with this evaluation's.
62
+ `Collector.new(level)` takes `:basic` (the failures, without messages), `:detailed` (the failures, with messages)
63
+ or `:verbose` (every result, and annotations); at every level the root's own result is the last row. `results`
64
+ returns its rows and `annotations` the annotations of a verbose evaluation, grouped by instance location, keyword and
65
+ schema location.
66
+
67
+ Errors are subclasses of `CorvusJsonSchema::Error`: `CompilationError` (an invalid schema, or a reference that cannot
68
+ be resolved), `DepthError` and `InvalidJsonError` (for `valid_json?`). An error raised by a format or resolver callable
69
+ propagates.
70
+
71
+ ## Values
72
+
73
+ A value is read as its JSON kind: a `Hash` (String or Symbol keys) is an object, an `Array` an array, a `String` (UTF-8
74
+ or US-ASCII) or `Symbol` a string, an `Integer` or `Float` a number, and `true`, `false` and `nil` themselves. An
75
+ Integer beyond 64 bits is compared as the nearest double, as by a JSON parser without arbitrary precision.
76
+
77
+ Values are read only as the schema examines them, so a value the schema never looks at is not checked: with
78
+ `{"type" => "object"}`, `{ "a" => Object.new }` is valid. A value the schema does examine that is none of the kinds
79
+ above raises `TypeError` (`ArgumentError` for a NaN or infinite Float, `EncodingError` for a String that is not valid
80
+ UTF-8).
81
+
82
+ ## How it works
83
+
84
+ The crate compiles the schema once into its node graph and fail-fast plans (see
85
+ [src-rs/corvus-json-schema](../../src-rs/corvus-json-schema/README.md)). Its evaluator is generic over an `Instance`
86
+ trait (a value shown as one of the six JSON kinds, with arrays and objects read in place), which this extension
87
+ implements over Ruby values: arrays are read by index, strings as the bytes Ruby holds, and a Hash's pairs are gathered
88
+ (with `rb_hash_foreach`) into a buffer reused across evaluations when the evaluator first reads that object.
89
+ Evaluation allocates no Ruby objects, so Ruby's garbage collector cannot run, and so cannot move a value, while it
90
+ reads them; when custom formats (Ruby code, which can allocate) are in use, the instance is first converted to the
91
+ crate's own form instead.
92
+
93
+ `valid_json?` parses into the crate's `JsonDocument`, whose buffers are reused for each thread: in the steady state a
94
+ validation of JSON text allocates nothing.
95
+
96
+ ## Building from source
97
+
98
+ In this repository, with Ruby 3.3 or later, a Rust toolchain and libclang:
99
+
100
+ ```sh
101
+ bundle install
102
+ bundle exec rake compile test
103
+ ```
104
+
105
+ The Rakefile copies the crate from `src-rs/corvus-json-schema` into `ext/corvus_json_schema/vendor` whenever it loads,
106
+ so the source gem carries the crate's sources and builds on its own. The tests run the JSON-Schema-Test-Suite from the
107
+ repository's submodule (or `JSON_SCHEMA_TEST_SUITE`).
108
+
109
+ ## License
110
+
111
+ Apache-2.0
data/VERSIONHISTORY.md ADDED
@@ -0,0 +1,7 @@
1
+ # Version History
2
+
3
+ The version history of the `corvus_json_schema` Ruby gem. It is versioned independently of the Corvus NuGet packages and of the [corvus-json-schema](../../src-rs/corvus-json-schema/VERSIONHISTORY.md) Rust crate it is built on.
4
+
5
+ ## V0.1.0
6
+
7
+ The first release: a native extension over the corvus-json-schema Rust crate (0.1.3), for drafts 4, 6, 7, 2019-09 and 2020-12. It reads Ruby values in place, validates JSON text without creating Ruby objects for it, and collects results (Basic, Detailed and Verbose) and annotations. It passes the whole JSON-Schema-Test-Suite, read in place, as JSON text and through a collector.
@@ -0,0 +1,18 @@
1
+ [package]
2
+ name = "corvus_json_schema"
3
+ version = "0.1.0"
4
+ edition = "2024"
5
+ rust-version = "1.85"
6
+ description = "The native extension of the corvus_json_schema gem: the corvus-json-schema crate, reading Ruby values in place."
7
+ license = "Apache-2.0"
8
+ publish = false
9
+
10
+ [lib]
11
+ crate-type = ["cdylib"]
12
+
13
+ [dependencies]
14
+ # The crate, copied in by `rake vendor` (from src-rs/corvus-json-schema) so that the source gem builds on its own.
15
+ corvus = { package = "corvus-json-schema", path = "vendor/corvus-json-schema", version = "0.1.3" }
16
+ magnus = { version = "0.9.1", features = ["rb-sys"] }
17
+ rb-sys = "0.9.130"
18
+ serde_json = { version = "1.0.151", features = ["preserve_order", "float_roundtrip"] }
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+ require "rb_sys/mkmf"
5
+
6
+ create_rust_makefile("corvus_json_schema/corvus_json_schema")
@@ -0,0 +1,2 @@
1
+ max_width = 120
2
+ use_small_heuristics = "Max"