jtd_infer/
lib.rs

1//! Infers JSON Type Definition schemas from example inputs.
2//!
3//! JSON Type Definition, aka [RFC 8927](https://tools.ietf.org/html/rfc8927),
4//! is an easy-to-learn, standardized way to define a schema for JSON data. You
5//! can use JSON Typedef to portably validate data across programming languages,
6//! create dummy data, generate code, and more.
7//!
8//! This Rust crate can generate a JSON Typedef schema from example data. If you
9//! are looking to use this package as a CLI tool, see [this crate's
10//! README](https://github.com/jsontypedef/json-typedef-infer). The remainder of
11//! these docs are focused on this crate as a Rust library, and so focuses on
12//! the Rust API for using `jtd_fuzz`.
13//!
14//! # Quick start
15//!
16//! Here's how you can use this crate to infer a schema:
17//!
18//! ```
19//! use serde_json::json;
20//! use jtd_infer::{Inferrer, Hints, HintSet, NumType};
21//!
22//! let mut inferrer = Inferrer::new(Hints::new(
23//!     NumType::Uint8,
24//!     HintSet::new(vec![]),
25//!     HintSet::new(vec![]),
26//!     HintSet::new(vec![]),
27//! ));
28//!
29//! inferrer = inferrer.infer(json!({ "foo": true, "bar": "xxx" }));
30//! inferrer = inferrer.infer(json!({ "foo": false, "bar": null, "baz": 5 }));
31//!
32//! let inference = inferrer.into_schema();
33//!
34//! assert_eq!(
35//!     json!({
36//!         "properties": {
37//!             "foo": { "type": "boolean" },
38//!             "bar": { "type": "string", "nullable": true },
39//!         },
40//!         "optionalProperties": {
41//!             "baz": { "type": "uint8" },
42//!         },
43//!     }),
44//!     serde_json::to_value(inference.into_serde_schema()).unwrap(),
45//! )
46//! ```
47
48mod hints;
49mod inferred_number;
50mod inferred_schema;
51
52pub use crate::hints::{HintSet, Hints};
53pub use crate::inferred_number::NumType;
54use crate::inferred_schema::InferredSchema;
55use jtd::Schema;
56use serde_json::Value;
57
58/// Keeps track of a sequence of example inputs, and can be converted into an
59/// inferred schema.
60pub struct Inferrer<'a> {
61    inference: InferredSchema,
62    hints: Hints<'a>,
63}
64
65impl<'a> Inferrer<'a> {
66    /// Constructs a new inferrer with a given set of hints.
67    ///
68    /// See the documentation for [`Hints`] for details on what affect they have
69    /// on [`Inferrer::infer`].
70    pub fn new(hints: Hints<'a>) -> Self {
71        Self {
72            inference: InferredSchema::Unknown,
73            hints,
74        }
75    }
76
77    /// "Updates" the inference given an example data.
78    ///
79    /// Note that though the previous sentence uses the word "update", in Rust
80    /// ownership terms this method *moves* `self`.
81    pub fn infer(self, value: Value) -> Self {
82        Self {
83            inference: self.inference.infer(value, &self.hints),
84            hints: self.hints,
85        }
86    }
87
88    /// Converts the inference to a JSON Type Definition schema.
89    ///
90    /// It is guaranteed that the resulting schema will accept all of the inputs
91    /// previously provided via [`Inferrer::infer`].
92    pub fn into_schema(self) -> Schema {
93        self.inference.into_schema(&self.hints)
94    }
95}