Skip to content

Commit

Permalink
fix(css/parser): Fix parsing of supports() (#6333)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed Nov 8, 2022
1 parent 35a53ae commit f483224
Show file tree
Hide file tree
Showing 37 changed files with 7,212 additions and 4,570 deletions.
24 changes: 11 additions & 13 deletions crates/swc_css_ast/src/at_rule.rs
Expand Up @@ -152,15 +152,14 @@ pub enum KeyframeSelector {
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct ImportPrelude {
pub span: Span,
pub href: Box<ImportPreludeHref>,
pub layer_name: Option<Box<ImportPreludeLayerName>>,
pub supports: Option<Box<ImportPreludeSupportsType>>,
pub media: Option<Box<MediaQueryList>>,
pub href: Box<ImportHref>,
pub layer_name: Option<Box<ImportLayerName>>,
pub import_conditions: Option<Box<ImportConditions>>,
}

#[ast_node]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
pub enum ImportPreludeHref {
pub enum ImportHref {
#[tag("Url")]
Url(Url),
#[tag("Str")]
Expand All @@ -169,20 +168,19 @@ pub enum ImportPreludeHref {

#[ast_node]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
pub enum ImportPreludeLayerName {
pub enum ImportLayerName {
#[tag("Ident")]
Ident(Ident),
#[tag("Function")]
Function(Function),
}

#[ast_node]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
pub enum ImportPreludeSupportsType {
#[tag("SupportsCondition")]
SupportsCondition(SupportsCondition),
#[tag("Declaration")]
Declaration(Box<Declaration>),
#[ast_node("ImportCondition")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct ImportConditions {
pub span: Span,
pub supports: Option<Box<Function>>,
pub media: Option<Box<MediaQueryList>>,
}

#[ast_node("NamespacePrelude")]
Expand Down
6 changes: 5 additions & 1 deletion crates/swc_css_ast/src/base.rs
Expand Up @@ -4,7 +4,7 @@ use swc_common::{ast_node, EqIgnoreSpan, Span};
use crate::{
AlphaValue, AtRule, CalcSum, CmykComponent, Color, ComplexSelector, DashedIdent, Delimiter,
Dimension, Hue, Ident, Integer, KeyframeBlock, LayerName, Number, Percentage, Ratio,
RelativeSelectorList, SelectorList, Str, TokenAndSpan, UnicodeRange, Url,
RelativeSelectorList, SelectorList, Str, SupportsCondition, TokenAndSpan, UnicodeRange, Url,
};

#[ast_node("Stylesheet")]
Expand Down Expand Up @@ -143,6 +143,10 @@ pub enum ComponentValue {
ComplexSelector(ComplexSelector),
#[tag("LayerName")]
LayerName(LayerName),
#[tag("SupportsCondition")]
SupportsCondition(SupportsCondition),
#[tag("Declaration")]
Declaration(Declaration),
}

#[ast_node]
Expand Down
67 changes: 35 additions & 32 deletions crates/swc_css_codegen/src/lib.rs
Expand Up @@ -210,10 +210,10 @@ where
}
AtRulePrelude::ImportPrelude(n) => {
match &*n.href {
ImportPreludeHref::Url(_) => {
ImportHref::Url(_) => {
space!(self);
}
ImportPreludeHref::Str(_) => {
ImportHref::Str(_) => {
formatting_space!(self);
}
}
Expand Down Expand Up @@ -334,56 +334,42 @@ where
)?;
}

#[emitter]
fn emit_import_prelude_supports_type(&mut self, n: &ImportPreludeSupportsType) -> Result {
match n {
ImportPreludeSupportsType::SupportsCondition(n) => emit!(self, n),
ImportPreludeSupportsType::Declaration(n) => emit!(self, n),
}
}

#[emitter]
fn emit_import_prelude(&mut self, n: &ImportPrelude) -> Result {
emit!(self, n.href);

if let Some(layer_name) = &n.layer_name {
if n.layer_name.is_some() || n.import_conditions.is_some() {
formatting_space!(self);
}

if let Some(layer_name) = &n.layer_name {
emit!(self, layer_name);

if self.config.minify && (n.supports.is_some() || n.media.is_some()) {
if let ImportPreludeLayerName::Ident(_) = &**layer_name {
if n.import_conditions.is_some() {
if let ImportLayerName::Ident(_) = &**layer_name {
space!(self);
} else {
formatting_space!(self);
}
}
}

if let Some(supports) = &n.supports {
formatting_space!(self);
write_raw!(self, "supports");
write_raw!(self, "(");
emit!(self, supports);
write_raw!(self, ")");
}

if let Some(media) = &n.media {
formatting_space!(self);
emit!(self, media);
}
emit!(self, n.import_conditions);
}

#[emitter]
fn emit_import_prelude_href(&mut self, n: &ImportPreludeHref) -> Result {
fn emit_import_prelude_href(&mut self, n: &ImportHref) -> Result {
match n {
ImportPreludeHref::Url(n) => emit!(self, n),
ImportPreludeHref::Str(n) => emit!(self, n),
ImportHref::Url(n) => emit!(self, n),
ImportHref::Str(n) => emit!(self, n),
}
}

#[emitter]
fn emit_import_layer_name(&mut self, n: &ImportPreludeLayerName) -> Result {
fn emit_import_layer_name(&mut self, n: &ImportLayerName) -> Result {
match n {
ImportPreludeLayerName::Ident(n) => emit!(self, n),
ImportPreludeLayerName::Function(n) if n.value.is_empty() => {
ImportLayerName::Ident(n) => emit!(self, n),
ImportLayerName::Function(n) if n.value.is_empty() => {
// Never emit `layer()`
emit!(
self,
Expand All @@ -394,12 +380,27 @@ where
})
)
}
ImportPreludeLayerName::Function(n) => {
ImportLayerName::Function(n) => {
emit!(self, n)
}
}
}

#[emitter]
fn emit_import_conditions(&mut self, n: &ImportConditions) -> Result {
if let Some(supports) = &n.supports {
emit!(self, supports);

if n.media.is_some() {
formatting_space!(self);
}
}

if let Some(media) = &n.media {
emit!(self, media);
}
}

#[emitter]
fn emit_keyframes_name(&mut self, n: &KeyframesName) -> Result {
match n {
Expand Down Expand Up @@ -1406,6 +1407,8 @@ where
ComponentValue::CalcSum(n) => emit!(self, n),
ComponentValue::ComplexSelector(n) => emit!(self, n),
ComponentValue::LayerName(n) => emit!(self, n),
ComponentValue::Declaration(n) => emit!(self, n),
ComponentValue::SupportsCondition(n) => emit!(self, n),
}
}

Expand Down
34 changes: 18 additions & 16 deletions crates/swc_css_lints/src/rules/no_duplicate_at_import_rules.rs
Expand Up @@ -45,8 +45,8 @@ impl Visit for NoDuplicateAtImportRules {

fn visit_import_prelude(&mut self, import_prelude: &ImportPrelude) {
let href = match &*import_prelude.href {
ImportPreludeHref::Str(Str { value, .. }) => value,
ImportPreludeHref::Url(Url {
ImportHref::Str(Str { value, .. }) => value,
ImportHref::Url(Url {
value: Some(value), ..
}) => match &**value {
UrlValue::Raw(UrlValueRaw { value, .. }) => value,
Expand All @@ -59,24 +59,26 @@ impl Visit for NoDuplicateAtImportRules {
}
};

if let Some(queries) = import_prelude.media.as_ref().map(|media| &media.queries) {
queries.iter().fold(&mut self.imports, |imports, query| {
let media = query.media_type.as_ref().map(|ident| {
let MediaType::Ident(Ident { value, .. }) = ident;
if let Some(import_conditions) = &import_prelude.import_conditions {
if let Some(queries) = import_conditions.media.as_ref().map(|media| &media.queries) {
queries.iter().fold(&mut self.imports, |imports, query| {
let media = query.media_type.as_ref().map(|ident| {
let MediaType::Ident(Ident { value, .. }) = ident;

value.clone()
});
let pair = (href.clone(), media);
value.clone()
});
let pair = (href.clone(), media);

if imports.contains(&pair) {
if let Some(at_rule) = &self.import_at_rules {
self.ctx.report(at_rule, build_message(href));
if imports.contains(&pair) {
if let Some(at_rule) = &self.import_at_rules {
self.ctx.report(at_rule, build_message(href));
}
}
}

imports.insert(pair);
imports
});
imports.insert(pair);
imports
});
}
} else {
let pair = (href.clone(), None);

Expand Down
6 changes: 3 additions & 3 deletions crates/swc_css_minifier/src/compressor/import.rs
Expand Up @@ -3,8 +3,8 @@ use swc_css_ast::*;
use super::Compressor;

impl Compressor {
pub(super) fn compress_import_prelude_href(&mut self, import_href: &mut ImportPreludeHref) {
if let ImportPreludeHref::Url(Url {
pub(super) fn compress_import_href(&mut self, import_href: &mut ImportHref) {
if let ImportHref::Url(Url {
value: Some(value),
modifiers,
span,
Expand All @@ -22,7 +22,7 @@ impl Compressor {
UrlValue::Raw(UrlValueRaw { value, .. }) => value,
};

*import_href = ImportPreludeHref::Str(Str {
*import_href = ImportHref::Str(Str {
span: *span,
value: (&*new_value).into(),
raw: None,
Expand Down
4 changes: 2 additions & 2 deletions crates/swc_css_minifier/src/compressor/mod.rs
Expand Up @@ -139,10 +139,10 @@ impl VisitMut for Compressor {
self.compress_keyframes_at_rule(n);
}

fn visit_mut_import_prelude_href(&mut self, n: &mut ImportPreludeHref) {
fn visit_mut_import_href(&mut self, n: &mut ImportHref) {
n.visit_mut_children_with(self);

self.compress_import_prelude_href(n);
self.compress_import_href(n);
}

fn visit_mut_media_query_list(&mut self, n: &mut MediaQueryList) {
Expand Down
8 changes: 4 additions & 4 deletions crates/swc_css_modules/src/imports.rs
Expand Up @@ -2,8 +2,8 @@

use swc_atoms::{js_word, JsWord};
use swc_css_ast::{
ComponentValue, Declaration, DeclarationName, Ident, ImportPrelude, ImportPreludeHref,
Stylesheet, UrlValue,
ComponentValue, Declaration, DeclarationName, Ident, ImportHref, ImportPrelude, Stylesheet,
UrlValue,
};
use swc_css_visit::{Visit, VisitWith};

Expand All @@ -26,7 +26,7 @@ impl Visit for Analyzer {
n.visit_children_with(self);

match &*n.href {
ImportPreludeHref::Url(u) => {
ImportHref::Url(u) => {
if let Some(s) = &u.value {
match &**s {
UrlValue::Str(s) => {
Expand All @@ -38,7 +38,7 @@ impl Visit for Analyzer {
}
}
}
ImportPreludeHref::Str(s) => {
ImportHref::Str(s) => {
self.imports.push(s.value.clone());
}
}
Expand Down
Expand Up @@ -143,7 +143,7 @@ st.css');
@import url("./test.css") layer(default) supports(display: flex) screen and (min-width: 400px);
@import url("./test.css") screen and (min-width: 400px);
@import url("./test.css") layer(default) supports(display: flex) screen and (min-width: 400px);
@import url("./test.css") LAYER(DEFAULT) supports(DISPLAY: FLEX) SCREEN AND (MIN-WIDTH: 400PX);
@import url("./test.css") LAYER(DEFAULT) SUPPORTS(DISPLAY: FLEX) SCREEN AND (MIN-WIDTH: 400PX);
@import url("./test.css") layer(default) supports(display: flex) screen and (min-width: 400px);
@import url(test.css);
@import url(test.css);
Expand Down

1 comment on commit f483224

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: f483224 Previous: 34b3710 Ratio
es/full/bugs-1 366125 ns/iter (± 34739) 330032 ns/iter (± 35664) 1.11
es/full/minify/libraries/antd 1929171607 ns/iter (± 33853782) 1879408602 ns/iter (± 65611871) 1.03
es/full/minify/libraries/d3 419807046 ns/iter (± 5873652) 429937732 ns/iter (± 27284367) 0.98
es/full/minify/libraries/echarts 1588274274 ns/iter (± 60715904) 1577735703 ns/iter (± 37222967) 1.01
es/full/minify/libraries/jquery 121766134 ns/iter (± 127092857) 105215812 ns/iter (± 5131380) 1.16
es/full/minify/libraries/lodash 134905168 ns/iter (± 71778349) 123910792 ns/iter (± 4204973) 1.09
es/full/minify/libraries/moment 64219214 ns/iter (± 2115660) 63526748 ns/iter (± 2516345) 1.01
es/full/minify/libraries/react 21534761 ns/iter (± 1219766) 24024084 ns/iter (± 1358416) 0.90
es/full/minify/libraries/terser 346834478 ns/iter (± 53504802) 336016305 ns/iter (± 26975963) 1.03
es/full/minify/libraries/three 606410993 ns/iter (± 24022094) 566637048 ns/iter (± 115062607) 1.07
es/full/minify/libraries/typescript 3628271605 ns/iter (± 60158265) 3416784586 ns/iter (± 88719387) 1.06
es/full/minify/libraries/victory 893971074 ns/iter (± 35586533) 833766293 ns/iter (± 18815868) 1.07
es/full/minify/libraries/vue 176009093 ns/iter (± 10783328) 163143559 ns/iter (± 9042481) 1.08
es/full/codegen/es3 33452 ns/iter (± 440) 33472 ns/iter (± 2804) 1.00
es/full/codegen/es5 33779 ns/iter (± 1151) 33511 ns/iter (± 1555) 1.01
es/full/codegen/es2015 33507 ns/iter (± 2240) 33737 ns/iter (± 2856) 0.99
es/full/codegen/es2016 33411 ns/iter (± 1247) 40261 ns/iter (± 5115) 0.83
es/full/codegen/es2017 33379 ns/iter (± 5373) 36009 ns/iter (± 4286) 0.93
es/full/codegen/es2018 33363 ns/iter (± 1327) 34769 ns/iter (± 1489) 0.96
es/full/codegen/es2019 33923 ns/iter (± 1706) 34216 ns/iter (± 1565) 0.99
es/full/codegen/es2020 33710 ns/iter (± 871) 34627 ns/iter (± 1672) 0.97
es/full/all/es3 203280888 ns/iter (± 17654184) 224587246 ns/iter (± 24863298) 0.91
es/full/all/es5 191325023 ns/iter (± 15220115) 207931195 ns/iter (± 30919080) 0.92
es/full/all/es2015 154715096 ns/iter (± 14605197) 166849989 ns/iter (± 22378466) 0.93
es/full/all/es2016 151694959 ns/iter (± 11210923) 167860617 ns/iter (± 15123670) 0.90
es/full/all/es2017 150515877 ns/iter (± 10224394) 164788923 ns/iter (± 15751552) 0.91
es/full/all/es2018 150732774 ns/iter (± 12959654) 163501346 ns/iter (± 14546965) 0.92
es/full/all/es2019 149932898 ns/iter (± 16089066) 161718190 ns/iter (± 16771474) 0.93
es/full/all/es2020 157094489 ns/iter (± 21624322) 158300059 ns/iter (± 20192419) 0.99
es/full/parser 767006 ns/iter (± 94854) 753464 ns/iter (± 31059) 1.02
es/full/base/fixer 27821 ns/iter (± 6439) 27124 ns/iter (± 1573) 1.03
es/full/base/resolver_and_hygiene 99914 ns/iter (± 14926) 94029 ns/iter (± 8953) 1.06
serialization of ast node 218 ns/iter (± 11) 217 ns/iter (± 8) 1.00
serialization of serde 220 ns/iter (± 33) 236 ns/iter (± 11) 0.93

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.