Skip to content

Commit

Permalink
Store unsupported functional pseudo classes and elements as raw tokens
Browse files Browse the repository at this point in the history
Part of #227. We now also warn on unsupported selectors.
  • Loading branch information
devongovett committed Aug 16, 2022
1 parent 9916cae commit bbb64b7
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 53 deletions.
12 changes: 2 additions & 10 deletions node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,7 @@ struct Drafts {

fn compile<'i>(code: &'i str, config: &Config) -> Result<TransformResult<'i>, CompileError<'i>> {
let drafts = config.drafts.as_ref();
let warnings = if config.error_recovery.unwrap_or_default() {
Some(Arc::new(RwLock::new(Vec::new())))
} else {
None
};
let warnings = Some(Arc::new(RwLock::new(Vec::new())));

let filename = config.filename.clone().unwrap_or_default();
let mut source_map = if config.source_map.unwrap_or_default() {
Expand Down Expand Up @@ -343,11 +339,7 @@ fn compile_bundle<'i>(
} else {
None
};
let warnings = if config.error_recovery.unwrap_or_default() {
Some(Arc::new(RwLock::new(Vec::new())))
} else {
None
};
let warnings = Some(Arc::new(RwLock::new(Vec::new())));
let res = {
let drafts = config.drafts.as_ref();
let parser_options = ParserOptions {
Expand Down
8 changes: 4 additions & 4 deletions selectors/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ macro_rules! with_bounds {
}

with_bounds! {
[Clone + Eq]
[Clone + PartialEq]
[From<CowRcStr<'i>>]
}

Expand Down Expand Up @@ -335,7 +335,7 @@ pub trait Parser<'i> {
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct SelectorList<'i, Impl: SelectorImpl<'i>>(pub SmallVec<[Selector<'i, Impl>; 1]>);

/// How to treat invalid selectors in a selector list.
Expand Down Expand Up @@ -615,7 +615,7 @@ pub fn namespace_empty_string<'i, Impl: SelectorImpl<'i>>() -> Impl::NamespaceUr
///
/// This reordering doesn't change the semantics of selector matching, and we
/// handle it in to_css to make it invisible to serialization.
#[derive(Clone, Eq, PartialEq)]
#[derive(Clone, PartialEq)]
pub struct Selector<'i, Impl: SelectorImpl<'i>>(SpecificityAndFlags, Vec<Component<'i, Impl>>);

impl<'i, Impl: SelectorImpl<'i>> Selector<'i, Impl> {
Expand Down Expand Up @@ -1067,7 +1067,7 @@ impl Combinator {
/// optimal packing and cache performance, see [1].
///
/// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1357973
#[derive(Clone, Eq, PartialEq)]
#[derive(Clone, PartialEq)]
pub enum Component<'i, Impl: SelectorImpl<'i>> {
Combinator(Combinator),

Expand Down
8 changes: 2 additions & 6 deletions src/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::borrow::Cow;
use std::ops::Range;

use crate::context::PropertyHandlerContext;
use crate::error::{Error, ParserError, PrinterError};
use crate::error::{ParserError, PrinterError};
use crate::parser::ParserOptions;
use crate::printer::Printer;
use crate::properties::box_shadow::BoxShadowHandler;
Expand Down Expand Up @@ -70,11 +70,7 @@ impl<'i> DeclarationBlock<'i> {
while let Some(res) = parser.next() {
if let Err((err, _)) = res {
if options.error_recovery {
if let Some(warnings) = &options.warnings {
if let Ok(mut warnings) = warnings.write() {
warnings.push(Error::from(err, options.filename.clone()));
}
}
options.warn(err);
continue;
}
return Err(err);
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5332,6 +5332,9 @@ mod tests {
"::cue(v[voice='active']) {color: yellow;}",
"::cue(v[voice=active]){color:#ff0}",
);
minify_test(":foo(bar) { color: yellow }", ":foo(bar){color:#ff0}");
minify_test("::foo(bar) { color: yellow }", "::foo(bar){color:#ff0}");
minify_test("::foo(*) { color: yellow }", "::foo(*){color:#ff0}");
}

#[test]
Expand Down
29 changes: 16 additions & 13 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ pub struct ParserOptions<'o, 'i> {
pub warnings: Option<Arc<RwLock<Vec<Error<ParserError<'i>>>>>>,
}

impl<'o, 'i> ParserOptions<'o, 'i> {
#[inline]
pub(crate) fn warn(&self, warning: ParseError<'i, ParserError<'i>>) {
if let Some(warnings) = &self.warnings {
if let Ok(mut warnings) = warnings.write() {
warnings.push(Error::from(warning, self.filename.clone()));
}
}
}
}

#[derive(PartialEq, PartialOrd)]
enum State {
Start = 1,
Expand Down Expand Up @@ -324,11 +335,7 @@ impl<'a, 'o, 'b, 'i> NestedRuleParser<'a, 'o, 'i> {
Ok(rule) => rules.push(rule),
Err((e, _)) => {
if self.options.error_recovery {
if let Some(warnings) = &self.options.warnings {
if let Ok(mut warnings) = warnings.write() {
warnings.push(Error::from(e, self.options.filename.clone()));
}
}
self.options.warn(e);
continue;
}
return Err(e);
Expand Down Expand Up @@ -600,7 +607,7 @@ impl<'a, 'o, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'o, 'i> {
default_namespace: self.default_namespace,
namespace_prefixes: self.namespace_prefixes,
is_nesting_allowed: false,
css_modules: self.options.css_modules.is_some(),
options: &self.options,
};
SelectorList::parse(&selector_parser, input, NestingRequirement::None)
}
Expand Down Expand Up @@ -663,11 +670,7 @@ fn parse_declarations_and_nested_rules<'a, 'o, 'i, 't>(
while let Some(result) = iter.next() {
if let Err((err, _)) = result {
if options.error_recovery {
if let Some(warnings) = &options.warnings {
if let Ok(mut warnings) = warnings.write() {
warnings.push(Error::from(err, options.filename.clone()));
}
}
options.warn(err);
continue;
}
return Err(err);
Expand Down Expand Up @@ -740,7 +743,7 @@ impl<'a, 'o, 'i> AtRuleParser<'i> for StyleRuleParser<'a, 'o, 'i> {
default_namespace: self.default_namespace,
namespace_prefixes: self.namespace_prefixes,
is_nesting_allowed: true,
css_modules: self.options.css_modules.is_some()
options: &self.options,
};
let selectors = SelectorList::parse(&selector_parser, input, NestingRequirement::Contained)?;
Ok(AtRulePrelude::Nest(selectors))
Expand Down Expand Up @@ -867,7 +870,7 @@ impl<'a, 'o, 'b, 'i> QualifiedRuleParser<'i> for StyleRuleParser<'a, 'o, 'i> {
default_namespace: self.default_namespace,
namespace_prefixes: self.namespace_prefixes,
is_nesting_allowed: true,
css_modules: self.options.css_modules.is_some(),
options: &self.options,
};
SelectorList::parse(&selector_parser, input, NestingRequirement::Prefixed)
}
Expand Down
2 changes: 1 addition & 1 deletion src/properties/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ impl<'i> TokenOrValue<'i> {
}

impl<'i> TokenList<'i> {
fn parse<'t>(
pub(crate) fn parse<'t>(
input: &mut Parser<'i, 't>,
options: &ParserOptions,
depth: usize,
Expand Down
57 changes: 43 additions & 14 deletions src/selector.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::compat::Feature;
use crate::error::{ParserError, PrinterError};
use crate::printer::Printer;
use crate::properties::custom::TokenList;
use crate::rules::{StyleContext, ToCssWithContext};
use crate::stylesheet::PrinterOptions;
use crate::stylesheet::{ParserOptions, PrinterOptions};
use crate::targets::Browsers;
use crate::traits::{Parse, ToCss};
use crate::vendor_prefix::VendorPrefix;
Expand Down Expand Up @@ -89,20 +90,20 @@ impl<'i> SelectorImpl<'i> for Selectors {
}
}

pub struct SelectorParser<'a, 'i> {
pub struct SelectorParser<'a, 'o, 'i> {
pub default_namespace: &'a Option<CowArcStr<'i>>,
pub namespace_prefixes: &'a HashMap<CowArcStr<'i>, CowArcStr<'i>>,
pub is_nesting_allowed: bool,
pub css_modules: bool,
pub options: &'a ParserOptions<'o, 'i>,
}

impl<'a, 'i> parcel_selectors::parser::Parser<'i> for SelectorParser<'a, 'i> {
impl<'a, 'o, 'i> parcel_selectors::parser::Parser<'i> for SelectorParser<'a, 'o, 'i> {
type Impl = Selectors;
type Error = ParserError<'i>;

fn parse_non_ts_pseudo_class(
&self,
_: SourceLocation,
loc: SourceLocation,
name: CowRcStr<'i>,
) -> Result<PseudoClass<'i>, ParseError<'i, Self::Error>> {
use PseudoClass::*;
Expand Down Expand Up @@ -188,7 +189,10 @@ impl<'a, 'i> parcel_selectors::parser::Parser<'i> for SelectorParser<'a, 'i> {
"corner-present" => WebKitScrollbar(WebKitScrollbarPseudoClass::CornerPresent),
"window-inactive" => WebKitScrollbar(WebKitScrollbarPseudoClass::WindowInactive),

_ => Custom(name.into())
_ => {
self.options.warn(loc.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())));
Custom(name.into())
}
};

Ok(pseudo_class)
Expand All @@ -210,9 +214,12 @@ impl<'a, 'i> parcel_selectors::parser::Parser<'i> for SelectorParser<'a, 'i> {
Lang(langs)
},
"dir" => Dir(Direction::parse(parser)?),
"local" if self.css_modules => Local(Box::new(parcel_selectors::parser::Selector::parse(self, parser)?)),
"global" if self.css_modules => Global(Box::new(parcel_selectors::parser::Selector::parse(self, parser)?)),
_ => return Err(parser.new_custom_error(parcel_selectors::parser::SelectorParseErrorKind::UnexpectedIdent(name.clone()))),
"local" if self.options.css_modules.is_some() => Local(Box::new(parcel_selectors::parser::Selector::parse(self, parser)?)),
"global" if self.options.css_modules.is_some() => Global(Box::new(parcel_selectors::parser::Selector::parse(self, parser)?)),
_ => {
self.options.warn(parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())));
CustomFunction(name.into(), TokenList::parse(parser, &self.options, 0)?)
},
};

Ok(pseudo_class)
Expand All @@ -228,7 +235,7 @@ impl<'a, 'i> parcel_selectors::parser::Parser<'i> for SelectorParser<'a, 'i> {

fn parse_pseudo_element(
&self,
_: SourceLocation,
loc: SourceLocation,
name: CowRcStr<'i>,
) -> Result<PseudoElement<'i>, ParseError<'i, Self::Error>> {
use PseudoElement::*;
Expand Down Expand Up @@ -260,7 +267,10 @@ impl<'a, 'i> parcel_selectors::parser::Parser<'i> for SelectorParser<'a, 'i> {
"-webkit-scrollbar-corner" => WebKitScrollbar(WebKitScrollbarPseudoElement::Corner),
"-webkit-resizer" => WebKitScrollbar(WebKitScrollbarPseudoElement::Resizer),

_ => Custom(name.into())
_ => {
self.options.warn(loc.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())));
Custom(name.into())
}
};

Ok(pseudo_element)
Expand All @@ -275,7 +285,10 @@ impl<'a, 'i> parcel_selectors::parser::Parser<'i> for SelectorParser<'a, 'i> {
let pseudo_element = match_ignore_ascii_case! { &name,
"cue" => CueFunction(Box::new(Selector::parse(self, arguments)?)),
"cue-region" => CueRegionFunction(Box::new(Selector::parse(self, arguments)?)),
_ => return Err(arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
_ => {
self.options.warn(arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())));
CustomFunction(name.into(), TokenList::parse(arguments, &self.options, 0)?)
}
};

Ok(pseudo_element)
Expand Down Expand Up @@ -324,7 +337,7 @@ enum_property! {
}

/// https://drafts.csswg.org/selectors-4/#structural-pseudos
#[derive(Clone, Eq, PartialEq)]
#[derive(Clone, PartialEq)]
pub enum PseudoClass<'i> {
// https://drafts.csswg.org/selectors-4/#linguistic-pseudos
Lang(Vec<CowArcStr<'i>>),
Expand Down Expand Up @@ -395,6 +408,7 @@ pub enum PseudoClass<'i> {
WebKitScrollbar(WebKitScrollbarPseudoClass),

Custom(CowArcStr<'i>),
CustomFunction(CowArcStr<'i>, TokenList<'i>),
}

/// https://webkit.org/blog/363/styling-scrollbars/
Expand Down Expand Up @@ -622,6 +636,13 @@ impl<'a, 'i> ToCssWithContext<'a, 'i> for PseudoClass<'i> {
dest.write_char(':')?;
return dest.write_str(&val);
}
CustomFunction(name, args) => {
dest.write_char(':')?;
dest.write_str(name)?;
dest.write_char('(')?;
args.to_css(dest, false)?;
dest.write_char(')')
}
}
}
}
Expand Down Expand Up @@ -665,7 +686,7 @@ impl<'i> PseudoClass<'i> {
}
}

