use super::*;
use crate::idl::{keywords::Keywords, parser::*};
pub fn format_document(parser: &Parser) -> Option<String> {
let mut body = String::new();
let mut library = String::new();
let mut imports = String::new();
let mut is_comment = false;
for node in &parser.nodes {
match node {
ParserNode::Imports(value) => {
imports = format!("{} {{", Keywords::Import);
imports +=
split_if_longer_than(value.as_slice(), MAX_LENGTH - imports.len() - 1).as_str();
imports += CLOSE_NEW_LINE;
}
ParserNode::Library(value) => {
library = format!("{} ", Keywords::Library);
library += value.as_str();
library += NEW_LINE;
}
ParserNode::Comment(value) => {
if is_comment {
body += "\n";
}
for comment in value {
let list_comment = format!("{}{}\n", COMMENT_START, comment.as_str());
body += list_comment.as_str();
}
is_comment = true;
}
nodw => {
if is_comment {
body += "\n";
is_comment = false;
}
match nodw {
ParserNode::Const(value) => {
if !value.comment.is_empty() {
push_comment(&mut body, &value.comment);
}
let type_body = format!(
"{} {} = {};{}",
Keywords::Const,
value.ident,
value.value.to_owned(),
NEW_LINE
);
body += type_body.as_str();
}
ParserNode::Enum(value) => {
if !value.comment.is_empty() {
push_comment(&mut body, &value.comment);
}
let type_body =
format!("{} {}{}", Keywords::Enum, value.ident, OPEN_NEW_LINE);
body += type_body.as_str();
for enum_node in value.fields.iter() {
match enum_node {
EnumNode::Comment(comment) => {
push_field_comment(&mut body, comment)
}
EnumNode::EnumField(field) => {
let field_str = format!("{}{},\n", INDENT, field);
body += field_str.as_str();
}
EnumNode::TypeEnumField(field) => {
let field_str = format!("{}{},\n", INDENT, field);
body += field_str.as_str();
}
}
}
body += CLOSE_NEW_LINE;
}
ParserNode::Interface(value) => {
if !value.comment.is_empty() {
push_comment(&mut body, &value.comment);
}
let type_body =
format!("{} {}{}", Keywords::Interface, value.ident, OPEN_NEW_LINE);
body += type_body.as_str();
for interface_node in value.fields.iter() {
match interface_node {
InterfaceNode::Comment(comment) => {
push_field_comment(&mut body, comment)
}
InterfaceNode::InterfaceField(field) => {
let field_str = split_interface_field(field);
body += field_str.as_str();
}
}
}
body += CLOSE_NEW_LINE;
}
ParserNode::Struct(value) => {
if !value.comment.is_empty() {
push_comment(&mut body, &value.comment);
}
let type_body =
format!("{} {}{}", Keywords::Struct, value.ident, OPEN_NEW_LINE);
body += type_body.as_str();
for struct_node in value.fields.iter() {
match struct_node {
StructNode::Comment(comment) => {
push_field_comment(&mut body, comment)
}
StructNode::StructField(field) => {
let field_str = format!("{}{},\n", INDENT, field);
body += field_str.as_str();
}
}
}
body += CLOSE_NEW_LINE;
}
_ => {}
}
}
}
}
library += imports.as_str();
library += body.as_str();
Some(library.trim().to_string())
}
fn push_field_comment(body: &mut String, comments: &[String]) {
for comment in comments {
let comment_str = format!("{}{}{}\n", INDENT, COMMENT_START, comment.as_str());
body.push_str(comment_str.as_str());
}
}
fn push_comment(body: &mut String, comments: &[String]) {
for comment in comments {
let list_comment = format!("{}{}\n", COMMENT_START, comment.as_str());
body.push_str(list_comment.as_str());
}
}
fn split_if_longer_than(txt: &[String], max_length: usize) -> String {
let mut result = String::from(" ");
for value in txt.iter() {
if result != " " {
result += ", ";
}
result += value;
}
result += " ";
if result.len() > max_length {
result = String::from("\n");
for value in txt.iter() {
let r = format!("{}{},\n", INDENT, value);
result += r.as_str();
}
}
result
}
fn split_interface_field(interface_field: &InterfaceField) -> String {
let split_tuple = |indent: usize, ty: &[TupleEntry]| {
let mut result = String::new();
if ty.is_empty() {
return "()".to_owned();
}
for (index, t) in ty.into_iter().enumerate() {
let st = format!(
"{}{}: {}{}",
if index == 0 {
"(".to_owned()
} else {
" ".repeat(indent)
},
t.ident,
t.ty,
if index != ty.len() - 1 { ",\n" } else { ")" }
);
result += st.as_str()
}
result
};
let tryln = format!(
"{}:{}{},",
INDENT,
interface_field.ident.to_owned(),
interface_field.ty.to_string()
);
if tryln.len() > MAX_LENGTH {
let indent_len = format!("{}:{}(", INDENT, interface_field.ident.to_owned()).len();
let ty_field = match &*interface_field.ty {
Type::Tuple(tuple) => split_tuple(indent_len, &tuple.fields),
Type::Function(function) => {
let tt = match &*function.args {
Type::Tuple(value) => value.clone(),
_ => panic!("Not a tuple"),
};
format!(
"{} -> {}",
split_tuple(indent_len, &*tt.fields),
function.ret_ty.to_string()
)
}
ty => ty.to_string(),
};
format!(
"{}:{}{},\n",
INDENT,
interface_field.ident.to_owned(),
ty_field
)
} else {
tryln + "\n"
}
}