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