mirror of
https://github.com/swc-project/swc.git
synced 2024-11-26 09:54:22 +03:00
feat(css/compat): Implement transform for nested css (#6077)
This commit is contained in:
parent
5c486c5234
commit
347d4b7602
3
.github/workflows/CI.yml
vendored
3
.github/workflows/CI.yml
vendored
@ -269,6 +269,9 @@ jobs:
|
||||
- crate: swc_css_codegen_macros
|
||||
os: ubuntu-latest
|
||||
runner: ubuntu-latest
|
||||
- crate: swc_css_compat
|
||||
os: ubuntu-latest
|
||||
runner: ubuntu-latest
|
||||
- crate: swc_css_lints
|
||||
os: ubuntu-latest
|
||||
runner: ubuntu-latest
|
||||
|
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -3196,9 +3196,11 @@ version = "0.128.0"
|
||||
dependencies = [
|
||||
"swc_css_ast",
|
||||
"swc_css_codegen",
|
||||
"swc_css_compat",
|
||||
"swc_css_minifier",
|
||||
"swc_css_modules",
|
||||
"swc_css_parser",
|
||||
"swc_css_prefixer",
|
||||
"swc_css_utils",
|
||||
"swc_css_visit",
|
||||
]
|
||||
@ -3245,6 +3247,24 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_css_compat"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"preset_env_base",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"swc_atoms",
|
||||
"swc_common",
|
||||
"swc_css_ast",
|
||||
"swc_css_codegen",
|
||||
"swc_css_parser",
|
||||
"swc_css_utils",
|
||||
"swc_css_visit",
|
||||
"testing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swc_css_lints"
|
||||
version = "0.34.0"
|
||||
|
@ -1,29 +1,33 @@
|
||||
[package]
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
description = "CSS apis for rust"
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
description = "CSS apis for rust"
|
||||
documentation = "https://rustdoc.swc.rs/swc_css/"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
name = "swc_css"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.128.0"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
name = "swc_css"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.128.0"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[features]
|
||||
compat = ["swc_css_compat"]
|
||||
minifier = ["swc_css_minifier"]
|
||||
modules = ["swc_css_modules"]
|
||||
modules = ["swc_css_modules"]
|
||||
prefixer = ["swc_css_prefixer"]
|
||||
|
||||
[dependencies]
|
||||
swc_css_ast = { version = "0.115.0", path = "../swc_css_ast" }
|
||||
swc_css_codegen = { version = "0.125.0", path = "../swc_css_codegen" }
|
||||
swc_css_minifier = { version = "0.90.0", path = "../swc_css_minifier", optional = true }
|
||||
swc_css_modules = { version = "0.1.0", path = "../swc_css_modules", optional = true }
|
||||
swc_css_parser = { version = "0.124.0", path = "../swc_css_parser" }
|
||||
swc_css_utils = { version = "0.112.0", path = "../swc_css_utils/" }
|
||||
swc_css_visit = { version = "0.114.0", path = "../swc_css_visit" }
|
||||
swc_css_ast = {version = "0.115.0", path = "../swc_css_ast"}
|
||||
swc_css_codegen = {version = "0.125.0", path = "../swc_css_codegen"}
|
||||
swc_css_compat = {version = "0.1.0", path = "../swc_css_compat", optional = true}
|
||||
swc_css_minifier = {version = "0.90.0", path = "../swc_css_minifier", optional = true}
|
||||
swc_css_modules = {version = "0.1.0", path = "../swc_css_modules", optional = true}
|
||||
swc_css_parser = {version = "0.124.0", path = "../swc_css_parser"}
|
||||
swc_css_prefixer = {version = "0.126.0", path = "../swc_css_prefixer", optional = true}
|
||||
swc_css_utils = {version = "0.112.0", path = "../swc_css_utils/"}
|
||||
swc_css_visit = {version = "0.114.0", path = "../swc_css_visit"}
|
||||
|
@ -1,5 +1,8 @@
|
||||
pub extern crate swc_css_ast as ast;
|
||||
pub extern crate swc_css_codegen as codegen;
|
||||
#[cfg(feature = "swc_css_compat")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "compat")))]
|
||||
pub extern crate swc_css_compat as compat;
|
||||
#[cfg(feature = "swc_css_minifier")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "minifier")))]
|
||||
pub extern crate swc_css_minifier as minifier;
|
||||
@ -7,5 +10,8 @@ pub extern crate swc_css_minifier as minifier;
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "modules")))]
|
||||
pub extern crate swc_css_modules as modules;
|
||||
pub extern crate swc_css_parser as parser;
|
||||
#[cfg(feature = "swc_css_prefixer")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "prefixer")))]
|
||||
pub extern crate swc_css_prefixer as prefixer;
|
||||
pub extern crate swc_css_utils as utils;
|
||||
pub extern crate swc_css_visit as visit;
|
||||
|
29
crates/swc_css_compat/Cargo.toml
Normal file
29
crates/swc_css_compat/Cargo.toml
Normal file
@ -0,0 +1,29 @@
|
||||
[package]
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
description = "Port of stylis"
|
||||
documentation = "https://rustdoc.swc.rs/swc_css_compat/"
|
||||
edition = "2021"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json", "data/**/*.json"]
|
||||
license = "Apache-2.0"
|
||||
name = "swc_css_compat"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.1.0"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
once_cell = "1.10.0"
|
||||
preset_env_base = { version = "0.3.2", path = "../preset_env_base" }
|
||||
serde = { version = "1.0.118", features = ["derive"] }
|
||||
serde_json = "1.0.61"
|
||||
swc_atoms = { version = "0.4.18", path = "../swc_atoms" }
|
||||
swc_common = { version = "0.29.5", path = "../swc_common" }
|
||||
swc_css_ast = { version = "0.115.0", path = "../swc_css_ast" }
|
||||
swc_css_utils = { version = "0.112.0", path = "../swc_css_utils/" }
|
||||
swc_css_visit = { version = "0.114.0", path = "../swc_css_visit" }
|
||||
|
||||
[dev-dependencies]
|
||||
swc_css_codegen = { version = "0.125.0", path = "../swc_css_codegen" }
|
||||
swc_css_parser = { version = "0.124.0", path = "../swc_css_parser" }
|
||||
testing = { version = "0.31.5", path = "../testing" }
|
3
crates/swc_css_compat/src/lib.rs
Normal file
3
crates/swc_css_compat/src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
||||
#![allow(clippy::vec_box)]
|
||||
|
||||
pub mod nesting;
|
227
crates/swc_css_compat/src/nesting.rs
Normal file
227
crates/swc_css_compat/src/nesting.rs
Normal file
@ -0,0 +1,227 @@
|
||||
use swc_common::util::take::Take;
|
||||
use swc_css_ast::{
|
||||
ComplexSelector, ComplexSelectorChildren, ComponentValue, CompoundSelector,
|
||||
ForgivingComplexSelector, ForgivingSelectorList, PseudoClassSelector,
|
||||
PseudoClassSelectorChildren, QualifiedRule, QualifiedRulePrelude, Rule, SelectorList,
|
||||
StyleBlock, SubclassSelector,
|
||||
};
|
||||
use swc_css_visit::{VisitMut, VisitMutWith};
|
||||
|
||||
pub fn nesting() -> impl VisitMut {
|
||||
NestingHandler {}
|
||||
}
|
||||
|
||||
struct NestingHandler {}
|
||||
|
||||
impl NestingHandler {
|
||||
fn append_compound(
|
||||
&mut self,
|
||||
prelude: &SelectorList,
|
||||
to: &mut ComplexSelector,
|
||||
base: &ComplexSelector,
|
||||
c: &CompoundSelector,
|
||||
) {
|
||||
if c.nesting_selector.is_some() {
|
||||
let len = base.children.len();
|
||||
|
||||
to.children
|
||||
.extend(
|
||||
base.children
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.map(|(idx, mut children)| {
|
||||
if idx == len - 1 {
|
||||
if let ComplexSelectorChildren::CompoundSelector(compound) =
|
||||
&mut children
|
||||
{
|
||||
if c.type_selector.is_some() {
|
||||
compound.type_selector = c.type_selector.clone();
|
||||
}
|
||||
|
||||
let mut subclass = c.subclass_selectors.clone();
|
||||
|
||||
self.process_subclass_selectors(prelude, &mut subclass);
|
||||
|
||||
compound.subclass_selectors.extend(subclass);
|
||||
}
|
||||
}
|
||||
|
||||
children
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
to.children
|
||||
.push(ComplexSelectorChildren::CompoundSelector(c.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
fn process_subclass_selectors(
|
||||
&mut self,
|
||||
prelude: &SelectorList,
|
||||
subclass: &mut Vec<SubclassSelector>,
|
||||
) {
|
||||
for sel in subclass {
|
||||
if let SubclassSelector::PseudoClass(PseudoClassSelector {
|
||||
children: Some(children),
|
||||
..
|
||||
}) = sel
|
||||
{
|
||||
for c in children {
|
||||
if let PseudoClassSelectorChildren::ForgivingSelectorList(c) = c {
|
||||
let mut selectors = vec![];
|
||||
|
||||
for sel in &mut c.children {
|
||||
match sel {
|
||||
ForgivingComplexSelector::ComplexSelector(sel) => {
|
||||
selectors.push(sel.clone());
|
||||
}
|
||||
ForgivingComplexSelector::ListOfComponentValues(_) => {
|
||||
// Abort
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.process_complex_selectors(prelude, &mut selectors);
|
||||
|
||||
*c = ForgivingSelectorList {
|
||||
children: selectors
|
||||
.into_iter()
|
||||
.map(ForgivingComplexSelector::ComplexSelector)
|
||||
.collect(),
|
||||
..*c
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_complex_selectors(
|
||||
&mut self,
|
||||
prelude: &SelectorList,
|
||||
selectors: &mut Vec<ComplexSelector>,
|
||||
) {
|
||||
let mut new_selectors = vec![];
|
||||
|
||||
//
|
||||
'complex: for complex in selectors.take() {
|
||||
for compound in &complex.children {
|
||||
match compound {
|
||||
ComplexSelectorChildren::CompoundSelector(compound) => {
|
||||
if compound.nesting_selector.is_some() {
|
||||
//
|
||||
|
||||
for prelude_children in &prelude.children {
|
||||
let mut new = ComplexSelector {
|
||||
span: Default::default(),
|
||||
children: Default::default(),
|
||||
};
|
||||
for compound in &complex.children {
|
||||
match compound {
|
||||
ComplexSelectorChildren::CompoundSelector(compound) => {
|
||||
self.append_compound(
|
||||
prelude,
|
||||
&mut new,
|
||||
prelude_children,
|
||||
compound,
|
||||
);
|
||||
}
|
||||
ComplexSelectorChildren::Combinator(_) => {
|
||||
new.children.push(compound.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
new_selectors.push(new);
|
||||
}
|
||||
continue 'complex;
|
||||
}
|
||||
}
|
||||
ComplexSelectorChildren::Combinator(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
new_selectors.push(complex);
|
||||
}
|
||||
|
||||
*selectors = new_selectors;
|
||||
}
|
||||
|
||||
/// Prepend current selector
|
||||
fn process_prelude(&mut self, prelude: &QualifiedRulePrelude, to: &mut QualifiedRulePrelude) {
|
||||
if let (
|
||||
QualifiedRulePrelude::SelectorList(prelude),
|
||||
QualifiedRulePrelude::SelectorList(selectors),
|
||||
) = (prelude, to)
|
||||
{
|
||||
self.process_complex_selectors(prelude, &mut selectors.children);
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_nested_rules(&mut self, rule: &mut QualifiedRule) -> Vec<Box<QualifiedRule>> {
|
||||
let mut rules = vec![];
|
||||
|
||||
let mut block_values = vec![];
|
||||
for value in rule.block.value.take() {
|
||||
match value {
|
||||
ComponentValue::StyleBlock(StyleBlock::QualifiedRule(mut q)) => {
|
||||
self.process_prelude(&rule.prelude, &mut q.prelude);
|
||||
|
||||
rules.push(q);
|
||||
}
|
||||
_ => {
|
||||
block_values.push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
rule.block.value = block_values;
|
||||
|
||||
rules
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMut for NestingHandler {
|
||||
fn visit_mut_rules(&mut self, n: &mut Vec<Rule>) {
|
||||
n.visit_mut_children_with(self);
|
||||
|
||||
let mut new = vec![];
|
||||
for n in n.take() {
|
||||
match n {
|
||||
Rule::QualifiedRule(mut n) => {
|
||||
let rules = self.extract_nested_rules(&mut n);
|
||||
new.push(Rule::QualifiedRule(n));
|
||||
new.extend(rules.into_iter().map(Rule::QualifiedRule));
|
||||
}
|
||||
_ => {
|
||||
new.push(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
*n = new;
|
||||
}
|
||||
|
||||
fn visit_mut_component_values(&mut self, n: &mut Vec<ComponentValue>) {
|
||||
n.visit_mut_children_with(self);
|
||||
|
||||
let mut new = vec![];
|
||||
for n in n.take() {
|
||||
match n {
|
||||
ComponentValue::StyleBlock(StyleBlock::QualifiedRule(mut n)) => {
|
||||
let rules = self.extract_nested_rules(&mut n);
|
||||
new.push(ComponentValue::StyleBlock(StyleBlock::QualifiedRule(n)));
|
||||
new.extend(
|
||||
rules
|
||||
.into_iter()
|
||||
.map(StyleBlock::QualifiedRule)
|
||||
.map(ComponentValue::StyleBlock),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
new.push(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
*n = new;
|
||||
}
|
||||
}
|
65
crates/swc_css_compat/tests/nesting.rs
Normal file
65
crates/swc_css_compat/tests/nesting.rs
Normal file
@ -0,0 +1,65 @@
|
||||
//! Tests ported from https://github.com/thysultan/stylis.js
|
||||
//!
|
||||
//! License is MIT, which is original license at the time of copying.
|
||||
//! Original test authors have copyright for their work.
|
||||
#![deny(warnings)]
|
||||
#![allow(clippy::needless_update)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use swc_css_ast::Stylesheet;
|
||||
use swc_css_codegen::{
|
||||
writer::basic::{BasicCssWriter, BasicCssWriterConfig},
|
||||
CodegenConfig, Emit,
|
||||
};
|
||||
use swc_css_compat::nesting::nesting;
|
||||
use swc_css_parser::{parse_file, parser::ParserConfig};
|
||||
use swc_css_visit::VisitMutWith;
|
||||
use testing::NormalizedOutput;
|
||||
|
||||
fn test_nesting(input: PathBuf, suffix: Option<&str>) {
|
||||
let parent = input.parent().unwrap();
|
||||
let output = match suffix {
|
||||
Some(suffix) => parent.join("output.".to_owned() + suffix + ".css"),
|
||||
_ => parent.join("output.css"),
|
||||
};
|
||||
|
||||
testing::run_test2(false, |cm, handler| {
|
||||
//
|
||||
let fm = cm.load_file(&input).unwrap();
|
||||
let mut errors = vec![];
|
||||
let mut ss: Stylesheet = parse_file(
|
||||
&fm,
|
||||
ParserConfig {
|
||||
allow_wrong_line_comments: true,
|
||||
..Default::default()
|
||||
},
|
||||
&mut errors,
|
||||
)
|
||||
.unwrap();
|
||||
for err in errors {
|
||||
err.to_diagnostics(&handler).emit();
|
||||
}
|
||||
|
||||
ss.visit_mut_with(&mut nesting());
|
||||
|
||||
let mut s = String::new();
|
||||
{
|
||||
let mut wr = BasicCssWriter::new(&mut s, None, BasicCssWriterConfig::default());
|
||||
let mut gen =
|
||||
swc_css_codegen::CodeGenerator::new(&mut wr, CodegenConfig { minify: false });
|
||||
|
||||
gen.emit(&ss).unwrap();
|
||||
}
|
||||
|
||||
NormalizedOutput::from(s).compare_to_file(&output).unwrap();
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[testing::fixture("tests/nesting/**/input.css")]
|
||||
fn test_without_env(input: PathBuf) {
|
||||
test_nesting(input, None)
|
||||
}
|
13
crates/swc_css_compat/tests/nesting/amphersand/input.css
Normal file
13
crates/swc_css_compat/tests/nesting/amphersand/input.css
Normal file
@ -0,0 +1,13 @@
|
||||
table.colortable {
|
||||
& td {
|
||||
text-align: center;
|
||||
&.c { text-transform:uppercase }
|
||||
&:first-child, &:first-child + td { border:1px solid black }
|
||||
}
|
||||
|
||||
& th {
|
||||
text-align:center;
|
||||
background:black;
|
||||
color:white;
|
||||
}
|
||||
}
|
16
crates/swc_css_compat/tests/nesting/amphersand/output.css
Normal file
16
crates/swc_css_compat/tests/nesting/amphersand/output.css
Normal file
@ -0,0 +1,16 @@
|
||||
table.colortable {}
|
||||
table.colortable td {
|
||||
text-align: center;
|
||||
}
|
||||
table.colortable td.c {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
table.colortable td:first-child,
|
||||
table.colortable td:first-child + td {
|
||||
border: 1px solid black;
|
||||
}
|
||||
table.colortable th {
|
||||
text-align: center;
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
69
crates/swc_css_compat/tests/nesting/basic/input.css
Normal file
69
crates/swc_css_compat/tests/nesting/basic/input.css
Normal file
@ -0,0 +1,69 @@
|
||||
table.colortable {
|
||||
& td {
|
||||
text-align: center;
|
||||
&.c { text-transform:uppercase }
|
||||
&:first-child, &:first-child + td { border:1px solid black }
|
||||
}
|
||||
|
||||
& th {
|
||||
text-align:center;
|
||||
background:black;
|
||||
color:white;
|
||||
}
|
||||
}
|
||||
|
||||
.foo {
|
||||
color: blue;
|
||||
& > .bar { color: red; }
|
||||
}
|
||||
|
||||
.foo {
|
||||
color: blue;
|
||||
&.bar { color: red; }
|
||||
}
|
||||
|
||||
.foo, .bar {
|
||||
color: blue;
|
||||
& + .baz, &.qux { color: red; }
|
||||
}
|
||||
|
||||
.foo {
|
||||
color: blue;
|
||||
& .bar & .baz & .qux { color: red; }
|
||||
}
|
||||
|
||||
.foo {
|
||||
color: blue;
|
||||
& { padding: 2ch; }
|
||||
}
|
||||
|
||||
/* TODO fix me */
|
||||
/*.foo {*/
|
||||
/* color: blue;*/
|
||||
/* && { padding: 2ch; }*/
|
||||
/*}*/
|
||||
|
||||
.error, #test {
|
||||
&:hover > .baz { color: red; }
|
||||
}
|
||||
|
||||
.foo {
|
||||
&:is(.bar, &.baz) { color: red; }
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0;
|
||||
|
||||
& > figcaption {
|
||||
background: hsl(0 0% 0% / 50%);
|
||||
|
||||
& > p {
|
||||
font-size: .9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.foo {
|
||||
color: blue;
|
||||
&__bar { color: red; }
|
||||
}
|
75
crates/swc_css_compat/tests/nesting/basic/output.css
Normal file
75
crates/swc_css_compat/tests/nesting/basic/output.css
Normal file
@ -0,0 +1,75 @@
|
||||
table.colortable {}
|
||||
table.colortable td {
|
||||
text-align: center;
|
||||
}
|
||||
table.colortable td.c {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
table.colortable td:first-child,
|
||||
table.colortable td:first-child + td {
|
||||
border: 1px solid black;
|
||||
}
|
||||
table.colortable th {
|
||||
text-align: center;
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
.foo {
|
||||
color: blue;
|
||||
}
|
||||
.foo > .bar {
|
||||
color: red;
|
||||
}
|
||||
.foo {
|
||||
color: blue;
|
||||
}
|
||||
.foo.bar {
|
||||
color: red;
|
||||
}
|
||||
.foo,
|
||||
.bar {
|
||||
color: blue;
|
||||
}
|
||||
.foo + .baz,
|
||||
.bar + .baz,
|
||||
.foo.qux,
|
||||
.bar.qux {
|
||||
color: red;
|
||||
}
|
||||
.foo {
|
||||
color: blue;
|
||||
}
|
||||
.foo .bar .foo .baz .foo .qux {
|
||||
color: red;
|
||||
}
|
||||
.foo {
|
||||
color: blue;
|
||||
}
|
||||
.foo {
|
||||
padding: 2ch;
|
||||
}
|
||||
.error,
|
||||
#test {}
|
||||
.error:hover > .baz,
|
||||
#test:hover > .baz {
|
||||
color: red;
|
||||
}
|
||||
.foo {}
|
||||
.foo:is(.bar, .foo.baz) {
|
||||
color: red;
|
||||
}
|
||||
figure {
|
||||
margin: 0;
|
||||
}
|
||||
figure > figcaption {
|
||||
background: hsl(0 0% 0% / 50%);
|
||||
}
|
||||
figure > figcaption > p {
|
||||
font-size: .9rem;
|
||||
}
|
||||
.foo {
|
||||
color: blue;
|
||||
}
|
||||
__bar.foo {
|
||||
color: red;
|
||||
}
|
3
crates/swc_css_compat/tests/nesting/pseudo-is/input.css
Normal file
3
crates/swc_css_compat/tests/nesting/pseudo-is/input.css
Normal file
@ -0,0 +1,3 @@
|
||||
.foo {
|
||||
&:is(.bar, &.baz) { color: red; }
|
||||
}
|
4
crates/swc_css_compat/tests/nesting/pseudo-is/output.css
Normal file
4
crates/swc_css_compat/tests/nesting/pseudo-is/output.css
Normal file
@ -0,0 +1,4 @@
|
||||
.foo {}
|
||||
.foo:is(.bar, .foo.baz) {
|
||||
color: red;
|
||||
}
|
@ -1,29 +1,29 @@
|
||||
[package]
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
description = "Port of stylis"
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
description = "Port of stylis"
|
||||
documentation = "https://rustdoc.swc.rs/swc_stylis/"
|
||||
edition = "2021"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json", "data/**/*.json"]
|
||||
license = "Apache-2.0"
|
||||
name = "swc_css_prefixer"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.126.0"
|
||||
edition = "2021"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json", "data/**/*.json"]
|
||||
license = "Apache-2.0"
|
||||
name = "swc_css_prefixer"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.126.0"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
once_cell = "1.10.0"
|
||||
preset_env_base = { version = "0.3.2", path = "../preset_env_base" }
|
||||
serde = { version = "1.0.118", features = ["derive"] }
|
||||
serde_json = "1.0.61"
|
||||
swc_atoms = { version = "0.4.18", path = "../swc_atoms" }
|
||||
swc_common = { version = "0.29.5", path = "../swc_common" }
|
||||
swc_css_ast = { version = "0.115.0", path = "../swc_css_ast" }
|
||||
swc_css_utils = { version = "0.112.0", path = "../swc_css_utils/" }
|
||||
swc_css_visit = { version = "0.114.0", path = "../swc_css_visit" }
|
||||
once_cell = "1.10.0"
|
||||
preset_env_base = {version = "0.3.2", path = "../preset_env_base"}
|
||||
serde = {version = "1.0.118", features = ["derive"]}
|
||||
serde_json = "1.0.61"
|
||||
swc_atoms = {version = "0.4.18", path = "../swc_atoms"}
|
||||
swc_common = {version = "0.29.5", path = "../swc_common"}
|
||||
swc_css_ast = {version = "0.115.0", path = "../swc_css_ast"}
|
||||
swc_css_utils = {version = "0.112.0", path = "../swc_css_utils/"}
|
||||
swc_css_visit = {version = "0.114.0", path = "../swc_css_visit"}
|
||||
|
||||
[dev-dependencies]
|
||||
swc_css_codegen = { version = "0.125.0", path = "../swc_css_codegen" }
|
||||
swc_css_parser = { version = "0.124.0", path = "../swc_css_parser" }
|
||||
testing = { version = "0.31.5", path = "../testing" }
|
||||
swc_css_codegen = {version = "0.125.0", path = "../swc_css_codegen"}
|
||||
swc_css_parser = {version = "0.124.0", path = "../swc_css_parser"}
|
||||
testing = {version = "0.31.5", path = "../testing"}
|
||||
|
@ -30,9 +30,9 @@ check:
|
||||
swc_bundler:
|
||||
- "cargo hack check --feature-powerset --no-dev-deps"
|
||||
swc_common:
|
||||
- "cargo hack check --feature-powerset --no-dev-deps --exclude-features plugin_transform_schema_vtest"
|
||||
- "cargo hack check --feature-powerset --no-dev-deps --exclude-features plugin_transform_schema_vtest --exclude-features __plugin --exclude-features __plugin_mode --exclude-features __plugin_rt --exclude-features __rkyv --exclude-features plugin-bytecheck-base --exclude-features plugin-bytecheck-mode --exclude-features plugin-bytecheck-rt --exclude-features rkyv-bytecheck-impl --exclude-features rkyv-impl"
|
||||
swc_ecma_ast:
|
||||
- "cargo hack check --feature-powerset --no-dev-deps"
|
||||
- "cargo hack check --feature-powerset --no-dev-deps --exclude-features __rkyv --exclude-features rkyv-bytecheck-impl"
|
||||
swc_ecma_loader:
|
||||
- "cargo hack check --feature-powerset --no-dev-deps"
|
||||
swc_ecma_transforms:
|
||||
|
Loading…
Reference in New Issue
Block a user