@@ -69,7 +69,6 @@ namespace jse
6969
7070 } // namespace
7171
72-
7372 // enriches a given json spec with included json specs
7473 json JSE::inject_include (const json &rules)
7574 {
@@ -83,20 +82,20 @@ namespace jse
8382 {
8483 // check if the rules have any include
8584 bool include_present = false ;
86- for (const auto & rule : current)
85+ for (const auto & rule : current)
8786 if (rule.at (" type" ) == " include" )
8887 include_present = true ;
89-
88+
9089 // if there are no includes, return the current ones
9190 if (!include_present)
9291 return current;
9392
9493 json enriched;
9594 // otherwise, do a round of replacement
96- for (const auto & rule : current)
95+ for (const auto & rule : current)
9796 {
9897 // copy all rules that are not include
99- if (rule.at (" type" ) != " include" )
98+ if (rule.at (" type" ) != " include" )
10099 {
101100 enriched.push_back (rule);
102101 }
@@ -105,7 +104,7 @@ namespace jse
105104 {
106105 bool replaced = false ;
107106 // the include file could be in any of the include directories
108- for (const auto & dir : dirs)
107+ for (const auto & dir : dirs)
109108 {
110109 string spec_file = rule.at (" spec_file" );
111110 string f = dir + " /" + spec_file;
@@ -116,23 +115,22 @@ namespace jse
116115 json include_rules = json::parse (ifs);
117116
118117 // loop over all rules to add the prefix
119- for (auto & i_rule : include_rules)
118+ for (auto & i_rule : include_rules)
120119 {
121120 string prefix = rule.at (" pointer" );
122121 string pointer = i_rule.at (" pointer" );
123- string new_pointer = prepend_pointer (pointer,prefix);
122+ string new_pointer = prepend_pointer (pointer, prefix);
124123 i_rule.at (" pointer" ) = new_pointer;
125124 }
126125
127126 // save modified rules
128- for (const auto & i_rule : include_rules)
127+ for (const auto & i_rule : include_rules)
129128 enriched.push_back (i_rule);
130129
131130 // one substitution is enough, give up the search over include dirs
132131 replaced = true ;
133132 break ;
134133 }
135-
136134 }
137135
138136 if (!replaced)
@@ -149,10 +147,8 @@ namespace jse
149147 }
150148
151149 throw std::runtime_error (" Reached maximal 10 levels of include recursion." );
152-
153150 }
154151
155-
156152 bool JSE::verify_json (const string &pointer, json &input, const json &rules)
157153 {
158154 // Find all rules that apply for the input node
@@ -167,19 +163,16 @@ namespace jse
167163 }
168164
169165 // Test all rules, one and only one must pass, otherwise throw exception
170- int count = 0 ;
171- json single_matched_rule;
172-
173- for (auto i : matching_rules)
166+ std::vector<json> verified_matching_rules;
167+ for (auto r : matching_rules)
174168 {
175- if (verify_rule (input, i ))
169+ if (verify_rule (input, r ))
176170 {
177- count++;
178- single_matched_rule = i;
171+ verified_matching_rules.push_back (r);
179172 }
180173 }
181174
182- if (count == 0 )
175+ if (verified_matching_rules. size () == 0 )
183176 {
184177 // Before giving up, try boxing a primitive type
185178 if (boxing_primitive && !input.is_array ())
@@ -199,16 +192,17 @@ namespace jse
199192 log.push_back (log_item (" error" , s.str ()));
200193 return false ;
201194 }
202- else if (count > 1 )
195+ else if (verified_matching_rules. size () > 1 )
203196 {
204197 std::stringstream s;
205198 s << " Multiple rules matched for \" " << pointer << " \" : " << input.dump (/* indent=*/ 4 ) << std::endl;
206199 s << " Multiple valid rules in this list, only one should be valid:" ;
207- for (int i = 0 ; i < matching_rules .size (); i++)
208- s << i << " : " << matching_rules [i].dump (/* indent=*/ 4 ) << " \n " ;
200+ for (int i = 0 ; i < verified_matching_rules .size (); i++)
201+ s << i << " : " << verified_matching_rules [i].dump (/* indent=*/ 4 ) << " \n " ;
209202 log.push_back (log_item (" error" , s.str ()));
210203 return false ;
211204 }
205+ const json &single_matched_rule = verified_matching_rules.front ();
212206
213207 // If it passes and if it is a dictionary, then test all childrens
214208 if (input.is_object ())
@@ -427,11 +421,25 @@ namespace jse
427421 if (!input.is_object () && !input.is_null ())
428422 return false ;
429423
424+ // Check that all required fields are present
430425 if (rule.contains (" required" ))
431426 for (auto e : rule[" required" ])
432427 if (!input.contains (string (e)))
433428 return false ;
434429
430+ std::vector<std::string> keys;
431+ keys.reserve ((rule.contains (" required" ) ? rule[" required" ].size () : 0 )
432+ + (rule.contains (" optional" ) ? rule[" optional" ].size () : 0 ));
433+ if (rule.contains (" required" ))
434+ keys.insert (keys.end (), rule[" required" ].begin (), rule[" required" ].end ());
435+ if (rule.contains (" optional" ))
436+ keys.insert (keys.end (), rule[" optional" ].begin (), rule[" optional" ].end ());
437+
438+ // Check that no extra fields are present
439+ for (const auto &[key, value] : input.items ())
440+ if (std::find (keys.begin (), keys.end (), key) == keys.end ())
441+ return false ;
442+
435443 if (rule.contains (" type_name" )
436444 && (!input.contains (" type" ) || input[" type" ] != rule[" type_name" ]))
437445 return false ;
0 commit comments