mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 22:22:34 +03:00
feat(css/modules): Preserve spans of CSS class names (#7185)
**Description:** x-ref: https://vercel.slack.com/archives/D03JF6EG45S/p1680280923015879
This commit is contained in:
parent
b7366fd5ce
commit
df7b4e71d2
@ -11,7 +11,7 @@ use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span};
|
||||
use crate::Function;
|
||||
|
||||
#[ast_node("Ident")]
|
||||
#[derive(Eq, Hash)]
|
||||
#[derive(Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Ident {
|
||||
pub span: Span,
|
||||
#[cfg_attr(feature = "rkyv", with(swc_atoms::EncodeJsWord))]
|
||||
|
@ -1,9 +1,8 @@
|
||||
#![feature(box_patterns)]
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::Serialize;
|
||||
use swc_atoms::{js_word, JsWord};
|
||||
use swc_common::util::take::Take;
|
||||
use swc_common::{util::take::Take, Span};
|
||||
use swc_css_ast::{
|
||||
ComplexSelector, ComplexSelectorChildren, ComponentValue, Declaration, DeclarationName,
|
||||
Delimiter, DelimiterValue, FunctionName, Ident, KeyframesName, PseudoClassSelectorChildren,
|
||||
@ -28,19 +27,18 @@ pub trait TransformConfig {
|
||||
// ComponentValue;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum CssClassName {
|
||||
Local {
|
||||
/// Tranformed css class name
|
||||
name: JsWord,
|
||||
name: Ident,
|
||||
},
|
||||
Global {
|
||||
name: JsWord,
|
||||
name: Ident,
|
||||
},
|
||||
Import {
|
||||
/// The exported class name. This is the value specified by the user.
|
||||
name: JsWord,
|
||||
name: Ident,
|
||||
/// The module specifier.
|
||||
from: JsWord,
|
||||
},
|
||||
@ -100,6 +98,7 @@ where
|
||||
n.raw = None;
|
||||
|
||||
rename(
|
||||
n.span,
|
||||
&mut self.config,
|
||||
&mut self.result,
|
||||
&mut self.data.orig_to_renamed,
|
||||
@ -111,6 +110,7 @@ where
|
||||
n.raw = None;
|
||||
|
||||
rename(
|
||||
n.span,
|
||||
&mut self.config,
|
||||
&mut self.result,
|
||||
&mut self.data.orig_to_renamed,
|
||||
@ -265,11 +265,9 @@ where
|
||||
ComponentValue::Str(import_source),
|
||||
) => {
|
||||
for class_name in n.value.iter().take(n.value.len() - 2) {
|
||||
if let ComponentValue::Ident(box Ident { value, .. }) =
|
||||
class_name
|
||||
{
|
||||
if let ComponentValue::Ident(value) = class_name {
|
||||
composes_for_current.push(CssClassName::Import {
|
||||
name: value.clone(),
|
||||
name: *value.clone(),
|
||||
from: import_source.value.clone(),
|
||||
});
|
||||
}
|
||||
@ -288,11 +286,9 @@ where
|
||||
}),
|
||||
) => {
|
||||
for class_name in n.value.iter().take(n.value.len() - 2) {
|
||||
if let ComponentValue::Ident(box Ident { value, .. }) =
|
||||
class_name
|
||||
{
|
||||
if let ComponentValue::Ident(value) = class_name {
|
||||
composes_for_current.push(CssClassName::Global {
|
||||
name: value.clone(),
|
||||
name: *value.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -303,10 +299,14 @@ where
|
||||
}
|
||||
|
||||
for class_name in n.value.iter() {
|
||||
if let ComponentValue::Ident(box Ident { value, .. }) = class_name {
|
||||
if let ComponentValue::Ident(box Ident { span, value, .. }) = class_name {
|
||||
if let Some(value) = self.data.orig_to_renamed.get(value) {
|
||||
composes_for_current.push(CssClassName::Local {
|
||||
name: value.clone(),
|
||||
name: Ident {
|
||||
span: *span,
|
||||
value: value.clone(),
|
||||
raw: None,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -328,7 +328,9 @@ where
|
||||
|
||||
for v in &mut n.value {
|
||||
match v {
|
||||
ComponentValue::Ident(box Ident { value, raw, .. }) => {
|
||||
ComponentValue::Ident(box Ident {
|
||||
span, value, raw, ..
|
||||
}) => {
|
||||
if !can_change {
|
||||
continue;
|
||||
}
|
||||
@ -388,6 +390,7 @@ where
|
||||
*raw = None;
|
||||
|
||||
rename(
|
||||
*span,
|
||||
&mut self.config,
|
||||
&mut self.result,
|
||||
&mut self.data.orig_to_renamed,
|
||||
@ -438,10 +441,14 @@ where
|
||||
}
|
||||
js_word!("animation-name") => {
|
||||
for v in &mut n.value {
|
||||
if let ComponentValue::Ident(box Ident { value, raw, .. }) = v {
|
||||
if let ComponentValue::Ident(box Ident {
|
||||
span, value, raw, ..
|
||||
}) = v
|
||||
{
|
||||
*raw = None;
|
||||
|
||||
rename(
|
||||
*span,
|
||||
&mut self.config,
|
||||
&mut self.result,
|
||||
&mut self.data.orig_to_renamed,
|
||||
@ -565,6 +572,7 @@ where
|
||||
}
|
||||
|
||||
fn rename<C>(
|
||||
span: Span,
|
||||
config: &mut C,
|
||||
result: &mut TransformResult,
|
||||
orig_to_renamed: &mut FxHashMap<JsWord, JsWord>,
|
||||
@ -586,7 +594,13 @@ fn rename<C>(
|
||||
{
|
||||
let e = result.renamed.entry(name.clone()).or_default();
|
||||
|
||||
let v = CssClassName::Local { name: new.clone() };
|
||||
let v = CssClassName::Local {
|
||||
name: Ident {
|
||||
span,
|
||||
value: new.clone(),
|
||||
raw: None,
|
||||
},
|
||||
};
|
||||
if !e.contains(&v) {
|
||||
e.push(v);
|
||||
}
|
||||
@ -609,6 +623,7 @@ fn process_local<C>(
|
||||
sel.text.raw = None;
|
||||
|
||||
rename(
|
||||
sel.span,
|
||||
config,
|
||||
result,
|
||||
orig_to_renamed,
|
||||
@ -620,6 +635,7 @@ fn process_local<C>(
|
||||
sel.text.raw = None;
|
||||
|
||||
rename(
|
||||
sel.span,
|
||||
config,
|
||||
result,
|
||||
orig_to_renamed,
|
||||
|
@ -1,10 +1,13 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::Serialize;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_css_codegen::{
|
||||
writer::basic::{BasicCssWriter, BasicCssWriterConfig, IndentType},
|
||||
CodeGenerator, Emit,
|
||||
};
|
||||
use swc_css_modules::CssClassName;
|
||||
use swc_css_parser::parser::ParserConfig;
|
||||
use testing::NormalizedOutput;
|
||||
|
||||
@ -84,8 +87,34 @@ fn compile(input: PathBuf) {
|
||||
.unwrap();
|
||||
|
||||
if !transform_result.renamed.is_empty() {
|
||||
let transformed_classes =
|
||||
serde_json::to_string_pretty(&transform_result.renamed).unwrap();
|
||||
let transformed_classes = serde_json::to_string_pretty(
|
||||
&transform_result
|
||||
.renamed
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
k,
|
||||
v.into_iter()
|
||||
.map(|v| match v {
|
||||
CssClassName::Global { name } => {
|
||||
CssClassNameForTest::Global { name: name.value }
|
||||
}
|
||||
CssClassName::Local { name } => {
|
||||
CssClassNameForTest::Local { name: name.value }
|
||||
}
|
||||
CssClassName::Import { name, from } => {
|
||||
CssClassNameForTest::Import {
|
||||
name: name.value,
|
||||
from,
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<FxHashMap<_, _>>(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
NormalizedOutput::from(transformed_classes)
|
||||
.compare_to_file(input.with_file_name(format!(
|
||||
@ -99,6 +128,24 @@ fn compile(input: PathBuf) {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
enum CssClassNameForTest {
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
struct TestConfig {}
|
||||
|
||||
impl swc_css_modules::TransformConfig for TestConfig {
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"bulb": [
|
||||
"1a2b3c": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__bulb"
|
||||
"name": "__local__1a2b3c"
|
||||
}
|
||||
],
|
||||
"class": [
|
||||
@ -125,10 +125,10 @@
|
||||
"name": "__local__test"
|
||||
}
|
||||
],
|
||||
"1a2b3c": [
|
||||
"bulb": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__1a2b3c"
|
||||
"name": "__local__bulb"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"bulb": [
|
||||
"1a2b3c": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__bulb"
|
||||
"name": "__local__1a2b3c"
|
||||
}
|
||||
],
|
||||
"class": [
|
||||
@ -125,10 +125,10 @@
|
||||
"name": "__local__test"
|
||||
}
|
||||
],
|
||||
"1a2b3c": [
|
||||
"bulb": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__1a2b3c"
|
||||
"name": "__local__bulb"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"body": [
|
||||
"header-baz": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__body"
|
||||
"name": "__local__header-baz"
|
||||
}
|
||||
],
|
||||
"footer": [
|
||||
@ -11,10 +11,10 @@
|
||||
"name": "__local__footer"
|
||||
}
|
||||
],
|
||||
"header-baz": [
|
||||
"body": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__header-baz"
|
||||
"name": "__local__body"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
{
|
||||
"bar": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__bar"
|
||||
}
|
||||
],
|
||||
"two": [
|
||||
{
|
||||
"type": "local",
|
||||
@ -16,11 +22,5 @@
|
||||
"type": "local",
|
||||
"name": "__local__one"
|
||||
}
|
||||
],
|
||||
"bar": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__bar"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
"⌘⌥": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__⌘⌥"
|
||||
}
|
||||
],
|
||||
"1a2b3c": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__1a2b3c"
|
||||
}
|
||||
],
|
||||
"☺☃": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__☺☃"
|
||||
}
|
||||
],
|
||||
"f+o+o": [
|
||||
{
|
||||
"type": "local",
|
||||
@ -281,10 +281,10 @@
|
||||
"name": "__local__😍"
|
||||
}
|
||||
],
|
||||
"☺☃": [
|
||||
"⌘⌥": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__☺☃"
|
||||
"name": "__local__⌘⌥"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"body": [
|
||||
"header-baz": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__body"
|
||||
"name": "__local__header-baz"
|
||||
}
|
||||
],
|
||||
"footer": [
|
||||
@ -11,10 +11,10 @@
|
||||
"name": "__local__footer"
|
||||
}
|
||||
],
|
||||
"header-baz": [
|
||||
"body": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__header-baz"
|
||||
"name": "__local__body"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"body": [
|
||||
"header-baz": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__body"
|
||||
"name": "__local__header-baz"
|
||||
}
|
||||
],
|
||||
"footer": [
|
||||
@ -11,10 +11,10 @@
|
||||
"name": "__local__footer"
|
||||
}
|
||||
],
|
||||
"header-baz": [
|
||||
"body": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__header-baz"
|
||||
"name": "__local__body"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
{
|
||||
"ghi": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__ghi"
|
||||
}
|
||||
],
|
||||
"jkl": [
|
||||
{
|
||||
"type": "local",
|
||||
@ -16,11 +22,5 @@
|
||||
"type": "local",
|
||||
"name": "__local__def"
|
||||
}
|
||||
],
|
||||
"ghi": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__ghi"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,22 +1,4 @@
|
||||
{
|
||||
"c5": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__c5"
|
||||
}
|
||||
],
|
||||
"c6": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__c6"
|
||||
}
|
||||
],
|
||||
"c7": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__c7"
|
||||
}
|
||||
],
|
||||
"c8": [
|
||||
{
|
||||
"type": "local",
|
||||
@ -40,5 +22,23 @@
|
||||
"type": "local",
|
||||
"name": "__local__c3"
|
||||
}
|
||||
],
|
||||
"c5": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__c5"
|
||||
}
|
||||
],
|
||||
"c6": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__c6"
|
||||
}
|
||||
],
|
||||
"c7": [
|
||||
{
|
||||
"type": "local",
|
||||
"name": "__local__c7"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user