turbopack_core/issue/
resolve.rs1use std::fmt::Write;
2
3use anyhow::Result;
4use async_trait::async_trait;
5use turbo_rcstr::{RcStr, rcstr};
6use turbo_tasks::{PrettyPrintError, ReadRef, ResolvedVc, ValueToString, ValueToStringRef, Vc};
7use turbo_tasks_fs::FileSystemPath;
8
9use super::{Issue, IssueSource, IssueStage, StyledString};
10use crate::{
11 issue::IssueSeverity,
12 resolve::{
13 options::{ImportMap, ImportMapResult, ResolveOptions},
14 parse::Request,
15 },
16};
17
18#[turbo_tasks::value(shared)]
19pub struct ResolvingIssue {
20 pub severity: IssueSeverity,
21 pub request_type: String,
22 pub request: ResolvedVc<Request>,
23 pub file_path: FileSystemPath,
24 pub resolve_options: ResolvedVc<ResolveOptions>,
25 pub error_message: Option<String>,
26 pub source: Option<IssueSource>,
27}
28
29#[async_trait]
30#[turbo_tasks::value_impl]
31impl Issue for ResolvingIssue {
32 fn severity(&self) -> IssueSeverity {
33 self.severity
34 }
35
36 async fn title(&self) -> Result<StyledString> {
37 let request = self.request.request_pattern().to_string().owned().await?;
38 Ok(StyledString::Line(vec![
39 StyledString::Strong(rcstr!("Module not found")),
40 StyledString::Text(rcstr!(": Can't resolve ")),
41 StyledString::Code(request),
42 ]))
43 }
44
45 fn stage(&self) -> IssueStage {
46 IssueStage::Resolve
47 }
48
49 async fn file_path(&self) -> Result<FileSystemPath> {
50 Ok(self.file_path.clone())
51 }
52
53 async fn description(&self) -> Result<Option<StyledString>> {
54 let mut description = String::new();
55 if let Some(error_message) = &self.error_message {
56 writeln!(description, "{error_message}")?;
57 }
58 let request_value = self.request.await?;
59 let request_parts = match &*request_value {
60 Request::Alternatives { requests } => requests.as_slice(),
61 _ => &[self.request],
62 };
63
64 if let Some(import_map) = &self.resolve_options.await?.import_map {
65 for req in request_parts {
66 match lookup_import_map(**import_map, self.file_path.clone(), **req).await {
67 Ok(None) => {}
68 Ok(Some(str)) => writeln!(description, "Import map: {str}")?,
69 Err(err) => {
70 writeln!(
71 description,
72 "Error while looking up import map: {}",
73 PrettyPrintError(&err)
74 )?;
75 }
76 }
77 }
78 }
79 Ok(Some(StyledString::Text(description.into())))
80 }
81
82 async fn detail(&self) -> Result<Option<StyledString>> {
83 let mut detail = String::new();
84
85 if self.error_message.is_some() {
86 writeln!(detail, "An error happened during resolving.")?;
87 } else {
88 writeln!(detail, "It was not possible to find the requested file.")?;
89 }
90 writeln!(
91 detail,
92 "Parsed request as written in source code: {request}",
93 request = self.request.to_string().await?
94 )?;
95 writeln!(
96 detail,
97 "Path where resolving has started: {context}",
98 context = self.file_path.to_string_ref().await?
99 )?;
100 writeln!(
101 detail,
102 "Type of request: {request_type}",
103 request_type = self.request_type,
104 )?;
105 Ok(Some(StyledString::Text(detail.into())))
106 }
107
108 fn source(&self) -> Option<IssueSource> {
109 self.source
110 }
111
112 }
115
116async fn lookup_import_map(
117 import_map: Vc<ImportMap>,
118 file_path: FileSystemPath,
119 request: Vc<Request>,
120) -> Result<Option<ReadRef<RcStr>>> {
121 let result = import_map.await?.lookup(file_path, request).await?;
122
123 if matches!(result, ImportMapResult::NoEntry) {
124 return Ok(None);
125 }
126 Ok(Some(result.cell().to_string().await?))
127}