@swc/plugin-styled-jsx 1.5.75 → 1.5.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/Cargo.toml +3 -2
  2. package/package.json +1 -1
  3. package/src/lib.rs +10 -3
  4. package/swc_plugin_styled_jsx.wasm +0 -0
  5. package/transform/Cargo.toml +10 -3
  6. package/transform/src/lib.rs +2 -1
  7. package/transform/src/transform_css_swc.rs +394 -0
  8. package/transform/src/visitor.rs +43 -10
  9. package/transform/tests/errors/nested-style-tags/output.js +31 -4
  10. package/transform/tests/errors/ts-with-css-resolve/output.js +1 -1
  11. package/transform/tests/fixture/absent/output.swc.js +7 -0
  12. package/transform/tests/fixture/attribute-generation-classname-rewriting/output.swc.js +112 -0
  13. package/transform/tests/fixture/attribute-generation-modes/output.swc.js +228 -0
  14. package/transform/tests/fixture/class/output.swc.js +12 -0
  15. package/transform/tests/fixture/comments/output.swc.js +12 -0
  16. package/transform/tests/fixture/component-attribute/output.swc.js +10 -0
  17. package/transform/tests/fixture/conflicts/output.swc.js +14 -0
  18. package/transform/tests/fixture/css-selector-after-pseudo/output.swc.js +11 -0
  19. package/transform/tests/fixture/css-tag-same-file/output.swc.js +21 -0
  20. package/transform/tests/fixture/different-jsx-ids/output.swc.js +24 -0
  21. package/transform/tests/fixture/dynamic-element/output.swc.js +40 -0
  22. package/transform/tests/fixture/dynamic-element-class/output.swc.js +25 -0
  23. package/transform/tests/fixture/dynamic-element-external/output.swc.js +12 -0
  24. package/transform/tests/fixture/dynamic-this-in-arrow/output.swc.js +39 -0
  25. package/transform/tests/fixture/exported-jsx-style/output.swc.js +1 -0
  26. package/transform/tests/fixture/exported-non-jsx-style/output.swc.js +1 -0
  27. package/transform/tests/fixture/external-nested-scope/output.swc.js +7 -0
  28. package/transform/tests/fixture/external-stylesheet/output.swc.js +34 -0
  29. package/transform/tests/fixture/external-stylesheet-global/output.swc.js +18 -0
  30. package/transform/tests/fixture/external-stylesheet-multi-line/output.swc.js +9 -0
  31. package/transform/tests/fixture/fragment/output.swc.js +47 -0
  32. package/transform/tests/fixture/global/output.swc.js +7 -0
  33. package/transform/tests/fixture/global-child-selector/output.swc.js +8 -0
  34. package/transform/tests/fixture/global-redundant/output.swc.js +10 -0
  35. package/transform/tests/fixture/issue-30480/output.swc.js +15 -0
  36. package/transform/tests/fixture/issue-30570/output.swc.js +12 -0
  37. package/transform/tests/fixture/issue-31562-interpolation-in-mdea/output.swc.js +43 -0
  38. package/transform/tests/fixture/mixed-global-scoped/output.swc.js +11 -0
  39. package/transform/tests/fixture/multiple-jsx/output.swc.js +32 -0
  40. package/transform/tests/fixture/next-54653/output.swc.js +3 -0
  41. package/transform/tests/fixture/non-styled-jsx-style/output.swc.js +12 -0
  42. package/transform/tests/fixture/not-styled-jsx-tagged-templates/{output.js → output.lightningcss.js} +1 -2
  43. package/transform/tests/fixture/not-styled-jsx-tagged-templates/output.swc.js +23 -0
  44. package/transform/tests/fixture/number-after-placeholder/output.swc.js +17 -0
  45. package/transform/tests/fixture/one-off-global-selectors/output.swc.js +8 -0
  46. package/transform/tests/fixture/source-maps/output.swc.js +8 -0
  47. package/transform/tests/fixture/styles/output.swc.js +39 -0
  48. package/transform/tests/fixture/styles-external-invalid/output.swc.js +9 -0
  49. package/transform/tests/fixture/styles-external-invalid2/output.swc.js +8 -0
  50. package/transform/tests/fixture/styles2/output.swc.js +5 -0
  51. package/transform/tests/fixture/too-many/output.swc.js +49 -0
  52. package/transform/tests/fixture/tpl-escape-1/output.swc.js +12 -0
  53. package/transform/tests/fixture/tpl-escape-2/output.swc.js +17 -0
  54. package/transform/tests/fixture/tpl-placeholder-1-as-property/output.swc.js +28 -0
  55. package/transform/tests/fixture/tpl-placeholder-2-as-part-of-value/output.swc.js +34 -0
  56. package/transform/tests/fixture/tpl-placeholder-3-as-value/output.swc.js +28 -0
  57. package/transform/tests/fixture/tpl-placeholder-4-as-part-of-value-in-multiple/output.swc.js +31 -0
  58. package/transform/tests/fixture/tpl-placeholder-5-values-of-multiple-properties/output.swc.js +31 -0
  59. package/transform/tests/fixture/transform-css/output.swc.js +8 -0
  60. package/transform/tests/fixture/transform-css-complex-selector/output.swc.js +8 -0
  61. package/transform/tests/fixture/transform-css-complex-selector-2/output.swc.js +8 -0
  62. package/transform/tests/fixture/transform-css-global/output.swc.js +8 -0
  63. package/transform/tests/fixture/transform-css-media-query/output.swc.js +8 -0
  64. package/transform/tests/fixture/transform-css-normal/output.swc.js +8 -0
  65. package/transform/tests/fixture/transform-css-nth-1/output.swc.js +8 -0
  66. package/transform/tests/fixture/whitespace/output.lightningcss.js +12 -0
  67. package/transform/tests/fixture/whitespace/output.swc.js +12 -0
  68. package/transform/tests/fixture.rs +55 -38
  69. package/transform/tests/fixture/.expressions/output.js +0 -91
  70. package/transform/tests/fixture/nested-style-tags/output.js +0 -0
  71. /package/transform/src/{transform_css.rs → transform_css_lightningcss.rs} +0 -0
  72. /package/transform/tests/fixture/absent/{output.js → output.lightningcss.js} +0 -0
  73. /package/transform/tests/fixture/attribute-generation-classname-rewriting/{output.js → output.lightningcss.js} +0 -0
  74. /package/transform/tests/fixture/attribute-generation-modes/{output.js → output.lightningcss.js} +0 -0
  75. /package/transform/tests/fixture/class/{output.js → output.lightningcss.js} +0 -0
  76. /package/transform/tests/fixture/comments/{output.js → output.lightningcss.js} +0 -0
  77. /package/transform/tests/fixture/component-attribute/{output.js → output.lightningcss.js} +0 -0
  78. /package/transform/tests/fixture/conflicts/{output.js → output.lightningcss.js} +0 -0
  79. /package/transform/tests/fixture/css-selector-after-pseudo/{output.js → output.lightningcss.js} +0 -0
  80. /package/transform/tests/fixture/css-tag-same-file/{output.js → output.lightningcss.js} +0 -0
  81. /package/transform/tests/fixture/different-jsx-ids/{output.js → output.lightningcss.js} +0 -0
  82. /package/transform/tests/fixture/dynamic-element/{output.js → output.lightningcss.js} +0 -0
  83. /package/transform/tests/fixture/dynamic-element-class/{output.js → output.lightningcss.js} +0 -0
  84. /package/transform/tests/fixture/dynamic-element-external/{output.js → output.lightningcss.js} +0 -0
  85. /package/transform/tests/fixture/dynamic-this-in-arrow/{output.js → output.lightningcss.js} +0 -0
  86. /package/transform/tests/fixture/exported-jsx-style/{output.js → output.lightningcss.js} +0 -0
  87. /package/transform/tests/fixture/exported-non-jsx-style/{output.js → output.lightningcss.js} +0 -0
  88. /package/transform/tests/fixture/external-nested-scope/{output.js → output.lightningcss.js} +0 -0
  89. /package/transform/tests/fixture/external-stylesheet/{output.js → output.lightningcss.js} +0 -0
  90. /package/transform/tests/fixture/external-stylesheet-global/{output.js → output.lightningcss.js} +0 -0
  91. /package/transform/tests/fixture/external-stylesheet-multi-line/{output.js → output.lightningcss.js} +0 -0
  92. /package/transform/tests/fixture/fragment/{output.js → output.lightningcss.js} +0 -0
  93. /package/transform/tests/fixture/global/{output.js → output.lightningcss.js} +0 -0
  94. /package/transform/tests/fixture/global-child-selector/{output.js → output.lightningcss.js} +0 -0
  95. /package/transform/tests/fixture/global-redundant/{output.js → output.lightningcss.js} +0 -0
  96. /package/transform/tests/fixture/issue-30480/{output.js → output.lightningcss.js} +0 -0
  97. /package/transform/tests/fixture/issue-30570/{output.js → output.lightningcss.js} +0 -0
  98. /package/transform/tests/fixture/issue-31562-interpolation-in-mdea/{output.js → output.lightningcss.js} +0 -0
  99. /package/transform/tests/fixture/mixed-global-scoped/{output.js → output.lightningcss.js} +0 -0
  100. /package/transform/tests/fixture/multiple-jsx/{output.js → output.lightningcss.js} +0 -0
  101. /package/transform/tests/fixture/next-54653/{output.js → output.lightningcss.js} +0 -0
  102. /package/transform/tests/fixture/non-styled-jsx-style/{output.js → output.lightningcss.js} +0 -0
  103. /package/transform/tests/fixture/number-after-placeholder/{output.js → output.lightningcss.js} +0 -0
  104. /package/transform/tests/fixture/one-off-global-selectors/{output.js → output.lightningcss.js} +0 -0
  105. /package/transform/tests/fixture/source-maps/{output.js → output.lightningcss.js} +0 -0
  106. /package/transform/tests/fixture/stateless/{output.js → output.lightningcss.js} +0 -0
  107. /package/transform/tests/fixture/{whitespace/output.js → stateless/output.swc.js} +0 -0
  108. /package/transform/tests/fixture/styles/{output.js → output.lightningcss.js} +0 -0
  109. /package/transform/tests/fixture/styles-external-invalid/{output.js → output.lightningcss.js} +0 -0
  110. /package/transform/tests/fixture/styles-external-invalid2/{output.js → output.lightningcss.js} +0 -0
  111. /package/transform/tests/fixture/styles2/{output.js → output.lightningcss.js} +0 -0
  112. /package/transform/tests/fixture/too-many/{output.js → output.lightningcss.js} +0 -0
  113. /package/transform/tests/fixture/tpl-escape-1/{output.js → output.lightningcss.js} +0 -0
  114. /package/transform/tests/fixture/tpl-escape-2/{output.js → output.lightningcss.js} +0 -0
  115. /package/transform/tests/fixture/tpl-placeholder-1-as-property/{output.js → output.lightningcss.js} +0 -0
  116. /package/transform/tests/fixture/tpl-placeholder-2-as-part-of-value/{output.js → output.lightningcss.js} +0 -0
  117. /package/transform/tests/fixture/tpl-placeholder-3-as-value/{output.js → output.lightningcss.js} +0 -0
  118. /package/transform/tests/fixture/tpl-placeholder-4-as-part-of-value-in-multiple/{output.js → output.lightningcss.js} +0 -0
  119. /package/transform/tests/fixture/tpl-placeholder-5-values-of-multiple-properties/{output.js → output.lightningcss.js} +0 -0
  120. /package/transform/tests/fixture/transform-css/{output.js → output.lightningcss.js} +0 -0
  121. /package/transform/tests/fixture/transform-css-complex-selector/{output.js → output.lightningcss.js} +0 -0
  122. /package/transform/tests/fixture/transform-css-complex-selector-2/{output.js → output.lightningcss.js} +0 -0
  123. /package/transform/tests/fixture/transform-css-global/{output.js → output.lightningcss.js} +0 -0
  124. /package/transform/tests/fixture/transform-css-media-query/{output.js → output.lightningcss.js} +0 -0
  125. /package/transform/tests/fixture/transform-css-normal/{output.js → output.lightningcss.js} +0 -0
  126. /package/transform/tests/fixture/transform-css-nth-1/{output.js → output.lightningcss.js} +0 -0
