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