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