1use super::*;
2use crate::idl::{keywords::Keywords, parser::*};
3
4pub fn format_document(parser: &Parser) -> Option<String> {
9 let mut body = String::new();
10 let mut library = String::new();
11 let mut imports = String::new();
12
13 let mut is_comment = false;
14
15 for node in &parser.nodes {
16 match node {
17 ParserNode::Imports(value) => {
18 imports = format!("{} {{", Keywords::Import);
19 imports +=
21 split_if_longer_than(value.as_slice(), MAX_LENGTH - imports.len() - 1).as_str();
22 imports += CLOSE_NEW_LINE;
23 }
24 ParserNode::Library(value) => {
25 library = format!("{} ", Keywords::Library);
26 library += value.as_str();
27 library += NEW_LINE;
28 }
29 ParserNode::Comment(value) => {
30 if is_comment {
31 body += "\n";
32 }
33
34 for comment in value {
35 let list_comment = format!("{}{}\n", COMMENT_START, comment.as_str());
36 body += list_comment.as_str();
37 }
38 is_comment = true;
39 }
40 nodw => {
41 if is_comment {
42 body += "\n";
43 is_comment = false;
44 }
45 match nodw {
46 ParserNode::Const(value) => {
47 if !value.comment.is_empty() {
48 push_comment(&mut body, &value.comment);
49 }
50
51 let type_body = format!(
52 "{} {} = {};{}",
53 Keywords::Const,
54 value.ident,
55 value.value.to_owned(),
56 NEW_LINE
57 );
58 body += type_body.as_str();
59 }
60 ParserNode::Enum(value) => {
61 if !value.comment.is_empty() {
62 push_comment(&mut body, &value.comment);
63 }
64
65 let type_body =
66 format!("{} {}{}", Keywords::Enum, value.ident, OPEN_NEW_LINE);
67 body += type_body.as_str();
68
69 for enum_node in value.fields.iter() {
70 match enum_node {
71 EnumNode::Comment(comment) => {
72 push_field_comment(&mut body, comment)
73 }
74 EnumNode::EnumField(field) => {
75 let field_str = format!("{}{},\n", INDENT, field);
76 body += field_str.as_str();
77 }
78 EnumNode::TypeEnumField(field) => {
79 let field_str = format!("{}{},\n", INDENT, field);
80 body += field_str.as_str();
81 }
82 }
83 }
84 body += CLOSE_NEW_LINE;
85 }
86 ParserNode::Interface(value) => {
87 if !value.comment.is_empty() {
88 push_comment(&mut body, &value.comment);
89 }
90
91 let type_body =
92 format!("{} {}{}", Keywords::Interface, value.ident, OPEN_NEW_LINE);
93 body += type_body.as_str();
94
95 for interface_node in value.fields.iter() {
96 match interface_node {
97 InterfaceNode::Comment(comment) => {
98 push_field_comment(&mut body, comment)
99 }
100 InterfaceNode::InterfaceField(field) => {
101 let field_str = split_interface_field(field);
102 body += field_str.as_str();
103 }
104 }
105 }
106 body += CLOSE_NEW_LINE;
107 }
108 ParserNode::Struct(value) => {
109 if !value.comment.is_empty() {
110 push_comment(&mut body, &value.comment);
111 }
112
113 let type_body =
114 format!("{} {}{}", Keywords::Struct, value.ident, OPEN_NEW_LINE);
115 body += type_body.as_str();
116
117 for struct_node in value.fields.iter() {
118 match struct_node {
119 StructNode::Comment(comment) => {
120 push_field_comment(&mut body, comment)
121 }
122 StructNode::StructField(field) => {
123 let field_str = format!("{}{},\n", INDENT, field);
124 body += field_str.as_str();
125 }
126 }
127 }
128 body += CLOSE_NEW_LINE;
129 }
130 _ => {}
131 }
132 }
133 }
134 }
135
136 library += imports.as_str();
137 library += body.as_str();
138
139 Some(library.trim().to_string())
140}
141
142fn push_field_comment(body: &mut String, comments: &[String]) {
143 for comment in comments {
144 let comment_str = format!("{}{}{}\n", INDENT, COMMENT_START, comment.as_str());
145 body.push_str(comment_str.as_str());
146 }
147}
148
149fn push_comment(body: &mut String, comments: &[String]) {
150 for comment in comments {
151 let list_comment = format!("{}{}\n", COMMENT_START, comment.as_str());
152 body.push_str(list_comment.as_str());
153 }
154}
155
156fn split_if_longer_than(txt: &[String], max_length: usize) -> String {
159 let mut result = String::from(" ");
160
161 for value in txt.iter() {
162 if result != " " {
163 result += ", ";
164 }
165 result += value;
166 }
167
168 result += " ";
169
170 if result.len() > max_length {
171 result = String::from("\n");
172
173 for value in txt.iter() {
174 let r = format!("{}{},\n", INDENT, value);
175 result += r.as_str();
176 }
177 }
178
179 result
180}
181
182fn split_interface_field(interface_field: &InterfaceField) -> String {
183 let split_tuple = |indent: usize, ty: &[TupleEntry]| {
185 let mut result = String::new();
186
187 if ty.is_empty() {
188 return "()".to_owned();
189 }
190
191 for (index, t) in ty.into_iter().enumerate() {
192 let st = format!(
193 "{}{}: {}{}",
194 if index == 0 {
195 "(".to_owned()
196 } else {
197 " ".repeat(indent)
198 },
199 t.ident,
200 t.ty,
201 if index != ty.len() - 1 { ",\n" } else { ")" }
202 );
203 result += st.as_str()
204 }
205
206 result
207 };
208
209 let tryln = format!(
210 "{}:{}{},",
211 INDENT,
212 interface_field.ident.to_owned(),
213 interface_field.ty.to_string()
214 );
215
216 if tryln.len() > MAX_LENGTH {
217 let indent_len = format!("{}:{}(", INDENT, interface_field.ident.to_owned()).len();
218 let ty_field = match &*interface_field.ty {
219 Type::Tuple(tuple) => split_tuple(indent_len, &tuple.fields),
220 Type::Function(function) => {
221 let tt = match &*function.args {
222 Type::Tuple(value) => value.clone(),
223 _ => panic!("Not a tuple"),
224 };
225
226 format!(
227 "{} -> {}",
228 split_tuple(indent_len, &*tt.fields),
229 function.ret_ty.to_string()
230 )
231 }
232 ty => ty.to_string(),
233 };
234
235 format!(
236 "{}:{}{},\n",
237 INDENT,
238 interface_field.ident.to_owned(),
239 ty_field
240 )
241 } else {
242 tryln + "\n"
243 }
244}