diff --git a/crates/swc_css_ast/src/lib.rs b/crates/swc_css_ast/src/lib.rs index a56d14a9866b..a48d2b0d569a 100644 --- a/crates/swc_css_ast/src/lib.rs +++ b/crates/swc_css_ast/src/lib.rs @@ -9,3 +9,26 @@ mod base; mod selector; mod token; mod value; + +/// Returns true if the given value matches one of the given patterns. +/// +/// The type of value and patterns should be identical. +/// +/// # Exmaples +/// +/// ``` +/// use swc_atoms::JsWord; +/// use swc_atoms::js_word; +/// use swc_css_ast::*; +/// +/// assert!(matches_eq_ignore_ascii_case!(JsWord::from("A"), js_word!("a"))); +/// assert!(matches_eq_ignore_ascii_case!("A", "a")); +/// ``` +#[macro_export] +macro_rules! matches_eq_ignore_ascii_case { + ($value:expr, $($pat:expr),*) => {{ + $( + $value.eq_ignore_ascii_case(&$pat) || + )* false + }}; +} diff --git a/crates/swc_css_codegen/src/lib.rs b/crates/swc_css_codegen/src/lib.rs index 1cdbbc16396a..d0648c1ecaeb 100644 --- a/crates/swc_css_codegen/src/lib.rs +++ b/crates/swc_css_codegen/src/lib.rs @@ -1565,7 +1565,7 @@ where fn emit_ident(&mut self, n: &Ident) -> Result { if self.config.minify { let value = if self.ctx.allow_to_lowercase && self.config.minify { - n.value.to_lowercase() + n.value.to_ascii_lowercase().to_string() } else { n.value.to_string() }; diff --git a/crates/swc_css_minifier/src/compressor/color.rs b/crates/swc_css_minifier/src/compressor/color.rs index d2f7011726a7..d6720fc57ab0 100644 --- a/crates/swc_css_minifier/src/compressor/color.rs +++ b/crates/swc_css_minifier/src/compressor/color.rs @@ -284,7 +284,7 @@ impl Compressor { Some(*value / 100.0) } Some(ComponentValue::Ident(box Ident { value, .. })) - if value.to_ascii_lowercase() == js_word!("none") => + if value.eq_ignore_ascii_case(&js_word!("none")) => { Some(0.0) } @@ -321,7 +321,7 @@ impl Compressor { Some(value) } Some(ComponentValue::Ident(box Ident { value, .. })) - if value.to_ascii_lowercase() == js_word!("none") => + if value.eq_ignore_ascii_case(&js_word!("none")) => { Some(0.0) } @@ -344,7 +344,7 @@ impl Compressor { Some(*value / 100.0) } Some(ComponentValue::Ident(box Ident { value, .. })) - if value.to_ascii_lowercase() == js_word!("none") => + if value.eq_ignore_ascii_case(&js_word!("none")) => { Some(0.0) } @@ -379,7 +379,7 @@ impl Compressor { Some((2.55 * *value).round()) } Some(ComponentValue::Ident(box Ident { value, .. })) - if value.to_ascii_lowercase() == js_word!("none") => + if value.eq_ignore_ascii_case(&js_word!("none")) => { Some(0.0) } diff --git a/crates/swc_css_minifier/src/compressor/declaration.rs b/crates/swc_css_minifier/src/compressor/declaration.rs index 7bda7d80d493..0245006d5f61 100644 --- a/crates/swc_css_minifier/src/compressor/declaration.rs +++ b/crates/swc_css_minifier/src/compressor/declaration.rs @@ -16,34 +16,37 @@ impl Compressor { for value in declaration.value.iter() { match value { outside_node @ ComponentValue::Ident(box Ident { value, .. }) - if matches!( - value.to_ascii_lowercase(), - js_word!("block") | js_word!("inline") | js_word!("run-in") + if matches_eq_ignore_ascii_case!( + value, + js_word!("block"), + js_word!("inline"), + js_word!("run-in") ) => { outside = Some(outside_node); } inside_node @ ComponentValue::Ident(box Ident { value, .. }) - if matches!( - value.to_ascii_lowercase(), - js_word!("flow") - | js_word!("flow-root") - | js_word!("table") - | js_word!("flex") - | js_word!("grid") - | js_word!("ruby") + if matches_eq_ignore_ascii_case!( + value, + js_word!("flow"), + js_word!("flow-root"), + js_word!("table"), + js_word!("flex"), + js_word!("grid"), + js_word!("ruby") ) => { inside = Some(inside_node); } list_item_node @ ComponentValue::Ident(box Ident { value, .. }) - if value.to_ascii_lowercase() == js_word!("list-item") => + if value.eq_ignore_ascii_case(&js_word!("list-item")) => { if let Some(ComponentValue::Ident(box Ident { value, .. })) = inside { - if !matches!( - value.to_ascii_lowercase(), - js_word!("flow") | js_word!("flow-root") + if !matches_eq_ignore_ascii_case!( + value, + js_word!("flow"), + js_word!("flow-root") ) { continue; } @@ -66,7 +69,7 @@ impl Compressor { .. })), None, - ) if inside_value.to_ascii_lowercase() == js_word!("flow") => { + ) if inside_value.eq_ignore_ascii_case(&js_word!("flow")) => { declaration.value = vec![outside.clone()]; } // `block flow-root` -> `flow-root` @@ -82,8 +85,8 @@ impl Compressor { }), ), None, - ) if outside_value.to_ascii_lowercase() == js_word!("block") - && inside_value.to_ascii_lowercase() == js_word!("flow-root") => + ) if outside_value.eq_ignore_ascii_case(&js_word!("block")) + && inside_value.eq_ignore_ascii_case(&js_word!("flow-root")) => { declaration.value = vec![inside.clone()]; } @@ -99,8 +102,8 @@ impl Compressor { .. })), None, - ) if outside_value.to_ascii_lowercase() == js_word!("inline") - && inside_value.to_ascii_lowercase() == js_word!("flow-root") => + ) if outside_value.eq_ignore_ascii_case(&js_word!("inline")) + && inside_value.eq_ignore_ascii_case(&js_word!("flow-root")) => { declaration.value = vec![ComponentValue::Ident(Box::new(Ident { span: *span, @@ -119,8 +122,8 @@ impl Compressor { .. })), Some(list_item), - ) if outside_value.to_ascii_lowercase() == js_word!("block") - && inside_value.to_ascii_lowercase() == js_word!("flow") => + ) if outside_value.eq_ignore_ascii_case(&js_word!("block")) + && inside_value.eq_ignore_ascii_case(&js_word!("flow")) => { declaration.value = vec![list_item.clone()]; } @@ -132,7 +135,7 @@ impl Compressor { })), None, Some(list_item), - ) if outside_value.to_ascii_lowercase() == js_word!("block") => { + ) if outside_value.eq_ignore_ascii_case(&js_word!("block")) => { declaration.value = vec![list_item.clone()]; } // `flow list-item` -> `list-item` @@ -143,7 +146,7 @@ impl Compressor { .. })), Some(list_item), - ) if inside_value.to_ascii_lowercase() == js_word!("flow") => { + ) if inside_value.eq_ignore_ascii_case(&js_word!("flow")) => { declaration.value = vec![list_item.clone()]; } // `inline flow list-item` -> `inline list-item` @@ -159,8 +162,8 @@ impl Compressor { .. })), Some(list_item), - ) if outside_value.to_ascii_lowercase() == js_word!("inline") - && inside_value.to_ascii_lowercase() == js_word!("flow") => + ) if outside_value.eq_ignore_ascii_case(&js_word!("inline")) + && inside_value.eq_ignore_ascii_case(&js_word!("flow")) => { declaration.value = vec![outside.clone(), list_item.clone()]; } @@ -179,10 +182,12 @@ impl Compressor { }), ), None, - ) if outside_value.to_ascii_lowercase() == js_word!("block") - && matches!( - inside_value.to_ascii_lowercase(), - js_word!("flex") | js_word!("grid") | js_word!("table") + ) if outside_value.eq_ignore_ascii_case(&js_word!("block")) + && matches_eq_ignore_ascii_case!( + inside_value, + js_word!("flex"), + js_word!("grid"), + js_word!("table") ) => { declaration.value = vec![inside.clone()]; @@ -200,8 +205,8 @@ impl Compressor { }), ), None, - ) if outside_value.to_ascii_lowercase() == js_word!("inline") - && inside_value.to_ascii_lowercase() == js_word!("ruby") => + ) if outside_value.eq_ignore_ascii_case(&js_word!("inline")) + && inside_value.eq_ignore_ascii_case(&js_word!("ruby")) => { declaration.value = vec![inside.clone()]; } @@ -336,7 +341,7 @@ impl Compressor { .into_iter() .map(|node| match node { ComponentValue::Ident(box Ident { value, span, .. }) - if value.to_ascii_lowercase() == js_word!("normal") => + if value.eq_ignore_ascii_case(&js_word!("normal")) => { ComponentValue::Number(Box::new(Number { span, @@ -345,7 +350,7 @@ impl Compressor { })) } ComponentValue::Ident(box Ident { value, span, .. }) - if value.to_ascii_lowercase() == js_word!("bold") => + if value.eq_ignore_ascii_case(&js_word!("bold")) => { ComponentValue::Number(Box::new(Number { span, @@ -464,7 +469,7 @@ impl Compressor { let value = ident.value.to_ascii_lowercase(); match &*value { _ if crate::is_css_wide_keyword(&ident.value) - || ident.value.to_ascii_lowercase() == js_word!("none") => + || ident.value.eq_ignore_ascii_case(&js_word!("none")) => { node } @@ -512,7 +517,7 @@ impl Compressor { .. }))), ) if value_1.value == value_2.value - && unit_1.value.to_ascii_lowercase() == unit_2.value.to_ascii_lowercase() => + && unit_1.value.eq_ignore_ascii_case(&unit_2.value) => { true } @@ -552,7 +557,7 @@ impl Compressor { .. }))), ) if value_1.value == value_2.value - && unit_1.value.to_ascii_lowercase() == unit_2.value.to_ascii_lowercase() => + && unit_1.value.eq_ignore_ascii_case(&unit_2.value) => { true } @@ -586,6 +591,6 @@ impl Compressor { matches!((node_1, node_2), ( Some(ComponentValue::Ident(box Ident { value: value_1, .. })), Some(ComponentValue::Ident(box Ident { value: value_2, .. })), - ) if value_1.to_ascii_lowercase() == value_2.to_ascii_lowercase()) + ) if value_1.eq_ignore_ascii_case(value_2)) } } diff --git a/crates/swc_css_minifier/src/compressor/easing_function.rs b/crates/swc_css_minifier/src/compressor/easing_function.rs index 75c4865bf4d2..e6195ec79807 100644 --- a/crates/swc_css_minifier/src/compressor/easing_function.rs +++ b/crates/swc_css_minifier/src/compressor/easing_function.rs @@ -10,7 +10,7 @@ impl Compressor { name, value: function_value, span, - }) if name.value.to_ascii_lowercase() == js_word!("cubic-bezier") + }) if name.value.eq_ignore_ascii_case(&js_word!("cubic-bezier")) && function_value.len() == 7 => { if let ( @@ -61,7 +61,7 @@ impl Compressor { name, value: function_value, span, - }) if name.value.to_ascii_lowercase() == js_word!("steps") + }) if name.value.eq_ignore_ascii_case(&js_word!("steps")) && function_value.len() == 3 => { match (&function_value[0], &function_value[2]) { @@ -95,7 +95,7 @@ impl Compressor { ComponentValue::Ident(box Ident { value: ident_value, .. }), - ) if ident_value.to_ascii_lowercase() == js_word!("jump-start") => { + ) if ident_value.eq_ignore_ascii_case(&js_word!("jump-start")) => { function_value[2] = ComponentValue::Ident(Box::new(Ident { span: *span, value: js_word!("start"), diff --git a/crates/swc_css_minifier/src/compressor/keyframes.rs b/crates/swc_css_minifier/src/compressor/keyframes.rs index 5ec5f7477d21..e52f5d03d92c 100644 --- a/crates/swc_css_minifier/src/compressor/keyframes.rs +++ b/crates/swc_css_minifier/src/compressor/keyframes.rs @@ -10,7 +10,7 @@ impl Compressor { match at_rule.prelude.as_deref() { Some(AtRulePrelude::KeyframesPrelude(KeyframesName::Str(string))) if !is_css_wide_keyword(&string.value) - && string.value.to_ascii_lowercase() != js_word!("none") => + && !string.value.eq_ignore_ascii_case(&js_word!("none")) => { at_rule.prelude = Some(Box::new(AtRulePrelude::KeyframesPrelude( if self.is_ident_shorter_than_str(&string.value) { @@ -34,7 +34,7 @@ impl Compressor { pub(super) fn compress_keyframe_selector(&mut self, keyframe_selector: &mut KeyframeSelector) { match keyframe_selector { - KeyframeSelector::Ident(i) if i.value.to_ascii_lowercase() == js_word!("from") => { + KeyframeSelector::Ident(i) if i.value.eq_ignore_ascii_case(&js_word!("from")) => { *keyframe_selector = KeyframeSelector::Percentage(Percentage { span: i.span, value: Number { diff --git a/crates/swc_css_minifier/src/compressor/math/mod.rs b/crates/swc_css_minifier/src/compressor/math/mod.rs index 31fb1940b374..34b03b164534 100644 --- a/crates/swc_css_minifier/src/compressor/math/mod.rs +++ b/crates/swc_css_minifier/src/compressor/math/mod.rs @@ -2,9 +2,12 @@ use swc_atoms::js_word; use swc_css_ast::*; pub fn is_calc_function_name(ident: &Ident) -> bool { - ident.value.to_ascii_lowercase() == js_word!("calc") - || ident.value.to_ascii_lowercase() == js_word!("-webkit-calc") - || ident.value.to_ascii_lowercase() == js_word!("-moz-calc") + matches_eq_ignore_ascii_case!( + ident.value, + js_word!("calc"), + js_word!("-webkit-calc"), + js_word!("-moz-calc") + ) } pub fn transform_calc_value_into_component_value(calc_value: &CalcValue) -> Option { diff --git a/crates/swc_css_minifier/src/compressor/mod.rs b/crates/swc_css_minifier/src/compressor/mod.rs index 380c11d99beb..3fd7d1686911 100644 --- a/crates/swc_css_minifier/src/compressor/mod.rs +++ b/crates/swc_css_minifier/src/compressor/mod.rs @@ -100,19 +100,19 @@ impl VisitMut for Compressor { fn visit_mut_declaration(&mut self, n: &mut Declaration) { if let DeclarationName::Ident(Ident { value, .. }) = &n.name { - match value.to_ascii_lowercase() { - js_word!("opacity") - | js_word!("fill-opacity") - | js_word!("stroke-opacity") - | js_word!("shape-image-threshold") => { - n.visit_mut_children_with(&mut *self.with_ctx(Ctx { - preserve_alpha_value: false, - ..self.ctx - })); - } - _ => { - n.visit_mut_children_with(self); - } + if matches_eq_ignore_ascii_case!( + value, + js_word!("opacity"), + js_word!("fill-opacity"), + js_word!("stroke-opacity"), + js_word!("shape-image-threshold") + ) { + n.visit_mut_children_with(&mut *self.with_ctx(Ctx { + preserve_alpha_value: false, + ..self.ctx + })); + } else { + n.visit_mut_children_with(self); } } else { n.visit_mut_children_with(self); @@ -245,14 +245,14 @@ impl VisitMut for Compressor { fn visit_mut_pseudo_class_selector(&mut self, n: &mut PseudoClassSelector) { match &n.name { Ident { value, .. } - if matches!( - value.to_ascii_lowercase(), - js_word!("not") - | js_word!("is") - | js_word!("where") - | js_word!("matches") - | js_word!("-moz-any") - | js_word!("-webkit-any") + if matches_eq_ignore_ascii_case!( + value, + js_word!("not"), + js_word!("is"), + js_word!("where"), + js_word!("matches"), + js_word!("-moz-any"), + js_word!("-webkit-any") ) => { n.visit_mut_children_with(&mut *self.with_ctx(Ctx { @@ -325,23 +325,23 @@ impl VisitMut for Compressor { } fn visit_mut_function(&mut self, n: &mut Function) { - match n.name.value.to_ascii_lowercase() { - js_word!("rotate") - | js_word!("skew") - | js_word!("skewx") - | js_word!("skewy") - | js_word!("rotate3d") - | js_word!("rotatex") - | js_word!("rotatey") - | js_word!("rotatez") => { - n.visit_mut_children_with(&mut *self.with_ctx(Ctx { - in_transform_function: true, - ..self.ctx - })); - } - _ => { - n.visit_mut_children_with(self); - } + if matches_eq_ignore_ascii_case!( + n.name.value, + js_word!("rotate"), + js_word!("skew"), + js_word!("skewx"), + js_word!("skewy"), + js_word!("rotate3d"), + js_word!("rotatex"), + js_word!("rotatey"), + js_word!("rotatez") + ) { + n.visit_mut_children_with(&mut *self.with_ctx(Ctx { + in_transform_function: true, + ..self.ctx + })); + } else { + n.visit_mut_children_with(self); } } diff --git a/crates/swc_css_minifier/src/compressor/rules.rs b/crates/swc_css_minifier/src/compressor/rules.rs index c8b5a83c794d..1d5b69bd6253 100644 --- a/crates/swc_css_minifier/src/compressor/rules.rs +++ b/crates/swc_css_minifier/src/compressor/rules.rs @@ -312,14 +312,14 @@ impl Compressor { _ => return false, }; - match name.to_ascii_lowercase() { - js_word!("media") - | js_word!("supports") - | js_word!("container") - | js_word!("layer") - | js_word!("nest") => true, - _ => false, - } + matches_eq_ignore_ascii_case!( + name, + js_word!("media"), + js_word!("supports"), + js_word!("container"), + js_word!("layer"), + js_word!("nest") + ) } fn try_merge_at_rule(&mut self, left: &mut AtRule, right: &mut AtRule) -> Option { @@ -675,5 +675,5 @@ impl Compressor { } fn need_keep_by_name(name: &JsWord) -> bool { - matches!(name.to_ascii_lowercase(), js_word!("color-profile")) + matches_eq_ignore_ascii_case!(name, js_word!("color-profile")) } diff --git a/crates/swc_css_minifier/src/compressor/selector.rs b/crates/swc_css_minifier/src/compressor/selector.rs index e6675e06cf4b..a1ef73f818e7 100644 --- a/crates/swc_css_minifier/src/compressor/selector.rs +++ b/crates/swc_css_minifier/src/compressor/selector.rs @@ -63,7 +63,7 @@ impl Compressor { } // `even` => `2n` AnPlusB::Ident(Ident { value, span, .. }) - if value.to_ascii_lowercase() == js_word!("even") => + if value.eq_ignore_ascii_case(&js_word!("even")) => { *an_plus_b = AnPlusB::AnPlusBNotation(AnPlusBNotation { span: *span, @@ -110,18 +110,18 @@ impl Compressor { pub(super) fn compress_subclass_selector(&mut self, subclass_selector: &mut SubclassSelector) { match &subclass_selector { SubclassSelector::PseudoElement(PseudoElementSelector { name, span, .. }) => { - match name.value.to_ascii_lowercase() { - js_word!("before") - | js_word!("after") - | js_word!("first-letter") - | js_word!("first-line") => { - *subclass_selector = SubclassSelector::PseudoClass(PseudoClassSelector { - span: *span, - name: name.clone(), - children: None, - }) - } - _ => {} + if matches_eq_ignore_ascii_case!( + name.value, + js_word!("before"), + js_word!("after"), + js_word!("first-letter"), + js_word!("first-line") + ) { + *subclass_selector = SubclassSelector::PseudoClass(PseudoClassSelector { + span: *span, + name: name.clone(), + children: None, + }) } } SubclassSelector::PseudoClass(PseudoClassSelector { @@ -129,7 +129,7 @@ impl Compressor { children: Some(children), span, .. - }) if name.value.to_ascii_lowercase() == js_word!("nth-child") + }) if name.value.eq_ignore_ascii_case(&js_word!("nth-child")) && children.len() == 1 => { match children.get(0) { @@ -158,7 +158,9 @@ impl Compressor { children: Some(children), span, .. - }) if name.value.to_ascii_lowercase() == js_word!("nth-last-child") + }) if name + .value + .eq_str_ignore_ascii_case(&js_word!("nth-last-child")) && children.len() == 1 => { match children.get(0) { @@ -187,7 +189,7 @@ impl Compressor { children: Some(children), span, .. - }) if name.value.to_ascii_lowercase() == js_word!("nth-of-type") + }) if name.value.eq_ignore_ascii_case(&js_word!("nth-of-type")) && children.len() == 1 => { match children.get(0) { @@ -216,7 +218,9 @@ impl Compressor { children: Some(children), span, .. - }) if name.value.to_ascii_lowercase() == js_word!("nth-last-of-type") + }) if name + .value + .eq_ignore_ascii_case(&js_word!("nth-last-of-type")) && children.len() == 1 => { match children.get(0) { diff --git a/crates/swc_css_minifier/src/compressor/transform_function.rs b/crates/swc_css_minifier/src/compressor/transform_function.rs index 9e1d9ff3d031..6c06a2dc1c17 100644 --- a/crates/swc_css_minifier/src/compressor/transform_function.rs +++ b/crates/swc_css_minifier/src/compressor/transform_function.rs @@ -10,7 +10,7 @@ impl Compressor { name, value: function_value, .. - }) if name.value.to_ascii_lowercase() == js_word!("translate") + }) if name.value.eq_ignore_ascii_case(&js_word!("translate")) && function_value.len() == 3 => { match (function_value.get(0), function_value.get(2)) { @@ -44,7 +44,7 @@ impl Compressor { name, value: function_value, .. - }) if name.value.to_ascii_lowercase() == js_word!("translate3d") + }) if name.value.eq_ignore_ascii_case(&js_word!("translate3d")) && function_value.len() == 5 => { match ( @@ -77,7 +77,7 @@ impl Compressor { name, value: function_value, .. - }) if name.value.to_ascii_lowercase() == js_word!("scale") + }) if name.value.eq_ignore_ascii_case(&js_word!("scale")) && function_value.len() == 3 => { match (function_value.get(0), function_value.get(2)) { @@ -130,7 +130,7 @@ impl Compressor { name, value: function_value, .. - }) if name.value.to_ascii_lowercase() == js_word!("scale3d") + }) if name.value.eq_ignore_ascii_case(&js_word!("scale3d")) && function_value.len() == 5 => { match ( @@ -199,7 +199,7 @@ impl Compressor { name, value: function_value, .. - }) if name.value.to_ascii_lowercase() == js_word!("matrix3d") + }) if name.value.eq_ignore_ascii_case(&js_word!("matrix3d")) && function_value.len() == 31 => { match ( @@ -314,7 +314,7 @@ impl Compressor { name, value: function_value, .. - }) if name.value.to_ascii_lowercase() == js_word!("rotate3d") + }) if name.value.eq_ignore_ascii_case(&js_word!("rotate3d")) && function_value.len() == 7 => { match ( @@ -396,7 +396,7 @@ impl Compressor { name, value: function_value, .. - }) if name.value.to_ascii_lowercase() == js_word!("rotatez") + }) if name.value.eq_ignore_ascii_case(&js_word!("rotatez")) && function_value.len() == 1 => { *name = Ident { @@ -410,7 +410,7 @@ impl Compressor { name, value: function_value, .. - }) if name.value.to_ascii_lowercase() == js_word!("skew") + }) if name.value.eq_ignore_ascii_case(&js_word!("skew")) && function_value.len() == 3 => { match (function_value.get(0), function_value.get(2)) { diff --git a/crates/swc_css_minifier/src/compressor/url.rs b/crates/swc_css_minifier/src/compressor/url.rs index bda458d731b8..9dbddc670350 100644 --- a/crates/swc_css_minifier/src/compressor/url.rs +++ b/crates/swc_css_minifier/src/compressor/url.rs @@ -5,7 +5,7 @@ use super::Compressor; impl Compressor { pub(super) fn compress_url(&self, url: &mut Url) { - if url.name.value.to_ascii_lowercase() != js_word!("url") { + if !url.name.value.eq_ignore_ascii_case(&js_word!("url")) { return; } diff --git a/crates/swc_css_minifier/src/lib.rs b/crates/swc_css_minifier/src/lib.rs index 53bf647ef13f..5d246e243a1c 100644 --- a/crates/swc_css_minifier/src/lib.rs +++ b/crates/swc_css_minifier/src/lib.rs @@ -19,15 +19,15 @@ pub fn minify(stylesheet: &mut Stylesheet, _options: MinifyOptions) { #[inline] fn is_css_wide_keyword(ident: &JsWord) -> bool { - match ident.to_ascii_lowercase() { + matches_eq_ignore_ascii_case!( + ident, // CSS Values and Units Level 3: https://drafts.csswg.org/css-values-3/#common-keywords - | js_word!("initial") - | js_word!("inherit") - | js_word!("unset") - | js_word!("default") + js_word!("initial"), + js_word!("inherit"), + js_word!("unset"), + js_word!("default"), // CSS Cascading and Inheritance Level 5: https://drafts.csswg.org/css-cascade-5/#defaulting-keywords - | js_word!("revert") - | js_word!("revert-layer") => true, - _ => false - } + js_word!("revert"), + js_word!("revert-layer") + ) } diff --git a/crates/swc_css_parser/src/lexer/mod.rs b/crates/swc_css_parser/src/lexer/mod.rs index 4d1441406771..8a4778723b0d 100644 --- a/crates/swc_css_parser/src/lexer/mod.rs +++ b/crates/swc_css_parser/src/lexer/mod.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, char::REPLACEMENT_CHARACTER, rc::Rc}; use swc_atoms::{js_word, Atom, JsWord}; use swc_common::{input::Input, BytePos, Span}; -use swc_css_ast::{DimensionToken, NumberType, Token, TokenAndSpan}; +use swc_css_ast::{matches_eq_ignore_ascii_case, DimensionToken, NumberType, Token, TokenAndSpan}; use crate::{ error::{Error, ErrorKind}, @@ -566,7 +566,9 @@ where // If string’s value is an ASCII case-insensitive match for "url", and the next // input code point is U+0028 LEFT PARENTHESIS ((), consume it. - if ident_sequence.0.to_ascii_lowercase() == js_word!("url") && self.next() == Some('(') { + if matches_eq_ignore_ascii_case!(ident_sequence.0, js_word!("url")) + && self.next() == Some('(') + { self.consume(); let start_whitespace = self.input.last_pos(); diff --git a/crates/swc_css_parser/src/parser/at_rules/mod.rs b/crates/swc_css_parser/src/parser/at_rules/mod.rs index be522e1975c8..e4e9b4ae744d 100644 --- a/crates/swc_css_parser/src/parser/at_rules/mod.rs +++ b/crates/swc_css_parser/src/parser/at_rules/mod.rs @@ -175,7 +175,9 @@ where let layer_name = if !is!(self, EOF) { match cur!(self) { - Token::Ident { value, .. } if *value.to_ascii_lowercase() == *"layer" => { + Token::Ident { value, .. } + if matches_eq_ignore_ascii_case!(value, js_word!("layer")) => + { let name = ImportLayerName::Ident(self.parse()?); self.input.skip_ws(); @@ -183,7 +185,7 @@ where Some(Box::new(name)) } Token::Function { value, .. } - if *value.to_ascii_lowercase() == *"layer" => + if matches_eq_ignore_ascii_case!(value, js_word!("layer")) => { let ctx = Ctx { in_import_at_rule: true, @@ -772,7 +774,9 @@ where let supports = if !is!(self, EOF) { match cur!(self) { - Token::Function { value, .. } if *value.to_ascii_lowercase() == *"supports" => { + Token::Function { value, .. } + if matches_eq_ignore_ascii_case!(value, js_word!("supports")) => + { let ctx = Ctx { in_import_at_rule: true, ..self.ctx @@ -820,8 +824,11 @@ where match cur!(self) { Token::Function { value, .. } - if (&*value.to_ascii_lowercase() == "local" - || &*value.to_ascii_lowercase() == "global") => + if matches_eq_ignore_ascii_case!( + value, + js_word!("local"), + js_word!("global") + ) => { let span = self.input.cur_span(); let pseudo = match bump!(self) { @@ -852,8 +859,11 @@ where ))) } Token::Ident { value, .. } - if (&*value.to_ascii_lowercase() == "local" - || &*value.to_ascii_lowercase() == "global") => + if matches_eq_ignore_ascii_case!( + value, + js_word!("local"), + js_word!("global") + ) => { let pseudo = self.parse()?; @@ -882,7 +892,7 @@ where tok!("ident") => { let custom_ident: CustomIdent = self.parse()?; - if &*custom_ident.value.to_ascii_lowercase() == "none" { + if matches_eq_ignore_ascii_case!(custom_ident.value, js_word!("none")) { return Err(Error::new( custom_ident.span, ErrorKind::InvalidCustomIdent(custom_ident.value), @@ -1176,7 +1186,9 @@ where Ok(SupportsFeature::Declaration(Box::new(declaration))) } - Token::Function { value, .. } if &*value.to_ascii_lowercase() == "selector" => { + Token::Function { value, .. } + if matches_eq_ignore_ascii_case!(&**value, "selector") => + { // TODO improve me let ctx = Ctx { in_supports_at_rule: true, @@ -1280,9 +1292,7 @@ where value: function_name, .. } => { - if &*function_name.to_ascii_lowercase() == "url" - || &*function_name.to_ascii_lowercase() == "src" - { + if matches_eq_ignore_ascii_case!(function_name, js_word!("url"), js_word!("src")) { Ok(DocumentPreludeMatchingFunction::Url(self.parse()?)) } else { // TODO improve me @@ -1985,10 +1995,7 @@ where let value = match cur!(self) { Token::Ident { value, .. } - if matches!( - &*value.to_ascii_lowercase(), - "left" | "right" | "first" | "blank" - ) => + if matches_eq_ignore_ascii_case!(&**value, "left", "right", "first", "blank") => { self.parse()? } diff --git a/crates/swc_css_parser/src/parser/macros.rs b/crates/swc_css_parser/src/parser/macros.rs index c8cccfe9837f..0283fd2366d1 100644 --- a/crates/swc_css_parser/src/parser/macros.rs +++ b/crates/swc_css_parser/src/parser/macros.rs @@ -73,7 +73,7 @@ macro_rules! is_case_insensitive_ident { ($parser:expr, $tt:tt) => {{ match $parser.input.cur() { Some(swc_css_ast::Token::Ident { value, .. }) - if &*value.to_ascii_lowercase() == $tt => + if (&**value).eq_ignore_ascii_case($tt) => { true } @@ -86,9 +86,7 @@ macro_rules! is_one_of_case_insensitive_ident { ($parser:expr, $($tt:tt),+) => { match $parser.input.cur() { Some(swc_css_ast::Token::Ident { value, .. }) => { - let lowercased = &*value.to_ascii_lowercase(); - - if $(lowercased == $tt)||* { + if $((&**value).eq_ignore_ascii_case($tt))||* { true } else { false diff --git a/crates/swc_css_parser/src/parser/selectors/mod.rs b/crates/swc_css_parser/src/parser/selectors/mod.rs index c318e09c38e5..79e14373bc39 100644 --- a/crates/swc_css_parser/src/parser/selectors/mod.rs +++ b/crates/swc_css_parser/src/parser/selectors/mod.rs @@ -1,3 +1,4 @@ +use swc_atoms::js_word; use swc_common::{BytePos, Span, Spanned}; use swc_css_ast::*; @@ -1187,8 +1188,7 @@ where match cur!(self) { // odd | even Token::Ident { value, .. } - if &(*value).to_ascii_lowercase() == "odd" - || &(*value).to_ascii_lowercase() == "even" => + if matches_eq_ignore_ascii_case!(value, js_word!("odd"), js_word!("even")) => { Ok(AnPlusB::Ident(self.parse()?)) } diff --git a/crates/swc_css_parser/src/parser/syntax/mod.rs b/crates/swc_css_parser/src/parser/syntax/mod.rs index ba67b45fbdb7..9efae7729416 100644 --- a/crates/swc_css_parser/src/parser/syntax/mod.rs +++ b/crates/swc_css_parser/src/parser/syntax/mod.rs @@ -692,7 +692,7 @@ where .. }, ) if exclamation_point_span.is_some() - && value.to_ascii_lowercase() == js_word!("important") => + && matches_eq_ignore_ascii_case!(value, js_word!("important")) => { important_ident = Some(token_and_span.clone()); } diff --git a/crates/swc_css_parser/src/parser/values_and_units/mod.rs b/crates/swc_css_parser/src/parser/values_and_units/mod.rs index d5566b6be551..3727f25adf11 100644 --- a/crates/swc_css_parser/src/parser/values_and_units/mod.rs +++ b/crates/swc_css_parser/src/parser/values_and_units/mod.rs @@ -78,7 +78,7 @@ where Token::Ident { value, .. } => { if value.starts_with("--") { return Ok(ComponentValue::DashedIdent(self.parse()?)); - } else if &*value.to_ascii_lowercase() == "u" + } else if matches_eq_ignore_ascii_case!(value, js_word!("u")) && peeked_is_one_of!(self, "+", "number", "dimension") { return Ok(ComponentValue::UnicodeRange(self.parse()?)); @@ -371,7 +371,9 @@ where let mut is_legacy_syntax = true; match cur!(self) { - Token::Ident { value, .. } if &*value.to_ascii_lowercase() == "from" => { + Token::Ident { value, .. } + if matches_eq_ignore_ascii_case!(value, js_word!("from")) => + { is_legacy_syntax = false; values.push(ComponentValue::Ident(self.parse()?)); @@ -806,7 +808,7 @@ where match cur!(self) { Token::Ident { value, .. } - if &*value.to_ascii_lowercase() == "from" + if matches_eq_ignore_ascii_case!(value, js_word!("from")) && function_name != "device-cmyk" => { values.push(ComponentValue::Ident(self.parse()?)); @@ -1282,7 +1284,9 @@ where let mut has_variable = false; match cur!(self) { - Token::Ident { value, .. } if &*value.to_ascii_lowercase() == "from" => { + Token::Ident { value, .. } + if matches_eq_ignore_ascii_case!(value, js_word!("from")) => + { values.push(ComponentValue::Ident(self.parse()?)); self.input.skip_ws(); @@ -1312,15 +1316,16 @@ where Ok(Some(ComponentValue::DashedIdent(parser.parse()?))) } else { - match &*value.to_ascii_lowercase() { - "xyz" | "xyz-d50" | "xyz-d65" => is_xyz = true, - _ => { - // There are predefined-rgb-params , but - // For unknown, we don't return an error - // to - // continue to support invalid color, - // because they fallback in browser - } + if matches_eq_ignore_ascii_case!( + &**value, "xyz", "xyz-d50", "xyz-d65" + ) { + is_xyz = true + } else { + // There are predefined-rgb-params , but + // For unknown, we don't return an error + // to + // continue to support invalid color, + // because they fallback in browser } Ok(Some(ComponentValue::Ident(parser.parse()?))) @@ -1397,9 +1402,8 @@ where } Token::Function { value, .. } if is_math_function(value) - || matches!( - &*value.to_ascii_lowercase(), - "var" | "env" | "constant" + || matches_eq_ignore_ascii_case!( + &**value, "var", "env", "constant" ) => { ComponentValue::Function(self.parse()?) @@ -1674,7 +1678,7 @@ where match cur!(self) { Token::Function { value, .. } - if matches!(&*value.to_ascii_lowercase(), "var" | "env" | "constant") => + if matches_eq_ignore_ascii_case!(&**value, "var", "env", "constant") => { *has_before_variable = true; @@ -1807,11 +1811,10 @@ where match bump!(self) { Token::Ident { value, raw, .. } => { - match &*value.to_ascii_lowercase() { - "initial" | "inherit" | "unset" | "revert" | "default" => { - return Err(Error::new(span, ErrorKind::InvalidCustomIdent(value))); - } - _ => {} + if matches_eq_ignore_ascii_case!( + &*value, "initial", "inherit", "unset", "revert", "default" + ) { + return Err(Error::new(span, ErrorKind::InvalidCustomIdent(value))); } Ok(CustomIdent { @@ -2564,9 +2567,7 @@ where value: function_name, raw: raw_function_name, } => { - if &*function_name.to_ascii_lowercase() != "url" - && &*function_name.to_ascii_lowercase() != "src" - { + if !matches_eq_ignore_ascii_case!(function_name, js_word!("url"), js_word!("src")) { return Err(Error::new( span, ErrorKind::Expected("'url' or 'src' name of a function token"), @@ -2645,7 +2646,7 @@ where // should start with `u` or `U` match cur!(self) { - Token::Ident { value, .. } if &*value.to_ascii_lowercase() == "u" => { + Token::Ident { value, .. } if matches_eq_ignore_ascii_case!(value, js_word!("u")) => { let ident = match bump!(self) { Token::Ident { value, .. } => value, _ => { @@ -3604,28 +3605,25 @@ fn is_length_unit(unit: &str) -> bool { } fn is_container_lengths_unit(unit: &str) -> bool { - matches!( - &*unit.to_ascii_lowercase(), - "cqw" | "cqh" | "cqi" | "cqb" | "cqmin" | "cqmax" - ) + matches_eq_ignore_ascii_case!(unit, "cqw", "cqh", "cqi", "cqb", "cqmin", "cqmax") } fn is_angle_unit(unit: &str) -> bool { - matches!(&*unit.to_ascii_lowercase(), "deg" | "grad" | "rad" | "turn") + matches_eq_ignore_ascii_case!(unit, "deg", "grad", "rad", "turn") } fn is_time_unit(unit: &str) -> bool { - matches!(&*unit.to_ascii_lowercase(), "s" | "ms") + matches_eq_ignore_ascii_case!(unit, "s", "ms") } fn is_frequency_unit(unit: &str) -> bool { - matches!(&*unit.to_ascii_lowercase(), "hz" | "khz") + matches_eq_ignore_ascii_case!(unit, "hz", "khz") } fn is_resolution_unit(unit: &str) -> bool { - matches!(&*unit.to_ascii_lowercase(), "dpi" | "dpcm" | "dppx" | "x") + matches_eq_ignore_ascii_case!(unit, "dpi", "dpcm", "dppx", "x") } fn is_flex_unit(unit: &str) -> bool { - matches!(&*unit.to_ascii_lowercase(), "fr") + matches_eq_ignore_ascii_case!(unit, "fr") } diff --git a/crates/swc_css_prefixer/src/prefixer.rs b/crates/swc_css_prefixer/src/prefixer.rs index e2ab9db30a7d..2ed9691b44ae 100644 --- a/crates/swc_css_prefixer/src/prefixer.rs +++ b/crates/swc_css_prefixer/src/prefixer.rs @@ -127,7 +127,7 @@ impl VisitMut for CrossFadeFunctionReplacerOnLegacyVariant<'_> { fn visit_mut_function(&mut self, n: &mut Function) { n.visit_mut_children_with(self); - if &*n.name.value.to_lowercase() == self.from { + if n.name.value.eq_str_ignore_ascii_case(self.from) { let mut transparency_values = vec![]; for group in n.value.split_mut(|n| { @@ -269,7 +269,7 @@ impl VisitMut for ImageSetFunctionReplacerOnLegacyVariant<'_> { n.visit_mut_children_with(self); - if &*n.name.value.to_lowercase() == self.from { + if n.name.value.eq_str_ignore_ascii_case(self.from) { n.name.value = self.to.into(); n.name.raw = None; } @@ -300,7 +300,7 @@ impl VisitMut for LinearGradientFunctionReplacerOnLegacyVariant<'_> { fn visit_mut_function(&mut self, n: &mut Function) { n.visit_mut_children_with(self); - if &*n.name.value.to_lowercase() == self.from { + if &*n.name.value.to_ascii_lowercase() == self.from { n.name.value = self.to.into(); n.name.raw = None; @@ -485,14 +485,14 @@ impl VisitMut for MediaFeatureResolutionReplacerOnLegacyVariant<'_> { .. }) = &n.name; - if &*feature_name_value.to_lowercase() == self.from { + if &*feature_name_value.to_ascii_lowercase() == self.from { n.name = MediaFeatureName::Ident(Ident { span: *feature_name_span, value: self.to.into(), raw: None, }); - let left = match &*resolution_unit.value.to_lowercase() { + let left = match &*resolution_unit.value.to_ascii_lowercase() { "dpi" => (resolution_value.value / 96.0 * 100.0).round() / 100.0, "dpcm" => (((resolution_value.value * 2.54) / 96.0) * 100.0).round() / 100.0, _ => resolution_value.value, @@ -1472,7 +1472,7 @@ impl VisitMut for Prefixer { }}; } - let property_name = &*name.to_lowercase(); + let property_name = &*name.to_ascii_lowercase(); match property_name { "appearance" => { @@ -1484,7 +1484,7 @@ impl VisitMut for Prefixer { "animation" => { let need_prefix = n.value.iter().all(|n| match n { ComponentValue::Ident(ident) => !matches!( - &*ident.value.to_lowercase(), + &*ident.value.to_ascii_lowercase(), "reverse" | "alternate-reverse" ), _ => true, @@ -1517,7 +1517,7 @@ impl VisitMut for Prefixer { "animation-direction" => { if let ComponentValue::Ident(ident) = &n.value[0] { - match &*ident.value.to_lowercase() { + match &*ident.value.to_ascii_lowercase() { "alternate-reverse" | "reverse" => {} _ => { add_declaration!(Prefix::Webkit, "-webkit-animation-direction", None); @@ -1554,7 +1554,7 @@ impl VisitMut for Prefixer { "background-clip" => { if let ComponentValue::Ident(ident) = &n.value[0] { - if &*ident.value.to_lowercase() == "text" { + if &*ident.value.to_ascii_lowercase() == "text" { add_declaration!(Prefix::Webkit, "-webkit-background-clip", None); } } @@ -1886,7 +1886,7 @@ impl VisitMut for Prefixer { "flex-flow" => { let is_single_flex_wrap = matches!(n.value.get(0), Some(ComponentValue::Ident(box Ident { value, .. })) if n.value.len() == 1 && matches!( - &*value.to_lowercase(), + &*value.to_ascii_lowercase(), "wrap" | "nowrap" | "wrap-reverse" )); @@ -2313,7 +2313,7 @@ impl VisitMut for Prefixer { add_declaration!(Prefix::Moz, "-moz-user-select", None); if let ComponentValue::Ident(ident) = &n.value[0] { - match &*ident.value.to_lowercase() { + match &*ident.value.to_ascii_lowercase() { "contain" => { add_declaration!( Prefix::Ms, @@ -2335,18 +2335,18 @@ impl VisitMut for Prefixer { let has_3d_function = n.value.iter().any(|n| match n { ComponentValue::Function(function) - if matches!( - &*function.name.value.to_ascii_lowercase(), - "matrix3d" - | "translate3d" - | "translatez" - | "scale3d" - | "scalez" - | "rotate3d" - | "rotatex" - | "rotatey" - | "rotatez" - | "perspective" + if matches_eq_ignore_ascii_case!( + &*function.name.value, + "matrix3d", + "translate3d", + "translatez", + "scale3d", + "scalez", + "rotate3d", + "rotatex", + "rotatey", + "rotatez", + "perspective" ) => { true @@ -2394,7 +2394,7 @@ impl VisitMut for Prefixer { match &n.value[0] { ComponentValue::Ident(ident) if matches!( - &*ident.value.to_lowercase(), + &*ident.value.to_ascii_lowercase(), "none" | "underline" | "overline" @@ -2437,7 +2437,7 @@ impl VisitMut for Prefixer { "text-decoration-skip-ink" => { if let ComponentValue::Ident(ident) = &n.value[0] { - match &*ident.value.to_lowercase() { + match &*ident.value.to_ascii_lowercase() { "auto" => { add_declaration!( Prefix::Webkit, @@ -2458,7 +2458,7 @@ impl VisitMut for Prefixer { "text-size-adjust" if n.value.len() == 1 => { if let ComponentValue::Ident(ident) = &n.value[0] { - if &*ident.value.to_lowercase() == "none" { + if &*ident.value.to_ascii_lowercase() == "none" { add_declaration!(Prefix::Webkit, "-webkit-text-size-adjust", None); add_declaration!(Prefix::Moz, "-moz-text-size-adjust", None); add_declaration!(Prefix::Ms, "-ms-text-size-adjust", None); @@ -2565,7 +2565,7 @@ impl VisitMut for Prefixer { }; if let ComponentValue::Ident(ident) = &n.value[0] { - match &*ident.value.to_lowercase() { + match &*ident.value.to_ascii_lowercase() { "vertical-lr" => { add_declaration!(Prefix::Webkit, "-webkit-writing-mode", None); @@ -2935,7 +2935,7 @@ impl VisitMut for Prefixer { "overscroll-behavior" => { if let ComponentValue::Ident(ident) = &n.value[0] { - match &*ident.value.to_lowercase() { + match &*ident.value.to_ascii_lowercase() { "auto" => { add_declaration!( Prefix::Ms, @@ -2970,7 +2970,7 @@ impl VisitMut for Prefixer { "break-inside" => { if let ComponentValue::Ident(ident) = &n.value[0] { - match &*ident.value.to_lowercase() { + match &*ident.value.to_ascii_lowercase() { "auto" | "avoid" => { add_declaration!(Prefix::Webkit, "-webkit-column-break-inside", None); } @@ -2981,7 +2981,7 @@ impl VisitMut for Prefixer { "break-before" => { if let ComponentValue::Ident(ident) = &n.value[0] { - match &*ident.value.to_lowercase() { + match &*ident.value.to_ascii_lowercase() { "auto" | "avoid" => { add_declaration!(Prefix::Webkit, "-webkit-column-break-before", None); } @@ -2999,7 +2999,7 @@ impl VisitMut for Prefixer { "break-after" => { if let ComponentValue::Ident(ident) = &n.value[0] { - match &*ident.value.to_lowercase() { + match &*ident.value.to_ascii_lowercase() { "auto" | "avoid" => { add_declaration!(Prefix::Webkit, "-webkit-column-break-after", None); } diff --git a/crates/swc_css_utils/src/lib.rs b/crates/swc_css_utils/src/lib.rs index b12c8ba8b373..7ee85a1c1b4b 100644 --- a/crates/swc_css_utils/src/lib.rs +++ b/crates/swc_css_utils/src/lib.rs @@ -18,7 +18,7 @@ impl VisitMut for IdentReplacer<'_> { fn visit_mut_ident(&mut self, n: &mut Ident) { n.visit_mut_children_with(self); - if &*n.value.to_lowercase() == self.from { + if n.value.eq_str_ignore_ascii_case(self.from) { n.value = self.to.into(); n.raw = None; } @@ -41,7 +41,7 @@ impl VisitMut for FunctionNameReplacer<'_> { fn visit_mut_function(&mut self, n: &mut Function) { n.visit_mut_children_with(self); - if &*n.name.value.to_lowercase() == self.from { + if n.name.value.eq_str_ignore_ascii_case(self.from) { n.name.value = self.to.into(); n.name.raw = None; } @@ -64,7 +64,7 @@ impl VisitMut for PseudoClassSelectorNameReplacer<'_> { fn visit_mut_pseudo_class_selector(&mut self, n: &mut PseudoClassSelector) { n.visit_mut_children_with(self); - if &*n.name.value.to_lowercase() == self.from { + if n.name.value.eq_str_ignore_ascii_case(self.from) { n.name.value = self.to.into(); n.name.raw = None; } @@ -87,7 +87,7 @@ impl VisitMut for PseudoElementSelectorNameReplacer<'_> { fn visit_mut_pseudo_element_selector(&mut self, n: &mut PseudoElementSelector) { n.visit_mut_children_with(self); - if &*n.name.value.to_lowercase() == self.from { + if n.name.value.eq_str_ignore_ascii_case(self.from) { n.name.value = self.to.into(); n.name.raw = None; } @@ -112,7 +112,7 @@ impl VisitMut for PseudoElementOnPseudoClassReplacer<'_> { match n { SubclassSelector::PseudoElement(PseudoElementSelector { name, span, .. }) - if &*name.value.to_lowercase() == self.from => + if name.value.eq_str_ignore_ascii_case(self.from) => { *n = SubclassSelector::PseudoClass(PseudoClassSelector { span: *span,