package/Cargo.toml CHANGED
@@ -16,7 +16,7 @@ custom_transform = ["swc_core/common_concurrent"]
16
16
  [dependencies]
17
17
  easy-error = "1.0.0"
18
18
  styled_jsx = { path = "./transform" }
19
- swc_core = { version = "0.82.10", features = [
19
+ swc_core = { version = "0.83.0", features = [
20
20
  "common",
21
21
  "ecma_ast",
22
22
  "ecma_plugin_transform",
@@ -26,7 +26,8 @@ swc_core = { version = "0.82.10", features = [
26
26
  "ecma_visit",
27
27
  ] }
28
28
  tracing = { version = "0.1.37", features = ["release_max_level_off"] }
29
+ serde_json = "1"
29
30
 
30
31
  [dev-dependencies]
31
- swc_core = { features = ["testing_transform"], version = "0.82.10" }
32
+ swc_core = { features = ["testing_transform"], version = "0.83.0" }
32
33
  testing = "0.34.1"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swc/plugin-styled-jsx",
3
- "version": "1.5.75",
3
+ "version": "1.5.77",
4
4
  "description": "SWC plugin for styled-jsx",
5
5
  "main": "swc_plugin_styled_jsx.wasm",
6
6
  "scripts": {
package/src/lib.rs CHANGED
@@ -1,7 +1,7 @@
1
1
  #![allow(clippy::not_unsafe_ptr_arg_deref)]
2
2
  #![feature(box_patterns)]
3
3
 
4
- use styled_jsx::visitor;
4
+ use styled_jsx::{visitor, visitor::Config};
5
5
  use swc_core::{
6
6
  common::{sync::Lrc, FileName, SourceMap},
7
7
  ecma::{ast::Program, visit::FoldWith},
@@ -9,9 +9,16 @@ use swc_core::{
9
9
  };
10
10
 
11
11
  #[plugin_transform]
12
- fn styled_jsx_plugin(program: Program, _: TransformPluginProgramMetadata) -> Program {
12
+ fn styled_jsx_plugin(program: Program, data: TransformPluginProgramMetadata) -> Program {
13
+ let config = serde_json::from_str::<Config>(
14
+ &data
15
+ .get_transform_plugin_config()
16
+ .expect("failed to get plugin config for styled-jsx"),
17
+ )
18
+ .expect("invalid config for styled-jsx");
19
+
13
20
  // TODO(kdy1): This is wrong, but it does not use cm
14
21
  let cm = Lrc::new(SourceMap::default());
15
22
 
16
- program.fold_with(&mut visitor::styled_jsx(cm, FileName::Anon))
23
+ program.fold_with(&mut visitor::styled_jsx(cm, FileName::Anon, config))
17
24
  }
Binary file
@@ -4,7 +4,7 @@ description = "AST transforms visitor for styled-jsx"
4
4
  edition = "2021"
5
5
  license = "Apache-2.0"
6
6
  name = "styled_jsx"
7
- version = "0.42.0"
7
+ version = "0.44.0"
8
8
 
9
9
  [features]
10
10
  custom_transform = ["swc_core/common_concurrent"]
@@ -17,9 +17,16 @@ lightningcss = { version = "1.0.0-alpha.44", features = [
17
17
  "into_owned",
18
18
  ] }
19
19
  parcel_selectors = "0.26.0"
20
+ serde = { version = "1", features = ["derive"] }
20
21
 
21
- swc_core = { version = "0.82.10", features = [
22
+ swc_core = { version = "0.83.0", features = [
22
23
  "common",
24
+ "css_ast",
25
+ "css_codegen",
26
+ "css_parser",
27
+ "css_prefixer",
28
+ "css_minifier",
29
+ "css_visit",
23
30
  "ecma_ast",
24
31
  "ecma_parser",
25
32
  "ecma_minifier",
@@ -29,4 +36,4 @@ swc_core = { version = "0.82.10", features = [
29
36
 
30
37
  [dev-dependencies]
31
38
  testing = "0.34.1"
32
- swc_core = { features = ["testing_transform"], version = "0.82.10" }
39
+ swc_core = { features = ["testing_transform"], version = "0.83.0" }
@@ -1,6 +1,7 @@
1
1
  #![feature(box_patterns)]
2
2
  mod lifetime;
3
3
  pub mod style;
4
- mod transform_css;
4
+ mod transform_css_lightningcss;
5
+ mod transform_css_swc;
5
6
  mod utils;
6
7
  pub mod visitor;
@@ -0,0 +1,394 @@
1
+ use std::{panic, sync::Arc};
2
+
3
+ use easy_error::{bail, Error};
4
+ use swc_core::{
5
+ common::{
6
+ errors::HANDLER, source_map::Pos, util::take::Take, BytePos, SourceMap, Span, Spanned,
7
+ SyntaxContext, DUMMY_SP,
8
+ },
9
+ css::{
10
+ ast::*,
11
+ codegen::{
12
+ writer::basic::{BasicCssWriter, BasicCssWriterConfig},
13
+ CodeGenerator, CodegenConfig, Emit,
14
+ },
15
+ parser::{
16
+ lexer::Lexer,
17
+ parse_input,
18
+ parser::{
19
+ input::{InputType, Tokens},
20
+ Parser, ParserConfig,
21
+ },
22
+ },
23
+ prefixer::prefixer,
24
+ visit::{VisitMut, VisitMutWith},
25
+ },
26
+ ecma::{
27
+ ast::{Expr, Tpl, TplElement},
28
+ parser::StringInput,
29
+ },
30
+ };
31
+ use tracing::{debug, trace};
32
+
33
+ use crate::{
34
+ style::LocalStyle,
35
+ utils::{hash_string, string_literal_expr},
36
+ };
37
+
38
+ pub fn transform_css(
39
+ _cm: Arc<SourceMap>,
40
+ style_info: &LocalStyle,
41
+ is_global: bool,
42
+ class_name: &Option<String>,
43
+ ) -> Result<Expr, Error> {
44
+ debug!("CSS: \n{}", style_info.css);
45
+
46
+ // TODO use `parse_string_input` in future
47
+ let config = ParserConfig {
48
+ allow_wrong_line_comments: true,
49
+ css_modules: false,
50
+ ..Default::default()
51
+ };
52
+ let lexer = Lexer::new(
53
+ StringInput::new(
54
+ &style_info.css,
55
+ style_info.css_span.lo,
56
+ style_info.css_span.hi,
57
+ ),
58
+ config,
59
+ );
60
+ let mut parser = Parser::new(lexer, config);
61
+
62
+ let result: Result<Stylesheet, _> = parser.parse_all();
63
+ let mut ss = match result {
64
+ Ok(ss) => ss,
65
+ Err(err) => {
66
+ HANDLER.with(|handler| {
67
+ // Print css parsing errors
68
+ err.to_diagnostics(handler).emit();
69
+
70
+ // TODO(kdy1): We may print css so the user can see the error, and report it.
71
+
72
+ handler
73
+ .struct_span_err(
74
+ style_info.css_span,
75
+ "Failed to parse css in styled jsx component",
76
+ )
77
+ .note(&format!("Input to the css parser is {}", style_info.css))
78
+ .emit()
79
+ });
80
+ bail!("Failed to parse css");
81
+ }
82
+ };
83
+ // ? Do we need to support optionally prefixing?
84
+ ss.visit_mut_with(&mut prefixer(Default::default()));
85
+ ss.visit_mut_with(&mut Namespacer {
86
+ class_name: match class_name {
87
+ Some(s) => s.clone(),
88
+ None => format!("jsx-{}", &hash_string(&style_info.hash)),
89
+ },
90
+ is_global,
91
+ is_dynamic: style_info.is_dynamic,
92
+ });
93
+
94
+ let mut s = String::new();
95
+ {
96
+ let mut wr = BasicCssWriter::new(&mut s, None, BasicCssWriterConfig::default());
97
+ let mut gen = CodeGenerator::new(&mut wr, CodegenConfig { minify: true });
98
+
99
+ gen.emit(&ss).unwrap();
100
+ }
101
+
102
+ if style_info.expressions.is_empty() {
103
+ return Ok(string_literal_expr(&s));
104
+ }
105
+
106
+ let mut parts: Vec<&str> = s.split("__styled-jsx-placeholder-").collect();
107
+ let mut final_expressions = vec![];
108
+ for i in parts.iter_mut().skip(1) {
109
+ let (num_len, expression_index) = read_number(i);
110
+ final_expressions.push(style_info.expressions[expression_index].clone());
111
+ let substr = &i[(num_len + 2)..];
112
+ *i = substr;
113
+ }
114
+
115
+ Ok(Expr::Tpl(Tpl {
116
+ quasis: parts
117
+ .iter()
118
+ .map(|quasi| {
119
+ TplElement {
120
+ cooked: None, // ? Do we need cooked as well
121
+ raw: quasi.replace('`', "\\`").into(),
122
+ span: DUMMY_SP,
123
+ tail: false,
124
+ }
125
+ })
126
+ .collect(),
127
+ exprs: final_expressions,
128
+ span: DUMMY_SP,
129
+ }))
130
+ }
131
+
132
+ /// Returns `(length, value)`
133
+ fn read_number(s: &str) -> (usize, usize) {
134
+ for (idx, c) in s.char_indices() {
135
+ if c.is_ascii_digit() {
136
+ continue;
137
+ }
138
+
139
+ // For 10, we reach here after `0`.
140
+ let value = s[0..idx].parse().expect("failed to parse");
141
+
142
+ return (idx, value);
143
+ }
144
+
145
+ unreachable!("read_number(`{}`) is invalid because it is empty", s)
146
+ }
147
+
148
+ struct Namespacer {
149
+ class_name: String,
150
+ is_global: bool,
151
+ is_dynamic: bool,
152
+ }
153
+
154
+ impl VisitMut for Namespacer {
155
+ fn visit_mut_complex_selector(&mut self, node: &mut ComplexSelector) {
156
+ #[cfg(debug_assertions)]
157
+ let _tracing = {
158
+ // This will add information to the log messages, only for debug build.
159
+ // Note that we use cargo feature to remove all logging on production builds.
160
+
161
+ let mut code = String::new();
162
+ {
163
+ let mut wr = BasicCssWriter::new(&mut code, None, BasicCssWriterConfig::default());
164
+ let mut gen = CodeGenerator::new(&mut wr, CodegenConfig { minify: true });
165
+
166
+ gen.emit(&*node).unwrap();
167
+ }
168
+
169
+ tracing::span!(
170
+ tracing::Level::TRACE,
171
+ "Namespacer::visit_mut_complex_selector",
172
+ class_name = &*self.class_name,
173
+ is_global = self.is_global,
174
+ is_dynamic = self.is_dynamic,
175
+ input = &*code
176
+ )
177
+ .entered()
178
+ };
179
+
180
+ let mut new_selectors = vec![];
181
+ let mut combinator = None;
182
+
183
+ for sel in node.children.take() {
184
+ match &sel {
185
+ ComplexSelectorChildren::CompoundSelector(selector) => {
186
+ match self.get_transformed_selectors(combinator, selector.clone()) {
187
+ Ok(transformed_selectors) => new_selectors.extend(transformed_selectors),
188
+ Err(_) => {
189
+ HANDLER.with(|handler| {
190
+ handler
191
+ .struct_span_err(
192
+ selector.span,
193
+ "Failed to transform one off global selector",
194
+ )
195
+ .emit()
196
+ });
197
+ new_selectors.push(sel);
198
+ }
199
+ }
200
+
201
+ combinator = None;
202
+ }
203
+ ComplexSelectorChildren::Combinator(v) => {
204
+ combinator = Some(v.clone());
205
+ }
206
+ };
207
+ }
208
+
209
+ node.children = new_selectors;
210
+ }
211
+ }
212
+
213
+ impl Namespacer {
214
+ fn get_transformed_selectors(
215
+ &mut self,
216
+ combinator: Option<Combinator>,
217
+ mut node: CompoundSelector,
218
+ ) -> Result<Vec<ComplexSelectorChildren>, Error> {
219
+ let mut pseudo_index = None;
220
+
221
+ for (i, selector) in node.subclass_selectors.iter().enumerate() {
222
+ let (name, children) = match &selector {
223
+ SubclassSelector::PseudoClass(PseudoClassSelector {
224
+ name,
225
+ children: Some(children),
226
+ ..
227
+ }) if &name.value == "global" => (name, children),
228
+ SubclassSelector::PseudoClass(_) | SubclassSelector::PseudoElement(_) => {
229
+ if pseudo_index.is_none() {
230
+ pseudo_index = Some(i);
231
+ }
232
+
233
+ continue;
234
+ }
235
+ _ => continue,
236
+ };
237
+
238
+ // One off global selector
239
+ if &name.value == "global" {
240
+ // TODO(alexander-akait): in future we should use list of component values
241
+ let tokens = children
242
+ .iter()
243
+ .map(|v| match v {
244
+ PseudoClassSelectorChildren::PreservedToken(v) => v.clone(),
245
+ _ => {
246
+ unreachable!();
247
+ }
248
+ })
249
+ .collect::<Vec<TokenAndSpan>>();
250
+ let mut tokens = {
251
+ let lo = tokens.first().map(|v| v.span_lo()).unwrap_or(BytePos(0));
252
+ let hi = tokens.last().map(|v| v.span_hi()).unwrap_or(BytePos(0));
253
+
254
+ Tokens {
255
+ span: Span::new(lo, hi, Default::default()),
256
+ tokens,
257
+ }
258
+ };
259
+
260
+ // Because it is allowed to write `.bar :global(> .foo) {}` or .bar
261
+ // :global(.foo) {}`, so selector can be complex or relative (it violates the
262
+ // specification), but it is popular usage, so we just add `a >` at top and then
263
+ // remove it
264
+ let mut front_tokens = get_front_selector_tokens(&tokens);
265
+
266
+ front_tokens.extend(tokens.tokens);
267
+
268
+ tokens.tokens = front_tokens;
269
+
270
+ let complex_selectors = panic::catch_unwind(|| {
271
+ let x: ComplexSelector = parse_input(
272
+ InputType::Tokens(&tokens),
273
+ ParserConfig {
274
+ allow_wrong_line_comments: true,
275
+ css_modules: true,
276
+ ..Default::default()
277
+ },
278
+ // TODO(kdy1): We might be able to report syntax errors.
279
+ &mut vec![],
280
+ )
281
+ .unwrap();
282
+ x
283
+ });
284
+
285
+ return match complex_selectors {
286
+ Ok(complex_selectors) => {
287
+ let mut v = complex_selectors.children[1..].to_vec();
288
+
289
+ if let ComplexSelectorChildren::Combinator(Combinator {
290
+ value: CombinatorValue::Descendant,
291
+ ..
292
+ }) = v[0]
293
+ {
294
+ v.remove(0);
295
+ }
296
+
297
+ if v.is_empty() {
298
+ bail!("Failed to transform one off global selector");
299
+ }
300
+
301
+ trace!("Combinator: {:?}", combinator);
302
+ trace!("v[0]: {:?}", v[0]);
303
+
304
+ let mut result = vec![];
305
+
306
+ if let Some(combinator) = combinator {
307
+ match v.get(0) {
308
+ // `Descendant` combinator can't be the first because we removed it
309
+ // above
310
+ Some(ComplexSelectorChildren::Combinator(..))
311
+ if combinator.value == CombinatorValue::Descendant => {}
312
+ _ => {
313
+ result.push(ComplexSelectorChildren::Combinator(combinator));
314
+ }
315
+ }
316
+ }
317
+
318
+ v.iter_mut().for_each(|sel| {
319
+ if i < node.subclass_selectors.len() {
320
+ if let ComplexSelectorChildren::CompoundSelector(sel) = sel {
321
+ sel.subclass_selectors
322
+ .extend(node.subclass_selectors[i + 1..].iter().cloned());
323
+ }
324
+ }
325
+ });
326
+
327
+ result.extend(v);
328
+
329
+ Ok(result)
330
+ }
331
+ Err(_) => bail!("Failed to transform one off global selector"),
332
+ };
333
+ }
334
+ }
335
+
336
+ let subclass_selector = match self.is_dynamic {
337
+ true => "__jsx-style-dynamic-selector",
338
+ false => &self.class_name,
339
+ };
340
+ let insert_index = match pseudo_index {
341
+ None => node.subclass_selectors.len(),
342
+ Some(i) => i,
343
+ };
344
+
345
+ if !self.is_global {
346
+ node.subclass_selectors.insert(
347
+ insert_index,
348
+ SubclassSelector::Class(ClassSelector {
349
+ span: DUMMY_SP,
350
+ text: Ident {
351
+ raw: Some(subclass_selector.into()),
352
+ value: subclass_selector.into(),
353
+ span: DUMMY_SP,
354
+ },
355
+ }),
356
+ );
357
+ }
358
+
359
+ let mut result = vec![];
360
+
361
+ if let Some(combinator) = combinator {
362
+ result.push(ComplexSelectorChildren::Combinator(combinator));
363
+ }
364
+
365
+ result.push(ComplexSelectorChildren::CompoundSelector(node));
366
+
367
+ Ok(result)
368
+ }
369
+ }
370
+
371
+ fn get_front_selector_tokens(selector_tokens: &Tokens) -> Vec<TokenAndSpan> {
372
+ let start_pos = selector_tokens.span.lo.to_u32() - 2;
373
+ vec![
374
+ TokenAndSpan {
375
+ span: Span {
376
+ lo: BytePos(start_pos),
377
+ hi: BytePos(start_pos + 1),
378
+ ctxt: SyntaxContext::empty(),
379
+ },
380
+ token: Token::Ident {
381
+ raw: "a".into(),
382
+ value: "a".into(),
383
+ },
384
+ },
385
+ TokenAndSpan {
386
+ span: Span {
387
+ lo: BytePos(start_pos + 1),
388
+ hi: BytePos(start_pos + 2),
389
+ ctxt: SyntaxContext::empty(),
390
+ },
391
+ token: Token::WhiteSpace { value: " ".into() },
392
+ },
393
+ ]
394
+ }
@@ -6,6 +6,7 @@ use std::{
6
6
  };
7
7
 
8
8
  use easy_error::{bail, Error};
9
+ use serde::Deserialize;
9
10
  use swc_core::{
10
11
  common::{collections::AHashSet, errors::HANDLER, FileName, SourceMap, Span, DUMMY_SP},
11
12
  ecma::{
@@ -21,16 +22,21 @@ use swc_core::{
21
22
 
22
23
  use crate::{
23
24
  style::{ExternalStyle, JSXStyle, LocalStyle},
24
- transform_css::transform_css,
25
25
  utils::{
26
26
  add, and, compute_class_names, get_usable_import_specifier, hash_string, ident,
27
27
  is_capitalized, make_external_styled_jsx_el, make_local_styled_jsx_el, not_eq, or,
28
28
  string_literal_expr, styled_jsx_import_decl,
29
29
  },
30
30
  };
31
- //use external::external_styles;
32
31
 
33
- pub fn styled_jsx(cm: Arc<SourceMap>, file_name: FileName) -> impl Fold {
32
+ #[derive(Deserialize)]
33
+ #[serde(rename_all = "camelCase")]
34
+ pub struct Config {
35
+ #[serde(default)]
36
+ pub use_lightningcss: bool,
37
+ }
38
+
39
+ pub fn styled_jsx(cm: Arc<SourceMap>, file_name: FileName, config: Config) -> impl Fold {
34
40
  let file_name = match file_name {
35
41
  FileName::Real(real_file_name) => real_file_name
36
42
  .to_str()
@@ -40,6 +46,7 @@ pub fn styled_jsx(cm: Arc<SourceMap>, file_name: FileName) -> impl Fold {
40
46
 
41
47
  StyledJSXTransformer {
42
48
  cm,
49
+ config,
43
50
  file_name,
44
51
  styles: Default::default(),
45
52
  static_class_name: Default::default(),
@@ -63,6 +70,8 @@ pub fn styled_jsx(cm: Arc<SourceMap>, file_name: FileName) -> impl Fold {
63
70
 
64
71
  struct StyledJSXTransformer {
65
72
  cm: Arc<SourceMap>,
73
+ config: Config,
74
+
66
75
  file_name: Option<String>,
67
76
  styles: Vec<JSXStyle>,
68
77
  static_class_name: Option<String>,
@@ -564,12 +573,22 @@ impl StyledJSXTransformer {
564
573
 
565
574
  match &style_info {
566
575
  JSXStyle::Local(style_info) => {
567
- let css = transform_css(
568
- self.cm.clone(),
569
- style_info,
570
- is_global,
571
- &self.static_class_name,
572
- )?;
576
+ let css = if self.config.use_lightningcss {
577
+ crate::transform_css_lightningcss::transform_css(
578
+ self.cm.clone(),
579
+ style_info,
580
+ is_global,
581
+ &self.static_class_name,
582
+ )?
583
+ } else {
584
+ crate::transform_css_swc::transform_css(
585
+ self.cm.clone(),
586
+ style_info,
587
+ is_global,
588
+ &self.static_class_name,
589
+ )?
590
+ };
591
+
573
592
  Ok(make_local_styled_jsx_el(
574
593
  style_info,
575
594
  css,
@@ -618,7 +637,21 @@ impl StyledJSXTransformer {
618
637
  } else {
619
638
  bail!("This shouldn't happen, we already know that this is a template literal");
620
639
  };
621
- let css = transform_css(self.cm.clone(), style, tag == "global", &static_class_name)?;
640
+ let css = if self.config.use_lightningcss {
641
+ crate::transform_css_lightningcss::transform_css(
642
+ self.cm.clone(),
643
+ style,
644
+ tag == "global",
645
+ &static_class_name,
646
+ )?
647
+ } else {
648
+ crate::transform_css_swc::transform_css(
649
+ self.cm.clone(),
650
+ style,
651
+ tag == "global",
652
+ &static_class_name,
653
+ )?
654
+ };
622
655
  if tag == "resolve" {
623
656
  self.file_has_css_resolve = true;
624
657
  return Ok(Expr::Object(ObjectLit {
@@ -1,31 +1,58 @@
1
1
  import _JSXStyle from "styled-jsx/style";
2
2
  const Component = ()=><>
3
- <header >
4
- <Comp >
3
+
4
+ <header>
5
+
6
+ <Comp>
7
+
5
8
  <_JSXStyle id={styles.__hash}>{styles}</_JSXStyle>
9
+
6
10
  <_JSXStyle id={"b3e1b6a7c9b96113"}>{""}</_JSXStyle>
11
+
7
12
  </Comp>
13
+
8
14
  <p className={"jsx-b3e1b6a7c9b96113"}><_JSXStyle id={"b3e1b6a7c9b96113"}>{""}</_JSXStyle></p>
15
+
9
16
  </header>
17
+
10
18
  <div className={"jsx-b3e1b6a7c9b96113"}>
19
+
11
20
  <h1 className={"jsx-b3e1b6a7c9b96113"}>
21
+
12
22
  Welcome!
23
+
13
24
  <style jsx>{``}</style>
25
+
14
26
  </h1>
27
+
15
28
  <_JSXStyle id={"b3e1b6a7c9b96113"}>{""}</_JSXStyle>
29
+
16
30
  </div>
31
+
17
32
  <div className={"jsx-b3e1b6a7c9b96113"}>
33
+
18
34
  <_JSXStyle id={"b3e1b6a7c9b96113"}>{""}</_JSXStyle>
35
+
19
36
  <h1 className={"jsx-b3e1b6a7c9b96113"}>
37
+
20
38
  Hello world!
39
+
21
40
  <style jsx global>{``}</style>
41
+
22
42
  </h1>
43
+
23
44
  </div>
45
+
24
46
  <div className={"jsx-b3e1b6a7c9b96113"}>
47
+
25
48
  <>
49
+
26
50
  <style jsx>{styles}</style>
51
+
27
52
  </>
53
+
28
54
  <_JSXStyle id={"b3e1b6a7c9b96113"}>{""}</_JSXStyle>
55
+
29
56
  </div>
30
- </>
31
- ;
57
+
58
+ </>;
@@ -1,5 +1,5 @@
1
1
  import _JSXStyle from "styled-jsx/style";
2
2
  export default {
3
- styles: <_JSXStyle id={"71f03d42ea0ec6"}>{".container.jsx-71f03d42ea0ec6{color:#fff;background:#000;height:100px;font-weight:700}"}</_JSXStyle>,
3
+ styles: <_JSXStyle id={"71f03d42ea0ec6"}>{".container.jsx-71f03d42ea0ec6{background:#000;color:white;font-weight:700;height:100px}"}</_JSXStyle>,
4
4
  className: "jsx-71f03d42ea0ec6"
5
5
  };
@@ -0,0 +1,7 @@
1
+ const a = ()=><div>
2
+
3
+ <p>hi</p>
4
+
5
+ <style>{'woot'}</style>
6
+
7
+ </div>;