mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 13:38:33 +03:00
feat(css/modules): Implement css modules (#6000)
This commit is contained in:
parent
37286e369e
commit
2cce1c82b2
3
.github/workflows/CI.yml
vendored
3
.github/workflows/CI.yml
vendored
@ -275,6 +275,9 @@ jobs:
|
|||||||
- crate: swc_css_minifier
|
- crate: swc_css_minifier
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
|
- crate: swc_css_modules
|
||||||
|
os: ubuntu-latest
|
||||||
|
runner: ubuntu-latest
|
||||||
- crate: swc_css_parser
|
- crate: swc_css_parser
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
runner: ubuntu-latest
|
runner: ubuntu-latest
|
||||||
|
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -3197,6 +3197,7 @@ dependencies = [
|
|||||||
"swc_css_ast",
|
"swc_css_ast",
|
||||||
"swc_css_codegen",
|
"swc_css_codegen",
|
||||||
"swc_css_minifier",
|
"swc_css_minifier",
|
||||||
|
"swc_css_modules",
|
||||||
"swc_css_parser",
|
"swc_css_parser",
|
||||||
"swc_css_utils",
|
"swc_css_utils",
|
||||||
"swc_css_visit",
|
"swc_css_visit",
|
||||||
@ -3280,6 +3281,23 @@ dependencies = [
|
|||||||
"testing",
|
"testing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "swc_css_modules"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-hash",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"swc_atoms",
|
||||||
|
"swc_common",
|
||||||
|
"swc_css_ast",
|
||||||
|
"swc_css_codegen",
|
||||||
|
"swc_css_parser",
|
||||||
|
"swc_css_visit",
|
||||||
|
"swc_ecma_loader",
|
||||||
|
"testing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "swc_css_parser"
|
name = "swc_css_parser"
|
||||||
version = "0.123.5"
|
version = "0.123.5"
|
||||||
|
@ -1,27 +1,29 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||||
description = "CSS apis for rust"
|
description = "CSS apis for rust"
|
||||||
documentation = "https://rustdoc.swc.rs/swc_css/"
|
documentation = "https://rustdoc.swc.rs/swc_css/"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
name = "swc_css"
|
name = "swc_css"
|
||||||
repository = "https://github.com/swc-project/swc.git"
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
version = "0.127.6"
|
version = "0.127.6"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
bench = false
|
bench = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
minifier = ["swc_css_minifier"]
|
minifier = ["swc_css_minifier"]
|
||||||
|
modules = ["swc_css_modules"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
swc_css_ast = {version = "0.114.5", path = "../swc_css_ast"}
|
swc_css_ast = { version = "0.114.5", path = "../swc_css_ast" }
|
||||||
swc_css_codegen = {version = "0.124.5", path = "../swc_css_codegen"}
|
swc_css_codegen = { version = "0.124.5", path = "../swc_css_codegen" }
|
||||||
swc_css_minifier = {version = "0.89.6", path = "../swc_css_minifier", optional = true}
|
swc_css_minifier = { version = "0.89.6", path = "../swc_css_minifier", optional = true }
|
||||||
swc_css_parser = {version = "0.123.5", path = "../swc_css_parser"}
|
swc_css_modules = { version = "0.1.0", path = "../swc_css_modules", optional = true }
|
||||||
swc_css_utils = {version = "0.111.5", path = "../swc_css_utils/"}
|
swc_css_parser = { version = "0.123.5", path = "../swc_css_parser" }
|
||||||
swc_css_visit = {version = "0.113.5", path = "../swc_css_visit"}
|
swc_css_utils = { version = "0.111.5", path = "../swc_css_utils/" }
|
||||||
|
swc_css_visit = { version = "0.113.5", path = "../swc_css_visit" }
|
||||||
|
@ -3,6 +3,9 @@ pub extern crate swc_css_codegen as codegen;
|
|||||||
#[cfg(feature = "swc_css_minifier")]
|
#[cfg(feature = "swc_css_minifier")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "minifier")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "minifier")))]
|
||||||
pub extern crate swc_css_minifier as minifier;
|
pub extern crate swc_css_minifier as minifier;
|
||||||
|
#[cfg(feature = "swc_css_modules")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "modules")))]
|
||||||
|
pub extern crate swc_css_modules as modules;
|
||||||
pub extern crate swc_css_parser as parser;
|
pub extern crate swc_css_parser as parser;
|
||||||
pub extern crate swc_css_utils as utils;
|
pub extern crate swc_css_utils as utils;
|
||||||
pub extern crate swc_css_visit as visit;
|
pub extern crate swc_css_visit as visit;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use is_macro::Is;
|
use is_macro::Is;
|
||||||
use string_enum::StringEnum;
|
use string_enum::StringEnum;
|
||||||
use swc_atoms::JsWord;
|
use swc_atoms::JsWord;
|
||||||
use swc_common::{ast_node, EqIgnoreSpan, Span};
|
use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span};
|
||||||
|
|
||||||
use crate::{Delimiter, Ident, ListOfComponentValues, Str, TokenAndSpan};
|
use crate::{Delimiter, Ident, ListOfComponentValues, Str, TokenAndSpan};
|
||||||
|
|
||||||
@ -65,6 +65,15 @@ pub struct ComplexSelector {
|
|||||||
pub children: Vec<ComplexSelectorChildren>,
|
pub children: Vec<ComplexSelectorChildren>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Take for ComplexSelector {
|
||||||
|
fn dummy() -> Self {
|
||||||
|
Self {
|
||||||
|
span: Take::dummy(),
|
||||||
|
children: Take::dummy(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[ast_node]
|
#[ast_node]
|
||||||
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
|
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
|
||||||
pub enum ComplexSelectorChildren {
|
pub enum ComplexSelectorChildren {
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
use is_macro::Is;
|
use is_macro::Is;
|
||||||
use string_enum::StringEnum;
|
use string_enum::StringEnum;
|
||||||
use swc_atoms::JsWord;
|
use swc_atoms::JsWord;
|
||||||
use swc_common::{ast_node, EqIgnoreSpan, Span};
|
use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span};
|
||||||
|
|
||||||
use crate::Function;
|
use crate::Function;
|
||||||
|
|
||||||
@ -26,6 +26,16 @@ impl EqIgnoreSpan for Ident {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Take for Ident {
|
||||||
|
fn dummy() -> Self {
|
||||||
|
Self {
|
||||||
|
span: Default::default(),
|
||||||
|
value: Default::default(),
|
||||||
|
raw: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[ast_node("CustomIdent")]
|
#[ast_node("CustomIdent")]
|
||||||
#[derive(Eq, Hash)]
|
#[derive(Eq, Hash)]
|
||||||
pub struct CustomIdent {
|
pub struct CustomIdent {
|
||||||
|
30
crates/swc_css_modules/Cargo.toml
Normal file
30
crates/swc_css_modules/Cargo.toml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
[package]
|
||||||
|
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||||
|
description = "CSS modules"
|
||||||
|
documentation = "https://rustdoc.swc.rs/swc_css_modules/"
|
||||||
|
edition = "2021"
|
||||||
|
include = ["Cargo.toml", "src/**/*.rs"]
|
||||||
|
license = "Apache-2.0"
|
||||||
|
name = "swc_css_modules"
|
||||||
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rustc-hash = "1.1.0"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
swc_atoms = { version = "0.4.18", path = "../swc_atoms" }
|
||||||
|
swc_common = { version = "0.29.4", path = "../swc_common" }
|
||||||
|
swc_css_ast = { version = "0.114.4", path = "../swc_css_ast" }
|
||||||
|
swc_css_codegen = { version = "0.124.5", path = "../swc_css_codegen" }
|
||||||
|
swc_css_parser = { version = "0.123.5", path = "../swc_css_parser" }
|
||||||
|
swc_css_visit = { version = "0.113.4", path = "../swc_css_visit" }
|
||||||
|
swc_ecma_loader = { version = "0.41.3", path = "../swc_ecma_loader" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
serde_json = "1"
|
||||||
|
testing = { version = "0.31.4", path = "../testing" }
|
68
crates/swc_css_modules/src/imports.rs
Normal file
68
crates/swc_css_modules/src/imports.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//! Import/export analyzer
|
||||||
|
|
||||||
|
use swc_atoms::{js_word, JsWord};
|
||||||
|
use swc_css_ast::{
|
||||||
|
ComponentValue, Declaration, DeclarationName, Ident, ImportPrelude, ImportPreludeHref,
|
||||||
|
Stylesheet, UrlValue,
|
||||||
|
};
|
||||||
|
use swc_css_visit::{Visit, VisitWith};
|
||||||
|
|
||||||
|
pub fn analyze_imports(ss: &Stylesheet) -> Vec<JsWord> {
|
||||||
|
let mut v = Analyzer {
|
||||||
|
imports: Default::default(),
|
||||||
|
};
|
||||||
|
ss.visit_with(&mut v);
|
||||||
|
v.imports.sort();
|
||||||
|
v.imports.dedup();
|
||||||
|
v.imports
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Analyzer {
|
||||||
|
imports: Vec<JsWord>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Visit for Analyzer {
|
||||||
|
fn visit_import_prelude(&mut self, n: &ImportPrelude) {
|
||||||
|
n.visit_children_with(self);
|
||||||
|
|
||||||
|
match &*n.href {
|
||||||
|
ImportPreludeHref::Url(u) => {
|
||||||
|
if let Some(s) = &u.value {
|
||||||
|
match &**s {
|
||||||
|
UrlValue::Str(s) => {
|
||||||
|
self.imports.push(s.value.clone());
|
||||||
|
}
|
||||||
|
UrlValue::Raw(v) => {
|
||||||
|
self.imports.push(v.value.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImportPreludeHref::Str(s) => {
|
||||||
|
self.imports.push(s.value.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_declaration(&mut self, d: &Declaration) {
|
||||||
|
d.visit_children_with(self);
|
||||||
|
|
||||||
|
if let DeclarationName::Ident(name) = &d.name {
|
||||||
|
if &*name.value == "composes" {
|
||||||
|
// comoses: name from 'foo.css'
|
||||||
|
if d.value.len() >= 3 {
|
||||||
|
if let (
|
||||||
|
ComponentValue::Ident(Ident {
|
||||||
|
value: js_word!("from"),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
ComponentValue::Str(s),
|
||||||
|
) = (&d.value[d.value.len() - 2], &d.value[d.value.len() - 1])
|
||||||
|
{
|
||||||
|
self.imports.push(s.value.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
437
crates/swc_css_modules/src/lib.rs
Normal file
437
crates/swc_css_modules/src/lib.rs
Normal file
@ -0,0 +1,437 @@
|
|||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use serde::Serialize;
|
||||||
|
use swc_atoms::{js_word, JsWord};
|
||||||
|
use swc_common::util::take::Take;
|
||||||
|
use swc_css_ast::{
|
||||||
|
ComplexSelector, ComplexSelectorChildren, ComponentValue, Declaration, DeclarationName,
|
||||||
|
DeclarationOrAtRule, Delimiter, DelimiterValue, Ident, KeyframesName, QualifiedRule,
|
||||||
|
QualifiedRulePrelude, StyleBlock, Stylesheet, SubclassSelector,
|
||||||
|
};
|
||||||
|
use swc_css_parser::{parse_tokens, parser::ParserConfig};
|
||||||
|
use swc_css_visit::{VisitMut, VisitMutWith};
|
||||||
|
use util::to_tokens::to_tokens_vec;
|
||||||
|
|
||||||
|
pub mod imports;
|
||||||
|
mod util;
|
||||||
|
|
||||||
|
/// Various configurations for the css modules.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// This is a trait rather than a struct because api like `fn() -> String` is
|
||||||
|
/// too restricted and `Box<Fn() -> String` is (needlessly) slow.
|
||||||
|
pub trait TransformConfig {
|
||||||
|
/// Creates a class name for the given `local_name`.
|
||||||
|
fn new_name_for(&self, local: &JsWord) -> JsWord;
|
||||||
|
|
||||||
|
// /// Used for `@value` imports.
|
||||||
|
// fn get_value(&self, import_source: &str, value_name: &JsWord) ->
|
||||||
|
// ComponentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||||
|
#[serde(tag = "type", rename_all = "camelCase")]
|
||||||
|
pub enum CssClassName {
|
||||||
|
Local {
|
||||||
|
/// Tranformed css class name
|
||||||
|
name: JsWord,
|
||||||
|
},
|
||||||
|
Global {
|
||||||
|
name: JsWord,
|
||||||
|
},
|
||||||
|
Import {
|
||||||
|
/// The exported class name. This is the value specified by the user.
|
||||||
|
name: JsWord,
|
||||||
|
/// The module specifier.
|
||||||
|
from: JsWord,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TransformResult {
|
||||||
|
/// A map of js class name to css class names.
|
||||||
|
pub renamed: FxHashMap<JsWord, Vec<CssClassName>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a map from local name to exported name.
|
||||||
|
pub fn compile(ss: &mut Stylesheet, config: impl TransformConfig) -> TransformResult {
|
||||||
|
let mut compiler = Compiler {
|
||||||
|
config,
|
||||||
|
data: Default::default(),
|
||||||
|
result: TransformResult {
|
||||||
|
renamed: Default::default(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
ss.visit_mut_with(&mut compiler);
|
||||||
|
|
||||||
|
compiler.result
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Compiler<C>
|
||||||
|
where
|
||||||
|
C: TransformConfig,
|
||||||
|
{
|
||||||
|
config: C,
|
||||||
|
data: Data,
|
||||||
|
result: TransformResult,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Data {
|
||||||
|
/// Context for `composes`
|
||||||
|
composes_for_current: Option<Vec<CssClassName>>,
|
||||||
|
|
||||||
|
renamed_to_orig: FxHashMap<JsWord, JsWord>,
|
||||||
|
orig_to_renamed: FxHashMap<JsWord, JsWord>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> VisitMut for Compiler<C>
|
||||||
|
where
|
||||||
|
C: TransformConfig,
|
||||||
|
{
|
||||||
|
fn visit_mut_qualified_rule(&mut self, n: &mut QualifiedRule) {
|
||||||
|
let old_compose_stack = self.data.composes_for_current.take();
|
||||||
|
self.data.composes_for_current = Some(Default::default());
|
||||||
|
|
||||||
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
if let QualifiedRulePrelude::SelectorList(sel) = &n.prelude {
|
||||||
|
//
|
||||||
|
if sel.children.len() == 1 && sel.children[0].children.len() == 1 {
|
||||||
|
if let ComplexSelectorChildren::CompoundSelector(sel) = &sel.children[0].children[0]
|
||||||
|
{
|
||||||
|
if sel.subclass_selectors.len() == 1 {
|
||||||
|
if let SubclassSelector::Class(class_sel) = &sel.subclass_selectors[0] {
|
||||||
|
if let Some(composes) = self.data.composes_for_current.take() {
|
||||||
|
let key = self
|
||||||
|
.data
|
||||||
|
.renamed_to_orig
|
||||||
|
.get(&class_sel.text.value)
|
||||||
|
.cloned();
|
||||||
|
|
||||||
|
if let Some(key) = key {
|
||||||
|
self.result.renamed.entry(key).or_default().extend(composes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.data.composes_for_current = old_compose_stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_component_values(&mut self, n: &mut Vec<ComponentValue>) {
|
||||||
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
n.retain(|v| match v {
|
||||||
|
ComponentValue::StyleBlock(StyleBlock::Declaration(d))
|
||||||
|
| ComponentValue::DeclarationOrAtRule(DeclarationOrAtRule::Declaration(d)) => {
|
||||||
|
if let DeclarationName::Ident(ident) = &d.name {
|
||||||
|
if &*ident.value == "composes" {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles `composes`
|
||||||
|
fn visit_mut_declaration(&mut self, n: &mut Declaration) {
|
||||||
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
if let Some(composes_for_current) = &mut self.data.composes_for_current {
|
||||||
|
if let DeclarationName::Ident(name) = &n.name {
|
||||||
|
if &*name.value == "composes" {
|
||||||
|
// comoses: name from 'foo.css'
|
||||||
|
if n.value.len() >= 3 {
|
||||||
|
match (&n.value[n.value.len() - 2], &n.value[n.value.len() - 1]) {
|
||||||
|
(
|
||||||
|
ComponentValue::Ident(Ident {
|
||||||
|
value: js_word!("from"),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
ComponentValue::Str(import_source),
|
||||||
|
) => {
|
||||||
|
for class_name in n.value.iter().take(n.value.len() - 2) {
|
||||||
|
if let ComponentValue::Ident(Ident { value, .. }) = class_name {
|
||||||
|
composes_for_current.push(CssClassName::Import {
|
||||||
|
name: value.clone(),
|
||||||
|
from: import_source.value.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(
|
||||||
|
ComponentValue::Ident(Ident {
|
||||||
|
value: js_word!("from"),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
ComponentValue::Ident(Ident {
|
||||||
|
value: js_word!("global"),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
) => {
|
||||||
|
for class_name in n.value.iter().take(n.value.len() - 2) {
|
||||||
|
if let ComponentValue::Ident(Ident { value, .. }) = class_name {
|
||||||
|
composes_for_current.push(CssClassName::Global {
|
||||||
|
name: value.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for class_name in n.value.iter() {
|
||||||
|
if let ComponentValue::Ident(Ident { value, .. }) = class_name {
|
||||||
|
if let Some(value) = self.data.orig_to_renamed.get(value) {
|
||||||
|
composes_for_current.push(CssClassName::Local {
|
||||||
|
name: value.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let DeclarationName::Ident(name) = &n.name {
|
||||||
|
match name.value.to_ascii_lowercase() {
|
||||||
|
js_word!("animation") => {
|
||||||
|
let mut can_change = true;
|
||||||
|
|
||||||
|
for v in &mut n.value {
|
||||||
|
if can_change {
|
||||||
|
if let ComponentValue::Ident(Ident { value, raw, .. }) = v {
|
||||||
|
*raw = None;
|
||||||
|
|
||||||
|
rename(
|
||||||
|
&mut self.config,
|
||||||
|
&mut self.result,
|
||||||
|
&mut self.data.orig_to_renamed,
|
||||||
|
&mut self.data.renamed_to_orig,
|
||||||
|
value,
|
||||||
|
);
|
||||||
|
can_change = false;
|
||||||
|
}
|
||||||
|
} else if let ComponentValue::Delimiter(Delimiter {
|
||||||
|
value: DelimiterValue::Comma,
|
||||||
|
..
|
||||||
|
}) = v
|
||||||
|
{
|
||||||
|
can_change = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js_word!("animation-name") => {
|
||||||
|
for v in &mut n.value {
|
||||||
|
if let ComponentValue::Ident(Ident { value, raw, .. }) = v {
|
||||||
|
*raw = None;
|
||||||
|
|
||||||
|
rename(
|
||||||
|
&mut self.config,
|
||||||
|
&mut self.result,
|
||||||
|
&mut self.data.orig_to_renamed,
|
||||||
|
&mut self.data.renamed_to_orig,
|
||||||
|
value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_complex_selector(&mut self, n: &mut ComplexSelector) {
|
||||||
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
let mut new_children = Vec::with_capacity(n.children.len());
|
||||||
|
|
||||||
|
'complex: for mut n in n.children.take() {
|
||||||
|
match &mut n {
|
||||||
|
ComplexSelectorChildren::CompoundSelector(sel) => {
|
||||||
|
//
|
||||||
|
|
||||||
|
for sel in &mut sel.subclass_selectors {
|
||||||
|
match sel {
|
||||||
|
SubclassSelector::Class(..) | SubclassSelector::Id(..) => {
|
||||||
|
process_local(
|
||||||
|
&mut self.config,
|
||||||
|
&mut self.result,
|
||||||
|
&mut self.data.orig_to_renamed,
|
||||||
|
&mut self.data.renamed_to_orig,
|
||||||
|
sel,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
SubclassSelector::PseudoClass(class_sel) => {
|
||||||
|
match &*class_sel.name.value {
|
||||||
|
"local" => {
|
||||||
|
if let Some(children) = &mut class_sel.children {
|
||||||
|
let tokens = to_tokens_vec(&*children);
|
||||||
|
|
||||||
|
let mut sel: ComplexSelector = parse_tokens(
|
||||||
|
&tokens,
|
||||||
|
ParserConfig {
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&mut vec![],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
sel.visit_mut_with(self);
|
||||||
|
|
||||||
|
new_children.extend(sel.children);
|
||||||
|
|
||||||
|
continue 'complex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"global" => {
|
||||||
|
if let Some(children) = &mut class_sel.children {
|
||||||
|
let tokens = to_tokens_vec(&*children);
|
||||||
|
|
||||||
|
let sel: ComplexSelector = parse_tokens(
|
||||||
|
&tokens,
|
||||||
|
ParserConfig {
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
&mut vec![],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
new_children.extend(sel.children);
|
||||||
|
|
||||||
|
continue 'complex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
sel.visit_mut_children_with(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ComplexSelectorChildren::Combinator(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_children.push(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
n.children = new_children;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_complex_selectors(&mut self, n: &mut Vec<ComplexSelector>) {
|
||||||
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
n.retain_mut(|s| !s.children.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mut_keyframes_name(&mut self, n: &mut KeyframesName) {
|
||||||
|
n.visit_mut_children_with(self);
|
||||||
|
|
||||||
|
match n {
|
||||||
|
KeyframesName::CustomIdent(n) => {
|
||||||
|
n.raw = None;
|
||||||
|
rename(
|
||||||
|
&mut self.config,
|
||||||
|
&mut self.result,
|
||||||
|
&mut self.data.orig_to_renamed,
|
||||||
|
&mut self.data.renamed_to_orig,
|
||||||
|
&mut n.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
KeyframesName::Str(n) => {
|
||||||
|
n.raw = None;
|
||||||
|
rename(
|
||||||
|
&mut self.config,
|
||||||
|
&mut self.result,
|
||||||
|
&mut self.data.orig_to_renamed,
|
||||||
|
&mut self.data.renamed_to_orig,
|
||||||
|
&mut n.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rename<C>(
|
||||||
|
config: &mut C,
|
||||||
|
result: &mut TransformResult,
|
||||||
|
orig_to_renamed: &mut FxHashMap<JsWord, JsWord>,
|
||||||
|
renamed_to_orig: &mut FxHashMap<JsWord, JsWord>,
|
||||||
|
name: &mut JsWord,
|
||||||
|
) where
|
||||||
|
C: TransformConfig,
|
||||||
|
{
|
||||||
|
if let Some(renamed) = orig_to_renamed.get(name) {
|
||||||
|
*name = renamed.clone();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new = config.new_name_for(name);
|
||||||
|
|
||||||
|
orig_to_renamed.insert(name.clone(), new.clone());
|
||||||
|
renamed_to_orig.insert(new.clone(), name.clone());
|
||||||
|
|
||||||
|
{
|
||||||
|
let e = result.renamed.entry(name.clone()).or_default();
|
||||||
|
|
||||||
|
let v = CssClassName::Local { name: new.clone() };
|
||||||
|
if !e.contains(&v) {
|
||||||
|
e.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*name = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_local<C>(
|
||||||
|
config: &mut C,
|
||||||
|
result: &mut TransformResult,
|
||||||
|
orig_to_renamed: &mut FxHashMap<JsWord, JsWord>,
|
||||||
|
renamed_to_orig: &mut FxHashMap<JsWord, JsWord>,
|
||||||
|
sel: &mut SubclassSelector,
|
||||||
|
) where
|
||||||
|
C: TransformConfig,
|
||||||
|
{
|
||||||
|
match sel {
|
||||||
|
SubclassSelector::Id(sel) => {
|
||||||
|
sel.text.raw = None;
|
||||||
|
|
||||||
|
rename(
|
||||||
|
config,
|
||||||
|
result,
|
||||||
|
orig_to_renamed,
|
||||||
|
renamed_to_orig,
|
||||||
|
&mut sel.text.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
SubclassSelector::Class(sel) => {
|
||||||
|
sel.text.raw = None;
|
||||||
|
|
||||||
|
rename(
|
||||||
|
config,
|
||||||
|
result,
|
||||||
|
orig_to_renamed,
|
||||||
|
renamed_to_orig,
|
||||||
|
&mut sel.text.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
SubclassSelector::Attribute(_) => {}
|
||||||
|
SubclassSelector::PseudoClass(_) => {}
|
||||||
|
SubclassSelector::PseudoElement(_) => {}
|
||||||
|
}
|
||||||
|
}
|
1
crates/swc_css_modules/src/util/mod.rs
Normal file
1
crates/swc_css_modules/src/util/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod to_tokens;
|
63
crates/swc_css_modules/src/util/to_tokens.rs
Normal file
63
crates/swc_css_modules/src/util/to_tokens.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use swc_common::{input::StringInput, Span, Spanned};
|
||||||
|
use swc_css_ast::Tokens;
|
||||||
|
use swc_css_codegen::{
|
||||||
|
writer::basic::{BasicCssWriter, BasicCssWriterConfig, IndentType},
|
||||||
|
CodeGenerator, CodegenConfig, Emit,
|
||||||
|
};
|
||||||
|
use swc_css_parser::{lexer::Lexer, parser::ParserConfig};
|
||||||
|
|
||||||
|
pub(crate) fn to_tokens_vec<N>(n: &[N]) -> Tokens
|
||||||
|
where
|
||||||
|
N: Spanned,
|
||||||
|
for<'aa, 'ab> CodeGenerator<BasicCssWriter<'aa, &'ab mut String>>: swc_css_codegen::Emit<N>,
|
||||||
|
{
|
||||||
|
let lo = n.first().span().lo();
|
||||||
|
let hi = n.last().span().lo();
|
||||||
|
|
||||||
|
let tokens = n.iter().flat_map(|n| to_tokens(n).tokens).collect();
|
||||||
|
|
||||||
|
Tokens {
|
||||||
|
span: Span::new(lo, hi, Default::default()),
|
||||||
|
tokens,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_tokens<N>(n: &N) -> Tokens
|
||||||
|
where
|
||||||
|
N: Spanned,
|
||||||
|
for<'aa, 'ab> CodeGenerator<BasicCssWriter<'aa, &'ab mut String>>: swc_css_codegen::Emit<N>,
|
||||||
|
{
|
||||||
|
let span = n.span();
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
{
|
||||||
|
let wr = BasicCssWriter::new(
|
||||||
|
&mut buf,
|
||||||
|
None,
|
||||||
|
BasicCssWriterConfig {
|
||||||
|
indent_type: IndentType::Tab,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let mut g = CodeGenerator::new(
|
||||||
|
wr,
|
||||||
|
CodegenConfig {
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
g.emit(n).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let lexer = Lexer::new(
|
||||||
|
StringInput::new(&buf, span.lo, span.hi),
|
||||||
|
ParserConfig {
|
||||||
|
allow_wrong_line_comments: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Tokens {
|
||||||
|
span,
|
||||||
|
tokens: lexer.collect(),
|
||||||
|
}
|
||||||
|
}
|
95
crates/swc_css_modules/tests/fixture.rs
Normal file
95
crates/swc_css_modules/tests/fixture.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use swc_atoms::JsWord;
|
||||||
|
use swc_css_codegen::{
|
||||||
|
writer::basic::{BasicCssWriter, BasicCssWriterConfig, IndentType},
|
||||||
|
CodeGenerator, CodegenConfig, Emit,
|
||||||
|
};
|
||||||
|
use testing::NormalizedOutput;
|
||||||
|
|
||||||
|
#[testing::fixture("tests/fixture/**/*.css", exclude("compiled\\.css"))]
|
||||||
|
fn imports(input: PathBuf) {
|
||||||
|
testing::run_test(false, |cm, handler| {
|
||||||
|
let fm = cm.load_file(&input).unwrap();
|
||||||
|
let mut errors = vec![];
|
||||||
|
let ss = swc_css_parser::parse_file(&fm, Default::default(), &mut errors).unwrap();
|
||||||
|
let result = swc_css_modules::imports::analyze_imports(&ss);
|
||||||
|
|
||||||
|
if result.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let s = serde_json::to_string_pretty(&result).unwrap();
|
||||||
|
NormalizedOutput::from(s)
|
||||||
|
.compare_to_file(input.with_file_name(format!(
|
||||||
|
"{}.imports.json",
|
||||||
|
input.file_stem().unwrap().to_string_lossy()
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[testing::fixture("tests/fixture/**/*.css", exclude("compiled\\.css"))]
|
||||||
|
fn compile(input: PathBuf) {
|
||||||
|
testing::run_test(false, |cm, handler| {
|
||||||
|
let fm = cm.load_file(&input).unwrap();
|
||||||
|
let mut errors = vec![];
|
||||||
|
let mut ss = swc_css_parser::parse_file(&fm, Default::default(), &mut errors).unwrap();
|
||||||
|
let result = swc_css_modules::imports::analyze_imports(&ss);
|
||||||
|
|
||||||
|
let transform_result = swc_css_modules::compile(&mut ss, TestConfig {});
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
{
|
||||||
|
let mut wr = BasicCssWriter::new(
|
||||||
|
&mut buf,
|
||||||
|
None,
|
||||||
|
BasicCssWriterConfig {
|
||||||
|
indent_type: IndentType::Space,
|
||||||
|
indent_width: 2,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let mut g = CodeGenerator::new(
|
||||||
|
wr,
|
||||||
|
CodegenConfig {
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
g.emit(&ss).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
NormalizedOutput::from(buf)
|
||||||
|
.compare_to_file(input.with_file_name(format!(
|
||||||
|
"{}.compiled.css",
|
||||||
|
input.file_stem().unwrap().to_string_lossy()
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if !transform_result.renamed.is_empty() {
|
||||||
|
let transformed_classes =
|
||||||
|
serde_json::to_string_pretty(&transform_result.renamed).unwrap();
|
||||||
|
|
||||||
|
NormalizedOutput::from(transformed_classes)
|
||||||
|
.compare_to_file(input.with_file_name(format!(
|
||||||
|
"{}.transform.json",
|
||||||
|
input.file_stem().unwrap().to_string_lossy()
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestConfig {}
|
||||||
|
|
||||||
|
impl swc_css_modules::TransformConfig for TestConfig {
|
||||||
|
fn new_name_for(&self, local: &JsWord) -> JsWord {
|
||||||
|
format!("__local__{}", local).into()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
@charset "UTF-8";
|
||||||
|
.__local__class {
|
||||||
|
color: red;
|
||||||
|
background: url("./url/img.png");
|
||||||
|
}
|
||||||
|
.__local__class-duplicate-url {
|
||||||
|
background: url("./url/img.png");
|
||||||
|
}
|
||||||
|
:root {
|
||||||
|
--foo: 1px;
|
||||||
|
--bar: 2px;
|
||||||
|
}
|
||||||
|
.__local__class {
|
||||||
|
a: b c d;
|
||||||
|
}
|
||||||
|
.__local__two {}
|
||||||
|
.__local__u-m\+ {
|
||||||
|
a: b c d;
|
||||||
|
}
|
||||||
|
.__local__class {
|
||||||
|
content: "\F10C";
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.__local__class {
|
||||||
|
content: "\2193";
|
||||||
|
content: "\2193\2193";
|
||||||
|
content: "\2193 \2193";
|
||||||
|
content: "\2193\2193\2193";
|
||||||
|
content: "\2193 \2193 \2193";
|
||||||
|
}
|
||||||
|
.__local__-top {}
|
||||||
|
.__local__-top {}
|
||||||
|
#__local__\#test {}
|
||||||
|
.__local__grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.__local__grid.__local__-top {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.__local__grid.__local__-top {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.__local__grid.__local__-middle {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.__local__grid.__local__-bottom {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
.__local__u-m\+ {}
|
||||||
|
.__local__u-m00002b {}
|
||||||
|
#__local__u-m\+ {}
|
||||||
|
body {
|
||||||
|
font-family: '微软雅黑';
|
||||||
|
}
|
||||||
|
.__local__myStyle {
|
||||||
|
content: '\e901';
|
||||||
|
}
|
||||||
|
.__local__myStyle {
|
||||||
|
content: '\E901';
|
||||||
|
}
|
||||||
|
.__local__♫ {}
|
||||||
|
.__local__\:\`\( {}
|
||||||
|
.__local__1a2b3c {}
|
||||||
|
#__local__\#fake-id {}
|
||||||
|
#__local__-a-b-c- {}
|
||||||
|
#__local__© {}
|
||||||
|
:root {
|
||||||
|
--title-align: center;
|
||||||
|
--sr-only: {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0,0,0,0);
|
||||||
|
white-space: nowrap;
|
||||||
|
clip-path: inset(50%);
|
||||||
|
border: 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
.__local__test {
|
||||||
|
content: "\2014\A0";
|
||||||
|
content: "\2014 \A0";
|
||||||
|
content: "\A0 \2014";
|
||||||
|
content: "\A0\2014";
|
||||||
|
margin-top: 1px\9;
|
||||||
|
background-color: #000\9;
|
||||||
|
}
|
||||||
|
.__local__light.__local__on .__local__bulb:before {
|
||||||
|
content: '💡';
|
||||||
|
}
|
||||||
|
.__local__base64 {
|
||||||
|
background: url(data:img/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAhxJREFUSA3tk71rU1EYxnMTEoJUkowWwdJ2akEHBfGjCiIF6ZylVUKSm2TqZLGI+A/oIu2UXm8C4lAyF4SWji0tdFLo1Eo7VN0SaBEhH7e/Nz0nPTfGOjiaCyfPc5734zlfCQT6X/8E/vUErL81KBaL9y3LSnued5PcITjUOwR3gsFg2bbtjYt6/NGgXC4P1et1l2aPLmpAbD0SidjpdPqgV15PA9d17zQajU8UxHQRK/4G35Q5pveAK8LlI1ZjPMnlcltnyvnvbwaO41xvtVqy7YHztMACq5xnlb9EY3dRdvcGo1kj5wR+t1AofDG0gM+A875E8DNjRCexsrV8Pj9ZqVQitVrtqejxePxjMpmss5hVTB4buXvMb2DyU2tBTRS+BjvNlVYUpPl7iuVO3Gq1uoQx1FtSOW1gPgp5ZWrdBtNmUDgv5asgxQ8F1af5vhY0YjyjuWC3wTszKJz7GBOkcFlQfW2ONq4FjWi+Hj6DRCKxQOK2TlY4x92EuYd5dvMAbYIzfikau3pu5tJ8KxaLLfo0cyKci7tK4TZjUMcoXAmHwzle0Q/RaC5P1GFMyVx9R9Fo9HYqlTrSgqDvFelAqVQa5hmuMR/WGtjAaBdjwBoDQ0ZsnwVMZjKZ9n0Zem8DSeDPdrnZbL6F2l3NOvUYNZk4oVDoRTabPe4EDNJzB0ZcjAYxeoZ2i3FNxQ7BHYw/cB/fldaH//UETgHHO8S44KbfXgAAAABJRU5ErkJggg==);
|
||||||
|
}
|
||||||
|
a[href=''] {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
a[href='' i] {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
a[href=""] {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
a[href="" i] {
|
||||||
|
color: blue;
|
||||||
|
}
|
135
crates/swc_css_modules/tests/fixture/basic-css-style-sheet.css
Normal file
135
crates/swc_css_modules/tests/fixture/basic-css-style-sheet.css
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
/* Comment */
|
||||||
|
|
||||||
|
.class {
|
||||||
|
color: red;
|
||||||
|
background: url("./url/img.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.class-duplicate-url {
|
||||||
|
background: url("./url/img.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--foo: 1px;
|
||||||
|
--bar: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.class { a: b c d; }
|
||||||
|
|
||||||
|
.two {}
|
||||||
|
|
||||||
|
.u-m\+ { a: b c d; }
|
||||||
|
|
||||||
|
.class { content: "\F10C" }
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.class {
|
||||||
|
content: "\2193";
|
||||||
|
content: "\2193\2193";
|
||||||
|
content: "\2193 \2193";
|
||||||
|
content: "\2193\2193\2193";
|
||||||
|
content: "\2193 \2193 \2193";
|
||||||
|
}
|
||||||
|
|
||||||
|
.-top {}
|
||||||
|
.\-top {}
|
||||||
|
|
||||||
|
#\#test {}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.grid.\-top {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.grid.-top {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.grid.\-middle {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.grid.\-bottom {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-m\00002b {}
|
||||||
|
|
||||||
|
.u-m00002b {}
|
||||||
|
|
||||||
|
#u-m\+ {}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: '微软雅黑'; /* some chinese font name */
|
||||||
|
}
|
||||||
|
|
||||||
|
.myStyle {
|
||||||
|
content: '\e901';
|
||||||
|
}
|
||||||
|
|
||||||
|
.myStyle {
|
||||||
|
content: '\E901';
|
||||||
|
}
|
||||||
|
|
||||||
|
.♫ {}
|
||||||
|
|
||||||
|
.\3A \`\( {} /* matches elements with class=":`(" */
|
||||||
|
.\31 a2b3c {} /* matches elements with class="1a2b3c" */
|
||||||
|
#\#fake-id {} /* matches the element with id="#fake-id" */
|
||||||
|
#-a-b-c- {} /* matches the element with id="-a-b-c-" */
|
||||||
|
#© {} /* matches the element with id="©" */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--title-align: center;
|
||||||
|
--sr-only: {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0,0,0,0);
|
||||||
|
white-space: nowrap;
|
||||||
|
clip-path: inset(50%);
|
||||||
|
border: 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
.test {
|
||||||
|
content: "\2014\A0";
|
||||||
|
content: "\2014 \A0";
|
||||||
|
content: "\A0 \2014";
|
||||||
|
content: "\A0\2014";
|
||||||
|
margin-top: 1px\9;
|
||||||
|
background-color: #000\9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light.on .bulb:before{
|
||||||
|
content: '💡';
|
||||||
|
}
|
||||||
|
|
||||||
|
.base64 {
|
||||||
|
background: url(data:img/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAhxJREFUSA3tk71rU1EYxnMTEoJUkowWwdJ2akEHBfGjCiIF6ZylVUKSm2TqZLGI+A/oIu2UXm8C4lAyF4SWji0tdFLo1Eo7VN0SaBEhH7e/Nz0nPTfGOjiaCyfPc5734zlfCQT6X/8E/vUErL81KBaL9y3LSnued5PcITjUOwR3gsFg2bbtjYt6/NGgXC4P1et1l2aPLmpAbD0SidjpdPqgV15PA9d17zQajU8UxHQRK/4G35Q5pveAK8LlI1ZjPMnlcltnyvnvbwaO41xvtVqy7YHztMACq5xnlb9EY3dRdvcGo1kj5wR+t1AofDG0gM+A875E8DNjRCexsrV8Pj9ZqVQitVrtqejxePxjMpmss5hVTB4buXvMb2DyU2tBTRS+BjvNlVYUpPl7iuVO3Gq1uoQx1FtSOW1gPgp5ZWrdBtNmUDgv5asgxQ8F1af5vhY0YjyjuWC3wTszKJz7GBOkcFlQfW2ONq4FjWi+Hj6DRCKxQOK2TlY4x92EuYd5dvMAbYIzfikau3pu5tJ8KxaLLfo0cyKci7tK4TZjUMcoXAmHwzle0Q/RaC5P1GFMyVx9R9Fo9HYqlTrSgqDvFelAqVQa5hmuMR/WGtjAaBdjwBoDQ0ZsnwVMZjKZ9n0Zem8DSeDPdrnZbL6F2l3NOvUYNZk4oVDoRTabPe4EDNJzB0ZcjAYxeoZ2i3FNxQ7BHYw/cB/fldaH//UETgHHO8S44KbfXgAAAABJRU5ErkJggg==);
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href=''] {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href='' i] {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href=""] {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href="" i] {
|
||||||
|
color: blue;
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"bulb": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__bulb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"class": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__class"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"class-duplicate-url": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__class-duplicate-url"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"two": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__two"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grid": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__grid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"-top": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__-top"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"-bottom": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__-bottom"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"#test": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__#test"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"myStyle": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__myStyle"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"♫": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__♫"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
":`(": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__:`("
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"#fake-id": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__#fake-id"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"-a-b-c-": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__-a-b-c-"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"light": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__light"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"u-m+": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__u-m+"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"base64": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__base64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"©": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__©"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__on"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"-middle": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__-middle"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"u-m00002b": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__u-m00002b"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__test"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"1a2b3c": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__1a2b3c"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
112
crates/swc_css_modules/tests/fixture/basic.compiled.css
Normal file
112
crates/swc_css_modules/tests/fixture/basic.compiled.css
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
@charset "UTF-8";
|
||||||
|
@import 'imported.css';
|
||||||
|
.__local__class {
|
||||||
|
color: red;
|
||||||
|
background: url("./url/img.png");
|
||||||
|
}
|
||||||
|
.__local__class-duplicate-url {
|
||||||
|
background: url("./url/img.png");
|
||||||
|
}
|
||||||
|
:root {
|
||||||
|
--foo: 1px;
|
||||||
|
--bar: 2px;
|
||||||
|
}
|
||||||
|
.__local__class {
|
||||||
|
a: b c d;
|
||||||
|
}
|
||||||
|
.__local__two {}
|
||||||
|
.__local__u-m\+ {
|
||||||
|
a: b c d;
|
||||||
|
}
|
||||||
|
.__local__class {
|
||||||
|
content: "\F10C";
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.__local__class {
|
||||||
|
content: "\2193";
|
||||||
|
content: "\2193\2193";
|
||||||
|
content: "\2193 \2193";
|
||||||
|
content: "\2193\2193\2193";
|
||||||
|
content: "\2193 \2193 \2193";
|
||||||
|
}
|
||||||
|
.__local__-top {}
|
||||||
|
.__local__-top {}
|
||||||
|
#__local__\#test {}
|
||||||
|
.__local__grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.__local__grid.__local__-top {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.__local__grid.__local__-top {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.__local__grid.__local__-middle {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.__local__grid.__local__-bottom {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
.__local__u-m\+ {}
|
||||||
|
.__local__u-m00002b {}
|
||||||
|
#__local__u-m\+ {}
|
||||||
|
body {
|
||||||
|
font-family: '微软雅黑';
|
||||||
|
}
|
||||||
|
.__local__myStyle {
|
||||||
|
content: '\e901';
|
||||||
|
}
|
||||||
|
.__local__myStyle {
|
||||||
|
content: '\E901';
|
||||||
|
}
|
||||||
|
.__local__♫ {}
|
||||||
|
.__local__\:\`\( {}
|
||||||
|
.__local__1a2b3c {}
|
||||||
|
#__local__\#fake-id {}
|
||||||
|
#__local__-a-b-c- {}
|
||||||
|
#__local__© {}
|
||||||
|
:root {
|
||||||
|
--title-align: center;
|
||||||
|
--sr-only: {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0,0,0,0);
|
||||||
|
white-space: nowrap;
|
||||||
|
clip-path: inset(50%);
|
||||||
|
border: 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
.__local__test {
|
||||||
|
content: "\2014\A0";
|
||||||
|
content: "\2014 \A0";
|
||||||
|
content: "\A0 \2014";
|
||||||
|
content: "\A0\2014";
|
||||||
|
margin-top: 1px\9;
|
||||||
|
background-color: #000\9;
|
||||||
|
}
|
||||||
|
.__local__light.__local__on .__local__bulb:before {
|
||||||
|
content: '💡';
|
||||||
|
}
|
||||||
|
.__local__base64 {
|
||||||
|
background: url(data:img/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAhxJREFUSA3tk71rU1EYxnMTEoJUkowWwdJ2akEHBfGjCiIF6ZylVUKSm2TqZLGI+A/oIu2UXm8C4lAyF4SWji0tdFLo1Eo7VN0SaBEhH7e/Nz0nPTfGOjiaCyfPc5734zlfCQT6X/8E/vUErL81KBaL9y3LSnued5PcITjUOwR3gsFg2bbtjYt6/NGgXC4P1et1l2aPLmpAbD0SidjpdPqgV15PA9d17zQajU8UxHQRK/4G35Q5pveAK8LlI1ZjPMnlcltnyvnvbwaO41xvtVqy7YHztMACq5xnlb9EY3dRdvcGo1kj5wR+t1AofDG0gM+A875E8DNjRCexsrV8Pj9ZqVQitVrtqejxePxjMpmss5hVTB4buXvMb2DyU2tBTRS+BjvNlVYUpPl7iuVO3Gq1uoQx1FtSOW1gPgp5ZWrdBtNmUDgv5asgxQ8F1af5vhY0YjyjuWC3wTszKJz7GBOkcFlQfW2ONq4FjWi+Hj6DRCKxQOK2TlY4x92EuYd5dvMAbYIzfikau3pu5tJ8KxaLLfo0cyKci7tK4TZjUMcoXAmHwzle0Q/RaC5P1GFMyVx9R9Fo9HYqlTrSgqDvFelAqVQa5hmuMR/WGtjAaBdjwBoDQ0ZsnwVMZjKZ9n0Zem8DSeDPdrnZbL6F2l3NOvUYNZk4oVDoRTabPe4EDNJzB0ZcjAYxeoZ2i3FNxQ7BHYw/cB/fldaH//UETgHHO8S44KbfXgAAAABJRU5ErkJggg==);
|
||||||
|
}
|
||||||
|
a[href=''] {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
a[href='' i] {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
a[href=""] {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
a[href="" i] {
|
||||||
|
color: blue;
|
||||||
|
}
|
137
crates/swc_css_modules/tests/fixture/basic.css
Normal file
137
crates/swc_css_modules/tests/fixture/basic.css
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
@import 'imported.css';
|
||||||
|
|
||||||
|
/* Comment */
|
||||||
|
|
||||||
|
.class {
|
||||||
|
color: red;
|
||||||
|
background: url("./url/img.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.class-duplicate-url {
|
||||||
|
background: url("./url/img.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--foo: 1px;
|
||||||
|
--bar: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.class { a: b c d; }
|
||||||
|
|
||||||
|
.two {}
|
||||||
|
|
||||||
|
.u-m\+ { a: b c d; }
|
||||||
|
|
||||||
|
.class { content: "\F10C" }
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.class {
|
||||||
|
content: "\2193";
|
||||||
|
content: "\2193\2193";
|
||||||
|
content: "\2193 \2193";
|
||||||
|
content: "\2193\2193\2193";
|
||||||
|
content: "\2193 \2193 \2193";
|
||||||
|
}
|
||||||
|
|
||||||
|
.-top {}
|
||||||
|
.\-top {}
|
||||||
|
|
||||||
|
#\#test {}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.grid.\-top {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.grid.-top {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.grid.\-middle {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.grid.\-bottom {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-m\00002b {}
|
||||||
|
|
||||||
|
.u-m00002b {}
|
||||||
|
|
||||||
|
#u-m\+ {}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: '微软雅黑'; /* some chinese font name */
|
||||||
|
}
|
||||||
|
|
||||||
|
.myStyle {
|
||||||
|
content: '\e901';
|
||||||
|
}
|
||||||
|
|
||||||
|
.myStyle {
|
||||||
|
content: '\E901';
|
||||||
|
}
|
||||||
|
|
||||||
|
.♫ {}
|
||||||
|
|
||||||
|
.\3A \`\( {} /* matches elements with class=":`(" */
|
||||||
|
.\31 a2b3c {} /* matches elements with class="1a2b3c" */
|
||||||
|
#\#fake-id {} /* matches the element with id="#fake-id" */
|
||||||
|
#-a-b-c- {} /* matches the element with id="-a-b-c-" */
|
||||||
|
#© {} /* matches the element with id="©" */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--title-align: center;
|
||||||
|
--sr-only: {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0,0,0,0);
|
||||||
|
white-space: nowrap;
|
||||||
|
clip-path: inset(50%);
|
||||||
|
border: 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
.test {
|
||||||
|
content: "\2014\A0";
|
||||||
|
content: "\2014 \A0";
|
||||||
|
content: "\A0 \2014";
|
||||||
|
content: "\A0\2014";
|
||||||
|
margin-top: 1px\9;
|
||||||
|
background-color: #000\9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.light.on .bulb:before{
|
||||||
|
content: '💡';
|
||||||
|
}
|
||||||
|
|
||||||
|
.base64 {
|
||||||
|
background: url(data:img/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAhxJREFUSA3tk71rU1EYxnMTEoJUkowWwdJ2akEHBfGjCiIF6ZylVUKSm2TqZLGI+A/oIu2UXm8C4lAyF4SWji0tdFLo1Eo7VN0SaBEhH7e/Nz0nPTfGOjiaCyfPc5734zlfCQT6X/8E/vUErL81KBaL9y3LSnued5PcITjUOwR3gsFg2bbtjYt6/NGgXC4P1et1l2aPLmpAbD0SidjpdPqgV15PA9d17zQajU8UxHQRK/4G35Q5pveAK8LlI1ZjPMnlcltnyvnvbwaO41xvtVqy7YHztMACq5xnlb9EY3dRdvcGo1kj5wR+t1AofDG0gM+A875E8DNjRCexsrV8Pj9ZqVQitVrtqejxePxjMpmss5hVTB4buXvMb2DyU2tBTRS+BjvNlVYUpPl7iuVO3Gq1uoQx1FtSOW1gPgp5ZWrdBtNmUDgv5asgxQ8F1af5vhY0YjyjuWC3wTszKJz7GBOkcFlQfW2ONq4FjWi+Hj6DRCKxQOK2TlY4x92EuYd5dvMAbYIzfikau3pu5tJ8KxaLLfo0cyKci7tK4TZjUMcoXAmHwzle0Q/RaC5P1GFMyVx9R9Fo9HYqlTrSgqDvFelAqVQa5hmuMR/WGtjAaBdjwBoDQ0ZsnwVMZjKZ9n0Zem8DSeDPdrnZbL6F2l3NOvUYNZk4oVDoRTabPe4EDNJzB0ZcjAYxeoZ2i3FNxQ7BHYw/cB/fldaH//UETgHHO8S44KbfXgAAAABJRU5ErkJggg==);
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href=''] {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href='' i] {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href=""] {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href="" i] {
|
||||||
|
color: blue;
|
||||||
|
}
|
3
crates/swc_css_modules/tests/fixture/basic.imports.json
Normal file
3
crates/swc_css_modules/tests/fixture/basic.imports.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"imported.css"
|
||||||
|
]
|
134
crates/swc_css_modules/tests/fixture/basic.transform.json
Normal file
134
crates/swc_css_modules/tests/fixture/basic.transform.json
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"bulb": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__bulb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"class": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__class"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"class-duplicate-url": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__class-duplicate-url"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"two": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__two"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grid": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__grid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"-top": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__-top"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"-bottom": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__-bottom"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"#test": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__#test"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"myStyle": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__myStyle"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"♫": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__♫"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
":`(": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__:`("
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"#fake-id": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__#fake-id"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"-a-b-c-": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__-a-b-c-"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"light": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__light"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"u-m+": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__u-m+"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"base64": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__base64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"©": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__©"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__on"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"-middle": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__-middle"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"u-m00002b": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__u-m00002b"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__test"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"1a2b3c": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__1a2b3c"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
0
crates/swc_css_modules/tests/fixture/empty.css
Normal file
0
crates/swc_css_modules/tests/fixture/empty.css
Normal file
2
crates/swc_css_modules/tests/fixture/error.compiled.css
Normal file
2
crates/swc_css_modules/tests/fixture/error.compiled.css
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.__local__some {
|
||||||
|
invalid css;}
|
3
crates/swc_css_modules/tests/fixture/error.css
Normal file
3
crates/swc_css_modules/tests/fixture/error.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.some {
|
||||||
|
invalid css;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"some": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__some"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
.__local__foo {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
.foo {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"foo": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__foo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
@charset "UTF-8";
|
||||||
|
@import './imported.css';
|
||||||
|
.__local__class {
|
||||||
|
color: red;
|
||||||
|
background: url("./img.png");
|
||||||
|
}
|
10
crates/swc_css_modules/tests/fixture/es-module/source.css
Normal file
10
crates/swc_css_modules/tests/fixture/es-module/source.css
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@charset "UTF-8";
|
||||||
|
|
||||||
|
@import './imported.css';
|
||||||
|
|
||||||
|
/* Comment */
|
||||||
|
|
||||||
|
.class {
|
||||||
|
color: red;
|
||||||
|
background: url("./img.png");
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"./imported.css"
|
||||||
|
]
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"class": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__class"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
.__local__header-baz {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.__local__body {
|
||||||
|
color: coral;
|
||||||
|
}
|
||||||
|
.__local__footer {
|
||||||
|
color: blue;
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
:local(.header-baz) {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local(.body) {
|
||||||
|
color: coral;
|
||||||
|
}
|
||||||
|
|
||||||
|
:local(.footer) {
|
||||||
|
color: blue;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__body"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"footer": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__footer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"header-baz": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__header-baz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
@import url("https://raw.githubusercontent.com/webpack-contrib/css-loader/master/test/fixtures/url/imported.css");
|
||||||
|
a {
|
||||||
|
background: url("https://raw.githubusercontent.com/webpack-contrib/css-loader/master/test/fixtures/url/img.png");
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
@import url("https://raw.githubusercontent.com/webpack-contrib/css-loader/master/test/fixtures/url/imported.css");
|
||||||
|
|
||||||
|
a {
|
||||||
|
background: url("https://raw.githubusercontent.com/webpack-contrib/css-loader/master/test/fixtures/url/img.png");
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"https://raw.githubusercontent.com/webpack-contrib/css-loader/master/test/fixtures/url/imported.css"
|
||||||
|
]
|
@ -0,0 +1,3 @@
|
|||||||
|
.__local__alias {
|
||||||
|
color: red;
|
||||||
|
}
|
3
crates/swc_css_modules/tests/fixture/import/alias.css
Normal file
3
crates/swc_css_modules/tests/fixture/import/alias.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.alias {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"alias": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__alias"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
@import url(circular.css);
|
||||||
|
div {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
@import url(circular.css);
|
||||||
|
|
||||||
|
div {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"circular.css"
|
||||||
|
]
|
@ -0,0 +1,6 @@
|
|||||||
|
@import url(circular.css);
|
||||||
|
@import url(circular.css);
|
||||||
|
@import url("relative.css");
|
||||||
|
a {
|
||||||
|
color: red;
|
||||||
|
}
|
11
crates/swc_css_modules/tests/fixture/import/circular.css
Normal file
11
crates/swc_css_modules/tests/fixture/import/circular.css
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@import url(circular.css);
|
||||||
|
@import url(circular.css);
|
||||||
|
/*
|
||||||
|
// TODO fixed nested circular `@import`
|
||||||
|
@import url(circular-nested.css);
|
||||||
|
*/
|
||||||
|
@import url("relative.css");
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
"circular.css",
|
||||||
|
"relative.css"
|
||||||
|
]
|
@ -0,0 +1,5 @@
|
|||||||
|
@import url("data:text/css;charset=utf-8;base64,YSB7DQogIGNvbG9yOiByZWQ7DQp9");
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
width: 100px;
|
||||||
|
}
|
6
crates/swc_css_modules/tests/fixture/import/data-uri.css
Normal file
6
crates/swc_css_modules/tests/fixture/import/data-uri.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
@import url("data:text/css;charset=utf-8;base64,YSB7DQogIGNvbG9yOiByZWQ7DQp9");
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
width: 100px;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"data:text/css;charset=utf-8;base64,YSB7DQogIGNvbG9yOiByZWQ7DQp9"
|
||||||
|
]
|
@ -0,0 +1,6 @@
|
|||||||
|
@import url("./import-with-layer.css") layer(form);
|
||||||
|
@layer form {
|
||||||
|
.__local__bar {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
@import url("./import-with-layer.css") layer(form);
|
||||||
|
|
||||||
|
@layer form {
|
||||||
|
.bar {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"./import-with-layer.css"
|
||||||
|
]
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"bar": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__bar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
@import url("./import-with-media.css") screen and (min-width: 400px);
|
@ -0,0 +1 @@
|
|||||||
|
@import url("./import-with-media.css") screen and (min-width: 400px);
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"./import-with-media.css"
|
||||||
|
]
|
@ -0,0 +1 @@
|
|||||||
|
@import url("./import-with-supports.css") supports(display: block);
|
@ -0,0 +1 @@
|
|||||||
|
@import url("./import-with-supports.css") supports(display: block);
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"./import-with-supports.css"
|
||||||
|
]
|
@ -0,0 +1,2 @@
|
|||||||
|
@import url("./relative.css") layer;
|
||||||
|
@import url("./test.css") layer;
|
@ -0,0 +1,3 @@
|
|||||||
|
/* unnamed wrapper layers around each sub-file */
|
||||||
|
@import url("./relative.css") layer;
|
||||||
|
@import url("./test.css") layer;
|
@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
"./relative.css",
|
||||||
|
"./test.css"
|
||||||
|
]
|
@ -0,0 +1 @@
|
|||||||
|
@import url("./deep-layer-base.css") layer(base);
|
@ -0,0 +1,2 @@
|
|||||||
|
/* the internal names are hidden from access, subsumed in "base" */
|
||||||
|
@import url("./deep-layer-base.css") layer(base);
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"./deep-layer-base.css"
|
||||||
|
]
|
@ -0,0 +1,6 @@
|
|||||||
|
@import url(./deep-layer-first-level.css) layer(bootstrap);
|
||||||
|
@layer bootstrap {
|
||||||
|
.__local__test {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
@import url(./deep-layer-first-level.css) layer(bootstrap);
|
||||||
|
|
||||||
|
/* Adds additional styles to the bootstrap layer: */
|
||||||
|
@layer bootstrap {
|
||||||
|
.test {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"./deep-layer-first-level.css"
|
||||||
|
]
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"test": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__test"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
div {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
@import url(./extensions-imported);
|
||||||
|
a {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
@import url(./extensions-imported);
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"./extensions-imported"
|
||||||
|
]
|
@ -0,0 +1,4 @@
|
|||||||
|
@import "/style.css";
|
||||||
|
.__local__class {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
@import "/style.css";
|
||||||
|
|
||||||
|
.class {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"/style.css"
|
||||||
|
]
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"class": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__class"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
@import "~package-with-exports";
|
@ -0,0 +1 @@
|
|||||||
|
@import "~package-with-exports";
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"~package-with-exports"
|
||||||
|
]
|
@ -0,0 +1 @@
|
|||||||
|
@import url("./import-with-supports-and-media.css") supports(display: flex) screen and (min-width: 400px);
|
@ -0,0 +1 @@
|
|||||||
|
@import url("./import-with-supports-and-media.css") supports(display: flex) screen and (min-width: 400px);
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"./import-with-supports-and-media.css"
|
||||||
|
]
|
@ -0,0 +1,5 @@
|
|||||||
|
@import url("./test.css") layer;
|
||||||
|
@import url("./relative.css") layer;
|
||||||
|
.__local__foo {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
@import url("./test.css") layer;
|
||||||
|
@import url("./relative.css") layer;
|
||||||
|
|
||||||
|
.foo {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
"./relative.css",
|
||||||
|
"./test.css"
|
||||||
|
]
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"foo": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__foo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
@import url('./test.css') layer(base);
|
||||||
|
@import url('./relative.css') layer(base);
|
||||||
|
@layer base {
|
||||||
|
.__local__foo {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
@import url('./test.css') layer(base);
|
||||||
|
@import url('./relative.css') layer(base);
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
.foo {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
"./relative.css",
|
||||||
|
"./test.css"
|
||||||
|
]
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"foo": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__foo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
@import "test";
|
||||||
|
@import "issue-683";
|
||||||
|
@import "aliasesPackage";
|
@ -0,0 +1,3 @@
|
|||||||
|
@import "test";
|
||||||
|
@import "issue-683";
|
||||||
|
@import "aliasesPackage";
|
@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
"aliasesPackage",
|
||||||
|
"issue-683",
|
||||||
|
"test"
|
||||||
|
]
|
@ -0,0 +1,5 @@
|
|||||||
|
@import url(/import/test.css);
|
||||||
|
@import "/import/test.css";
|
||||||
|
.__local__class {
|
||||||
|
a: b c d;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
@import url(/import/test.css);
|
||||||
|
@import "/import/test.css";
|
||||||
|
|
||||||
|
.class {
|
||||||
|
a: b c d;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"/import/test.css"
|
||||||
|
]
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"class": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"name": "__local__class"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
@import url("./test.css") layer;
|
||||||
|
.__local__foo {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
@import url("./test.css") layer;
|
||||||
|
|
||||||
|
.foo {
|
||||||
|
color: red;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"./test.css"
|
||||||
|
]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user