Skip to content

Commit ee197c5

Browse files
added untested injection method
1 parent 6a929e9 commit ee197c5

File tree

2 files changed

+176
-28
lines changed

2 files changed

+176
-28
lines changed

src/sjv/sjv.cpp

Lines changed: 143 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,65 @@
33
#include <iostream>
44
#include <filesystem> // C++17
55
#include <sstream>
6+
#include <algorithm>
67
////////////////////////////////////////////////////////////////////////////////
78

89
namespace sjv
910
{
11+
12+
//////////// PUBLIC
13+
1014
bool SJV::verify_json(const json &input, const json &rules)
1115
{
1216
log.clear();
1317
return verify_json("/", input, rules);
14-
}
18+
};
19+
20+
json SJV::inject_defaults(const json &input, const json &rules)
21+
{
22+
// The code below assumes that the input satisfies the rules
23+
assert(verify_json(input, rules));
24+
25+
// Find all the default rules
26+
json default_rules = collect_default_rules(rules);
27+
28+
// Flatten the input
29+
json flat = input.flatten();
30+
json out_flat = flat;
31+
32+
// For each rule, go over all entries of a flattened input
33+
for (auto rule : default_rules)
34+
{
35+
for (auto e : flat.items())
36+
{
37+
// If the pointer matches a strict subset of it, add it to the flattened
38+
std::tuple<bool, string> subset = is_subset_pointer(string(rule["pointer"]), e.key());
39+
if (std::get<0>(subset))
40+
out_flat[std::get<1>(subset)] = rule["default"];
41+
}
42+
}
43+
44+
// Unflatten the input
45+
json output = out_flat.unflatten();
46+
47+
// Certify the validity of the final file
48+
assert(verify_json(input, rules));
49+
50+
return output;
51+
};
52+
53+
std::string SJV::log2str()
54+
{
55+
std::stringstream s;
56+
57+
for (log_item i : log)
58+
{
59+
s << i.first << ": " << i.second << std::endl;
60+
}
61+
return s.str();
62+
};
63+
64+
//////////// PRIVATE
1565

1666
bool SJV::verify_json(const string &pointer, const json &input, const json &rules)
1767
{
@@ -44,7 +94,7 @@ namespace sjv
4494
// Make sure there are some rules for the boxed version before recursively checking
4595
if (collect_pointer(new_pointer, rules).size() > 0)
4696
if (verify_json(new_pointer, input, rules))
47-
return true;
97+
return true;
4898
}
4999

50100
std::stringstream s;
@@ -274,17 +324,21 @@ namespace sjv
274324
return false;
275325

276326
return true;
277-
}
327+
};
278328

279-
std::string SJV::log2str()
329+
json SJV::collect_default_rules(const json &rules)
280330
{
281-
std::stringstream s;
331+
// Find all rules that apply for the input node
332+
// TODO: accelerate this
282333

283-
for (log_item i : log)
334+
std::vector<json> matching_rules;
335+
for (auto i : rules)
284336
{
285-
s << i.first << ": " << i.second << std::endl;
337+
if (i.contains("default"))
338+
matching_rules.push_back(i);
286339
}
287-
return s.str();
340+
341+
return matching_rules;
288342
};
289343

290344
json SJV::collect_default_rules(const string &pointer, const json &rules)
@@ -307,7 +361,7 @@ namespace sjv
307361
return std::find(list.begin(), list.end(), item) != list.end();
308362
};
309363

