turbopack_ecmascript/
single_file_ecmascript_output.rs1use std::sync::Arc;
2
3use anyhow::Result;
4use swc_core::common::{BytePos, FileName, LineCol, SourceMap};
5use tokio::io::AsyncReadExt;
6use turbo_tasks::{ResolvedVc, Vc};
7use turbo_tasks_fs::{File, FileContent, FileSystemPath, rope::Rope};
8use turbopack_core::{
9 asset::{Asset, AssetContent},
10 output::{OutputAsset, OutputAssetsReference},
11 source::Source,
12 source_map::GenerateSourceMap,
13};
14
15use crate::parse::generate_js_source_map;
16
17#[turbo_tasks::value]
20pub struct SingleFileEcmascriptOutput {
21 output_path: FileSystemPath,
22 source_path: FileSystemPath,
23 source: ResolvedVc<Box<dyn Source>>,
24}
25
26#[turbo_tasks::value_impl]
27impl OutputAsset for SingleFileEcmascriptOutput {
28 #[turbo_tasks::function]
29 fn path(&self) -> Vc<FileSystemPath> {
30 self.output_path.clone().cell()
31 }
32}
33
34#[turbo_tasks::value_impl]
35impl OutputAssetsReference for SingleFileEcmascriptOutput {}
36
37#[turbo_tasks::value_impl]
38impl Asset for SingleFileEcmascriptOutput {
39 #[turbo_tasks::function]
40 fn content(&self) -> Vc<AssetContent> {
41 self.source.content()
42 }
43}
44
45#[turbo_tasks::value_impl]
46impl SingleFileEcmascriptOutput {
47 #[turbo_tasks::function]
48 pub fn new(
49 output_path: FileSystemPath,
50 source_path: FileSystemPath,
51 source: ResolvedVc<Box<dyn Source>>,
52 ) -> Vc<SingleFileEcmascriptOutput> {
53 SingleFileEcmascriptOutput {
54 output_path,
55 source_path,
56 source,
57 }
58 .cell()
59 }
60}
61
62#[turbo_tasks::value_impl]
63impl GenerateSourceMap for SingleFileEcmascriptOutput {
64 #[turbo_tasks::function]
65 pub async fn generate_source_map(&self) -> Result<Vc<FileContent>> {
66 let FileContent::Content(file) = &*self.source.content().file_content().await? else {
67 return Ok(FileContent::NotFound.cell());
68 };
69
70 let file_source = {
71 let mut s = String::new();
72 file.read().read_to_string(&mut s).await?;
73 s
74 };
75
76 let mut mappings = vec![];
77 let mut pos: u32 = 1;
79 for (index, line) in file_source.split_inclusive('\n').enumerate() {
80 mappings.push((
81 BytePos(pos),
82 LineCol {
83 line: index as u32,
84 col: 0,
85 },
86 ));
87 pos += line.len() as u32;
88 }
89
90 let sm: Arc<SourceMap> = Default::default();
91 sm.new_source_file(
92 FileName::Custom(self.source_path.to_string()).into(),
93 file_source,
94 );
95
96 let map = generate_js_source_map(&*sm, mappings, None::<&Rope>, true, true)?;
97 Ok(FileContent::Content(File::from(map)).cell())
98 }
99}