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