#![allow(clippy::not_unsafe_ptr_arg_deref)]
use std::path::Path;
use serde::Deserialize;
use swc_core::{
ecma::{ast::Program, visit::FoldWith},
plugin::{
metadata::TransformPluginMetadataContextKind, plugin_transform,
proxies::TransformPluginProgramMetadata,
},
};
use swc_emotion::EmotionOptions;
pub struct TransformVisitor;
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
enum EmotionJsAutoLabel {
Never,
DevOnly,
Always,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct EmotionJsOptions {
source_map: Option<bool>,
auto_label: Option<EmotionJsAutoLabel>,
label_format: Option<String>,
#[serde(flatten)]
extra: swc_emotion::EmotionOptions,
}
impl EmotionJsOptions {
fn to_emotion_options(self, env_name: &str) -> EmotionOptions {
EmotionOptions {
enabled: Some(true),
sourcemap: Some(match env_name {
"development" => self.source_map.unwrap_or(true),
_ => false,
}),
auto_label: Some(
match self.auto_label.unwrap_or(EmotionJsAutoLabel::DevOnly) {
EmotionJsAutoLabel::Always => true,
EmotionJsAutoLabel::Never => false,
EmotionJsAutoLabel::DevOnly => matches!(env_name, "development"),
},
),
label_format: Some(self.label_format.unwrap_or_else(|| "[local]".to_string())),
..self.extra
}
}
}
#[plugin_transform]
pub fn process_transform(program: Program, data: TransformPluginProgramMetadata) -> Program {
let config = serde_json::from_str::<EmotionJsOptions>(
&data
.get_transform_plugin_config()
.expect("failed to get plugin config for emotion"),
)
.expect("invalid config for emotion");
let config = config.to_emotion_options(
&data
.get_context(&TransformPluginMetadataContextKind::Env)
.unwrap_or_default(),
);
let file_name = data
.get_context(&TransformPluginMetadataContextKind::Filename)
.unwrap_or_default();
let path = Path::new(&file_name);
let source_map = std::sync::Arc::new(data.source_map);
program.fold_with(&mut swc_emotion::emotion(
config,
path,
source_map,
data.comments,
))
}