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