turbopack_ecmascript_plugins/transform/
styled_components.rs1use anyhow::Result;
2use async_trait::async_trait;
3use serde::Deserialize;
4use swc_core::{atoms::Wtf8Atom, common::comments::NoopComments, ecma::ast::Program};
5use turbopack_ecmascript::{CustomTransformer, TransformContext};
6
7#[turbo_tasks::value(shared, operation)]
8#[derive(Clone, Debug, Deserialize)]
9#[serde(default, rename_all = "camelCase")]
10pub struct StyledComponentsTransformConfig {
11 pub display_name: bool,
12 pub ssr: bool,
13 pub file_name: bool,
14 pub top_level_import_paths: Vec<String>,
15 pub meaningless_file_names: Vec<String>,
16 pub css_prop: bool,
17 pub namespace: Option<String>,
18}
19
20impl Default for StyledComponentsTransformConfig {
21 fn default() -> Self {
22 StyledComponentsTransformConfig {
23 display_name: true,
24 ssr: true,
25 file_name: true,
26 top_level_import_paths: vec![],
27 meaningless_file_names: vec!["index".to_string()],
28 css_prop: true,
29 namespace: None,
30 }
31 }
32}
33
34#[derive(Debug)]
35pub struct StyledComponentsTransformer {
36 config: styled_components::Config,
37}
38
39impl StyledComponentsTransformer {
40 pub fn new(config: &StyledComponentsTransformConfig) -> Self {
41 let mut options = styled_components::Config {
42 display_name: config.display_name,
43 ssr: config.ssr,
44 file_name: config.file_name,
45 css_prop: config.css_prop,
46 ..Default::default()
47 };
48
49 if let Some(namespace) = &config.namespace {
50 options.namespace.clone_from(namespace);
51 }
52
53 let top_level_import_paths = &config.top_level_import_paths;
54 if !top_level_import_paths.is_empty() {
55 options.top_level_import_paths = top_level_import_paths
56 .iter()
57 .map(|s| Wtf8Atom::from(s.clone()))
58 .collect();
59 }
60 let meaningless_file_names = &config.meaningless_file_names;
61 if !meaningless_file_names.is_empty() {
62 options
63 .meaningless_file_names
64 .clone_from(meaningless_file_names);
65 }
66
67 Self { config: options }
68 }
69}
70
71#[async_trait]
72impl CustomTransformer for StyledComponentsTransformer {
73 #[tracing::instrument(level = tracing::Level::TRACE, name = "styled_components", skip_all)]
74 async fn transform(&self, program: &mut Program, ctx: &TransformContext<'_>) -> Result<()> {
75 program.mutate(styled_components::styled_components(
76 Some(ctx.file_path_str),
77 ctx.file_name_hash,
78 &self.config,
79 NoopComments,
80 ));
81
82 Ok(())
83 }
84}