Skip to content

Commit

Permalink
Fix partial one off global selectors (#29128)
Browse files Browse the repository at this point in the history
  • Loading branch information
padmaia committed Sep 16, 2021
1 parent e313398 commit c6cec75
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 14 deletions.
81 changes: 67 additions & 14 deletions packages/next/build/swc/src/styled_jsx/transform_css.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use easy_error::{bail, Error};
use std::panic;
use swc_common::{source_map::Pos, BytePos, Span, SyntaxContext, DUMMY_SP};
use swc_css::ast::*;
use swc_css::parser::{parse_str, parse_tokens, parser::ParserConfig};
Expand Down Expand Up @@ -102,17 +103,32 @@ impl VisitMut for Namespacer {
fn visit_mut_complex_selector(&mut self, node: &mut ComplexSelector) {
let mut new_selectors = vec![];
for selector in &node.selectors {
let transformed_selectors = self.get_transformed_selectors(selector.clone());
new_selectors.extend(transformed_selectors);
match self.get_transformed_selectors(selector.clone()) {
Ok(transformed_selectors) => new_selectors.extend(transformed_selectors),
Err(_) => {
HANDLER.with(|handler| {
handler
.struct_span_err(
selector.span,
"Failed to parse tokens inside one off global selector",
)
.emit()
});
new_selectors.push(selector.clone());
}
};
}
node.selectors = new_selectors;
}
}

impl Namespacer {
fn get_transformed_selectors(&mut self, mut node: CompoundSelector) -> Vec<CompoundSelector> {
fn get_transformed_selectors(
&mut self,
mut node: CompoundSelector,
) -> Result<Vec<CompoundSelector>, Error> {
if self.is_global {
return vec![node];
return Ok(vec![node]);
}

let mut pseudo_index = None;
Expand All @@ -121,16 +137,31 @@ impl Namespacer {
// One off global selector
if &name.value == "global" {
let block_tokens = get_block_tokens(&args);
let mut front_tokens = get_front_selector_tokens(&args);
let mut args = args.clone();
args.tokens.extend(block_tokens);
let complex_selectors: Vec<ComplexSelector> = parse_tokens(
&args,
ParserConfig {
parse_values: false,
},
)
.unwrap();
return complex_selectors[0].selectors.clone();
front_tokens.extend(args.tokens);
front_tokens.extend(block_tokens);
args.tokens = front_tokens;
let complex_selectors = panic::catch_unwind(|| {
let x: Vec<ComplexSelector> = parse_tokens(
&args,
ParserConfig {
parse_values: false,
},
)
.unwrap();
return x;
});

return match complex_selectors {
Ok(complex_selectors) => Ok(
complex_selectors[0].selectors[1..]
.iter()
.cloned()
.collect(),
),
Err(_) => bail!("Failed to transform one off global selector"),
};
} else if pseudo_index.is_none() {
pseudo_index = Some(i);
}
Expand All @@ -156,10 +187,32 @@ impl Namespacer {
}),
);

vec![node]
Ok(vec![node])
}
}

fn get_front_selector_tokens(selector_tokens: &Tokens) -> Vec<TokenAndSpan> {
let start_pos = selector_tokens.span.lo.to_u32() - 2;
vec![
TokenAndSpan {
span: Span {
lo: BytePos(start_pos + 0),
hi: BytePos(start_pos + 1),
ctxt: SyntaxContext::empty(),
},
token: Token::Ident("a".into()),
},
TokenAndSpan {
span: Span {
lo: BytePos(start_pos + 1),
hi: BytePos(start_pos + 2),
ctxt: SyntaxContext::empty(),
},
token: Token::WhiteSpace,
},
]
}

fn get_block_tokens(selector_tokens: &Tokens) -> Vec<TokenAndSpan> {
let start_pos = selector_tokens.span.hi.to_u32();
vec![
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default () => (
<div>
<p>test</p>
<style jsx>{`
.container :global(> *) {
color: red;
}
`}</style>
</div>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import _JSXStyle from "styled-jsx/style";
export default (()=><div className={"jsx-c7c3a8e231c9215a"}>
<p className={"jsx-c7c3a8e231c9215a"}>test</p>
<_JSXStyle id={"c7c3a8e231c9215a"}>{".container.jsx-c7c3a8e231c9215a >* {color:red}"}</_JSXStyle>
</div>
);

0 comments on commit c6cec75

Please sign in to comment.