fix(css): Fix @supports at-rule (#3329)

This commit is contained in:
Alexander Akait 2022-01-21 16:32:49 +03:00 committed by GitHub
parent 4ee4672e4d
commit 9f3806029c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 13520 additions and 34 deletions

View File

@ -1,4 +1,4 @@
use crate::{Function, Ident, MediaQueryList, Str, UrlValue}; use crate::{Declaration, Function, Ident, MediaQueryList, Str, SupportsCondition, UrlValue};
use swc_common::{ast_node, Span}; use swc_common::{ast_node, Span};
#[ast_node] #[ast_node]
@ -22,10 +22,19 @@ pub enum ImportLayerName {
Function(Function), Function(Function),
} }
#[ast_node]
pub enum ImportSupportsType {
#[tag("SupportsCondition")]
SupportsCondition(SupportsCondition),
#[tag("Declaration")]
Declaration(Declaration),
}
#[ast_node("ImportRule")] #[ast_node("ImportRule")]
pub struct ImportRule { pub struct ImportRule {
pub span: Span, pub span: Span,
pub href: ImportHref, pub href: ImportHref,
pub layer_name: Option<ImportLayerName>, pub layer_name: Option<ImportLayerName>,
pub supports: Option<ImportSupportsType>,
pub media: Option<MediaQueryList>, pub media: Option<MediaQueryList>,
} }

View File

@ -1,4 +1,5 @@
#![deny(clippy::all)] #![deny(clippy::all)]
#![allow(clippy::large_enum_variant)]
//! AST definitions for CSS. //! AST definitions for CSS.
pub use self::{at_rule::*, base::*, selector::*, style_rule::*, token::*, value::*}; pub use self::{at_rule::*, base::*, selector::*, style_rule::*, token::*, value::*};

View File

@ -83,6 +83,14 @@ where
} }
} }
#[emitter]
fn emit_import_supports_type(&mut self, n: &ImportSupportsType) -> Result {
match n {
ImportSupportsType::SupportsCondition(n) => emit!(self, n),
ImportSupportsType::Declaration(n) => emit!(self, n),
}
}
#[emitter] #[emitter]
fn emit_charset_rule(&mut self, n: &CharsetRule) -> Result { fn emit_charset_rule(&mut self, n: &CharsetRule) -> Result {
punct!(self, "@"); punct!(self, "@");
@ -95,6 +103,34 @@ where
semi!(self); semi!(self);
} }
#[emitter]
fn emit_import_rule(&mut self, n: &ImportRule) -> Result {
punct!(self, "@");
keyword!(self, "import");
space!(self);
emit!(self, n.href);
if let Some(layer_name) = &n.layer_name {
space!(self);
emit!(self, layer_name);
}
if let Some(supports) = &n.supports {
space!(self);
keyword!(self, "supports");
punct!(self, "(");
emit!(self, supports);
punct!(self, ")");
}
if let Some(media) = &n.media {
space!(self);
emit!(self, media);
}
semi!(self);
}
#[emitter] #[emitter]
fn emit_import_href(&mut self, n: &ImportHref) -> Result { fn emit_import_href(&mut self, n: &ImportHref) -> Result {
match n { match n {
@ -112,26 +148,6 @@ where
} }
} }
#[emitter]
fn emit_import_rule(&mut self, n: &ImportRule) -> Result {
punct!(self, "@");
keyword!(self, "import");
space!(self);
emit!(self, n.href);
if let Some(layer_name) = &n.layer_name {
space!(self);
emit!(self, layer_name);
}
if let Some(media) = &n.media {
space!(self);
emit!(self, media);
}
semi!(self);
}
#[emitter] #[emitter]
fn emit_font_face_rule(&mut self, n: &FontFaceRule) -> Result { fn emit_font_face_rule(&mut self, n: &FontFaceRule) -> Result {
punct!(self, "@"); punct!(self, "@");

View File

@ -315,6 +315,25 @@ where
_ => None, _ => None,
}; };
let supports = match cur!(self) {
Token::Function { value, .. } if *value.to_ascii_lowercase() == *"supports" => {
bump!(self);
self.input.skip_ws()?;
let supports = if is_one_of!(self, "not", "(") {
ImportSupportsType::SupportsCondition(self.parse()?)
} else {
ImportSupportsType::Declaration(self.parse()?)
};
expect!(self, ")");
Some(supports)
}
_ => None,
};
let media = if !is!(self, ";") { let media = if !is!(self, ";") {
Some(self.parse()?) Some(self.parse()?)
} else { } else {
@ -327,6 +346,7 @@ where
span: span!(self, span.lo), span: span!(self, span.lo),
href, href,
layer_name, layer_name,
supports,
media, media,
}) })
} }

