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