Filtering at-rules by name

This commit is contained in:
Tyler Hallada 2020-03-21 23:12:01 -04:00
parent de742425d0
commit 359be3a3e3
4 changed files with 137 additions and 37 deletions

View File

@ -651,5 +651,52 @@ fn main() {
"z-index", "z-index",
]) ])
.write_to_file(&Path::new(&env::var("OUT_DIR").unwrap()).join("css_property.rs")) .write_to_file(&Path::new(&env::var("OUT_DIR").unwrap()).join("css_property.rs"))
.unwrap();
string_cache_codegen::AtomType::new("css_at_rule::CssAtRule", "css_at_rule!")
.atoms(vec![
"top-left-corner",
"top-left",
"top-center",
"top-right",
"top-right-corner",
"bottom-left-corner",
"bottom-left",
"bottom-center",
"bottom-right",
"bottom-right-corner",
"left-top",
"left-middle",
"left-bottom",
"right-top",
"right-middle",
"right-bottom",
"-moz-keyframes",
"-o-keyframes",
"-webkit-keyframes",
"apply",
"annotation",
"character-variant",
"charset",
"counter-style",
"custom-media",
"custom-selector",
"document",
"font-face",
"font-feature-values",
"import",
"keyframes",
"media",
"namespace",
"nest",
"ornaments",
"page",
"styleset",
"stylistic",
"supports",
"swash",
"viewport",
])
.write_to_file(&Path::new(&env::var("OUT_DIR").unwrap()).join("css_at_rule.rs"))
.unwrap() .unwrap()
} }

View File

@ -10,6 +10,7 @@ use super::basic::{
}; };
use crate::css_property::CssProperty; use crate::css_property::CssProperty;
use crate::css_at_rule::CssAtRule;
lazy_static! { lazy_static! {
pub static ref ELEMENTS: HashSet<LocalName> = BASIC_ELEMENTS pub static ref ELEMENTS: HashSet<LocalName> = BASIC_ELEMENTS
@ -845,4 +846,31 @@ lazy_static! {
css_property!("writing-mode"), css_property!("writing-mode"),
css_property!("z-index"), css_property!("z-index"),
].into_iter().collect(); ].into_iter().collect();
pub static ref CSS_AT_RULES: HashSet<CssAtRule> = vec![
css_at_rule!("bottom-center"),
css_at_rule!("bottom-left"),
css_at_rule!("bottom-left-corner"),
css_at_rule!("bottom-right"),
css_at_rule!("bottom-right-corner"),
css_at_rule!("font-face"),
css_at_rule!("left-bottom"),
css_at_rule!("left-middle"),
css_at_rule!("left-top"),
css_at_rule!("page"),
css_at_rule!("right-bottom"),
css_at_rule!("right-middle"),
css_at_rule!("right-top"),
css_at_rule!("top-center"),
css_at_rule!("top-left"),
css_at_rule!("top-left-corner"),
css_at_rule!("top-right"),
css_at_rule!("top-right-corner"),
css_at_rule!("-moz-keyframes"),
css_at_rule!("-o-keyframes"),
css_at_rule!("-webkit-keyframes"),
css_at_rule!("document"),
css_at_rule!("keyframes"),
css_at_rule!("media"),
css_at_rule!("supports"),
].into_iter().collect();
} }

View File

@ -25,7 +25,7 @@ pub struct CssAtRule {
// TODO: put name into the string cache // TODO: put name into the string cache
pub name: String, pub name: String,
pub prelude: String, pub prelude: String,
pub block: Option<String>, pub block: Option<Vec<CssRule>>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -81,12 +81,24 @@ impl<'i> AtRuleParser<'i> for CssParser {
_location: SourceLocation, _location: SourceLocation,
input: &mut Parser<'i, 't> input: &mut Parser<'i, 't>
) -> Result<Self::AtRule, CssParseError<'i>> { ) -> Result<Self::AtRule, CssParseError<'i>> {
let position = input.position(); let rule_list_parser = RuleListParser::new_for_stylesheet(input, CssParser);
while input.next().is_ok() {} let mut rules = Vec::new();
for result in rule_list_parser {
let rule = match result {
Ok(r) => r,
Err((error, string)) => {
eprintln!("Rule dropped: {:?}, {:?}", error, string);
continue;
}
};
rules.push(rule);
}
Ok(CssRule::AtRule(CssAtRule { Ok(CssRule::AtRule(CssAtRule {
name: prelude.name, name: prelude.name,
prelude: prelude.prelude, prelude: prelude.prelude,
block: Some(input.slice_from(position).to_string()), block: Some(rules),
})) }))
} }

View File

