Skip to main content

turbopack_resolve/
ecmascript.rs

1use anyhow::Result;
2use turbo_rcstr::rcstr;
3use turbo_tasks::{ResolvedVc, Vc};
4use turbopack_core::{
5    issue::IssueSource,
6    reference_type::{CommonJsReferenceSubType, EcmaScriptModulesReferenceSubType, ReferenceType},
7    resolve::{
8        ModuleResolveResult, ResolveErrorMode, ResolveResult, handle_resolve_error,
9        handle_resolve_source_error,
10        options::{
11            ConditionValue, ResolutionConditions, ResolveInPackage, ResolveIntoPackage,
12            ResolveOptions,
13        },
14        origin::{ResolveOrigin, ResolveOriginExt},
15        parse::Request,
16        resolve,
17    },
18};
19/// Retrieves the [ResolutionConditions] of the "into" and "in" package resolution options, so that
20/// they can be manipulated together.
21///
22/// - "into" allows a package to control how it can be imported
23/// - "in" controls how this package imports others
24pub fn get_condition_maps(
25    options: &mut ResolveOptions,
26) -> impl Iterator<Item = &mut ResolutionConditions> {
27    options
28        .into_package
29        .iter_mut()
30        .filter_map(|item| {
31            if let ResolveIntoPackage::ExportsField { conditions, .. } = item {
32                Some(conditions)
33            } else {
34                None
35            }
36        })
37        .chain(options.in_package.iter_mut().filter_map(|item| {
38            if let ResolveInPackage::ImportsField { conditions, .. } = item {
39                Some(conditions)
40            } else {
41                None
42            }
43        }))
44}
45
46pub fn apply_esm_specific_options(
47    options: Vc<ResolveOptions>,
48    reference_type: &ReferenceType,
49) -> Vc<ResolveOptions> {
50    let clear_extensions = matches!(
51        reference_type,
52        ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::ImportWithType(_))
53    );
54
55    apply_esm_specific_options_internal(options, clear_extensions)
56}
57
58#[turbo_tasks::function]
59async fn apply_esm_specific_options_internal(
60    options: Vc<ResolveOptions>,
61    clear_extensions: bool,
62) -> Result<Vc<ResolveOptions>> {
63    let mut options: ResolveOptions = options.owned().await?;
64    // TODO set fully_specified when in strict ESM mode
65    // options.fully_specified = true;
66    for conditions in get_condition_maps(&mut options) {
67        conditions.insert(rcstr!("import"), ConditionValue::Set);
68        conditions.insert(rcstr!("require"), ConditionValue::Unset);
69    }
70
71    if clear_extensions {
72        options.extensions.clear();
73    }
74
75    options.parse_data_uris = true;
76
77    Ok(options.cell())
78}
79
80#[turbo_tasks::function]
81pub async fn apply_cjs_specific_options(options: Vc<ResolveOptions>) -> Result<Vc<ResolveOptions>> {
82    let mut options: ResolveOptions = options.owned().await?;
83    for conditions in get_condition_maps(&mut options) {
84        conditions.insert(rcstr!("import"), ConditionValue::Unset);
85        conditions.insert(rcstr!("require"), ConditionValue::Set);
86    }
87    Ok(options.cell())
88}
89
90pub async fn esm_resolve(
91    origin: Vc<Box<dyn ResolveOrigin>>,
92    request: Vc<Request>,
93    ty: EcmaScriptModulesReferenceSubType,
94    error_mode: ResolveErrorMode,
95    issue_source: Option<IssueSource>,
96) -> Result<Vc<ModuleResolveResult>> {
97    let ty = ReferenceType::EcmaScriptModules(ty);
98    let options = apply_esm_specific_options(origin.resolve_options(), &ty)
99        .resolve()
100        .await?;
101    specific_resolve(origin, request, options, ty, error_mode, issue_source).await
102}
103
104#[turbo_tasks::function]
105pub async fn cjs_resolve(
106    origin: Vc<Box<dyn ResolveOrigin>>,
107    request: Vc<Request>,
108    ty: CommonJsReferenceSubType,
109    issue_source: Option<IssueSource>,
110    error_mode: ResolveErrorMode,
111) -> Result<Vc<ModuleResolveResult>> {
112    let ty = ReferenceType::CommonJs(ty);
113    let options = apply_cjs_specific_options(origin.resolve_options())
114        .resolve()
115        .await?;
116    specific_resolve(origin, request, options, ty, error_mode, issue_source).await
117}
118
119#[turbo_tasks::function]
120pub async fn cjs_resolve_source(
121    origin: ResolvedVc<Box<dyn ResolveOrigin>>,
122    request: ResolvedVc<Request>,
123    ty: CommonJsReferenceSubType,
124    issue_source: Option<IssueSource>,
125    error_mode: ResolveErrorMode,
126) -> Result<Vc<ResolveResult>> {
127    let ty = ReferenceType::CommonJs(ty);
128    let options = apply_cjs_specific_options(origin.resolve_options())
129        .resolve()
130        .await?;
131    let result = resolve(
132        origin.origin_path().await?.parent(),
133        ty.clone(),
134        *request,
135        options,
136    );
137
138    handle_resolve_source_error(
139        result,
140        ty,
141        *origin,
142        *request,
143        options,
144        error_mode,
145        issue_source,
146    )
147    .await
148}
149
150async fn specific_resolve(
151    origin: Vc<Box<dyn ResolveOrigin>>,
152    request: Vc<Request>,
153    options: Vc<ResolveOptions>,
154    reference_type: ReferenceType,
155    error_mode: ResolveErrorMode,
156    issue_source: Option<IssueSource>,
157) -> Result<Vc<ModuleResolveResult>> {
158    let result = origin
159        .resolve_asset(request, options, reference_type.clone())
160        .await?;
161
162    handle_resolve_error(
163        result,
164        reference_type,
165        origin,
166        request,
167        options,
168        error_mode,
169        issue_source,
170    )
171    .await
172}