Skip to content

Commit

Permalink
Move handling and handle more cases
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett committed Aug 28, 2024
1 parent 5a27ff1 commit 424ac0e
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 32 deletions.
42 changes: 19 additions & 23 deletions selectors/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ pub enum SelectorParseErrorKind<'i> {
InvalidQualNameInAttr(Token<'i>),
ExplicitNamespaceUnexpectedToken(Token<'i>),
ClassNeedsIdent(Token<'i>),
UnexpectedSelectorAfterPseudoElements(Token<'i>),
UnexpectedSelectorAfterPseudoElement(Token<'i>),
}

macro_rules! with_all_bounds {
Expand Down Expand Up @@ -2142,6 +2142,14 @@ where
}

if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
// Input should be exhausted here.
let source_location = input.current_source_location();
if let Ok(next) = input.next() {
let next = next.clone();
return Err(
source_location.new_custom_error(SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElement(next)),
);
}
break;
}

Expand Down Expand Up @@ -2957,6 +2965,7 @@ where
Impl: SelectorImpl<'i>,
{
let start = input.state();
let token_location = input.current_source_location();
let token = match input.next_including_whitespace().map(|t| t.clone()) {
Ok(t) => t,
Err(..) => {
Expand All @@ -2968,14 +2977,18 @@ where
Ok(Some(match token {
Token::IDHash(id) => {
if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
return Err(token_location.new_custom_error(
SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElement(Token::IDHash(id)),
));
}
let id = Component::ID(id.into());
SimpleSelectorParseResult::SimpleSelector(id)
}
Token::Delim('.') => {
if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
return Err(token_location.new_custom_error(
SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElement(Token::Delim('.')),
));
}
let location = input.current_source_location();
let class = match *input.next_including_whitespace()? {
Expand All @@ -2990,7 +3003,9 @@ where
}
Token::SquareBracketBlock => {
if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
return Err(token_location.new_custom_error(
SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElement(Token::SquareBracketBlock),
));
}
let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
SimpleSelectorParseResult::SimpleSelector(attr)
Expand Down Expand Up @@ -3060,25 +3075,6 @@ where
SimpleSelectorParseResult::SimpleSelector(Component::Nesting)
}
_ => {
if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
let source_location = input.current_source_location();
// Handle the case where the token is a whitespace token
let token = match token {
Token::WhiteSpace(..) => input.next(),
_ => Ok(&token),
};

// Use better error message
if let Ok(token @ Token::Ident(..) | token @ Token::IDHash(..) | token @ Token::Delim('.')) = token {
return Err(source_location.new_custom_error(
SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElements(token.clone()),
));
}

input.reset(&start);
return Ok(None);
}

input.reset(&start);
return Ok(None);
}
Expand Down
8 changes: 4 additions & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub enum SelectorError<'i> {
AmbiguousCssModuleClass(CowArcStr<'i>),

/// An unexpected token was encountered after a pseudo element.
UnexpectedSelectorAfterPseudoElements(
UnexpectedSelectorAfterPseudoElement(
#[cfg_attr(any(feature = "serde", feature = "nodejs"), serde(skip))] Token<'i>,
),
}
Expand Down Expand Up @@ -266,7 +266,7 @@ impl<'i> fmt::Display for SelectorError<'i> {
UnexpectedTokenInAttributeSelector(token) => write!(f, "Unexpected token in attribute selector: {:?}", token),
UnsupportedPseudoClassOrElement(name) => write!(f, "Unsupported pseudo class or element: {}", name),
AmbiguousCssModuleClass(_) => write!(f, "Ambiguous CSS module class not supported"),
UnexpectedSelectorAfterPseudoElements(token) => {
UnexpectedSelectorAfterPseudoElement(token) => {
write!(
f,
"Pseudo-elements like '::before' or '::after' can't be followed by selectors like '{token:?}'"
Expand Down Expand Up @@ -313,8 +313,8 @@ impl<'i> From<SelectorParseErrorKind<'i>> for SelectorError<'i> {
}
SelectorParseErrorKind::ClassNeedsIdent(t) => SelectorError::ClassNeedsIdent(t.into()),
SelectorParseErrorKind::AmbiguousCssModuleClass(name) => SelectorError::AmbiguousCssModuleClass(name.into()),
SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElements(t) => {
SelectorError::UnexpectedSelectorAfterPseudoElements(t.into())
SelectorParseErrorKind::UnexpectedSelectorAfterPseudoElement(t) => {
SelectorError::UnexpectedSelectorAfterPseudoElement(t.into())
}
}
}
Expand Down
30 changes: 25 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6903,22 +6903,42 @@ mod tests {

error_test(
"input.defaultCheckbox::before h1 {width: 20px}",
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElements(Token::Ident(
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElement(Token::Ident(
"h1".into(),
))),
);

error_test(
"input.defaultCheckbox::before .my-class {width: 20px}",
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElements(Token::Delim('.'))),
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElement(Token::Delim('.'))),
);
error_test(
"input.defaultCheckbox::before.my-class {width: 20px}",
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElement(Token::Delim('.'))),
);

error_test(
"input.defaultCheckbox::before #id {width: 20px}",
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElements(Token::IDHash(
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElement(Token::IDHash(
"id".into(),
))),
);
error_test(
"input.defaultCheckbox::before#id {width: 20px}",
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElement(Token::IDHash(
"id".into(),
))),
);
error_test(
"input.defaultCheckbox::before [attr] {width: 20px}",
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElement(
Token::SquareBracketBlock,
)),
);
error_test(
"input.defaultCheckbox::before[attr] {width: 20px}",
ParserError::SelectorError(SelectorError::UnexpectedSelectorAfterPseudoElement(
Token::SquareBracketBlock,
)),
);
}

#[test]
Expand Down

0 comments on commit 424ac0e

Please sign in to comment.