summaryrefslogtreecommitdiff
path: root/src/diagnostics/top_level_character_data.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/diagnostics/top_level_character_data.rs')
-rw-r--r--src/diagnostics/top_level_character_data.rs41
1 files changed, 41 insertions, 0 deletions
diff --git a/src/diagnostics/top_level_character_data.rs b/src/diagnostics/top_level_character_data.rs
new file mode 100644
index 0000000..5deb595
--- /dev/null
+++ b/src/diagnostics/top_level_character_data.rs
@@ -0,0 +1,41 @@
+use miette::Diagnostic;
+use thiserror::Error;
+
+use crate::{
+ diagnostics::AstDiagnostic,
+ parse::Node,
+ tokenize::{Span, TokenType},
+};
+
+#[derive(Error, Debug, Diagnostic)]
+#[error("Top-level character data is present")]
+#[diagnostic(code(TopLevelCharacterData), severity(Error))]
+pub struct TopLevelCharacterData {
+ #[label(collection)]
+ nodes: Vec<Span>,
+}
+
+impl AstDiagnostic for TopLevelCharacterData {
+ fn handle_document(document: &crate::parse::Document<'_>) -> Option<Self> {
+ let cdata_nodes = document
+ .children
+ .iter()
+ .filter_map(|node| {
+ if let Node::CharacterData(token) = node
+ && let TokenType::Data(data) = token.ty
+ && data.chars().any(|c| !c.is_whitespace())
+ {
+ Some(token.span)
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>();
+
+ if cdata_nodes.is_empty() {
+ return None;
+ }
+
+ Some(Self { nodes: cdata_nodes })
+ }
+}