turbopack_ecmascript/references/
util.rs

1use anyhow::Result;
2use swc_core::{ecma::ast::Expr, quote};
3use turbo_rcstr::{RcStr, rcstr};
4use turbo_tasks::Vc;
5use turbo_tasks_fs::{FileSystemPath, rope::Rope};
6use turbopack_core::{
7    resolve::parse::Request,
8    source_map::{
9        GenerateSourceMap, OptionStringifiedSourceMap, utils::resolve_source_map_sources,
10    },
11};
12
13/// Creates a IIFE expression that throws a "Cannot find module" error for the
14/// given request string
15pub fn throw_module_not_found_expr(request: &str) -> Expr {
16    let message = format!("Cannot find module '{request}'");
17    quote!(
18        "(() => { const e = new Error($message); e.code = 'MODULE_NOT_FOUND'; throw e; })()"
19            as Expr,
20        message: Expr = message.into()
21    )
22}
23
24/// Creates a IIFE expression that throws a "Cannot find module" error for the
25/// given request string
26pub fn throw_module_not_found_error_expr(request: &str, message: &str) -> Expr {
27    let message = format!("Cannot find module '{request}': {message}");
28    quote!(
29        "(() => { const e = new Error($message); e.code = 'MODULE_NOT_FOUND'; throw e; })()"
30            as Expr,
31        message: Expr = message.into()
32    )
33}
34
35#[turbo_tasks::function]
36pub async fn request_to_string(request: Vc<Request>) -> Result<Vc<RcStr>> {
37    Ok(Vc::cell(
38        request
39            .await?
40            .request()
41            // TODO: Handle Request::Dynamic, Request::Alternatives
42            .unwrap_or(rcstr!("unknown")),
43    ))
44}
45
46#[turbo_tasks::value(shared)]
47#[derive(Debug, Clone)]
48pub struct InlineSourceMap {
49    /// The file path of the module containing the sourcemap data URL
50    pub origin_path: FileSystemPath,
51    /// The Base64 encoded JSON sourcemap string
52    pub source_map: RcStr,
53}
54
55#[turbo_tasks::value_impl]
56impl GenerateSourceMap for InlineSourceMap {
57    #[turbo_tasks::function]
58    pub async fn generate_source_map(&self) -> Result<Vc<OptionStringifiedSourceMap>> {
59        let source_map = maybe_decode_data_url(&self.source_map);
60        let source_map =
61            resolve_source_map_sources(source_map.as_ref(), self.origin_path.clone()).await?;
62        Ok(Vc::cell(source_map))
63    }
64}
65
66fn maybe_decode_data_url(url: &str) -> Option<Rope> {
67    const DATA_PREAMBLE: &str = "data:application/json;base64,";
68
69    if !url.starts_with(DATA_PREAMBLE) {
70        return None;
71    }
72    let data_b64 = &url[DATA_PREAMBLE.len()..];
73    data_encoding::BASE64
74        .decode(data_b64.as_bytes())
75        .ok()
76        .map(Rope::from)
77}