use crate::{ParseState, TemplateParser};
use nargo_ir::{AttributeIR, ElementIR, TemplateNodeIR, Trivia};
use nargo_types::{Position, Result, Span};
use oak_core::{parser::ParseSession, tree::RedTree, Parser, SourceText};
use oak_vue::{VueElementType, VueLanguage, VueParser};
pub struct OakVueTemplateParser;
impl TemplateParser for OakVueTemplateParser {
fn parse(&self, state: &mut ParseState, _lang: &str) -> Result<Vec<TemplateNodeIR>> {
let source = SourceText::new(state.cursor.source.to_string());
let language = VueLanguage::default();
let parser = VueParser::new(&language);
let mut session = ParseSession::default();
let parse_output = parser.parse(&source, &[], &mut session);
let green_node = parse_output.result.map_err(|e| nargo_types::Error::parse_error(format!("Vue parsing error: {:?}", e), Span::default()))?;
let red_tree = RedTree::new(green_node);
let nodes = self.convert_to_ir(&red_tree, &source);
Ok(nodes)
}
}
impl OakVueTemplateParser {
fn convert_to_ir(&self, tree: &RedTree<'_, VueLanguage>, source: &SourceText) -> Vec<TemplateNodeIR> {
let mut nodes = Vec::new();
self.convert_node(tree, source, &mut nodes);
nodes
}
fn convert_node(&self, tree: &RedTree<'_, VueLanguage>, source: &SourceText, result: &mut Vec<TemplateNodeIR>) {
match tree {
RedTree::Node(node) => {
match node.element_type() {
VueElementType::Root => {
for child in node.children() {
self.convert_node(&child, source, result);
}
}
VueElementType::Element => {
let mut tag = String::new();
let mut attributes = Vec::new();
let mut children = Vec::new();
let mut trivia = Trivia::default();
for child in node.children() {
match &child {
RedTree::Node(child_node) => {
match child_node.element_type() {
VueElementType::Tag => {
tag = self.get_node_text(child_node, source);
}
VueElementType::Attribute | VueElementType::Directive => {
let attribute = self.convert_attribute(&child, source);
attributes.push(attribute);
}
VueElementType::Element => {
let mut child_nodes = Vec::new();
self.convert_node(&child, source, &mut child_nodes);
children.extend(child_nodes);
}
_ => {}
}
}
RedTree::Leaf(leaf) => {
let text = leaf.text(source).to_string();
if !text.trim().is_empty() {
let span = Span { start: Position::new(1, 1, leaf.span().start as u32), end: Position::new(1, 1, leaf.span().end as u32) };
let text_node = TemplateNodeIR::Text(text, span, Trivia::default());
result.push(text_node);
}
}
}
}
let span = Span { start: Position::new(1, 1, node.span().start as u32), end: Position::new(1, 1, node.span().end as u32) };
let element = TemplateNodeIR::Element(ElementIR { tag, attributes, children, is_static: false, span, trivia });
result.push(element);
}
_ => {}
}
}
RedTree::Leaf(_) => {
}
}
}
fn convert_attribute(&self, tree: &RedTree<'_, VueLanguage>, source: &SourceText) -> AttributeIR {
let mut name = String::new();
let mut value = None;
let mut is_directive = false;
let mut is_dynamic = false;
let mut trivia = Trivia::default();
if let RedTree::Node(node) = tree {
for child in node.children() {
if let RedTree::Node(child_node) = &child {
match child_node.element_type() {
VueElementType::AttributeName => {
name = self.get_node_text(child_node, source);
}
VueElementType::AttributeValue => {
let text = self.get_node_text(child_node, source);
value = Some(text);
}
VueElementType::Directive => {
is_directive = true;
}
_ => {}
}
}
}
}
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) } };
AttributeIR { name, value, value_ast: None, argument: None, modifiers: Vec::new(), is_directive, is_dynamic, span, trivia }
}
fn get_node_text(&self, node: &oak_core::tree::RedNode<'_, VueLanguage>, source: &SourceText) -> String {
node.text(source).to_string()
}
}