1use anyhow::Result;
2use turbo_rcstr::RcStr;
3use turbo_tasks::{IntoTraitRef, PrettyPrintError, ResolvedVc, Vc};
4use turbo_tasks_fs::FileSystemPath;
5
6use crate::{
7 issue::{
8 Issue, IssueExt, IssueSeverity, IssueSource, IssueStage, OptionIssueSource,
9 OptionStyledString, StyledString, resolve::ResolvingIssue,
10 },
11 reference_type::ReferenceType,
12 resolve::{
13 ModuleResolveResult, ResolveErrorMode, ResolveResult, options::ResolveOptions,
14 origin::ResolveOrigin, parse::Request,
15 },
16};
17
18pub async fn handle_resolve_error(
19 result: Vc<ModuleResolveResult>,
20 reference_type: ReferenceType,
21 origin: Vc<Box<dyn ResolveOrigin>>,
22 request: Vc<Request>,
23 resolve_options: Vc<ResolveOptions>,
24 error_mode: ResolveErrorMode,
25
26 source: Option<IssueSource>,
27) -> Result<Vc<ModuleResolveResult>> {
28 Ok(match result.await {
29 Ok(result_ref) => {
30 if result_ref.is_unresolvable_ref() {
31 emit_unresolvable_issue(
32 error_mode,
33 origin,
34 reference_type,
35 request,
36 resolve_options,
37 source,
38 )
39 .await?;
40 }
41
42 handle_item_issues(result_ref.errors(), origin, source).await?;
43
44 result
45 }
46 Err(err) => {
47 emit_resolve_error_issue(
48 error_mode,
49 origin,
50 reference_type,
51 request,
52 resolve_options,
53 err,
54 source,
55 )
56 .await?;
57 *ModuleResolveResult::unresolvable()
58 }
59 })
60}
61
62pub async fn handle_resolve_source_error(
63 result: Vc<ResolveResult>,
64 reference_type: ReferenceType,
65 origin: Vc<Box<dyn ResolveOrigin>>,
66 request: Vc<Request>,
67 resolve_options: Vc<ResolveOptions>,
68 error_mode: ResolveErrorMode,
69 source: Option<IssueSource>,
70) -> Result<Vc<ResolveResult>> {
71 Ok(match result.await {
72 Ok(result_ref) => {
73 if result_ref.is_unresolvable_ref() {
74 emit_unresolvable_issue(
75 error_mode,
76 origin,
77 reference_type,
78 request,
79 resolve_options,
80 source,
81 )
82 .await?;
83 }
84
85 handle_item_issues(result_ref.errors(), origin, source).await?;
86
87 result
88 }
89 Err(err) => {
90 emit_resolve_error_issue(
91 error_mode,
92 origin,
93 reference_type,
94 request,
95 resolve_options,
96 err,
97 source,
98 )
99 .await?;
100 ResolveResult::unresolvable().cell()
101 }
102 })
103}
104
105async fn handle_item_issues(
106 items: impl Iterator<Item = ResolvedVc<Box<dyn Issue>>>,
107 origin: Vc<Box<dyn ResolveOrigin>>,
108 source: Option<IssueSource>,
109) -> Result<()> {
110 let mut items = items.peekable();
111 if items.peek().is_some() {
112 let file_path = origin.origin_path().owned().await?;
113 for item in items {
114 ResolvingIssueWithLocation {
115 inner: item,
116 severity: item.into_trait_ref().await?.severity(),
117 file_path: file_path.clone(),
118 source,
119 }
120 .resolved_cell()
121 .emit();
122 }
123 }
124 Ok(())
125}
126
127async fn emit_resolve_error_issue(
128 error_mode: ResolveErrorMode,
129 origin: Vc<Box<dyn ResolveOrigin>>,
130 reference_type: ReferenceType,
131 request: Vc<Request>,
132 resolve_options: Vc<ResolveOptions>,
133 err: anyhow::Error,
134 source: Option<IssueSource>,
135) -> Result<()> {
136 if error_mode == ResolveErrorMode::Ignore {
137 return Ok(());
138 }
139 let severity = if error_mode == ResolveErrorMode::Warn || resolve_options.await?.loose_errors {
140 IssueSeverity::Warning
141 } else {
142 IssueSeverity::Error
143 };
144 ResolvingIssue {
145 severity,
146 file_path: origin.origin_path().owned().await?,
147 request_type: format!("{reference_type} request"),
148 request: request.to_resolved().await?,
149 resolve_options: resolve_options.to_resolved().await?,
150 error_message: Some(format!("{}", PrettyPrintError(&err))),
151 source,
152 }
153 .resolved_cell()
154 .emit();
155 Ok(())
156}
157
158async fn emit_unresolvable_issue(
159 error_mode: ResolveErrorMode,
160
161 origin: Vc<Box<dyn ResolveOrigin>>,
162 reference_type: ReferenceType,
163 request: Vc<Request>,
164 resolve_options: Vc<ResolveOptions>,
165 source: Option<IssueSource>,
166) -> Result<()> {
167 if error_mode == ResolveErrorMode::Ignore {
168 return Ok(());
169 }
170 let severity = if error_mode == ResolveErrorMode::Warn || resolve_options.await?.loose_errors {
171 IssueSeverity::Warning
172 } else {
173 IssueSeverity::Error
174 };
175 ResolvingIssue {
176 severity,
177 file_path: origin.origin_path().owned().await?,
178 request_type: format!("{reference_type} request"),
179 request: request.to_resolved().await?,
180 resolve_options: resolve_options.to_resolved().await?,
181 error_message: None,
182 source,
183 }
184 .resolved_cell()
185 .emit();
186 Ok(())
187}
188
189pub async fn resolve_error_severity(resolve_options: Vc<ResolveOptions>) -> Result<IssueSeverity> {
190 Ok(if resolve_options.await?.loose_errors {
191 IssueSeverity::Warning
192 } else {
193 IssueSeverity::Error
194 })
195}
196
197#[turbo_tasks::value(shared)]
199pub struct ResolvingIssueWithLocation {
200 pub inner: ResolvedVc<Box<dyn Issue>>,
201 pub severity: IssueSeverity,
202 pub file_path: FileSystemPath,
203 pub source: Option<IssueSource>,
204}
205
206#[turbo_tasks::value_impl]
207impl Issue for ResolvingIssueWithLocation {
208 fn severity(&self) -> IssueSeverity {
209 self.severity
210 }
211
212 #[turbo_tasks::function]
213 fn file_path(&self) -> Vc<FileSystemPath> {
214 self.file_path.clone().cell()
215 }
216
217 #[turbo_tasks::function]
218 fn stage(&self) -> Vc<IssueStage> {
219 self.inner.stage()
220 }
221
222 #[turbo_tasks::function]
223 fn title(&self) -> Vc<StyledString> {
224 self.inner.title()
225 }
226
227 #[turbo_tasks::function]
228 fn description(&self) -> Vc<OptionStyledString> {
229 self.inner.description()
230 }
231
232 #[turbo_tasks::function]
233 fn detail(&self) -> Vc<OptionStyledString> {
234 self.inner.detail()
235 }
236
237 #[turbo_tasks::function]
238 fn documentation_link(&self) -> Vc<RcStr> {
239 self.inner.documentation_link()
240 }
241
242 #[turbo_tasks::function]
243 fn source(&self) -> Vc<OptionIssueSource> {
244 Vc::cell(self.source)
245 }
246}