1use crate::counter::counter_commands::CounterCommand;
2
3use super::datacell::{
4 BlockCell::BlockCell, BlockChildType::*, CellTrait::Cell, Datacell::*, ElementCell::*,
5};
6use super::element_text::ElementText;
7use super::helpers::*;
8use super::parser_helpers::{tag_stack_pop, TagInfo};
9
10#[derive(Debug)]
11pub struct Parser {
12 result: DataCell,
13 pub id: usize,
14 }
16
17#[derive(Debug)]
18pub enum ParserError {
19 ExtraSpacesError(usize),
20 None4xSpacesError(usize),
21}
22
23impl ParserError {
24 pub fn to_string(&self) -> String {
25 match self {
26 ParserError::ExtraSpacesError(line) => format!("Extra spaces found on line {}", line),
27 ParserError::None4xSpacesError(line) => {
28 format!("None 4x spaces found on line {}", line)
29 }
30 }
31 }
32
33 pub fn to_string_without_line(&self) -> String {
34 match self {
35 ParserError::ExtraSpacesError(_) => format!("Extra spaces found"),
36 ParserError::None4xSpacesError(_) => {
37 format!("None 4x spaces found")
38 }
39 }
40 }
41}
42
43impl Parser {
44 pub fn new() -> Parser {
45 Self {
46 result: DataCell {
47 parent_id: 0,
48 id: 0,
49 cell_type: CellType::Root(Root { children: vec![] }),
50 },
51 id: 1,
52 }
53 }
54
55 pub fn import_json(json: &String) -> String {
56 json.clone()
57 }
58
59 fn handle_tag_line(
60 &mut self,
61 trimmed_line: &str,
62 mut curr_el_id: Option<usize>,
63 mut is_nested: &bool,
64 tag_stack: &mut Vec<TagInfo>,
65 indent: usize,
66 ) {
67 let tag_name = trimmed_line[3..].trim();
68 tag_stack_pop(tag_stack, &indent);
69
70 curr_el_id = if let Some(last) = tag_stack.last() {
71 Some(last.id)
72 } else if *is_nested {
73 is_nested = &false;
74 curr_el_id
75 } else {
76 Some(0)
77 };
78
79 ElementCell::add_cell(&mut self.result, curr_el_id.unwrap(), self.id, tag_name);
80
81 tag_stack.push(TagInfo {
82 id: self.id,
83 name: tag_name.to_string(),
84 indent,
85 is_self_closing: false,
86 in_props: true,
87 });
88 self.id += 1;
89 }
90
91 fn props_end(&mut self, trimmed_line: &str, tag_stack: &Vec<TagInfo>) -> bool {
92 trimmed_line.is_empty() && tag_stack
94 .last()
95 .map_or(false, |tag| tag.in_props && !tag.is_self_closing)
96 }
97
98 pub fn export_json(
99 &mut self,
100 elm: &str,
101 mut curr_el_id: Option<usize>,
102 mut is_nested: bool,
103 ) -> Result<String, ParserError> {
104 let mut tag_stack: Vec<TagInfo> = Vec::new();
105 let lines = elm.lines();
106 let mut lines_to_skip: u32 = 0;
107 let mut text_node = String::new();
108
109 for (index, line) in lines.clone().enumerate() {
110 if lines_to_skip > 0 {
111 lines_to_skip = lines_to_skip - 1;
112 continue;
113 }
114
115 let trimmed_line = line.trim_start();
116 let indent = get_line_indent(line);
117
118 if trimmed_line.starts_with("!!") {
119 continue;
120 }
121 check_indent_size(indent as isize, index)?;
122 if let Some(last) = tag_stack.last() {
123 check_extra_spaces(indent, last.indent, index)?;
124 }
125
126 if trimmed_line.starts_with("|> ") {
127 self.handle_tag_line(trimmed_line, curr_el_id, &is_nested, &mut tag_stack, indent);
128 continue;
129 }
130 if self.props_end(trimmed_line, &tag_stack) {
131 if let Some(last) = tag_stack.last_mut() {
132 last.in_props = false;
133 }
134 continue;
135 }
136
137 if !trimmed_line.is_empty() {
138 tag_stack_pop(&mut tag_stack, &indent);
139
140 curr_el_id = if let Some(last) = tag_stack.last() {
141 Some(last.id)
142 } else if is_nested {
143 is_nested = false;
144 curr_el_id
145 } else {
146 Some(0)
147 };
148
149 let last = tag_stack
150 .last()
151 .expect(&format!("There is no parent tag . at line \n {:?}", index));
152 if last.in_props {
153 ElementCell::add_attribute(&mut self.result, last.id, trimmed_line);
155 continue;
156 }
157
158 let next_line = lines.clone().nth(index + 1);
159 let next_line_empty = next_line.is_none()
160 || (next_line.is_some() && next_line.unwrap().trim().is_empty());
161 let next_line_is_element =
162 next_line.is_some() && next_line.unwrap().trim_start().starts_with("|> ");
163 let next_line_indent = if let Some(next_line) = next_line {
164 Some(get_line_indent(next_line))
165 } else {
166 None
167 };
168
169 let end_of_attached_element =
170 next_line_indent.is_some_and(|ne| ne > 0 && ne < indent);
171
172 if next_line_empty
174 || next_line_is_element
175 || indent < tag_stack.last().unwrap().indent
176 || end_of_attached_element
177 {
178 text_node = format!(
179 "{}{}{}",
180 text_node,
181 if text_node == "" { "" } else { " " },
182 if trimmed_line.trim_end().len() + 1 == trimmed_line.len() {
184 trimmed_line
185 } else {
186 trimmed_line.trim_end()
187 },
188 );
189
190 let mut block = BlockCell::new();
191
192 let e = ElementText::new(&text_node);
193 let block_children = e.split_text();
194
195 block.has_counter_commands =
200 CounterCommand::has_counter_syntax(text_node.as_str());
201 block.has_handle_insert =
202 CounterCommand::has_handle_insert_syntax(text_node.as_str());
203
204 block_children.iter().for_each(|child| {
205 if let BlockChildType::Text(text) = &child {
206 if text.content != "" {
207 BlockChildType::push_cell(&mut block, child.to_owned());
208 }
209 } else {
210 BlockChildType::push_cell(&mut block, child.to_owned());
211 }
212 });
213
214 text_node = "".to_string();
215
216 BlockCell::add_cell(&mut self.result, curr_el_id.unwrap(), self.id, &block);
217 self.id += 1;
218
219 if end_of_attached_element && tag_stack.len() > 1 {
220 let parent_id = self.get_parent_id(&tag_stack);
221 ElementCell::add_cell(
222 &mut self.result,
223 parent_id.unwrap(),
224 self.id,
225 "Space",
226 );
227 self.id += 1;
228 }
229
230 continue;
231 }
232
233 text_node = format!(
234 "{}{}{}",
235 text_node,
236 if text_node == "" { "" } else { " " },
237 if trimmed_line.trim_end().len() + 1 == trimmed_line.len() {
238 trimmed_line
239 } else {
240 trimmed_line.trim_end()
241 },
242 );
243 if !text_node.is_empty() {
244 text_node.push_str("\n")
245 }
246 }
247 }
248 let res = serde_json::to_string_pretty(&self.result);
249 Ok(res.unwrap_or("Something Wrong".to_string()))
250 }
251
252 fn get_parent_id(&self, tag_stack: &Vec<TagInfo>) -> Option<usize> {
253 let before_last_index = tag_stack.len().checked_sub(2);
254 if before_last_index.is_none() {
255 return None;
256 }
257 let before_last_index = before_last_index.unwrap();
258 if let Some(before_last) = tag_stack.get(before_last_index) {
259 Some(before_last.id)
260 } else {
261 None
262 }
263 }
264}