Last active
August 5, 2023 02:38
-
-
Save romanbsd/da181151170e396e8e36a6576f045aa2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import json | |
import sys | |
import re | |
TYPES = { | |
'boolean': 'bool', | |
'integer': 'int', | |
'string': 'string', | |
'object': 'object', | |
'array': 'array', | |
'null': 'string' | |
} | |
def get_obj_def(j): | |
if j['type'] == 'object': | |
return j | |
elif j['type'] == 'array' and 'items' in j: | |
return j['items'] | |
def get_type(j): | |
typ = j['type'] | |
if type(typ) == list: | |
return next(filter(lambda x: x != 'null', typ)) | |
return TYPES[typ] | |
def capitalize(s): | |
return re.sub('_([a-z])', lambda x: x[1].capitalize(), s.capitalize()) | |
class Table: | |
def __init__(self, name, props, required): | |
self.name, self.required = name, required | |
self.fields = [] | |
self.build(props) | |
def build(self, props): | |
for k, v in props.items(): | |
if 'anyOf' in v: | |
# FIXME | |
print('not adding', k, v, file=sys.stderr) | |
continue | |
if re.match('^\\d', k): | |
print('key cannot start with a digit: ', k, file=sys.stderr) | |
continue | |
is_array = False | |
if v['type'] == 'array': | |
is_array = True | |
if 'items' not in v or 'type' not in v['items']: | |
continue | |
typ = v['items']['type'] | |
if typ == 'object': | |
typ = capitalize(re.sub('s$', '', k)) | |
else: | |
typ = capitalize(k) if v['type'] == 'object' else get_type(v) | |
required = k in self.required | |
self.add_field(Field(k, typ, is_array=is_array, required=required)) | |
def add_field(self, field): | |
self.fields.append(field) | |
def __str__(self): | |
fields = "\n".join([str(field) for field in self.fields]) | |
return f'table {self.name} {{\n{fields}\n}}\n' | |
class Field: | |
def __init__(self, name, type, is_array=False, required=False): | |
self.name, self.type, self.is_array = name, type, is_array | |
self.required = required and type not in ['bool', 'int'] | |
def __str__(self) -> str: | |
kind = f'[{self.type}]' if self.is_array else self.type | |
required = ' (required)' if self.required else '' | |
return f' {self.name}: {kind}{required};' | |
class Schema: | |
def __init__(self, j, namespace) -> None: | |
self.namespace = namespace | |
obj = get_obj_def(j) | |
self.tables = [Table('Root', obj['properties'], obj['required'])] | |
self.build(j) | |
def build(self, j): | |
if j['type'] not in ['object', 'array']: | |
raise Exception('unsupported') | |
self.add_tables(j) | |
def add_tables(self, j): | |
obj_def = get_obj_def(j) | |
if obj_def is None or 'properties' not in obj_def: | |
return | |
props = obj_def['properties'] | |
if props is None: | |
return | |
for key, val in props.items(): | |
if 'anyOf' in val: | |
# FIXME | |
print('anyOf is unsupported, key: ', key, file=sys.stderr) | |
continue | |
typ = get_type(val) | |
name = key.capitalize() | |
name = re.sub('_([a-z])', lambda x: x[1].capitalize(), name) | |
if typ == 'object': | |
self.add_table(name, val) | |
elif typ == 'array' and 'items' in val and val['items']['type'] == 'object': | |
self.add_table(re.sub('s$', '', name), val['items']) | |
else: | |
continue | |
self.add_tables(val) | |
def add_table(self, name, obj_def): | |
if re.match('^\\d', name): | |
return | |
if name in [table.name for table in self.tables]: | |
return | |
table = Table(name, obj_def['properties'], obj_def['required']) | |
self.tables.append(table) | |
def __str__(self) -> str: | |
tables = "\n".join([str(table) for table in self.tables]) | |
return f'namespace {self.namespace};\n\n{tables}\nroot_type {self.tables[0].name};' | |
if __name__ == '__main__': | |
with open(sys.argv[1]) as f: | |
j = json.load(f) | |
namespace = sys.argv[2] if len(sys.argv) > 2 else 'com.example' | |
schema = Schema(j, namespace) | |
print(schema) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment