Skip to content

Commit e8b39d1

Browse files
authored
Generate a JSON representation of Stone. (#485)
1 parent 77328a5 commit e8b39d1

File tree

4 files changed

+145
-2
lines changed

4 files changed

+145
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import json
2+
import os
3+
4+
from stone.ir import (
5+
Api,
6+
ApiNamespace,
7+
ApiRoute,
8+
DataType,
9+
Field,
10+
Int32,
11+
List,
12+
is_boolean_type,
13+
is_bytes_type,
14+
is_composite_type,
15+
is_list_type,
16+
is_map_type,
17+
is_nullable_type,
18+
is_numeric_type,
19+
is_primitive_type,
20+
is_string_type,
21+
is_struct_type,
22+
is_timestamp_type,
23+
is_union_type,
24+
is_user_defined_type,
25+
is_void_type,
26+
StructField,
27+
TagRef,
28+
Union,
29+
UnionField,
30+
unwrap_nullable,
31+
Void,
32+
)
33+
from stone.backend import CodeBackend
34+
35+
36+
def is_enum(data_type):
37+
if data_type is None:
38+
return False
39+
40+
assert isinstance(data_type, DataType), repr(data_type)
41+
if is_union_type(data_type):
42+
return all(is_void_type(f.data_type) for f in data_type.all_fields)
43+
else:
44+
return False
45+
46+
47+
# Generates an unofficial JSON representation of Stone.
48+
class JsonCodeGenerator(CodeBackend):
49+
def what_type_info(self, data_type):
50+
if data_type is None:
51+
return None
52+
53+
type_info = {
54+
"name": data_type.name,
55+
"is_struct_type": is_struct_type(data_type),
56+
"is_primitive_type": is_primitive_type(data_type),
57+
"is_boolean_type": is_boolean_type(data_type),
58+
"is_numeric_type": is_numeric_type(data_type),
59+
"is_list_type": is_list_type(data_type),
60+
"is_union_type": is_union_type(data_type),
61+
"is_bytes_type": is_bytes_type(data_type),
62+
"is_map_type": is_map_type(data_type),
63+
"is_composite_type": is_composite_type(data_type),
64+
"is_nullable_type": is_nullable_type(data_type),
65+
"is_string_type": is_string_type(data_type),
66+
"is_void_type": is_void_type(data_type),
67+
"is_timestamp_type": is_timestamp_type(data_type),
68+
}
69+
70+
if is_struct_type(data_type):
71+
type_info["namespace"] = data_type.namespace.name
72+
type_info["parent_type_data"] = self.what_type_info(data_type.parent_type)
73+
if is_union_type(data_type):
74+
type_info["namespace"] = data_type.namespace.name
75+
if is_nullable_type(data_type):
76+
type_info["nullable_type_data"] = self.what_type_info(data_type.data_type)
77+
if is_union_type(data_type):
78+
type_info["parent_type_data"] = self.what_type_info(data_type.parent_type)
79+
if is_list_type(data_type):
80+
type_info["list_item_type_data"] = self.what_type_info(data_type.data_type)
81+
type_info["min_items"] = data_type.min_items
82+
type_info["max_items"] = data_type.max_items
83+
if is_map_type(data_type):
84+
type_info["map_key_type_data"] = self.what_type_info(data_type.key_data_type)
85+
type_info["map_value_type_data"] = self.what_type_info(data_type.value_data_type)
86+
87+
return type_info
88+
89+
def generate(self, api):
90+
for namespace in api.namespaces.values():
91+
namespace_data = {
92+
"name": namespace.name,
93+
"doc": namespace.doc,
94+
"routes": [],
95+
"types": []
96+
}
97+
for data_type in namespace.linearize_data_types():
98+
type_data = {
99+
"name": data_type.name,
100+
"doc": data_type.doc,
101+
"type_info": self.what_type_info(data_type),
102+
"fields": [],
103+
}
104+
105+
type_data["examples"] = []
106+
for example in data_type.get_examples().values():
107+
type_data["examples"].append({
108+
"text": example.text,
109+
"label": example.label,
110+
"value": example.value,
111+
})
112+
113+
for field in data_type.all_fields:
114+
if field.name is not "other":
115+
field_data = {
116+
"name": field.name,
117+
"doc": field.doc,
118+
"type_info": self.what_type_info(field.data_type),
119+
"deprecated": field.deprecated,
120+
"preview": field.preview,
121+
}
122+
123+
type_data["fields"].append(field_data)
124+
125+
namespace_data["types"].append(type_data)
126+
127+
for route in namespace.routes:
128+
namespace_data["route_count"] = len(namespace.routes)
129+
namespace_data["routes"].append({
130+
"name": route.name,
131+
"doc": route.doc,
132+
"version": route.version,
133+
"path": "/" + str(route.version) + "/" + namespace.name + "/" + route.name
134+
})
135+
136+
output_dir = "build/stone-json/types"
137+
138+
if not os.path.exists(output_dir):
139+
os.makedirs(output_dir)
140+
141+
if len(namespace_data["types"]) > 0:
142+
with open(output_dir + '/' + namespace.name + '.json', 'w') as f:
143+
f.write(json.dumps(namespace_data, indent=2))

stone-java-gradle-plugin/src/main/kotlin/com/dropbox/stone/java/StonePlugin.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class StonePlugin : Plugin<Project> {
5252
val mySpecDir: String = specDirPropNameValue ?: "src/${sourceSet.name}/stone"
5353

5454
stoneTask.specDir(mySpecDir)
55-
stoneTask.generatorDir("${project.projectDir.absoluteFile}/generator")
55+
stoneTask.generatorDir("${project.projectDir.absoluteFile}/generator/java")
5656
stoneTask.stoneDir("stone")
5757
stoneTask.pythonCommand("python")
5858
stoneTask.outputDir("${project.buildDir}/generated/source/stone/${sourceSet.name}")

stone-java-gradle-plugin/src/main/kotlin/com/dropbox/stone/java/StoneTask.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ abstract class StoneTask : DefaultTask() {
9696
generatorFile,
9797
specFiles,
9898
getOutputDir().asFile.get(),
99-
getPythonCommand().get()
99+
getPythonCommand().get(),
100100
)
101101
}
102102

0 commit comments

Comments
 (0)