diff --git a/src/lib.rs b/src/lib.rs index 86323d07..e1dd6b63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6686,6 +6686,22 @@ mod tests { ".foo ::unknown:only-child {width: 20px}", ".foo ::unknown:only-child{width:20px}", ); + minify_test( + ".foo ::unknown(.foo) .bar {width: 20px}", + ".foo ::unknown(.foo) .bar{width:20px}", + ); + minify_test( + ".foo ::unknown(.foo .bar / .baz) .bar {width: 20px}", + ".foo ::unknown(.foo .bar / .baz) .bar{width:20px}", + ); + minify_test( + ".foo ::unknown(something(foo)) .bar {width: 20px}", + ".foo ::unknown(something(foo)) .bar{width:20px}", + ); + minify_test( + ".foo ::unknown([abc]) .bar {width: 20px}", + ".foo ::unknown([abc]) .bar{width:20px}", + ); let deep_options = ParserOptions { flags: ParserFlags::DEEP_SELECTOR_COMBINATOR, diff --git a/src/properties/custom.rs b/src/properties/custom.rs index 3e2cd2f9..671e7b74 100644 --- a/src/properties/custom.rs +++ b/src/properties/custom.rs @@ -312,6 +312,54 @@ impl<'i> TokenList<'i> { return Ok(TokenList(tokens)); } + pub(crate) fn parse_raw<'t>( + input: &mut Parser<'i, 't>, + tokens: &mut Vec>, + options: &ParserOptions<'_, 'i>, + depth: usize, + ) -> Result<(), ParseError<'i, ParserError<'i>>> { + if depth > 500 { + return Err(input.new_custom_error(ParserError::MaximumNestingDepth)); + } + + loop { + let state = input.state(); + match input.next_including_whitespace_and_comments() { + Ok(token @ &cssparser::Token::ParenthesisBlock) + | Ok(token @ &cssparser::Token::SquareBracketBlock) + | Ok(token @ &cssparser::Token::CurlyBracketBlock) => { + tokens.push(Token::from(token).into()); + let closing_delimiter = match token { + cssparser::Token::ParenthesisBlock => Token::CloseParenthesis, + cssparser::Token::SquareBracketBlock => Token::CloseSquareBracket, + cssparser::Token::CurlyBracketBlock => Token::CloseCurlyBracket, + _ => unreachable!(), + }; + + input.parse_nested_block(|input| TokenList::parse_raw(input, tokens, options, depth + 1))?; + tokens.push(closing_delimiter.into()); + } + Ok(token @ &cssparser::Token::Function(_)) => { + tokens.push(Token::from(token).into()); + input.parse_nested_block(|input| TokenList::parse_raw(input, tokens, options, depth + 1))?; + tokens.push(Token::CloseParenthesis.into()); + } + Ok(token) if token.is_parse_error() => { + return Err(ParseError { + kind: ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(token.clone())), + location: state.source_location(), + }) + } + Ok(token) => { + tokens.push(Token::from(token).into()); + } + Err(_) => break, + } + } + + Ok(()) + } + fn parse_into<'t>( input: &mut Parser<'i, 't>, tokens: &mut Vec>, @@ -584,6 +632,27 @@ impl<'i> TokenList<'i> { Ok(()) } + pub(crate) fn to_css_raw(&self, dest: &mut Printer) -> Result<(), PrinterError> + where + W: std::fmt::Write, + { + for token_or_value in &self.0 { + match token_or_value { + TokenOrValue::Token(token) => { + token.to_css(dest)?; + } + _ => { + return Err(PrinterError { + kind: PrinterErrorKind::FmtError, + loc: None, + }) + } + } + } + + Ok(()) + } + #[inline] fn write_whitespace_if_needed(&self, i: usize, dest: &mut Printer) -> Result where diff --git a/src/selector.rs b/src/selector.rs index 891a586f..6a46075d 100644 --- a/src/selector.rs +++ b/src/selector.rs @@ -195,9 +195,11 @@ impl<'a, 'o, 'i> parcel_selectors::parser::Parser<'i> for SelectorParser<'a, 'o, if !name.starts_with('-') { self.options.warn(parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone()))); } + let mut args = Vec::new(); + TokenList::parse_raw(parser, &mut args, &self.options, 0)?; CustomFunction { name: name.into(), - arguments: TokenList::parse(parser, &self.options, 0)? + arguments: TokenList(args) } }, }; @@ -277,7 +279,9 @@ impl<'a, 'o, 'i> parcel_selectors::parser::Parser<'i> for SelectorParser<'a, 'o, if !name.starts_with('-') { self.options.warn(arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone()))); } - CustomFunction { name: name.into(), arguments: TokenList::parse(arguments, &self.options, 0)? } + let mut args = Vec::new(); + TokenList::parse_raw(arguments, &mut args, &self.options, 0)?; + CustomFunction { name: name.into(), arguments: TokenList(args) } } }; @@ -734,7 +738,7 @@ where dest.write_char(':')?; dest.write_str(name)?; dest.write_char('(')?; - args.to_css(dest, false)?; + args.to_css_raw(dest)?; dest.write_char(')') } } @@ -1095,7 +1099,7 @@ where dest.write_str("::")?; dest.write_str(name)?; dest.write_char('(')?; - args.to_css(dest, false)?; + args.to_css_raw(dest)?; dest.write_char(')') } }