json: basic support for reserved names {number:{number:{root:number}}}

This commit is contained in:
ochafik 2024-03-15 10:35:34 +00:00
parent daceced65e
commit 5714487830
4 changed files with 113 additions and 5 deletions

View file

@ -35,6 +35,8 @@ DATE_RULES = {
'date-time-string': '"\\"" date-time "\\"" space', 'date-time-string': '"\\"" date-time "\\"" space',
} }
RESERVED_NAMES = set(["root", *PRIMITIVE_RULES.keys(), *DATE_RULES.keys()])
INVALID_RULE_CHARS_RE = re.compile(r'[^a-zA-Z0-9-]+') INVALID_RULE_CHARS_RE = re.compile(r'[^a-zA-Z0-9-]+')
GRAMMAR_LITERAL_ESCAPE_RE = re.compile(r'[\r\n"]') GRAMMAR_LITERAL_ESCAPE_RE = re.compile(r'[\r\n"]')
GRAMMAR_RANGE_LITERAL_ESCAPE_RE = re.compile(r'[\r\n"\]\-\\]') GRAMMAR_RANGE_LITERAL_ESCAPE_RE = re.compile(r'[\r\n"\]\-\\]')
@ -300,7 +302,7 @@ class SchemaConverter:
def visit(self, schema, name): def visit(self, schema, name):
schema_type = schema.get('type') schema_type = schema.get('type')
schema_format = schema.get('format') schema_format = schema.get('format')
rule_name = name or 'root' rule_name = name + '-' if name in RESERVED_NAMES else name or 'root'
if (ref := schema.get('$ref')) is not None: if (ref := schema.get('$ref')) is not None:
return self._add_rule(rule_name, self._resolve_ref(ref)) return self._add_rule(rule_name, self._resolve_ref(ref))

View file

@ -43,6 +43,16 @@ unordered_map<string, string> DATE_RULES = {
{"date-time-string", "\"\\\"\" date-time \"\\\"\" space"} {"date-time-string", "\"\\\"\" date-time \"\\\"\" space"}
}; };
static bool is_reserved_name(const string& name) {
static std::unordered_set<std::string> RESERVED_NAMES;
if (RESERVED_NAMES.empty()) {
RESERVED_NAMES.insert("root");
for (const auto &p : PRIMITIVE_RULES) RESERVED_NAMES.insert(p.first);
for (const auto &p : DATE_RULES) RESERVED_NAMES.insert(p.first);
}
return RESERVED_NAMES.find(name) != RESERVED_NAMES.end();
}
regex INVALID_RULE_CHARS_RE("[^a-zA-Z0-9-]+"); regex INVALID_RULE_CHARS_RE("[^a-zA-Z0-9-]+");
regex GRAMMAR_LITERAL_ESCAPE_RE("[\r\n\"]"); regex GRAMMAR_LITERAL_ESCAPE_RE("[\r\n\"]");
regex GRAMMAR_RANGE_LITERAL_ESCAPE_RE("[\r\n\"\\]\\-\\\\]"); regex GRAMMAR_RANGE_LITERAL_ESCAPE_RE("[\r\n\"\\]\\-\\\\]");
@ -523,7 +533,7 @@ public:
string visit(const json& schema, const string& name) { string visit(const json& schema, const string& name) {
json schema_type = schema.contains("type") ? schema["type"] : json(); json schema_type = schema.contains("type") ? schema["type"] : json();
string schema_format = schema.contains("format") ? schema["format"].get<string>() : ""; string schema_format = schema.contains("format") ? schema["format"].get<string>() : "";
string rule_name = name.empty() ? "root" : name; string rule_name = is_reserved_name(name) ? name + "-" : name.empty() ? "root" : name;
if (schema.contains("$ref")) { if (schema.contains("$ref")) {
return _add_rule(rule_name, _resolve_ref(schema["$ref"])); return _add_rule(rule_name, _resolve_ref(schema["$ref"]));

View file

@ -26,6 +26,8 @@ const DATE_RULES = {
'date-time-string': '"\\"" date-time "\\"" space', 'date-time-string': '"\\"" date-time "\\"" space',
}; };
const RESERVED_NAMES = {'root': true, ...PRIMITIVE_RULES, ...DATE_RULES};
const INVALID_RULE_CHARS_RE = /[^\dA-Za-z-]+/g; const INVALID_RULE_CHARS_RE = /[^\dA-Za-z-]+/g;
const GRAMMAR_LITERAL_ESCAPE_RE = /[\n\r"]/g; const GRAMMAR_LITERAL_ESCAPE_RE = /[\n\r"]/g;
const GRAMMAR_RANGE_LITERAL_ESCAPE_RE = /[\n\r"\]\-\\]/g; const GRAMMAR_RANGE_LITERAL_ESCAPE_RE = /[\n\r"\]\-\\]/g;
@ -326,7 +328,7 @@ export class SchemaConverter {
visit(schema, name) { visit(schema, name) {
const schemaType = schema.type; const schemaType = schema.type;
const schemaFormat = schema.format; const schemaFormat = schema.format;
const ruleName = name || 'root'; const ruleName = name in RESERVED_NAMES ? name + '-' : name == '' ? 'root' : name;
const ref = schema.$ref; const ref = schema.$ref;
if (ref !== undefined) { if (ref !== undefined) {

View file

@ -259,10 +259,61 @@ int main() {
)""" )"""
}); });
run_all({
"object w/ required props",
R"""({
"type": "object",
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string"
}
},
"required": [
"a",
"b"
],
"additionalProperties": false,
"definitions": {}
})""",
R"""(
a-kv ::= "\"a\"" space ":" space string
b-kv ::= "\"b\"" space ":" space string
root ::= "{" space a-kv "," space b-kv "}" space
space ::= " "?
string ::= "\"" (
[^"\\] |
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
)* "\"" space
)"""
});
run_all({
"1 optional",
R"""({
"properties": {
"a": {
"type": "string"
}
},
"additionalProperties": false
})""",
R"""(
a-kv ::= "\"a\"" space ":" space string
root ::= "{" space (a-kv )? "}" space
space ::= " "?
string ::= "\"" (
[^"\\] |
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
)* "\"" space
)"""
});
run_all({ run_all({
"optionals", "optionals",
R"""({ R"""({
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object", "type": "object",
"properties": { "properties": {
"a": { "a": {
@ -333,7 +384,6 @@ int main() {
run_all({ run_all({
"top-level $ref", "top-level $ref",
R"""({ R"""({
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/MyType", "$ref": "#/definitions/MyType",
"definitions": { "definitions": {
"MyType": { "MyType": {
@ -362,4 +412,48 @@ int main() {
)""" )"""
}); });
run_all({
"conflicting names",
R"""({
"type": "object",
"properties": {
"number": {
"type": "object",
"properties": {
"number": {
"type": "object",
"properties": {
"root": {
"type": "number"
}
},
"required": [
"root"
],
"additionalProperties": false
}
},
"required": [
"number"
],
"additionalProperties": false
}
},
"required": [
"number"
],
"additionalProperties": false,
"definitions": {}
})""",
R"""(
number ::= ("-"? ([0-9] | [1-9] [0-9]*)) ("." [0-9]+)? ([eE] [-+]? [0-9]+)? space
number- ::= "{" space number-number-kv "}" space
number-kv ::= "\"number\"" space ":" space number-
number-number ::= "{" space number-number-root-kv "}" space
number-number-kv ::= "\"number\"" space ":" space number-number
number-number-root-kv ::= "\"root\"" space ":" space number
root ::= "{" space number-kv "}" space
space ::= " "?
)"""
});
} }