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