View File

@ -323,9 +323,10 @@ impl Visit for SpanVisualizer<'_> {
mtd!(CharsetRule, visit_charset_rule); mtd!(CharsetRule, visit_charset_rule);
mtd!(DocumentRule, visit_document_rule); mtd!(DocumentRule, visit_document_rule);
mtd!(FontFaceRule, visit_font_face_rule); mtd!(FontFaceRule, visit_font_face_rule);
mtd!(ImportRule, visit_import_rule);
mtd!(ImportHref, visit_import_href); mtd!(ImportHref, visit_import_href);
mtd!(ImportLayerName, visit_import_layer_name); mtd!(ImportLayerName, visit_import_layer_name);
mtd!(ImportRule, visit_import_rule); mtd!(ImportSupportsType, visit_import_supports_type);
mtd!(KeyframeBlock, visit_keyframe_block); mtd!(KeyframeBlock, visit_keyframe_block);
mtd!(KeyframeBlockRule, visit_keyframe_block_rule); mtd!(KeyframeBlockRule, visit_keyframe_block_rule);
mtd!(KeyframeSelector, visit_keyframe_selector); mtd!(KeyframeSelector, visit_keyframe_selector);

View File

@ -16,4 +16,149 @@
@import url("theme.css") LAYER(default); @import url("theme.css") LAYER(default);
/*@import url("tabs.css") layer(framework.component);*/ /*@import url("tabs.css") layer(framework.component);*/
@import url("override.css") layer(); @import url("override.css") layer();
/*@import url("narrow.css") supports(display: flex) handheld and (max-width: 400px);*/ @import url("narrow.css") supports(display: flex) handheld and (max-width: 400px);
@import url("narrow.css") SUPPORTS(display: flex) handheld and (max-width: 400px);
@import url("fallback-layout.css") supports(not (display: flex));
@import url(test.css);
@import url('test.css');
@import url("test.css");
@IMPORT url(test.css);
@import URL(test.css);
@import url(test.css );
@import url( test.css);
@import url( test.css );
@import url(
test.css
);
@import url();
@import url('');
@import url("");
@import "test.css";
@import 'test.css';
@import '';
@import "";
@import " ";
@import "\
";
@import url();
@import url('');
@import url("");
@import url(test.css) screen and (orientation:landscape);
/*@import url(test.css) SCREEN AND (ORIENTATION: LANDSCAPE);*/
@import url(test.css)screen and (orientation:landscape);
@import url(test.css) screen and ( orientation : landscape ) ;
@import url(test.css) screen and (orientation:landscape);
@import url("//example.com/style.css");
@import url(~package/test.css);
@import url('https://fonts.googleapis.com/css?family=Roboto');
@import url('https://fonts.googleapis.com/css?family=Noto+Sans+TC');
@import url('https://fonts.googleapis.com/css?family=Noto+Sans+TC|Roboto');
@import url('./relative.css');
@import url('../import/top-relative.css');
@import url(~package/tilde.css);
@import url(~aliasesImport/alias.css);
@import url('./url.css');
@import url(./test.css);
@import './te\
st.css';
@import './te\
\
\
st.css';
@import url('./te\
st.css');
@import url('./te\
\
\
st.css');
@import "./te'st.css";
@import url("./te'st.css");
@import './te\'st.css';
@import url('./te\'st.css');
@import './test test.css';
@import url('./test test.css');
@import './test\ test.css';
@import url('./test\ test.css');
@import './test%20test.css';
@import url('./test%20test.css');
@import './\74\65\73\74.css';
@import url('./\74\65\73\74.css');
@import './t\65\73\74.css';
@import url('./t\65\73\74.css');
@import url(./test\ test.css);
@import url(./t\65st%20test.css);
@import url('./t\65st%20test.css');
@import url("./t\65st%20test.css");
@import "./t\65st%20test.css";
@import './t\65st%20test.css';
@import url( test.css );
@import '\
\
\
';
@import url('!!../../helpers/string-loader.js?esModule=false!~package/tilde.css');
@import url(test.css?foo=bar);
@import url(test.css?foo=bar#hash);
@import url(test.css?#hash);
@import "test.css" supports(display: flex);
@import "test.css" supports(display: flex) screen and (orientation:landscape);
@import"test.css"supports(display: flex)screen and (orientation:landscape);
@import " ./test.css ";
@import url(' ./test.css ');
@import url( ./test.css );
@import "./my.scss";
@import url(' https://fonts.googleapis.com/css?family=Roboto ');
@import url('!!../../helpers/string-loader.js?esModule=false!');
@import url(' !!../../helpers/string-loader.js?esModule=false!~package/tilde.css ');
@import url(data:text/css;charset=utf-8,a%20%7B%0D%0A%20%20color%3A%20red%3B%0D%0A%7D);
@import url(package/first.css);
@import url(package/second.css);
/*@import url("./test.css") supports();*/
/*@import url("./test.css") supports(unknown);*/
@import url("./test.css") supports(display: flex);
@import url("./test.css") supports(display: flex !important);
@import url("./test.css") supports(display: flex) screen and (min-width: 400px);
@import url("./test.css") layer;
@import url("./test.css") layer(default);
@import url("./test.css") layer(default) supports(display: flex) screen and (min-width: 400px);
@import url("./test.css") layer supports(display: flex) screen and (min-width: 400px);
@import url("./test.css") layer() supports(display: flex) screen and (min-width: 400px);
@import url("./test.css") layer();
@import url("http://example.com/style.css") 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")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") /* Comment */ layer(/* Comment */default/* Comment */) /* Comment */ supports(/* Comment */display/* Comment */:/* Comment */ flex/* Comment */)/* Comment */ screen/* Comment */ and/* Comment */ (/* Comment */min-width/* Comment */: /* Comment */400px/* Comment */);
@import url(test.css) /* Comment */;
@import /* Comment */ url(test.css) /* Comment */;
@import url(test.css) /* Comment */ print and (orientation:landscape);
@import /* Comment */ url(test.css) /* Comment */ print and (orientation:landscape);
@import url("./deep-import-with-media.css") (prefers-color-scheme: dark);
@import url("./import-with-supports.css") supports(display: flex);
@import url("./import-with-supports.css") supports(((display: flex)));
@import url("./deep-import-with-supports.css") supports(display: flex);
@import url('./test.css') supports(display: grid);
@import url('./test.css') supports( display : grid );
@import url("./import-with-supports-and-media.css") supports(display: flex) screen and (min-width: 400px);
@import url("./test.css") layer(framework);
@import url("./import-multiple-with-layer.css") layer(default);
@import url("./import-unnamed-layer.css") layer(base);
@import url("./import-with-layer-and-supports.css") layer(default) supports(display: flex);
/*@import url("./test.css") unknown(default) unknown(display: flex) unknown;*/
/*.foo {*/
/* @import 'path.css';*/
/*}*/

File diff suppressed because it is too large Load Diff

View File

@ -44,6 +44,7 @@
] ]
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": { "media": {
"type": "MediaQueryList", "type": "MediaQueryList",
"span": { "span": {

View File

@ -24,6 +24,7 @@
"raw": "foo.css" "raw": "foo.css"
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
} }
] ]

