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};
19pub 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 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}