2021-08-05 22:07:27 -04:00
|
|
|
use std::collections::HashMap;
|
2021-08-06 06:16:30 -04:00
|
|
|
use std::fmt::{Debug, Formatter};
|
|
|
|
use std::str::from_utf8;
|
|
|
|
|
|
|
|
use crate::spec::tag::ns::Namespace;
|
2021-08-05 22:07:27 -04:00
|
|
|
|
2021-08-06 06:16:30 -04:00
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
2021-08-06 02:17:45 -04:00
|
|
|
pub enum ElementClosingTag {
|
|
|
|
Omitted,
|
|
|
|
Present,
|
|
|
|
SelfClosing,
|
|
|
|
Void,
|
|
|
|
}
|
|
|
|
|
2021-08-06 06:16:30 -04:00
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
2021-08-06 02:17:45 -04:00
|
|
|
pub enum ScriptOrStyleLang {
|
|
|
|
CSS,
|
|
|
|
Data,
|
|
|
|
JS,
|
|
|
|
}
|
|
|
|
|
2021-08-06 06:16:30 -04:00
|
|
|
// Derive Eq for testing.
|
|
|
|
#[derive(Eq, PartialEq)]
|
2021-08-05 22:07:27 -04:00
|
|
|
pub enum NodeData {
|
2021-08-06 02:17:45 -04:00
|
|
|
Bang {
|
2021-08-05 22:07:27 -04:00
|
|
|
code: Vec<u8>,
|
2021-08-06 02:17:45 -04:00
|
|
|
// If the source unexpectedly ended before `>`, we can't add it, as otherwise output could be longer than source.
|
|
|
|
ended: bool,
|
2021-08-05 22:07:27 -04:00
|
|
|
},
|
2021-08-06 02:17:45 -04:00
|
|
|
Comment {
|
2021-08-05 22:07:27 -04:00
|
|
|
code: Vec<u8>,
|
2021-08-06 02:17:45 -04:00
|
|
|
// If the source unexpectedly ended before `-->`, we can't add it, as otherwise output could be longer than source.
|
|
|
|
ended: bool,
|
2021-08-05 22:07:27 -04:00
|
|
|
},
|
|
|
|
Element {
|
|
|
|
attributes: HashMap<Vec<u8>, Vec<u8>>,
|
|
|
|
children: Vec<NodeData>,
|
2021-08-06 02:17:45 -04:00
|
|
|
// If the source doesn't have a closing tag, then we can't add one, as otherwise output could be longer than source.
|
|
|
|
closing_tag: ElementClosingTag,
|
|
|
|
name: Vec<u8>,
|
2021-08-06 03:33:56 -04:00
|
|
|
namespace: Namespace,
|
2021-08-06 09:07:55 -04:00
|
|
|
// WARNING: This should only be set during minification, as minification can alter tree (e.g. remove text nodes completely).
|
2021-08-06 08:53:33 -04:00
|
|
|
// If the next text or element sibling is an element, this will be set to its tag name.
|
|
|
|
// Otherwise, this will be empty. It should be empty on creation.
|
|
|
|
next_sibling_element_name: Vec<u8>,
|
2021-08-05 22:07:27 -04:00
|
|
|
},
|
|
|
|
Instruction {
|
|
|
|
code: Vec<u8>,
|
2021-08-06 02:17:45 -04:00
|
|
|
// If the source unexpectedly ended before `?>`, we can't add it, as otherwise output could be longer than source.
|
|
|
|
ended: bool,
|
2021-08-05 22:07:27 -04:00
|
|
|
},
|
|
|
|
// Entities should not be decoded in ScriptOrStyleContent.
|
|
|
|
ScriptOrStyleContent {
|
|
|
|
code: Vec<u8>,
|
2021-08-06 02:17:45 -04:00
|
|
|
lang: ScriptOrStyleLang,
|
2021-08-05 22:07:27 -04:00
|
|
|
},
|
|
|
|
Text {
|
2021-08-06 02:17:45 -04:00
|
|
|
value: Vec<u8>,
|
2021-08-05 22:07:27 -04:00
|
|
|
},
|
|
|
|
}
|
2021-08-06 06:16:30 -04:00
|
|
|
|
|
|
|
fn str(bytes: &[u8]) -> &str {
|
|
|
|
from_utf8(bytes).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for NodeData {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
NodeData::Bang { code, ended } => f
|
|
|
|
.debug_struct("Bang")
|
|
|
|
.field("code", &from_utf8(code).unwrap().to_string())
|
|
|
|
.field("ended", ended)
|
|
|
|
.finish(),
|
|
|
|
NodeData::Comment { code, ended } => f
|
|
|
|
.debug_struct("Comment")
|
|
|
|
.field("code", &from_utf8(code).unwrap().to_string())
|
|
|
|
.field("ended", ended)
|
|
|
|
.finish(),
|
|
|
|
NodeData::Element {
|
|
|
|
attributes,
|
|
|
|
children,
|
|
|
|
closing_tag,
|
|
|
|
name,
|
|
|
|
namespace,
|
2021-08-06 08:53:33 -04:00
|
|
|
next_sibling_element_name,
|
2021-08-06 06:16:30 -04:00
|
|
|
} => f
|
|
|
|
.debug_struct("Element")
|
|
|
|
.field("tag", &{
|
|
|
|
let mut out = format!("{:?}:{}", namespace, str(name));
|
|
|
|
for (n, v) in attributes {
|
|
|
|
out.push_str(format!(" {}={}", str(n), str(v)).as_str());
|
|
|
|
}
|
|
|
|
out
|
|
|
|
})
|
|
|
|
.field("children", children)
|
|
|
|
.field("closing_tag", closing_tag)
|
2021-08-06 08:53:33 -04:00
|
|
|
.field(
|
|
|
|
"next_sibling_element_name",
|
|
|
|
&from_utf8(next_sibling_element_name).unwrap().to_string(),
|
|
|
|
)
|
2021-08-06 06:16:30 -04:00
|
|
|
.finish(),
|
|
|
|
NodeData::Instruction { code, ended } => f
|
|
|
|
.debug_struct("Instruction")
|
|
|
|
.field("code", &from_utf8(code).unwrap().to_string())
|
|
|
|
.field("ended", ended)
|
|
|
|
.finish(),
|
|
|
|
NodeData::ScriptOrStyleContent { code, lang } => f
|
|
|
|
.debug_struct("ScriptOrStyleContent")
|
|
|
|
.field("code", &from_utf8(code).unwrap().to_string())
|
|
|
|
.field("lang", lang)
|
|
|
|
.finish(),
|
|
|
|
NodeData::Text { value } => f.write_str(str(value)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|