turbopack_ecmascript_plugins/transform/
relay.rs1use std::{path::PathBuf, sync::Arc};
2
3use anyhow::{Context, Result};
4use async_trait::async_trait;
5use bincode::{Decode, Encode};
6use serde::Deserialize;
7use swc_core::{common::FileName, ecma::ast::Program};
8use swc_relay::RelayLanguageConfig;
9use turbo_tasks::{NonLocalValue, OperationValue};
10use turbo_tasks_fs::FileSystemPath;
11use turbopack_ecmascript::{CustomTransformer, TransformContext};
12
13#[derive(Clone, Debug, PartialEq, Deserialize, NonLocalValue, OperationValue, Encode, Decode)]
14#[serde(rename_all = "camelCase")]
15pub struct RelayConfig {
16 pub src: String,
17 pub artifact_directory: Option<String>,
18 pub language: Option<RelayLanguage>,
19}
20
21#[derive(Clone, Debug, PartialEq, Deserialize, NonLocalValue, OperationValue, Encode, Decode)]
22#[serde(rename_all = "lowercase")]
23pub enum RelayLanguage {
24 TypeScript,
25 Flow,
26 JavaScript,
27}
28
29#[derive(Debug)]
30pub struct RelayTransformer {
31 config: Arc<swc_relay::Config>,
32 project_path: FileSystemPath,
33}
34
35impl RelayTransformer {
36 pub fn new(config: &RelayConfig, project_path: &FileSystemPath) -> Self {
37 let options = swc_relay::Config {
38 artifact_directory: config.artifact_directory.as_ref().map(PathBuf::from),
39 language: config.language.as_ref().map_or(
40 RelayLanguageConfig::TypeScript,
41 |v| match v {
42 RelayLanguage::JavaScript => RelayLanguageConfig::JavaScript,
43 RelayLanguage::TypeScript => RelayLanguageConfig::TypeScript,
44 RelayLanguage::Flow => RelayLanguageConfig::Flow,
45 },
46 ),
47 ..Default::default()
48 };
49
50 Self {
51 config: options.into(),
52 project_path: project_path.clone(),
53 }
54 }
55}
56
57#[async_trait]
58impl CustomTransformer for RelayTransformer {
59 #[tracing::instrument(level = tracing::Level::TRACE, name = "relay", skip_all)]
60 async fn transform(&self, program: &mut Program, ctx: &TransformContext<'_>) -> Result<()> {
61 let path_to_proj = PathBuf::from(
64 ctx.file_path
65 .parent()
66 .get_relative_path_to(&self.project_path)
67 .context("Expected relative path to relay artifact")?,
68 );
69
70 program.mutate(swc_relay::relay(
71 self.config.clone(),
72 FileName::Real(PathBuf::from(ctx.file_name_str)),
73 path_to_proj,
74 None,
77 Some(ctx.unresolved_mark),
78 ));
79
80 Ok(())
81 }
82}