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