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