@ -23,6 +23,10 @@ use url::{ParseError, Url};
mod css_property { mod css_property {
include!(concat!(env!("OUT_DIR"), "/css_property.rs")); include!(concat!(env!("OUT_DIR"), "/css_property.rs"));
} }
#[macro_use]
mod css_at_rule {
include!(concat!(env!("OUT_DIR"), "/css_at_rule.rs"));
}
mod arena_dom; mod arena_dom;
mod config; mod config;
@ -30,9 +34,10 @@ mod css_parser;
use arena_dom::{create_element, html5ever_parse_slice_into_arena, Arena, NodeData, Ref}; use arena_dom::{create_element, html5ever_parse_slice_into_arena, Arena, NodeData, Ref};
use config::permissive::{ADD_ATTRIBUTES, ALL_ATTRIBUTES, ATTRIBUTES, ELEMENTS, PROTOCOLS}; use config::permissive::{ADD_ATTRIBUTES, ALL_ATTRIBUTES, ATTRIBUTES, ELEMENTS, PROTOCOLS};
use config::relaxed::CSS_PROPERTIES; use config::relaxed::{CSS_PROPERTIES, CSS_AT_RULES};
use css_parser::{CssRule, parse_css_style_attribute, parse_css_stylesheet}; use css_parser::{CssRule, parse_css_style_attribute, parse_css_stylesheet};
use css_property::CssProperty; use css_property::CssProperty;
use css_at_rule::CssAtRule;
fn main() { fn main() {
let mut bytes = Vec::new(); let mut bytes = Vec::new();
@ -65,6 +70,45 @@ fn sanitize<'arena>(node: Ref<'arena>, arena: Arena<'arena>) {
} }
} }
fn css_rules_to_string(rules: Vec<CssRule>) -> String {
let mut sanitized_css = String::new();
for rule in rules {
match rule {
CssRule::StyleRule(style_rule) => {
sanitized_css += &style_rule.selectors.trim();
sanitized_css += " {\n";
for declaration in style_rule.declarations.into_iter() {
let declaration_string = &declaration.to_string();
if CSS_PROPERTIES
.contains(&CssProperty::from(declaration.property))
{
sanitized_css += " ";
sanitized_css += declaration_string;
sanitized_css += " ";
}
}
sanitized_css += "\n}";
},
CssRule::AtRule(at_rule) => {
dbg!(&at_rule);
if CSS_AT_RULES
.contains(&CssAtRule::from(at_rule.name.clone()))
{
sanitized_css += &format!("@{} ", &at_rule.name);
sanitized_css += &at_rule.prelude.trim();
if let Some(block) = at_rule.block {
sanitized_css += " {\n";
sanitized_css += &css_rules_to_string(block);
sanitized_css += "\n}";
}
}
}
}
sanitized_css += "\n";
}
sanitized_css.trim().to_string()
}
// TODO: make separate rich and plain transformers // TODO: make separate rich and plain transformers
// TODO: add whitelist of tags, remove any not in it DONE // TODO: add whitelist of tags, remove any not in it DONE
// TODO: add whitelist of attributes, remove any not in it DONE // TODO: add whitelist of attributes, remove any not in it DONE
@ -90,38 +134,7 @@ fn transform_node<'arena>(node: Ref<'arena>, arena: Arena<'arena>) {
if name.local == local_name!("style") { if name.local == local_name!("style") {
let rules = parse_css_stylesheet(&contents.borrow()); let rules = parse_css_stylesheet(&contents.borrow());
dbg!(&rules); dbg!(&rules);
let mut sanitized_css = String::new(); let sanitized_css = css_rules_to_string(rules);
for rule in rules {
match rule {
CssRule::StyleRule(style_rule) => {
sanitized_css += &style_rule.selectors.trim();
sanitized_css += " {\n";
for declaration in style_rule.declarations.into_iter() {
let declaration_string = &declaration.to_string();
if CSS_PROPERTIES
.contains(&CssProperty::from(declaration.property))
{
sanitized_css += " ";
sanitized_css += declaration_string;
sanitized_css += " ";
}
}
sanitized_css += "\n}";
},
CssRule::AtRule(at_rule) => {
dbg!(&at_rule);
sanitized_css += &format!("@{} ", at_rule.name);
sanitized_css += &at_rule.prelude.trim();
if let Some(block) = at_rule.block {
sanitized_css += " {\n";
sanitized_css += &block.trim();
sanitized_css += "\n}";
}
}
}
sanitized_css += "\n";
}
let sanitized_css = sanitized_css.trim();
dbg!(&sanitized_css); dbg!(&sanitized_css);
contents.replace(StrTendril::from(sanitized_css)); contents.replace(StrTendril::from(sanitized_css));
} }