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