outlines_core/json_schema/
mod.rs

1//! Provides interfaces to generate a regular expression based on a given JSON schema.
2//!
3//! An optional custom pattern could be passed as well to handle whitespace within the regex.
4//! If `None`, the default [`WHITESPACE`] pattern is used.
5//!
6//! Returns errors if JSON schema's content is invalid or some feature is not yet supported
7//! for regex generation.
8//!
9//! ## Supported features
10//!
11//! Note, that only some of the features of JSON schema are supported for regex generation.
12//!
13//! ### Supported constraints
14//!
15//! #### Common
16//!  - `type`
17//!     - Specifies the data type (string, number, integer, boolean, array, object, null).
18//!  - `enum`
19//!     - Lists the allowed values.
20//!  - `const`
21//!     - Specifies a single allowed value.
22//!
23//! #### Object
24//! - `properties`
25//!     - Defines the expected properties of an object and their schemas.
26//! - `required`
27//!     - Lists the properties that must be present.
28//! - `additionalProperties`
29//!     - Specifies whether additional properties are allowed or defines their schema.
30//! - `minProperties`
31//!     - Minimum number of properties required.
32//! - `maxProperties`
33//!     - Maximum number of properties allowed.
34//!
35//! #### Array
36//! - `items`
37//!     - Defines the schema for array elements (single schema or a schema per index).
38//! - `prefixItems`
39//!     - Specifies schemas for the first few elements of an array (tuple validation).
40//! - `minItems`
41//!     - Minimum number of items required in the array.
42//! - `maxItems`
43//!     - Maximum number of items allowed in the array.
44//!
45//! #### String
46//! - `minLength`
47//!     - Minimum string length.
48//! - `maxLength`
49//!     - Maximum string length.
50//! - `pattern`
51//!     - Regular expression the string must match.
52//! - `format`
53//!     - Specifies a pre-defined format, these are supported [`FormatType`]
54//!
55//! #### Number
56//! - `minDigitsInteger`
57//!     - Specifies minimum number of digits in the integer part of a numeric value.
58//! - `maxDigitsInteger`
59//!     - Specifies maximum number of digits in the integer part of a numeric value.
60//! - `minDigitsFraction`
61//!     - Constraints on minimum number of digits allowed in the fractional part of a numeric value.
62//! - `maxDigitsFraction`
63//!     - Constraints on maximum number of digits allowed in the fractional part of a numeric value.
64//! - `minDigitsExponent`
65//!     - Defines minimum number of digits in the exponent part of a scientific notation number.
66//! - `maxDigitsExponent`
67//!     - Defines maximum number of digits in the exponent part of a scientific notation number.
68//!
69//! #### Integer
70//! - `minDigits`
71//!     - Defines the minimum number of digits.
72//! - `maxDigits`
73//!     - Defines the maximum number of digits.
74//!
75//! #### Logical
76//! - `allOf`
77//!     - Combines multiple schemas; all must be valid.
78//! - `anyOf`
79//!     - Combines multiple schemas; at least one must be valid.
80//! - `oneOf`
81//!     - Combines multiple schemas; exactly one must be valid.
82//!
83//! ### Recursion
84//!
85//! Currently maximum recursion depth is cautiously defined at the level 3.
86//!
87//! Note, that in general recursion in regular expressions is not the best approach due to inherent limitations
88//! and inefficiencies, especially when applied to complex patterns or large input.
89//!
90//! But often, even simple referential JSON schemas will produce enormous regex size, since it increases
91//! exponentially in recursive case, which likely to introduce performance issues by consuming large
92//! amounts of time, resources and memory.
93//!
94//! ### References
95//!
96//! Only local references are currently being supported.
97//!
98//! ### Unconstrained objects
99//!
100//! An empty object means unconstrained, allowing any JSON type.
101
102use serde_json::Value;
103pub use types::*;
104
105mod parsing;
106pub mod types;
107
108use crate::Result;
109
110/// Generates a regular expression string from given JSON schema string.
111///
112/// # Example
113///
114/// ```rust
115/// # use outlines_core::Error;
116/// use outlines_core::prelude::*;
117///
118/// # fn main() -> Result<(), Error> {
119///     // Define a JSON schema
120///     let schema = r#"{
121///         "type": "object",
122///         "properties": {
123///             "name": { "type": "string" },
124///             "age": { "type": "integer" }
125///         },
126///         "required": ["name", "age"]
127///     }"#;
128///
129///     // Generate regex from schema
130///     let regex = json_schema::regex_from_str(&schema, None, None)?;
131///     println!("Generated regex: {}", regex);
132///
133///     // Custom whitespace pattern could be passed as well
134///     let whitespace_pattern = Some(r#"[\n ]*"#);
135///     let regex = json_schema::regex_from_str(&schema, whitespace_pattern, None)?;
136///     println!("Generated regex with custom whitespace pattern: {}", regex);
137///
138/// #   Ok(())
139/// }
140/// ```
141pub fn regex_from_str(
142    json: &str,
143    whitespace_pattern: Option<&str>,
144    max_recursion_depth: Option<usize>,
145) -> Result<String> {
146    let json_value: Value = serde_json::from_str(json)?;
147    regex_from_value(&json_value, whitespace_pattern, max_recursion_depth)
148}
149
150/// Generates a regular expression string from `serde_json::Value` type of JSON schema.
151///
152/// # Example
153///
154/// ```rust
155/// # use outlines_core::Error;
156/// use serde_json::Value;
157/// use outlines_core::prelude::*;
158///
159/// # fn main() -> Result<(), Error> {
160///     // Define a JSON schema
161///     let schema = r#"{
162///         "type": "object",
163///         "properties": {
164///             "name": { "type": "string" },
165///             "age": { "type": "integer" }
166///         },
167///         "required": ["name", "age"]
168///     }"#;
169///
170///     // If schema's `Value` was already parsed
171///     let schema_value: Value = serde_json::from_str(schema)?;
172///
173///     // It's possible to generate a regex from schema value
174///     let regex = json_schema::regex_from_value(&schema_value, None, None)?;
175///     println!("Generated regex: {}", regex);
176///
177///     // Custom whitespace pattern could be passed as well
178///     let whitespace_pattern = Some(r#"[\n ]*"#);
179///     let regex = json_schema::regex_from_value(&schema_value, whitespace_pattern, None)?;
180///     println!("Generated regex with custom whitespace pattern: {}", regex);
181///
182/// #   Ok(())
183/// }
184/// ```
185pub fn regex_from_value(
186    json: &Value,
187    whitespace_pattern: Option<&str>,
188    max_recursion_depth: Option<usize>,
189) -> Result<String> {
190    let mut parser = parsing::Parser::new(json);
191    if let Some(pattern) = whitespace_pattern {
192        parser = parser.with_whitespace_pattern(pattern)
193    }
194    if let Some(depth) = max_recursion_depth {
195        parser = parser.with_max_recursion_depth(depth)
196    }
197    parser.to_regex(json)
198}
199
200#[cfg(test)]
201mod tests {
202    use regex::Regex;
203
204    use super::*;
205
206    fn should_match(re: &Regex, value: &str) {
207        // Asserts that value is fully matched.
208        match re.find(value) {
209            Some(matched) => {
210                assert_eq!(
211                    matched.as_str(),
212                    value,
213                    "Value should match, but does not for: {value}, re:\n{re}"
214                );
215                assert_eq!(matched.range(), 0..value.len());
216            }
217            None => unreachable!(
218                "Value should match, but does not, in unreachable for: {value}, re:\n{re}"
219            ),
220        }
221    }
222
223    fn should_not_match(re: &Regex, value: &str) {
224        // Asserts that regex does not find a match or not a full match.
225        if let Some(matched) = re.find(value) {
226            assert_ne!(
227                matched.as_str(),
228                value,
229                "Value should NOT match, but does for: {value}, re:\n{re}"
230            );
231            assert_ne!(matched.range(), 0..value.len());
232        }
233    }
234
235    #[test]
236    fn test_schema_matches_regex() {
237        for (schema, regex, a_match, not_a_match) in [
238            // ==========================================================
239            //                       Integer Type
240            // ==========================================================
241            (
242                r#"{"title": "Foo", "type": "integer"}"#,
243                INTEGER,
244                vec!["0", "1", "-1"],
245                vec!["01", "1.3", "t"],
246            ),
247            // Required integer property
248            (
249                r#"{
250                    "title": "Foo",
251                    "type": "object",
252                    "properties": {"count": {"title": "Count", "type": "integer"}},
253                    "required": ["count"]
254                }"#,
255                r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?\}"#,
256                vec![r#"{ "count": 100 }"#],
257                vec![r#"{ "count": "a" }"#, ""],
258            ),
259            // Integer with minimum digits
260            (
261                r#"{
262                    "title": "Foo",
263                    "type": "object",
264                    "properties": {
265                        "count": {"title": "Count", "type": "integer", "minDigits": 3}
266                    },
267                    "required": ["count"]
268                }"#,
269                r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]{2,})[ ]?\}"#,
270                vec![r#"{ "count": 100 }"#, r#"{ "count": 1000 }"#],
271                vec![r#"{ "count": 10 }"#],
272            ),
273            // Integer with maximum digits
274            (
275                r#"{
276                    "title": "Foo",
277                    "type": "object",
278                    "properties": {
279                        "count": {"title": "Count", "type": "integer", "maxDigits": 3}
280                    },
281                    "required": ["count"]
282                }"#,
283                r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]{0,2})[ ]?\}"#,
284                vec![r#"{ "count": 100 }"#, r#"{ "count": 10 }"#],
285                vec![r#"{ "count": 1000 }"#],
286            ),
287            // Integer with minimum and maximum digits
288            (
289                r#"{
290                    "title": "Foo",
291                    "type": "object",
292                    "properties": {
293                        "count": {
294                            "title": "Count",
295                            "type": "integer",
296                            "minDigits": 3,
297                            "maxDigits": 5
298                        }
299                    },
300                    "required": ["count"]
301                }"#,
302                r#"\{[ ]?"count"[ ]?:[ ]?(-)?(0|[1-9][0-9]{2,4})[ ]?\}"#,
303                vec![r#"{ "count": 100 }"#, r#"{ "count": 10000 }"#],
304                vec![r#"{ "count": 10 }"#, r#"{ "count": 100000 }"#],
305            ),
306            // ==========================================================
307            //                       Number Type
308            // ==========================================================
309            (
310                r#"{"title": "Foo", "type": "number"}"#,
311                NUMBER,
312                vec!["1", "0", "1.3", "-1.3", "1.3e+9"],
313                vec!["01", ".3", "1.3e9"],
314            ),
315            // Required number property
316            (
317                r#"{
318                    "title": "Foo",
319                    "type": "object",
320                    "properties": {"count": {"title": "Count", "type": "number"}},
321                    "required": ["count"]
322                }"#,
323                r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]+)?([eE][+-][0-9]+)?[ ]?\}"#,
324                vec![r#"{ "count": 100 }"#, r#"{ "count": 100.5 }"#],
325                vec![""],
326            ),
327            // Number with min and max integer digits
328            (
329                r#"{
330                    "title": "Foo",
331                    "type": "object",
332                    "properties": {
333                        "count": {
334                            "title": "Count",
335                            "type": "number",
336                            "minDigitsInteger": 3,
337                            "maxDigitsInteger": 5
338                        }
339                    },
340                    "required": ["count"]
341                }"#,
342                r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]{2,4}))(\.[0-9]+)?([eE][+-][0-9]+)?[ ]?\}"#,
343                vec![r#"{ "count": 100.005 }"#, r#"{ "count": 10000.005 }"#],
344                vec![r#"{ "count": 10.005 }"#, r#"{ "count": 100000.005 }"#],
345            ),
346            // Number with min and max fraction digits
347            (
348                r#"{
349                    "title": "Foo",
350                    "type": "object",
351                    "properties": {
352                        "count": {
353                            "title": "Count",
354                            "type": "number",
355                            "minDigitsFraction": 3,
356                            "maxDigitsFraction": 5
357                        }
358                    },
359                    "required": ["count"]
360                }"#,
361                r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]{3,5})?([eE][+-][0-9]+)?[ ]?\}"#,
362                vec![r#"{ "count": 1.005 }"#, r#"{ "count": 1.00005 }"#],
363                vec![r#"{ "count": 1.05 }"#, r#"{ "count": 1.000005 }"#],
364            ),
365            // Number with min and max exponent digits
366            (
367                r#"{
368                    "title": "Foo",
369                    "type": "object",
370                    "properties": {
371                        "count": {
372                            "title": "Count",
373                            "type": "number",
374                            "minDigitsExponent": 3,
375                            "maxDigitsExponent": 5
376                        }
377                    },
378                    "required": ["count"]
379                }"#,
380                r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]+)?([eE][+-][0-9]{3,5})?[ ]?\}"#,
381                vec![r#"{ "count": 1.05e+001 }"#, r#"{ "count": 1.05e-00001 }"#],
382                vec![r#"{ "count": 1.05e1 }"#, r#"{ "count": 1.05e0000001 }"#],
383            ),
384            // Number with min and max integer, fraction and exponent digits
385            (
386                r#"{
387                    "title": "Foo",
388                    "type": "object",
389                    "properties": {
390                        "count": {
391                            "title": "Count",
392                            "type": "number",
393                            "minDigitsInteger": 3,
394                            "maxDigitsInteger": 5,
395                            "minDigitsFraction": 3,
396                            "maxDigitsFraction": 5,
397                            "minDigitsExponent": 3,
398                            "maxDigitsExponent": 5
399                        }
400                    },
401                    "required": ["count"]
402                }"#,
403                r#"\{[ ]?"count"[ ]?:[ ]?((-)?(0|[1-9][0-9]{2,4}))(\.[0-9]{3,5})?([eE][+-][0-9]{3,5})?[ ]?\}"#,
404                vec![r#"{ "count": 100.005e+001 }"#, r#"{ "count": 10000.00005e-00001 }"#],
405                vec![r#"{ "count": 1.05e1 }"#, r#"{ "count": 100000.0000005e0000001 }"#],
406            ),
407            // ==========================================================
408            //                       Array Type
409            // ==========================================================
410            (
411                r#"{"title": "Foo", "type": "array", "items": {"type": "number"}}"#,
412                format!(r#"\[{WHITESPACE}(({NUMBER})(,{WHITESPACE}({NUMBER})){{0,}})?{WHITESPACE}\]"#).as_str(),
413                vec!["[1e+9,1.3]", "[]"], vec!["[1", r#"["a"]"#],
414            ),
415            // Array with a set min length
416            (
417                r#"{
418                    "title": "Foo",
419                    "type": "array",
420                    "items": {"type": "integer"},
421                    "minItems": 3
422                }"#,
423                format!(r#"\[{WHITESPACE}(({INTEGER})(,{WHITESPACE}({INTEGER})){{2,}}){WHITESPACE}\]"#).as_str(),
424                vec!["[1,2,3]", "[1,2,3,4]"], vec!["[1]", "[1,2]", "[]"],
425            ),
426            // Array with a set max length
427            (
428                r#"{
429                    "title": "Foo",
430                    "type": "array",
431                    "items": {"type": "integer"},
432                    "maxItems": 3
433                }"#,
434                format!(r#"\[{WHITESPACE}(({INTEGER})(,{WHITESPACE}({INTEGER})){{0,2}})?{WHITESPACE}\]"#).as_str(),
435                vec!["[1,2,3]", "[1,2]", "[]"], vec!["[1,2,3,4]"],
436            ),
437            // Array with a set min/max length
438            (
439                r#"{
440                    "title": "Foo",
441                    "type": "array",
442                    "items": {"type": "integer"},
443                    "minItems": 1,
444                    "maxItems": 1
445                }"#,
446                format!(r#"\[{WHITESPACE}(({INTEGER})(,{WHITESPACE}({INTEGER})){{0,0}}){WHITESPACE}\]"#).as_str(),
447                vec!["[1]"], vec!["[1, 2]", r#"["a"]"#, "[]"],
448            ),
449            // Array with zero length
450            (
451                r#"{
452                    "title": "Foo",
453                    "type": "array",
454                    "items": {"type": "integer"},
455                    "minItems": 0,
456                    "maxItems": 0
457                }"#,
458                format!(r#"\[{WHITESPACE}\]"#).as_str(),
459                vec!["[]"], vec!["[1, 2]", "[1]", "[1,2,3,4]"],
460            ),
461            // ==========================================================
462            //                       String Type
463            // ==========================================================
464            (
465                r#"{"title": "Foo", "type": "string"}"#,
466                STRING,
467                vec![
468                    r#""(parenthesized_string)""#,
469                    r#""malformed) parenthesis (((() string""#,
470                    r#""quoted_string""#,
471                    r#""double_\\escape""#,
472                    r#""\\n""#,
473                    r#""escaped \" quote""#,
474                    r#""\n""#,
475                    r#""\/""#,
476                    r#""\b""#,
477                    r#""\f""#,
478                    r#""\r""#,
479                    r#""\t""#
480                ],
481                vec![
482                    "unquotedstring",
483                    r#""escape_\character""#,
484                    r#""unescaped " quote""#,
485                ],
486            ),
487            (
488                r#"{"title": "Foo", "type": "boolean"}"#,
489                BOOLEAN,
490                vec!["true", "false"],
491                vec!["null", "0"],
492            ),
493            (
494                r#"{"title": "Foo", "type": "null"}"#,
495                NULL,
496                vec!["null"],
497                vec!["true", "0"],
498            ),
499            // String with maximum length
500            (
501                r#"{"title": "Foo", "type": "string", "maxLength": 3}"#,
502                format!(r#""{STRING_INNER}{{0,3}}""#).as_str(),
503                vec![r#""ab""#], vec![r#""a"""#, r#""abcd""#],
504            ),
505            // String with minimum length
506            (
507                r#"{"title": "Foo", "type": "string", "minLength": 3}"#,
508                format!(r#""{STRING_INNER}{{3,}}""#).as_str(),
509                vec![r#""abcd""#], vec![r#""ab""#, r#""abc"""#],
510            ),
511            // String with both minimum and maximum length
512            (
513                r#"{"title": "Foo", "type": "string", "minLength": 3, "maxLength": 5}"#,
514                format!(r#""{STRING_INNER}{{3,5}}""#).as_str(),
515                vec![r#""abcd""#], vec![r#""ab""#, r#""abcdef"""#],
516            ),
517            // String defined by a regular expression
518            (
519                r#"{"title": "Foo", "type": "string", "pattern": "^[a-z]$"}"#,
520                r#"("[a-z]")"#,
521                vec![r#""a""#], vec![r#""1""#],
522            ),
523            // Make sure strings are escaped with regex escaping
524            (
525                r#"{"title": "Foo", "const": ".*", "type": "string"}"#,
526                r#""\.\*""#,
527                vec![r#"".*""#], vec![r#""\s*""#, r#""\.\*""#],
528            ),
529            // Make sure strings are escaped with JSON escaping
530            (
531                r#"{"title": "Foo", "const": "\"", "type": "string"}"#,
532                r#""\\"""#,
533                vec![r#""\"""#], vec![r#"""""#],
534            ),
535            // ==========================================================
536            //                       Const
537            // ==========================================================
538            // Const string
539            (
540                r#"{"title": "Foo", "const": "Marc", "type": "string"}"#,
541                r#""Marc""#,
542                vec![r#""Marc""#], vec![r#""Jonh""#, r#""Mar""#],
543            ),
544            // Const integer
545            (
546                r#"{"title": "Foo", "const": 0, "type": "integer"}"#,
547                "0",
548                vec!["0"], vec!["1", "a"],
549            ),
550            // Const float
551            (
552                r#"{"title": "Foo", "const": 0.2, "type": "float"}"#,
553                r#"0\.2"#,
554                vec!["0.2"], vec!["032"],
555            ),
556            // Const boolean
557            (
558                r#"{"title": "Foo", "const": true, "type": "boolean"}"#,
559                "true",
560                vec!["true"], vec!["false", "null"],
561            ),
562            // Const null
563            (
564                r#"{"title": "Foo", "const": null, "type": "null"}"#,
565                "null",
566                vec!["null"], vec!["none", ""],
567            ),
568            // ==========================================================
569            //                      Enum
570            // ==========================================================
571            (
572                r#"{"title": "Foo", "enum": ["Marc", "Jean"], "type": "string"}"#,
573                r#"("Marc"|"Jean")"#,
574                vec![r#""Marc""#, r#""Jean""#], vec![r#""Jonh""#],
575            ),
576            // Enum with regex and JSON escaping
577            (
578                r#"{"title": "Foo", "enum": [".*", "\\s*"], "type": "string"}"#,
579                r#"("\.\*"|"\\\\s\*")"#,
580                vec![r#"".*""#, r#""\\s*""#], vec![r#""\.\*""#],
581            ),
582            // Enum integer
583            (
584                r#"{"title": "Foo", "enum": [0, 1], "type": "integer"}"#,
585                r#"(0|1)"#,
586                vec!["0", "1"], vec!["a"],
587            ),
588            // Enum array
589            (
590                r#"{"title": "Foo", "enum": [[1,2],[3,4]], "type": "array"}"#,
591                format!(r#"(\[{0}1{0},{0}2{0}\]|\[{0}3{0},{0}4{0}\])"#, WHITESPACE).as_str(),
592                vec!["[1,2]", "[3,4]", "[1, 2 ]"], vec!["1", "[1,3]"],
593            ),
594            // Enum object
595            (
596                r#"{"title": "Foo", "enum": [{"a":"b","c":"d"}, {"e":"f"}], "type": "object"}"#,
597                format!(r#"(\{{{0}"a"{0}:{0}"b"{0},{0}"c"{0}:{0}"d"{0}\}}|\{{{0}"e"{0}:{0}"f"{0}\}})"#, WHITESPACE).as_str(),
598                vec![r#"{"a":"b","c":"d"}"#, r#"{"e":"f"}"#, r#"{"a" : "b", "c": "d" }"#], vec!["a", r#"{"a":"b"}"#],
599            ),
600            // Enum mix of types
601            (
602                r#"{"title": "Foo", "enum": [6, 5.3, "potato", true, null, [1,2], {"a":"b"}]}"#,
603                format!(r#"(6|5\.3|"potato"|true|null|\[{0}1{0},{0}2{0}\]|\{{{0}"a"{0}:{0}"b"{0}\}})"#, WHITESPACE).as_str(),
604                vec!["6", "5.3", r#""potato""#, "true", "null", "[1, 2]", r#"{"a": "b" }"#], vec!["none", "53"],
605            ),
606            // ==========================================================
607            //                      UUID
608            // ==========================================================
609            (
610                r#"{"title": "Foo", "type": "string", "format": "uuid"}"#,
611                UUID,
612                vec![
613                    r#""123e4567-e89b-12d3-a456-426614174000""#,
614                ],
615                vec![
616                    r#"123e4567-e89b-12d3-a456-426614174000"#,
617                    r#""123e4567-e89b-12d3-a456-42661417400""#,
618                    r#""123e4567-e89b-12d3-a456-42661417400g""#,
619                    r#""123e4567-e89b-12d3-a456-42661417400-""#,
620                    r#""""#,
621                ],
622            ),
623            // Nested UUID
624            (
625                r#"{
626                    "title": "Foo",
627                    "type": "object",
628                    "properties": {"uuid": {"type": "string", "format": "uuid"}}
629                }"#,
630                format!(r#"\{{([ ]?"uuid"[ ]?:[ ]?{UUID})?[ ]?\}}"#).as_str(),
631                vec![
632                    r#"{"uuid": "123e4567-e89b-12d3-a456-426614174000"}"#,
633                ],
634                vec![
635                    r#"{"uuid":"123e4567-e89b-12d3-a456-42661417400"}"#,
636                    r#"{"uuid":"123e4567-e89b-12d3-a456-42661417400g"}"#,
637                    r#"{"uuid":"123e4567-e89b-12d3-a456-42661417400-"}"#,
638                    r#"{"uuid":123e4567-e89b-12d3-a456-426614174000}"#, // missing quotes for value
639                    r#"{"uuid":""}"#,
640                ],
641            ),
642            // ==========================================================
643            //                     DATE & TIME
644            // ==========================================================
645            // DATE-TIME
646            (
647                r#"{"title": "Foo", "type": "string", "format": "date-time"}"#,
648                DATE_TIME,
649                vec![
650                    r#""2018-11-13T20:20:39Z""#,
651                    r#""2016-09-18T17:34:02.666Z""#,
652                    r#""2008-05-11T15:30:00Z""#,
653                    r#""2021-01-01T00:00:00""#,
654                ],
655                vec![
656                    "2018-11-13T20:20:39Z",
657                    r#""2022-01-10 07:19:30""#, // missing T
658                    r#""2022-12-10T10-04-29""#, // incorrect separator
659                    r#""2023-01-01""#,
660                ],
661            ),
662            // DATE
663            (
664                r#"{"title": "Foo", "type": "string", "format": "date"}"#,
665                DATE,
666                vec![
667                    r#""2018-11-13""#,
668                    r#""2016-09-18""#,
669                    r#""2008-05-11""#,
670                ],
671                vec![
672                    "2018-11-13",
673                    r#""2015-13-01""#, // incorrect month
674                    r#""2022-01""#, // missing day
675                    r#""2022/12/01""#, // incorrect separator
676                ],
677            ),
678            // TIME
679            (
680                r#"{"title": "Foo", "type": "string", "format": "time"}"#,
681                TIME,
682                vec![
683                    r#""20:20:39Z""#,
684                    r#""15:30:00Z""#,
685                ],
686                vec![
687                    "20:20:39Z",
688                    r#""25:30:00""#, // incorrect hour
689                    r#""15:30""#, // missing seconds
690                    r#""15:30:00.000""#, // missing Z
691                    r#""15-30-00""#, // incorrect separator
692                    r#""15:30:00+01:00""#, // incorrect separator
693                ],
694            ),
695            // Nested DATE-TIME
696            (
697                r#"{
698                    "title": "Foo",
699                    "type": "object",
700                    "properties": {"dateTime": {"type": "string", "format": "date-time"}}
701                }"#,
702                format!(r#"\{{([ ]?"dateTime"[ ]?:[ ]?{DATE_TIME})?[ ]?\}}"#).as_str(),
703                vec![
704                    r#"{"dateTime": "2018-11-13T20:20:39Z"}"#,
705                    r#"{"dateTime":"2016-09-18T17:34:02.666Z"}"#,
706                    r#"{"dateTime":"2008-05-11T15:30:00Z"}"#,
707                    r#"{"dateTime":"2021-01-01T00:00:00"}"#,
708                ],
709                vec![
710                    r#"{"dateTime":"2022-01-10 07:19:30"}"#, // missing T
711                    r#"{"dateTime":"2022-12-10T10-04-29"}"#, // incorrect separator
712                    r#"{"dateTime":2018-11-13T20:20:39Z}"#, // missing quotes for value
713                    r#"{"dateTime":"2023-01-01"}"#,
714                ],
715            ),
716            // Nested DATE
717            (
718                r#"{
719                    "title": "Foo",
720                    "type": "object",
721                    "properties": {"date": {"type": "string", "format": "date"}}
722                }"#,
723                format!(r#"\{{([ ]?"date"[ ]?:[ ]?{DATE})?[ ]?\}}"#).as_str(),
724                vec![
725                    r#"{"date": "2018-11-13"}"#,
726                    r#"{"date":"2016-09-18"}"#,
727                    r#"{"date":"2008-05-11"}"#,
728                ],
729                vec![
730                    r#"{"date":"2015-13-01"}"#, // incorrect month
731                    r#"{"date":"2022-01"}"#, // missing day
732                    r#"{"date":"2022/12/01"}"#, // incorrect separator
733                    r#"{"date":2018-11-13}"#, // missing quotes for value
734                ],
735            ),
736            // Nested TIME
737            (
738                r#"{
739                    "title": "Foo",
740                    "type": "object",
741                    "properties": {"time": {"type": "string", "format": "time"}}
742                }"#,
743                format!(r#"\{{([ ]?"time"[ ]?:[ ]?{TIME})?[ ]?\}}"#).as_str(),
744                vec![
745                    r#"{"time": "20:20:39Z"}"#,
746                    r#"{"time":"15:30:00Z"}"#,
747                ],
748                vec![
749                    r#"{"time":"25:30:00"}"#, // incorrect hour
750                    r#"{"time":"15:30"}"#, // missing seconds
751                    r#"{"time":"15:30:00.000"}"#, // missing Z
752                    r#"{"time":"15-30-00"}"#, // incorrect separator
753                    r#"{"time":"15:30:00+01:00"}"#, // incorrect separator
754                    r#"{"time":20:20:39Z}"#, // missing quotes for value
755                ],
756            ),
757            // ==========================================================
758            //                     ... Of
759            // ==========================================================
760            // oneOf
761            (
762                r#"{
763                    "title": "Foo",
764                    "oneOf": [{"type": "string"}, {"type": "number"}, {"type": "boolean"}]
765                }"#,
766                format!(r#"((?:"{STRING_INNER}*")|(?:{NUMBER})|(?:{BOOLEAN}))"#).as_str(),
767                vec!["12.3", "true", r#""a""#],
768                vec![
769                    "null",
770                    "",
771                    "12true",
772                    r#"1.3"a""#,
773                    r#"12.3true"a""#,
774                ],
775            ),
776            // anyOf
777            (
778                r#"{
779                    "title": "Foo",
780                    "anyOf": [{"type": "string"}, {"type": "integer"}]
781                }"#,
782                format!(r#"({STRING}|{INTEGER})"#).as_str(),
783                vec!["12", r#""a""#],
784                vec![r#"1"a""#],
785            ),
786            // allOf
787            (
788                r#"{
789                    "title": "Foo",
790                    "allOf": [{"type": "string"}, {"type": "integer"}]
791                }"#,
792                format!(r#"({STRING}{INTEGER})"#).as_str(),
793                vec![r#""a"1"#],
794                vec![r#""a""#, r#""1""#],
795            ),
796            // ==========================================================
797            //                     Object
798            // ==========================================================
799            (
800                r#"{
801                    "title": "TestSchema",
802                    "type": "object",
803                    "properties": {
804                        "test_dict": {
805                            "title": "Test Dict",
806                            "additionalProperties": {"type": "string"},
807                            "type": "object"
808                        }
809                    },
810                    "required": ["test_dict"]
811                }"#,
812                format!(r#"\{{{WHITESPACE}"test_dict"{WHITESPACE}:{WHITESPACE}\{{{WHITESPACE}({STRING}{WHITESPACE}:{WHITESPACE}{STRING}({WHITESPACE},{WHITESPACE}{STRING}{WHITESPACE}:{WHITESPACE}{STRING}){{0,}})?{WHITESPACE}\}}{WHITESPACE}\}}"#).as_str(),
813                vec![
814                    r#"{ "test_dict":{"foo":"bar","baz": "bif"}}"#,
815                    r#"{ "test_dict":{"foo":"bar" }}"#,
816                    r#"{ "test_dict":{}}"#,
817                ],
818                vec![
819                    r#"{ "WRONG_KEY":{}}"#,
820                    r#"{ "test_dict":{"wrong_type" 1}}"#,
821                ],
822            ),
823            // Object containing object with undefined keys
824            (
825                r#"{
826                    "title": "TestSchema",
827                    "type": "object",
828                    "properties": {
829                        "test_dict": {
830                            "title": "Test Dict",
831                            "additionalProperties": {
832                                "additionalProperties": {"type": "integer"},
833                                "type": "object"
834                            },
835                            "type": "object"
836                        }
837                    },
838                    "required": ["test_dict"]
839                }"#,
840                format!(r#"\{{{WHITESPACE}"test_dict"{WHITESPACE}:{WHITESPACE}\{{{WHITESPACE}({STRING}{WHITESPACE}:{WHITESPACE}\{{{WHITESPACE}({STRING}{WHITESPACE}:{WHITESPACE}{INTEGER}({WHITESPACE},{WHITESPACE}{STRING}{WHITESPACE}:{WHITESPACE}{INTEGER}){{0,}})?{WHITESPACE}\}}({WHITESPACE},{WHITESPACE}{STRING}{WHITESPACE}:{WHITESPACE}\{{{WHITESPACE}({STRING}{WHITESPACE}:{WHITESPACE}{INTEGER}({WHITESPACE},{WHITESPACE}{STRING}{WHITESPACE}:{WHITESPACE}{INTEGER}){{0,}})?{WHITESPACE}\}}){{0,}})?{WHITESPACE}\}}{WHITESPACE}\}}"#).as_str(),
841                vec![
842                    r#"{"test_dict": {"foo": {"bar": 123, "apple": 99}, "baz": {"bif": 456}}}"#,
843                    r#"{"test_dict": {"anykey": {"anykey": 123}, "anykey2": {"bif": 456}}}"#,
844                    r#"{"test_dict": {}}"#,
845                    r#"{"test_dict": {"dict of empty dicts are ok": {} }}"#,
846                ],
847                vec![
848                    r#"{"test_dict": {"anykey": {"ONLY Dict[Dict]": 123}, "No Dict[int]" 1: }}"#,
849                    r#"{"test_dict": {"anykey": {"anykey": 123}, "anykey2": {"bif": "bof"}}}"#,
850                ],
851            ),
852            // Object contains object with defined keys
853            (
854                r#"{
855                    "title": "Bar",
856                    "type": "object",
857                    "properties": {
858                        "fuzz": {
859                            "title": "Foo",
860                            "type": "object",
861                            "properties": {"spam": {"title": "Spam", "type": "integer"}},
862                            "required": ["spam"]
863                        }
864                    },
865                    "required": ["fuzz"]
866                }"#,
867                format!(r#"\{{[ ]?"fuzz"[ ]?:[ ]?\{{[ ]?"spam"[ ]?:[ ]?{INTEGER}[ ]?\}}[ ]?\}}"#).as_str(),
868                vec![r#"{ "fuzz": { "spam": 100 }}"#],
869                vec![r#"{ "fuzz": { "spam": 100, "notspam": 500 }}"#, r#"{ "fuzz": {}}"#, r#"{ "spam": 5}"#],
870            ),
871            // Object with internal reference: #/
872            (
873                r##"{
874                    "title": "User",
875                    "type": "object",
876                    "properties": {
877                        "user_id": {"title": "User Id", "type": "integer"},
878                        "name": {"title": "Name", "type": "string"},
879                        "a": {"$ref": "#/properties/name"}
880                    },
881                    "required": ["user_id", "name", "a"]
882                }"##,
883                format!(r#"\{{[ ]?"user_id"[ ]?:[ ]?{INTEGER}[ ]?,[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"a"[ ]?:[ ]?{STRING}[ ]?\}}"#).as_str(),
884                vec![r#"{"user_id": 100, "name": "John", "a": "Marc"}"#],
885                vec![r#"{"user_id": 100, "name": "John", "a": 0}"#],
886            ),
887            // Object with internal reference: #/$defs
888            (
889                r##"{
890                    "title": "User",
891                    "type": "object",
892                    "$defs": {"name": {"title": "Name2", "type": "string"}},
893                    "properties": {
894                        "user_id": {"title": "User Id", "type": "integer"},
895                        "name": {"title": "Name", "type": "string"},
896                        "name2": {"$ref": "#/$defs/name"}
897                    },
898                    "required": ["user_id", "name", "name2"]
899                }"##,
900                format!(r#"\{{[ ]?"user_id"[ ]?:[ ]?{INTEGER}[ ]?,[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"name2"[ ]?:[ ]?{STRING}[ ]?\}}"#).as_str(),
901                vec![r#"{"user_id": 100, "name": "John", "name2": "Marc"}"#],
902                vec![r#"{"user_id": 100, "name": "John", "name2": 0}"#],
903            ),
904            // Object with internal reference to $id: $id#/$defs
905            // And required list requires more than being defined
906            (
907                r##"{
908                    "$id": "customer",
909                    "$schema": "https://json-schema.org/draft/2020-12/schema",
910                    "title": "Customer",
911                    "type": "object",
912                    "properties": {
913                        "name": {"type": "string"},
914                        "last_name": {"type": "string"},
915                        "address": {"$ref": "customer#/$defs/address"}
916                    },
917                    "required": [
918                        "name",
919                        "first_name",
920                        "last_name",
921                        "address",
922                        "shipping_address",
923                        "billing_address"
924                    ],
925                    "$defs": {
926                        "address": {
927                            "title": "Address",
928                            "$schema": "http://json-schema.org/draft-07/schema#",
929                            "type": "object",
930                            "properties": {
931                                "city": {"type": "string"}
932                            },
933                            "required": ["street_address", "city", "state"],
934                            "definitions": {
935                                "state": {
936                                    "type": "object",
937                                    "title": "State",
938                                    "properties": {"name": {"type": "string"}},
939                                    "required": ["name"]
940                                }
941                            }
942                        }
943                    }
944                }"##,
945                format!(r#"\{{[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"last_name"[ ]?:[ ]?{STRING}[ ]?,[ ]?"address"[ ]?:[ ]?\{{[ ]?"city"[ ]?:[ ]?{STRING}[ ]?\}}[ ]?\}}"#).as_str(),
946                vec![
947                    r#"{"name": "John", "last_name": "Doe", "address": {"city": "Paris"}}"#,
948                ],
949                vec![
950                    r#"{"name": "John", "last_name": "Doe", "address": {}}"#,
951                    r#"{"name": "John", "last_name": "Doe"}"#,
952                ],
953            ),
954            // Object with optional properties:
955            // - last required property in first position
956            (
957                r#"{
958                    "properties": {
959                        "name": {"type": "string"},
960                        "age": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
961                        "weapon": {"anyOf": [{"type": "string"}, {"type": "null"}]}
962                    },
963                    "required": ["name"],
964                    "title": "Character",
965                    "type": "object"
966                }"#,
967                format!(r#"\{{[ ]?"name"[ ]?:[ ]?{STRING}([ ]?,[ ]?"age"[ ]?:[ ]?({INTEGER}|null))?([ ]?,[ ]?"weapon"[ ]?:[ ]?({STRING}|null))?[ ]?\}}"#).as_str(),
968                vec![
969                    r#"{ "name" : "Player" }"#,
970                    r#"{ "name" : "Player", "weapon" : "sword" }"#,
971                ],
972                vec![
973                    r#"{ "age" : 10, "weapon" : "sword" }"#,
974                ],
975            ),
976            // Object with optional properties:
977            // - last required property in middle position
978            (
979                r#"{
980                    "properties": {
981                        "name": {"type": "string"},
982                        "age": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
983                        "weapon": {"type": "string"},
984                        "strength": {"anyOf": [{"type": "integer"}, {"type": "null"}]}
985                    },
986                    "required": ["name", "weapon"],
987                    "title": "Character",
988                    "type": "object"
989                }"#,
990                format!(r#"\{{[ ]?"name"[ ]?:[ ]?{STRING}[ ]?,([ ]?"age"[ ]?:[ ]?({INTEGER}|null)[ ]?,)?[ ]?"weapon"[ ]?:[ ]?{STRING}([ ]?,[ ]?"strength"[ ]?:[ ]?({INTEGER}|null))?[ ]?\}}"#).as_str(),
991                vec![
992                    r#"{ "name" : "Player" , "weapon" : "sword" }"#,
993                    r#"{ "name" : "Player", "age" : 10, "weapon" : "sword" , "strength" : 10 }"#,
994                ],
995                vec![
996                    r#"{ "weapon" : "sword" }"#,
997                ],
998            ),
999            // Object with optional properties:
1000            // - last required property in last position
1001            (
1002                r#"{
1003                    "properties": {
1004                        "name": {"anyOf": [{"type": "string"}, {"type": "null"}]},
1005                        "age": {"type": "integer"},
1006                        "armor": {"type": "string"},
1007                        "strength": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
1008                        "weapon": {"title": "Weapon", "type": "string"}
1009                    },
1010                    "required": ["age", "armor", "weapon"],
1011                    "title": "Character",
1012                    "type": "object"
1013                }"#,
1014                format!(r#"\{{([ ]?"name"[ ]?:[ ]?({STRING}|null)[ ]?,)?[ ]?"age"[ ]?:[ ]?{INTEGER}[ ]?,[ ]?"armor"[ ]?:[ ]?{STRING}[ ]?,([ ]?"strength"[ ]?:[ ]?({INTEGER}|null)[ ]?,)?[ ]?"weapon"[ ]?:[ ]?{STRING}[ ]?\}}"#).as_str(),
1015                vec![
1016                    r#"{ "name" : "Player", "age" : 10, "armor" : "plate", "strength" : 11, "weapon" : "sword" }"#,
1017                    r#"{ "age" : 10, "armor" : "plate", "weapon" : "sword" }"#,
1018                ],
1019                vec![
1020                    r#"{ "name" : "Kahlhanbeh", "armor" : "plate", "weapon" : "sword" }"#,
1021                ],
1022            ),
1023            // Object with all optional properties
1024            (
1025                r#"{
1026                    "properties": {
1027                        "name": {"anyOf": [{"type": "string"}, {"type": "null"}]},
1028                        "age": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
1029                        "strength": {"anyOf": [{"type": "integer"}, {"type": "null"}]}
1030                    },
1031                    "title": "Character",
1032                    "type": "object"
1033                }"#,
1034                format!(r#"\{{([ ]?"name"[ ]?:[ ]?({STRING}|null)|([ ]?"name"[ ]?:[ ]?({STRING}|null)[ ]?,)?[ ]?"age"[ ]?:[ ]?({INTEGER}|null)|([ ]?"name"[ ]?:[ ]?({STRING}|null)[ ]?,)?([ ]?"age"[ ]?:[ ]?({INTEGER}|null)[ ]?,)?[ ]?"strength"[ ]?:[ ]?({INTEGER}|null))?[ ]?\}}"#).as_str(),
1035                vec![
1036                    r#"{ "name" : "Player" }"#,
1037                    r#"{ "name" : "Player", "age" : 10, "strength" : 10 }"#,
1038                    r#"{ "age" : 10, "strength" : 10 }"#,
1039                    "{ }",
1040                ],
1041                vec![r#"{ "foo": 0 } "#],
1042            ),
1043            // ==========================================================
1044            //                    Misc
1045            // ==========================================================
1046            // prefixItems
1047            (
1048                r#"{
1049                    "title": "Foo",
1050                    "prefixItems": [{"type": "string"}, {"type": "integer"}]
1051                }"#,
1052                format!(r#"\[{WHITESPACE}{STRING}{WHITESPACE},{WHITESPACE}{INTEGER}{WHITESPACE}\]"#).as_str(),
1053                vec![r#"["a", 1]"#],
1054                vec![r#"["a", 1, 1]"#, "[]"],
1055            ),
1056            // Unconstrained value (no schema)
1057            // (huge regex, but important test to verify matching it explicitely)
1058            (
1059                "{}",
1060                "((true|false))|(null)|(((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?)|((-)?(0|[1-9][0-9]*))|(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")|(\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])){0,})?[ ]?\\])|(\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|\\{[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)([ ]?,[ ]?\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"[ ]?:[ ]?(\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\"|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(true|false)|null)){0,})?[ ]?\\}|\\[[ ]?(((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")(,[ ]?((true|false)|null|((-)?(0|[1-9][0-9]*))(\\.[0-9]+)?([eE][+-][0-9]+)?|(-)?(0|[1-9][0-9]*)|\"([^\"\\\\\\x00-\\x1F\\x7F-\\x9F]|\\\\[\"\\\\/bfnrt])*\")){0,})?[ ]?\\])){0,})?[ ]?\\])){0,})?[ ]?\\})",
1061                vec![
1062                    r#""aaabbuecuh""#,
1063                    "5.554",
1064                    "true",
1065                    "null",
1066                    "5999",
1067                    r#"["a", "b"]"#,
1068                    r#"{"key": {"k2": "value"}}"#,
1069                ],
1070                vec!["this isnt valid json"],
1071            ),
1072            // ==========================================================
1073            //                      URI Format
1074            // ==========================================================
1075            (
1076                r#"{"title": "Foo", "type": "string", "format": "uri"}"#,
1077                URI,
1078                vec![
1079                    r#""http://example.com""#,
1080                    r#""https://example.com/path?query=param#fragment""#,
1081                    r#""ftp://ftp.example.com/resource""#,
1082                    r#""urn:isbn:0451450523""#,
1083                ],
1084                vec![
1085                    r#""http:/example.com""#, // missing slash
1086                    r#""htp://example.com""#, // invalid scheme
1087                    r#""http://""#,           // missing host
1088                    r#""example.com""#,       // missing scheme
1089                ]
1090            ),
1091            (
1092                r#"{"title": "Bar", "type": "string", "format": "email"}"#,
1093                EMAIL,
1094                vec![
1095                    // Valid emails
1096                    r#""user@example.com""#,               // valid
1097                    r#""user.name+tag+sorting@example.com""#, // valid
1098                    r#""user_name@example.co.uk""#,         // valid
1099                    r#""user-name@sub.example.com""#,       // valid
1100                ],
1101                vec![
1102                    // Invalid emails
1103                    r#""plainaddress""#,                   // missing '@' and domain
1104                    r#""@missingusername.com""#,           // missing username
1105                    r#""username@.com""#,                  // leading dot in domain
1106                    r#""username@com""#,                   // TLD must have at least 2 characters
1107                    r#""username@example,com""#,           // invalid character in domain
1108                    r#""username@.example.com""#,          // leading dot in domain
1109                    r#""username@-example.com""#,          // domain cannot start with a hyphen
1110                    r#""username@example-.com""#,          // domain cannot end with a hyphen
1111                    r#""username@example..com""#,          // double dot in domain name
1112                    r#""username@.example..com""#,         // multiple errors in domain
1113                ]
1114            ),
1115            // Nested URI and email
1116            (
1117                r#"{
1118                    "title": "Test Schema",
1119                    "type": "object",
1120                    "properties": {
1121                        "test_str": {"title": "Test string", "type": "string"},
1122                        "test_uri": {"title": "Test URI", "type": "string", "format": "uri"},
1123                        "test_email": {"title": "Test email", "type": "string", "format": "email"}
1124                    },
1125                    "required": ["test_str", "test_uri", "test_email"]
1126                }"#,
1127                format!(
1128                    r#"\{{{0}"test_str"{0}:{0}{STRING}{0},{0}"test_uri"{0}:{0}{URI}{0},{0}"test_email"{0}:{0}{EMAIL}{0}\}}"#,
1129                    WHITESPACE
1130                ).as_str(),
1131                vec![
1132                    r#"{ "test_str": "cat", "test_uri": "http://example.com", "test_email": "user@example.com" }"#,
1133                ],
1134                vec![
1135                    // Invalid URI
1136                    r#"{ "test_str": "cat", "test_uri": "http:/example.com", "test_email": "user@example.com" }"#,
1137                    // Invalid email
1138                    r#"{ "test_str": "cat", "test_uri": "http://example.com", "test_email": "username@.com" }"#,
1139                ]
1140            ),
1141
1142            // ==========================================================
1143            //                      Multiple types
1144            // ==========================================================
1145            (
1146                r#"{
1147                    "title": "Foo",
1148                    "type": ["string", "number", "boolean"]
1149                }"#,
1150                format!(r#"((?:"{STRING_INNER}*")|(?:{NUMBER})|(?:{BOOLEAN}))"#).as_str(),
1151                vec!["12.3", "true", r#""a""#],
1152                vec![
1153                    "null",
1154                    "",
1155                    "12true",
1156                    r#"1.3"a""#,
1157                    r#"12.3true"a""#,
1158                ],
1159            ),
1160            // Confirm that oneOf doesn't produce illegal lookaround: https://github.com/dottxt-ai/outlines/issues/823
1161            //
1162            // The pet field uses the discriminator field to decide which schema (Cat or Dog) applies, based on the pet_type property.
1163            // - if pet_type is "cat", the Cat schema applies, requiring a meows field (integer)
1164            // - if pet_type is "dog", the Dog schema applies, requiring a barks field (number)
1165            //
1166            // So, expected object requires two fields:
1167            //  - pet, which must be one of two types: Cat or Dog, determined by the pet_type field
1168            //  - n, an integer
1169            (
1170                r##"{
1171                    "$defs": {
1172                        "Cat": {
1173                            "properties": {
1174                                "pet_type": {
1175                                    "const": "cat",
1176                                    "enum": ["cat"],
1177                                    "title": "Pet Type",
1178                                    "type": "string"
1179                                },
1180                                "meows": {
1181                                    "title": "Meows",
1182                                    "type": "integer"
1183                                }
1184                            },
1185                            "required": ["pet_type", "meows"],
1186                            "title": "Cat",
1187                            "type": "object"
1188                        },
1189                        "Dog": {
1190                            "properties": {
1191                                "pet_type": {
1192                                    "const": "dog",
1193                                    "enum": ["dog"],
1194                                    "title": "Pet Type",
1195                                    "type": "string"
1196                                },
1197                                "barks": {
1198                                    "title": "Barks",
1199                                    "type": "number"
1200                                }
1201                            },
1202                            "required": ["pet_type", "barks"],
1203                            "title": "Dog",
1204                            "type": "object"
1205                        }
1206                    },
1207                    "properties": {
1208                        "pet": {
1209                            "discriminator": {
1210                                "mapping": {
1211                                    "cat": "#/$defs/Cat",
1212                                    "dog": "#/$defs/Dog"
1213                                },
1214                                "propertyName": "pet_type"
1215                            },
1216                            "oneOf": [
1217                                {"$ref": "#/$defs/Cat"},
1218                                {"$ref": "#/$defs/Dog"}
1219                            ],
1220                            "title": "Pet"
1221                        },
1222                        "n": {
1223                            "title": "N",
1224                            "type": "integer"
1225                        }
1226                    },
1227                    "required": ["pet", "n"],
1228                    "title": "Model",
1229                    "type": "object"
1230                }"##,
1231                r#"\{[ ]?"pet"[ ]?:[ ]?((?:\{[ ]?"pet_type"[ ]?:[ ]?("cat")[ ]?,[ ]?"meows"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?\})|(?:\{[ ]?"pet_type"[ ]?:[ ]?("dog")[ ]?,[ ]?"barks"[ ]?:[ ]?((-)?(0|[1-9][0-9]*))(\.[0-9]+)?([eE][+-][0-9]+)?[ ]?\}))[ ]?,[ ]?"n"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?\}"#,
1232                vec![
1233                    r#"{ "pet": { "pet_type": "cat", "meows": 5 }, "n": 10 }"#,
1234                    r#"{ "pet": { "pet_type": "dog", "barks": 3.5 }, "n": 7 }"#,
1235                ],
1236                vec![
1237                    // Missing required fields
1238                    r#"{ "pet": { "pet_type": "cat" }, "n": 10 }"#,
1239                    // Incorrect pet_type
1240                    r#"{ "pet": { "pet_type": "bird", "meows": 2 }, "n": 5 }"#
1241                ],
1242            ),
1243        ] {
1244            let result = regex_from_str(schema, None, None).expect("To regex failed");
1245            assert_eq!(result, regex, "JSON Schema {} didn't match", schema);
1246
1247            let re = Regex::new(&result).expect("Regex failed");
1248            for m in a_match {
1249                should_match(&re, m);
1250            }
1251            for not_m in not_a_match {
1252                should_not_match(&re, not_m);
1253            }
1254        }
1255    }
1256
1257    #[test]
1258    fn test_unconstrained_others() {
1259        for (schema, a_match, not_a_match) in [
1260            // Unconstrained Object
1261            (
1262                r#"{
1263                    "title": "Foo",
1264                    "type": "object"
1265                }"#,
1266                vec![
1267                    "{}",
1268                    r#"{"a": 1, "b": null}"#,
1269                    r#"{"a": {"z": {"g": 4}}, "b": null}"#,
1270                ],
1271                vec![
1272                    "1234",          // not an object
1273                    r#"["a", "a"]"#, // not an array
1274                ],
1275            ),
1276            // Unconstrained Array
1277            (
1278                r#"{"type": "array"}"#,
1279                vec![
1280                    r#"[1, {}, false]"#,
1281                    r#"[{}]"#,
1282                    r#"[{"a": {"z": "q"}, "b": null}]"#,
1283                    r#"[{"a": [1, 2, true], "b": null}]"#,
1284                    r#"[{"a": [1, 2, true], "b": {"a": "b"}}, 1, true, [1, [2]]]"#,
1285                ],
1286                vec![
1287                    // too deep, default unconstrained depth limit = 2
1288                    r#"[{"a": [1, 2, true], "b": {"a": "b"}}, 1, true, [1, [2, [3]]]]"#,
1289                    r#"[{"a": {"z": {"g": 4}}, "b": null}]"#,
1290                    r#"[[[[1]]]]"#,
1291                    // not an array
1292                    r#"{}"#,
1293                    r#"{"a": 1, "b": null}"#,
1294                    r#"{"a": {"z": {"g": 4}}, "b": null}"#,
1295                    "1234",
1296                    r#"{"a": "a"}"#,
1297                ],
1298            ),
1299        ] {
1300            let regex = regex_from_str(schema, None, None).expect("To regex failed");
1301            let re = Regex::new(&regex).expect("Regex failed");
1302            for m in a_match {
1303                should_match(&re, m);
1304            }
1305            for not_m in not_a_match {
1306                should_not_match(&re, not_m);
1307            }
1308        }
1309    }
1310
1311    #[test]
1312    fn with_whitespace_patterns() {
1313        let schema = r#"{
1314            "title": "Foo",
1315            "type": "object",
1316            "properties": {"date": {"type": "string", "format": "date"}}
1317        }"#;
1318
1319        for (whitespace_pattern, expected_regex, a_match) in [
1320            // Default
1321            (
1322                None,
1323                format!(
1324                    r#"\{{({WHITESPACE}"date"{WHITESPACE}:{WHITESPACE}{DATE})?{WHITESPACE}\}}"#
1325                ),
1326                vec![
1327                    r#"{"date": "2018-11-13"}"#,
1328                    r#"{ "date": "2018-11-13"}"#,
1329                    r#"{"date": "2018-11-13" }"#,
1330                ],
1331            ),
1332            (
1333                Some(r#"[\n ]*"#),
1334                format!(
1335                    r#"\{{({ws}"date"{ws}:{ws}{DATE})?{ws}\}}"#,
1336                    ws = r#"[\n ]*"#
1337                ),
1338                vec![
1339                    r#"{
1340                        "date":  "2018-11-13"
1341                    }"#,
1342                    r#"{ "date":
1343
1344                    "2018-11-13"     }"#,
1345                ],
1346            ),
1347            (
1348                Some("SPACE"),
1349                format!(r#"\{{({ws}"date"{ws}:{ws}{DATE})?{ws}\}}"#, ws = "SPACE"),
1350                vec![r#"{SPACE"date"SPACE:SPACE"2018-11-13"SPACE}"#],
1351            ),
1352        ] {
1353            let regex = regex_from_str(schema, whitespace_pattern, None).expect("To regex failed");
1354            assert_eq!(regex, expected_regex);
1355
1356            let re = Regex::new(&regex).expect("Regex failed");
1357            for m in a_match {
1358                should_match(&re, m);
1359            }
1360        }
1361    }
1362
1363    #[test]
1364    fn direct_recursion_in_array_and_default_behaviour() {
1365        let schema = r##"
1366        {
1367            "type": "object",
1368            "properties": {
1369                "name": { "type": "string" },
1370                "children": {
1371                    "type": "array",
1372                    "items": { "$ref": "#" }
1373                }
1374            }
1375        }"##;
1376
1377        let regex = regex_from_str(schema, None, None);
1378        assert!(regex.is_ok(), "{:?}", regex);
1379
1380        // Confirm the depth of 3 recursion levels by default, recursion level starts
1381        // when children start to have children
1382        let re = Regex::new(&regex.unwrap()).expect("Regex failed");
1383        for lvl in [
1384            // level 0
1385            r#"{ "name": "Az"}"#,
1386            r#"{ "name": "Az", "children": [] }"#,
1387            r#"{ "name": "Az", "children": [{"name": "Bo"}] }"#,
1388            // level 1
1389            r#"{ "name": "Az", "children": [{"name": "Bo", "children": [] }] }"#,
1390            r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li"}] }] }"#,
1391            // level 2
1392            r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [] }] }] }"#,
1393            r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho"}] }] }] }"#,
1394            // level 3
1395            r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [] }] }] }] }"#,
1396            r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro"}] }] }] }] }"#,
1397        ] {
1398            should_match(&re, lvl);
1399        }
1400
1401        for lvl in [
1402            // level 4
1403            r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro", "children": [] }] }] }] }] }"#,
1404            r#"{ "name": "Az", "children": [{"name": "Bo", "children": [{"name": "Li", "children": [{"name": "Ho", "children": [{"name": "Ro", "children": [{"name": "Ks"}] }] }] }] }] }"#,
1405        ] {
1406            should_not_match(&re, lvl);
1407        }
1408    }
1409
1410    #[test]
1411    fn indirect_recursion_with_recursion_level_regex_match() {
1412        let json = r##"{
1413          "type": "object",
1414          "properties": {
1415              "node": { "$ref": "#/definitions/node" }
1416          },
1417          "definitions": {
1418              "node": {
1419                  "type": "object",
1420                  "properties": {
1421                      "value": { "type": "integer" },
1422                      "next": { "$ref": "#/definitions/node" }
1423                  }
1424              }
1425          }
1426        }"##;
1427        let json_value: Value = serde_json::from_str(json).expect("Can't parse json");
1428        let mut parser = parsing::Parser::new(&json_value).with_max_recursion_depth(0);
1429
1430        let result = parser.to_regex(&json_value);
1431        assert!(result.is_ok(), "{:?}", result);
1432        let regex = result.unwrap();
1433        assert_eq!(
1434            r#"\{([ ]?"node"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*))?[ ]?\})?[ ]?\}"#,
1435            regex,
1436        );
1437
1438        //  More readable version to confirm that logic is correct.
1439        //  Recursion depth 1:
1440        //  {
1441        //      ("node":
1442        //          {
1443        //              ("value":(-)?(0|[1-9][0-9]*)(,"next":{("value":(-)?(0|[1-9][0-9]*))?})?
1444        //              |
1445        //              ("value":(-)?(0|[1-9][0-9]*),)?"next":{("value":(-)?(0|[1-9][0-9]*))?})?
1446        //          }
1447        //      )?
1448        //  }
1449        //  Recursion depth 2:
1450        //  {
1451        //      ("node":
1452        //          {
1453        //              ("value":(-)?(0|[1-9][0-9]*)(,"next":{
1454        //                  ("value":(-)?(0|[1-9][0-9]*)(,"next":{("value":(-)?(0|[1-9][0-9]*))?})?
1455        //                  |
1456        //                  ("value":(-)?(0|[1-9][0-9]*),)?"next":{("value":(-)?(0|[1-9][0-9]*))?})?
1457        //              })?
1458        //              |
1459        //              ("value":(-)?(0|[1-9][0-9]*),)?"next":{
1460        //                  ("value":(-)?(0|[1-9][0-9]*)(,"next":{("value":(-)?(0|[1-9][0-9]*))?})?
1461        //                  |
1462        //                  ("value":(-)?(0|[1-9][0-9]*),)?"next":{("value":(-)?(0|[1-9][0-9]*))?})?
1463        //              })?
1464        //          }
1465        //      )?
1466        // }
1467        let mut parser = parser.with_max_recursion_depth(1);
1468        let result = parser.to_regex(&json_value);
1469        assert!(result.is_ok(), "{:?}", result);
1470        let regex = result.unwrap();
1471        assert_eq!(
1472            r#"\{([ ]?"node"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)|([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*)[ ]?,)?[ ]?"next"[ ]?:[ ]?\{([ ]?"value"[ ]?:[ ]?(-)?(0|[1-9][0-9]*))?[ ]?\})?[ ]?\})?[ ]?\}"#,
1473            regex,
1474        );
1475    }
1476
1477    #[test]
1478    fn triple_recursion_doesnt_fail() {
1479        let schema = r##"
1480        {
1481            "definitions": {
1482                "typeA": {
1483                    "type": "object",
1484                    "properties": {
1485                        "name": { "type": "string" },
1486                        "child": { "$ref": "#/definitions/typeB" }
1487                    },
1488                    "required": ["name"]
1489                },
1490                "typeB": {
1491                    "type": "object",
1492                    "properties": {
1493                        "value": { "type": "number" },
1494                        "next": { "$ref": "#/definitions/typeC" }
1495                    },
1496                    "required": ["value"]
1497                },
1498                "typeC": {
1499                    "type": "object",
1500                    "properties": {
1501                        "flag": { "type": "boolean" },
1502                        "parent": { "$ref": "#/definitions/typeA" }
1503                    },
1504                    "required": ["flag"]
1505                }
1506           },
1507          "$ref": "#/definitions/typeA"
1508        }"##;
1509
1510        let regex = regex_from_str(schema, None, None);
1511        assert!(regex.is_ok(), "{:?}", regex);
1512    }
1513
1514    #[test]
1515    fn quadruple_recursion_doesnt_include_leaf() {
1516        let schema = r##"
1517        {
1518            "definitions": {
1519                "typeA": {
1520                "type": "object",
1521                "properties": {
1522                    "data": { "type": "string" },
1523                    "typeB": { "$ref": "#/definitions/typeB" }
1524                },
1525                "required": ["data", "typeB"]
1526                },
1527                "typeB": {
1528                "type": "object",
1529                "properties": {
1530                    "data": { "type": "string" },
1531                    "typeC": { "$ref": "#/definitions/typeC" }
1532                },
1533                "required": ["data", "typeC"]
1534                },
1535                "typeC": {
1536                "type": "object",
1537                "properties": {
1538                    "data": { "type": "string" },
1539                    "typeD": { "$ref": "#/definitions/typeD" }
1540                },
1541                "required": ["data", "typeD"]
1542                },
1543                "typeD": {
1544                "type": "object",
1545                "properties": {
1546                    "data": { "type": "string" },
1547                    "typeE": { "$ref": "#/definitions/typeE" }
1548                },
1549                "required": ["data", "typeE"]
1550                },
1551                "typeE": {
1552                "type": "object",
1553                "properties": {
1554                    "data": { "type": "string" },
1555                    "typeA": { "$ref": "#/definitions/typeA" }
1556                },
1557                "required": ["data", "typeA"]
1558                }
1559            },
1560            "$ref": "#/definitions/typeA"
1561        }"##;
1562
1563        let regex = regex_from_str(schema, None, None);
1564        assert!(regex.is_ok(), "{:?}", regex);
1565        let regex_str = regex.unwrap();
1566        assert!(
1567            !regex_str.contains("typeE"),
1568            "Regex should not contain typeE when max_recursion_depth is not specified"
1569        );
1570    }
1571
1572    #[test]
1573    fn quadruple_recursion_includes_leaf_when_max_recursion_depth_is_specified() {
1574        let schema = r##"
1575        {
1576            "definitions": {
1577                "typeA": {
1578                "type": "object",
1579                "properties": {
1580                    "data": { "type": "string" },
1581                    "typeB": { "$ref": "#/definitions/typeB" }
1582                },
1583                "required": ["data", "typeB"]
1584                },
1585                "typeB": {
1586                "type": "object",
1587                "properties": {
1588                    "data": { "type": "string" },
1589                    "typeC": { "$ref": "#/definitions/typeC" }
1590                },
1591                "required": ["data", "typeC"]
1592                },
1593                "typeC": {
1594                "type": "object",
1595                "properties": {
1596                    "data": { "type": "string" },
1597                    "typeD": { "$ref": "#/definitions/typeD" }
1598                },
1599                "required": ["data", "typeD"]
1600                },
1601                "typeD": {
1602                "type": "object",
1603                "properties": {
1604                    "data": { "type": "string" },
1605                    "typeE": { "$ref": "#/definitions/typeE" }
1606                },
1607                "required": ["data", "typeE"]
1608                },
1609                "typeE": {
1610                "type": "object",
1611                "properties": {
1612                    "data": { "type": "string" },
1613                    "typeA": { "$ref": "#/definitions/typeA" }
1614                },
1615                "required": ["data", "typeA"]
1616                }
1617            },
1618            "$ref": "#/definitions/typeA"
1619        }"##;
1620
1621        let regex = regex_from_str(schema, None, Some(4));
1622        assert!(regex.is_ok(), "{:?}", regex);
1623        let regex_str = regex.unwrap();
1624        assert!(
1625            regex_str.contains("typeE"),
1626            "Regex should contain typeE when max_recursion_depth is specified"
1627        );
1628    }
1629}