1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
use yarte_hir::{Each as HEach, IfElse as HIfElse, HIR};

use crate::{
    serialize::serialize,
    sink::{parse_document, parse_fragment, ParseResult, Sink, HEAD, TAIL},
};

pub struct DOMFmt(pub Vec<HIR>);

// TODO: to try from
impl From<Vec<HIR>> for DOMFmt {
    fn from(ir: Vec<HIR>) -> Self {
        DOMFmt(to_domfmt(ir).expect("correct html"))
    }
}

const HASH: &str = "0x00000000";

fn to_domfmt(ir: Vec<HIR>) -> ParseResult<Vec<HIR>> {
    let mut html = String::new();
    for x in &ir {
        match x {
            HIR::Lit(x) => html.push_str(x),
            _ => {
                html.push_str(HEAD);
                html.push_str(HASH);
                html.push_str(TAIL);
            }
        }
    }

    let sink = match parse_document(&html) {
        Ok(a) => a,
        Err(_) => parse_fragment(&html)?,
    };

    serialize_domfmt(sink, ir)
}

fn serialize_domfmt(sink: Sink, mut ir: Vec<HIR>) -> ParseResult<Vec<HIR>> {
    let mut writer = Vec::new();
    serialize(&mut writer, &sink.into()).expect("some serialize node");

    let html = String::from_utf8(writer).expect("");
    let mut chunks = html.split(HEAD).peekable();

    if let Some(first) = chunks.peek() {
        if first.is_empty() {
            chunks.next();
        }
    }

    let mut buff = vec![];
    for chunk in chunks {
        if chunk.is_empty() {
            panic!("chunk empty")
        } else if chunk.starts_with(HASH) {
            resolve_node(ir.remove(0), &mut buff)?;
            let cut = &chunk[HASH.len() + TAIL.len()..];
            if !cut.is_empty() {
                buff.push(HIR::Lit(cut.into()));
                ir.remove(0);
            }
        } else {
            buff.push(HIR::Lit(chunk.into()));
            ir.remove(0);
        }
    }

    // Standard or empty case (with only comments,...)
    assert!(ir.is_empty() || (ir.len() == 1 && ir[0] == HIR::Lit("".into())));

    Ok(buff)
}

fn resolve_node(ir: HIR, buff: &mut Vec<HIR>) -> ParseResult<()> {
    match ir {
        HIR::Each(each) => {
            let HEach { args, body, expr } = *each;
            buff.push(HIR::Each(Box::new(HEach {
                args,
                expr,
                body: to_domfmt(body)?,
            })))
        }
        HIR::IfElse(if_else) => {
            let HIfElse { ifs, if_else, els } = *if_else;
            let mut buf_if_else = vec![];
            for (expr, body) in if_else {
                buf_if_else.push((expr, to_domfmt(body)?));
            }
            let els = if let Some(els) = els {
                Some(to_domfmt(els)?)
            } else {
                None
            };
            buff.push(HIR::IfElse(Box::new(HIfElse {
                ifs: (ifs.0, to_domfmt(ifs.1)?),
                if_else: buf_if_else,
                els,
            })));
        }
        HIR::Lit(_) => panic!("Need some node"),
        ir => buff.push(ir),
    }
    Ok(())
}