Skip to main content

turbopack_ecmascript/references/
mod.rs

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