mirror of
https://github.com/swc-project/swc.git
synced 2024-12-25 14:43:33 +03:00
fix(css/prefixer): Handle supports (#5503)
This commit is contained in:
parent
916af18b8f
commit
dc98234fab
@ -3,6 +3,7 @@ use std::mem::take;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use preset_env_base::{query::targets_to_versions, version::Version, BrowserData, Versions};
|
||||
use swc_atoms::js_word;
|
||||
use swc_common::{
|
||||
collections::{AHashMap, AHashSet},
|
||||
EqIgnoreSpan, DUMMY_SP,
|
||||
@ -548,6 +549,7 @@ pub enum Prefix {
|
||||
struct Prefixer {
|
||||
env: Versions,
|
||||
in_keyframe_block: bool,
|
||||
supports_condition: Option<SupportsCondition>,
|
||||
simple_block: Option<SimpleBlock>,
|
||||
rule_prefix: Option<Prefix>,
|
||||
added_top_rules: Vec<(Prefix, Rule)>,
|
||||
@ -601,7 +603,8 @@ impl VisitMut for Prefixer {
|
||||
stylesheet.rules = new_rules;
|
||||
}
|
||||
|
||||
// TODO handle declarations in `@media`/`@support`
|
||||
// TODO `@import` test
|
||||
// TODO `selector()` supports
|
||||
fn visit_mut_at_rule(&mut self, at_rule: &mut AtRule) {
|
||||
let original_simple_block = at_rule.block.clone();
|
||||
|
||||
@ -698,6 +701,67 @@ impl VisitMut for Prefixer {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_supports_condition(&mut self, supports_condition: &mut SupportsCondition) {
|
||||
let old_supports_condition = self.supports_condition.take();
|
||||
|
||||
self.supports_condition = Some(supports_condition.clone());
|
||||
|
||||
supports_condition.visit_mut_children_with(self);
|
||||
|
||||
self.supports_condition = old_supports_condition;
|
||||
}
|
||||
|
||||
fn visit_mut_supports_in_parens(&mut self, supports_in_parens: &mut SupportsInParens) {
|
||||
supports_in_parens.visit_mut_children_with(self);
|
||||
|
||||
if let Some(supports_condition) = &self.supports_condition {
|
||||
match supports_in_parens {
|
||||
SupportsInParens::Feature(_) if !self.added_declarations.is_empty() => {
|
||||
let mut conditions = Vec::with_capacity(1 + self.added_declarations.len());
|
||||
|
||||
conditions.push(swc_css_ast::SupportsConditionType::SupportsInParens(
|
||||
supports_in_parens.clone(),
|
||||
));
|
||||
|
||||
for n in take(&mut self.added_declarations) {
|
||||
let supports_condition_type = SupportsConditionType::Or(SupportsOr {
|
||||
span: DUMMY_SP,
|
||||
keyword: Ident {
|
||||
span: DUMMY_SP,
|
||||
value: js_word!("or"),
|
||||
raw: None,
|
||||
},
|
||||
condition: SupportsInParens::Feature(SupportsFeature::Declaration(n)),
|
||||
});
|
||||
|
||||
let need_skip =
|
||||
supports_condition
|
||||
.conditions
|
||||
.iter()
|
||||
.any(|existing_condition_type| {
|
||||
supports_condition_type.eq_ignore_span(existing_condition_type)
|
||||
});
|
||||
|
||||
if need_skip {
|
||||
continue;
|
||||
}
|
||||
|
||||
conditions.push(supports_condition_type);
|
||||
}
|
||||
|
||||
if conditions.len() > 1 {
|
||||
*supports_in_parens =
|
||||
SupportsInParens::SupportsCondition(SupportsCondition {
|
||||
span: DUMMY_SP,
|
||||
conditions,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_media_query_list(&mut self, media_query_list: &mut MediaQueryList) {
|
||||
media_query_list.visit_mut_children_with(self);
|
||||
|
||||
@ -1020,7 +1084,7 @@ impl VisitMut for Prefixer {
|
||||
|
||||
self.simple_block = Some(simple_block.clone());
|
||||
|
||||
let mut new = vec![];
|
||||
let mut new = Vec::with_capacity(simple_block.value.len());
|
||||
|
||||
for mut n in take(&mut simple_block.value) {
|
||||
n.visit_mut_children_with(self);
|
||||
@ -1117,10 +1181,6 @@ impl VisitMut for Prefixer {
|
||||
fn visit_mut_declaration(&mut self, n: &mut Declaration) {
|
||||
n.visit_mut_children_with(self);
|
||||
|
||||
if self.simple_block.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
if n.value.is_empty() {
|
||||
return;
|
||||
}
|
||||
@ -1285,22 +1345,27 @@ impl VisitMut for Prefixer {
|
||||
let mut ms_value = n.value.clone();
|
||||
|
||||
let declarations = Lazy::new(|| {
|
||||
let simple_block = self.simple_block.as_ref().unwrap();
|
||||
let mut declarations = Vec::with_capacity(simple_block.value.len());
|
||||
if let Some(simple_block) = &self.simple_block {
|
||||
let mut declarations = Vec::with_capacity(simple_block.value.len());
|
||||
|
||||
for n in simple_block.value.iter() {
|
||||
match n {
|
||||
ComponentValue::DeclarationOrAtRule(DeclarationOrAtRule::Declaration(
|
||||
declaration,
|
||||
)) => declarations.push(declaration),
|
||||
ComponentValue::StyleBlock(StyleBlock::Declaration(declaration)) => {
|
||||
declarations.push(declaration)
|
||||
for n in simple_block.value.iter() {
|
||||
match n {
|
||||
ComponentValue::DeclarationOrAtRule(DeclarationOrAtRule::Declaration(
|
||||
declaration,
|
||||
)) => {
|
||||
declarations.push(declaration);
|
||||
}
|
||||
ComponentValue::StyleBlock(StyleBlock::Declaration(declaration)) => {
|
||||
declarations.push(declaration);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
declarations
|
||||
declarations
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
});
|
||||
|
||||
let properties = Lazy::new(|| {
|
||||
|
@ -244,7 +244,7 @@ a {
|
||||
-ms-flex-direction: inherit;
|
||||
flex-direction: inherit;
|
||||
}
|
||||
@supports (display: flex) {
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
.foo {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
@ -253,7 +253,7 @@ a {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports (flex: auto) {
|
||||
@supports ((flex: auto) or (-webkit-box-flex: 1) or (-webkit-flex: auto) or (-moz-box-flex: 1) or (-ms-flex: auto)) {
|
||||
.foo {
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex: auto;
|
||||
|
@ -103,7 +103,7 @@ a {
|
||||
order: inherit;
|
||||
flex-direction: inherit;
|
||||
}
|
||||
@supports (display: flex) {
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
.foo {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
|
@ -18,7 +18,7 @@
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
@supports (flex-wrap: wrap) {
|
||||
@supports ((flex-wrap: wrap) or (-webkit-flex-wrap: wrap) or (-ms-flex-wrap: wrap)) {
|
||||
@-webkit-keyframes test {
|
||||
0% {
|
||||
color: red;
|
||||
@ -40,8 +40,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@supports (flex-wrap: wrap) {
|
||||
@supports (flex-wrap: wrap) {
|
||||
@supports ((flex-wrap: wrap) or (-webkit-flex-wrap: wrap) or (-ms-flex-wrap: wrap)) {
|
||||
@supports ((flex-wrap: wrap) or (-webkit-flex-wrap: wrap) or (-ms-flex-wrap: wrap)) {
|
||||
@-webkit-keyframes test {
|
||||
0% {
|
||||
color: red;
|
||||
@ -59,8 +59,6 @@
|
||||
}
|
||||
@keyframes test {
|
||||
0% {
|
||||
-webkit-flex-wrap: wrap;
|
||||
-ms-flex-wrap: wrap;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
@ -19,10 +19,8 @@
|
||||
-ms-appearance: auto;
|
||||
appearance: auto;
|
||||
}
|
||||
@supports (flex-wrap: wrap) {
|
||||
@supports ((flex-wrap: wrap) or (-webkit-flex-wrap: wrap) or (-ms-flex-wrap: wrap)) {
|
||||
.foo {
|
||||
-webkit-flex-wrap: wrap;
|
||||
-ms-flex-wrap: wrap;
|
||||
-webkit-appearance: auto;
|
||||
-moz-appearance: auto;
|
||||
-ms-appearance: auto;
|
||||
@ -30,7 +28,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@supports (flex-wrap: wrap) {
|
||||
@supports ((flex-wrap: wrap) or (-webkit-flex-wrap: wrap) or (-ms-flex-wrap: wrap)) {
|
||||
.foo {
|
||||
-webkit-appearance: auto;
|
||||
-moz-appearance: auto;
|
||||
|
73
crates/swc_css_prefixer/tests/fixture/supports/input.css
Normal file
73
crates/swc_css_prefixer/tests/fixture/supports/input.css
Normal file
@ -0,0 +1,73 @@
|
||||
@supports (display: flex) {
|
||||
div {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@supports not (display: flex) {
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
@supports not (not (display: flex)) {
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (display: flex) or (cursor: grab) {
|
||||
div {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (display: flex) and (cursor: grab) {
|
||||
div {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@supports ((display: flex) and (cursor: grab)) {
|
||||
div {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@supports ((display: flex)) and ((cursor: grab)) {
|
||||
div {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@supports ((perspective: 1px) and (not (-webkit-overflow-scrolling: touch))) {
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (cursor: grab) or (color: black) {
|
||||
a {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (display: flex) {
|
||||
@media screen and (min-width: 900px) {
|
||||
article {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
div {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (display: flex) or (display: -webkit-box) {
|
||||
div {
|
||||
display: flex;
|
||||
}
|
||||
}
|
94
crates/swc_css_prefixer/tests/fixture/supports/output.css
Normal file
94
crates/swc_css_prefixer/tests/fixture/supports/output.css
Normal file
@ -0,0 +1,94 @@
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports not ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
@supports not ( not ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox))) {
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) or ((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab)) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) and ((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab)) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports (((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) and ((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab))) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports (((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox))) and (((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab))) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports (((perspective: 1px) or (-webkit-perspective: 1px) or (-moz-perspective: 1px)) and ( not (-webkit-overflow-scrolling: touch))) {
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
@supports ((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab)) or (color: black) {
|
||||
a {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
@media screen and (min-width: 900px) {
|
||||
article {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) or (display: -webkit-box) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports not ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
@supports not ( not ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox))) {
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) or ((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab)) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) and ((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab)) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports (((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) and ((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab))) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports (((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox))) and (((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab))) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports ((perspective: 1px) and ( not (-webkit-overflow-scrolling: touch))) {
|
||||
a {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
@supports ((cursor: grab) or (cursor: -webkit-grab) or (cursor: -moz-grab)) or (color: black) {
|
||||
a {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
@media screen and (min-width: 900px) {
|
||||
article {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-box) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@supports ((display: flex) or (display: -webkit-flex) or (display: -moz-box) or (display: -ms-flexbox)) or (display: -webkit-box) {
|
||||
div {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
}
|
@ -100,7 +100,7 @@ button::-moz-submit-invalid {
|
||||
transition: opacity 0.5s 2s, -o-transform 0.5s 0.5s;
|
||||
transition: opacity 0.5s 2s, transform 0.5s 0.5s;
|
||||
}
|
||||
@supports (transition: opacity 0.5s 2s, transform 0.5s 0.5s) {
|
||||
@supports ((transition: opacity 0.5s 2s, transform 0.5s 0.5s) or (-webkit-transition: opacity 0.5s 2s, -webkit-transform 0.5s 0.5s) or (-moz-transition: opacity 0.5s 2s, -moz-transform 0.5s 0.5s) or (-o-transition: opacity 0.5s 2s, -o-transform 0.5s 0.5s) or (transition: opacity 0.5s 2s, -webkit-transform 0.5s 0.5s) or (transition: opacity 0.5s 2s, -moz-transform 0.5s 0.5s) or (transition: opacity 0.5s 2s, -o-transform 0.5s 0.5s)) {
|
||||
button::-moz-submit-invalid {
|
||||
opacity: 1;
|
||||
-webkit-transform: translateX(45px);
|
||||
|
@ -46,7 +46,7 @@ button::-moz-submit-invalid {
|
||||
transition: opacity 0.5s 2s, -o-transform 0.5s 0.5s;
|
||||
transition: opacity 0.5s 2s, transform 0.5s 0.5s;
|
||||
}
|
||||
@supports (transition: opacity 0.5s 2s, transform 0.5s 0.5s) {
|
||||
@supports ((transition: opacity 0.5s 2s, transform 0.5s 0.5s) or (transition: opacity 0.5s 2s, -webkit-transform 0.5s 0.5s) or (transition: opacity 0.5s 2s, -moz-transform 0.5s 0.5s) or (transition: opacity 0.5s 2s, -o-transform 0.5s 0.5s)) {
|
||||
button::-moz-submit-invalid {
|
||||
opacity: 1;
|
||||
transform: translateX(45px);
|
||||
|
Loading…
Reference in New Issue
Block a user