View File

@ -24,6 +24,7 @@
"raw": "\"foo.css\"" "raw": "\"foo.css\""
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
} }
] ]

View File

@ -44,6 +44,7 @@
] ]
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": { "media": {
"type": "MediaQueryList", "type": "MediaQueryList",
"span": { "span": {

View File

@ -24,6 +24,7 @@
"raw": "\"foo.css\"" "raw": "\"foo.css\""
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
} }
] ]

View File

@ -24,6 +24,7 @@
"raw": "foo.css" "raw": "foo.css"
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
} }
] ]

View File

@ -24,6 +24,7 @@
"raw": "" "raw": ""
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
} }
] ]

View File

@ -44,6 +44,7 @@
] ]
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
} }
] ]

View File

@ -24,6 +24,7 @@
"raw": "\"foo.css\"" "raw": "\"foo.css\""
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
} }
] ]

View File

@ -44,6 +44,7 @@
] ]
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
} }
] ]

View File

@ -24,6 +24,7 @@
"raw": "\"something.css\"" "raw": "\"something.css\""
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
}, },
{ {
@ -64,6 +65,7 @@
] ]
}, },
"layerName": null, "layerName": null,
"supports": null,
"media": null "media": null
} }
] ]

View File

@ -0,0 +1 @@
@import nourl(test.css);

View File

@ -0,0 +1 @@
@import ;

View File

@ -0,0 +1,53 @@
{
"type": "Stylesheet",
"span": {
"start": 0,
"end": 10,
"ctxt": 0
},
"rules": [
{
"type": "UnknownAtRule",
"span": {
"start": 0,
"end": 9,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 0,
"end": 8,
"ctxt": 0
},
"value": "import",
"raw": "import"
},
"prelude": [
{
"type": "Tokens",
"span": {
"start": 7,
"end": 8,
"ctxt": 0
},
"tokens": [
{
"span": {
"start": 7,
"end": 8,
"ctxt": 0
},
"token": {
"WhiteSpace": {
"value": " "
}
}
}
]
}
],
"block": null
}
]
}

