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_info;
9pub mod external_module;
10pub mod hot_module;
11pub mod ident;
12pub mod member;
13pub mod node;
14pub mod pattern_mapping;
15pub mod raw;
16pub mod require_context;
17pub mod type_issue;
18pub mod typescript;
19pub mod unreachable;
20pub mod util;
21pub mod worker;
22
23use std::{
24 collections::BTreeMap,
25 future::Future,
26 mem::take,
27 ops::Deref,
28 sync::{Arc, LazyLock},
29};
30
31use anyhow::{Result, bail};
32use bincode::{Decode, Encode};
33use constant_condition::{ConstantConditionCodeGen, ConstantConditionValue};
34use constant_value::ConstantValueCodeGen;
35use either::Either;
36use indexmap::map::Entry;
37use num_traits::Zero;
38use once_cell::sync::Lazy;
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, SyntaxContext,
46 comments::{CommentKind, Comments},
47 errors::{DiagnosticId, HANDLER, Handler, Level},
48 pass::AstNodePath,
49 source_map::SmallPos,
50 },
51 ecma::{
52 ast::*,
53 utils::IsDirective,
54 visit::{
55 AstParentKind, AstParentNodeRef, VisitAstPath, VisitWithAstPath,
56 fields::{
57 AssignExprField, AssignTargetField, BindingIdentField, SimpleAssignTargetField,
58 },
59 },
60 },
61};
62use tokio::sync::OnceCell;
63use tracing::Instrument;
64use turbo_rcstr::{RcStr, rcstr};
65use turbo_tasks::{
66 FxIndexMap, FxIndexSet, NonLocalValue, PrettyPrintError, ReadRef, ResolvedVc, TaskInput,
67 TryJoinIterExt, Upcast, ValueToString, Vc, trace::TraceRawVcs, turbofmt,
68};
69use turbo_tasks_fs::FileSystemPath;
70use turbopack_core::{
71 chunk::ChunkingType,
72 compile_time_info::{
73 CompileTimeDefineValue, CompileTimeDefines, CompileTimeInfo, DefinableNameSegment,
74 DefinableNameSegmentRef, FreeVarReference, FreeVarReferences, FreeVarReferencesMembers,
75 InputRelativeConstant,
76 },
77 environment::Rendering,
78 issue::{IssueExt, IssueSeverity, IssueSource, StyledString, analyze::AnalyzeIssue},
79 module::{Module, ModuleSideEffects},
80 reference::{ModuleReference, ModuleReferences},
81 reference_type::{CommonJsReferenceSubType, ReferenceType},
82 resolve::{
83 ExportUsage, FindContextFileResult, ImportUsage, ModulePart, ResolveErrorMode,
84 find_context_file,
85 origin::{PlainResolveOrigin, ResolveOrigin},
86 parse::Request,
87 pattern::Pattern,
88 resolve,
89 },
90 source::Source,
91 source_map::GenerateSourceMap,
92};
93use turbopack_resolve::{
94 ecmascript::{apply_cjs_specific_options, cjs_resolve_source},
95 typescript::tsconfig,
96};
97use turbopack_swc_utils::emitter::IssueEmitter;
98use unreachable::Unreachable;
99use worker::WorkerAssetReference;
100
101pub use crate::references::esm::export::{FollowExportsResult, follow_reexports};
102use crate::{
103 AnalyzeMode, EcmascriptInputTransforms, EcmascriptModuleAsset, EcmascriptModuleAssetType,
104 EcmascriptParsable, ModuleTypeResult, SpecifiedModuleType, TreeShakingMode, TypeofWindow,
105 analyzer::{
106 ConstantNumber, ConstantString, ConstantValue as JsConstantValue, JsValue, JsValueUrlKind,
107 ObjectPart, RequireContextValue, WellKnownFunctionKind, WellKnownObjectKind,
108 builtin::{early_replace_builtin, replace_builtin},
109 graph::{
110 ConditionalKind, DeclUsage, Effect, EffectArg, EvalContext, VarGraph, create_graph,
111 },
112 imports::{ImportAnnotations, ImportAttributes, ImportMap, ImportedSymbol, Reexport},
113 linker::link,
114 parse_require_context, side_effects,
115 top_level_await::has_top_level_await,
116 well_known::replace_well_known,
117 },
118 chunk::EcmascriptExports,
119 code_gen::{CodeGen, CodeGens, IntoCodeGenReference},
120 errors,
121 export::Liveness,
122 magic_identifier,
123 parse::ParseResult,
124 references::{
125 amd::{
126 AmdDefineAssetReference, AmdDefineDependencyElement, AmdDefineFactoryType,
127 AmdDefineWithDependenciesCodeGen,
128 },
129 async_module::{AsyncModule, OptionAsyncModule},
130 cjs::{
131 CjsAssetReference, CjsRequireAssetReference, CjsRequireCacheAccess,
132 CjsRequireResolveAssetReference,
133 },
134 dynamic_expression::DynamicExpression,
135 esm::{
136 EsmAssetReference, EsmAsyncAssetReference, EsmBinding, EsmExports, EsmModuleItem,
137 ImportMetaBinding, ImportMetaRef, UrlAssetReference, UrlRewriteBehavior,
138 base::EsmAssetReferences, export::EsmExport, module_id::EsmModuleIdAssetReference,
139 },
140 exports_info::{ExportsInfoBinding, ExportsInfoRef},
141 hot_module::{ModuleHotReferenceAssetReference, ModuleHotReferenceCodeGen},
142 ident::IdentReplacement,
143 member::MemberReplacement,
144 node::PackageJsonReference,
145 raw::{DirAssetReference, FileSourceReference},
146 require_context::{RequireContextAssetReference, RequireContextMap},
147 type_issue::SpecifiedModuleTypeIssue,
148 typescript::{
149 TsConfigReference, TsReferencePathAssetReference, TsReferenceTypeAssetReference,
150 },
151 },
152 runtime_functions::{
153 TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_EXPORT_VALUE, TURBOPACK_EXPORTS, TURBOPACK_GLOBAL,
154 TURBOPACK_REQUIRE_REAL, TURBOPACK_REQUIRE_STUB, TURBOPACK_RUNTIME_FUNCTION_SHORTCUTS,
155 },
156 source_map::parse_source_map_comment,
157 tree_shake::{find_turbopack_part_id_in_asserts, part_of_module, split_module},
158 utils::{AstPathRange, js_value_to_pattern, module_value_to_well_known_object},
159 webpack::{
160 WebpackChunkAssetReference, WebpackEntryAssetReference, WebpackRuntimeAssetReference,
161 parse::{WebpackRuntime, webpack_runtime},
162 },
163};
164
165#[turbo_tasks::value(shared)]
166pub struct AnalyzeEcmascriptModuleResult {
167 references: Vec<ResolvedVc<Box<dyn ModuleReference>>>,
168
169 pub esm_references: ResolvedVc<EsmAssetReferences>,
170 pub esm_local_references: ResolvedVc<EsmAssetReferences>,
171 pub esm_reexport_references: ResolvedVc<EsmAssetReferences>,
172
173 pub code_generation: ResolvedVc<CodeGens>,
174 pub exports: ResolvedVc<EcmascriptExports>,
175 pub async_module: ResolvedVc<OptionAsyncModule>,
176 pub side_effects: ModuleSideEffects,
177 pub successful: bool,
179 pub source_map: Option<ResolvedVc<Box<dyn GenerateSourceMap>>>,
180}
181
182#[turbo_tasks::value_impl]
183impl AnalyzeEcmascriptModuleResult {
184 #[turbo_tasks::function]
185 pub async fn references(&self) -> Result<Vc<ModuleReferences>> {
186 Ok(Vc::cell(
187 self.esm_references
188 .await?
189 .iter()
190 .map(|r| ResolvedVc::upcast(*r))
191 .chain(self.references.iter().copied())
192 .collect(),
193 ))
194 }
195
196 #[turbo_tasks::function]
197 pub async fn local_references(&self) -> Result<Vc<ModuleReferences>> {
198 Ok(Vc::cell(
199 self.esm_local_references
200 .await?
201 .iter()
202 .map(|r| ResolvedVc::upcast(*r))
203 .chain(self.references.iter().copied())
204 .collect(),
205 ))
206 }
207}
208
209#[cfg(debug_assertions)]
212type CodeGenCollection = FxIndexSet<CodeGen>;
213#[cfg(not(debug_assertions))]
214type CodeGenCollection = Vec<CodeGen>;
215
216struct AnalyzeEcmascriptModuleResultBuilder {
219 analyze_mode: AnalyzeMode,
220
221 references: FxIndexSet<ResolvedVc<Box<dyn ModuleReference>>>,
222
223 esm_references: FxHashSet<usize>,
224 esm_local_references: FxHashSet<usize>,
225 esm_reexport_references: FxHashSet<usize>,
226
227 esm_references_free_var: FxIndexMap<RcStr, ResolvedVc<EsmAssetReference>>,
228 esm_references_rewritten: FxHashMap<usize, FxIndexMap<RcStr, ResolvedVc<EsmAssetReference>>>,
231
232 code_gens: CodeGenCollection,
233 exports: EcmascriptExports,
234 async_module: ResolvedVc<OptionAsyncModule>,
235 successful: bool,
236 source_map: Option<ResolvedVc<Box<dyn GenerateSourceMap>>>,
237 side_effects: ModuleSideEffects,
238 #[cfg(debug_assertions)]
239 ident: RcStr,
240}
241
242impl AnalyzeEcmascriptModuleResultBuilder {
243 fn new(analyze_mode: AnalyzeMode) -> Self {
244 Self {
245 analyze_mode,
246 references: Default::default(),
247 esm_references: Default::default(),
248 esm_local_references: Default::default(),
249 esm_reexport_references: Default::default(),
250 esm_references_rewritten: Default::default(),
251 esm_references_free_var: Default::default(),
252 code_gens: Default::default(),
253 exports: EcmascriptExports::Unknown,
254 async_module: ResolvedVc::cell(None),
255 successful: false,
256 source_map: None,
257 side_effects: ModuleSideEffects::SideEffectful,
258 #[cfg(debug_assertions)]
259 ident: Default::default(),
260 }
261 }
262
263 pub fn add_reference(&mut self, reference: ResolvedVc<impl Upcast<Box<dyn ModuleReference>>>) {
265 let r = ResolvedVc::upcast_non_strict(reference);
266 self.references.insert(r);
267 }
268
269 pub fn add_reference_code_gen<R: IntoCodeGenReference>(&mut self, reference: R, path: AstPath) {
271 let (reference, code_gen) = reference.into_code_gen_reference(path);
272 self.references.insert(reference);
273 self.add_code_gen(code_gen);
274 }
275
276 pub fn add_esm_reference(&mut self, idx: usize) {
278 self.esm_references.insert(idx);
279 self.esm_local_references.insert(idx);
280 }
281
282 pub fn add_esm_reexport_reference(&mut self, idx: usize) {
285 self.esm_references.insert(idx);
286 self.esm_reexport_references.insert(idx);
287 }
288
289 pub fn add_esm_evaluation_reference(&mut self, idx: usize) {
292 self.esm_references.insert(idx);
293 self.esm_local_references.insert(idx);
294 }
295
296 pub fn add_code_gen<C>(&mut self, code_gen: C)
298 where
299 C: Into<CodeGen>,
300 {
301 if self.analyze_mode.is_code_gen() {
302 #[cfg(debug_assertions)]
303 {
304 let (index, added) = self.code_gens.insert_full(code_gen.into());
305 debug_assert!(
306 added,
307 "Duplicate code gen added: {:?} in {}",
308 self.code_gens.get_index(index).unwrap(),
309 self.ident
310 );
311 }
312 #[cfg(not(debug_assertions))]
313 {
314 self.code_gens.push(code_gen.into());
315 }
316 }
317 }
318
319 pub fn set_source_map(&mut self, source_map: ResolvedVc<Box<dyn GenerateSourceMap>>) {
321 self.source_map = Some(source_map);
322 }
323
324 pub fn set_exports(&mut self, exports: EcmascriptExports) {
326 self.exports = exports;
327 }
328
329 pub fn set_async_module(&mut self, async_module: ResolvedVc<AsyncModule>) {
331 self.async_module = ResolvedVc::cell(Some(async_module));
332 }
333
334 pub fn set_side_effects_mode(&mut self, value: ModuleSideEffects) {
336 self.side_effects = value;
337 }
338
339 pub fn set_successful(&mut self, successful: bool) {
341 self.successful = successful;
342 }
343
344 pub fn add_esm_reference_namespace_resolved(
345 &mut self,
346 esm_reference_idx: usize,
347 export: RcStr,
348 on_insert: impl FnOnce() -> ResolvedVc<EsmAssetReference>,
349 ) -> ResolvedVc<EsmAssetReference> {
350 *self
351 .esm_references_rewritten
352 .entry(esm_reference_idx)
353 .or_default()
354 .entry(export)
355 .or_insert_with(on_insert)
356 }
357
358 pub async fn add_esm_reference_free_var(
359 &mut self,
360 request: RcStr,
361 on_insert: impl AsyncFnOnce() -> Result<ResolvedVc<EsmAssetReference>>,
362 ) -> Result<ResolvedVc<EsmAssetReference>> {
363 Ok(match self.esm_references_free_var.entry(request) {
364 Entry::Occupied(e) => *e.get(),
365 Entry::Vacant(e) => *e.insert(on_insert().await?),
366 })
367 }
368
369 pub async fn build(
371 mut self,
372 import_references: Vec<ResolvedVc<EsmAssetReference>>,
373 track_reexport_references: bool,
374 ) -> Result<Vc<AnalyzeEcmascriptModuleResult>> {
375 let mut esm_references = Vec::with_capacity(
378 self.esm_references.len()
379 + self.esm_references_free_var.len()
380 + self.esm_references_rewritten.len(),
381 );
382 esm_references.extend(self.esm_references_free_var.values());
383
384 let mut esm_local_references = track_reexport_references.then(|| {
385 let mut esm_local_references = Vec::with_capacity(
386 self.esm_local_references.len()
387 + self.esm_references_free_var.len()
388 + self.esm_references_rewritten.len(),
389 );
390 esm_local_references.extend(self.esm_references_free_var.values());
391 esm_local_references
392 });
393 let mut esm_reexport_references = track_reexport_references
394 .then(|| Vec::with_capacity(self.esm_reexport_references.len()));
395 for (i, reference) in import_references.iter().enumerate() {
396 if self.esm_references.contains(&i) {
397 esm_references.push(*reference);
398 }
399 esm_references.extend(
400 self.esm_references_rewritten
401 .get(&i)
402 .iter()
403 .flat_map(|m| m.values().copied()),
404 );
405 if let Some(esm_local_references) = &mut esm_local_references {
406 if self.esm_local_references.contains(&i) {
407 esm_local_references.push(*reference);
408 }
409 esm_local_references.extend(
410 self.esm_references_rewritten
411 .get(&i)
412 .iter()
413 .flat_map(|m| m.values().copied()),
414 );
415 }
416 if let Some(esm_reexport_references) = &mut esm_reexport_references
417 && self.esm_reexport_references.contains(&i)
418 {
419 esm_reexport_references.push(*reference);
420 }
421 }
422
423 let references: Vec<_> = self.references.into_iter().collect();
424
425 if !self.analyze_mode.is_code_gen() {
426 debug_assert!(self.code_gens.is_empty());
427 }
428
429 self.code_gens.shrink_to_fit();
430
431 #[cfg(debug_assertions)]
432 let code_generation = self.code_gens.into_iter().collect::<Vec<_>>();
433 #[cfg(not(debug_assertions))]
434 let code_generation = self.code_gens;
435
436 Ok(AnalyzeEcmascriptModuleResult::cell(
437 AnalyzeEcmascriptModuleResult {
438 references,
439 esm_references: ResolvedVc::cell(esm_references),
440 esm_local_references: ResolvedVc::cell(esm_local_references.unwrap_or_default()),
441 esm_reexport_references: ResolvedVc::cell(
442 esm_reexport_references.unwrap_or_default(),
443 ),
444 code_generation: ResolvedVc::cell(code_generation),
445 exports: self.exports.resolved_cell(),
446 async_module: self.async_module,
447 side_effects: self.side_effects,
448 successful: self.successful,
449 source_map: self.source_map,
450 },
451 ))
452 }
453}
454
455struct AnalysisState<'a> {
456 handler: &'a Handler,
457 module: ResolvedVc<EcmascriptModuleAsset>,
458 source: ResolvedVc<Box<dyn Source>>,
459 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
460 compile_time_info: ResolvedVc<CompileTimeInfo>,
461 free_var_references_members: ResolvedVc<FreeVarReferencesMembers>,
462 compile_time_info_ref: ReadRef<CompileTimeInfo>,
463 var_graph: &'a VarGraph,
464 allow_project_root_tracing: bool,
468 fun_args_values: Mutex<FxHashMap<u32, Vec<JsValue>>>,
471 var_cache: Mutex<FxHashMap<Id, JsValue>>,
472 first_import_meta: bool,
475 first_webpack_exports_info: bool,
478 tree_shaking_mode: Option<TreeShakingMode>,
479 import_externals: bool,
480 ignore_dynamic_requests: bool,
481 url_rewrite_behavior: Option<UrlRewriteBehavior>,
482 collect_affecting_sources: bool,
485 tracing_only: bool,
488 is_esm: bool,
490 import_references: &'a [ResolvedVc<EsmAssetReference>],
492 imports: &'a ImportMap,
494}
495
496impl AnalysisState<'_> {
497 async fn link_value(&self, value: JsValue, attributes: &ImportAttributes) -> Result<JsValue> {
499 Ok(link(
500 self.var_graph,
501 value,
502 &early_value_visitor,
503 &|value| {
504 value_visitor(
505 *self.origin,
506 value,
507 *self.compile_time_info,
508 &self.compile_time_info_ref,
509 self.var_graph,
510 attributes,
511 self.allow_project_root_tracing,
512 )
513 },
514 &self.fun_args_values,
515 &self.var_cache,
516 )
517 .await?
518 .0)
519 }
520}
521
522fn set_handler_and_globals<F, R>(handler: &Handler, globals: &Arc<Globals>, f: F) -> R
523where
524 F: FnOnce() -> R,
525{
526 HANDLER.set(handler, || GLOBALS.set(globals, f))
527}
528
529#[turbo_tasks::function]
531pub async fn analyze_ecmascript_module(
532 module: ResolvedVc<EcmascriptModuleAsset>,
533 part: Option<ModulePart>,
534) -> Result<Vc<AnalyzeEcmascriptModuleResult>> {
535 let span = tracing::info_span!(
536 "analyze ecmascript module",
537 name = display(module.ident().to_string().await?)
538 );
539 let result = analyze_ecmascript_module_internal(module, part)
540 .instrument(span)
541 .await;
542
543 match result {
544 Ok(result) => Ok(result),
545 Err(err) => Err(err
547 .context(turbofmt!("failed to analyze ecmascript module '{}'", module.ident()).await?)),
548 }
549}
550
551async fn analyze_ecmascript_module_internal(
552 module: ResolvedVc<EcmascriptModuleAsset>,
553 part: Option<ModulePart>,
554) -> Result<Vc<AnalyzeEcmascriptModuleResult>> {
555 let raw_module = module.await?;
556
557 let source = raw_module.source;
558 let ty = raw_module.ty;
559 let transforms = raw_module.transforms;
560 let options = raw_module.options;
561 let options = options.await?;
562 let import_externals = options.import_externals;
563 let analyze_mode = options.analyze_mode;
564
565 let origin = ResolvedVc::upcast::<Box<dyn ResolveOrigin>>(module);
566 let path = &*origin.origin_path().await?;
567 let mut analysis = AnalyzeEcmascriptModuleResultBuilder::new(analyze_mode);
568 #[cfg(debug_assertions)]
569 {
570 analysis.ident = source.ident().to_string().owned().await?;
571 }
572
573 let analyze_types = match &ty {
575 EcmascriptModuleAssetType::Typescript { analyze_types, .. } => *analyze_types,
576 EcmascriptModuleAssetType::TypescriptDeclaration => true,
577 EcmascriptModuleAssetType::Ecmascript
578 | EcmascriptModuleAssetType::EcmascriptExtensionless => false,
579 };
580
581 let parsed = if let Some(part) = part {
583 let split_data = split_module(*module);
584 part_of_module(split_data, part)
585 } else {
586 module.failsafe_parse()
587 };
588
589 let ModuleTypeResult {
590 module_type: specified_type,
591 ref referenced_package_json,
592 } = *module.determine_module_type().await?;
593
594 if let Some(package_json) = referenced_package_json {
595 let span = tracing::trace_span!("package.json reference");
596 async {
597 analysis.add_reference(
598 PackageJsonReference::new(package_json.clone())
599 .to_resolved()
600 .await?,
601 );
602 anyhow::Ok(())
603 }
604 .instrument(span)
605 .await?;
606 }
607
608 if analyze_types {
609 let span = tracing::trace_span!("tsconfig reference");
610 async {
611 match &*find_context_file(path.parent(), tsconfig(), false).await? {
612 FindContextFileResult::Found(tsconfig, _) => {
613 analysis.add_reference(
614 TsConfigReference::new(*origin, tsconfig.clone())
615 .to_resolved()
616 .await?,
617 );
618 }
619 FindContextFileResult::NotFound(_) => {}
620 };
621 anyhow::Ok(())
622 }
623 .instrument(span)
624 .await?;
625 }
626
627 let parsed = if !analyze_mode.is_code_gen() {
628 parsed.final_read_hint().await?
630 } else {
631 parsed.await?
632 };
633
634 let ParseResult::Ok {
635 program,
636 globals,
637 eval_context,
638 comments,
639 source_map,
640 source_mapping_url,
641 } = &*parsed
642 else {
643 return analysis.build(Default::default(), false).await;
644 };
645
646 let has_side_effect_free_directive = match program {
647 Program::Module(module) => Either::Left(
648 module
649 .body
650 .iter()
651 .take_while(|i| match i {
652 ModuleItem::Stmt(stmt) => stmt.directive_continue(),
653 ModuleItem::ModuleDecl(_) => false,
654 })
655 .filter_map(|i| i.as_stmt()),
656 ),
657 Program::Script(script) => Either::Right(
658 script
659 .body
660 .iter()
661 .take_while(|stmt| stmt.directive_continue()),
662 ),
663 }
664 .any(|f| match f {
665 Stmt::Expr(ExprStmt { expr, .. }) => match &**expr {
666 Expr::Lit(Lit::Str(Str { value, .. })) => value == "use turbopack no side effects",
667 _ => false,
668 },
669 _ => false,
670 });
671 analysis.set_side_effects_mode(if has_side_effect_free_directive {
672 ModuleSideEffects::SideEffectFree
673 } else if options.infer_module_side_effects {
674 GLOBALS.set(globals, || {
676 side_effects::compute_module_evaluation_side_effects(
677 program,
678 comments,
679 eval_context.unresolved_mark,
680 )
681 })
682 } else {
683 ModuleSideEffects::SideEffectful
685 });
686
687 let is_esm = eval_context.is_esm(specified_type);
688 let compile_time_info = compile_time_info_for_module_options(
689 *raw_module.compile_time_info,
690 is_esm,
691 options.enable_typeof_window_inlining,
692 )
693 .to_resolved()
694 .await?;
695
696 let pos = program.span().lo;
697 if analyze_types {
698 let span = tracing::trace_span!("type references");
699 async {
700 if let Some(comments) = comments.get_leading(pos) {
701 for comment in comments.iter() {
702 if let CommentKind::Line = comment.kind {
703 static REFERENCE_PATH: LazyLock<Regex> = LazyLock::new(|| {
704 Regex::new(r#"^/\s*<reference\s*path\s*=\s*["'](.+)["']\s*/>\s*$"#)
705 .unwrap()
706 });
707 static REFERENCE_TYPES: LazyLock<Regex> = LazyLock::new(|| {
708 Regex::new(r#"^/\s*<reference\s*types\s*=\s*["'](.+)["']\s*/>\s*$"#)
709 .unwrap()
710 });
711 let text = &comment.text;
712 if let Some(m) = REFERENCE_PATH.captures(text) {
713 let path = &m[1];
714 analysis.add_reference(
715 TsReferencePathAssetReference::new(*origin, path.into())
716 .to_resolved()
717 .await?,
718 );
719 } else if let Some(m) = REFERENCE_TYPES.captures(text) {
720 let types = &m[1];
721 analysis.add_reference(
722 TsReferenceTypeAssetReference::new(*origin, types.into())
723 .to_resolved()
724 .await?,
725 );
726 }
727 }
728 }
729 }
730 anyhow::Ok(())
731 }
732 .instrument(span)
733 .await?;
734 }
735
736 if options.extract_source_map {
737 let span = tracing::trace_span!("source map reference");
738 async {
739 if let Some((source_map, reference)) = parse_source_map_comment(
740 source,
741 source_mapping_url.as_deref(),
742 &*origin.origin_path().await?,
743 )
744 .await?
745 {
746 analysis.set_source_map(source_map);
747 if let Some(reference) = reference {
748 analysis.add_reference(reference);
749 }
750 }
751 anyhow::Ok(())
752 }
753 .instrument(span)
754 .await?;
755 }
756
757 let (emitter, collector) = IssueEmitter::new(source, source_map.clone(), None);
758 let handler = Handler::with_emitter(true, false, Box::new(emitter));
759
760 let mut var_graph = {
761 let _span = tracing::trace_span!("analyze variable values").entered();
762 set_handler_and_globals(&handler, globals, || {
763 create_graph(program, eval_context, analyze_mode)
764 })
765 };
766
767 let mut import_usage =
768 FxHashMap::with_capacity_and_hasher(var_graph.import_usages.len(), Default::default());
769 for (reference, usage) in &var_graph.import_usages {
770 if let DeclUsage::Bindings(ids) = usage {
772 let mut visited = ids.clone();
774 let mut stack = ids.iter().collect::<Vec<_>>();
775 let mut has_global_usage = false;
776 while let Some(id) = stack.pop() {
777 match var_graph.decl_usages.get(id) {
778 Some(DeclUsage::SideEffects) => {
779 has_global_usage = true;
780 break;
781 }
782 Some(DeclUsage::Bindings(callers)) => {
783 for caller in callers {
784 if visited.insert(caller.clone()) {
785 stack.push(caller);
786 }
787 }
788 }
789 _ => {}
790 }
791 }
792
793 import_usage.insert(
795 *reference,
796 if has_global_usage {
797 ImportUsage::TopLevel
798 } else {
799 ImportUsage::Exports(
800 var_graph
801 .exports
802 .iter()
803 .filter(|(_, id)| visited.contains(*id))
804 .map(|(exported, _)| exported.as_str().into())
805 .collect(),
806 )
807 },
808 );
809 }
810 }
811
812 let span = tracing::trace_span!("esm import references");
813 let import_references = async {
814 let mut import_references = Vec::with_capacity(eval_context.imports.references().len());
815 for (i, r) in eval_context.imports.references().enumerate() {
816 let mut should_add_evaluation = false;
817 let reference = EsmAssetReference::new(
818 module,
819 ResolvedVc::upcast(module),
820 RcStr::from(&*r.module_path.to_string_lossy()),
821 r.issue_source
822 .unwrap_or_else(|| IssueSource::from_source_only(source)),
823 r.annotations.as_ref().map(|a| (**a).clone()),
824 match &r.imported_symbol {
825 ImportedSymbol::ModuleEvaluation => {
826 should_add_evaluation = true;
827 Some(ModulePart::evaluation())
828 }
829 ImportedSymbol::Symbol(name) => Some(ModulePart::export((&**name).into())),
830 ImportedSymbol::PartEvaluation(part_id) | ImportedSymbol::Part(part_id) => {
831 if !matches!(
832 options.tree_shaking_mode,
833 Some(TreeShakingMode::ModuleFragments)
834 ) {
835 bail!(
836 "Internal imports only exist in reexports only mode when \
837 importing {:?} from {}",
838 r.imported_symbol,
839 r.module_path.to_string_lossy()
840 );
841 }
842 if matches!(&r.imported_symbol, ImportedSymbol::PartEvaluation(_)) {
843 should_add_evaluation = true;
844 }
845 Some(ModulePart::internal(*part_id))
846 }
847 ImportedSymbol::Exports => matches!(
848 options.tree_shaking_mode,
849 Some(TreeShakingMode::ModuleFragments)
850 )
851 .then(ModulePart::exports),
852 },
853 import_usage.get(&i).cloned().unwrap_or_default(),
854 import_externals,
855 options.tree_shaking_mode,
856 )
857 .resolved_cell();
858
859 import_references.push(reference);
860 if should_add_evaluation {
861 analysis.add_esm_evaluation_reference(i);
862 }
863 }
864 anyhow::Ok(import_references)
865 }
866 .instrument(span)
867 .await?;
868
869 let span = tracing::trace_span!("exports");
870 let (webpack_runtime, webpack_entry, webpack_chunks) = async {
871 let (webpack_runtime, webpack_entry, webpack_chunks, mut esm_exports) =
872 set_handler_and_globals(&handler, globals, || {
873 let mut visitor = ModuleReferencesVisitor::new(
875 eval_context,
876 &import_references,
877 &mut analysis,
878 analyze_mode,
879 &var_graph,
880 );
881 program.visit_with_ast_path(&mut visitor, &mut Default::default());
884 (
885 visitor.webpack_runtime,
886 visitor.webpack_entry,
887 visitor.webpack_chunks,
888 visitor.esm_exports,
889 )
890 });
891
892 let mut esm_star_exports: Vec<ResolvedVc<Box<dyn ModuleReference>>> = vec![];
893 for (i, reexport) in eval_context.imports.reexports() {
894 let reference = import_references[i];
895 match reexport {
896 Reexport::Star => {
897 esm_star_exports.push(ResolvedVc::upcast(reference));
898 analysis.add_esm_reexport_reference(i);
899 }
900 Reexport::Namespace { exported: n } => {
901 esm_exports.insert(
902 n.as_str().into(),
903 EsmExport::ImportedNamespace(ResolvedVc::upcast(reference)),
904 );
905 analysis.add_esm_reexport_reference(i);
906 }
907 Reexport::Named { imported, exported } => {
908 esm_exports.insert(
909 exported.as_str().into(),
910 EsmExport::ImportedBinding(
911 ResolvedVc::upcast(reference),
912 imported.to_string().into(),
913 false,
914 ),
915 );
916 analysis.add_esm_reexport_reference(i);
917 }
918 }
919 }
920
921 let exports = if !esm_exports.is_empty() || !esm_star_exports.is_empty() {
922 if specified_type == SpecifiedModuleType::CommonJs {
923 SpecifiedModuleTypeIssue {
924 source: IssueSource::from_source_only(source),
926 specified_type,
927 }
928 .resolved_cell()
929 .emit();
930 }
931
932 let esm_exports = EsmExports {
933 exports: esm_exports,
934 star_exports: esm_star_exports,
935 }
936 .cell();
937
938 EcmascriptExports::EsmExports(esm_exports.to_resolved().await?)
939 } else if specified_type == SpecifiedModuleType::EcmaScript {
940 match detect_dynamic_export(program) {
941 DetectedDynamicExportType::CommonJs => {
942 SpecifiedModuleTypeIssue {
943 source: IssueSource::from_source_only(source),
946 specified_type,
947 }
948 .resolved_cell()
949 .emit();
950
951 EcmascriptExports::EsmExports(
952 EsmExports {
953 exports: Default::default(),
954 star_exports: Default::default(),
955 }
956 .resolved_cell(),
957 )
958 }
959 DetectedDynamicExportType::Namespace => EcmascriptExports::DynamicNamespace,
960 DetectedDynamicExportType::Value => EcmascriptExports::Value,
961 DetectedDynamicExportType::UsingModuleDeclarations
962 | DetectedDynamicExportType::None => EcmascriptExports::EsmExports(
963 EsmExports {
964 exports: Default::default(),
965 star_exports: Default::default(),
966 }
967 .resolved_cell(),
968 ),
969 }
970 } else {
971 match detect_dynamic_export(program) {
972 DetectedDynamicExportType::CommonJs => EcmascriptExports::CommonJs,
973 DetectedDynamicExportType::Namespace => EcmascriptExports::DynamicNamespace,
974 DetectedDynamicExportType::Value => EcmascriptExports::Value,
975 DetectedDynamicExportType::UsingModuleDeclarations => {
976 EcmascriptExports::EsmExports(
977 EsmExports {
978 exports: Default::default(),
979 star_exports: Default::default(),
980 }
981 .resolved_cell(),
982 )
983 }
984 DetectedDynamicExportType::None => EcmascriptExports::EmptyCommonJs,
985 }
986 };
987 analysis.set_exports(exports);
988 anyhow::Ok((webpack_runtime, webpack_entry, webpack_chunks))
989 }
990 .instrument(span)
991 .await?;
992
993 let mut ignore_effect_span = None;
994 if let Some((request, webpack_runtime_span)) = webpack_runtime {
996 let span = tracing::trace_span!("webpack runtime reference");
997 async {
998 let request = Request::parse(request.into()).to_resolved().await?;
999 let runtime = resolve_as_webpack_runtime(*origin, *request, *transforms)
1000 .to_resolved()
1001 .await?;
1002
1003 if let WebpackRuntime::Webpack5 { .. } = &*runtime.await? {
1004 ignore_effect_span = Some(webpack_runtime_span);
1005 analysis.add_reference(
1006 WebpackRuntimeAssetReference {
1007 origin,
1008 request,
1009 runtime,
1010 transforms,
1011 }
1012 .resolved_cell(),
1013 );
1014
1015 if webpack_entry {
1016 analysis.add_reference(
1017 WebpackEntryAssetReference {
1018 source,
1019 runtime,
1020 transforms,
1021 }
1022 .resolved_cell(),
1023 );
1024 }
1025
1026 for chunk in webpack_chunks {
1027 analysis.add_reference(
1028 WebpackChunkAssetReference {
1029 chunk_id: chunk,
1030 runtime,
1031 transforms,
1032 }
1033 .resolved_cell(),
1034 );
1035 }
1036 }
1037 anyhow::Ok(())
1038 }
1039 .instrument(span)
1040 .await?;
1041 }
1042 let span = tracing::trace_span!("async module handling");
1044 async {
1045 let top_level_await_span =
1046 set_handler_and_globals(&handler, globals, || has_top_level_await(program));
1047 let has_top_level_await = top_level_await_span.is_some();
1048
1049 if eval_context.is_esm(specified_type) {
1050 let async_module = AsyncModule {
1051 has_top_level_await,
1052 import_externals,
1053 }
1054 .resolved_cell();
1055 analysis.set_async_module(async_module);
1056 } else if let Some(span) = top_level_await_span {
1057 AnalyzeIssue::new(
1058 IssueSeverity::Error,
1059 source.ident(),
1060 Vc::cell(rcstr!("unexpected top level await")),
1061 StyledString::Text(rcstr!("top level await is only supported in ESM modules."))
1062 .cell(),
1063 None,
1064 Some(issue_source(source, span)),
1065 )
1066 .to_resolved()
1067 .await?
1068 .emit();
1069 }
1070 anyhow::Ok(())
1071 }
1072 .instrument(span)
1073 .await?;
1074
1075 let span = tracing::trace_span!("effects processing");
1076 async {
1077 let effects = take(&mut var_graph.effects);
1078 let compile_time_info_ref = compile_time_info.await?;
1079
1080 let mut analysis_state = AnalysisState {
1081 handler: &handler,
1082 module,
1083 source,
1084 origin,
1085 compile_time_info,
1086 free_var_references_members: compile_time_info_ref
1087 .free_var_references
1088 .members()
1089 .to_resolved()
1090 .await?,
1091 compile_time_info_ref,
1092 var_graph: &var_graph,
1093 allow_project_root_tracing: !source.ident().path().await?.is_in_node_modules(),
1094 fun_args_values: Default::default(),
1095 var_cache: Default::default(),
1096 first_import_meta: true,
1097 first_webpack_exports_info: true,
1098 tree_shaking_mode: options.tree_shaking_mode,
1099 import_externals: options.import_externals,
1100 ignore_dynamic_requests: options.ignore_dynamic_requests,
1101 url_rewrite_behavior: options.url_rewrite_behavior,
1102 collect_affecting_sources: options.analyze_mode.is_tracing_assets(),
1103 tracing_only: !options.analyze_mode.is_code_gen(),
1104 is_esm,
1105 import_references: &import_references,
1106 imports: &eval_context.imports,
1107 };
1108
1109 enum Action {
1110 Effect(Effect),
1111 LeaveScope(u32),
1112 }
1113
1114 let mut queue_stack = Mutex::new(Vec::new());
1119 queue_stack
1120 .get_mut()
1121 .extend(effects.into_iter().map(Action::Effect).rev());
1122
1123 while let Some(action) = queue_stack.get_mut().pop() {
1124 let effect = match action {
1125 Action::LeaveScope(func_ident) => {
1126 analysis_state.fun_args_values.get_mut().remove(&func_ident);
1127 continue;
1128 }
1129 Action::Effect(effect) => effect,
1130 };
1131
1132 let add_effects = |effects: Vec<Effect>| {
1133 queue_stack
1134 .lock()
1135 .extend(effects.into_iter().map(Action::Effect).rev())
1136 };
1137
1138 match effect {
1139 Effect::Unreachable { start_ast_path } => {
1140 debug_assert!(
1141 analyze_mode.is_code_gen(),
1142 "unexpected Effect::Unreachable in tracing mode"
1143 );
1144
1145 analysis
1146 .add_code_gen(Unreachable::new(AstPathRange::StartAfter(start_ast_path)));
1147 }
1148 Effect::Conditional {
1149 condition,
1150 kind,
1151 ast_path: condition_ast_path,
1152 span: _,
1153 } => {
1154 let condition_has_side_effects = condition.has_side_effects();
1157
1158 let condition = analysis_state
1159 .link_value(*condition, ImportAttributes::empty_ref())
1160 .await?;
1161
1162 macro_rules! inactive {
1163 ($block:ident) => {
1164 if analyze_mode.is_code_gen() {
1165 analysis.add_code_gen(Unreachable::new($block.range.clone()));
1166 }
1167 };
1168 }
1169 macro_rules! condition {
1170 ($expr:expr) => {
1171 if analyze_mode.is_code_gen() && !condition_has_side_effects {
1172 analysis.add_code_gen(ConstantConditionCodeGen::new(
1173 $expr,
1174 condition_ast_path.to_vec().into(),
1175 ));
1176 }
1177 };
1178 }
1179 macro_rules! active {
1180 ($block:ident) => {
1181 queue_stack
1182 .get_mut()
1183 .extend($block.effects.into_iter().map(Action::Effect).rev())
1184 };
1185 }
1186 match *kind {
1187 ConditionalKind::If { then } => match condition.is_truthy() {
1188 Some(true) => {
1189 condition!(ConstantConditionValue::Truthy);
1190 active!(then);
1191 }
1192 Some(false) => {
1193 condition!(ConstantConditionValue::Falsy);
1194 inactive!(then);
1195 }
1196 None => {
1197 active!(then);
1198 }
1199 },
1200 ConditionalKind::Else { r#else } => match condition.is_truthy() {
1201 Some(true) => {
1202 condition!(ConstantConditionValue::Truthy);
1203 inactive!(r#else);
1204 }
1205 Some(false) => {
1206 condition!(ConstantConditionValue::Falsy);
1207 active!(r#else);
1208 }
1209 None => {
1210 active!(r#else);
1211 }
1212 },
1213 ConditionalKind::IfElse { then, r#else }
1214 | ConditionalKind::Ternary { then, r#else } => {
1215 match condition.is_truthy() {
1216 Some(true) => {
1217 condition!(ConstantConditionValue::Truthy);
1218 active!(then);
1219 inactive!(r#else);
1220 }
1221 Some(false) => {
1222 condition!(ConstantConditionValue::Falsy);
1223 active!(r#else);
1224 inactive!(then);
1225 }
1226 None => {
1227 active!(then);
1228 active!(r#else);
1229 }
1230 }
1231 }
1232 ConditionalKind::IfElseMultiple { then, r#else } => {
1233 match condition.is_truthy() {
1234 Some(true) => {
1235 condition!(ConstantConditionValue::Truthy);
1236 for then in then {
1237 active!(then);
1238 }
1239 for r#else in r#else {
1240 inactive!(r#else);
1241 }
1242 }
1243 Some(false) => {
1244 condition!(ConstantConditionValue::Falsy);
1245 for then in then {
1246 inactive!(then);
1247 }
1248 for r#else in r#else {
1249 active!(r#else);
1250 }
1251 }
1252 None => {
1253 for then in then {
1254 active!(then);
1255 }
1256 for r#else in r#else {
1257 active!(r#else);
1258 }
1259 }
1260 }
1261 }
1262 ConditionalKind::And { expr } => match condition.is_truthy() {
1263 Some(true) => {
1264 condition!(ConstantConditionValue::Truthy);
1265 active!(expr);
1266 }
1267 Some(false) => {
1268 inactive!(expr);
1270 }
1271 None => {
1272 active!(expr);
1273 }
1274 },
1275 ConditionalKind::Or { expr } => match condition.is_truthy() {
1276 Some(true) => {
1277 inactive!(expr);
1279 }
1280 Some(false) => {
1281 condition!(ConstantConditionValue::Falsy);
1282 active!(expr);
1283 }
1284 None => {
1285 active!(expr);
1286 }
1287 },
1288 ConditionalKind::NullishCoalescing { expr } => {
1289 match condition.is_nullish() {
1290 Some(true) => {
1291 condition!(ConstantConditionValue::Nullish);
1292 active!(expr);
1293 }
1294 Some(false) => {
1295 inactive!(expr);
1296 }
1297 None => {
1298 active!(expr);
1299 }
1300 }
1301 }
1302 ConditionalKind::Labeled { body } => {
1303 active!(body);
1304 }
1305 }
1306 }
1307 Effect::Call {
1308 func,
1309 args,
1310 ast_path,
1311 span,
1312 in_try,
1313 new,
1314 } => {
1315 if let Some(ignored) = &ignore_effect_span
1316 && *ignored == span
1317 {
1318 continue;
1319 }
1320
1321 let func = analysis_state
1322 .link_value(*func, eval_context.imports.get_attributes(span))
1323 .await?;
1324
1325 handle_call(
1326 &ast_path,
1327 span,
1328 func,
1329 args,
1330 &analysis_state,
1331 &add_effects,
1332 &mut analysis,
1333 in_try,
1334 new,
1335 eval_context.imports.get_attributes(span),
1336 )
1337 .await?;
1338 }
1339 Effect::DynamicImport {
1340 args,
1341 ast_path,
1342 span,
1343 in_try,
1344 export_usage,
1345 } => {
1346 if let Some(ignored) = &ignore_effect_span
1347 && *ignored == span
1348 {
1349 continue;
1350 }
1351
1352 handle_dynamic_import(
1353 &ast_path,
1354 span,
1355 args,
1356 &analysis_state,
1357 &add_effects,
1358 &mut analysis,
1359 in_try,
1360 eval_context.imports.get_attributes(span),
1361 export_usage,
1362 )
1363 .await?;
1364 }
1365 Effect::MemberCall {
1366 obj,
1367 prop,
1368 mut args,
1369 ast_path,
1370 span,
1371 in_try,
1372 new,
1373 } => {
1374 if let Some(ignored) = &ignore_effect_span
1375 && *ignored == span
1376 {
1377 continue;
1378 }
1379
1380 let func = analysis_state
1381 .link_value(
1382 JsValue::member(obj.clone(), prop),
1383 eval_context.imports.get_attributes(span),
1384 )
1385 .await?;
1386
1387 if !new
1388 && matches!(
1389 func,
1390 JsValue::WellKnownFunction(
1391 WellKnownFunctionKind::ArrayFilter
1392 | WellKnownFunctionKind::ArrayForEach
1393 | WellKnownFunctionKind::ArrayMap
1394 )
1395 )
1396 && let [EffectArg::Closure(value, block)] = &mut args[..]
1397 && let JsValue::Array {
1398 items: ref mut values,
1399 mutable,
1400 ..
1401 } = analysis_state
1402 .link_value(*obj, eval_context.imports.get_attributes(span))
1403 .await?
1404 {
1405 *value = analysis_state
1406 .link_value(take(value), ImportAttributes::empty_ref())
1407 .await?;
1408 if let JsValue::Function(_, func_ident, _) = value {
1409 let mut closure_arg = JsValue::alternatives(take(values));
1410 if mutable {
1411 closure_arg.add_unknown_mutations(true);
1412 }
1413 analysis_state
1414 .fun_args_values
1415 .get_mut()
1416 .insert(*func_ident, vec![closure_arg]);
1417 queue_stack.get_mut().push(Action::LeaveScope(*func_ident));
1418 queue_stack.get_mut().extend(
1419 take(&mut block.effects)
1420 .into_iter()
1421 .map(Action::Effect)
1422 .rev(),
1423 );
1424 continue;
1425 }
1426 }
1427
1428 handle_call(
1429 &ast_path,
1430 span,
1431 func,
1432 args,
1433 &analysis_state,
1434 &add_effects,
1435 &mut analysis,
1436 in_try,
1437 new,
1438 eval_context.imports.get_attributes(span),
1439 )
1440 .await?;
1441 }
1442 Effect::FreeVar {
1443 var,
1444 ast_path,
1445 span,
1446 } => {
1447 debug_assert!(
1448 analyze_mode.is_code_gen(),
1449 "unexpected Effect::FreeVar in tracing mode"
1450 );
1451
1452 if options.enable_exports_info_inlining && var == "__webpack_exports_info__" {
1453 if analysis_state.first_webpack_exports_info {
1454 analysis_state.first_webpack_exports_info = false;
1455 analysis.add_code_gen(ExportsInfoBinding::new());
1456 }
1457 analysis.add_code_gen(ExportsInfoRef::new(ast_path.into()));
1458 continue;
1459 }
1460
1461 if !analysis_state
1463 .link_value(
1464 JsValue::FreeVar(var.clone()),
1465 eval_context.imports.get_attributes(span),
1466 )
1467 .await?
1468 .is_unknown()
1469 {
1470 handle_free_var(
1472 &ast_path,
1473 JsValue::FreeVar(var),
1474 span,
1475 &analysis_state,
1476 &mut analysis,
1477 )
1478 .await?;
1479 }
1480 }
1481 Effect::Member {
1482 obj,
1483 prop,
1484 ast_path,
1485 span,
1486 } => {
1487 debug_assert!(
1488 analyze_mode.is_code_gen(),
1489 "unexpected Effect::Member in tracing mode"
1490 );
1491
1492 let obj = analysis_state.link_value(*obj, ImportAttributes::empty_ref());
1494
1495 let prop = analysis_state
1496 .link_value(*prop, ImportAttributes::empty_ref())
1497 .await?;
1498
1499 handle_member(&ast_path, obj, prop, span, &analysis_state, &mut analysis)
1500 .await?;
1501 }
1502 Effect::ImportedBinding {
1503 esm_reference_index,
1504 export,
1505 ast_path,
1506 span: _,
1507 } => {
1508 let Some(r) = import_references.get(esm_reference_index) else {
1509 continue;
1510 };
1511
1512 if let Some("__turbopack_module_id__") = export.as_deref() {
1513 let chunking_type = r
1514 .await?
1515 .annotations
1516 .as_ref()
1517 .and_then(|a| a.chunking_type())
1518 .map_or_else(
1519 || {
1520 Some(ChunkingType::Parallel {
1521 inherit_async: true,
1522 hoisted: true,
1523 })
1524 },
1525 |c| c.as_chunking_type(true, true),
1526 );
1527 analysis.add_reference_code_gen(
1528 EsmModuleIdAssetReference::new(*r, chunking_type),
1529 ast_path.into(),
1530 )
1531 } else {
1532 if matches!(
1533 options.tree_shaking_mode,
1534 Some(TreeShakingMode::ReexportsOnly)
1535 ) {
1536 let original_reference = r.await?;
1539 if original_reference.export_name.is_none()
1540 && export.is_some()
1541 && let Some(export) = export
1542 {
1543 let named_reference = analysis
1546 .add_esm_reference_namespace_resolved(
1547 esm_reference_index,
1548 export.clone(),
1549 || {
1550 EsmAssetReference::new(
1551 original_reference.module,
1552 original_reference.origin,
1553 original_reference.request.clone(),
1554 original_reference.issue_source,
1555 original_reference.annotations.clone(),
1556 Some(ModulePart::export(export.clone())),
1557 original_reference.import_usage.clone(),
1562 original_reference.import_externals,
1563 original_reference.tree_shaking_mode,
1564 )
1565 .resolved_cell()
1566 },
1567 );
1568 analysis.add_code_gen(EsmBinding::new_keep_this(
1569 named_reference,
1570 Some(export),
1571 ast_path.into(),
1572 ));
1573 continue;
1574 }
1575 }
1576
1577 analysis.add_esm_reference(esm_reference_index);
1578 analysis.add_code_gen(EsmBinding::new(*r, export, ast_path.into()));
1579 }
1580 }
1581 Effect::TypeOf {
1582 arg,
1583 ast_path,
1584 span,
1585 } => {
1586 debug_assert!(
1587 analyze_mode.is_code_gen(),
1588 "unexpected Effect::TypeOf in tracing mode"
1589 );
1590 let arg = analysis_state
1591 .link_value(*arg, ImportAttributes::empty_ref())
1592 .await?;
1593 handle_typeof(&ast_path, arg, span, &analysis_state, &mut analysis).await?;
1594 }
1595 Effect::ImportMeta { ast_path, span: _ } => {
1596 debug_assert!(
1597 analyze_mode.is_code_gen(),
1598 "unexpected Effect::ImportMeta in tracing mode"
1599 );
1600 if analysis_state.first_import_meta {
1601 analysis_state.first_import_meta = false;
1602 analysis.add_code_gen(ImportMetaBinding::new(
1603 source.ident().path().owned().await?,
1604 analysis_state
1605 .compile_time_info_ref
1606 .hot_module_replacement_enabled,
1607 ));
1608 }
1609
1610 analysis.add_code_gen(ImportMetaRef::new(ast_path.into()));
1611 }
1612 }
1613 }
1614 anyhow::Ok(())
1615 }
1616 .instrument(span)
1617 .await?;
1618
1619 analysis.set_successful(true);
1620
1621 collector.emit(false).await?;
1622
1623 analysis
1624 .build(
1625 import_references,
1626 matches!(
1627 options.tree_shaking_mode,
1628 Some(TreeShakingMode::ReexportsOnly)
1629 ),
1630 )
1631 .await
1632}
1633
1634#[turbo_tasks::function]
1635async fn compile_time_info_for_module_options(
1636 compile_time_info: Vc<CompileTimeInfo>,
1637 is_esm: bool,
1638 enable_typeof_window_inlining: Option<TypeofWindow>,
1639) -> Result<Vc<CompileTimeInfo>> {
1640 let compile_time_info = compile_time_info.await?;
1641 let free_var_references = compile_time_info.free_var_references;
1642 let defines = compile_time_info.defines;
1643
1644 let mut free_var_references = free_var_references.owned().await?;
1645 let mut defines = defines.owned().await?;
1646
1647 let (typeof_exports, typeof_module, typeof_this, require) = if is_esm {
1648 (
1649 rcstr!("undefined"),
1650 rcstr!("undefined"),
1651 rcstr!("undefined"),
1652 TURBOPACK_REQUIRE_STUB,
1653 )
1654 } else {
1655 (
1656 rcstr!("object"),
1657 rcstr!("object"),
1658 rcstr!("object"),
1659 TURBOPACK_REQUIRE_REAL,
1660 )
1661 };
1662 let typeofs: [(&[RcStr], RcStr); _] = [
1663 (&[rcstr!("import"), rcstr!("meta")], rcstr!("object")),
1664 (&[rcstr!("exports")], typeof_exports),
1665 (&[rcstr!("module")], typeof_module),
1666 (&[rcstr!("this")], typeof_this),
1667 (&[rcstr!("require")], rcstr!("function")),
1668 (&[rcstr!("__dirname")], rcstr!("string")),
1669 (&[rcstr!("__filename")], rcstr!("string")),
1670 (&[rcstr!("global")], rcstr!("object")),
1671 ];
1672 for (typeof_path, typeof_value) in typeofs {
1673 let name = typeof_path
1674 .iter()
1675 .map(|s| DefinableNameSegment::Name(s.clone()))
1676 .chain(std::iter::once(DefinableNameSegment::TypeOf))
1677 .collect::<Vec<_>>();
1678 free_var_references
1679 .entry(name.clone())
1680 .or_insert(typeof_value.clone().into());
1681 defines.entry(name).or_insert(typeof_value.into());
1682 }
1683
1684 free_var_references
1685 .entry(vec![DefinableNameSegment::Name(rcstr!("require"))])
1686 .or_insert(require.into());
1687 free_var_references
1688 .entry(vec![DefinableNameSegment::Name(rcstr!("__dirname"))])
1689 .or_insert(FreeVarReference::InputRelative(
1690 InputRelativeConstant::DirName,
1691 ));
1692 free_var_references
1693 .entry(vec![DefinableNameSegment::Name(rcstr!("__filename"))])
1694 .or_insert(FreeVarReference::InputRelative(
1695 InputRelativeConstant::FileName,
1696 ));
1697
1698 free_var_references
1701 .entry(vec![DefinableNameSegment::Name(rcstr!("global"))])
1702 .or_insert(TURBOPACK_GLOBAL.into());
1703
1704 free_var_references.extend(TURBOPACK_RUNTIME_FUNCTION_SHORTCUTS.into_iter().map(
1705 |(name, shortcut)| {
1706 (
1707 vec![DefinableNameSegment::Name(name.into())],
1708 shortcut.into(),
1709 )
1710 },
1711 ));
1712 free_var_references
1717 .entry(vec![DefinableNameSegment::Name(rcstr!("this"))])
1718 .or_insert(if is_esm {
1719 FreeVarReference::Value(CompileTimeDefineValue::Undefined)
1720 } else {
1721 TURBOPACK_EXPORTS.into()
1724 });
1725
1726 if let Some(enable_typeof_window_inlining) = enable_typeof_window_inlining {
1727 let value = match enable_typeof_window_inlining {
1728 TypeofWindow::Object => rcstr!("object"),
1729 TypeofWindow::Undefined => rcstr!("undefined"),
1730 };
1731 let window = rcstr!("window");
1732 free_var_references
1733 .entry(vec![
1734 DefinableNameSegment::Name(window.clone()),
1735 DefinableNameSegment::TypeOf,
1736 ])
1737 .or_insert(value.clone().into());
1738 defines
1739 .entry(vec![
1740 DefinableNameSegment::Name(window),
1741 DefinableNameSegment::TypeOf,
1742 ])
1743 .or_insert(value.into());
1744 }
1745
1746 Ok(CompileTimeInfo {
1747 environment: compile_time_info.environment,
1748 defines: CompileTimeDefines(defines).resolved_cell(),
1749 free_var_references: FreeVarReferences(free_var_references).resolved_cell(),
1750 hot_module_replacement_enabled: compile_time_info.hot_module_replacement_enabled,
1751 }
1752 .cell())
1753}
1754
1755async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
1756 ast_path: &[AstParentKind],
1757 span: Span,
1758 func: JsValue,
1759 args: Vec<EffectArg>,
1760 state: &AnalysisState<'_>,
1761 add_effects: &G,
1762 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
1763 in_try: bool,
1764 new: bool,
1765 attributes: &ImportAttributes,
1766) -> Result<()> {
1767 let &AnalysisState {
1768 handler,
1769 origin,
1770 source,
1771 compile_time_info,
1772 ignore_dynamic_requests,
1773 url_rewrite_behavior,
1774 collect_affecting_sources,
1775 tracing_only,
1776 allow_project_root_tracing: _,
1777 ..
1778 } = state;
1779
1780 let unlinked_args = args
1784 .into_iter()
1785 .map(|effect_arg| match effect_arg {
1786 EffectArg::Value(value) => value,
1787 EffectArg::Closure(value, block) => {
1788 add_effects(block.effects);
1789 value
1790 }
1791 EffectArg::Spread => JsValue::unknown_empty(true, "spread is not supported yet"),
1792 })
1793 .collect::<Vec<_>>();
1794
1795 let linked_args_cache = OnceCell::new();
1797
1798 let linked_args = || async {
1800 linked_args_cache
1801 .get_or_try_init(|| async {
1802 unlinked_args
1803 .iter()
1804 .cloned()
1805 .map(|arg| state.link_value(arg, ImportAttributes::empty_ref()))
1806 .try_join()
1807 .await
1808 })
1809 .await
1810 };
1811
1812 match func {
1813 JsValue::Alternatives {
1814 total_nodes: _,
1815 values,
1816 logical_property: _,
1817 } => {
1818 for alt in values {
1819 if let JsValue::WellKnownFunction(wkf) = alt {
1820 handle_well_known_function_call(
1821 wkf,
1822 new,
1823 &linked_args,
1824 handler,
1825 span,
1826 ignore_dynamic_requests,
1827 analysis,
1828 origin,
1829 compile_time_info,
1830 url_rewrite_behavior,
1831 source,
1832 ast_path,
1833 in_try,
1834 state,
1835 collect_affecting_sources,
1836 tracing_only,
1837 attributes,
1838 )
1839 .await?;
1840 }
1841 }
1842 }
1843 JsValue::WellKnownFunction(wkf) => {
1844 handle_well_known_function_call(
1845 wkf,
1846 new,
1847 &linked_args,
1848 handler,
1849 span,
1850 ignore_dynamic_requests,
1851 analysis,
1852 origin,
1853 compile_time_info,
1854 url_rewrite_behavior,
1855 source,
1856 ast_path,
1857 in_try,
1858 state,
1859 collect_affecting_sources,
1860 tracing_only,
1861 attributes,
1862 )
1863 .await?;
1864 }
1865 _ => {}
1866 }
1867
1868 Ok(())
1869}
1870
1871async fn handle_dynamic_import<G: Fn(Vec<Effect>) + Send + Sync>(
1872 ast_path: &[AstParentKind],
1873 span: Span,
1874 args: Vec<EffectArg>,
1875 state: &AnalysisState<'_>,
1876 add_effects: &G,
1877 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
1878 in_try: bool,
1879 attributes: &ImportAttributes,
1880 export_usage: ExportUsage,
1881) -> Result<()> {
1882 if attributes.ignore {
1885 return Ok(());
1886 }
1887
1888 let &AnalysisState {
1889 handler,
1890 origin,
1891 source,
1892 ignore_dynamic_requests,
1893 ..
1894 } = state;
1895
1896 let error_mode = if attributes.optional {
1897 ResolveErrorMode::Ignore
1898 } else if in_try {
1899 ResolveErrorMode::Warn
1900 } else {
1901 ResolveErrorMode::Error
1902 };
1903
1904 let unlinked_args: Vec<JsValue> = args
1906 .into_iter()
1907 .map(|effect_arg| match effect_arg {
1908 EffectArg::Value(value) => value,
1909 EffectArg::Closure(value, block) => {
1910 add_effects(block.effects);
1911 value
1912 }
1913 EffectArg::Spread => JsValue::unknown_empty(true, "spread is not supported yet"),
1914 })
1915 .collect();
1916
1917 let linked_args = unlinked_args
1918 .iter()
1919 .cloned()
1920 .map(|arg| state.link_value(arg, ImportAttributes::empty_ref()))
1921 .try_join()
1922 .await?;
1923
1924 handle_dynamic_import_with_linked_args(
1925 ast_path,
1926 span,
1927 &linked_args,
1928 handler,
1929 origin,
1930 source,
1931 ignore_dynamic_requests,
1932 analysis,
1933 error_mode,
1934 state.import_externals,
1935 export_usage,
1936 )
1937 .await
1938}
1939
1940async fn handle_dynamic_import_with_linked_args(
1941 ast_path: &[AstParentKind],
1942 span: Span,
1943 linked_args: &[JsValue],
1944 handler: &Handler,
1945 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
1946 source: ResolvedVc<Box<dyn Source>>,
1947 ignore_dynamic_requests: bool,
1948 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
1949 error_mode: ResolveErrorMode,
1950 import_externals: bool,
1951 export_usage: ExportUsage,
1952) -> Result<()> {
1953 if linked_args.len() == 1 || linked_args.len() == 2 {
1954 let pat = js_value_to_pattern(&linked_args[0]);
1955 let options = linked_args.get(1);
1956 let import_annotations = options
1957 .and_then(|options| {
1958 if let JsValue::Object { parts, .. } = options {
1959 parts.iter().find_map(|part| {
1960 if let ObjectPart::KeyValue(
1961 JsValue::Constant(super::analyzer::ConstantValue::Str(key)),
1962 value,
1963 ) = part
1964 && key.as_str() == "with"
1965 {
1966 return Some(value);
1967 }
1968 None
1969 })
1970 } else {
1971 None
1972 }
1973 })
1974 .and_then(ImportAnnotations::parse_dynamic)
1975 .unwrap_or_default();
1976 if !pat.has_constant_parts() {
1977 let (args, hints) = JsValue::explain_args(linked_args, 10, 2);
1978 handler.span_warn_with_code(
1979 span,
1980 &format!("import({args}) is very dynamic{hints}",),
1981 DiagnosticId::Lint(
1982 errors::failed_to_analyze::ecmascript::DYNAMIC_IMPORT.to_string(),
1983 ),
1984 );
1985 if ignore_dynamic_requests {
1986 analysis.add_code_gen(DynamicExpression::new_promise(ast_path.to_vec().into()));
1987 return Ok(());
1988 }
1989 }
1990 analysis.add_reference_code_gen(
1991 EsmAsyncAssetReference::new(
1992 origin,
1993 Request::parse(pat).to_resolved().await?,
1994 issue_source(source, span),
1995 import_annotations,
1996 error_mode,
1997 import_externals,
1998 export_usage,
1999 ),
2000 ast_path.to_vec().into(),
2001 );
2002 return Ok(());
2003 }
2004 let (args, hints) = JsValue::explain_args(linked_args, 10, 2);
2005 handler.span_warn_with_code(
2006 span,
2007 &format!("import({args}) is not statically analyze-able{hints}",),
2008 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::DYNAMIC_IMPORT.to_string()),
2009 );
2010
2011 Ok(())
2012}
2013
2014async fn handle_well_known_function_call<'a, F, Fut>(
2015 func: WellKnownFunctionKind,
2016 new: bool,
2017 linked_args: &F,
2018 handler: &Handler,
2019 span: Span,
2020 ignore_dynamic_requests: bool,
2021 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
2022 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
2023 compile_time_info: ResolvedVc<CompileTimeInfo>,
2024 url_rewrite_behavior: Option<UrlRewriteBehavior>,
2025 source: ResolvedVc<Box<dyn Source>>,
2026 ast_path: &[AstParentKind],
2027 in_try: bool,
2028 state: &'a AnalysisState<'a>,
2029 collect_affecting_sources: bool,
2030 tracing_only: bool,
2031 attributes: &ImportAttributes,
2032) -> Result<()>
2033where
2034 F: Fn() -> Fut,
2035 Fut: Future<Output = Result<&'a Vec<JsValue>>>,
2036{
2037 fn explain_args(args: &[JsValue]) -> (String, String) {
2038 JsValue::explain_args(args, 10, 2)
2039 }
2040
2041 let error_mode = if attributes.optional {
2043 ResolveErrorMode::Ignore
2044 } else if in_try {
2045 ResolveErrorMode::Warn
2046 } else {
2047 ResolveErrorMode::Error
2048 };
2049
2050 let get_traced_project_dir = async || -> Result<FileSystemPath> {
2051 if state.allow_project_root_tracing
2061 && let Some(cwd) = compile_time_info.environment().cwd().owned().await?
2062 {
2063 Ok(cwd)
2064 } else {
2065 Ok(source.ident().path().await?.parent())
2066 }
2067 };
2068
2069 let get_issue_source =
2070 || IssueSource::from_swc_offsets(source, span.lo.to_u32(), span.hi.to_u32());
2071 if new {
2072 match func {
2073 WellKnownFunctionKind::URLConstructor => {
2074 let args = linked_args().await?;
2075 if let [
2076 url,
2077 JsValue::Member(
2078 _,
2079 box JsValue::WellKnownObject(WellKnownObjectKind::ImportMeta),
2080 box JsValue::Constant(super::analyzer::ConstantValue::Str(meta_prop)),
2081 ),
2082 ] = &args[..]
2083 && meta_prop.as_str() == "url"
2084 {
2085 let pat = js_value_to_pattern(url);
2086 if !pat.has_constant_parts() {
2087 let (args, hints) = explain_args(args);
2088 handler.span_warn_with_code(
2089 span,
2090 &format!("new URL({args}) is very dynamic{hints}",),
2091 DiagnosticId::Lint(
2092 errors::failed_to_analyze::ecmascript::NEW_URL_IMPORT_META
2093 .to_string(),
2094 ),
2095 );
2096 if ignore_dynamic_requests {
2097 return Ok(());
2098 }
2099 }
2100 let error_mode = if in_try {
2101 ResolveErrorMode::Warn
2102 } else {
2103 ResolveErrorMode::Error
2104 };
2105 analysis.add_reference_code_gen(
2106 UrlAssetReference::new(
2107 origin,
2108 Request::parse(pat).to_resolved().await?,
2109 *compile_time_info.environment().rendering().await?,
2110 issue_source(source, span),
2111 error_mode,
2112 url_rewrite_behavior.unwrap_or(UrlRewriteBehavior::Relative),
2113 ),
2114 ast_path.to_vec().into(),
2115 );
2116 }
2117 return Ok(());
2118 }
2119 WellKnownFunctionKind::WorkerConstructor
2120 | WellKnownFunctionKind::SharedWorkerConstructor => {
2121 let args = linked_args().await?;
2122 if let Some(url @ JsValue::Url(_, JsValueUrlKind::Relative)) = args.first() {
2123 let (name, is_shared) = match func {
2124 WellKnownFunctionKind::WorkerConstructor => ("Worker", false),
2125 WellKnownFunctionKind::SharedWorkerConstructor => ("SharedWorker", true),
2126 _ => unreachable!(),
2127 };
2128 let pat = js_value_to_pattern(url);
2129 if !pat.has_constant_parts() {
2130 let (args, hints) = explain_args(args);
2131 handler.span_warn_with_code(
2132 span,
2133 &format!("new {name}({args}) is very dynamic{hints}",),
2134 DiagnosticId::Lint(
2135 errors::failed_to_analyze::ecmascript::NEW_WORKER.to_string(),
2136 ),
2137 );
2138 if ignore_dynamic_requests {
2139 return Ok(());
2140 }
2141 }
2142
2143 if *compile_time_info.environment().rendering().await? == Rendering::Client {
2144 let error_mode = if in_try {
2145 ResolveErrorMode::Warn
2146 } else {
2147 ResolveErrorMode::Error
2148 };
2149 analysis.add_reference_code_gen(
2150 WorkerAssetReference::new_web_worker(
2151 origin,
2152 Request::parse(pat).to_resolved().await?,
2153 issue_source(source, span),
2154 error_mode,
2155 tracing_only,
2156 is_shared,
2157 ),
2158 ast_path.to_vec().into(),
2159 );
2160 }
2161
2162 return Ok(());
2163 }
2164 return Ok(());
2166 }
2167 WellKnownFunctionKind::NodeWorkerConstructor => {
2168 let args = linked_args().await?;
2169 if !args.is_empty() {
2170 let mut dynamic_warning: Option<&str> = None;
2174 if let Some(opts) = args.get(1) {
2175 match opts {
2176 JsValue::Object { parts, .. } => {
2177 let eval_value = parts.iter().find_map(|part| match part {
2178 ObjectPart::KeyValue(
2179 JsValue::Constant(JsConstantValue::Str(key)),
2180 value,
2181 ) if key.as_str() == "eval" => Some(value),
2182 _ => None,
2183 });
2184 if let Some(eval_value) = eval_value {
2185 match eval_value {
2186 JsValue::Constant(JsConstantValue::True) => {
2189 return Ok(());
2190 }
2191 JsValue::Constant(JsConstantValue::False) => {}
2194 _ => {
2196 dynamic_warning = Some("has a dynamic `eval` option");
2197 }
2198 }
2199 }
2200 }
2201 _ => {
2204 dynamic_warning = Some("has a dynamic options argument");
2205 }
2206 }
2207 }
2208 if let Some(warning) = dynamic_warning {
2209 let (args, hints) = explain_args(args);
2210 handler.span_warn_with_code(
2211 span,
2212 &format!("new Worker({args}) {warning}{hints}"),
2213 DiagnosticId::Lint(
2214 errors::failed_to_analyze::ecmascript::NEW_WORKER.to_string(),
2215 ),
2216 );
2217 if ignore_dynamic_requests {
2218 return Ok(());
2219 }
2220 }
2221
2222 let pat = js_value_to_pattern(&args[0]);
2223 if !pat.has_constant_parts() {
2224 let (args, hints) = explain_args(args);
2225 handler.span_warn_with_code(
2226 span,
2227 &format!("new Worker({args}) is very dynamic{hints}",),
2228 DiagnosticId::Lint(
2229 errors::failed_to_analyze::ecmascript::NEW_WORKER.to_string(),
2230 ),
2231 );
2232 if ignore_dynamic_requests {
2233 return Ok(());
2234 }
2235 }
2236
2237 let error_mode = if in_try {
2238 ResolveErrorMode::Warn
2239 } else {
2240 ResolveErrorMode::Error
2241 };
2242 analysis.add_reference_code_gen(
2243 WorkerAssetReference::new_node_worker_thread(
2244 origin,
2245 get_traced_project_dir().await?,
2247 Pattern::new(pat).to_resolved().await?,
2248 collect_affecting_sources,
2249 get_issue_source(),
2250 error_mode,
2251 tracing_only,
2252 ),
2253 ast_path.to_vec().into(),
2254 );
2255
2256 return Ok(());
2257 }
2258 let (args, hints) = explain_args(args);
2259 handler.span_warn_with_code(
2260 span,
2261 &format!("new Worker({args}) is not statically analyze-able{hints}",),
2262 DiagnosticId::Error(
2263 errors::failed_to_analyze::ecmascript::NEW_WORKER.to_string(),
2264 ),
2265 );
2266 return Ok(());
2268 }
2269 _ => {}
2270 }
2271
2272 return Ok(());
2273 }
2274
2275 match func {
2276 WellKnownFunctionKind::Import => {
2277 let args = linked_args().await?;
2278 let export_usage = match &attributes.export_names {
2279 Some(names) if names.is_empty() => ExportUsage::Evaluation,
2280 Some(names) => ExportUsage::PartialNamespaceObject(names.clone()),
2281 None => ExportUsage::All,
2282 };
2283 handle_dynamic_import_with_linked_args(
2284 ast_path,
2285 span,
2286 args,
2287 handler,
2288 origin,
2289 source,
2290 ignore_dynamic_requests,
2291 analysis,
2292 error_mode,
2293 state.import_externals,
2294 export_usage,
2295 )
2296 .await?;
2297 }
2298 WellKnownFunctionKind::Require => {
2299 let args = linked_args().await?;
2300 if args.len() == 1 {
2301 let pat = js_value_to_pattern(&args[0]);
2302 if !pat.has_constant_parts() {
2303 let (args, hints) = explain_args(args);
2304 handler.span_warn_with_code(
2305 span,
2306 &format!("require({args}) is very dynamic{hints}",),
2307 DiagnosticId::Lint(
2308 errors::failed_to_analyze::ecmascript::REQUIRE.to_string(),
2309 ),
2310 );
2311 if ignore_dynamic_requests {
2312 analysis.add_code_gen(DynamicExpression::new(ast_path.to_vec().into()));
2313 return Ok(());
2314 }
2315 }
2316 analysis.add_reference_code_gen(
2317 CjsRequireAssetReference::new(
2318 origin,
2319 Request::parse(pat).to_resolved().await?,
2320 issue_source(source, span),
2321 error_mode,
2322 attributes.chunking_type,
2323 ),
2324 ast_path.to_vec().into(),
2325 );
2326 return Ok(());
2327 }
2328 let (args, hints) = explain_args(args);
2329 handler.span_warn_with_code(
2330 span,
2331 &format!("require({args}) is not statically analyze-able{hints}",),
2332 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::REQUIRE.to_string()),
2333 )
2334 }
2335 WellKnownFunctionKind::Define => {
2336 analyze_amd_define(
2337 source,
2338 analysis,
2339 origin,
2340 handler,
2341 span,
2342 ast_path,
2343 linked_args().await?,
2344 error_mode,
2345 )
2346 .await?;
2347 }
2348
2349 WellKnownFunctionKind::RequireResolve => {
2350 let args = linked_args().await?;
2351 if args.len() == 1 || args.len() == 2 {
2352 let pat = js_value_to_pattern(&args[0]);
2356 if !pat.has_constant_parts() {
2357 let (args, hints) = explain_args(args);
2358 handler.span_warn_with_code(
2359 span,
2360 &format!("require.resolve({args}) is very dynamic{hints}",),
2361 DiagnosticId::Lint(
2362 errors::failed_to_analyze::ecmascript::REQUIRE_RESOLVE.to_string(),
2363 ),
2364 );
2365 if ignore_dynamic_requests {
2366 analysis.add_code_gen(DynamicExpression::new(ast_path.to_vec().into()));
2367 return Ok(());
2368 }
2369 }
2370 analysis.add_reference_code_gen(
2371 CjsRequireResolveAssetReference::new(
2372 origin,
2373 Request::parse(pat).to_resolved().await?,
2374 issue_source(source, span),
2375 error_mode,
2376 attributes.chunking_type,
2377 ),
2378 ast_path.to_vec().into(),
2379 );
2380 return Ok(());
2381 }
2382 let (args, hints) = explain_args(args);
2383 handler.span_warn_with_code(
2384 span,
2385 &format!("require.resolve({args}) is not statically analyze-able{hints}",),
2386 DiagnosticId::Error(
2387 errors::failed_to_analyze::ecmascript::REQUIRE_RESOLVE.to_string(),
2388 ),
2389 )
2390 }
2391
2392 WellKnownFunctionKind::RequireContext => {
2393 let args = linked_args().await?;
2394 let options = match parse_require_context(args) {
2395 Ok(options) => options,
2396 Err(err) => {
2397 let (args, hints) = explain_args(args);
2398 handler.span_err_with_code(
2399 span,
2400 &format!(
2401 "require.context({args}) is not statically analyze-able: {}{hints}",
2402 PrettyPrintError(&err)
2403 ),
2404 DiagnosticId::Error(
2405 errors::failed_to_analyze::ecmascript::REQUIRE_CONTEXT.to_string(),
2406 ),
2407 );
2408 return Ok(());
2409 }
2410 };
2411
2412 analysis.add_reference_code_gen(
2413 RequireContextAssetReference::new(
2414 source,
2415 origin,
2416 options.dir,
2417 options.include_subdirs,
2418 options.filter.cell(),
2419 Some(issue_source(source, span)),
2420 error_mode,
2421 )
2422 .await?,
2423 ast_path.to_vec().into(),
2424 );
2425 }
2426
2427 WellKnownFunctionKind::FsReadMethod(name) if analysis.analyze_mode.is_tracing_assets() => {
2428 let args = linked_args().await?;
2429 if !args.is_empty() {
2430 let pat = js_value_to_pattern(&args[0]);
2431 if !pat.has_constant_parts() {
2432 let (args, hints) = explain_args(args);
2433 handler.span_warn_with_code(
2434 span,
2435 &format!("fs.{name}({args}) is very dynamic{hints}",),
2436 DiagnosticId::Lint(
2437 errors::failed_to_analyze::ecmascript::FS_METHOD.to_string(),
2438 ),
2439 );
2440 if ignore_dynamic_requests {
2441 return Ok(());
2442 }
2443 }
2444 analysis.add_reference(
2445 FileSourceReference::new(
2446 get_traced_project_dir().await?,
2447 Pattern::new(pat),
2448 collect_affecting_sources,
2449 get_issue_source(),
2450 )
2451 .to_resolved()
2452 .await?,
2453 );
2454 return Ok(());
2455 }
2456 let (args, hints) = explain_args(args);
2457 handler.span_warn_with_code(
2458 span,
2459 &format!("fs.{name}({args}) is not statically analyze-able{hints}",),
2460 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::FS_METHOD.to_string()),
2461 )
2462 }
2463
2464 WellKnownFunctionKind::PathResolve(..) if analysis.analyze_mode.is_tracing_assets() => {
2465 let parent_path = origin.origin_path().owned().await?.parent();
2466 let args = linked_args().await?;
2467
2468 let linked_func_call = state
2469 .link_value(
2470 JsValue::call(
2471 Box::new(JsValue::WellKnownFunction(
2472 WellKnownFunctionKind::PathResolve(Box::new(
2473 parent_path.path.as_str().into(),
2474 )),
2475 )),
2476 args.clone(),
2477 ),
2478 ImportAttributes::empty_ref(),
2479 )
2480 .await?;
2481
2482 let pat = js_value_to_pattern(&linked_func_call);
2483 if !pat.has_constant_parts() {
2484 let (args, hints) = explain_args(args);
2485 handler.span_warn_with_code(
2486 span,
2487 &format!("path.resolve({args}) is very dynamic{hints}",),
2488 DiagnosticId::Lint(
2489 errors::failed_to_analyze::ecmascript::PATH_METHOD.to_string(),
2490 ),
2491 );
2492 if ignore_dynamic_requests {
2493 return Ok(());
2494 }
2495 }
2496 analysis.add_reference(
2497 DirAssetReference::new(
2498 get_traced_project_dir().await?,
2499 Pattern::new(pat),
2500 get_issue_source(),
2501 )
2502 .to_resolved()
2503 .await?,
2504 );
2505 return Ok(());
2506 }
2507
2508 WellKnownFunctionKind::PathJoin if analysis.analyze_mode.is_tracing_assets() => {
2509 let context_path = source.ident().path().await?;
2510 if context_path.path.contains("node_modules/node-gyp") {
2512 return Ok(());
2513 }
2514 let args = linked_args().await?;
2515 let linked_func_call = state
2516 .link_value(
2517 JsValue::call(
2518 Box::new(JsValue::WellKnownFunction(WellKnownFunctionKind::PathJoin)),
2519 args.clone(),
2520 ),
2521 ImportAttributes::empty_ref(),
2522 )
2523 .await?;
2524 let pat = js_value_to_pattern(&linked_func_call);
2525 if !pat.has_constant_parts() {
2526 let (args, hints) = explain_args(args);
2527 handler.span_warn_with_code(
2528 span,
2529 &format!("path.join({args}) is very dynamic{hints}",),
2530 DiagnosticId::Lint(
2531 errors::failed_to_analyze::ecmascript::PATH_METHOD.to_string(),
2532 ),
2533 );
2534 if ignore_dynamic_requests {
2535 return Ok(());
2536 }
2537 }
2538 analysis.add_reference(
2539 DirAssetReference::new(
2540 get_traced_project_dir().await?,
2541 Pattern::new(pat),
2542 get_issue_source(),
2543 )
2544 .to_resolved()
2545 .await?,
2546 );
2547 return Ok(());
2548 }
2549 WellKnownFunctionKind::ChildProcessSpawnMethod(name)
2550 if analysis.analyze_mode.is_tracing_assets() =>
2551 {
2552 let args = linked_args().await?;
2553
2554 if is_invoking_node_process_eval(args) {
2556 return Ok(());
2557 }
2558
2559 if !args.is_empty() {
2560 let mut show_dynamic_warning = false;
2561 let pat = js_value_to_pattern(&args[0]);
2562 if pat.is_match_ignore_dynamic("node") && args.len() >= 2 {
2563 let first_arg =
2564 JsValue::member(Box::new(args[1].clone()), Box::new(0_f64.into()));
2565 let first_arg = state
2566 .link_value(first_arg, ImportAttributes::empty_ref())
2567 .await?;
2568 let pat = js_value_to_pattern(&first_arg);
2569 let dynamic = !pat.has_constant_parts();
2570 if dynamic {
2571 show_dynamic_warning = true;
2572 }
2573 if !dynamic || !ignore_dynamic_requests {
2574 let error_mode = if in_try {
2575 ResolveErrorMode::Warn
2576 } else {
2577 ResolveErrorMode::Error
2578 };
2579 analysis.add_reference(
2580 CjsAssetReference::new(
2581 *origin,
2582 Request::parse(pat),
2583 issue_source(source, span),
2584 error_mode,
2585 )
2586 .to_resolved()
2587 .await?,
2588 );
2589 }
2590 }
2591 let dynamic = !pat.has_constant_parts();
2592 if dynamic {
2593 show_dynamic_warning = true;
2594 }
2595 if !dynamic || !ignore_dynamic_requests {
2596 analysis.add_reference(
2597 FileSourceReference::new(
2598 get_traced_project_dir().await?,
2599 Pattern::new(pat),
2600 collect_affecting_sources,
2601 IssueSource::from_swc_offsets(
2602 source,
2603 span.lo.to_u32(),
2604 span.hi.to_u32(),
2605 ),
2606 )
2607 .to_resolved()
2608 .await?,
2609 );
2610 }
2611 if show_dynamic_warning {
2612 let (args, hints) = explain_args(args);
2613 handler.span_warn_with_code(
2614 span,
2615 &format!("child_process.{name}({args}) is very dynamic{hints}",),
2616 DiagnosticId::Lint(
2617 errors::failed_to_analyze::ecmascript::CHILD_PROCESS_SPAWN.to_string(),
2618 ),
2619 );
2620 }
2621 return Ok(());
2622 }
2623 let (args, hints) = explain_args(args);
2624 handler.span_warn_with_code(
2625 span,
2626 &format!("child_process.{name}({args}) is not statically analyze-able{hints}",),
2627 DiagnosticId::Error(
2628 errors::failed_to_analyze::ecmascript::CHILD_PROCESS_SPAWN.to_string(),
2629 ),
2630 )
2631 }
2632 WellKnownFunctionKind::ChildProcessFork if analysis.analyze_mode.is_tracing_assets() => {
2633 let args = linked_args().await?;
2634 if !args.is_empty() {
2635 let first_arg = &args[0];
2636 let pat = js_value_to_pattern(first_arg);
2637 if !pat.has_constant_parts() {
2638 let (args, hints) = explain_args(args);
2639 handler.span_warn_with_code(
2640 span,
2641 &format!("child_process.fork({args}) is very dynamic{hints}",),
2642 DiagnosticId::Lint(
2643 errors::failed_to_analyze::ecmascript::CHILD_PROCESS_SPAWN.to_string(),
2644 ),
2645 );
2646 if ignore_dynamic_requests {
2647 return Ok(());
2648 }
2649 }
2650 let error_mode = if in_try {
2651 ResolveErrorMode::Warn
2652 } else {
2653 ResolveErrorMode::Error
2654 };
2655 analysis.add_reference(
2656 CjsAssetReference::new(
2657 *origin,
2658 Request::parse(pat),
2659 issue_source(source, span),
2660 error_mode,
2661 )
2662 .to_resolved()
2663 .await?,
2664 );
2665 return Ok(());
2666 }
2667 let (args, hints) = explain_args(args);
2668 handler.span_warn_with_code(
2669 span,
2670 &format!("child_process.fork({args}) is not statically analyze-able{hints}",),
2671 DiagnosticId::Error(
2672 errors::failed_to_analyze::ecmascript::CHILD_PROCESS_SPAWN.to_string(),
2673 ),
2674 )
2675 }
2676 WellKnownFunctionKind::NodePreGypFind if analysis.analyze_mode.is_tracing_assets() => {
2677 use turbopack_resolve::node_native_binding::NodePreGypConfigReference;
2678
2679 let args = linked_args().await?;
2680 if args.len() == 1 {
2681 let first_arg = &args[0];
2682 let pat = js_value_to_pattern(first_arg);
2683 if !pat.has_constant_parts() {
2684 let (args, hints) = explain_args(args);
2685 handler.span_warn_with_code(
2686 span,
2687 &format!("node-pre-gyp.find({args}) is very dynamic{hints}",),
2688 DiagnosticId::Lint(
2689 errors::failed_to_analyze::ecmascript::NODE_PRE_GYP_FIND.to_string(),
2690 ),
2691 );
2692 return Ok(());
2694 }
2695 analysis.add_reference(
2696 NodePreGypConfigReference::new(
2697 origin.origin_path().await?.parent(),
2698 Pattern::new(pat),
2699 compile_time_info.environment().compile_target(),
2700 collect_affecting_sources,
2701 )
2702 .to_resolved()
2703 .await?,
2704 );
2705 return Ok(());
2706 }
2707 let (args, hints) = explain_args(args);
2708 handler.span_warn_with_code(
2709 span,
2710 &format!(
2711 "require('@mapbox/node-pre-gyp').find({args}) is not statically \
2712 analyze-able{hints}",
2713 ),
2714 DiagnosticId::Error(
2715 errors::failed_to_analyze::ecmascript::NODE_PRE_GYP_FIND.to_string(),
2716 ),
2717 )
2718 }
2719 WellKnownFunctionKind::NodeGypBuild if analysis.analyze_mode.is_tracing_assets() => {
2720 use turbopack_resolve::node_native_binding::NodeGypBuildReference;
2721
2722 let args = linked_args().await?;
2723 if args.len() == 1 {
2724 let first_arg = state
2725 .link_value(args[0].clone(), ImportAttributes::empty_ref())
2726 .await?;
2727 if let Some(s) = first_arg.as_str() {
2728 let current_context = origin
2730 .origin_path()
2731 .await?
2732 .root()
2733 .await?
2734 .join(s.trim_start_matches("/ROOT/"))?;
2735 analysis.add_reference(
2736 NodeGypBuildReference::new(
2737 current_context,
2738 collect_affecting_sources,
2739 compile_time_info.environment().compile_target(),
2740 )
2741 .to_resolved()
2742 .await?,
2743 );
2744 return Ok(());
2745 }
2746 }
2747 let (args, hints) = explain_args(args);
2748 handler.span_warn_with_code(
2749 span,
2750 &format!(
2751 "require('node-gyp-build')({args}) is not statically analyze-able{hints}",
2752 ),
2753 DiagnosticId::Error(
2754 errors::failed_to_analyze::ecmascript::NODE_GYP_BUILD.to_string(),
2755 ),
2756 )
2757 }
2758 WellKnownFunctionKind::NodeBindings if analysis.analyze_mode.is_tracing_assets() => {
2759 use turbopack_resolve::node_native_binding::NodeBindingsReference;
2760
2761 let args = linked_args().await?;
2762 if args.len() == 1 {
2763 let first_arg = state
2764 .link_value(args[0].clone(), ImportAttributes::empty_ref())
2765 .await?;
2766 if let Some(s) = first_arg.as_str() {
2767 analysis.add_reference(
2768 NodeBindingsReference::new(
2769 origin.origin_path().owned().await?,
2770 s.into(),
2771 collect_affecting_sources,
2772 )
2773 .to_resolved()
2774 .await?,
2775 );
2776 return Ok(());
2777 }
2778 }
2779 let (args, hints) = explain_args(args);
2780 handler.span_warn_with_code(
2781 span,
2782 &format!("require('bindings')({args}) is not statically analyze-able{hints}",),
2783 DiagnosticId::Error(
2784 errors::failed_to_analyze::ecmascript::NODE_BINDINGS.to_string(),
2785 ),
2786 )
2787 }
2788 WellKnownFunctionKind::NodeExpressSet if analysis.analyze_mode.is_tracing_assets() => {
2789 let args = linked_args().await?;
2790 if args.len() == 2
2791 && let Some(s) = args.first().and_then(|arg| arg.as_str())
2792 {
2793 let pkg_or_dir = args.get(1).unwrap();
2794 let pat = js_value_to_pattern(pkg_or_dir);
2795 if !pat.has_constant_parts() {
2796 let (args, hints) = explain_args(args);
2797 handler.span_warn_with_code(
2798 span,
2799 &format!("require('express')().set({args}) is very dynamic{hints}",),
2800 DiagnosticId::Lint(
2801 errors::failed_to_analyze::ecmascript::NODE_EXPRESS.to_string(),
2802 ),
2803 );
2804 return Ok(());
2806 }
2807 match s {
2808 "views" => {
2809 if let Pattern::Constant(p) = &pat {
2810 let abs_pattern = if p.starts_with("/ROOT/") {
2811 pat
2812 } else {
2813 let linked_func_call = state
2814 .link_value(
2815 JsValue::call(
2816 Box::new(JsValue::WellKnownFunction(
2817 WellKnownFunctionKind::PathJoin,
2818 )),
2819 vec![
2820 JsValue::FreeVar(atom!("__dirname")),
2821 pkg_or_dir.clone(),
2822 ],
2823 ),
2824 ImportAttributes::empty_ref(),
2825 )
2826 .await?;
2827 js_value_to_pattern(&linked_func_call)
2828 };
2829 analysis.add_reference(
2830 DirAssetReference::new(
2831 get_traced_project_dir().await?,
2832 Pattern::new(abs_pattern),
2833 get_issue_source(),
2834 )
2835 .to_resolved()
2836 .await?,
2837 );
2838 return Ok(());
2839 }
2840 }
2841 "view engine" => {
2842 if let Some(pkg) = pkg_or_dir.as_str() {
2843 if pkg != "html" {
2844 let pat = js_value_to_pattern(pkg_or_dir);
2845 let error_mode = if in_try {
2846 ResolveErrorMode::Warn
2847 } else {
2848 ResolveErrorMode::Error
2849 };
2850 analysis.add_reference(
2851 CjsAssetReference::new(
2852 *origin,
2853 Request::parse(pat),
2854 issue_source(source, span),
2855 error_mode,
2856 )
2857 .to_resolved()
2858 .await?,
2859 );
2860 }
2861 return Ok(());
2862 }
2863 }
2864 _ => {}
2865 }
2866 }
2867 let (args, hints) = explain_args(args);
2868 handler.span_warn_with_code(
2869 span,
2870 &format!("require('express')().set({args}) is not statically analyze-able{hints}",),
2871 DiagnosticId::Error(
2872 errors::failed_to_analyze::ecmascript::NODE_EXPRESS.to_string(),
2873 ),
2874 )
2875 }
2876 WellKnownFunctionKind::NodeStrongGlobalizeSetRootDir
2877 if analysis.analyze_mode.is_tracing_assets() =>
2878 {
2879 let args = linked_args().await?;
2880 if let Some(p) = args.first().and_then(|arg| arg.as_str()) {
2881 let abs_pattern = if p.starts_with("/ROOT/") {
2882 Pattern::Constant(format!("{p}/intl").into())
2883 } else {
2884 let linked_func_call = state
2885 .link_value(
2886 JsValue::call(
2887 Box::new(JsValue::WellKnownFunction(
2888 WellKnownFunctionKind::PathJoin,
2889 )),
2890 vec![
2891 JsValue::FreeVar(atom!("__dirname")),
2892 p.into(),
2893 atom!("intl").into(),
2894 ],
2895 ),
2896 ImportAttributes::empty_ref(),
2897 )
2898 .await?;
2899 js_value_to_pattern(&linked_func_call)
2900 };
2901 analysis.add_reference(
2902 DirAssetReference::new(
2903 get_traced_project_dir().await?,
2904 Pattern::new(abs_pattern),
2905 get_issue_source(),
2906 )
2907 .to_resolved()
2908 .await?,
2909 );
2910 return Ok(());
2911 }
2912 let (args, hints) = explain_args(args);
2913 handler.span_warn_with_code(
2914 span,
2915 &format!(
2916 "require('strong-globalize').SetRootDir({args}) is not statically \
2917 analyze-able{hints}",
2918 ),
2919 DiagnosticId::Error(
2920 errors::failed_to_analyze::ecmascript::NODE_GYP_BUILD.to_string(),
2921 ),
2922 )
2923 }
2924 WellKnownFunctionKind::NodeResolveFrom if analysis.analyze_mode.is_tracing_assets() => {
2925 let args = linked_args().await?;
2926 if args.len() == 2 && args.get(1).and_then(|arg| arg.as_str()).is_some() {
2927 let error_mode = if in_try {
2928 ResolveErrorMode::Warn
2929 } else {
2930 ResolveErrorMode::Error
2931 };
2932 analysis.add_reference(
2933 CjsAssetReference::new(
2934 *origin,
2935 Request::parse(js_value_to_pattern(&args[1])),
2936 issue_source(source, span),
2937 error_mode,
2938 )
2939 .to_resolved()
2940 .await?,
2941 );
2942 return Ok(());
2943 }
2944 let (args, hints) = explain_args(args);
2945 handler.span_warn_with_code(
2946 span,
2947 &format!("require('resolve-from')({args}) is not statically analyze-able{hints}",),
2948 DiagnosticId::Error(
2949 errors::failed_to_analyze::ecmascript::NODE_RESOLVE_FROM.to_string(),
2950 ),
2951 )
2952 }
2953 WellKnownFunctionKind::NodeProtobufLoad if analysis.analyze_mode.is_tracing_assets() => {
2954 let args = linked_args().await?;
2955 if args.len() == 2
2956 && let Some(JsValue::Object { parts, .. }) = args.get(1)
2957 {
2958 let context_dir = get_traced_project_dir().await?;
2959 let resolved_dirs = parts
2960 .iter()
2961 .filter_map(|object_part| match object_part {
2962 ObjectPart::KeyValue(
2963 JsValue::Constant(key),
2964 JsValue::Array { items: dirs, .. },
2965 ) if key.as_str() == Some("includeDirs") => {
2966 Some(dirs.iter().filter_map(|dir| dir.as_str()))
2967 }
2968 _ => None,
2969 })
2970 .flatten()
2971 .map(|dir| {
2972 DirAssetReference::new(
2973 context_dir.clone(),
2974 Pattern::new(Pattern::Constant(dir.into())),
2975 get_issue_source(),
2976 )
2977 .to_resolved()
2978 })
2979 .try_join()
2980 .await?;
2981
2982 for resolved_dir_ref in resolved_dirs {
2983 analysis.add_reference(resolved_dir_ref);
2984 }
2985
2986 return Ok(());
2987 }
2988 let (args, hints) = explain_args(args);
2989 handler.span_warn_with_code(
2990 span,
2991 &format!(
2992 "require('@grpc/proto-loader').load({args}) is not statically \
2993 analyze-able{hints}",
2994 ),
2995 DiagnosticId::Error(
2996 errors::failed_to_analyze::ecmascript::NODE_PROTOBUF_LOADER.to_string(),
2997 ),
2998 )
2999 }
3000 kind @ (WellKnownFunctionKind::ModuleHotAccept
3001 | WellKnownFunctionKind::ModuleHotDecline) => {
3002 let is_accept = matches!(kind, WellKnownFunctionKind::ModuleHotAccept);
3003 let args = linked_args().await?;
3004 if let Some(first_arg) = args.first() {
3005 if let Some(dep_strings) = extract_hot_dep_strings(first_arg) {
3006 let mut references = Vec::new();
3007 let mut esm_references = Vec::new();
3008 for dep_str in &dep_strings {
3009 let request = Request::parse_string(dep_str.clone()).to_resolved().await?;
3010 let reference = ModuleHotReferenceAssetReference::new(
3011 *origin,
3012 *request,
3013 issue_source(source, span),
3014 error_mode,
3015 state.is_esm,
3016 )
3017 .to_resolved()
3018 .await?;
3019 analysis.add_reference(reference);
3020 references.push(reference);
3021
3022 let esm_ref = if is_accept {
3025 state
3026 .imports
3027 .references()
3028 .enumerate()
3029 .find(|(_, r)| r.module_path.to_string_lossy() == dep_str.as_str())
3030 .and_then(|(idx, _)| state.import_references.get(idx).copied())
3031 } else {
3032 None
3033 };
3034 esm_references.push(esm_ref);
3035 }
3036 analysis.add_code_gen(ModuleHotReferenceCodeGen::new(
3037 references,
3038 esm_references,
3039 ast_path.to_vec().into(),
3040 ));
3041 } else if first_arg.is_unknown() {
3042 let (args_str, hints) = explain_args(args);
3043 let method = if is_accept { "accept" } else { "decline" };
3044 let error_code = if is_accept {
3045 errors::failed_to_analyze::ecmascript::MODULE_HOT_ACCEPT
3046 } else {
3047 errors::failed_to_analyze::ecmascript::MODULE_HOT_DECLINE
3048 };
3049 handler.span_warn_with_code(
3050 span,
3051 &format!(
3052 "module.hot.{method}({args_str}) is not statically analyzable{hints}",
3053 ),
3054 DiagnosticId::Error(error_code.to_string()),
3055 )
3056 }
3057 }
3058 }
3059 _ => {}
3060 };
3061 Ok(())
3062}
3063
3064fn extract_hot_dep_strings(arg: &JsValue) -> Option<Vec<RcStr>> {
3068 if let Some(s) = arg.as_str() {
3070 return Some(vec![s.into()]);
3071 }
3072 if let JsValue::Array { items, .. } = arg {
3074 let mut deps = Vec::new();
3075 for item in items {
3076 deps.push(item.as_str()?.into());
3077 }
3078 return Some(deps);
3079 }
3080 None
3081}
3082
3083async fn handle_member(
3084 ast_path: &[AstParentKind],
3085 link_obj: impl Future<Output = Result<JsValue>> + Send + Sync,
3086 prop: JsValue,
3087 span: Span,
3088 state: &AnalysisState<'_>,
3089 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3090) -> Result<()> {
3091 if let Some(prop) = prop.as_str() {
3092 let has_member = state.free_var_references_members.contains_key(prop).await?;
3093 let is_prop_cache = prop == "cache";
3094
3095 let obj = if has_member || is_prop_cache {
3097 Some(link_obj.await?)
3098 } else {
3099 None
3100 };
3101
3102 if has_member {
3103 let obj = obj.as_ref().unwrap();
3104 if let Some((mut name, false)) = obj.get_definable_name(Some(state.var_graph)) {
3105 name.0.push(DefinableNameSegmentRef::Name(prop));
3106 if let Some(value) = state
3107 .compile_time_info_ref
3108 .free_var_references
3109 .get(&name)
3110 .await?
3111 {
3112 handle_free_var_reference(ast_path, &value, span, state, analysis).await?;
3113 return Ok(());
3114 }
3115 }
3116 }
3117
3118 if is_prop_cache
3119 && let JsValue::WellKnownFunction(WellKnownFunctionKind::Require) =
3120 obj.as_ref().unwrap()
3121 {
3122 analysis.add_code_gen(CjsRequireCacheAccess::new(ast_path.to_vec().into()));
3123 }
3124 }
3125
3126 Ok(())
3127}
3128
3129async fn handle_typeof(
3130 ast_path: &[AstParentKind],
3131 arg: JsValue,
3132 span: Span,
3133 state: &AnalysisState<'_>,
3134 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3135) -> Result<()> {
3136 if let Some((mut name, false)) = arg.get_definable_name(Some(state.var_graph)) {
3137 name.0.push(DefinableNameSegmentRef::TypeOf);
3138 if let Some(value) = state
3139 .compile_time_info_ref
3140 .free_var_references
3141 .get(&name)
3142 .await?
3143 {
3144 handle_free_var_reference(ast_path, &value, span, state, analysis).await?;
3145 return Ok(());
3146 }
3147 }
3148
3149 Ok(())
3150}
3151
3152async fn handle_free_var(
3153 ast_path: &[AstParentKind],
3154 var: JsValue,
3155 span: Span,
3156 state: &AnalysisState<'_>,
3157 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3158) -> Result<()> {
3159 if let Some((name, _)) = var.get_definable_name(None)
3160 && let Some(value) = state
3161 .compile_time_info_ref
3162 .free_var_references
3163 .get(&name)
3164 .await?
3165 {
3166 handle_free_var_reference(ast_path, &value, span, state, analysis).await?;
3167 return Ok(());
3168 }
3169
3170 Ok(())
3171}
3172
3173async fn handle_free_var_reference(
3174 ast_path: &[AstParentKind],
3175 value: &FreeVarReference,
3176 span: Span,
3177 state: &AnalysisState<'_>,
3178 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3179) -> Result<bool> {
3180 if matches!(
3182 ast_path,
3183 [
3185 ..,
3186 AstParentKind::AssignExpr(AssignExprField::Left),
3187 AstParentKind::AssignTarget(AssignTargetField::Simple),
3188 AstParentKind::SimpleAssignTarget(SimpleAssignTargetField::Member),
3189 ] |
3190 [
3192 ..,
3193 AstParentKind::AssignExpr(AssignExprField::Left),
3194 AstParentKind::AssignTarget(AssignTargetField::Simple),
3195 AstParentKind::SimpleAssignTarget(SimpleAssignTargetField::Ident),
3196 AstParentKind::BindingIdent(BindingIdentField::Id),
3197 ]
3198 ) {
3199 return Ok(false);
3200 }
3201
3202 match value {
3203 FreeVarReference::Value(value) => {
3204 analysis.add_code_gen(ConstantValueCodeGen::new(
3205 value.clone(),
3206 ast_path.to_vec().into(),
3207 ));
3208 }
3209 FreeVarReference::Ident(value) => {
3210 analysis.add_code_gen(IdentReplacement::new(
3211 value.clone(),
3212 ast_path.to_vec().into(),
3213 ));
3214 }
3215 FreeVarReference::Member(key, value) => {
3216 analysis.add_code_gen(MemberReplacement::new(
3217 key.clone(),
3218 value.clone(),
3219 ast_path.to_vec().into(),
3220 ));
3221 }
3222 FreeVarReference::EcmaScriptModule {
3223 request,
3224 lookup_path,
3225 export,
3226 } => {
3227 let esm_reference = analysis
3228 .add_esm_reference_free_var(request.clone(), async || {
3229 Ok(EsmAssetReference::new_pure(
3234 state.module,
3235 if let Some(lookup_path) = lookup_path {
3236 ResolvedVc::upcast(
3237 PlainResolveOrigin::new(
3238 state.origin.asset_context(),
3239 lookup_path.clone(),
3240 )
3241 .to_resolved()
3242 .await?,
3243 )
3244 } else {
3245 state.origin
3246 },
3247 request.clone(),
3248 IssueSource::from_swc_offsets(
3249 state.source,
3250 span.lo.to_u32(),
3251 span.hi.to_u32(),
3252 ),
3253 Default::default(),
3254 export.clone().map(ModulePart::export),
3255 ImportUsage::TopLevel,
3256 state.import_externals,
3257 state.tree_shaking_mode,
3258 )
3259 .resolved_cell())
3260 })
3261 .await?;
3262
3263 analysis.add_code_gen(EsmBinding::new(
3264 esm_reference,
3265 export.clone(),
3266 ast_path.to_vec().into(),
3267 ));
3268 }
3269 FreeVarReference::InputRelative(kind) => {
3270 let source_path = (*state.source).ident().path().owned().await?;
3271 let source_path = match kind {
3272 InputRelativeConstant::DirName => source_path.parent(),
3273 InputRelativeConstant::FileName => source_path,
3274 };
3275 analysis.add_code_gen(ConstantValueCodeGen::new(
3276 as_abs_path(source_path).into(),
3277 ast_path.to_vec().into(),
3278 ));
3279 }
3280 FreeVarReference::ReportUsage {
3281 message,
3282 severity,
3283 inner,
3284 } => {
3285 state.handler.emit_with_code(
3286 &span.into(),
3287 message,
3288 DiagnosticId::Error(
3289 errors::failed_to_analyze::ecmascript::FREE_VAR_REFERENCE.to_string(),
3290 ),
3291 match severity {
3292 IssueSeverity::Bug => Level::Bug,
3293 IssueSeverity::Fatal => Level::Fatal,
3294 IssueSeverity::Error => Level::Error,
3295 IssueSeverity::Warning => Level::Warning,
3296 IssueSeverity::Hint => Level::Help,
3297 IssueSeverity::Info | IssueSeverity::Note => Level::Note,
3298 IssueSeverity::Suggestion => Level::Cancelled,
3299 },
3300 );
3301
3302 if let Some(inner) = inner {
3303 return Box::pin(handle_free_var_reference(
3304 ast_path, inner, span, state, analysis,
3305 ))
3306 .await;
3307 }
3308 }
3309 }
3310 Ok(true)
3311}
3312
3313fn issue_source(source: ResolvedVc<Box<dyn Source>>, span: Span) -> IssueSource {
3314 IssueSource::from_swc_offsets(source, span.lo.to_u32(), span.hi.to_u32())
3315}
3316
3317async fn analyze_amd_define(
3318 source: ResolvedVc<Box<dyn Source>>,
3319 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3320 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
3321 handler: &Handler,
3322 span: Span,
3323 ast_path: &[AstParentKind],
3324 args: &[JsValue],
3325 error_mode: ResolveErrorMode,
3326) -> Result<()> {
3327 match args {
3328 [JsValue::Constant(id), JsValue::Array { items: deps, .. }, _] if id.as_str().is_some() => {
3329 analyze_amd_define_with_deps(
3330 source,
3331 analysis,
3332 origin,
3333 handler,
3334 span,
3335 ast_path,
3336 id.as_str(),
3337 deps,
3338 error_mode,
3339 )
3340 .await?;
3341 }
3342 [JsValue::Array { items: deps, .. }, _] => {
3343 analyze_amd_define_with_deps(
3344 source, analysis, origin, handler, span, ast_path, None, deps, error_mode,
3345 )
3346 .await?;
3347 }
3348 [JsValue::Constant(id), JsValue::Function(..)] if id.as_str().is_some() => {
3349 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3350 vec![
3351 AmdDefineDependencyElement::Require,
3352 AmdDefineDependencyElement::Exports,
3353 AmdDefineDependencyElement::Module,
3354 ],
3355 origin,
3356 ast_path.to_vec().into(),
3357 AmdDefineFactoryType::Function,
3358 issue_source(source, span),
3359 error_mode,
3360 ));
3361 }
3362 [JsValue::Constant(id), _] if id.as_str().is_some() => {
3363 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3364 vec![
3365 AmdDefineDependencyElement::Require,
3366 AmdDefineDependencyElement::Exports,
3367 AmdDefineDependencyElement::Module,
3368 ],
3369 origin,
3370 ast_path.to_vec().into(),
3371 AmdDefineFactoryType::Unknown,
3372 issue_source(source, span),
3373 error_mode,
3374 ));
3375 }
3376 [JsValue::Function(..)] => {
3377 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3378 vec![
3379 AmdDefineDependencyElement::Require,
3380 AmdDefineDependencyElement::Exports,
3381 AmdDefineDependencyElement::Module,
3382 ],
3383 origin,
3384 ast_path.to_vec().into(),
3385 AmdDefineFactoryType::Function,
3386 issue_source(source, span),
3387 error_mode,
3388 ));
3389 }
3390 [JsValue::Object { .. }] => {
3391 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3392 vec![],
3393 origin,
3394 ast_path.to_vec().into(),
3395 AmdDefineFactoryType::Value,
3396 issue_source(source, span),
3397 error_mode,
3398 ));
3399 }
3400 [_] => {
3401 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3402 vec![
3403 AmdDefineDependencyElement::Require,
3404 AmdDefineDependencyElement::Exports,
3405 AmdDefineDependencyElement::Module,
3406 ],
3407 origin,
3408 ast_path.to_vec().into(),
3409 AmdDefineFactoryType::Unknown,
3410 issue_source(source, span),
3411 error_mode,
3412 ));
3413 }
3414 _ => {
3415 handler.span_err_with_code(
3416 span,
3417 "unsupported AMD define() form",
3418 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::AMD_DEFINE.to_string()),
3419 );
3420 }
3421 }
3422
3423 Ok(())
3424}
3425
3426async fn analyze_amd_define_with_deps(
3427 source: ResolvedVc<Box<dyn Source>>,
3428 analysis: &mut AnalyzeEcmascriptModuleResultBuilder,
3429 origin: ResolvedVc<Box<dyn ResolveOrigin>>,
3430 handler: &Handler,
3431 span: Span,
3432 ast_path: &[AstParentKind],
3433 id: Option<&str>,
3434 deps: &[JsValue],
3435 error_mode: ResolveErrorMode,
3436) -> Result<()> {
3437 let mut requests = Vec::new();
3438 for dep in deps {
3439 if let Some(dep) = dep.as_str() {
3440 match dep {
3441 "exports" => {
3442 requests.push(AmdDefineDependencyElement::Exports);
3443 }
3444 "require" => {
3445 handler.span_warn_with_code(
3446 span,
3447 "using \"require\" as dependency in an AMD define() is not yet supported",
3448 DiagnosticId::Error(
3449 errors::failed_to_analyze::ecmascript::AMD_DEFINE.to_string(),
3450 ),
3451 );
3452 requests.push(AmdDefineDependencyElement::Require);
3453 }
3454 "module" => {
3455 requests.push(AmdDefineDependencyElement::Module);
3456 }
3457 _ => {
3458 let request = Request::parse_string(dep.into()).to_resolved().await?;
3459 let reference = AmdDefineAssetReference::new(
3460 *origin,
3461 *request,
3462 issue_source(source, span),
3463 error_mode,
3464 )
3465 .to_resolved()
3466 .await?;
3467 requests.push(AmdDefineDependencyElement::Request {
3468 request,
3469 request_str: dep.to_string(),
3470 });
3471 analysis.add_reference(reference);
3472 }
3473 }
3474 } else {
3475 handler.span_err_with_code(
3476 span,
3479 "unsupported AMD define() dependency element form",
3480 DiagnosticId::Error(errors::failed_to_analyze::ecmascript::AMD_DEFINE.to_string()),
3481 );
3482 }
3483 }
3484
3485 if id.is_some() {
3486 handler.span_warn_with_code(
3487 span,
3488 "passing an ID to AMD define() is not yet fully supported",
3489 DiagnosticId::Lint(errors::failed_to_analyze::ecmascript::AMD_DEFINE.to_string()),
3490 );
3491 }
3492
3493 analysis.add_code_gen(AmdDefineWithDependenciesCodeGen::new(
3494 requests,
3495 origin,
3496 ast_path.to_vec().into(),
3497 AmdDefineFactoryType::Function,
3498 issue_source(source, span),
3499 error_mode,
3500 ));
3501
3502 Ok(())
3503}
3504
3505pub fn as_abs_path(path: FileSystemPath) -> String {
3508 require_resolve(path)
3513}
3514
3515fn require_resolve(path: FileSystemPath) -> String {
3517 format!("/ROOT/{}", path.path.as_str())
3518}
3519
3520async fn early_value_visitor(mut v: JsValue) -> Result<(JsValue, bool)> {
3521 let modified = early_replace_builtin(&mut v);
3522 Ok((v, modified))
3523}
3524
3525async fn value_visitor(
3526 origin: Vc<Box<dyn ResolveOrigin>>,
3527 v: JsValue,
3528 compile_time_info: Vc<CompileTimeInfo>,
3529 compile_time_info_ref: &CompileTimeInfo,
3530 var_graph: &VarGraph,
3531 attributes: &ImportAttributes,
3532 allow_project_root_tracing: bool,
3533) -> Result<(JsValue, bool)> {
3534 let (mut v, modified) = value_visitor_inner(
3535 origin,
3536 v,
3537 compile_time_info,
3538 compile_time_info_ref,
3539 var_graph,
3540 attributes,
3541 allow_project_root_tracing,
3542 )
3543 .await?;
3544 v.normalize_shallow();
3545 Ok((v, modified))
3546}
3547
3548async fn value_visitor_inner(
3549 origin: Vc<Box<dyn ResolveOrigin>>,
3550 v: JsValue,
3551 compile_time_info: Vc<CompileTimeInfo>,
3552 compile_time_info_ref: &CompileTimeInfo,
3553 var_graph: &VarGraph,
3554 attributes: &ImportAttributes,
3555 allow_project_root_tracing: bool,
3556) -> Result<(JsValue, bool)> {
3557 let ImportAttributes { ignore, .. } = *attributes;
3558 if let Some((name, _)) = v.get_definable_name(Some(var_graph))
3559 && let Some(value) = compile_time_info_ref.defines.get(&name).await?
3560 {
3561 return Ok(((&*value).try_into()?, true));
3562 }
3563 let value = match v {
3564 JsValue::Call(
3565 _,
3566 box JsValue::WellKnownFunction(WellKnownFunctionKind::RequireResolve),
3567 args,
3568 ) => require_resolve_visitor(origin, args).await?,
3569 JsValue::Call(
3570 _,
3571 box JsValue::WellKnownFunction(WellKnownFunctionKind::RequireContext),
3572 args,
3573 ) => require_context_visitor(origin, args).await?,
3574 JsValue::Call(
3575 _,
3576 box JsValue::WellKnownFunction(
3577 WellKnownFunctionKind::RequireContextRequire(..)
3578 | WellKnownFunctionKind::RequireContextRequireKeys(..)
3579 | WellKnownFunctionKind::RequireContextRequireResolve(..),
3580 ),
3581 _,
3582 ) => {
3583 v.into_unknown(
3586 true,
3587 "require.context() static analysis is currently limited",
3588 )
3589 }
3590 JsValue::Call(
3591 _,
3592 box JsValue::WellKnownFunction(WellKnownFunctionKind::CreateRequire),
3593 ref args,
3594 ) => {
3595 if let [
3597 JsValue::Member(
3598 _,
3599 box JsValue::WellKnownObject(WellKnownObjectKind::ImportMeta),
3600 box JsValue::Constant(super::analyzer::ConstantValue::Str(prop)),
3601 ),
3602 ] = &args[..]
3603 && prop.as_str() == "url"
3604 {
3605 JsValue::WellKnownFunction(WellKnownFunctionKind::Require)
3606 } else {
3607 v.into_unknown(true, "createRequire() non constant")
3608 }
3609 }
3610 JsValue::New(
3611 _,
3612 box JsValue::WellKnownFunction(WellKnownFunctionKind::URLConstructor),
3613 ref args,
3614 ) => {
3615 if let [
3616 JsValue::Constant(super::analyzer::ConstantValue::Str(url)),
3617 JsValue::Member(
3618 _,
3619 box JsValue::WellKnownObject(WellKnownObjectKind::ImportMeta),
3620 box JsValue::Constant(super::analyzer::ConstantValue::Str(prop)),
3621 ),
3622 ] = &args[..]
3623 {
3624 if prop.as_str() == "url" {
3625 JsValue::Url(url.clone(), JsValueUrlKind::Relative)
3626 } else {
3627 v.into_unknown(true, "new URL() non constant")
3628 }
3629 } else {
3630 v.into_unknown(true, "new non constant")
3631 }
3632 }
3633 JsValue::WellKnownFunction(
3634 WellKnownFunctionKind::PathJoin
3635 | WellKnownFunctionKind::PathResolve(_)
3636 | WellKnownFunctionKind::FsReadMethod(_),
3637 ) => {
3638 if ignore {
3639 return Ok((
3640 JsValue::unknown(v, true, "ignored well known function"),
3641 true,
3642 ));
3643 } else {
3644 return Ok((v, false));
3645 }
3646 }
3647 JsValue::FreeVar(ref kind) => match &**kind {
3648 "__dirname" => as_abs_path(origin.origin_path().owned().await?.parent()).into(),
3649 "__filename" => as_abs_path(origin.origin_path().owned().await?).into(),
3650
3651 "require" => JsValue::unknown_if(
3652 ignore,
3653 JsValue::WellKnownFunction(WellKnownFunctionKind::Require),
3654 true,
3655 "ignored require",
3656 ),
3657 "import" => JsValue::unknown_if(
3658 ignore,
3659 JsValue::WellKnownFunction(WellKnownFunctionKind::Import),
3660 true,
3661 "ignored import",
3662 ),
3663 "Worker" => JsValue::unknown_if(
3664 ignore,
3665 JsValue::WellKnownFunction(WellKnownFunctionKind::WorkerConstructor),
3666 true,
3667 "ignored Worker constructor",
3668 ),
3669 "SharedWorker" => JsValue::unknown_if(
3670 ignore,
3671 JsValue::WellKnownFunction(WellKnownFunctionKind::SharedWorkerConstructor),
3672 true,
3673 "ignored SharedWorker constructor",
3674 ),
3675 "define" => JsValue::WellKnownFunction(WellKnownFunctionKind::Define),
3676 "URL" => JsValue::WellKnownFunction(WellKnownFunctionKind::URLConstructor),
3677 "process" => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessModule),
3678 "Object" => JsValue::WellKnownObject(WellKnownObjectKind::GlobalObject),
3679 "Buffer" => JsValue::WellKnownObject(WellKnownObjectKind::NodeBuffer),
3680 _ => return Ok((v, false)),
3681 },
3682 JsValue::Module(ref mv) => compile_time_info
3683 .environment()
3684 .node_externals()
3685 .await?
3686 .then(|| module_value_to_well_known_object(mv))
3688 .flatten()
3689 .unwrap_or_else(|| v.into_unknown(true, "cross module analyzing is not yet supported")),
3690 JsValue::Argument(..) => {
3691 v.into_unknown(true, "cross function analyzing is not yet supported")
3692 }
3693 _ => {
3694 let (mut v, mut modified) =
3695 replace_well_known(v, compile_time_info, allow_project_root_tracing).await?;
3696 modified = replace_builtin(&mut v) || modified;
3697 modified = modified || v.make_nested_operations_unknown();
3698 return Ok((v, modified));
3699 }
3700 };
3701 Ok((value, true))
3702}
3703
3704async fn require_resolve_visitor(
3705 origin: Vc<Box<dyn ResolveOrigin>>,
3706 args: Vec<JsValue>,
3707) -> Result<JsValue> {
3708 Ok(if args.len() == 1 {
3709 let pat = js_value_to_pattern(&args[0]);
3710 let request = Request::parse(pat.clone());
3711 let resolved = cjs_resolve_source(
3712 origin,
3713 request,
3714 CommonJsReferenceSubType::Undefined,
3715 None,
3716 ResolveErrorMode::Warn,
3717 )
3718 .resolve()
3719 .await?;
3720 let mut values = resolved
3721 .primary_sources()
3722 .await?
3723 .iter()
3724 .map(|&source| async move {
3725 Ok(require_resolve(source.ident().path().owned().await?).into())
3726 })
3727 .try_join()
3728 .await?;
3729
3730 match values.len() {
3731 0 => JsValue::unknown(
3732 JsValue::call(
3733 Box::new(JsValue::WellKnownFunction(
3734 WellKnownFunctionKind::RequireResolve,
3735 )),
3736 args,
3737 ),
3738 false,
3739 "unresolvable request",
3740 ),
3741 1 => values.pop().unwrap(),
3742 _ => JsValue::alternatives(values),
3743 }
3744 } else {
3745 JsValue::unknown(
3746 JsValue::call(
3747 Box::new(JsValue::WellKnownFunction(
3748 WellKnownFunctionKind::RequireResolve,
3749 )),
3750 args,
3751 ),
3752 true,
3753 "only a single argument is supported",
3754 )
3755 })
3756}
3757
3758async fn require_context_visitor(
3759 origin: Vc<Box<dyn ResolveOrigin>>,
3760 args: Vec<JsValue>,
3761) -> Result<JsValue> {
3762 let options = match parse_require_context(&args) {
3763 Ok(options) => options,
3764 Err(err) => {
3765 return Ok(JsValue::unknown(
3766 JsValue::call(
3767 Box::new(JsValue::WellKnownFunction(
3768 WellKnownFunctionKind::RequireContext,
3769 )),
3770 args,
3771 ),
3772 true,
3773 PrettyPrintError(&err).to_string(),
3774 ));
3775 }
3776 };
3777
3778 let dir = origin
3779 .origin_path()
3780 .owned()
3781 .await?
3782 .parent()
3783 .join(options.dir.as_str())?;
3784
3785 let map = RequireContextMap::generate(
3786 origin,
3787 dir,
3788 options.include_subdirs,
3789 options.filter.cell(),
3790 None,
3791 ResolveErrorMode::Warn,
3792 );
3793
3794 Ok(JsValue::WellKnownFunction(
3795 WellKnownFunctionKind::RequireContextRequire(
3796 RequireContextValue::from_context_map(map).await?,
3797 ),
3798 ))
3799}
3800
3801#[derive(Debug)]
3802enum StaticExpr {
3803 String(String),
3804 FreeVar(Vec<String>),
3805 ImportedVar(String, Vec<String>),
3806 Unknown,
3807}
3808
3809#[derive(Default)]
3811struct StaticAnalyser {
3812 imports: FxHashMap<String, (String, Vec<String>)>,
3813}
3814
3815impl StaticAnalyser {
3816 fn prop_to_name(&self, prop: &MemberProp) -> Option<String> {
3817 match prop {
3818 MemberProp::Ident(ident) => Some(ident.sym.to_string()),
3819 MemberProp::PrivateName(_) => None,
3820 MemberProp::Computed(ComputedPropName { expr, .. }) => match self.evaluate_expr(expr) {
3821 StaticExpr::String(str) => Some(str),
3822 _ => None,
3823 },
3824 }
3825 }
3826
3827 fn evaluate_expr(&self, expr: &Expr) -> StaticExpr {
3828 match expr {
3829 Expr::Lit(Lit::Str(str)) => {
3830 StaticExpr::String(str.value.to_string_lossy().into_owned())
3831 }
3832 Expr::Ident(ident) => {
3833 let str = ident.sym.to_string();
3834 match self.imports.get(&str) {
3835 Some((module, import)) => {
3836 StaticExpr::ImportedVar(module.clone(), import.clone())
3837 }
3838 None => StaticExpr::FreeVar(vec![str]),
3839 }
3840 }
3841 Expr::Member(member) => match self.evaluate_expr(&member.obj) {
3842 StaticExpr::FreeVar(mut vec) => match self.prop_to_name(&member.prop) {
3843 Some(name) => {
3844 vec.push(name);
3845 StaticExpr::FreeVar(vec)
3846 }
3847 None => StaticExpr::Unknown,
3848 },
3849 StaticExpr::ImportedVar(module, mut vec) => match self.prop_to_name(&member.prop) {
3850 Some(name) => {
3851 vec.push(name);
3852 StaticExpr::ImportedVar(module, vec)
3853 }
3854 None => StaticExpr::Unknown,
3855 },
3856 _ => StaticExpr::Unknown,
3857 },
3858 _ => StaticExpr::Unknown,
3859 }
3860 }
3861}
3862
3863struct ModuleReferencesVisitor<'a> {
3866 analyze_mode: AnalyzeMode,
3867 eval_context: &'a EvalContext,
3868 old_analyzer: StaticAnalyser,
3869 import_references: &'a [ResolvedVc<EsmAssetReference>],
3870 analysis: &'a mut AnalyzeEcmascriptModuleResultBuilder,
3871 esm_exports: BTreeMap<RcStr, EsmExport>,
3872 webpack_runtime: Option<(RcStr, Span)>,
3873 webpack_entry: bool,
3874 webpack_chunks: Vec<Lit>,
3875 var_graph: &'a VarGraph,
3876}
3877
3878impl<'a> ModuleReferencesVisitor<'a> {
3879 fn new(
3880 eval_context: &'a EvalContext,
3881 import_references: &'a [ResolvedVc<EsmAssetReference>],
3882 analysis: &'a mut AnalyzeEcmascriptModuleResultBuilder,
3883 analyze_mode: AnalyzeMode,
3884 var_graph: &'a VarGraph,
3885 ) -> Self {
3886 Self {
3887 analyze_mode,
3888 eval_context,
3889 old_analyzer: StaticAnalyser::default(),
3890 import_references,
3891 analysis,
3892 esm_exports: BTreeMap::new(),
3893 webpack_runtime: None,
3894 webpack_entry: false,
3895 webpack_chunks: Vec::new(),
3896 var_graph,
3897 }
3898 }
3899}
3900
3901impl<'a> ModuleReferencesVisitor<'a> {
3902 fn get_export_ident_liveness(&self, id: Id) -> Liveness {
3905 if let Some(crate::analyzer::graph::VarMeta {
3906 value: _,
3907 assignment_scopes: assignment_kinds,
3908 }) = self.var_graph.values.get(&id)
3909 {
3910 if *assignment_kinds != crate::analyzer::graph::AssignmentScopes::AllInModuleEvalScope {
3912 Liveness::Live
3913 } else {
3914 Liveness::Constant
3915 }
3916 } else {
3917 Liveness::Live
3922 }
3923 }
3924}
3925
3926fn as_parent_path(ast_path: &AstNodePath<AstParentNodeRef<'_>>) -> Vec<AstParentKind> {
3927 ast_path.iter().map(|n| n.kind()).collect()
3928}
3929
3930pub(crate) fn for_each_ident_in_pat(pat: &Pat, f: &mut impl FnMut(&Atom, SyntaxContext)) {
3931 match pat {
3932 Pat::Ident(BindingIdent { id, .. }) => {
3933 f(&id.sym, id.ctxt);
3934 }
3935 Pat::Array(ArrayPat { elems, .. }) => elems.iter().for_each(|e| {
3936 if let Some(e) = e {
3937 for_each_ident_in_pat(e, f);
3938 }
3939 }),
3940 Pat::Rest(RestPat { arg, .. }) => {
3941 for_each_ident_in_pat(arg, f);
3942 }
3943 Pat::Object(ObjectPat { props, .. }) => {
3944 props.iter().for_each(|p| match p {
3945 ObjectPatProp::KeyValue(KeyValuePatProp { value, .. }) => {
3946 for_each_ident_in_pat(value, f);
3947 }
3948 ObjectPatProp::Assign(AssignPatProp { key, .. }) => {
3949 f(&key.sym, key.ctxt);
3950 }
3951 ObjectPatProp::Rest(RestPat { arg, .. }) => {
3952 for_each_ident_in_pat(arg, f);
3953 }
3954 });
3955 }
3956 Pat::Assign(AssignPat { left, .. }) => {
3957 for_each_ident_in_pat(left, f);
3958 }
3959 Pat::Invalid(_) | Pat::Expr(_) => {
3960 panic!("Unexpected pattern while enumerating idents");
3961 }
3962 }
3963}
3964
3965impl VisitAstPath for ModuleReferencesVisitor<'_> {
3966 fn visit_export_all<'ast: 'r, 'r>(
3967 &mut self,
3968 export: &'ast ExportAll,
3969 ast_path: &mut AstNodePath<AstParentNodeRef<'r>>,
3970 ) {
3971 if self.analyze_mode.is_code_gen() {
3972 self.analysis
3973 .add_code_gen(EsmModuleItem::new(as_parent_path(ast_path).into()));
3974 }
3975 export.visit_children_with_ast_path(self, ast_path);
3976 }
3977
3978 fn visit_named_export<'ast: 'r, 'r>(
3979 &mut self,
3980 export: &'ast NamedExport,
3981 ast_path: &mut AstNodePath<AstParentNodeRef<'r>>,
3982 ) {
3983 let is_fake_esm = export
3985 .with
3986 .as_deref()
3987 .map(find_turbopack_part_id_in_asserts)
3988 .is_some();
3989
3990 if export.src.is_none() {
3992 for spec in export.specifiers.iter() {
3993 fn to_rcstr(name: &ModuleExportName) -> RcStr {
3994 name.atom().as_str().into()
3995 }
3996 match spec {
3997 ExportSpecifier::Namespace(_) => {
3998 panic!(
3999 "ExportNamespaceSpecifier will not happen in combination with src == \
4000 None"
4001 );
4002 }
4003 ExportSpecifier::Default(_) => {
4004 panic!(
4005 "ExportDefaultSpecifier will not happen in combination with src == \
4006 None"
4007 );
4008 }
4009 ExportSpecifier::Named(ExportNamedSpecifier { orig, exported, .. }) => {
4010 let key = to_rcstr(exported.as_ref().unwrap_or(orig));
4011 let binding_name = to_rcstr(orig);
4012 let export = {
4013 let imported_binding = if let ModuleExportName::Ident(ident) = orig {
4014 self.eval_context.imports.get_binding(&ident.to_id())
4015 } else {
4016 None
4017 };
4018 if let Some((index, export)) = imported_binding {
4019 let esm_ref = self.import_references[index];
4020 self.analysis.add_esm_reexport_reference(index);
4021 if let Some(export) = export {
4022 EsmExport::ImportedBinding(
4023 ResolvedVc::upcast(esm_ref),
4024 export,
4025 is_fake_esm,
4026 )
4027 } else {
4028 EsmExport::ImportedNamespace(ResolvedVc::upcast(esm_ref))
4029 }
4030 } else {
4031 let liveness = match orig {
4032 ModuleExportName::Ident(ident) => {
4033 self.get_export_ident_liveness(ident.to_id())
4034 }
4035 ModuleExportName::Str(_) => Liveness::Constant,
4036 };
4037
4038 EsmExport::LocalBinding(
4039 binding_name,
4040 if is_fake_esm {
4041 Liveness::Mutable
4043 } else {
4044 liveness
4045 },
4046 )
4047 }
4048 };
4049 self.esm_exports.insert(key, export);
4050 }
4051 }
4052 }
4053 }
4054
4055 if self.analyze_mode.is_code_gen() {
4056 self.analysis
4057 .add_code_gen(EsmModuleItem::new(as_parent_path(ast_path).into()));
4058 }
4059 export.visit_children_with_ast_path(self, ast_path);
4060 }
4061
4062 fn visit_export_decl<'ast: 'r, 'r>(
4063 &mut self,
4064 export: &'ast ExportDecl,
4065 ast_path: &mut AstNodePath<AstParentNodeRef<'r>>,
4066 ) {
4067 {
4068 let decl: &Decl = &export.decl;
4069 let insert_export_binding = &mut |id: &Atom, ctx: SyntaxContext| {
4070 let liveness = self.get_export_ident_liveness((id.clone(), ctx));
4071 let name: RcStr = id.as_str().into();
4072 self.esm_exports
4073 .insert(name.clone(), EsmExport::LocalBinding(name, liveness));
4074 };
4075 match decl {
4076 Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => {
4077 insert_export_binding(&ident.sym, ident.ctxt);
4078 }
4079 Decl::Var(var_decl) => {
4080 var_decl
4081 .decls
4082 .iter()
4083 .for_each(|VarDeclarator { name, .. }| {
4084 for_each_ident_in_pat(name, insert_export_binding);
4085 });
4086 }
4087 Decl::Using(_) => {
4088 unreachable!("using declarations can not be exported");
4090 }
4091 Decl::TsInterface(_)
4092 | Decl::TsTypeAlias(_)
4093 | Decl::TsEnum(_)
4094 | Decl::TsModule(_) => {
4095 }
4097 }
4098 };
4099 if self.analyze_mode.is_code_gen() {
4100 self.analysis
4101 .add_code_gen(EsmModuleItem::new(as_parent_path(ast_path).into()));
4102 }
4103 export.visit_children_with_ast_path(self, ast_path);
4104 }
4105
4106 fn visit_export_default_expr<'ast: 'r, 'r>(
4107 &mut self,
4108 export: &'ast ExportDefaultExpr,
4109 ast_path: &mut AstNodePath<AstParentNodeRef<'r>>,
4110 ) {
4111 self.esm_exports.insert(
4112 rcstr!("default"),
4113 EsmExport::LocalBinding(
4114 magic_identifier::mangle("default export").into(),
4115 Liveness::Constant,
4117 ),
4118 );
4119 if self.analyze_mode.is_code_gen() {
4120 self.analysis
4121 .add_code_gen(EsmModuleItem::new(as_parent_path(ast_path).into()));
4122 }
4123 export.visit_children_with_ast_path(self, ast_path);
4124 }
4125
4126 fn visit_export_default_decl<'ast: 'r, 'r>(
4127 &mut self,
4128 export: &'ast ExportDefaultDecl,
4129 ast_path: &mut AstNodePath<AstParentNodeRef<'r>>,
4130 ) {
4131 match &export.decl {
4132 DefaultDecl::Class(ClassExpr { ident, .. }) | DefaultDecl::Fn(FnExpr { ident, .. }) => {
4133 let export = match ident {
4134 Some(ident) => EsmExport::LocalBinding(
4135 ident.sym.as_str().into(),
4136 self.get_export_ident_liveness(ident.to_id()),
4137 ),
4138 None => EsmExport::LocalBinding(
4140 magic_identifier::mangle("default export").into(),
4141 Liveness::Constant,
4142 ),
4143 };
4144 self.esm_exports.insert(rcstr!("default"), export);
4145 }
4146 DefaultDecl::TsInterfaceDecl(..) => {
4147 }
4149 }
4150 if self.analyze_mode.is_code_gen() {
4151 self.analysis
4152 .add_code_gen(EsmModuleItem::new(as_parent_path(ast_path).into()));
4153 }
4154 export.visit_children_with_ast_path(self, ast_path);
4155 }
4156
4157 fn visit_import_decl<'ast: 'r, 'r>(
4158 &mut self,
4159 import: &'ast ImportDecl,
4160 ast_path: &mut AstNodePath<AstParentNodeRef<'r>>,
4161 ) {
4162 let path = as_parent_path(ast_path).into();
4163 let src = import.src.value.to_string_lossy().into_owned();
4164 import.visit_children_with_ast_path(self, ast_path);
4165 if import.type_only {
4166 return;
4167 }
4168 for specifier in &import.specifiers {
4169 match specifier {
4170 ImportSpecifier::Named(named) => {
4171 if !named.is_type_only {
4172 self.old_analyzer.imports.insert(
4173 named.local.sym.to_string(),
4174 (
4175 src.clone(),
4176 vec![match &named.imported {
4177 Some(ModuleExportName::Ident(ident)) => ident.sym.to_string(),
4178 Some(ModuleExportName::Str(str)) => {
4179 str.value.to_string_lossy().into_owned()
4180 }
4181 None => named.local.sym.to_string(),
4182 }],
4183 ),
4184 );
4185 }
4186 }
4187 ImportSpecifier::Default(default_import) => {
4188 self.old_analyzer.imports.insert(
4189 default_import.local.sym.to_string(),
4190 (src.clone(), vec!["default".to_string()]),
4191 );
4192 }
4193 ImportSpecifier::Namespace(namespace) => {
4194 self.old_analyzer
4195 .imports
4196 .insert(namespace.local.sym.to_string(), (src.clone(), Vec::new()));
4197 }
4198 }
4199 }
4200 if self.analyze_mode.is_code_gen() {
4201 self.analysis.add_code_gen(EsmModuleItem::new(path));
4202 }
4203 }
4204
4205 fn visit_var_declarator<'ast: 'r, 'r>(
4206 &mut self,
4207 decl: &'ast VarDeclarator,
4208 ast_path: &mut AstNodePath<AstParentNodeRef<'r>>,
4209 ) {
4210 if let Some(ident) = decl.name.as_ident()
4211 && &*ident.id.sym == "__webpack_require__"
4212 && let Some(init) = &decl.init
4213 && let Some(call) = init.as_call()
4214 && let Some(expr) = call.callee.as_expr()
4215 && let Some(ident) = expr.as_ident()
4216 && &*ident.sym == "require"
4217 && let [ExprOrSpread { spread: None, expr }] = &call.args[..]
4218 && let Some(Lit::Str(str)) = expr.as_lit()
4219 {
4220 self.webpack_runtime =
4221 Some((str.value.to_string_lossy().into_owned().into(), call.span));
4222 return;
4223 }
4224 decl.visit_children_with_ast_path(self, ast_path);
4225 }
4226
4227 fn visit_call_expr<'ast: 'r, 'r>(
4228 &mut self,
4229 call: &'ast CallExpr,
4230 ast_path: &mut AstNodePath<AstParentNodeRef<'r>>,
4231 ) {
4232 if let Callee::Expr(expr) = &call.callee
4233 && let StaticExpr::FreeVar(var) = self.old_analyzer.evaluate_expr(expr)
4234 {
4235 match &var[..] {
4236 [webpack_require, property]
4237 if webpack_require == "__webpack_require__" && property == "C" =>
4238 {
4239 self.webpack_entry = true;
4240 }
4241 [webpack_require, property]
4242 if webpack_require == "__webpack_require__" && property == "X" =>
4243 {
4244 if let [
4245 _,
4246 ExprOrSpread {
4247 spread: None,
4248 expr: chunk_ids,
4249 },
4250 _,
4251 ] = &call.args[..]
4252 && let Some(array) = chunk_ids.as_array()
4253 {
4254 for elem in array.elems.iter().flatten() {
4255 if let ExprOrSpread { spread: None, expr } = elem
4256 && let Some(lit) = expr.as_lit()
4257 {
4258 self.webpack_chunks.push(lit.clone());
4259 }
4260 }
4261 }
4262 }
4263 _ => {}
4264 }
4265 }
4266 call.visit_children_with_ast_path(self, ast_path);
4267 }
4268}
4269
4270#[turbo_tasks::function]
4271async fn resolve_as_webpack_runtime(
4272 origin: Vc<Box<dyn ResolveOrigin>>,
4273 request: Vc<Request>,
4274 transforms: Vc<EcmascriptInputTransforms>,
4275) -> Result<Vc<WebpackRuntime>> {
4276 let options = origin.resolve_options();
4277
4278 let options = apply_cjs_specific_options(options);
4279
4280 let resolved = resolve(
4281 origin.origin_path().await?.parent(),
4282 ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined),
4283 request,
4284 options,
4285 );
4286
4287 if let Some(source) = *resolved.first_source().await? {
4288 Ok(webpack_runtime(*source, transforms))
4289 } else {
4290 Ok(WebpackRuntime::None.cell())
4291 }
4292}
4293
4294#[derive(Hash, Debug, Clone, Eq, PartialEq, TraceRawVcs, Encode, Decode)]
4295pub struct AstPath(
4296 #[bincode(with_serde)]
4297 #[turbo_tasks(trace_ignore)]
4298 Vec<AstParentKind>,
4299);
4300
4301impl TaskInput for AstPath {
4302 fn is_transient(&self) -> bool {
4303 false
4304 }
4305}
4306unsafe impl NonLocalValue for AstPath {}
4307
4308impl Deref for AstPath {
4309 type Target = [AstParentKind];
4310
4311 fn deref(&self) -> &Self::Target {
4312 &self.0
4313 }
4314}
4315
4316impl From<Vec<AstParentKind>> for AstPath {
4317 fn from(v: Vec<AstParentKind>) -> Self {
4318 Self(v)
4319 }
4320}
4321
4322pub static TURBOPACK_HELPER: Lazy<Atom> = Lazy::new(|| atom!("__turbopack-helper__"));
4323pub static TURBOPACK_HELPER_WTF8: Lazy<Wtf8Atom> =
4324 Lazy::new(|| atom!("__turbopack-helper__").into());
4325
4326pub fn is_turbopack_helper_import(import: &ImportDecl) -> bool {
4327 let annotations = ImportAnnotations::parse(import.with.as_deref());
4328
4329 annotations.is_some_and(|a| a.get(&TURBOPACK_HELPER_WTF8).is_some())
4330}
4331
4332pub fn is_swc_helper_import(import: &ImportDecl) -> bool {
4333 import.src.value.starts_with("@swc/helpers/")
4334}
4335
4336#[derive(Debug)]
4337enum DetectedDynamicExportType {
4338 CommonJs,
4339 Namespace,
4340 Value,
4341 None,
4342 UsingModuleDeclarations,
4343}
4344
4345fn detect_dynamic_export(p: &Program) -> DetectedDynamicExportType {
4346 use swc_core::ecma::visit::{Visit, VisitWith, visit_obj_and_computed};
4347
4348 if let Program::Module(m) = p {
4349 if m.body.iter().any(|item| {
4351 item.as_module_decl().is_some_and(|module_decl| {
4352 module_decl.as_import().is_none_or(|import| {
4353 !is_turbopack_helper_import(import) && !is_swc_helper_import(import)
4354 })
4355 })
4356 }) {
4357 return DetectedDynamicExportType::UsingModuleDeclarations;
4358 }
4359 }
4360
4361 struct Visitor {
4362 cjs: bool,
4363 value: bool,
4364 namespace: bool,
4365 found: bool,
4366 }
4367
4368 impl Visit for Visitor {
4369 visit_obj_and_computed!();
4370
4371 fn visit_ident(&mut self, i: &Ident) {
4372 if &*i.sym == "module" || &*i.sym == "exports" {
4377 self.cjs = true;
4378 self.found = true;
4379 }
4380 if &*i.sym == "__turbopack_export_value__" {
4381 self.value = true;
4382 self.found = true;
4383 }
4384 if &*i.sym == "__turbopack_export_namespace__" {
4385 self.namespace = true;
4386 self.found = true;
4387 }
4388 }
4389
4390 fn visit_expr(&mut self, n: &Expr) {
4391 if self.found {
4392 return;
4393 }
4394
4395 if let Expr::Member(member) = n
4396 && member.obj.is_ident_ref_to("__turbopack_context__")
4397 && let MemberProp::Ident(prop) = &member.prop
4398 {
4399 const TURBOPACK_EXPORT_VALUE_SHORTCUT: &str = TURBOPACK_EXPORT_VALUE.shortcut;
4400 const TURBOPACK_EXPORT_NAMESPACE_SHORTCUT: &str =
4401 TURBOPACK_EXPORT_NAMESPACE.shortcut;
4402 match &*prop.sym {
4403 TURBOPACK_EXPORT_VALUE_SHORTCUT => {
4404 self.value = true;
4405 self.found = true;
4406 }
4407 TURBOPACK_EXPORT_NAMESPACE_SHORTCUT => {
4408 self.namespace = true;
4409 self.found = true;
4410 }
4411 _ => {}
4412 }
4413 }
4414
4415 n.visit_children_with(self);
4416 }
4417
4418 fn visit_stmt(&mut self, n: &Stmt) {
4419 if self.found {
4420 return;
4421 }
4422 n.visit_children_with(self);
4423 }
4424 }
4425
4426 let mut v = Visitor {
4427 cjs: false,
4428 value: false,
4429 namespace: false,
4430 found: false,
4431 };
4432 p.visit_with(&mut v);
4433 if v.cjs {
4434 DetectedDynamicExportType::CommonJs
4435 } else if v.value {
4436 DetectedDynamicExportType::Value
4437 } else if v.namespace {
4438 DetectedDynamicExportType::Namespace
4439 } else {
4440 DetectedDynamicExportType::None
4441 }
4442}
4443
4444fn is_invoking_node_process_eval(args: &[JsValue]) -> bool {
4449 if args.len() < 2 {
4450 return false;
4451 }
4452
4453 if let JsValue::Member(_, obj, constant) = &args[0] {
4454 if let (
4456 &box JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessArgv),
4457 &box JsValue::Constant(JsConstantValue::Num(ConstantNumber(num))),
4458 ) = (obj, constant)
4459 {
4460 if num.is_zero()
4462 && let JsValue::Array {
4463 total_nodes: _,
4464 items,
4465 mutable: _,
4466 } = &args[1]
4467 {
4468 if items.iter().any(|e| {
4470 if let JsValue::Constant(JsConstantValue::Str(ConstantString::Atom(arg))) = e {
4471 arg == "-e"
4472 } else {
4473 false
4474 }
4475 }) {
4476 return true;
4479 }
4480 }
4481 }
4482 }
4483
4484 false
4485}