diff options
| -rw-r--r-- | src/analyze.rs | 16 | ||||
| -rw-r--r-- | src/compile.rs | 17 | ||||
| -rw-r--r-- | src/diagnostics.rs | 48 | ||||
| -rw-r--r-- | src/diagnostics/forbidden_top_level_tag.rs | 6 | ||||
| -rw-r--r-- | src/diagnostics/non_self_closing_void_tag.rs | 3 | ||||
| -rw-r--r-- | src/diagnostics/non_void_self_closing_tag.rs | 3 | ||||
| -rw-r--r-- | src/lib.rs | 6 |
7 files changed, 72 insertions, 27 deletions
diff --git a/src/analyze.rs b/src/analyze.rs index b8a7012..6526c2b 100644 --- a/src/analyze.rs +++ b/src/analyze.rs @@ -58,6 +58,10 @@ pub struct HeadSymbol<'a> { #[derive(Debug)] pub enum ConstantType<'a> { String, + Fragment { + direct_children_tags: Option<&'a [&'a str]>, + transitive_children_tags: Option<&'a [&'a str]>, + }, Block { direct_children_tags: Option<&'a [&'a str]>, transitive_children_tags: Option<&'a [&'a str]>, @@ -65,14 +69,14 @@ pub enum ConstantType<'a> { } #[derive(Debug)] -pub enum ConstantValue<'a> { +pub enum ConstantLiteral<'a> { String(&'a str), } #[derive(Debug)] pub enum ConstantExpression<'a> { Name(&'a str), - Value(ConstantValue<'a>), + Value(ConstantLiteral<'a>), Fragment(&'a [ConstantSymbolId]), Block { tag_name_lowercase: &'a str, @@ -104,7 +108,7 @@ fn element_attributes<'a>( id, name: None, ty: Some(ConstantType::String), - value: Some(ConstantExpression::Value(ConstantValue::String(value))), + value: Some(ConstantExpression::Value(ConstantLiteral::String(value))), definition_site: None, }, ); @@ -146,7 +150,7 @@ fn node_to_constant<'a>( id, name: None, ty: Some(ConstantType::String), - value: Some(ConstantExpression::Value(ConstantValue::String(value))), + value: Some(ConstantExpression::Value(ConstantLiteral::String(value))), definition_site: None, }, ); @@ -164,7 +168,7 @@ fn node_to_constant<'a>( ConstantSymbol { id, name: None, - // TODO fragment type + // TODO acquire the type ty: None, value: Some(fragment), definition_site: None, @@ -259,7 +263,7 @@ fn add_constant<'a>(symbol_table: &mut ScopedSymbolTable<'a>, element: &'a Eleme id, name, ty: Some(ConstantType::String), - value: value.map(|value| ConstantExpression::Value(ConstantValue::String(value))), + value: value.map(|value| ConstantExpression::Value(ConstantLiteral::String(value))), definition_site: Some(*element), }, ); diff --git a/src/compile.rs b/src/compile.rs index 9e19b18..a0877cd 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,6 +1,9 @@ use html_escape::{encode_double_quoted_attribute, encode_single_quoted_attribute}; -use crate::analyze::{ConstantExpression, ConstantSymbolId, ConstantValue, ScopedSymbolTable}; +use crate::{ + VOID_TAGS, + analyze::{ConstantExpression, ConstantLiteral, ConstantSymbolId, ScopedSymbolTable}, +}; fn symbol_table_from_path<'a>( symbol_table: &'a ScopedSymbolTable<'a>, @@ -62,7 +65,7 @@ fn compile_constant<'a>( }; match expression { ConstantExpression::Value(value) => match value { - ConstantValue::String(value) => buffer.push_str(value), + ConstantLiteral::String(value) => buffer.push_str(value), }, ConstantExpression::Name(name) => { let mut name = *name; @@ -97,10 +100,12 @@ fn compile_constant<'a>( compile_attribute_value(buffer, symbol_table, name, *value); } buffer.push('>'); - compile_constant(buffer, symbol_table, *child); - buffer.push_str("</"); - buffer.push_str(tag_name_lowercase); - buffer.push('>'); + if !VOID_TAGS.contains(tag_name_lowercase) { + compile_constant(buffer, symbol_table, *child); + buffer.push_str("</"); + buffer.push_str(tag_name_lowercase); + buffer.push('>'); + } } } } diff --git a/src/diagnostics.rs b/src/diagnostics.rs index d2db96b..295de94 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -6,6 +6,8 @@ use crate::{ tokenize::{AttributeToken, Token, TokenType}, }; +mod deprecated_attributes; +mod deprecated_tag; mod duplicate_attribute_names; mod empty_tag_name; mod end_tag_with_attributes; @@ -25,12 +27,6 @@ mod unclosed_start_tag; mod unterminated_comment; mod unterminated_tag; -const VOID_TAGS: &[&str] = &[ - "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", - "track", "wbr", "import", -]; -const ALLOWED_TOP_LEVEL_TAGS: &[&str] = &["import", "const", "block", "head", "body"]; - pub struct DiagnosticsContext { source_code: &'static str, } @@ -194,6 +190,8 @@ pub fn run_token_diagnostics(ctx: &DiagnosticsContext, tokens: &[Token<'_>]) -> ctx, tokens, ) .is_none(); + // TODO allow the AST diagnostics to still run if this fails + has_failed |= run_token_diagnostic::<deprecated_tag::DeprectatedTag>(ctx, tokens).is_none(); // TODO invalid character reference (!has_failed).then_some(()) } @@ -221,8 +219,29 @@ pub fn run_ast_diagnostics(ctx: &DiagnosticsContext, document: &Document<'_>) -> // TODO invalid <import /> // TODO invalid <const /> // TODO invalid <block /> - // TODO deprecated tag + // TODO invalid <kuht-http /> // TODO deprecated tag attribute + // TODO warning-only obsolete features + // TODO invalid name on anchor + // TODO invalid language on script + // TODO invalid type on style + // TODO base without href or target + // TODO multiple base elements + // TODO base target with a newline, tab, or < + // TODO invalid cite on <blockquote> or <q> + // TODO non html1 tag or attribute + // TODO empty, missing, or invalid image src + // TODO invalid form enctype + // TODO invalid form action + // TODO invalid form method + // TODO input without name + // TODO invalid input attributes for type + // TODO invalid select size + // TODO invalid select mutliple attribute + // TODO select without name + // TODO invalid option selected attribute + // TODO invalid cols and rows attributes for textarea + // TODO textarea without name // // TODO forbidden tag in noscript // TODO head tag outside head @@ -244,6 +263,20 @@ pub fn run_ast_diagnostics(ctx: &DiagnosticsContext, document: &Document<'_>) -> // TODO select inside select // TODO input, keygen, textarea inside select // TODO caption, table, tbody, tfoot, thread, tr, td, th inside select + // TODO more than one body + // TODO invalid head child + // TODO missing title + // TODO title outside head + // TODO warning for title longer than 64 characters + // TODO warning for more than one <h1> + // TODO invalid heading hierarchy + // TODO invalid <p>, <pre>, <address>, <cite> or <h_> content + // TODO wrap on <pre> + // TODO address inside address + // TODO heading inside addres + // TODO <header> or <footer> inside <address> + // TODO section content (<article>, <aside>, <section>, <nav>) inside address + // TODO image map outside <a> // // TODO anchor with invalid href // TODO dt or dd outside dl @@ -251,7 +284,6 @@ pub fn run_ast_diagnostics(ctx: &DiagnosticsContext, document: &Document<'_>) -> // TODO invalid dl, ul, menu // TODO invalid attribute values (see microsyntaxes) // TODO aria tags don't match tag semantics - // TODO empty or missing image src // TODO missing alt text for image (unless inside figure with caption, or has title, or meta name = "generator") (!has_failed).then_some(()) } diff --git a/src/diagnostics/forbidden_top_level_tag.rs b/src/diagnostics/forbidden_top_level_tag.rs index 8b5301e..c834e8a 100644 --- a/src/diagnostics/forbidden_top_level_tag.rs +++ b/src/diagnostics/forbidden_top_level_tag.rs @@ -1,11 +1,7 @@ use miette::Diagnostic; use thiserror::Error; -use crate::{ - diagnostics::{ALLOWED_TOP_LEVEL_TAGS, AstDiagnostic}, - parse::Node, - tokenize::Span, -}; +use crate::{ALLOWED_TOP_LEVEL_TAGS, diagnostics::AstDiagnostic, parse::Node, tokenize::Span}; #[derive(Error, Debug, Diagnostic)] #[error("Forbidden top-level tag is present")] diff --git a/src/diagnostics/non_self_closing_void_tag.rs b/src/diagnostics/non_self_closing_void_tag.rs index bfff266..1c987c3 100644 --- a/src/diagnostics/non_self_closing_void_tag.rs +++ b/src/diagnostics/non_self_closing_void_tag.rs @@ -2,7 +2,8 @@ use miette::Diagnostic; use thiserror::Error; use crate::{ - diagnostics::{TokenDiagnostic, VOID_TAGS}, + VOID_TAGS, + diagnostics::TokenDiagnostic, tokenize::{Span, Token, TokenType}, }; diff --git a/src/diagnostics/non_void_self_closing_tag.rs b/src/diagnostics/non_void_self_closing_tag.rs index 8a64be1..2667fa1 100644 --- a/src/diagnostics/non_void_self_closing_tag.rs +++ b/src/diagnostics/non_void_self_closing_tag.rs @@ -2,7 +2,8 @@ use miette::Diagnostic; use thiserror::Error; use crate::{ - diagnostics::{TokenDiagnostic, VOID_TAGS}, + VOID_TAGS, + diagnostics::TokenDiagnostic, tokenize::{Span, Token, TokenType}, }; @@ -3,3 +3,9 @@ pub mod compile; pub mod diagnostics; pub mod parse; pub mod tokenize; + +pub const VOID_TAGS: &[&str] = &[ + "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", + "track", "wbr", "import", +]; +pub const ALLOWED_TOP_LEVEL_TAGS: &[&str] = &["import", "const", "block", "head", "body"]; |
