1pub mod amd;
2pub mod async_module;
3pub mod cjs;
4pub mod constant_condition;
5pub mod constant_value;
6pub mod dynamic_expression;
7pub mod esm;
8pub mod exports;
9pub mod exports_info;
10pub mod external_module;
11pub mod hot_module;
12pub mod ident;
13pub mod import_meta_glob;
14pub mod member;
15pub mod node;
16pub mod pattern_mapping;
17pub mod raw;
18pub mod require_context;
19pub mod type_issue;
20pub mod typescript;
21pub mod unreachable;
22pub mod util;
23pub mod worker;
24
25use std::{
26 future::Future,
27 mem::take,
28 ops::Deref,
29 sync::{Arc, LazyLock},
30};
31
32use anyhow::Result;
33use bincode::{Decode, Encode};
34use constant_condition::{ConstantConditionCodeGen, ConstantConditionValue};
35use constant_value::ConstantValueCodeGen;
36use either::Either;
37use indexmap::map::Entry;
38use num_traits::Zero;
39use parking_lot::Mutex;
40use regex::Regex;
41use rustc_hash::{FxHashMap, FxHashSet};
42use swc_core::{
43 atoms::{Atom, Wtf8Atom, atom},
44 common::{
45 GLOBALS, Globals, Span, Spanned,
46 comments::{CommentKind, Comments},
47 errors::{DiagnosticId, HANDLER, Handler, Level},
48 source_map::SmallPos,
49 },
50 ecma::{
51 ast::*,
52 utils::IsDirective,
53 visit::{
54 AstParentKind,
55 fields::{
56 AssignExprField, AssignTargetField, BindingIdentField, SimpleAssignTargetField,
57 },
58 },
59 },
60};
61use tokio::sync::OnceCell;
62use tracing::Instrument;
63use turbo_rcstr::{RcStr, rcstr};
64use turbo_tasks::{
65 FxIndexMap, FxIndexSet, NonLocalValue, PrettyPrintError, ReadRef, ResolvedVc, TaskInput,
66 TryJoinIterExt, Upcast, ValueToString, Vc, trace::TraceRawVcs, turbofmt,
67};
68use turbo_tasks_fs::FileSystemPath;
69use turbopack_core::{
70 chunk::ChunkingType,
71 compile_time_info::{
72 CompileTimeDefineValue, CompileTimeDefines, CompileTimeInfo, DefinableNameSegment,
73 DefinableNameSegmentRef, FreeVarReference, FreeVarReferences, FreeVarReferencesMembers,
74 InputRelativeConstant,
75 },
76 environment::Rendering,
77 issue::{IssueExt, IssueSeverity, IssueSource, StyledString, analyze::AnalyzeIssue},
78 module::{Module, ModuleSideEffects},
79 reference::{ModuleReference, ModuleReferences},
80 reference_type::{CommonJsReferenceSubType, InnerAssets},
81 resolve::{
82 ExportUsage, FindContextFileResult, ImportUsage, ModulePart, ResolveErrorMode,
83 find_context_file,
84 origin::{PlainResolveOrigin, ResolveOrigin},
85 parse::Request,
86 pattern::Pattern,
87 },
88 source::Source,
89 source_map::GenerateSourceMap,
90};
91use turbopack_resolve::{ecmascript::cjs_resolve_source, typescript::tsconfig};
92use turbopack_swc_utils::emitter::IssueEmitter;
93use unreachable::Unreachable;
94use worker::WorkerAssetReference;
95
96pub use crate::references::esm::export::{FollowExportsResult, follow_reexports};
97use crate::{
98 AnalyzeMode, EcmascriptModuleAsset, EcmascriptModuleAssetType, EcmascriptParsable,
99 ModuleTypeResult, TreeShakingMode, TypeofWindow,
100 analyzer::{
101 ConstantNumber, ConstantString, ConstantValue as JsConstantValue, JsValue, JsValueUrlKind,
102 ObjectPart, RequireContextValue, WellKnownFunctionKind, WellKnownObjectKind,
103 builtin::{early_replace_builtin, replace_builtin},
104 graph::{ConditionalKind, Effect, EffectArg, VarGraph, create_graph},
105 imports::{ImportAnnotations, ImportAttributes, ImportMap},
106 linker::link,
107 parse_require_context, side_effects,
108 top_level_await::has_top_level_await,
109 well_known::replace_well_known,
110 },
111 code_gen::{CodeGen, CodeGens, IntoCodeGenReference},
112 errors,
113 parse::ParseResult,
114 references::{
115 amd::{
116 AmdDefineAssetReference, AmdDefineDependencyElement, AmdDefineFactoryType,
117 AmdDefineWithDependenciesCodeGen,
118 },
119 async_module::{AsyncModule, OptionAsyncModule},
120 cjs::{
121 CjsAssetReference, CjsRequireAssetReference, CjsRequireCacheAccess,
122 CjsRequireResolveAssetReference,
123 },
124 dynamic_expression::DynamicExpression,
125 esm::{
126 EsmAssetReference, EsmAsyncAssetReference, EsmBinding, ImportMetaBinding,
127 ImportMetaRef, UrlAssetReference, UrlRewriteBehavior, base::EsmAssetReferences,
128 module_id::EsmModuleIdAssetReference,
129 },
130 exports::{EcmascriptExportsAnalysis, compute_ecmascript_module_exports},
131 exports_info::{ExportsInfoBinding, ExportsInfoRef},
132 hot_module::{ModuleHotReferenceAssetReference, ModuleHotReferenceCodeGen},
133 ident::IdentReplacement,
134 import_meta_glob::{ImportMetaGlobAssetReference, parse_import_meta_glob},
135 member::MemberReplacement,
136 node::PackageJsonReference,
137 raw::{DirAssetReference, FileSourceReference},
138 require_context::{RequireContextAssetReference, RequireContextMap},
139 typescript::{
140 TsConfigReference, TsReferencePathAssetReference, TsReferenceTypeAssetReference,
141 },
142 },
143 runtime_functions::{
144 TURBOPACK_EXPORTS, TURBOPACK_GLOBAL, TURBOPACK_REQUIRE_REAL, TURBOPACK_REQUIRE_STUB,
145 TURBOPACK_RUNTIME_FUNCTION_SHORTCUTS,
146 },
147 source_map::parse_source_map_comment,
148 tree_shake::{part_of_module, split_module},
149 utils::{AstPathRange, js_value_to_pattern, module_value_to_well_known_object},
150};
151
152#[turbo_tasks::value(shared)]
153pub struct AnalyzeEcmascriptModuleResult {
154 references: Vec<ResolvedVc<Box<dyn ModuleReference>>>,
155
156 pub esm_references: ResolvedVc<EsmAssetReferences>,
157 pub esm_local_references: ResolvedVc<EsmAssetReferences>,
158 pub esm_reexport_references: ResolvedVc<EsmAssetReferences>,
159
160 pub code_generation: ResolvedVc<CodeGens>,
161 pub async_module: ResolvedVc<OptionAsyncModule>,
162 pub side_effects: ModuleSideEffects,
163 pub successful: bool,
165 pub source_map: Option<ResolvedVc<Box<dyn GenerateSourceMap>>>,
166}
167
168#[turbo_tasks::value_impl]
169impl AnalyzeEcmascriptModuleResult {
170 #[turbo_tasks::function]
171 pub async fn references(&self) -> Result<Vc<ModuleReferences>> {
172 Ok(Vc::cell(
173 self.esm_references
174 .await?
175 .iter()
176 .map(|r| ResolvedVc::upcast(*r))
177 .chain(self.references.iter().copied())
178 .collect(),
179 ))
180 }
181
182 #[turbo_tasks::function]
183 pub async fn local_references(&self) -> Result<Vc<ModuleReferences>> {
184 Ok(Vc::cell(
185 self.esm_local_references
186 .await?
187 .iter()
188 .map(|r| ResolvedVc::upcast(*r))
189 .chain(self.references.iter().copied())
190 .collect(),
191 ))
192 }
193}
194
195#[cfg(debug_assertions)]
198type CodeGenCollection = FxIndexSet<CodeGen>;
199#[cfg(not(debug_assertions))]
200type CodeGenCollection = Vec<CodeGen>;
201
202struct AnalyzeEcmascriptModuleResultBuilder {
205 analyze_mode: AnalyzeMode,
206
207 references: FxIndexSet<ResolvedVc<Box<dyn ModuleReference>>>,
208
209 esm_references: FxHashSet<usize>,
210 esm_local_references: FxHashSet<usize>,
211 esm_reexport_references: FxHashSet<usize>,
212
213 esm_references_free_var: FxIndexMap<RcStr, ResolvedVc<EsmAssetReference>>,
214 esm_references_rewritten: FxHashMap<usize, FxIndexMap<RcStr, ResolvedVc<EsmAssetReference>>>,
217
218 code_gens: CodeGenCollection,
219 async_module: ResolvedVc<OptionAsyncModule>,
220 successful: bool,
221 source_map: Option<ResolvedVc<Box<dyn GenerateSourceMap>>>,
222 side_effects: ModuleSideEffects,
223 #[cfg(debug_assertions)]
224 ident: RcStr,
225}
226
227impl AnalyzeEcmascriptModuleResultBuilder {
228 fn new(analyze_mode: AnalyzeMode) -> Self {
229 Self {
230 analyze_mode,
231 references: Default::default(),
232 esm_references: Default::default(),
233 esm_local_references: Default::default(),
234 esm_reexport_references: Default::default(),
235 esm_references_rewritten: Default::default(),
236 esm_references_free_var: Default::default(),
237 code_gens: Default::default(),
238 async_module: ResolvedVc::cell(None),
239 successful: false,
240 source_map: None,
241 side_effects: ModuleSideEffects::SideEffectful,
242 #[cfg(debug_assertions)]
243 ident: Default::default(),
244 }
245 }
246
247 pub fn add_reference(&mut self, reference: ResolvedVc<impl Upcast<Box<dyn ModuleReference>>>) {
249 let r = ResolvedVc::upcast_non_strict(reference);
250 self.references.insert(r);
251 }
252
253 pub fn add_reference_code_gen<R: IntoCodeGenReference>(&mut self, reference: R, path: AstPath) {
255 let (reference, code_gen) = reference.into_code_gen_reference(path);
256 self.references.insert(reference);
257 self.add_code_gen(code_gen);
258 }
259
260 pub fn add_esm_reference(&mut self, idx: usize) {
262 self.esm_references.insert(idx);
263 self.esm_local_references.insert(idx);
264 }
265
266 pub fn add_esm_reexport_reference(&mut self, idx: usize) {
269 self.esm_references.insert(idx);
270 self.esm_reexport_references.insert(idx);
271 }
272
273 pub fn add_esm_evaluation_reference(&mut self, idx: usize) {
276 self.esm_references.insert(idx);
277 self.esm_local_references.insert(idx);
278 }
279
280 pub fn add_code_gen<C>(&mut self, code_gen: C)
282 where
283 C: Into<CodeGen>,
284 {
285 if self.analyze_mode.is_code_gen() {
286 #[cfg(debug_assertions)]
287 {
288 let (index, added) = self.code_gens.insert_full(code_gen.into());
289 debug_assert!(
290 added,
291 "Duplicate code gen added: {:?} in {}",
292 self.code_gens.get_index(index).unwrap(),
293 self.ident
294 );
295 }
296 #[cfg(not(debug_assertions))]
297 {
298 self.code_gens.push(code_gen.into());
299 }
300 }
301 }
302
303 pub fn set_source_map(&mut self, source_map: ResolvedVc<Box<dyn GenerateSourceMap>>) {
305 self.source_map = Some(source_map);
306 }
307
308 pub fn set_async_module(&mut self, async_module: ResolvedVc<AsyncModule>) {
310 self.async_module = ResolvedVc::cell(Some(async_module));
311 }
312
313 pub fn set_side_effects_mode(&mut self, value: ModuleSideEffects) {
315 self.side_effects = value;
316 }
317
318 pub fn set_successful(&mut self, successful: bool) {
320 self.successful = successful;
321 }
322
323 pub fn add_esm_reference_namespace_resolved(
324 &mut self,
325 esm_reference_idx: usize,
326 export: RcStr,
327 on_insert: impl FnOnce() -> ResolvedVc<EsmAssetReference>,
328 ) -> ResolvedVc<EsmAssetReference> {
329 *self
330 .esm_references_rewritten
331 .entry(esm_reference_idx)
332 .or_default()
333 .entry(export)
334 .or_insert_with(on_insert)
335 }
336
337 pub async fn add_esm_reference_free_var(
338 &mut self,
339 request: RcStr,
340 on_insert: impl AsyncFnOnce() -> Result<ResolvedVc<EsmAssetReference>>,
341 ) -> Result<ResolvedVc<EsmAssetReference>> {
342 Ok(match self.esm_references_free_var.entry(request) {
343 Entry::Occupied(e) => *e.get(),
344 Entry::Vacant(e) => *e.insert(on_insert().await?),
345 })
346 }
347
348 pub async fn build(
350 mut self,
351 import_references: &[ResolvedVc<EsmAssetReference>],
352 track_reexport_references: bool,
353 ) -> Result<Vc<AnalyzeEcmascriptModuleResult>> {
354 let mut esm_references = Vec::with_capacity(
357 self.esm_references.len()
358 + self.esm_references_free_var.len()
359 + self.esm_references_rewritten.len(),
360 );
361 esm_references.extend(self.esm_references_free_var.values());
362
363 let mut esm_local_references = track_reexport_references.then(|| {
364 let mut esm_local_references = Vec::with_capacity(
365 self.esm_local_references.len()
366 + self.esm_references_free_var.len()
367 + self.esm_references_rewritten.len(),
368 );
369 esm_local_references.extend(self.esm_references_free_var.values());
370 esm_local_references
371 });
372 let mut esm_reexport_references = track_reexport_references
373 .then(|| Vec::with_capacity(self.esm_reexport_references.len()));
374 for (i, reference) in import_references.iter().enumerate() {
375 if self.esm_references.contains(&i) {
376 esm_references.push(*reference);
377 }
378 esm_references.extend(
379 self.esm_references_rewritten
380 .get(&i)
381 .iter()
382 .flat_map(|m| m.values().copied()),
383 );
384 if let Some(esm_local_references) = &mut esm_local_references {
385 if self.esm_local_references.contains(&i) {
386 esm_local_references.push(*reference);
387 }
388 esm_local_references.extend(
389 self.esm_references_rewritten
390 .get(&i)
391 .iter()
392 .flat_map(|m| m.values().copied()),
393 );
394 }
395 if let Some(esm_reexport_references) = &mut esm_reexport_references
396 && self.esm_reexport_references.contains(&i)
397 {
398 esm_reexport_references.push(*reference);
399 }
400 }
401
402 let references: Vec<_> = self.references.into_iter().collect();
403
404 if !self.analyze_mode.is_code_gen() {
405 debug_assert!(self.code_gens.is_empty());
406 }
407
408 self.code_gens.shrink_to_fit();
409
410 #[cfg(debug_assertions)]
411 let code_generation = self.code_gens.into_iter().collect::<Vec<_>>();
412 #[cfg(not(debug_assertions))]
413 let code_generation = self.code_gens;
414
415 Ok(AnalyzeEcmascriptModuleResult::cell(
416 AnalyzeEcmascriptModuleResult {
417 references,
418 esm_references: ResolvedVc::cell(esm_references),
419 esm_local_references: ResolvedVc::cell(esm_local_references.unwrap_or_default()),
420 esm_reexport_references: ResolvedVc::cell(
421 esm_reexport_references.unwrap_or_default(),
422 ),
423 code_generation: ResolvedVc::cell(code_generation),
424 async_module: self.async_module,
425 side_effects: self.side_effects,
426 successful: self.successful,
427 source_map: self.source_map,
428 },
429 ))
430 }
431}
432
433struct AnalysisState<'a> {
434 handler: &'a Handler,
435 module: ResolvedVc<EcmascriptModuleAsset>,
436 source: ResolvedVc<Box<dyn Source>>,
437 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
438 compile_time_info: ResolvedVc<CompileTimeInfo>,
439 free_var_references_members: ResolvedVc<FreeVarReferencesMembers>,
440 compile_time_info_ref: ReadRef<CompileTimeInfo>,
441 var_graph: &'a VarGraph,
442 allow_project_root_tracing: bool,
446 fun_args_values: Mutex<FxHashMap<u32, Vec<JsValue>>>,
449 var_cache: Mutex<FxHashMap<Id, JsValue>>,
450 first_import_meta: bool,
453 first_webpack_exports_info: bool,
456 tree_shaking_mode: Option<TreeShakingMode>,
457 import_externals: bool,
458 ignore_dynamic_requests: bool,
459 url_rewrite_behavior: Option<UrlRewriteBehavior>,
460 collect_affecting_sources: bool,
463 tracing_only: bool,
466 is_esm: bool,
468 import_references: &'a [ResolvedVc<EsmAssetReference>],
470 imports: &'a ImportMap,
472 inner_assets: Option<ReadRef<InnerAssets>>,
474}
475
476impl AnalysisState<'_> {
477 async fn link_value(&self, value: JsValue, attributes: &ImportAttributes) -> Result<JsValue> {
479 Ok(link(
480 self.var_graph,
481 value,
482 &early_value_visitor,
483 &|value| {
484 value_visitor(
485 *self.origin,
486 value,
487 *self.compile_time_info,
488 &self.compile_time_info_ref,
489 self.var_graph,
490 attributes,
491 self.allow_project_root_tracing,
492 )
493 },
494 &self.fun_args_values,
495 &self.var_cache,
496 )
497 .await?
498 .0)
499 }
500}
501
502fn set_handler_and_globals<F, R>(handler: &Handler, globals: &Arc<Globals>, f: F) -> R
503where
504 F: FnOnce() -> R,
505{
506 HANDLER.set(handler, || GLOBALS.set(globals, f))
507}
508
509#[turbo_tasks::function]
511pub async fn analyze_ecmascript_module(
512 module: ResolvedVc<EcmascriptModuleAsset>,
513 part: Option<ModulePart>,
514) -> Result<Vc<AnalyzeEcmascriptModuleResult>> {
515 let span = tracing::info_span!(
516 "analyze ecmascript module",
517 name = display(module.ident().to_string().await?)
518 );
519 let result = analyze_ecmascript_module_internal(module, part)
520 .instrument(span)
521 .await;
522
523 match result {
524 Ok(result) => Ok(result),
525 Err(err) => Err(err
527 .context(turbofmt!("failed to analyze ecmascript module '{}'", module.ident()).await?)),
528 }
529}
530
531async fn analyze_ecmascript_module_internal(
532 module: ResolvedVc<EcmascriptModuleAsset>,
533 part: Option<ModulePart>,
534) -> Result<Vc<AnalyzeEcmascriptModuleResult>> {
535 let raw_module = module.await?;
536
537 let source = raw_module.source;
538 let ty = raw_module.ty;
539 let options = raw_module.options;
540 let options = options.await?;
541 let import_externals = options.import_externals;
542 let analyze_mode = options.analyze_mode;
543
544 let origin = ResolvedVc::upcast::<Box<dyn ResolveOrigin>>(module);
545 let path = &*origin.origin_path().await?;
546 let mut analysis = AnalyzeEcmascriptModuleResultBuilder::new(analyze_mode);
547 #[cfg(debug_assertions)]
548 {
549 analysis.ident = source.ident().to_string().owned().await?;
550 }
551
552 let inner_assets = if let Some(assets) = raw_module.inner_assets {
553 Some(assets.await?)
554 } else {
555 None
556 };
557
558 let analyze_types = match &ty {
560 EcmascriptModuleAssetType::Typescript { analyze_types, .. } => *analyze_types,
561 EcmascriptModuleAssetType::TypescriptDeclaration => true,
562 EcmascriptModuleAssetType::Ecmascript
563 | EcmascriptModuleAssetType::EcmascriptExtensionless => false,
564 };
565
566 let parsed = if let Some(part) = &part {
568 let split_data = split_module(*module);
569 part_of_module(split_data, part.clone())
570 } else {
571 module.failsafe_parse()
572 };
573
574 let ModuleTypeResult {
575 module_type: specified_type,
576 ref referenced_package_json,
577 } = *module.determine_module_type().await?;
578
579 if let Some(package_json) = referenced_package_json {
580 let span = tracing::trace_span!("package.json reference");
581 async {
582 analysis.add_reference(
583 PackageJsonReference::new(package_json.clone())
584 .to_resolved()
585 .await?,
586 );
587 anyhow::Ok(())
588 }
589 .instrument(span)
590 .await?;
591 }
592
593 if analyze_types {
594 let span = tracing::trace_span!("tsconfig reference");
595 async {
596 match &*find_context_file(path.parent(), tsconfig(), false).await? {
597 FindContextFileResult::Found(tsconfig, _) => {
598 analysis.add_reference(
599 TsConfigReference::new(*origin, tsconfig.clone())
600 .to_resolved()
601 .await?,
602 );
603 }
604 FindContextFileResult::NotFound(_) => {}
605 };
606 anyhow::Ok(())
607 }
608 .instrument(span)
609 .await?;
610 }
611
612 let EcmascriptExportsAnalysis {
613 exports: _,
614 import_references,
615 esm_reexport_reference_idxs,
616 esm_evaluation_reference_idxs,
617 } = &*compute_ecmascript_module_exports(*module, part).await?;
619
620 let parsed = if !analyze_mode.is_code_gen() {
621 parsed.final_read_hint().await?
623 } else {
624 parsed.await?
625 };
626
627 let ParseResult::Ok {
628 program,
629 globals,
630 eval_context,
631 comments,
632 source_map,
633 source_mapping_url,
634 program_source: _,
635 } = &*parsed
636 else {
637 return analysis.build(Default::default(), false).await;
638 };
639
640 for i in esm_reexport_reference_idxs {
641 analysis.add_esm_reexport_reference(*i);
642 }
643 for i in esm_evaluation_reference_idxs {
644 analysis.add_esm_evaluation_reference(*i);
645 }
646
647 let has_side_effect_free_directive = match program {
648 Program::Module(module) => Either::Left(
649 module
650 .body
651 .iter()
652 .take_while(|i| match i {
653 ModuleItem::Stmt(stmt) => stmt.directive_continue(),
654 ModuleItem::ModuleDecl(_) => false,
655 })
656 .filter_map(|i| i.as_stmt()),
657 ),
658 Program::Script(script) => Either::Right(
659 script
660 .body
661 .iter()
662 .take_while(|stmt| stmt.directive_continue()),
663 ),
664 }
665 .any(|f| match f {
666 Stmt::Expr(ExprStmt { expr, .. }) => match &**expr {
667 Expr::Lit(Lit::Str(Str { value, .. })) => value == "use turbopack no side effects",
668 _ => false,
669 },
670 _ => false,
671 });
672 analysis.set_side_effects_mode(if has_side_effect_free_directive {
673 ModuleSideEffects::SideEffectFree
674 } else if options.infer_module_side_effects {
675 GLOBALS.set(globals, || {
677 side_effects::compute_module_evaluation_side_effects(
678 program,
679 comments,
680 eval_context.unresolved_mark,
681 )
682 })
683 } else {
684 ModuleSideEffects::SideEffectful
686 });
687
688 let is_esm = eval_context.is_esm(specified_type);
689 let compile_time_info = compile_time_info_for_module_options(
690 *raw_module.compile_time_info,
691 is_esm,
692 options.enable_typeof_window_inlining,
693 )
694 .to_resolved()
695 .await?;
696
697 let pos = program.span().lo;
698 if analyze_types {
699 let span = tracing::trace_span!("type references");
700 async {
701 if let Some(comments) = comments.get_leading(pos) {
702 for comment in comments.iter() {
703 if let CommentKind::Line = comment.kind {
704 static REFERENCE_PATH: LazyLock<Regex> = LazyLock::new(|| {
705 Regex::new(r#"^/\s*<reference\s*path\s*=\s*["'](.+)["']\s*/>\s*$"#)
706 .unwrap()
707 });
708 static REFERENCE_TYPES: LazyLock<Regex> = LazyLock::new(|| {
709 Regex::new(r#"^/\s*<reference\s*types\s*=\s*["'](.+)["']\s*/>\s*$"#)
710 .unwrap()
711 });
712 let text = &comment.text;
713 if let Some(m) = REFERENCE_PATH.captures(text) {
714 let path = &m[1];
715 analysis.add_reference(
716 TsReferencePathAssetReference::new(*origin, path.into())
717 .to_resolved()
718 .await?,
719 );
720 } else if let Some(m) = REFERENCE_TYPES.captures(text) {
721 let types = &m[1];
722 analysis.add_reference(
723 TsReferenceTypeAssetReference::new(*origin, types.into())
724 .to_resolved()
725 .await?,
726 );
727 }
728 }
729 }
730 }
731 anyhow::Ok(())
732 }
733 .instrument(span)
734 .await?;
735 }
736
737 if options.extract_source_map {
738 let span = tracing::trace_span!("source map reference");
739 async {
740 if let Some((source_map, reference)) = parse_source_map_comment(
741 source,
742 source_mapping_url.as_deref(),
743 &*origin.origin_path().await?,
744 )
745 .await?
746 {
747 analysis.set_source_map(source_map);
748 if let Some(reference) = reference {
749 analysis.add_reference(reference);
750 }
751 }
752 anyhow::Ok(())
753 }
754 .instrument(span)
755 .await?;
756 }
757
758 let (emitter, collector) = IssueEmitter::new(source, source_map.clone(), None);
759 let handler = Handler::with_emitter(true, false, Box::new(emitter));
760
761 let supports_block_scoping = *compile_time_info
762 .environment()
763 .runtime_versions()
764 .supports_block_scoping()
765 .await?;
766
767 let span = tracing::trace_span!("async module handling");
769 async {
770 let top_level_await_span =
771 set_handler_and_globals(&handler, globals, || has_top_level_await(program));
772 let has_top_level_await = top_level_await_span.is_some();
773
774 if eval_context.is_esm(specified_type) {
775 let async_module = AsyncModule {
776 has_top_level_await,
777 import_externals,
778 }
779 .resolved_cell();
780 analysis.set_async_module(async_module);
781 } else if let Some(span) = top_level_await_span {
782 AnalyzeIssue::new(
783 IssueSeverity::Error,
784 source.ident(),
785 Vc::cell(rcstr!("unexpected top level await")),
786 StyledString::Text(rcstr!("top level await is only supported in ESM modules."))
787 .cell(),
788 None,
789 Some(issue_source(source, span)),
790 )
791 .to_resolved()
792 .await?
793 .emit();
794 }
795 anyhow::Ok(())
796 }
797 .instrument(span)
798 .await?;
799
800 let mut var_graph = {
801 let _span = tracing::trace_span!("analyze variable values").entered();
802 set_handler_and_globals(&handler, globals, || {
803 create_graph(program, eval_context, analyze_mode, supports_block_scoping)
804 })
805 };
806
807 let span = tracing::trace_span!("effects processing");
808 async {
809 analysis.code_gens.extend(take(&mut var_graph.code_gens));
810 let effects = take(&mut var_graph.effects);
811 let compile_time_info_ref = compile_time_info.await?;
812
813 let mut analysis_state = AnalysisState {
814 handler: &handler,
815 module,
816 source,
817 origin,
818 compile_time_info,
819 free_var_references_members: compile_time_info_ref
820 .free_var_references
821 .members()
822 .to_resolved()
823 .await?,
824 compile_time_info_ref,
825 var_graph: &var_graph,
826 allow_project_root_tracing: !source.ident().await?.path.is_in_node_modules(),
827 fun_args_values: Default::default(),
828 var_cache: Default::default(),
829 first_import_meta: true,
830 first_webpack_exports_info: true,
831 tree_shaking_mode: options.tree_shaking_mode,
832 import_externals: options.import_externals,
833 ignore_dynamic_requests: options.ignore_dynamic_requests,
834 url_rewrite_behavior: options.url_rewrite_behavior,
835 collect_affecting_sources: options.analyze_mode.is_tracing_assets(),
836 tracing_only: !options.analyze_mode.is_code_gen(),
837 is_esm,
838 import_references,
839 imports: &eval_context.imports,
840 inner_assets,
841 };
842
843 enum Action {
844 Effect(Effect),
845 LeaveScope(u32),
846 }
847
848 let mut queue_stack = Mutex::new(Vec::new());
853 queue_stack
854 .get_mut()
855 .extend(effects.into_iter().map(Action::Effect).rev());
856
857 while let Some(action) = queue_stack.get_mut().pop() {
858 let effect = match action {
859 Action::LeaveScope(func_ident) => {
860 analysis_state.fun_args_values.get_mut().remove(&func_ident);
861 continue;
862 }
863 Action::Effect(effect) => effect,
864 };
865
866 let add_effects = |effects: Vec<Effect>| {
867 queue_stack
868 .lock()
869 .extend(effects.into_iter().map(Action::Effect).rev())
870 };
871
872 match effect {
873 Effect::Unreachable { start_ast_path } => {
874 debug_assert!(
875 analyze_mode.is_code_gen(),
876 "unexpected Effect::Unreachable in tracing mode"
877 );
878
879 analysis
880 .add_code_gen(Unreachable::new(AstPathRange::StartAfter(start_ast_path)));
881 }
882 Effect::Conditional {
883 condition,
884 kind,
885 ast_path: condition_ast_path,
886 span: _,
887 } => {
888 let condition_has_side_effects = condition.has_side_effects();
891
892 let condition = analysis_state
893 .link_value(*condition, ImportAttributes::empty_ref())
894 .await?;
895
896 macro_rules! inactive {
897 ($block:ident) => {
898 if analyze_mode.is_code_gen() {
899 analysis.add_code_gen(Unreachable::new($block.range.clone()));
900 }
901 };
902 }
903 macro_rules! condition {
904 ($expr:expr) => {
905 if analyze_mode.is_code_gen() && !condition_has_side_effects {
906 analysis.add_code_gen(ConstantConditionCodeGen::new(
907 $expr,
908 condition_ast_path.to_vec().into(),
909 ));
910 }
911 };
912 }
913 macro_rules! active {
914 ($block:ident) => {
915 queue_stack
916 .get_mut()
917 .extend($block.effects.into_iter().map(Action::Effect).rev())
918 };
919 }
920 match *kind {
921 ConditionalKind::If { then } => match condition.is_truthy() {
922 Some(true) => {
923 condition!(ConstantConditionValue::Truthy);
924 active!(then);
925 }
926 Some(false) => {
927 condition!(ConstantConditionValue::Falsy);
928 inactive!(then);
929 }
930 None => {
931 active!(then);
932 }
933 },
934 ConditionalKind::Else { r#else } => match condition.is_truthy() {
935 Some(true) => {
936 condition!(ConstantConditionValue::Truthy);
937 inactive!(r#else);
938 }
939 Some(false) => {
940 condition!(ConstantConditionValue::Falsy);
941 active!(r#else);
942 }
943 None => {
944 active!(r#else);
945 }
946 },
947 ConditionalKind::IfElse { then, r#else }
948 | ConditionalKind::Ternary { then, r#else } => {
949 match condition.is_truthy() {
950 Some(true) => {
951 condition!(ConstantConditionValue::Truthy);
952 active!(then);
953 inactive!(r#else);
954 }
955 Some(false) => {
956 condition!(ConstantConditionValue::Falsy);
957 active!(r#else);
958 inactive!(then);
959 }
960 None => {
961 active!(then);
962 active!(r#else);
963 }
964 }
965 }
966 ConditionalKind::IfElseMultiple { then, r#else } => {
967 match condition.is_truthy() {
968 Some(true) => {
969 condition!(ConstantConditionValue::Truthy);
970 for then in then {
971 active!(then);
972 }
973 for r#else in r#else {
974 inactive!(r#else);
975 }
976 }
977 Some(false) => {
978 condition!(ConstantConditionValue::Falsy);
979 for then in then {
980 inactive!(then);
981 }
982 for r#else in r#else {
983 active!(r#else);
984 }
985 }
986 None => {
987 for then in then {
988 active!(then);
989 }
990 for r#else in r#else {
991 active!(r#else);
992 }
993 }
994 }
995 }
996 ConditionalKind::And { expr } => match condition.is_truthy() {
997 Some(true) => {
998 condition!(ConstantConditionValue::Truthy);
999 active!(expr);
1000 }
1001 Some(false) => {
1002 inactive!(expr);
1004 }
1005 None => {
1006 active!(expr);
1007 }
1008 },
1009 ConditionalKind::Or { expr } => match condition.is_truthy() {
1010 Some(true) => {
1011 inactive!(expr);
1013 }
1014 Some(false) => {
1015 condition!(ConstantConditionValue::Falsy);
1016 active!(expr);
1017 }
1018 None => {
1019 active!(expr);
1020 }
1021 },
1022 ConditionalKind::NullishCoalescing { expr } => {
1023 match condition.is_nullish() {
1024 Some(true) => {
1025 condition!(ConstantConditionValue::Nullish);
1026 active!(expr);
1027 }
1028 Some(false) => {
1029 inactive!(expr);
1030 }
1031 None => {
1032 active!(expr);
1033 }
1034 }
1035 }
1036 ConditionalKind::Labeled { body } => {
1037 active!(body);
1038 }
1039 }
1040 }
1041 Effect::Call {
1042 func,
1043 args,
1044 ast_path,
1045 span,
1046 in_try,
1047 new,
1048 } => {
1049 let func = analysis_state
1050 .link_value(*func, eval_context.imports.get_attributes(span))
1051 .await?;
1052
1053 handle_call(
1054 &ast_path,
1055 span,
1056 func,
1057 args,
1058 &analysis_state,
1059 &add_effects,
1060 &mut analysis,
1061 in_try,
1062 new,
1063 eval_context.imports.get_attributes(span),
1064 )
1065 .await?;
1066 }
1067 Effect::DynamicImport {
1068 args,
1069 ast_path,
1070 span,
1071 in_try,
1072 export_usage,
1073 } => {
1074 handle_dynamic_import(
1075 &ast_path,
1076 span,
1077 args,
1078 &analysis_state,
1079 &add_effects,
1080 &mut analysis,
1081 in_try,
1082 eval_context.imports.get_attributes(span),
1083 export_usage,
1084 )
1085 .await?;
1086 }
1087 Effect::MemberCall {
1088 obj,
1089 prop,
1090 mut args,
1091 ast_path,
1092 span,
1093 in_try,
1094 new,
1095 } => {
1096 let func = analysis_state
1097 .link_value(
1098 JsValue::member(obj.clone(), prop),
1099 eval_context.imports.get_attributes(span),
1100 )
1101 .await?;
1102
1103 if !new
1104 && matches!(
1105 func,
1106 JsValue::WellKnownFunction(
1107 WellKnownFunctionKind::ArrayFilter
1108 | WellKnownFunctionKind::ArrayForEach
1109 | WellKnownFunctionKind::ArrayMap
1110 )
1111 )
1112 && let [EffectArg::Closure(value, block)] = &mut args[..]
1113 && let JsValue::Array {
1114 items: ref mut values,
1115 mutable,
1116 ..
1117 } = analysis_state
1118 .link_value(*obj, eval_context.imports.get_attributes(span))
1119 .await?
1120 {
1121 *value = analysis_state
1122 .link_value(take(value), ImportAttributes::empty_ref())
1123 .await?;
1124 if let JsValue::Function(_, func_ident, _) = value {
1125 let mut closure_arg = JsValue::alternatives(take(values));
1126 if mutable {
1127 closure_arg.add_unknown_mutations(true);
1128 }
1129 analysis_state
1130 .fun_args_values
1131 .get_mut()
1132 .insert(*func_ident, vec![closure_arg]);
1133 queue_stack.get_mut().push(Action::LeaveScope(*func_ident));
1134 queue_stack.get_mut().extend(
1135 take(&mut block.effects)
1136 .into_iter()
1137 .map(Action::Effect)
1138 .rev(),
1139 );
1140 continue;
1141 }
1142 }
1143
1144 handle_call(
1145 &ast_path,
1146 span,
1147 func,
1148 args,
1149 &analysis_state,
1150 &add_effects,
1151 &mut analysis,
1152 in_try,
1153 new,
1154 eval_context.imports.get_attributes(span),
1155 )
1156 .await?;
1157 }
1158 Effect::FreeVar {
1159 var,
1160 ast_path,
1161 span,
1162 } => {
1163 debug_assert!(
1164 analyze_mode.is_code_gen(),
1165 "unexpected Effect::FreeVar in tracing mode"
1166 );
1167
1168 if options.enable_exports_info_inlining && var == "__webpack_exports_info__" {
1169 if analysis_state.first_webpack_exports_info {
1170 analysis_state.first_webpack_exports_info = false;
1171 analysis.add_code_gen(ExportsInfoBinding::new());
1172 }
1173 analysis.add_code_gen(ExportsInfoRef::new(ast_path.into()));
1174 continue;
1175 }
1176
1177 if !analysis_state
1179 .link_value(
1180 JsValue::FreeVar(var.clone()),
1181 eval_context.imports.get_attributes(span),
1182 )
1183 .await?
1184 .is_unknown()
1185 {
1186 handle_free_var(
1188 &ast_path,
1189 JsValue::FreeVar(var),
1190 span,
1191 &analysis_state,
1192 &mut analysis,
1193 )
1194 .await?;
1195 }
1196 }
1197 Effect::Member {
1198 obj,
1199 prop,
1200 ast_path,
1201 span,
1202 } => {
1203 debug_assert!(
1204 analyze_mode.is_code_gen(),
1205 "unexpected Effect::Member in tracing mode"
1206 );
1207
1208 let obj = analysis_state.link_value(*obj, ImportAttributes::empty_ref());
1210
1211 let prop = analysis_state
1212 .link_value(*prop, ImportAttributes::empty_ref())
1213 .await?;
1214
1215 handle_member(&ast_path, obj, prop, span, &analysis_state, &mut analysis)
1216 .await?;
1217 }
1218 Effect::ImportedBinding {
1219 esm_reference_index,
1220 export,
1221 ast_path,
1222 span: _,
1223 } => {
1224 let Some(r) = import_references.get(esm_reference_index) else {
1225 continue;
1226 };
1227
1228 if let Some("__turbopack_module_id__") = export.as_deref() {
1229 let chunking_type = r
1230 .await?
1231 .annotations
1232 .as_ref()
1233 .and_then(|a| a.chunking_type())
1234 .map_or_else(
1235 || {
1236 Some(ChunkingType::Parallel {
1237 inherit_async: true,
1238 hoisted: true,
1239 })
1240 },
1241 |c| c.as_chunking_type(true, true),
1242 );
1243 analysis.add_reference_code_gen(
1244 EsmModuleIdAssetReference::new(*r, chunking_type),
1245 ast_path.into(),
1246 )
1247 } else {
1248 if matches!(
1249 options.tree_shaking_mode,
1250 Some(TreeShakingMode::ReexportsOnly)
1251 ) {
1252 let original_reference = r.await?;
1255 if original_reference.export_name.is_none()
1256 && export.is_some()
1257 && let Some(export) = export
1258 {
1259 let named_reference = analysis
1262 .add_esm_reference_namespace_resolved(
1263 esm_reference_index,
1264 export.clone(),
1265 || {
1266 EsmAssetReference::new(
1267 original_reference.module,
1268 original_reference.origin,
1269 original_reference.request.clone(),
1270 original_reference.issue_source,
1271 original_reference.annotations.clone(),
1272 Some(ModulePart::export(export.clone())),
1273 original_reference.import_usage.clone(),
1278 original_reference.import_externals,
1279 original_reference.tree_shaking_mode,
1280 original_reference.resolve_override,
1281 )
1282 .resolved_cell()
1283 },
1284 );
1285 analysis.add_code_gen(EsmBinding::new_keep_this(
1286 named_reference,
1287 Some(export),
1288 ast_path.into(),
1289 ));
1290 continue;
1291 }
1292 }
1293
1294 analysis.add_esm_reference(esm_reference_index);
1295 analysis.add_code_gen(EsmBinding::new(*r, export, ast_path.into()));
1296 }
1297 }
1298 Effect::TypeOf {
1299 arg,
1300 ast_path,
1301 span,
1302 } => {
1303 debug_assert!(
1304 analyze_mode.is_code_gen(),
1305 "unexpected Effect::TypeOf in tracing mode"
1306 );
1307 let arg = analysis_state
1308 .link_value(*arg, ImportAttributes::empty_ref())
1309 .await?;
1310 handle_typeof(&ast_path, arg, span, &analysis_state, &mut analysis).await?;
1311 }
1312 Effect::ImportMeta { ast_path, span: _ } => {
1313 debug_assert!(
1314 analyze_mode.is_code_gen(),
1315 "unexpected Effect::ImportMeta in tracing mode"
1316 );
1317 if analysis_state.first_import_meta {
1318 analysis_state.first_import_meta = false;
1319 analysis.add_code_gen(ImportMetaBinding::new(
1320 source.ident().await?.path.clone(),
1321 analysis_state
1322 .compile_time_info_ref
1323 .hot_module_replacement_enabled,
1324 ));
1325 }
1326
1327 analysis.add_code_gen(ImportMetaRef::new(ast_path.into()));
1328 }
1329 }
1330 }
1331 anyhow::Ok(())
1332 }
1333 .instrument(span)
1334 .await?;
1335
1336 analysis.set_successful(true);
1337
1338 collector.emit(false).await?;
1339
1340 analysis
1341 .build(
1342 import_references,
1343 matches!(
1344 options.tree_shaking_mode,
1345 Some(TreeShakingMode::ReexportsOnly)
1346 ),
1347 )
1348 .await
1349}
1350
1351#[turbo_tasks::function]
1352async fn compile_time_info_for_module_options(
1353 compile_time_info: Vc<CompileTimeInfo>,
1354 is_esm: bool,
1355 enable_typeof_window_inlining: Option<TypeofWindow>,
1356) -> Result<Vc<CompileTimeInfo>> {
1357 let compile_time_info = compile_time_info.await?;
1358 let free_var_references = compile_time_info.free_var_references;
1359 let defines = compile_time_info.defines;
1360
1361 let mut free_var_references = free_var_references.owned().await?;
1362 let mut defines = defines.owned().await?;
1363
1364 let (typeof_exports, typeof_module, typeof_this, require) = if is_esm {
1365 (
1366 rcstr!("undefined"),
1367 rcstr!("undefined"),
1368 rcstr!("undefined"),
1369 TURBOPACK_REQUIRE_STUB,
1370 )
1371 } else {
1372 (
1373 rcstr!("object"),
1374 rcstr!("object"),
1375 rcstr!("object"),
1376 TURBOPACK_REQUIRE_REAL,
1377 )
1378 };
1379 let typeofs: [(&[RcStr], RcStr); _] = [
1380 (&[rcstr!("import"), rcstr!("meta")], rcstr!("object")),
1381 (&[rcstr!("exports")], typeof_exports),
1382 (&[rcstr!("module")], typeof_module),
1383 (&[rcstr!("this")], typeof_this),
1384 (&[rcstr!("require")], rcstr!("function")),
1385 (&[rcstr!("__dirname")], rcstr!("string")),
1386 (&[rcstr!("__filename")], rcstr!("string")),
1387 (&[rcstr!("global")], rcstr!("object")),
1388 ];
1389 for (typeof_path, typeof_value) in typeofs {
1390 let name = typeof_path
1391 .iter()
1392 .map(|s| DefinableNameSegment::Name(s.clone()))
1393 .chain(std::iter::once(DefinableNameSegment::TypeOf))
1394 .collect::<Vec<_>>();
1395 free_var_references
1396 .entry(name.clone())
1397 .or_insert(typeof_value.clone().into());
1398 defines.entry(name).or_insert(typeof_value.into());
1399 }
1400
1401 free_var_references
1402 .entry(vec![DefinableNameSegment::Name(rcstr!("require"))])
1403 .or_insert(require.into());
1404 free_var_references
1405 .entry(vec![DefinableNameSegment::Name(rcstr!("__dirname"))])
1406 .or_insert(FreeVarReference::InputRelative(
1407 InputRelativeConstant::DirName,
1408 ));
1409 free_var_references
1410 .entry(vec![DefinableNameSegment::Name(rcstr!("__filename"))])
1411 .or_insert(FreeVarReference::InputRelative(
1412 InputRelativeConstant::FileName,
1413 ));
1414
1415 free_var_references
1418 .entry(vec![DefinableNameSegment::Name(rcstr!("global"))])
1419 .or_insert(TURBOPACK_GLOBAL.into());
1420
1421 free_var_references.extend(TURBOPACK_RUNTIME_FUNCTION_SHORTCUTS.into_iter().map(
1422 |(name, shortcut)| {
1423 (
1424 vec![DefinableNameSegment::Name(name.into())],
1425 shortcut.into(),
1426 )
1427 },
1428 ));
1429 free_var_references
1434 .entry(vec![DefinableNameSegment::Name(rcstr!("this"))])
1435 .or_insert(if is_esm {
1436 FreeVarReference::Value(CompileTimeDefineValue::Undefined)
1437 } else {
1438 TURBOPACK_EXPORTS.into()
1441 });
1442
1443 if let Some(enable_typeof_window_inlining) = enable_typeof_window_inlining {
1444 let value = match enable_typeof_window_inlining {
1445 TypeofWindow::Object => rcstr!("object"),
1446 TypeofWindow::Undefined => rcstr!("undefined"),
1447 };
1448 let window = rcstr!("window");
1449 free_var_references
1450 .entry(vec![
1451 DefinableNameSegment::Name(window.clone()),
1452 DefinableNameSegment::TypeOf,
1453 ])
1454 .or_insert(value.clone().into());
1455 defines
1456 .entry(vec![
1457 DefinableNameSegment::Name(window),
1458 DefinableNameSegment::TypeOf,
1459 ])
1460 .or_insert(value.into());
1461 }
1462
1463 Ok(CompileTimeInfo {
1464 environment: compile_time_info.environment,
1465 defines: CompileTimeDefines(defines).resolved_cell(),
1466 free_var_references: FreeVarReferences(free_var_references).resolved_cell(),
1467 hot_module_replacement_enabled: compile_time_info.hot_module_replacement_enabled,
1468 }
1469 .cell())
1470}
1471
1472async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
1473 ast_path: &[AstParentKind],
1474 span: Span,
1475 func: JsValue,
1476 args: Vec<EffectArg>,
1477 state: &AnalysisState<'_>,
1478 add_effects: &G,
1479 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
1480 in_try: bool,
1481 new: bool,
1482 attributes: &ImportAttributes,
1483) -> Result<()> {
1484 let &AnalysisState {
1485 handler,
1486 origin,
1487 source,
1488 compile_time_info,
1489 ignore_dynamic_requests,
1490 url_rewrite_behavior,
1491 collect_affecting_sources,
1492 tracing_only,
1493 allow_project_root_tracing: _,
1494 ..
1495 } = state;
1496
1497 let unlinked_args = args
1501 .into_iter()
1502 .map(|effect_arg| match effect_arg {
1503 EffectArg::Value(value) => value,
1504 EffectArg::Closure(value, block) => {
1505 add_effects(block.effects);
1506 value
1507 }
1508 EffectArg::Spread => {
1509 JsValue::unknown_empty(true, rcstr!("spread is not supported yet"))
1510 }
1511 })
1512 .collect::<Vec<_>>();
1513
1514 let linked_args_cache = OnceCell::new();
1516
1517 let linked_args = || async {
1519 linked_args_cache
1520 .get_or_try_init(|| async {
1521 unlinked_args
1522 .iter()
1523 .cloned()
1524 .map(|arg| state.link_value(arg, ImportAttributes::empty_ref()))
1525 .try_join()
1526 .await
1527 })
1528 .await
1529 };
1530
1531 match func {
1532 JsValue::Alternatives {
1533 total_nodes: _,
1534 values,
1535 logical_property: _,
1536 } => {
1537 for alt in values {
1538 if let JsValue::WellKnownFunction(wkf) = alt {
1539 handle_well_known_function_call(
1540 wkf,
1541 new,
1542 &linked_args,
1543 handler,
1544 span,
1545 ignore_dynamic_requests,
1546 analysis,
1547 origin,
1548 compile_time_info,
1549 url_rewrite_behavior,
1550 source,
1551 ast_path,
1552 in_try,
1553 state,
1554 collect_affecting_sources,
1555 tracing_only,
1556 attributes,
1557 )
1558 .await?;
1559 }
1560 }
1561 }
1562 JsValue::WellKnownFunction(wkf) => {
1563 handle_well_known_function_call(
1564 wkf,
1565 new,
1566 &linked_args,
1567 handler,
1568 span,
1569 ignore_dynamic_requests,
1570 analysis,
1571 origin,
1572 compile_time_info,
1573 url_rewrite_behavior,
1574 source,
1575 ast_path,
1576 in_try,
1577 state,
1578 collect_affecting_sources,
1579 tracing_only,
1580 attributes,
1581 )
1582 .await?;
1583 }
1584 _ => {}
1585 }
1586
1587 Ok(())
1588}
1589
1590async fn handle_dynamic_import<G: Fn(Vec<Effect>) + Send + Sync>(
1591 ast_path: &[AstParentKind],
1592 span: Span,
1593 args: Vec<EffectArg>,
1594 state: &AnalysisState<'_>,
1595 add_effects: &G,
1596 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
1597 in_try: bool,
1598 attributes: &ImportAttributes,
1599 export_usage: ExportUsage,
1600) -> Result<()> {
1601 if attributes.ignore {
1604 return Ok(());
1605 }
1606
1607 let &AnalysisState {
1608 handler,
1609 origin,
1610 source,
1611 ignore_dynamic_requests,
1612 ..
1613 } = state;
1614
1615 let error_mode = if attributes.optional {
1616 ResolveErrorMode::Ignore
1617 } else if in_try {
1618 ResolveErrorMode::Warn
1619 } else {
1620 ResolveErrorMode::Error
1621 };
1622
1623 let unlinked_args: Vec<JsValue> = args
1625 .into_iter()
1626 .map(|effect_arg| match effect_arg {
1627 EffectArg::Value(value) => value,
1628 EffectArg::Closure(value, block) => {
1629 add_effects(block.effects);
1630 value
1631 }
1632 EffectArg::Spread => {
1633 JsValue::unknown_empty(true, rcstr!("spread is not supported yet"))
1634 }
1635 })
1636 .collect();
1637
1638 let linked_args = unlinked_args
1639 .iter()
1640 .cloned()
1641 .map(|arg| state.link_value(arg, ImportAttributes::empty_ref()))
1642 .try_join()
1643 .await?;
1644
1645 handle_dynamic_import_with_linked_args(
1646 ast_path,
1647 span,
1648 &linked_args,
1649 handler,
1650 origin,
1651 source,
1652 &state.inner_assets,
1653 ignore_dynamic_requests,
1654 analysis,
1655 error_mode,
1656 state.import_externals,
1657 export_usage,
1658 )
1659 .await
1660}
1661
1662async fn handle_dynamic_import_with_linked_args(
1663 ast_path: &[AstParentKind],
1664 span: Span,
1665 linked_args: &[JsValue],
1666 handler: &Handler,
1667 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
1668 source: ResolvedVc<Box<dyn Source>>,
1669 inner_assets: &Option<ReadRef<InnerAssets>>,
1670 ignore_dynamic_requests: bool,
1671 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
1672 error_mode: ResolveErrorMode,
1673 import_externals: bool,
1674 export_usage: ExportUsage,
1675) -> Result<()> {
1676 if linked_args.len() == 1 || linked_args.len() == 2 {
1677 let pat = js_value_to_pattern(&linked_args[0]);
1678 let options = linked_args.get(1);
1679 let import_annotations = options
1680 .and_then(|options| {
1681 if let JsValue::Object { parts, .. } = options {
1682 parts.iter().find_map(|part| {
1683 if let ObjectPart::KeyValue(
1684 JsValue::Constant(super::analyzer::ConstantValue::Str(key)),
1685 value,
1686 ) = part
1687 && key.as_str() == "with"
1688 {
1689 return Some(value);
1690 }
1691 None
1692 })
1693 } else {
1694 None
1695 }
1696 })
1697 .and_then(ImportAnnotations::parse_dynamic)
1698 .unwrap_or_default();
1699 if !pat.has_constant_parts() {
1700 let (args, hints) = JsValue::explain_args(linked_args, 10, 2);
1701 handler.span_warn_with_code(
1702 span,
1703 &format!("import({args}) is very dynamic{hints}",),
1704 DiagnosticId::Lint(
1705 errors::failed_to_analyze::ecmascript::DYNAMIC_IMPORT.to_string(),
1706 ),
1707 );
1708 if ignore_dynamic_requests {
1709 analysis.add_code_gen(DynamicExpression::new_promise(ast_path.to_vec().into()));
1710 return Ok(());
1711 }
1712 }
1713
1714 let resolve_override = if let Some(inner_assets) = &inner_assets
1715 && let Some(req) = pat.as_constant_string()
1716 && let Some(a) = inner_assets.get(req)
1717 {
1718 Some(*a)
1719 } else {
1720 None
1721 };
1722
1723 analysis.add_reference_code_gen(
1724 EsmAsyncAssetReference::new(
1725 origin,
1726 Request::parse(pat).to_resolved().await?,
1727 issue_source(source, span),
1728 import_annotations,
1729 error_mode,
1730 import_externals,
1731 export_usage,
1732 resolve_override,
1733 ),
1734 ast_path.to_vec().into(),
1735 );
1736 return Ok(());
1737 }
1738 let (args, hints) = JsValue::explain_args(linked_args, 10, 2);
1739 handler.span_warn_with_code(
1740 span,
1741 &format!("import({args}) is not statically analyze-able{hints}",),
1742 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::DYNAMIC_IMPORT.to_string()),
1743 );
1744
1745 Ok(())
1746}
1747
1748async fn handle_well_known_function_call<'a, F, Fut>(
1749 func: WellKnownFunctionKind,
1750 new: bool,
1751 linked_args: &F,
1752 handler: &Handler,
1753 span: Span,
1754 ignore_dynamic_requests: bool,
1755 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
1756 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
1757 compile_time_info: ResolvedVc<CompileTimeInfo>,
1758 url_rewrite_behavior: Option<UrlRewriteBehavior>,
1759 source: ResolvedVc<Box<dyn Source>>,
1760 ast_path: &[AstParentKind],
1761 in_try: bool,
1762 state: &'a AnalysisState<'a>,
1763 collect_affecting_sources: bool,
1764 tracing_only: bool,
1765 attributes: &ImportAttributes,
1766) -> Result<()>
1767where
1768 F: Fn() -> Fut,
1769 Fut: Future<Output = Result<&'a Vec<JsValue>>>,
1770{
1771 fn explain_args(args: &[JsValue]) -> (String, String) {
1772 JsValue::explain_args(args, 10, 2)
1773 }
1774
1775 let error_mode = if attributes.optional {
1777 ResolveErrorMode::Ignore
1778 } else if in_try {
1779 ResolveErrorMode::Warn
1780 } else {
1781 ResolveErrorMode::Error
1782 };
1783
1784 let get_traced_project_dir = async || -> Result<FileSystemPath> {
1785 if state.allow_project_root_tracing
1795 && let Some(cwd) = compile_time_info.environment().cwd().owned().await?
1796 {
1797 Ok(cwd)
1798 } else {
1799 Ok(source.ident().await?.path.parent())
1800 }
1801 };
1802
1803 let get_issue_source =
1804 || IssueSource::from_swc_offsets(source, span.lo.to_u32(), span.hi.to_u32());
1805 if new {
1806 match func {
1807 WellKnownFunctionKind::URLConstructor => {
1808 let args = linked_args().await?;
1809 if let [
1810 url,
1811 JsValue::Member(
1812 _,
1813 box JsValue::WellKnownObject(WellKnownObjectKind::ImportMeta),
1814 box JsValue::Constant(super::analyzer::ConstantValue::Str(meta_prop)),
1815 ),
1816 ] = &args[..]
1817 && meta_prop.as_str() == "url"
1818 {
1819 let pat = js_value_to_pattern(url);
1820 if !pat.has_constant_parts() {
1821 let (args, hints) = explain_args(args);
1822 handler.span_warn_with_code(
1823 span,
1824 &format!("new URL({args}) is very dynamic{hints}",),
1825 DiagnosticId::Lint(
1826 errors::failed_to_analyze::ecmascript::NEW_URL_IMPORT_META
1827 .to_string(),
1828 ),
1829 );
1830 if ignore_dynamic_requests {
1831 return Ok(());
1832 }
1833 }
1834 let error_mode = if in_try {
1835 ResolveErrorMode::Warn
1836 } else {
1837 ResolveErrorMode::Error
1838 };
1839 analysis.add_reference_code_gen(
1840 UrlAssetReference::new(
1841 origin,
1842 Request::parse(pat).to_resolved().await?,
1843 *compile_time_info.environment().rendering().await?,
1844 issue_source(source, span),
1845 error_mode,
1846 url_rewrite_behavior.unwrap_or(UrlRewriteBehavior::Relative),
1847 ),
1848 ast_path.to_vec().into(),
1849 );
1850 }
1851 return Ok(());
1852 }
1853 WellKnownFunctionKind::WorkerConstructor
1854 | WellKnownFunctionKind::SharedWorkerConstructor => {
1855 let args = linked_args().await?;
1856 if let Some(url @ JsValue::Url(_, JsValueUrlKind::Relative)) = args.first() {
1857 let (name, is_shared) = match func {
1858 WellKnownFunctionKind::WorkerConstructor => ("Worker", false),
1859 WellKnownFunctionKind::SharedWorkerConstructor => ("SharedWorker", true),
1860 _ => unreachable!(),
1861 };
1862 let pat = js_value_to_pattern(url);
1863 if !pat.has_constant_parts() {
1864 let (args, hints) = explain_args(args);
1865 handler.span_warn_with_code(
1866 span,
1867 &format!("new {name}({args}) is very dynamic{hints}",),
1868 DiagnosticId::Lint(
1869 errors::failed_to_analyze::ecmascript::NEW_WORKER.to_string(),
1870 ),
1871 );
1872 if ignore_dynamic_requests {
1873 return Ok(());
1874 }
1875 }
1876
1877 if *compile_time_info.environment().rendering().await? == Rendering::Client {
1878 let error_mode = if in_try {
1879 ResolveErrorMode::Warn
1880 } else {
1881 ResolveErrorMode::Error
1882 };
1883 analysis.add_reference_code_gen(
1884 WorkerAssetReference::new_web_worker(
1885 origin,
1886 Request::parse(pat).to_resolved().await?,
1887 issue_source(source, span),
1888 error_mode,
1889 tracing_only,
1890 is_shared,
1891 ),
1892 ast_path.to_vec().into(),
1893 );
1894 }
1895
1896 return Ok(());
1897 }
1898 return Ok(());
1900 }
1901 WellKnownFunctionKind::NodeWorkerConstructor => {
1902 let args = linked_args().await?;
1903 if !args.is_empty() {
1904 let mut dynamic_warning: Option<&str> = None;
1908 if let Some(opts) = args.get(1) {
1909 match opts {
1910 JsValue::Object { parts, .. } => {
1911 let eval_value = parts.iter().find_map(|part| match part {
1912 ObjectPart::KeyValue(
1913 JsValue::Constant(JsConstantValue::Str(key)),
1914 value,
1915 ) if key.as_str() == "eval" => Some(value),
1916 _ => None,
1917 });
1918 if let Some(eval_value) = eval_value {
1919 match eval_value {
1920 JsValue::Constant(JsConstantValue::True) => {
1923 return Ok(());
1924 }
1925 JsValue::Constant(JsConstantValue::False) => {}
1928 _ => {
1930 dynamic_warning = Some("has a dynamic `eval` option");
1931 }
1932 }
1933 }
1934 }
1935 _ => {
1938 dynamic_warning = Some("has a dynamic options argument");
1939 }
1940 }
1941 }
1942 if let Some(warning) = dynamic_warning {
1943 let (args, hints) = explain_args(args);
1944 handler.span_warn_with_code(
1945 span,
1946 &format!("new Worker({args}) {warning}{hints}"),
1947 DiagnosticId::Lint(
1948 errors::failed_to_analyze::ecmascript::NEW_WORKER.to_string(),
1949 ),
1950 );
1951 if ignore_dynamic_requests {
1952 return Ok(());
1953 }
1954 }
1955
1956 let pat = js_value_to_pattern(&args[0]);
1957 if !pat.has_constant_parts() {
1958 let (args, hints) = explain_args(args);
1959 handler.span_warn_with_code(
1960 span,
1961 &format!("new Worker({args}) is very dynamic{hints}",),
1962 DiagnosticId::Lint(
1963 errors::failed_to_analyze::ecmascript::NEW_WORKER.to_string(),
1964 ),
1965 );
1966 if ignore_dynamic_requests {
1967 return Ok(());
1968 }
1969 }
1970
1971 let error_mode = if in_try {
1972 ResolveErrorMode::Warn
1973 } else {
1974 ResolveErrorMode::Error
1975 };
1976 let context_dir = if matches!(
1979 args.first(),
1980 Some(JsValue::Url(_, JsValueUrlKind::Relative))
1981 ) {
1982 origin.origin_path().await?.parent()
1983 } else {
1984 get_traced_project_dir().await?
1985 };
1986 analysis.add_reference_code_gen(
1987 WorkerAssetReference::new_node_worker_thread(
1988 origin,
1989 context_dir,
1990 Pattern::new(pat).to_resolved().await?,
1991 collect_affecting_sources,
1992 get_issue_source(),
1993 error_mode,
1994 tracing_only,
1995 ),
1996 ast_path.to_vec().into(),
1997 );
1998
1999 return Ok(());
2000 }
2001 let (args, hints) = explain_args(args);
2002 handler.span_warn_with_code(
2003 span,
2004 &format!("new Worker({args}) is not statically analyze-able{hints}",),
2005 DiagnosticId::Error(
2006 errors::failed_to_analyze::ecmascript::NEW_WORKER.to_string(),
2007 ),
2008 );
2009 return Ok(());
2011 }
2012 _ => {}
2013 }
2014
2015 return Ok(());
2016 }
2017
2018 match func {
2019 WellKnownFunctionKind::Import => {
2020 let args = linked_args().await?;
2021 let export_usage = match &attributes.export_names {
2022 Some(names) if names.is_empty() => ExportUsage::Evaluation,
2023 Some(names) => ExportUsage::PartialNamespaceObject(names.clone()),
2024 None => ExportUsage::All,
2025 };
2026 handle_dynamic_import_with_linked_args(
2027 ast_path,
2028 span,
2029 args,
2030 handler,
2031 origin,
2032 source,
2033 &state.inner_assets,
2034 ignore_dynamic_requests,
2035 analysis,
2036 error_mode,
2037 state.import_externals,
2038 export_usage,
2039 )
2040 .await?;
2041 }
2042 WellKnownFunctionKind::Require => {
2043 let args = linked_args().await?;
2044 if args.len() == 1 {
2045 let pat = js_value_to_pattern(&args[0]);
2046 if !pat.has_constant_parts() {
2047 let (args, hints) = explain_args(args);
2048 handler.span_warn_with_code(
2049 span,
2050 &format!("require({args}) is very dynamic{hints}",),
2051 DiagnosticId::Lint(
2052 errors::failed_to_analyze::ecmascript::REQUIRE.to_string(),
2053 ),
2054 );
2055 if ignore_dynamic_requests {
2056 analysis.add_code_gen(DynamicExpression::new(ast_path.to_vec().into()));
2057 return Ok(());
2058 }
2059 }
2060
2061 let resolve_override = if let Some(inner_assets) = &state.inner_assets
2062 && let Some(req) = pat.as_constant_string()
2063 && let Some(a) = inner_assets.get(req)
2064 {
2065 Some(*a)
2066 } else {
2067 None
2068 };
2069
2070 analysis.add_reference_code_gen(
2071 CjsRequireAssetReference::new(
2072 origin,
2073 Request::parse(pat).to_resolved().await?,
2074 issue_source(source, span),
2075 error_mode,
2076 attributes.chunking_type,
2077 resolve_override,
2078 ),
2079 ast_path.to_vec().into(),
2080 );
2081 return Ok(());
2082 }
2083 let (args, hints) = explain_args(args);
2084 handler.span_warn_with_code(
2085 span,
2086 &format!("require({args}) is not statically analyze-able{hints}",),
2087 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::REQUIRE.to_string()),
2088 )
2089 }
2090 WellKnownFunctionKind::RequireFrom(rel) => {
2091 let args = linked_args().await?;
2092 if args.len() == 1 {
2093 let pat = js_value_to_pattern(&args[0]);
2094 if !pat.has_constant_parts() {
2095 let (args, hints) = explain_args(args);
2096 handler.span_warn_with_code(
2097 span,
2098 &format!("createRequire()({args}) is very dynamic{hints}",),
2099 DiagnosticId::Lint(
2100 errors::failed_to_analyze::ecmascript::REQUIRE.to_string(),
2101 ),
2102 );
2103 if ignore_dynamic_requests {
2104 analysis.add_code_gen(DynamicExpression::new(ast_path.to_vec().into()));
2105 return Ok(());
2106 }
2107 }
2108 let origin = ResolvedVc::upcast(
2109 PlainResolveOrigin::new(
2110 origin.asset_context(),
2111 origin
2112 .origin_path()
2113 .await?
2114 .parent()
2115 .join(rel.as_str())?
2116 .join("_")?,
2117 )
2118 .to_resolved()
2119 .await?,
2120 );
2121
2122 analysis.add_reference_code_gen(
2123 CjsRequireAssetReference::new(
2124 origin,
2125 Request::parse(pat).to_resolved().await?,
2126 issue_source(source, span),
2127 error_mode,
2128 attributes.chunking_type,
2129 None,
2130 ),
2131 ast_path.to_vec().into(),
2132 );
2133 return Ok(());
2134 }
2135 let (args, hints) = explain_args(args);
2136 handler.span_warn_with_code(
2137 span,
2138 &format!("createRequire()({args}) is not statically analyze-able{hints}",),
2139 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::REQUIRE.to_string()),
2140 )
2141 }
2142 WellKnownFunctionKind::Define => {
2143 analyze_amd_define(
2144 source,
2145 analysis,
2146 origin,
2147 handler,
2148 span,
2149 ast_path,
2150 linked_args().await?,
2151 error_mode,
2152 )
2153 .await?;
2154 }
2155
2156 WellKnownFunctionKind::RequireResolve => {
2157 let args = linked_args().await?;
2158 if args.len() == 1 || args.len() == 2 {
2159 let pat = js_value_to_pattern(&args[0]);
2163 if !pat.has_constant_parts() {
2164 let (args, hints) = explain_args(args);
2165 handler.span_warn_with_code(
2166 span,
2167 &format!("require.resolve({args}) is very dynamic{hints}",),
2168 DiagnosticId::Lint(
2169 errors::failed_to_analyze::ecmascript::REQUIRE_RESOLVE.to_string(),
2170 ),
2171 );
2172 if ignore_dynamic_requests {
2173 analysis.add_code_gen(DynamicExpression::new(ast_path.to_vec().into()));
2174 return Ok(());
2175 }
2176 }
2177
2178 let resolve_override = if let Some(inner_assets) = &state.inner_assets
2179 && let Some(req) = pat.as_constant_string()
2180 && let Some(a) = inner_assets.get(req)
2181 {
2182 Some(*a)
2183 } else {
2184 None
2185 };
2186
2187 analysis.add_reference_code_gen(
2188 CjsRequireResolveAssetReference::new(
2189 origin,
2190 Request::parse(pat).to_resolved().await?,
2191 issue_source(source, span),
2192 error_mode,
2193 attributes.chunking_type,
2194 resolve_override,
2195 ),
2196 ast_path.to_vec().into(),
2197 );
2198 return Ok(());
2199 }
2200 let (args, hints) = explain_args(args);
2201 handler.span_warn_with_code(
2202 span,
2203 &format!("require.resolve({args}) is not statically analyze-able{hints}",),
2204 DiagnosticId::Error(
2205 errors::failed_to_analyze::ecmascript::REQUIRE_RESOLVE.to_string(),
2206 ),
2207 )
2208 }
2209
2210 WellKnownFunctionKind::ImportMetaGlob => {
2211 let args = linked_args().await?;
2212 let Some(options) = parse_import_meta_glob(
2213 args,
2214 handler,
2215 span,
2216 DiagnosticId::Error(
2217 errors::failed_to_analyze::ecmascript::IMPORT_META_GLOB.to_string(),
2218 ),
2219 ) else {
2220 return Ok(());
2221 };
2222
2223 analysis.add_reference_code_gen(
2224 ImportMetaGlobAssetReference::new(
2225 origin,
2226 options.patterns,
2227 options.eager,
2228 options.import,
2229 options.query,
2230 options.base,
2231 Some(issue_source(source, span)),
2232 error_mode,
2233 ),
2234 ast_path.to_vec().into(),
2235 );
2236 }
2237
2238 WellKnownFunctionKind::RequireContext => {
2239 let args = linked_args().await?;
2240 let options = match parse_require_context(args) {
2241 Ok(options) => options,
2242 Err(err) => {
2243 let (args, hints) = explain_args(args);
2244 handler.span_err_with_code(
2245 span,
2246 &format!(
2247 "require.context({args}) is not statically analyze-able: {}{hints}",
2248 PrettyPrintError(&err)
2249 ),
2250 DiagnosticId::Error(
2251 errors::failed_to_analyze::ecmascript::REQUIRE_CONTEXT.to_string(),
2252 ),
2253 );
2254 return Ok(());
2255 }
2256 };
2257
2258 analysis.add_reference_code_gen(
2259 RequireContextAssetReference::new(
2260 source,
2261 origin,
2262 options.dir,
2263 options.include_subdirs,
2264 options.filter.cell(),
2265 Some(issue_source(source, span)),
2266 error_mode,
2267 )
2268 .await?,
2269 ast_path.to_vec().into(),
2270 );
2271 }
2272
2273 WellKnownFunctionKind::FsReadMethod(name) if analysis.analyze_mode.is_tracing_assets() => {
2274 let args = linked_args().await?;
2275 if !args.is_empty() {
2276 let pat = js_value_to_pattern(&args[0]);
2277 if !pat.has_constant_parts() {
2278 let (args, hints) = explain_args(args);
2279 handler.span_warn_with_code(
2280 span,
2281 &format!("fs.{name}({args}) is very dynamic{hints}",),
2282 DiagnosticId::Lint(
2283 errors::failed_to_analyze::ecmascript::FS_METHOD.to_string(),
2284 ),
2285 );
2286 if ignore_dynamic_requests {
2287 return Ok(());
2288 }
2289 }
2290 analysis.add_reference(
2291 FileSourceReference::new(
2292 get_traced_project_dir().await?,
2293 Pattern::new(pat),
2294 collect_affecting_sources,
2295 get_issue_source(),
2296 )
2297 .to_resolved()
2298 .await?,
2299 );
2300 return Ok(());
2301 }
2302 let (args, hints) = explain_args(args);
2303 handler.span_warn_with_code(
2304 span,
2305 &format!("fs.{name}({args}) is not statically analyze-able{hints}",),
2306 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::FS_METHOD.to_string()),
2307 )
2308 }
2309 WellKnownFunctionKind::FsReadDir if analysis.analyze_mode.is_tracing_assets() => {
2310 let args = linked_args().await?;
2311 if !args.is_empty() {
2312 let pat = js_value_to_pattern(&args[0]);
2313 if !pat.has_constant_parts() {
2314 let (args, hints) = explain_args(args);
2315 handler.span_warn_with_code(
2316 span,
2317 &format!("fs.readdir({args}) is very dynamic{hints}"),
2318 DiagnosticId::Lint(
2319 errors::failed_to_analyze::ecmascript::FS_METHOD.to_string(),
2320 ),
2321 );
2322 if ignore_dynamic_requests {
2323 return Ok(());
2324 }
2325 }
2326 analysis.add_reference(
2327 DirAssetReference::new(
2328 get_traced_project_dir().await?,
2329 Pattern::new(pat),
2330 get_issue_source(),
2331 )
2332 .to_resolved()
2333 .await?,
2334 );
2335 return Ok(());
2336 }
2337 let (args, hints) = explain_args(args);
2338 handler.span_warn_with_code(
2339 span,
2340 &format!("fs.readdir({args}) is not statically analyze-able{hints}"),
2341 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::FS_METHOD.to_string()),
2342 )
2343 }
2344 WellKnownFunctionKind::PathResolve(..) if analysis.analyze_mode.is_tracing_assets() => {
2345 let parent_path = origin.origin_path().owned().await?.parent();
2346 let args = linked_args().await?;
2347
2348 let linked_func_call = state
2349 .link_value(
2350 JsValue::call_from_parts(
2351 JsValue::WellKnownFunction(WellKnownFunctionKind::PathResolve(Box::new(
2352 parent_path.path.as_str().into(),
2353 ))),
2354 args.clone(),
2355 ),
2356 ImportAttributes::empty_ref(),
2357 )
2358 .await?;
2359
2360 let pat = js_value_to_pattern(&linked_func_call);
2361 if !pat.has_constant_parts() {
2362 let (args, hints) = explain_args(args);
2363 handler.span_warn_with_code(
2364 span,
2365 &format!("path.resolve({args}) is very dynamic{hints}",),
2366 DiagnosticId::Lint(
2367 errors::failed_to_analyze::ecmascript::PATH_METHOD.to_string(),
2368 ),
2369 );
2370 if ignore_dynamic_requests {
2371 return Ok(());
2372 }
2373 }
2374 analysis.add_reference(
2375 DirAssetReference::new(
2376 get_traced_project_dir().await?,
2377 Pattern::new(pat),
2378 get_issue_source(),
2379 )
2380 .to_resolved()
2381 .await?,
2382 );
2383 return Ok(());
2384 }
2385 WellKnownFunctionKind::PathJoin if analysis.analyze_mode.is_tracing_assets() => {
2386 if source
2388 .ident()
2389 .await?
2390 .path
2391 .path
2392 .contains("node_modules/node-gyp")
2393 {
2394 return Ok(());
2395 }
2396 let args = linked_args().await?;
2397 let linked_func_call = state
2398 .link_value(
2399 JsValue::call_from_parts(
2400 JsValue::WellKnownFunction(WellKnownFunctionKind::PathJoin),
2401 args.clone(),
2402 ),
2403 ImportAttributes::empty_ref(),
2404 )
2405 .await?;
2406 let pat = js_value_to_pattern(&linked_func_call);
2407 if !pat.has_constant_parts() {
2408 let (args, hints) = explain_args(args);
2409 handler.span_warn_with_code(
2410 span,
2411 &format!("path.join({args}) is very dynamic{hints}",),
2412 DiagnosticId::Lint(
2413 errors::failed_to_analyze::ecmascript::PATH_METHOD.to_string(),
2414 ),
2415 );
2416 if ignore_dynamic_requests {
2417 return Ok(());
2418 }
2419 }
2420 analysis.add_reference(
2421 DirAssetReference::new(
2422 get_traced_project_dir().await?,
2423 Pattern::new(pat),
2424 get_issue_source(),
2425 )
2426 .to_resolved()
2427 .await?,
2428 );
2429 return Ok(());
2430 }
2431 WellKnownFunctionKind::ChildProcessSpawnMethod(name)
2432 if analysis.analyze_mode.is_tracing_assets() =>
2433 {
2434 let args = linked_args().await?;
2435
2436 if is_invoking_node_process_eval(args) {
2438 return Ok(());
2439 }
2440
2441 if !args.is_empty() {
2442 let mut show_dynamic_warning = false;
2443 let pat = js_value_to_pattern(&args[0]);
2444 if pat.is_match_ignore_dynamic("node") && args.len() >= 2 {
2445 let first_arg =
2446 JsValue::member(Box::new(args[1].clone()), Box::new(0_f64.into()));
2447 let first_arg = state
2448 .link_value(first_arg, ImportAttributes::empty_ref())
2449 .await?;
2450 let pat = js_value_to_pattern(&first_arg);
2451 let dynamic = !pat.has_constant_parts();
2452 if dynamic {
2453 show_dynamic_warning = true;
2454 }
2455 if !dynamic || !ignore_dynamic_requests {
2456 let error_mode = if in_try {
2457 ResolveErrorMode::Warn
2458 } else {
2459 ResolveErrorMode::Error
2460 };
2461 analysis.add_reference(
2462 CjsAssetReference::new(
2463 *origin,
2464 Request::parse(pat),
2465 issue_source(source, span),
2466 error_mode,
2467 )
2468 .to_resolved()
2469 .await?,
2470 );
2471 }
2472 }
2473 let dynamic = !pat.has_constant_parts();
2474 if dynamic {
2475 show_dynamic_warning = true;
2476 }
2477 if !dynamic || !ignore_dynamic_requests {
2478 analysis.add_reference(
2479 FileSourceReference::new(
2480 get_traced_project_dir().await?,
2481 Pattern::new(pat),
2482 collect_affecting_sources,
2483 IssueSource::from_swc_offsets(
2484 source,
2485 span.lo.to_u32(),
2486 span.hi.to_u32(),
2487 ),
2488 )
2489 .to_resolved()
2490 .await?,
2491 );
2492 }
2493 if show_dynamic_warning {
2494 let (args, hints) = explain_args(args);
2495 handler.span_warn_with_code(
2496 span,
2497 &format!("child_process.{name}({args}) is very dynamic{hints}",),
2498 DiagnosticId::Lint(
2499 errors::failed_to_analyze::ecmascript::CHILD_PROCESS_SPAWN.to_string(),
2500 ),
2501 );
2502 }
2503 return Ok(());
2504 }
2505 let (args, hints) = explain_args(args);
2506 handler.span_warn_with_code(
2507 span,
2508 &format!("child_process.{name}({args}) is not statically analyze-able{hints}",),
2509 DiagnosticId::Error(
2510 errors::failed_to_analyze::ecmascript::CHILD_PROCESS_SPAWN.to_string(),
2511 ),
2512 )
2513 }
2514 WellKnownFunctionKind::ChildProcessFork if analysis.analyze_mode.is_tracing_assets() => {
2515 let args = linked_args().await?;
2516 if !args.is_empty() {
2517 let first_arg = &args[0];
2518 let pat = js_value_to_pattern(first_arg);
2519 if !pat.has_constant_parts() {
2520 let (args, hints) = explain_args(args);
2521 handler.span_warn_with_code(
2522 span,
2523 &format!("child_process.fork({args}) is very dynamic{hints}",),
2524 DiagnosticId::Lint(
2525 errors::failed_to_analyze::ecmascript::CHILD_PROCESS_SPAWN.to_string(),
2526 ),
2527 );
2528 if ignore_dynamic_requests {
2529 return Ok(());
2530 }
2531 }
2532 let error_mode = if in_try {
2533 ResolveErrorMode::Warn
2534 } else {
2535 ResolveErrorMode::Error
2536 };
2537 analysis.add_reference(
2538 CjsAssetReference::new(
2539 *origin,
2540 Request::parse(pat),
2541 issue_source(source, span),
2542 error_mode,
2543 )
2544 .to_resolved()
2545 .await?,
2546 );
2547 return Ok(());
2548 }
2549 let (args, hints) = explain_args(args);
2550 handler.span_warn_with_code(
2551 span,
2552 &format!("child_process.fork({args}) is not statically analyze-able{hints}",),
2553 DiagnosticId::Error(
2554 errors::failed_to_analyze::ecmascript::CHILD_PROCESS_SPAWN.to_string(),
2555 ),
2556 )
2557 }
2558 WellKnownFunctionKind::NodePreGypFind if analysis.analyze_mode.is_tracing_assets() => {
2559 use turbopack_resolve::node_native_binding::NodePreGypConfigReference;
2560
2561 let args = linked_args().await?;
2562 if args.len() == 1 {
2563 let first_arg = &args[0];
2564 let pat = js_value_to_pattern(first_arg);
2565 if !pat.has_constant_parts() {
2566 let (args, hints) = explain_args(args);
2567 handler.span_warn_with_code(
2568 span,
2569 &format!("node-pre-gyp.find({args}) is very dynamic{hints}",),
2570 DiagnosticId::Lint(
2571 errors::failed_to_analyze::ecmascript::NODE_PRE_GYP_FIND.to_string(),
2572 ),
2573 );
2574 return Ok(());
2576 }
2577 analysis.add_reference(
2578 NodePreGypConfigReference::new(
2579 origin.origin_path().await?.parent(),
2580 Pattern::new(pat),
2581 compile_time_info.environment().compile_target(),
2582 collect_affecting_sources,
2583 )
2584 .to_resolved()
2585 .await?,
2586 );
2587 return Ok(());
2588 }
2589 let (args, hints) = explain_args(args);
2590 handler.span_warn_with_code(
2591 span,
2592 &format!(
2593 "require('@mapbox/node-pre-gyp').find({args}) is not statically \
2594 analyze-able{hints}",
2595 ),
2596 DiagnosticId::Error(
2597 errors::failed_to_analyze::ecmascript::NODE_PRE_GYP_FIND.to_string(),
2598 ),
2599 )
2600 }
2601 WellKnownFunctionKind::NodeGypBuild if analysis.analyze_mode.is_tracing_assets() => {
2602 use turbopack_resolve::node_native_binding::NodeGypBuildReference;
2603
2604 let args = linked_args().await?;
2605 if args.len() == 1 {
2606 let first_arg = state
2607 .link_value(args[0].clone(), ImportAttributes::empty_ref())
2608 .await?;
2609 if let Some(s) = first_arg.as_str() {
2610 let current_context = origin
2612 .origin_path()
2613 .await?
2614 .root()
2615 .await?
2616 .join(s.trim_start_matches("/ROOT/"))?;
2617 analysis.add_reference(
2618 NodeGypBuildReference::new(
2619 current_context,
2620 collect_affecting_sources,
2621 compile_time_info.environment().compile_target(),
2622 )
2623 .to_resolved()
2624 .await?,
2625 );
2626 return Ok(());
2627 }
2628 }
2629 let (args, hints) = explain_args(args);
2630 handler.span_warn_with_code(
2631 span,
2632 &format!(
2633 "require('node-gyp-build')({args}) is not statically analyze-able{hints}",
2634 ),
2635 DiagnosticId::Error(
2636 errors::failed_to_analyze::ecmascript::NODE_GYP_BUILD.to_string(),
2637 ),
2638 )
2639 }
2640 WellKnownFunctionKind::NodeBindings if analysis.analyze_mode.is_tracing_assets() => {
2641 use turbopack_resolve::node_native_binding::NodeBindingsReference;
2642
2643 let args = linked_args().await?;
2644 if args.len() == 1 {
2645 let first_arg = state
2646 .link_value(args[0].clone(), ImportAttributes::empty_ref())
2647 .await?;
2648 if let Some(s) = first_arg.as_str() {
2649 analysis.add_reference(
2650 NodeBindingsReference::new(
2651 origin.origin_path().owned().await?,
2652 s.into(),
2653 collect_affecting_sources,
2654 )
2655 .to_resolved()
2656 .await?,
2657 );
2658 return Ok(());
2659 }
2660 }
2661 let (args, hints) = explain_args(args);
2662 handler.span_warn_with_code(
2663 span,
2664 &format!("require('bindings')({args}) is not statically analyze-able{hints}",),
2665 DiagnosticId::Error(
2666 errors::failed_to_analyze::ecmascript::NODE_BINDINGS.to_string(),
2667 ),
2668 )
2669 }
2670 WellKnownFunctionKind::NodeExpressSet if analysis.analyze_mode.is_tracing_assets() => {
2671 let args = linked_args().await?;
2672 if args.len() == 2
2673 && let Some(s) = args.first().and_then(|arg| arg.as_str())
2674 {
2675 let pkg_or_dir = args.get(1).unwrap();
2676 let pat = js_value_to_pattern(pkg_or_dir);
2677 if !pat.has_constant_parts() {
2678 let (args, hints) = explain_args(args);
2679 handler.span_warn_with_code(
2680 span,
2681 &format!("require('express')().set({args}) is very dynamic{hints}",),
2682 DiagnosticId::Lint(
2683 errors::failed_to_analyze::ecmascript::NODE_EXPRESS.to_string(),
2684 ),
2685 );
2686 return Ok(());
2688 }
2689 match s {
2690 "views" => {
2691 if let Pattern::Constant(p) = &pat {
2692 let abs_pattern = if p.starts_with("/ROOT/") {
2693 pat
2694 } else {
2695 let linked_func_call = state
2696 .link_value(
2697 JsValue::call_from_parts(
2698 JsValue::WellKnownFunction(
2699 WellKnownFunctionKind::PathJoin,
2700 ),
2701 vec![
2702 JsValue::FreeVar(atom!("__dirname")),
2703 pkg_or_dir.clone(),
2704 ],
2705 ),
2706 ImportAttributes::empty_ref(),
2707 )
2708 .await?;
2709 js_value_to_pattern(&linked_func_call)
2710 };
2711 analysis.add_reference(
2712 DirAssetReference::new(
2713 get_traced_project_dir().await?,
2714 Pattern::new(abs_pattern),
2715 get_issue_source(),
2716 )
2717 .to_resolved()
2718 .await?,
2719 );
2720 return Ok(());
2721 }
2722 }
2723 "view engine" => {
2724 if let Some(pkg) = pkg_or_dir.as_str() {
2725 if pkg != "html" {
2726 let pat = js_value_to_pattern(pkg_or_dir);
2727 let error_mode = if in_try {
2728 ResolveErrorMode::Warn
2729 } else {
2730 ResolveErrorMode::Error
2731 };
2732 analysis.add_reference(
2733 CjsAssetReference::new(
2734 *origin,
2735 Request::parse(pat),
2736 issue_source(source, span),
2737 error_mode,
2738 )
2739 .to_resolved()
2740 .await?,
2741 );
2742 }
2743 return Ok(());
2744 }
2745 }
2746 _ => {}
2747 }
2748 }
2749 let (args, hints) = explain_args(args);
2750 handler.span_warn_with_code(
2751 span,
2752 &format!("require('express')().set({args}) is not statically analyze-able{hints}",),
2753 DiagnosticId::Error(
2754 errors::failed_to_analyze::ecmascript::NODE_EXPRESS.to_string(),
2755 ),
2756 )
2757 }
2758 WellKnownFunctionKind::NodeStrongGlobalizeSetRootDir
2759 if analysis.analyze_mode.is_tracing_assets() =>
2760 {
2761 let args = linked_args().await?;
2762 if let Some(p) = args.first().and_then(|arg| arg.as_str()) {
2763 let abs_pattern = if p.starts_with("/ROOT/") {
2764 Pattern::Constant(format!("{p}/intl").into())
2765 } else {
2766 let linked_func_call = state
2767 .link_value(
2768 JsValue::call_from_parts(
2769 JsValue::WellKnownFunction(WellKnownFunctionKind::PathJoin),
2770 vec![
2771 JsValue::FreeVar(atom!("__dirname")),
2772 p.into(),
2773 atom!("intl").into(),
2774 ],
2775 ),
2776 ImportAttributes::empty_ref(),
2777 )
2778 .await?;
2779 js_value_to_pattern(&linked_func_call)
2780 };
2781 analysis.add_reference(
2782 DirAssetReference::new(
2783 get_traced_project_dir().await?,
2784 Pattern::new(abs_pattern),
2785 get_issue_source(),
2786 )
2787 .to_resolved()
2788 .await?,
2789 );
2790 return Ok(());
2791 }
2792 let (args, hints) = explain_args(args);
2793 handler.span_warn_with_code(
2794 span,
2795 &format!(
2796 "require('strong-globalize').SetRootDir({args}) is not statically \
2797 analyze-able{hints}",
2798 ),
2799 DiagnosticId::Error(
2800 errors::failed_to_analyze::ecmascript::NODE_GYP_BUILD.to_string(),
2801 ),
2802 )
2803 }
2804 WellKnownFunctionKind::NodeResolveFrom if analysis.analyze_mode.is_tracing_assets() => {
2805 let args = linked_args().await?;
2806 if args.len() == 2 && args.get(1).and_then(|arg| arg.as_str()).is_some() {
2807 let error_mode = if in_try {
2808 ResolveErrorMode::Warn
2809 } else {
2810 ResolveErrorMode::Error
2811 };
2812 analysis.add_reference(
2813 CjsAssetReference::new(
2814 *origin,
2815 Request::parse(js_value_to_pattern(&args[1])),
2816 issue_source(source, span),
2817 error_mode,
2818 )
2819 .to_resolved()
2820 .await?,
2821 );
2822 return Ok(());
2823 }
2824 let (args, hints) = explain_args(args);
2825 handler.span_warn_with_code(
2826 span,
2827 &format!("require('resolve-from')({args}) is not statically analyze-able{hints}",),
2828 DiagnosticId::Error(
2829 errors::failed_to_analyze::ecmascript::NODE_RESOLVE_FROM.to_string(),
2830 ),
2831 )
2832 }
2833 WellKnownFunctionKind::NodeProtobufLoad if analysis.analyze_mode.is_tracing_assets() => {
2834 let args = linked_args().await?;
2835 if args.len() == 2
2836 && let Some(JsValue::Object { parts, .. }) = args.get(1)
2837 {
2838 let context_dir = get_traced_project_dir().await?;
2839 let resolved_dirs = parts
2840 .iter()
2841 .filter_map(|object_part| match object_part {
2842 ObjectPart::KeyValue(
2843 JsValue::Constant(key),
2844 JsValue::Array { items: dirs, .. },
2845 ) if key.as_str() == Some("includeDirs") => {
2846 Some(dirs.iter().filter_map(|dir| dir.as_str()))
2847 }
2848 _ => None,
2849 })
2850 .flatten()
2851 .map(|dir| {
2852 DirAssetReference::new(
2853 context_dir.clone(),
2854 Pattern::new(Pattern::Constant(dir.into())),
2855 get_issue_source(),
2856 )
2857 .to_resolved()
2858 })
2859 .try_join()
2860 .await?;
2861
2862 for resolved_dir_ref in resolved_dirs {
2863 analysis.add_reference(resolved_dir_ref);
2864 }
2865
2866 return Ok(());
2867 }
2868 let (args, hints) = explain_args(args);
2869 handler.span_warn_with_code(
2870 span,
2871 &format!(
2872 "require('@grpc/proto-loader').load({args}) is not statically \
2873 analyze-able{hints}",
2874 ),
2875 DiagnosticId::Error(
2876 errors::failed_to_analyze::ecmascript::NODE_PROTOBUF_LOADER.to_string(),
2877 ),
2878 )
2879 }
2880 kind @ (WellKnownFunctionKind::ModuleHotAccept
2881 | WellKnownFunctionKind::ModuleHotDecline) => {
2882 let is_accept = matches!(kind, WellKnownFunctionKind::ModuleHotAccept);
2883 let args = linked_args().await?;
2884 if let Some(first_arg) = args.first() {
2885 if let Some(dep_strings) = extract_hot_dep_strings(first_arg) {
2886 let mut references = Vec::new();
2887 let mut esm_references = Vec::new();
2888 for dep_str in &dep_strings {
2889 let request = Request::parse_string(dep_str.clone()).to_resolved().await?;
2890 let reference = ModuleHotReferenceAssetReference::new(
2891 *origin,
2892 *request,
2893 issue_source(source, span),
2894 error_mode,
2895 state.is_esm,
2896 )
2897 .to_resolved()
2898 .await?;
2899 analysis.add_reference(reference);
2900 references.push(reference);
2901
2902 let esm_ref = if is_accept {
2905 state
2906 .imports
2907 .references()
2908 .enumerate()
2909 .find(|(_, r)| r.module_path.to_string_lossy() == dep_str.as_str())
2910 .and_then(|(idx, _)| state.import_references.get(idx).copied())
2911 } else {
2912 None
2913 };
2914 esm_references.push(esm_ref);
2915 }
2916 analysis.add_code_gen(ModuleHotReferenceCodeGen::new(
2917 references,
2918 esm_references,
2919 ast_path.to_vec().into(),
2920 ));
2921 } else if first_arg.is_unknown() {
2922 let (args_str, hints) = explain_args(args);
2923 let method = if is_accept { "accept" } else { "decline" };
2924 let error_code = if is_accept {
2925 errors::failed_to_analyze::ecmascript::MODULE_HOT_ACCEPT
2926 } else {
2927 errors::failed_to_analyze::ecmascript::MODULE_HOT_DECLINE
2928 };
2929 handler.span_warn_with_code(
2930 span,
2931 &format!(
2932 "module.hot.{method}({args_str}) is not statically analyzable{hints}",
2933 ),
2934 DiagnosticId::Error(error_code.to_string()),
2935 )
2936 }
2937 }
2938 }
2939 _ => {}
2940 };
2941 Ok(())
2942}
2943
2944fn extract_hot_dep_strings(arg: &JsValue) -> Option<Vec<RcStr>> {
2948 if let Some(s) = arg.as_str() {
2950 return Some(vec![s.into()]);
2951 }
2952 if let JsValue::Array { items, .. } = arg {
2954 let mut deps = Vec::new();
2955 for item in items {
2956 deps.push(item.as_str()?.into());
2957 }
2958 return Some(deps);
2959 }
2960 None
2961}
2962
2963async fn handle_member(
2964 ast_path: &[AstParentKind],
2965 link_obj: impl Future<Output = Result<JsValue>> + Send + Sync,
2966 prop: JsValue,
2967 span: Span,
2968 state: &AnalysisState<'_>,
2969 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
2970) -> Result<()> {
2971 if let Some(prop) = prop.as_str() {
2972 let has_member = state.free_var_references_members.contains_key(prop).await?;
2973 let is_prop_cache = prop == "cache";
2974
2975 let obj = if has_member || is_prop_cache {
2977 Some(link_obj.await?)
2978 } else {
2979 None
2980 };
2981
2982 if has_member {
2983 let obj = obj.as_ref().unwrap();
2984 if let Some((mut name, false)) = obj.get_definable_name(Some(state.var_graph)) {
2985 name.0.push(DefinableNameSegmentRef::Name(prop));
2986 if let Some(value) = state
2987 .compile_time_info_ref
2988 .free_var_references
2989 .get(&name)
2990 .await?
2991 {
2992 handle_free_var_reference(ast_path, &value, span, state, analysis).await?;
2993 return Ok(());
2994 }
2995 }
2996 }
2997
2998 if is_prop_cache
2999 && let JsValue::WellKnownFunction(WellKnownFunctionKind::Require) =
3000 obj.as_ref().unwrap()
3001 {
3002 analysis.add_code_gen(CjsRequireCacheAccess::new(ast_path.to_vec().into()));
3003 }
3004 }
3005
3006 Ok(())
3007}
3008
3009async fn handle_typeof(
3010 ast_path: &[AstParentKind],
3011 arg: JsValue,
3012 span: Span,
3013 state: &AnalysisState<'_>,
3014 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3015) -> Result<()> {
3016 if let Some((mut name, false)) = arg.get_definable_name(Some(state.var_graph)) {
3017 name.0.push(DefinableNameSegmentRef::TypeOf);
3018 if let Some(value) = state
3019 .compile_time_info_ref
3020 .free_var_references
3021 .get(&name)
3022 .await?
3023 {
3024 handle_free_var_reference(ast_path, &value, span, state, analysis).await?;
3025 return Ok(());
3026 }
3027 }
3028
3029 Ok(())
3030}
3031
3032async fn handle_free_var(
3033 ast_path: &[AstParentKind],
3034 var: JsValue,
3035 span: Span,
3036 state: &AnalysisState<'_>,
3037 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3038) -> Result<()> {
3039 if let Some((name, _)) = var.get_definable_name(None)
3040 && let Some(value) = state
3041 .compile_time_info_ref
3042 .free_var_references
3043 .get(&name)
3044 .await?
3045 {
3046 handle_free_var_reference(ast_path, &value, span, state, analysis).await?;
3047 return Ok(());
3048 }
3049
3050 Ok(())
3051}
3052
3053async fn handle_free_var_reference(
3054 ast_path: &[AstParentKind],
3055 value: &FreeVarReference,
3056 span: Span,
3057 state: &AnalysisState<'_>,
3058 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3059) -> Result<bool> {
3060 if matches!(
3062 ast_path,
3063 [
3065 ..,
3066 AstParentKind::AssignExpr(AssignExprField::Left),
3067 AstParentKind::AssignTarget(AssignTargetField::Simple),
3068 AstParentKind::SimpleAssignTarget(SimpleAssignTargetField::Member),
3069 ] |
3070 [
3072 ..,
3073 AstParentKind::AssignExpr(AssignExprField::Left),
3074 AstParentKind::AssignTarget(AssignTargetField::Simple),
3075 AstParentKind::SimpleAssignTarget(SimpleAssignTargetField::Ident),
3076 AstParentKind::BindingIdent(BindingIdentField::Id),
3077 ]
3078 ) {
3079 return Ok(false);
3080 }
3081
3082 match value {
3083 FreeVarReference::Value(value) => {
3084 analysis.add_code_gen(ConstantValueCodeGen::new(
3085 value.clone(),
3086 ast_path.to_vec().into(),
3087 ));
3088 }
3089 FreeVarReference::Ident(value) => {
3090 analysis.add_code_gen(IdentReplacement::new(
3091 value.clone(),
3092 ast_path.to_vec().into(),
3093 ));
3094 }
3095 FreeVarReference::Member(key, value) => {
3096 analysis.add_code_gen(MemberReplacement::new(
3097 key.clone(),
3098 value.clone(),
3099 ast_path.to_vec().into(),
3100 ));
3101 }
3102 FreeVarReference::EcmaScriptModule {
3103 request,
3104 lookup_path,
3105 export,
3106 } => {
3107 let esm_reference = analysis
3108 .add_esm_reference_free_var(request.clone(), async || {
3109 Ok(EsmAssetReference::new_pure(
3114 state.module,
3115 if let Some(lookup_path) = lookup_path {
3116 ResolvedVc::upcast(
3117 PlainResolveOrigin::new(
3118 state.origin.asset_context(),
3119 lookup_path.clone(),
3120 )
3121 .to_resolved()
3122 .await?,
3123 )
3124 } else {
3125 state.origin
3126 },
3127 request.clone(),
3128 IssueSource::from_swc_offsets(
3129 state.source,
3130 span.lo.to_u32(),
3131 span.hi.to_u32(),
3132 ),
3133 Default::default(),
3134 export.clone().map(ModulePart::export),
3135 ImportUsage::TopLevel,
3138 state.import_externals,
3139 state.tree_shaking_mode,
3140 None,
3141 )
3142 .resolved_cell())
3143 })
3144 .await?;
3145
3146 analysis.add_code_gen(EsmBinding::new(
3147 esm_reference,
3148 export.clone(),
3149 ast_path.to_vec().into(),
3150 ));
3151 }
3152 FreeVarReference::InputRelative(kind) => {
3153 let source_path = (*state.source).ident().await?.path.clone();
3154 let source_path = match kind {
3155 InputRelativeConstant::DirName => source_path.parent(),
3156 InputRelativeConstant::FileName => source_path,
3157 };
3158 analysis.add_code_gen(ConstantValueCodeGen::new(
3159 as_abs_path(source_path).into(),
3160 ast_path.to_vec().into(),
3161 ));
3162 }
3163 FreeVarReference::ReportUsage {
3164 message,
3165 severity,
3166 inner,
3167 } => {
3168 state.handler.emit_with_code(
3169 &span.into(),
3170 message,
3171 DiagnosticId::Error(
3172 errors::failed_to_analyze::ecmascript::FREE_VAR_REFERENCE.to_string(),
3173 ),
3174 match severity {
3175 IssueSeverity::Bug => Level::Bug,
3176 IssueSeverity::Fatal => Level::Fatal,
3177 IssueSeverity::Error => Level::Error,
3178 IssueSeverity::Warning => Level::Warning,
3179 IssueSeverity::Hint => Level::Help,
3180 IssueSeverity::Info | IssueSeverity::Note => Level::Note,
3181 IssueSeverity::Suggestion => Level::Cancelled,
3182 },
3183 );
3184
3185 if let Some(inner) = inner {
3186 return Box::pin(handle_free_var_reference(
3187 ast_path, inner, span, state, analysis,
3188 ))
3189 .await;
3190 }
3191 }
3192 }
3193 Ok(true)
3194}
3195
3196fn issue_source(source: ResolvedVc<Box<dyn Source>>, span: Span) -> IssueSource {
3197 IssueSource::from_swc_offsets(source, span.lo.to_u32(), span.hi.to_u32())
3198}
3199
3200async fn analyze_amd_define(
3201 source: ResolvedVc<Box<dyn Source>>,
3202 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3203 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
3204 handler: &Handler,
3205 span: Span,
3206 ast_path: &[AstParentKind],
3207 args: &[JsValue],
3208 error_mode: ResolveErrorMode,
3209) -> Result<()> {
3210 match args {
3211 [JsValue::Constant(id), JsValue::Array { items: deps, .. }, _] if id.as_str().is_some() => {
3212 analyze_amd_define_with_deps(
3213 source,
3214 analysis,
3215 origin,
3216 handler,
3217 span,
3218 ast_path,
3219 id.as_str(),
3220 deps,
3221 error_mode,
3222 )
3223 .await?;
3224 }
3225 [JsValue::Array { items: deps, .. }, _] => {
3226 analyze_amd_define_with_deps(
3227 source, analysis, origin, handler, span, ast_path, None, deps, error_mode,
3228 )
3229 .await?;
3230 }
3231 [JsValue::Constant(id), JsValue::Function(..)] if id.as_str().is_some() => {
3232 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3233 vec![
3234 AmdDefineDependencyElement::Require,
3235 AmdDefineDependencyElement::Exports,
3236 AmdDefineDependencyElement::Module,
3237 ],
3238 origin,
3239 ast_path.to_vec().into(),
3240 AmdDefineFactoryType::Function,
3241 issue_source(source, span),
3242 error_mode,
3243 ));
3244 }
3245 [JsValue::Constant(id), _] if id.as_str().is_some() => {
3246 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3247 vec![
3248 AmdDefineDependencyElement::Require,
3249 AmdDefineDependencyElement::Exports,
3250 AmdDefineDependencyElement::Module,
3251 ],
3252 origin,
3253 ast_path.to_vec().into(),
3254 AmdDefineFactoryType::Unknown,
3255 issue_source(source, span),
3256 error_mode,
3257 ));
3258 }
3259 [JsValue::Function(..)] => {
3260 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3261 vec![
3262 AmdDefineDependencyElement::Require,
3263 AmdDefineDependencyElement::Exports,
3264 AmdDefineDependencyElement::Module,
3265 ],
3266 origin,
3267 ast_path.to_vec().into(),
3268 AmdDefineFactoryType::Function,
3269 issue_source(source, span),
3270 error_mode,
3271 ));
3272 }
3273 [JsValue::Object { .. }] => {
3274 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3275 vec![],
3276 origin,
3277 ast_path.to_vec().into(),
3278 AmdDefineFactoryType::Value,
3279 issue_source(source, span),
3280 error_mode,
3281 ));
3282 }
3283 [_] => {
3284 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3285 vec![
3286 AmdDefineDependencyElement::Require,
3287 AmdDefineDependencyElement::Exports,
3288 AmdDefineDependencyElement::Module,
3289 ],
3290 origin,
3291 ast_path.to_vec().into(),
3292 AmdDefineFactoryType::Unknown,
3293 issue_source(source, span),
3294 error_mode,
3295 ));
3296 }
3297 _ => {
3298 handler.span_err_with_code(
3299 span,
3300 "unsupported AMD define() form",
3301 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::AMD_DEFINE.to_string()),
3302 );
3303 }
3304 }
3305
3306 Ok(())
3307}
3308
3309async fn analyze_amd_define_with_deps(
3310 source: ResolvedVc<Box<dyn Source>>,
3311 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3312 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
3313 handler: &Handler,
3314 span: Span,
3315 ast_path: &[AstParentKind],
3316 id: Option<&str>,
3317 deps: &[JsValue],
3318 error_mode: ResolveErrorMode,
3319) -> Result<()> {
3320 let mut requests = Vec::new();
3321 for dep in deps {
3322 if let Some(dep) = dep.as_str() {
3323 match dep {
3324 "exports" => {
3325 requests.push(AmdDefineDependencyElement::Exports);
3326 }
3327 "require" => {
3328 handler.span_warn_with_code(
3329 span,
3330 "using \"require\" as dependency in an AMD define() is not yet supported",
3331 DiagnosticId::Error(
3332 errors::failed_to_analyze::ecmascript::AMD_DEFINE.to_string(),
3333 ),
3334 );
3335 requests.push(AmdDefineDependencyElement::Require);
3336 }
3337 "module" => {
3338 requests.push(AmdDefineDependencyElement::Module);
3339 }
3340 _ => {
3341 let request = Request::parse_string(dep.into()).to_resolved().await?;
3342 let reference = AmdDefineAssetReference::new(
3343 *origin,
3344 *request,
3345 issue_source(source, span),
3346 error_mode,
3347 )
3348 .to_resolved()
3349 .await?;
3350 requests.push(AmdDefineDependencyElement::Request {
3351 request,
3352 request_str: dep.to_string(),
3353 });
3354 analysis.add_reference(reference);
3355 }
3356 }
3357 } else {
3358 handler.span_err_with_code(
3359 span,
3362 "unsupported AMD define() dependency element form",
3363 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::AMD_DEFINE.to_string()),
3364 );
3365 }
3366 }
3367
3368 if id.is_some() {
3369 handler.span_warn_with_code(
3370 span,
3371 "passing an ID to AMD define() is not yet fully supported",
3372 DiagnosticId::Lint(errors::failed_to_analyze::ecmascript::AMD_DEFINE.to_string()),
3373 );
3374 }
3375
3376 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3377 requests,
3378 origin,
3379 ast_path.to_vec().into(),
3380 AmdDefineFactoryType::Function,
3381 issue_source(source, span),
3382 error_mode,
3383 ));
3384
3385 Ok(())
3386}
3387
3388pub fn as_abs_path(path: FileSystemPath) -> String {
3391 require_resolve(path)
3396}
3397
3398fn require_resolve(path: FileSystemPath) -> String {
3400 format!("/ROOT/{}", path.path.as_str())
3401}
3402
3403async fn early_value_visitor(mut v: JsValue) -> Result<(JsValue, bool)> {
3404 let modified = early_replace_builtin(&mut v);
3405 Ok((v, modified))
3406}
3407
3408async fn value_visitor(
3409 origin: Vc<Box<dyn ResolveOrigin>>,
3410 v: JsValue,
3411 compile_time_info: Vc<CompileTimeInfo>,
3412 compile_time_info_ref: &CompileTimeInfo,
3413 var_graph: &VarGraph,
3414 attributes: &ImportAttributes,
3415 allow_project_root_tracing: bool,
3416) -> Result<(JsValue, bool)> {
3417 let (mut v, modified) = value_visitor_inner(
3418 origin,
3419 v,
3420 compile_time_info,
3421 compile_time_info_ref,
3422 var_graph,
3423 attributes,
3424 allow_project_root_tracing,
3425 )
3426 .await?;
3427 v.normalize_shallow();
3428 Ok((v, modified))
3429}
3430
3431async fn value_visitor_inner(
3432 origin: Vc<Box<dyn ResolveOrigin>>,
3433 v: JsValue,
3434 compile_time_info: Vc<CompileTimeInfo>,
3435 compile_time_info_ref: &CompileTimeInfo,
3436 var_graph: &VarGraph,
3437 attributes: &ImportAttributes,
3438 allow_project_root_tracing: bool,
3439) -> Result<(JsValue, bool)> {
3440 let ImportAttributes { ignore, .. } = *attributes;
3441 if let Some((name, _)) = v.get_definable_name(Some(var_graph))
3442 && let Some(value) = compile_time_info_ref.defines.get(&name).await?
3443 {
3444 return Ok(((&*value).try_into()?, true));
3445 }
3446 let value = match v {
3447 JsValue::Call(_, call)
3448 if matches!(
3449 call.callee(),
3450 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireResolve)
3451 ) =>
3452 {
3453 let (_, args) = call.into_parts();
3454 require_resolve_visitor(origin, args).await?
3455 }
3456 JsValue::Call(_, ref call)
3457 if matches!(
3458 call.callee(),
3459 JsValue::WellKnownFunction(WellKnownFunctionKind::ImportMetaGlob)
3460 ) =>
3461 {
3462 v.into_unknown(false, rcstr!("import.meta.glob()"))
3465 }
3466 JsValue::Call(_, call)
3467 if matches!(
3468 call.callee(),
3469 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContext)
3470 ) =>
3471 {
3472 let (_, args) = call.into_parts();
3473 require_context_visitor(origin, args).await?
3474 }
3475 JsValue::Call(_, ref call)
3476 if matches!(
3477 call.callee(),
3478 JsValue::WellKnownFunction(
3479 WellKnownFunctionKind::RequireContextRequire(..)
3480 | WellKnownFunctionKind::RequireContextRequireKeys(..)
3481 | WellKnownFunctionKind::RequireContextRequireResolve(..),
3482 )
3483 ) =>
3484 {
3485 v.into_unknown(
3488 true,
3489 rcstr!("require.context() static analysis is currently limited"),
3490 )
3491 }
3492 JsValue::Call(_, ref call)
3493 if matches!(
3494 call.callee(),
3495 JsValue::WellKnownFunction(WellKnownFunctionKind::CreateRequire)
3496 ) =>
3497 {
3498 if let [
3499 JsValue::Member(
3500 _,
3501 box JsValue::WellKnownObject(WellKnownObjectKind::ImportMeta),
3502 box JsValue::Constant(super::analyzer::ConstantValue::Str(prop)),
3503 ),
3504 ] = call.args()
3505 && prop.as_str() == "url"
3506 {
3507 JsValue::WellKnownFunction(WellKnownFunctionKind::Require)
3509 } else if let [JsValue::Url(rel, JsValueUrlKind::Relative)] = call.args() {
3510 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireFrom(Box::new(
3512 rel.clone(),
3513 )))
3514 } else {
3515 v.into_unknown(true, rcstr!("createRequire() non constant"))
3516 }
3517 }
3518 JsValue::New(_, ref call)
3519 if matches!(
3520 call.callee(),
3521 JsValue::WellKnownFunction(WellKnownFunctionKind::URLConstructor)
3522 ) =>
3523 {
3524 if let [
3525 JsValue::Constant(super::analyzer::ConstantValue::Str(url)),
3526 JsValue::Member(
3527 _,
3528 box JsValue::WellKnownObject(WellKnownObjectKind::ImportMeta),
3529 box JsValue::Constant(super::analyzer::ConstantValue::Str(prop)),
3530 ),
3531 ] = call.args()
3532 {
3533 if prop.as_str() == "url" {
3534 JsValue::Url(url.clone(), JsValueUrlKind::Relative)
3535 } else {
3536 v.into_unknown(true, rcstr!("new URL() non constant"))
3537 }
3538 } else {
3539 v.into_unknown(true, rcstr!("new non constant"))
3540 }
3541 }
3542 JsValue::WellKnownFunction(
3543 WellKnownFunctionKind::PathJoin
3544 | WellKnownFunctionKind::PathResolve(_)
3545 | WellKnownFunctionKind::FsReadMethod(_),
3546 ) => {
3547 if ignore {
3548 return Ok((
3549 JsValue::unknown(v, true, rcstr!("ignored well known function")),
3550 true,
3551 ));
3552 } else {
3553 return Ok((v, false));
3554 }
3555 }
3556 JsValue::FreeVar(ref kind) => match &**kind {
3557 "__dirname" => as_abs_path(origin.origin_path().owned().await?.parent()).into(),
3558 "__filename" => as_abs_path(origin.origin_path().owned().await?).into(),
3559
3560 "require" => JsValue::unknown_if(
3561 ignore,
3562 JsValue::WellKnownFunction(WellKnownFunctionKind::Require),
3563 true,
3564 rcstr!("ignored require"),
3565 ),
3566 "import" => JsValue::unknown_if(
3567 ignore,
3568 JsValue::WellKnownFunction(WellKnownFunctionKind::Import),
3569 true,
3570 rcstr!("ignored import"),
3571 ),
3572 "Worker" => JsValue::unknown_if(
3573 ignore,
3574 JsValue::WellKnownFunction(WellKnownFunctionKind::WorkerConstructor),
3575 true,
3576 rcstr!("ignored Worker constructor"),
3577 ),
3578 "SharedWorker" => JsValue::unknown_if(
3579 ignore,
3580 JsValue::WellKnownFunction(WellKnownFunctionKind::SharedWorkerConstructor),
3581 true,
3582 rcstr!("ignored SharedWorker constructor"),
3583 ),
3584 "define" => JsValue::WellKnownFunction(WellKnownFunctionKind::Define),
3585 "URL" => JsValue::WellKnownFunction(WellKnownFunctionKind::URLConstructor),
3586 "process" => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessModule),
3587 "Object" => JsValue::WellKnownObject(WellKnownObjectKind::GlobalObject),
3588 "Buffer" => JsValue::WellKnownObject(WellKnownObjectKind::NodeBuffer),
3589 _ => return Ok((v, false)),
3590 },
3591 JsValue::Module(ref mv) => compile_time_info
3592 .environment()
3593 .node_externals()
3594 .await?
3595 .then(|| module_value_to_well_known_object(mv))
3597 .flatten()
3598 .unwrap_or_else(|| {
3599 v.into_unknown(true, rcstr!("cross module analyzing is not yet supported"))
3600 }),
3601 JsValue::Argument(..) => v.into_unknown(
3602 true,
3603 rcstr!("cross function analyzing is not yet supported"),
3604 ),
3605 _ => {
3606 let (mut v, mut modified) =
3607 replace_well_known(v, compile_time_info, allow_project_root_tracing).await?;
3608 modified = replace_builtin(&mut v) || modified;
3609 modified = modified || v.make_nested_operations_unknown();
3610 return Ok((v, modified));
3611 }
3612 };
3613 Ok((value, true))
3614}
3615
3616async fn require_resolve_visitor(
3617 origin: Vc<Box<dyn ResolveOrigin>>,
3618 args: Vec<JsValue>,
3619) -> Result<JsValue> {
3620 Ok(if args.len() == 1 {
3621 let pat = js_value_to_pattern(&args[0]);
3622 let request = Request::parse(pat.clone());
3623 let resolved = cjs_resolve_source(
3624 origin,
3625 request,
3626 CommonJsReferenceSubType::Undefined,
3627 None,
3628 ResolveErrorMode::Warn,
3629 )
3630 .to_resolved()
3631 .await?;
3632 let mut values =
3633 resolved
3634 .await?
3635 .primary_sources()
3636 .map(|source| async move {
3637 Ok(require_resolve(source.ident().await?.path.clone()).into())
3638 })
3639 .try_join()
3640 .await?;
3641
3642 match values.len() {
3643 0 => JsValue::unknown(
3644 JsValue::call_from_parts(
3645 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireResolve),
3646 args,
3647 ),
3648 false,
3649 rcstr!("unresolvable request"),
3650 ),
3651 1 => values.pop().unwrap(),
3652 _ => JsValue::alternatives(values),
3653 }
3654 } else {
3655 JsValue::unknown(
3656 JsValue::call_from_parts(
3657 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireResolve),
3658 args,
3659 ),
3660 true,
3661 rcstr!("only a single argument is supported"),
3662 )
3663 })
3664}
3665
3666async fn require_context_visitor(
3667 origin: Vc<Box<dyn ResolveOrigin>>,
3668 args: Vec<JsValue>,
3669) -> Result<JsValue> {
3670 let options = match parse_require_context(&args) {
3671 Ok(options) => options,
3672 Err(err) => {
3673 return Ok(JsValue::unknown(
3674 JsValue::call_from_parts(
3675 JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContext),
3676 args,
3677 ),
3678 true,
3679 PrettyPrintError(&err).to_string().into(),
3680 ));
3681 }
3682 };
3683
3684 let dir = origin
3685 .origin_path()
3686 .owned()
3687 .await?
3688 .parent()
3689 .join(options.dir.as_str())?;
3690
3691 let map = RequireContextMap::generate(
3692 origin,
3693 dir,
3694 options.include_subdirs,
3695 options.filter.cell(),
3696 None,
3697 ResolveErrorMode::Warn,
3698 );
3699
3700 Ok(JsValue::WellKnownFunction(
3701 WellKnownFunctionKind::RequireContextRequire(Box::new(
3702 RequireContextValue::from_context_map(map).await?,
3703 )),
3704 ))
3705}
3706
3707#[derive(Hash, Debug, Clone, Eq, PartialEq, TraceRawVcs, Encode, Decode)]
3708pub struct AstPath(
3709 #[bincode(with_serde)]
3710 #[turbo_tasks(trace_ignore)]
3711 Vec<AstParentKind>,
3712);
3713
3714impl TaskInput for AstPath {
3715 fn is_transient(&self) -> bool {
3716 false
3717 }
3718}
3719unsafe impl NonLocalValue for AstPath {}
3720
3721impl Deref for AstPath {
3722 type Target = [AstParentKind];
3723
3724 fn deref(&self) -> &Self::Target {
3725 &self.0
3726 }
3727}
3728
3729impl From<Vec<AstParentKind>> for AstPath {
3730 fn from(v: Vec<AstParentKind>) -> Self {
3731 Self(v)
3732 }
3733}
3734
3735pub static TURBOPACK_HELPER: LazyLock<Atom> = LazyLock::new(|| atom!("__turbopack-helper__"));
3736pub static TURBOPACK_HELPER_WTF8: LazyLock<Wtf8Atom> =
3737 LazyLock::new(|| atom!("__turbopack-helper__").into());
3738
3739fn is_invoking_node_process_eval(args: &[JsValue]) -> bool {
3744 if args.len() < 2 {
3745 return false;
3746 }
3747
3748 if let JsValue::Member(_, obj, constant) = &args[0] {
3749 if let (
3751 &box JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessArgv),
3752 &box JsValue::Constant(JsConstantValue::Num(ConstantNumber(num))),
3753 ) = (obj, constant)
3754 {
3755 if num.is_zero()
3757 && let JsValue::Array {
3758 total_nodes: _,
3759 items,
3760 mutable: _,
3761 } = &args[1]
3762 {
3763 if items.iter().any(|e| {
3765 if let JsValue::Constant(JsConstantValue::Str(ConstantString::Atom(arg))) = e {
3766 arg == "-e"
3767 } else {
3768 false
3769 }
3770 }) {
3771 return true;
3774 }
3775 }
3776 }
3777 }
3778
3779 false
3780}