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