Skip to main content

turbopack_ecmascript/references/
mod.rs

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