#[derive(PartialEq, Eq, Clone, Debug)]
#[derive(PartialEq, Clone, Debug)]
pub enum PseudoElement<'i> {
After,
Before,
Expand All @@ -682,6 +703,7 @@ pub enum PseudoElement<'i> {
CueFunction(Box<Selector<'i, Selectors>>),
CueRegionFunction(Box<Selector<'i, Selectors>>),
Custom(CowArcStr<'i>),
CustomFunction(CowArcStr<'i>, TokenList<'i>),
}

#[derive(PartialEq, Eq, Clone, Debug, Hash)]
Expand Down Expand Up @@ -796,6 +818,13 @@ impl<'i> ToCss for PseudoElement<'i> {
dest.write_str("::")?;
return dest.write_str(val);
}
CustomFunction(name, args) => {
dest.write_str("::")?;
dest.write_str(name)?;
dest.write_char('(')?;
args.to_css(dest, false)?;
dest.write_char(')')
}
}
}
}
Expand Down
6 changes: 1 addition & 5 deletions src/stylesheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,7 @@ impl<'i, 'o> StyleSheet<'i, 'o> {
Ok((_, rule)) => rule,
Err((e, _)) => {
if options.error_recovery {
if let Some(warnings) = &options.warnings {
if let Ok(mut warnings) = warnings.write() {
warnings.push(Error::from(e, options.filename.clone()));
}
}
options.warn(e);
continue;
}

Expand Down

0 comments on commit bbb64b7

Please sign in to comment.