1use crate::{
2 XmlElementType, XmlLanguage,
3 ast::{XmlAttribute, XmlElement, XmlRoot, XmlValue},
4 lexer::token_type::XmlTokenType,
5};
6use core::range::Range;
7use oak_core::{
8 Builder, BuilderCache, GreenNode, GreenTree, OakDiagnostics, OakError, Parser, Source,
9 builder::BuildOutput,
10 source::{SourceText, TextEdit},
11};
12
13pub struct XmlBuilder;
15
16impl XmlBuilder {
17 pub fn new() -> Self {
19 Self
20 }
21
22 fn build_root<'a>(&self, green_tree: &GreenNode<'a, XmlLanguage>, source: &SourceText) -> Result<XmlRoot, OakError> {
23 let mut children = Vec::new();
24 let mut current_offset = 0;
25
26 for child in green_tree.children {
27 match child {
28 GreenTree::Node(node) => {
29 match node.kind {
30 XmlElementType::Prolog => {
31 }
33 XmlElementType::Element => {
34 children.push(self.build_element(node, current_offset, source)?);
35 }
36 _ => {}
37 }
38 current_offset += node.byte_length as usize;
39 }
40 GreenTree::Leaf(leaf) => {
41 current_offset += leaf.length as usize;
42 }
43 }
44 }
45
46 let value = if children.len() == 1 { XmlValue::Element(children.remove(0)) } else { children.into_iter().next().map(XmlValue::Element).unwrap_or(XmlValue::Text(String::new())) };
47
48 Ok(XmlRoot { value })
49 }
50
51 fn build_element<'a>(&self, node: &GreenNode<'a, XmlLanguage>, offset: usize, source: &SourceText) -> Result<XmlElement, OakError> {
52 let mut name = String::new();
53 let mut attributes = Vec::new();
54 let mut children = Vec::new();
55 let mut current_offset = offset;
56
57 for child in node.children {
58 match child {
59 GreenTree::Node(n) => {
60 match n.kind {
61 XmlElementType::StartTag | XmlElementType::SelfClosingTag => {
62 let mut sub_offset = current_offset;
63 for sub_child in n.children {
64 match sub_child {
65 GreenTree::Leaf(t) if t.kind == XmlTokenType::Identifier => {
66 name = source.get_text_in(Range { start: sub_offset, end: sub_offset + t.length as usize }).to_string();
67 }
68 GreenTree::Node(attr_node) if attr_node.kind == XmlElementType::Attribute => {
69 attributes.push(self.build_attribute(attr_node, sub_offset, source)?);
70 }
71 _ => {}
72 }
73 sub_offset += sub_child.len() as usize;
74 }
75 }
76 XmlElementType::Element => {
77 children.push(XmlValue::Element(self.build_element(n, current_offset, source)?));
78 }
79 _ => {}
80 }
81 current_offset += n.byte_length as usize;
82 }
83 GreenTree::Leaf(t) => {
84 match t.kind {
85 XmlTokenType::Text => {
86 let text = source.get_text_in(Range { start: current_offset, end: current_offset + t.length as usize });
87 if !text.trim().is_empty() {
88 children.push(XmlValue::Text(text.to_string()));
89 }
90 }
91 _ => {}
92 }
93 current_offset += t.length as usize;
94 }
95 }
96 }
97
98 Ok(XmlElement { name, attributes, children, span: Range { start: offset, end: offset + node.byte_length as usize } })
99 }
100
101 fn build_attribute<'a>(&self, node: &GreenNode<'a, XmlLanguage>, offset: usize, source: &SourceText) -> Result<XmlAttribute, OakError> {
102 let mut name = String::new();
103 let mut value = String::new();
104 let mut current_offset = offset;
105
106 for child in node.children {
107 match child {
108 GreenTree::Leaf(t) => {
109 match t.kind {
110 XmlTokenType::Identifier => {
111 name = source.get_text_in(Range { start: current_offset, end: current_offset + t.length as usize }).to_string();
112 }
113 XmlTokenType::StringLiteral => {
114 let raw = source.get_text_in(Range { start: current_offset, end: current_offset + t.length as usize });
115 if raw.len() >= 2 {
117 value = raw[1..raw.len() - 1].to_string();
118 }
119 else {
120 value = raw.to_string();
121 }
122 }
123 _ => {}
124 }
125 current_offset += t.length as usize;
126 }
127 GreenTree::Node(n) => {
128 current_offset += n.byte_length as usize;
129 }
130 }
131 }
132
133 Ok(XmlAttribute { name, value, span: Range { start: offset, end: offset + node.byte_length as usize } })
134 }
135}
136
137impl Builder<XmlLanguage> for XmlBuilder {
138 fn build<'a, S: Source + ?Sized>(&self, text: &S, edits: &[TextEdit], cache: &'a mut impl BuilderCache<XmlLanguage>) -> BuildOutput<XmlLanguage> {
139 let source = SourceText::new(text.get_text_in(Range { start: 0, end: text.length() }).to_string());
140 let config = XmlLanguage::default();
141 let parser = crate::parser::XmlParser::new(&config);
142 let parse_output = parser.parse(text, edits, cache);
143
144 let mut diagnostics = Vec::new();
145 for error in parse_output.diagnostics {
146 diagnostics.push(error);
147 }
148
149 let result = parse_output.result.and_then(|green_tree| self.build_root(green_tree, &source));
150
151 OakDiagnostics { result, diagnostics }
152 }
153}