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:
Donny/강동윤 2023-04-01 15:15:25 +09:00 committed by GitHub
parent b7366fd5ce
commit df7b4e71d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 144 additions and 81 deletions

View File

@ -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))]

View File

@ -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,

View File

@ -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 {

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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__⌘⌥"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}