1use std::fs;
5use serde_json;
6use heck::ToTitleCase;
7use schema::TypeName;
8use handlebars::Handlebars;
9
10pub mod blueprint;
11pub mod schema;
12pub mod template;
13
14pub struct Codegen<'a> {
15 handlebars: Handlebars<'a>,
16}
17
18impl Codegen<'_> {
19 pub fn new() -> Codegen<'static> {
20 Codegen {
21 handlebars: template::init_handlebars(),
22 }
23 }
24
25 fn get_schema_name(&self, key: String) -> String {
26 return key
27 .replace("#/definitions/", "")
28 .replace("~1", " ")
29 .replace("/", " ")
30 .replace("_", " ")
31 .replace("$", " ")
32 .to_title_case()
33 .replace(" ", "");
34 }
35
36 pub fn get_blueprint_from_json(&self, json: String) -> blueprint::Blueprint {
46 serde_json::from_str(&json).expect("Unable to parse")
47 }
48
49 pub fn get_blueprint_from_path(&self, path: String) -> blueprint::Blueprint {
59 let json = fs::read_to_string(path).expect("Unable to read file");
60 self.get_blueprint_from_json(json)
61 }
62
63 pub fn get_schemas_from_blueprint(&self, blueprint: blueprint::Blueprint) -> Vec<schema::Schema> {
73 let mut schemas: Vec<schema::Schema> = vec![];
74 if blueprint.definitions.is_some() {
75 for definition in blueprint.definitions.unwrap().inner.iter() {
76 let definition_name = self.get_schema_name(definition.0.clone());
77 let definition_json = serde_json::to_string(&definition.1).unwrap();
78 if definition.1.data_type.is_some() {
79 match definition.1.data_type.unwrap() {
80 blueprint::DataType::Integer => {
81 schemas.push(schema::Schema::new_integer(definition_name.clone(), definition_json.clone()));
82 }
83 blueprint::DataType::Bytes => {
84 schemas.push(schema::Schema::new_bytes(definition_name.clone(), definition_json.clone()));
85 }
86 blueprint::DataType::List => {
87 if definition.1.items.is_some() {
88 match definition.1.items.as_ref().unwrap() {
89 blueprint::ReferencesArray::Single(reference) => {
90 if reference.reference.is_some() {
91 schemas.push(schema::Schema::new_list(
92 definition_name.clone(),
93 schema::Reference{
94 name: None,
95 schema_name: self.get_schema_name(reference.reference.as_ref().unwrap().clone())
96 },
97 definition_json.clone()
98 ));
99 }
100 }
101 blueprint::ReferencesArray::Array(references) => {
102 let mut properties: Vec<schema::Reference> = vec![];
103 for reference in references {
104 if reference.reference.is_some() {
105 properties.push(schema::Reference{
106 name: None,
107 schema_name: self.get_schema_name(reference.reference.as_ref().unwrap().clone())
108 });
109 }
110 }
111 schemas.push(schema::Schema::new_tuple(definition_name.clone(), properties, definition_json.clone()));
112 }
113 }
114 }
115 }
116 _ => {}
117 }
118 }
119 if definition.1.title.is_some() {
120 if definition.1.title.as_ref().unwrap() == "Data" && definition_name == "Data" {
121 schemas.push(schema::Schema::new_anydata(definition_json.clone()));
122 }
123 }
124 if definition.1.any_of.is_some() {
125 let mut internal_schemas: Vec<schema::Schema> = vec![];
126 for (index, parameter) in definition.1.any_of.as_ref().unwrap().iter().enumerate() {
127 match parameter.data_type {
128 blueprint::DataType::Constructor => {
129 let schema_name = format!("{}{}", definition_name, parameter.title.clone().unwrap_or((index+1).to_string()));
130 let mut properties: Vec<schema::Reference> = vec![];
131 for property in ¶meter.fields {
132 let mut schema_name = self.get_schema_name(property.reference.clone());
133 if schema_name == "Data" {
134 schema_name = "AnyData".to_string();
135 }
136 properties.push(schema::Reference{
137 name: property.title.clone(),
138 schema_name,
139 });
140 }
141 let schema: schema::Schema;
142 if properties.len().gt(&0) || parameter.title.is_none() {
143 if properties.iter().any(|p| p.name.is_none()) {
144 schema = schema::Schema::new_tuple(schema_name, properties, definition_json.clone());
145 } else {
146 schema = schema::Schema::new_object(schema_name, properties, definition_json.clone());
147 }
148 } else {
149 schema = schema::Schema::new_literal(schema_name, parameter.title.clone().unwrap(), definition_json.clone());
150 }
151 internal_schemas.push(schema);
152 }
153 _ => {}
154 }
155 }
156 if internal_schemas.len().eq(&1) {
157 let mut schema = internal_schemas.first().unwrap().clone();
158 schema.name = definition_name.clone();
159 schemas.push(schema);
160 }
161 if internal_schemas.len().gt(&1) {
162 if internal_schemas.len().eq(&2)
163 && internal_schemas.iter().any(|s| s.type_name.eq(&TypeName::Literal))
164 && !internal_schemas.iter().all(|s| s.type_name.eq(&TypeName::Literal))
165 {
166 let reference = internal_schemas.iter().find(|s| s.type_name.ne(&TypeName::Literal));
167 schemas.push(reference.unwrap().clone());
168 schemas.push(schema::Schema::new_nullable(
169 definition_name.clone(),
170 reference.unwrap().name.clone(),
171 definition_json.clone()
172 ));
173 } else {
174 for schema in &internal_schemas {
175 schemas.push(schema.clone());
176 }
177 schemas.push(schema::Schema::new_enum(definition_name.clone(), &internal_schemas, definition_json.clone()));
178 }
179 }
180 }
181 }
182 }
183
184 schemas
185 }
186
187 pub fn get_validators_from_blueprint(&self, blueprint: blueprint::Blueprint) -> Vec<schema::Validator> {
197 let mut validators: Vec<schema::Validator> = vec![];
198 for validator in blueprint.validators.iter() {
199 let mut datum: Option<schema::Reference> = None;
200 if validator.datum.is_some() && validator.datum.as_ref().unwrap().schema.reference.is_some() {
201 datum = Some(schema::Reference {
202 name: validator.datum.as_ref().unwrap().title.clone(),
203 schema_name: self.get_schema_name(validator.datum.as_ref().unwrap().schema.reference.as_ref().unwrap().clone()),
204 });
205 }
206 let mut redeemer: Option<schema::Reference> = None;
207 if validator.redeemer.is_some() && validator.redeemer.as_ref().unwrap().schema.reference.is_some() {
208 redeemer = Some(schema::Reference {
209 name: validator.redeemer.as_ref().unwrap().title.clone(),
210 schema_name: self.get_schema_name(validator.redeemer.as_ref().unwrap().schema.reference.as_ref().unwrap().clone()),
211 });
212 }
213 let mut parameters: Vec<schema::Reference> = vec![];
214 if let Some(p) = &validator.parameters {
215 for parameter in p {
216 if parameter.schema.reference.is_some() {
217 parameters.push(
218 schema::Reference {
219 name: parameter.title.clone(),
220 schema_name: self.get_schema_name(parameter.schema.reference.as_ref().unwrap().clone()),
221 }
222 )
223 }
224 }
225 }
226 validators.push(
227 schema::Validator {
228 name: validator.title.clone(),
229 datum: datum,
230 redeemer: redeemer,
231 parameters: parameters,
232 }
233 );
234 }
235 validators
236 }
237
238 pub fn get_template_from_blueprint(&self, blueprint: blueprint::Blueprint, template: template::Template) -> String {
249 let schemas = self.get_schemas_from_blueprint(blueprint);
250 self.handlebars.render(&template.to_string(), &schemas).unwrap()
251 }
252}