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