rolldown_plugin/plugin_context/
transform_plugin_context.rs1use std::{ops::Deref, sync::Arc};
2
3use crate::PluginContext;
4use arcstr::ArcStr;
5use rolldown_common::{ModuleIdx, PluginIdx, SourceMapGenMsg, SourcemapChainElement, WatchPath};
6use rolldown_sourcemap::{SourceMap, collapse_sourcemaps, empty_sourcemap};
7use rolldown_utils::unique_arc::WeakRef;
8use std::sync::mpsc;
9use string_wizard::{MagicString, SourceMapOptions};
10
11#[derive(Debug)]
12pub struct TransformPluginContext {
13 pub inner: PluginContext,
14 sourcemap_chain: WeakRef<Vec<SourcemapChainElement>>,
15 original_code: ArcStr,
16 id: ArcStr,
17 module_idx: ModuleIdx,
18 plugin_idx: PluginIdx,
19 magic_string_tx: Option<mpsc::Sender<SourceMapGenMsg>>,
20}
21
22impl TransformPluginContext {
23 pub fn new(
24 inner: PluginContext,
25 sourcemap_chain: WeakRef<Vec<SourcemapChainElement>>,
26 original_code: ArcStr,
27 id: ArcStr,
28 module_idx: ModuleIdx,
29 plugin_idx: PluginIdx,
30 magic_string_tx: Option<mpsc::Sender<SourceMapGenMsg>>,
31 ) -> Self {
32 Self { inner, sourcemap_chain, original_code, id, module_idx, plugin_idx, magic_string_tx }
33 }
34
35 pub fn get_combined_sourcemap(&self) -> SourceMap {
36 self.sourcemap_chain.with_inner(|sourcemap_chain| {
37 let empty_map = empty_sourcemap();
38 let chain: Vec<&SourceMap> = sourcemap_chain
39 .iter()
40 .filter_map(|element| match element {
41 SourcemapChainElement::Transform((_, sourcemap))
42 | SourcemapChainElement::Load(sourcemap) => Some(sourcemap),
43 SourcemapChainElement::Omitted { .. } => Some(&empty_map),
44 SourcemapChainElement::Null { .. } => None,
45 })
46 .collect();
47 match chain.as_slice() {
48 [] => self.create_sourcemap(),
49 [single] => (*single).clone(),
50 _ => collapse_sourcemaps(&chain),
52 }
53 })
54 }
55
56 fn create_sourcemap(&self) -> SourceMap {
57 let magic_string = MagicString::new(self.original_code.as_str());
58 magic_string.source_map(SourceMapOptions {
59 hires: string_wizard::Hires::Boundary,
60 include_content: true,
61 source: self.id.as_str().into(),
62 })
63 }
64
65 pub fn add_watch_file(&self, file: &str) {
67 if self.id.starts_with('\0') {
70 return;
71 }
72
73 self.inner.add_watch_file(file);
75
76 if let crate::PluginContext::Native(ctx) = &self.inner {
78 if let Some(plugin_driver) = ctx.plugin_driver.upgrade() {
79 plugin_driver
80 .add_transform_dependency(self.module_idx, WatchPath::new(file, &ctx.options.cwd));
81 }
82 }
83 }
84
85 pub fn send_magic_string(
86 &self,
87 magic_string: MagicString<'static>,
88 ) -> Result<Option<String>, mpsc::SendError<SourceMapGenMsg>> {
89 if let Some(tx) = self.magic_string_tx.as_ref() {
90 tx.send(SourceMapGenMsg::MagicString(Box::new((
91 self.module_idx,
92 self.plugin_idx,
93 self.id.clone(),
94 magic_string,
95 ))))
96 .map(|()| None)
97 } else {
98 Ok(Some(magic_string.source_map(string_wizard::SourceMapOptions::default()).to_json_string()))
99 }
100 }
101}
102
103impl Deref for TransformPluginContext {
104 type Target = PluginContext;
105
106 fn deref(&self) -> &Self::Target {
107 &self.inner
108 }
109}
110
111pub type SharedTransformPluginContext = Arc<TransformPluginContext>;