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