nargo_parser/
oak_template_parser.rs1use crate::{ParseState, TemplateParser};
2use nargo_ir::{AttributeIR, ElementIR, TemplateNodeIR, Trivia};
3use nargo_types::{Position, Result, Span};
4use oak_core::{parser::ParseSession, tree::RedTree, Parser, SourceText};
5use oak_vue::{VueElementType, VueLanguage, VueParser};
6
7pub struct OakVueTemplateParser;
9
10impl TemplateParser for OakVueTemplateParser {
11 fn parse(&self, state: &mut ParseState, _lang: &str) -> Result<Vec<TemplateNodeIR>> {
12 let source = SourceText::new(state.cursor.source.to_string());
13 let language = VueLanguage::default();
14 let parser = VueParser::new(&language);
15 let mut session = ParseSession::default();
16 let parse_output = parser.parse(&source, &[], &mut session);
17
18 let green_node = parse_output.result.map_err(|e| nargo_types::Error::parse_error(format!("Vue parsing error: {:?}", e), Span::default()))?;
20 let red_tree = RedTree::new(green_node);
21
22 let nodes = self.convert_to_ir(&red_tree, &source);
24 Ok(nodes)
25 }
26}
27
28impl OakVueTemplateParser {
29 fn convert_to_ir(&self, tree: &RedTree<'_, VueLanguage>, source: &SourceText) -> Vec<TemplateNodeIR> {
31 let mut nodes = Vec::new();
32 self.convert_node(tree, source, &mut nodes);
33 nodes
34 }
35
36 fn convert_node(&self, tree: &RedTree<'_, VueLanguage>, source: &SourceText, result: &mut Vec<TemplateNodeIR>) {
38 match tree {
39 RedTree::Node(node) => {
40 match node.element_type() {
41 VueElementType::Root => {
42 for child in node.children() {
43 self.convert_node(&child, source, result);
44 }
45 }
46 VueElementType::Element => {
47 let mut tag = String::new();
48 let mut attributes = Vec::new();
49 let mut children = Vec::new();
50 let mut trivia = Trivia::default();
51
52 for child in node.children() {
53 match &child {
54 RedTree::Node(child_node) => {
55 match child_node.element_type() {
56 VueElementType::Tag => {
57 tag = self.get_node_text(child_node, source);
59 }
60 VueElementType::Attribute | VueElementType::Directive => {
61 let attribute = self.convert_attribute(&child, source);
62 attributes.push(attribute);
63 }
64 VueElementType::Element => {
65 let mut child_nodes = Vec::new();
66 self.convert_node(&child, source, &mut child_nodes);
67 children.extend(child_nodes);
68 }
69 _ => {}
70 }
71 }
72 RedTree::Leaf(leaf) => {
73 let text = leaf.text(source).to_string();
75 if !text.trim().is_empty() {
76 let span = Span { start: Position::new(1, 1, leaf.span().start as u32), end: Position::new(1, 1, leaf.span().end as u32) };
77 let text_node = TemplateNodeIR::Text(text, span, Trivia::default());
78 result.push(text_node);
79 }
80 }
81 }
82 }
83
84 let span = Span { start: Position::new(1, 1, node.span().start as u32), end: Position::new(1, 1, node.span().end as u32) };
85 let element = TemplateNodeIR::Element(ElementIR { tag, attributes, children, is_static: false, span, trivia });
86 result.push(element);
87 }
88 _ => {}
89 }
90 }
91 RedTree::Leaf(_) => {
92 }
94 }
95 }
96
97 fn convert_attribute(&self, tree: &RedTree<'_, VueLanguage>, source: &SourceText) -> AttributeIR {
99 let mut name = String::new();
100 let mut value = None;
101 let mut is_directive = false;
102 let mut is_dynamic = false;
103 let mut trivia = Trivia::default();
104
105 if let RedTree::Node(node) = tree {
106 for child in node.children() {
107 if let RedTree::Node(child_node) = &child {
108 match child_node.element_type() {
109 VueElementType::AttributeName => {
110 name = self.get_node_text(child_node, source);
111 }
112 VueElementType::AttributeValue => {
113 let text = self.get_node_text(child_node, source);
114 value = Some(text);
115 }
116 VueElementType::Directive => {
117 is_directive = true;
118 }
119 _ => {}
120 }
121 }
122 }
123 }
124
125 let span = if let RedTree::Node(node) = tree { Span { start: Position::new(1, 1, node.span().start as u32), end: Position::new(1, 1, node.span().end as u32) } } else { Span { start: Position::new(1, 1, 0), end: Position::new(1, 1, 0) } };
126
127 AttributeIR { name, value, value_ast: None, argument: None, modifiers: Vec::new(), is_directive, is_dynamic, span, trivia }
128 }
129
130 fn get_node_text(&self, node: &oak_core::tree::RedNode<'_, VueLanguage>, source: &SourceText) -> String {
132 node.text(source).to_string()
133 }
134}