View File

@ -0,0 +1 @@
@import foo-bar;

View File

@ -0,0 +1,76 @@
{
"type": "Stylesheet",
"span": {
"start": 0,
"end": 17,
"ctxt": 0
},
"rules": [
{
"type": "UnknownAtRule",
"span": {
"start": 0,
"end": 16,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 0,
"end": 8,
"ctxt": 0
},
"value": "import",
"raw": "import"
},
"prelude": [
{
"type": "Tokens",
"span": {
"start": 7,
"end": 8,
"ctxt": 0
},
"tokens": [
{
"span": {
"start": 7,
"end": 8,
"ctxt": 0
},
"token": {
"WhiteSpace": {
"value": " "
}
}
}
]
},
{
"type": "Tokens",
"span": {
"start": 8,
"end": 15,
"ctxt": 0
},
"tokens": [
{
"span": {
"start": 8,
"end": 15,
"ctxt": 0
},
"token": {
"Ident": {
"value": "foo-bar",
"raw": "foo-bar"
}
}
}
]
}
],
"block": null
}
]
}

View File

@ -0,0 +1 @@
@import url('http://') :root {}

View File

@ -0,0 +1,177 @@
{
"type": "Stylesheet",
"span": {
"start": 0,
"end": 32,
"ctxt": 0
},
"rules": [
{
"type": "UnknownAtRule",
"span": {
"start": 0,
"end": 31,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 0,
"end": 23,
"ctxt": 0
},
"value": "import",
"raw": "import"
},
"prelude": [
{
"type": "Tokens",
"span": {
"start": 7,
"end": 8,
"ctxt": 0
},
"tokens": [
{
"span": {
"start": 7,
"end": 8,
"ctxt": 0
},
"token": {
"WhiteSpace": {
"value": " "
}
}
}
]
},
{
"type": "Function",
"span": {
"start": 8,
"end": 22,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 8,
"end": 11,
"ctxt": 0
},
"value": "url",
"raw": "url"
},
"value": [
{
"type": "String",
"span": {
"start": 12,
"end": 21,
"ctxt": 0
},
"value": "http://",
"raw": "'http://'"
}
]
},
{
"type": "Tokens",
"span": {
"start": 22,
"end": 23,
"ctxt": 0
},
"tokens": [
{
"span": {
"start": 22,
"end": 23,
"ctxt": 0
},
"token": {
"WhiteSpace": {
"value": " "
}
}
}
]
},
{
"type": "Tokens",
"span": {
"start": 23,
"end": 24,
"ctxt": 0
},
"tokens": [
{
"span": {
"start": 23,
"end": 24,
"ctxt": 0
},
"token": "Colon"
}
]
},
{
"type": "Tokens",
"span": {
"start": 24,
"end": 28,
"ctxt": 0
},
"tokens": [
{
"span": {
"start": 24,
"end": 28,
"ctxt": 0
},
"token": {
"Ident": {
"value": "root",
"raw": "root"
}
}
}
]
},
{
"type": "Tokens",
"span": {
"start": 28,
"end": 29,
"ctxt": 0
},
"tokens": [
{
"span": {
"start": 28,
"end": 29,
"ctxt": 0
},
"token": {
"WhiteSpace": {
"value": " "
}
}
}
]
}
],
"block": {
"type": "SimpleBlock",
"span": {
"start": 29,
"end": 31,
"ctxt": 0
},
"name": "{",
"value": []
}
}
]
}

View File

@ -0,0 +1 @@
@import-normalize;

View File

@ -0,0 +1,30 @@
{
"type": "Stylesheet",
"span": {
"start": 0,
"end": 19,
"ctxt": 0
},
"rules": [
{
"type": "UnknownAtRule",
"span": {
"start": 0,
"end": 18,
"ctxt": 0
},
"name": {
"type": "Identifier",
"span": {
"start": 0,
"end": 17,
"ctxt": 0
},
"value": "import-normalize",
"raw": "import-normalize"
},
"prelude": [],
"block": null
}
]
}

View File

@ -354,10 +354,16 @@ define!({
Function(Function), Function(Function),
} }
pub enum ImportSupportsType {
SupportsCondition(SupportsCondition),
Declaration(Declaration),
}
pub struct ImportRule { pub struct ImportRule {
pub span: Span, pub span: Span,
pub href: ImportHref, pub href: ImportHref,
pub layer_name: Option<ImportLayerName>, pub layer_name: Option<ImportLayerName>,
pub supports: Option<ImportSupportsType>,
pub media: Option<MediaQueryList>, pub media: Option<MediaQueryList>,
} }