310-
std::vector<json> SJV::collect_pointer(const string& pointer, const json& rules)
364+
std::vector<json> SJV::collect_pointer(const string &pointer, const json &rules)
311365
{
312366
std::vector<json> matching_rules;
313367
for (auto i : rules)
@@ -317,4 +371,84 @@ namespace sjv
317371
}
318372
return matching_rules;
319373
};
374+
375+
json SJV::find_valid_rule(const string &pointer, const json &input, const json &rules)
376+
{
377+
for (auto i : collect_pointer(pointer, rules))
378+
if (verify_rule(input, i))
379+
return i;
380+
381+
return json();
382+
};
383+
384+
std::tuple<bool, string> SJV::is_subset_pointer(const string &json, const string &pointer)
385+
{
386+
387+
// Splits a string into tokens using the deliminator delim
388+
auto tokenize = [](std::string const &str, const char delim) {
389+
size_t start;
390+
size_t end = 0;
391+
std::vector<string> out;
392+
393+
while ((start = str.find_first_not_of(delim, end)) != std::string::npos)
394+
{
395+
end = str.find(delim, start);
396+
out.push_back(str.substr(start, end - start));
397+
}
398+
399+
return out;
400+
};
401+
402+
// Replaces occurrences of a substring
403+
auto replace_all = [](std::string str, const std::string &from, const std::string &to) {
404+
size_t start_pos = 0;
405+
while ((start_pos = str.find(from, start_pos)) != std::string::npos)
406+
{
407+
str.replace(start_pos, from.length(), to);
408+
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
409+
}
410+
return str;
411+
};
412+
413+
// Check if a string is an integer
414+
auto is_number = [](const string &str) {
415+
for (char const &c : str)
416+
if (std::isdigit(c) == 0)
417+
return false;
418+
return true;
419+
};
420+
421+
// Tokenize json_pointer
422+
std::vector<string> json_t = tokenize(json, '/');
423+
std::vector<string> pointer_t = tokenize(pointer, '/');
424+
425+
// if the json is not shorter or if there are no tokens, give up
426+
if ((json_t.size() >= pointer_t.size())
427+
|| (pointer_t.size() == 0))
428+
return {false, ""};
429+
430+
std::string buf = "/";
431+
// if it is shorter, match every entry
432+
for (unsigned i = 0; i < pointer_t.size(); ++i)
433+
{
434+
// if there is no corresponding entry on json, copy and move on
435+
if (json_t.size() < i)
436+
buf.append(replace_all(pointer_t[i], "*", "0") + "/");
437+
438+
// if there is an entry on json and it is the same, move on
439+
if (json_t[i] == pointer_t[i])
440+
buf.append(pointer_t[i] + "/");
441+
442+
// if the pointer contains a star, then accept any integer on json
443+
if (pointer_t[i] == "*")
444+
if (is_number(json_t[i]))
445+
buf.append(json_t[i] + "/");
446+
447+
// if no rule matches it is not a match
448+
return {false, ""};
449+
}
450+
451+
return {true, buf};
452+
};
453+
320454
} // namespace sjv

src/sjv/sjv.h

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,11 @@ namespace sjv
1515
// verify the input json against the set of rules in specs
1616
bool verify_json(const json &input, const json &rules);
1717

18-
// Verify a node pointed by
19-
bool verify_json(const string &pointer, const json &input, const json &rules);
20-
21-
// Dispatcher for rule verification
22-
bool verify_rule(const json &input, const json &rule);
18+
// enriches a given json with default values
19+
json inject_defaults(const json &input, const json &rules);
2320

24-
// Type-specific rule handlers
25-
bool verify_rule_file(const json &input, const json &rule);
26-
bool verify_rule_folder(const json &input, const json &rule);
27-
bool verify_rule_float(const json &input, const json &rule);
28-
bool verify_rule_int(const json &input, const json &rule);
29-
bool verify_rule_string(const json &input, const json &rule);
30-
bool verify_rule_object(const json &input, const json &rule);
31-
bool verify_rule_bool(const json &input, const json &rule);
32-
bool verify_rule_list(const json &input, const json &rule);
33-
34-
// TODO
35-
json generate_default_json(const json &rules);
21+
// log to string
22+
std::string log2str();
3623

3724
// Working directory
3825
string cwd = ".";
@@ -48,17 +35,44 @@ namespace sjv
4835
typedef std::pair<std::string, std::string> log_item;
4936
std::vector<log_item> log;
5037

51-
// log to string
52-
std::string log2str();
38+
private:
39+
// enriches a given json with default values
40+
void inject_defaults(const string &pointer, const json &input, const json &rules, json &output);
41+
42+
// Verify a node pointed by
43+
bool verify_json(const string &pointer, const json &input, const json &rules);
44+
45+
// Dispatcher for rule verification
46+
bool verify_rule(const json &input, const json &rule);
47+
48+
// Type-specific rule handlers
49+
bool verify_rule_file(const json &input, const json &rule);
50+
bool verify_rule_folder(const json &input, const json &rule);
51+
bool verify_rule_float(const json &input, const json &rule);
52+
bool verify_rule_int(const json &input, const json &rule);
53+
bool verify_rule_string(const json &input, const json &rule);
54+
bool verify_rule_object(const json &input, const json &rule);
55+
bool verify_rule_bool(const json &input, const json &rule);
56+
bool verify_rule_list(const json &input, const json &rule);
57+
58+
// Collect all rules having a default
59+
json collect_default_rules(const json &rules);
5360

5461
// Collect all rules having a default for a given pointer
5562
json collect_default_rules(const string &pointer, const json &rules);
5663

5764
// Collect all rules having a given pointer
5865
std::vector<json> collect_pointer(const string &pointer, const json &rules);
5966

67+
// Find the first rule matching a pointer
68+
json find_valid_rule(const string &pointer, const json &input, const json &rules);
69+
6070
// Utils
6171
bool contained_in_list(string item, const json &list);
72+
73+
// Checks if a given json pointer is a subset of a pointer string (containing wildcards).
74+
// If it is, the second return parameter is an instantiated pointer
75+
std::tuple<bool, string> is_subset_pointer(const string &json_pointer, const string &pointer);
6276
};
6377

6478
} // namespace sjv

0 commit comments

Comments
 (0)