Skip to main content

turbopack_ecmascript/references/
mod.rs

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