Skip to content

Commit

Permalink
Remove parentheses from supports condition AST
Browse files Browse the repository at this point in the history
We will add parentheses where needed when printing instead, as we did recently for media queries.
  • Loading branch information
devongovett committed Dec 21, 2022
1 parent 560b784 commit 87ca705
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/bundler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,7 @@ mod tests {
assert_eq!(
res,
indoc! { r#"
@supports ((color: red) or (foo: bar)) {
@supports (color: red) or (foo: bar) {
.b {
color: green;
}
Expand Down
64 changes: 64 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10260,6 +10260,22 @@ mod tests {
}
"#},
);
test(
r#"
@supports (((foo: bar) or (bar: baz))) {
.test {
foo: bar;
}
}
"#,
indoc! { r#"
@supports (foo: bar) or (bar: baz) {
.test {
foo: bar;
}
}
"#},
);
test(
r#"
@supports (foo: bar) and (bar: baz) {
Expand All @@ -10276,6 +10292,54 @@ mod tests {
}
"#},
);
test(
r#"
@supports (((foo: bar) and (bar: baz))) {
.test {
foo: bar;
}
}
"#,
indoc! { r#"
@supports (foo: bar) and (bar: baz) {
.test {
foo: bar;
}
}
"#},
);
test(
r#"
@supports (foo: bar) and (((bar: baz) or (test: foo))) {
.test {
foo: bar;
}
}
"#,
indoc! { r#"
@supports (foo: bar) and ((bar: baz) or (test: foo)) {
.test {
foo: bar;
}
}
"#},
);
test(
r#"
@supports not (((foo: bar) and (bar: baz))) {
.test {
foo: bar;
}
}
"#,
indoc! { r#"
@supports not ((foo: bar) and (bar: baz)) {
.test {
foo: bar;
}
}
"#},
);
test(
r#"
@supports selector(a > b) {
Expand Down
5 changes: 1 addition & 4 deletions src/rules/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,7 @@ impl<'i> ToCss for ImportRule<'i> {

if let Some(supports) = &self.supports {
dest.write_str(" supports")?;
if matches!(
supports,
SupportsCondition::Declaration { .. } | SupportsCondition::Parens(_)
) {
if matches!(supports, SupportsCondition::Declaration { .. }) {
supports.to_css(dest)?;
} else {
dest.write_char('(')?;
Expand Down
45 changes: 30 additions & 15 deletions src/rules/supports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,6 @@ pub enum SupportsCondition<'i> {
/// A selector to evaluate.
Selector(CowArcStr<'i>),
// FontTechnology()
/// A parenthesized expression.
#[cfg_attr(feature = "visitor", skip_type)]
Parens(Box<SupportsCondition<'i>>),
/// An unknown condition.
Unknown(CowArcStr<'i>),
}
Expand All @@ -113,7 +110,7 @@ impl<'i> SupportsCondition<'i> {
a.push(b.clone());
}
} else if self != b {
*self = SupportsCondition::Parens(Box::new(SupportsCondition::And(vec![self.clone(), b.clone()])))
*self = SupportsCondition::And(vec![self.clone(), b.clone()])
}
}

Expand All @@ -124,13 +121,13 @@ impl<'i> SupportsCondition<'i> {
a.push(b.clone());
}
} else if self != b {
*self = SupportsCondition::Parens(Box::new(SupportsCondition::Or(vec![self.clone(), b.clone()])))
*self = SupportsCondition::Or(vec![self.clone(), b.clone()])
}
}

fn set_prefixes_for_targets(&mut self, targets: &Browsers) {
match self {
SupportsCondition::Not(cond) | SupportsCondition::Parens(cond) => cond.set_prefixes_for_targets(targets),
SupportsCondition::Not(cond) => cond.set_prefixes_for_targets(targets),
SupportsCondition::And(items) | SupportsCondition::Or(items) => {
for item in items {
item.set_prefixes_for_targets(targets);
Expand Down Expand Up @@ -226,7 +223,7 @@ impl<'i> SupportsCondition<'i> {
let res = input.try_parse(|input| {
input.parse_nested_block(|input| {
if let Ok(condition) = input.try_parse(SupportsCondition::parse) {
return Ok(SupportsCondition::Parens(Box::new(condition)));
return Ok(condition);
}

Self::parse_declaration(input)
Expand Down Expand Up @@ -256,6 +253,29 @@ impl<'i> SupportsCondition<'i> {
value: input.slice_from(pos).into(),
})
}

fn needs_parens(&self, parent: &SupportsCondition) -> bool {
match self {
SupportsCondition::Not(_) => true,
SupportsCondition::And(_) => !matches!(parent, SupportsCondition::And(_)),
SupportsCondition::Or(_) => !matches!(parent, SupportsCondition::Or(_)),
_ => false,
}
}

fn to_css_with_parens_if_needed<W>(&self, dest: &mut Printer<W>, needs_parens: bool) -> Result<(), PrinterError>
where
W: std::fmt::Write,
{
if needs_parens {
dest.write_char('(')?;
}
self.to_css(dest)?;
if needs_parens {
dest.write_char(')')?;
}
Ok(())
}
}

impl<'i> ToCss for SupportsCondition<'i> {
Expand All @@ -266,7 +286,7 @@ impl<'i> ToCss for SupportsCondition<'i> {
match self {
SupportsCondition::Not(condition) => {
dest.write_str("not ")?;
condition.to_css(dest)
condition.to_css_with_parens_if_needed(dest, condition.needs_parens(self))
}
SupportsCondition::And(conditions) => {
let mut first = true;
Expand All @@ -276,7 +296,7 @@ impl<'i> ToCss for SupportsCondition<'i> {
} else {
dest.write_str(" and ")?;
}
condition.to_css(dest)?;
condition.to_css_with_parens_if_needed(dest, condition.needs_parens(self))?;
}
Ok(())
}
Expand All @@ -288,15 +308,10 @@ impl<'i> ToCss for SupportsCondition<'i> {
} else {
dest.write_str(" or ")?;
}
condition.to_css(dest)?;
condition.to_css_with_parens_if_needed(dest, condition.needs_parens(self))?;
}
Ok(())
}
SupportsCondition::Parens(condition) => {
dest.write_char('(')?;
condition.to_css(dest)?;
dest.write_char(')')
}
SupportsCondition::Declaration { property_id, value } => {
dest.write_char('(')?;

Expand Down

0 comments on commit 87ca705

Please sign in to comment.