turbopack_ecmascript/references/
util.rs

1use anyhow::Result;
2use swc_core::{ecma::ast::Expr, quote};
3use turbo_rcstr::RcStr;
4use turbo_tasks::{ResolvedVc, 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_else(|| "unknown".into()),
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: ResolvedVc<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 = resolve_source_map_sources(source_map.as_ref(), *self.origin_path).await?;
61        Ok(Vc::cell(source_map))
62    }
63}
64
65fn maybe_decode_data_url(url: &str) -> Option<Rope> {
66    const DATA_PREAMBLE: &str = "data:application/json;base64,";
67
68    if !url.starts_with(DATA_PREAMBLE) {
69        return None;
70    }
71    let data_b64 = &url[DATA_PREAMBLE.len()..];
72    data_encoding::BASE64
73        .decode(data_b64.as_bytes())
74        .ok()
75        .map(Rope::from)
76}