@@ -49,6 +49,15 @@ impl<'a> Parser<'a> {
49
49
50
50
#[ allow( clippy:: wrong_self_convention) ]
51
51
pub fn to_regex ( & mut self , json : & Value ) -> Result < String > {
52
+ // TODO: the current design of this parser is conceptually limited and should be reworked!
53
+ //
54
+ // It branch in the following `match` for specific keys in the JSON schema (e.g., "allOf", "anyOf", etc.).
55
+ // This approach makes these keys mutually exclusive, meaning that if a JSON schema contains multiple keys
56
+ // that should be combined, the parser will just silently take the first one and ignore the others.
57
+ //
58
+ // To address this, the parser should retain some state while parsing, using a data structure that, e.g.,
59
+ // can contain one option per possible key. This would allow the parser to handle more complex cases by
60
+ // combining constraints appropriately.
52
61
match json {
53
62
Value :: Object ( obj) if obj. is_empty ( ) => self . parse_empty_object ( ) ,
54
63
Value :: Object ( obj) if obj. contains_key ( "properties" ) => self . parse_properties ( obj) ,
@@ -62,6 +71,15 @@ impl<'a> Parser<'a> {
62
71
Value :: Object ( obj) if obj. contains_key ( "type" ) => self . parse_type ( obj) ,
63
72
json => Err ( Error :: UnsupportedJsonSchema ( Box :: new ( json. clone ( ) ) ) ) ,
64
73
}
74
+ // Each function in this recursive descent parser generates a regex as a `String`, eventually patching
75
+ // JSONSchema on the fly and calling `.to_regex()`, which is then combined using simple string formatting.
76
+ // This approach is extremely fragile and not expressive. It is prone to errors and difficult to maintain
77
+ // or debug.
78
+ //
79
+ // The right way to implement this is to design the parser like a small compiler with an intermediate
80
+ // representation (IR). This IR would be a higher-level representation of regex that can be combined and
81
+ // mutated more easily. The code generation step could then be a default `Display` string formatter
82
+ // version of the IR. This approach would be more robust, easier to debug, and maintainable.
65
83
}
66
84
67
85
fn parse_empty_object ( & mut self ) -> Result < String > {
@@ -164,6 +182,15 @@ impl<'a> Parser<'a> {
164
182
regex += & format ! ( "({})?" , possible_patterns. join( "|" ) ) ;
165
183
}
166
184
185
+ // FIXME: the following lines broke `with_whitespace_patterns`,
186
+ // `indirect_recursion_with_recursion_level_regex_match` and
187
+ // `direct_recursion_in_array_and_default_behaviour`
188
+ if obj. contains_key ( "type" ) {
189
+ // This is a hack to quickly fix issue #150
190
+ let s = self . parse_type ( obj) ?;
191
+ regex += & format ! ( ",{}" , & s[ 2 ..s. len( ) - 2 ] ) ;
192
+ }
193
+
167
194
regex += & format ! ( "{}\\ }}" , self . whitespace_pattern) ;
168
195
Ok ( regex)
169
196
}
@@ -503,7 +530,9 @@ impl<'a> Parser<'a> {
503
530
let additional_properties = obj. get ( "additionalProperties" ) ;
504
531
505
532
let value_pattern = match additional_properties {
506
- None | Some ( & Value :: Bool ( true ) ) => {
533
+ // FIXME: the following lines broke `test_unconstrained_others` and `test_schema_matches_regex`
534
+ None | Some ( & Value :: Bool ( false ) ) => "" . to_string ( ) ,
535
+ Some ( & Value :: Bool ( true ) ) => {
507
536
let mut legal_types = vec ! [
508
537
json!( { "type" : "string" } ) ,
509
538
json!( { "type" : "number" } ) ,
0 commit comments