turbopack_ecmascript/references/
util.rs1use anyhow::Result;
2use async_trait::async_trait;
3use bincode::{Decode, Encode};
4use swc_core::{
5 common::{
6 Span,
7 errors::{DiagnosticId, HANDLER},
8 },
9 ecma::ast::Expr,
10 quote,
11};
12use turbo_rcstr::{RcStr, rcstr};
13use turbo_tasks::{NonLocalValue, ResolvedVc, Vc, trace::TraceRawVcs, turbofmt};
14use turbo_tasks_fs::FileSystemPath;
15use turbopack_core::{
16 self,
17 chunk::ChunkingType,
18 issue::{Issue, IssueExt, IssueSeverity, IssueSource, IssueStage, StyledString},
19 resolve::{ModuleResolveResult, parse::Request, pattern::Pattern},
20};
21
22use crate::errors;
23
24pub fn throw_module_not_found_expr(request: &str) -> Expr {
27 let message = format!("Cannot find module '{request}'");
28 quote!(
29 "(() => { const e = new Error($message); e.code = 'MODULE_NOT_FOUND'; throw e; })()"
30 as Expr,
31 message: Expr = message.into()
32 )
33}
34
35pub fn throw_module_not_found_expr_async(request: &str) -> Expr {
38 let message = format!("Cannot find module '{request}'");
39 quote!(
40 "Promise.resolve().then(() => { const e = new Error($message); e.code = 'MODULE_NOT_FOUND'; throw e; })"
41 as Expr,
42 message: Expr = message.into()
43 )
44}
45
46pub fn throw_module_not_found_error_expr(request: &str, message: &str) -> Expr {
49 let message = format!("Cannot find module '{request}': {message}");
50 quote!(
51 "(() => { const e = new Error($message); e.code = 'MODULE_NOT_FOUND'; throw e; })()"
52 as Expr,
53 message: Expr = message.into()
54 )
55}
56
57#[turbo_tasks::function]
58pub async fn request_to_string(request: Vc<Request>) -> Result<Vc<RcStr>> {
59 Ok(Vc::cell(
60 request
61 .await?
62 .request()
63 .unwrap_or(rcstr!("unknown")),
65 ))
66}
67
68const TOO_MANY_MATCHES_LIMIT: usize = 10000;
70
71pub async fn check_and_emit_too_many_matches_warning(
72 result: Vc<ModuleResolveResult>,
73 issue_source: IssueSource,
74 context_dir: FileSystemPath,
75 pattern: ResolvedVc<Pattern>,
76) -> Result<()> {
77 let num_matches = result.await?.primary.len();
78 if num_matches > TOO_MANY_MATCHES_LIMIT {
79 TooManyMatchesWarning {
80 source: issue_source,
81 context_dir,
82 num_matches,
83 pattern,
84 }
85 .resolved_cell()
86 .emit();
87 }
88 Ok(())
89}
90
91#[turbo_tasks::value(shared)]
92struct TooManyMatchesWarning {
93 source: IssueSource,
94 context_dir: FileSystemPath,
95 num_matches: usize,
96 pattern: ResolvedVc<Pattern>,
97}
98
99#[async_trait]
100#[turbo_tasks::value_impl]
101impl Issue for TooManyMatchesWarning {
102 async fn title(&self) -> Result<StyledString> {
103 Ok(StyledString::Text(
104 turbofmt!(
105 "The file pattern {} matches {} files in {}",
106 self.pattern,
107 self.num_matches,
108 self.context_dir
109 )
110 .await?,
111 ))
112 }
113
114 async fn description(&self) -> Result<Option<StyledString>> {
115 Ok(Some(StyledString::Text(rcstr!(
116 "Overly broad patterns can lead to build performance issues and over bundling."
117 ))))
118 }
119
120 async fn file_path(&self) -> Result<FileSystemPath> {
121 self.source.file_path().await
122 }
123
124 fn stage(&self) -> IssueStage {
125 IssueStage::Resolve
126 }
127
128 fn severity(&self) -> IssueSeverity {
129 IssueSeverity::Warning
130 }
131
132 fn source(&self) -> Option<IssueSource> {
133 Some(self.source)
134 }
135}
136
137#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encode, Decode, TraceRawVcs, NonLocalValue)]
138pub enum SpecifiedChunkingType {
139 Parallel,
140 Shared,
141 None,
142}
143
144impl SpecifiedChunkingType {
145 pub fn as_chunking_type(&self, inherit_async: bool, hoisted: bool) -> Option<ChunkingType> {
146 match self {
147 SpecifiedChunkingType::Parallel => Some(ChunkingType::Parallel {
148 inherit_async,
149 hoisted,
150 }),
151 SpecifiedChunkingType::Shared => Some(ChunkingType::Shared {
152 inherit_async,
153 merge_tag: None,
154 }),
155 SpecifiedChunkingType::None => None,
156 }
157 }
158}
159
160pub fn parse_chunking_type_annotation(
161 span: Span,
162 chunking_type_annotation: &str,
163) -> Option<SpecifiedChunkingType> {
164 match chunking_type_annotation {
165 "parallel" => Some(SpecifiedChunkingType::Parallel),
166 "shared" => Some(SpecifiedChunkingType::Shared),
167 "none" => Some(SpecifiedChunkingType::None),
168 _ => {
169 HANDLER.with(|handler| {
170 handler.span_err_with_code(
171 span,
172 &format!(
173 "Unknown specified chunking-type: \"{chunking_type_annotation}\", \
174 expected \"parallel\", \"shared\" or \"none\""
175 ),
176 DiagnosticId::Error(
177 errors::failed_to_analyze::ecmascript::CHUNKING_TYPE.into(),
178 ),
179 );
180 });
181 None
182 }
183 }
184}