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