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