Skip to main content

rspack_plugin_javascript/visitors/dependency/parser/
mod.rs

1pub mod ast;
2mod call_hooks_name;
3pub mod estree;
4mod location_advancer;
5mod walk;
6mod walk_block_pre;
7mod walk_module_pre;
8mod walk_pre;
9
10use std::{
11  borrow::Cow,
12  fmt::Display,
13  hash::{Hash, Hasher},
14  rc::Rc,
15};
16
17use bitflags::bitflags;
18pub use call_hooks_name::CallHooksName;
19use rspack_cacheable::{
20  cacheable,
21  with::{AsCacheable, AsOption, AsPreset, AsVec},
22};
23use rspack_core::{
24  AsyncDependenciesBlock, BoxDependency, BoxDependencyTemplate, BuildInfo, BuildMeta,
25  CompilerOptions, DependencyLocation, DependencyRange, FactoryMeta, ImportMeta,
26  JavascriptParserCommonjsExportsOption, JavascriptParserOptions, ModuleIdentifier, ModuleLayer,
27  ModuleType, ParseMeta, ResourceData, SideEffectsBailoutItemWithSpan,
28};
29use rspack_error::{Diagnostic, Result};
30use rspack_util::{SpanExt, fx_hash::FxIndexSet};
31use rustc_hash::{FxHashMap, FxHashSet};
32use smallvec::SmallVec;
33use swc_core::{
34  atoms::Atom,
35  common::{BytePos, Mark, Span, Spanned, comments::Comments},
36  ecma::{
37    ast::{
38      ArrayPat, AssignPat, AssignTargetPat, CallExpr, Decl, Expr, Ident, Lit, MemberExpr,
39      MetaPropExpr, MetaPropKind, ObjectPat, ObjectPatProp, OptCall, OptChainBase, OptChainExpr,
40      Pat, Program, RestPat, Stmt, ThisExpr,
41    },
42    utils::ExprFactory,
43  },
44};
45
46use crate::{
47  BoxJavascriptParserPlugin,
48  dependency::{DependencyBranchGuard, local_module::LocalModule, set_dependency_branch_guards},
49  parser_and_generator::ParserRuntimeRequirementsData,
50  parser_plugin::{
51    self, ImportsReferencesState, InnerGraphParserPlugin, JavaScriptParserPluginDrive,
52    JavascriptParserPlugin, RequireReferencesState, inner_graph::state::InnerGraphState,
53  },
54  utils::eval::{self, BasicEvaluatedExpression},
55  visitors::{
56    ScanDependenciesResult,
57    dependency::parser::{ast::ExprRef, location_advancer::DependencyLocationAdvancer},
58    scope_info::{
59      ScopeInfoDB, ScopeInfoId, TagInfo, TagInfoId, VariableInfo, VariableInfoFlags, VariableInfoId,
60    },
61  },
62};
63
64pub trait TagInfoData: Clone + Sized + 'static {
65  fn into_any(data: Self) -> Box<dyn anymap::CloneAny>;
66
67  fn downcast(any: Box<dyn anymap::CloneAny>) -> Self;
68
69  fn downcast_ref(any: &dyn anymap::CloneAny) -> &Self;
70}
71
72impl<T> TagInfoData for T
73where
74  T: Clone + Sized + 'static,
75{
76  fn into_any(data: Self) -> Box<dyn anymap::CloneAny> {
77    Box::new(data)
78  }
79
80  fn downcast(any: Box<dyn anymap::CloneAny>) -> Self {
81    *(any as Box<dyn std::any::Any>)
82      .downcast()
83      .expect("TagInfoData should be downcasted from correct tag info")
84  }
85
86  fn downcast_ref(any: &dyn anymap::CloneAny) -> &Self {
87    let any = any as &dyn std::any::Any;
88    any
89      .downcast_ref()
90      .expect("TagInfoData should be downcasted from correct tag info")
91  }
92}
93
94// Most parsed member chains are one or two segments long, so keep them inline.
95pub type AtomMembers = SmallVec<[Atom; 2]>;
96pub type OptionalMembers = SmallVec<[bool; 2]>;
97pub type MemberRanges = SmallVec<[Span; 2]>;
98
99#[derive(Debug)]
100pub struct ExtractedMemberExpressionChainData<'ast> {
101  pub object: ExprRef<'ast>,
102  pub members: AtomMembers,
103  pub members_optionals: OptionalMembers,
104  pub member_ranges: MemberRanges,
105}
106
107bitflags! {
108  #[derive(Clone, Copy)]
109  pub struct AllowedMemberTypes: u8 {
110    const CallExpression = 1 << 0;
111    const Expression = 1 << 1;
112  }
113}
114
115#[derive(Debug)]
116pub enum MemberExpressionInfo<'ast> {
117  Call(CallExpressionInfo<'ast>),
118  Expression(ExpressionExpressionInfo),
119}
120
121#[derive(Debug)]
122pub struct CallExpressionInfo<'ast> {
123  pub call: &'ast CallExpr,
124  pub root_info: ExportedVariableInfo,
125  pub callee_members: AtomMembers,
126  pub members: AtomMembers,
127  pub members_optionals: OptionalMembers,
128  pub member_ranges: MemberRanges,
129}
130
131#[derive(Debug)]
132pub struct ExpressionExpressionInfo {
133  pub name: String,
134  pub root_info: ExportedVariableInfo,
135  pub members: AtomMembers,
136  pub members_optionals: OptionalMembers,
137  pub member_ranges: MemberRanges,
138}
139
140#[derive(Debug, Clone)]
141pub enum ExportedVariableInfo {
142  Name(Atom),
143  VariableInfo(VariableInfoId),
144}
145
146fn object_and_members_to_name(object: &Atom, members_reversed: &[impl AsRef<str>]) -> String {
147  let total_len = object.len()
148    + members_reversed.len()
149    + members_reversed
150      .iter()
151      .map(|m| m.as_ref().len())
152      .sum::<usize>();
153
154  let mut name = String::with_capacity(total_len);
155  name.push_str(object);
156  let iter = members_reversed.iter();
157  for member in iter.rev() {
158    name.push('.');
159    name.push_str(member.as_ref());
160  }
161  name
162}
163
164pub trait RootName {
165  fn get_root_name(&self) -> Option<Atom> {
166    None
167  }
168}
169
170impl RootName for Expr {
171  fn get_root_name(&self) -> Option<Atom> {
172    match self {
173      Expr::Ident(ident) => ident.get_root_name(),
174      Expr::This(this) => this.get_root_name(),
175      Expr::MetaProp(meta) => meta.get_root_name(),
176      _ => None,
177    }
178  }
179}
180
181impl RootName for ExprRef<'_> {
182  fn get_root_name(&self) -> Option<Atom> {
183    match self {
184      ExprRef::Ident(ident) => ident.get_root_name(),
185      ExprRef::This(this) => this.get_root_name(),
186      ExprRef::MetaProp(meta) => meta.get_root_name(),
187      _ => None,
188    }
189  }
190}
191
192impl RootName for ThisExpr {
193  fn get_root_name(&self) -> Option<Atom> {
194    Some("this".into())
195  }
196}
197
198impl RootName for Ident {
199  fn get_root_name(&self) -> Option<Atom> {
200    Some(self.sym.clone())
201  }
202}
203
204impl RootName for MetaPropExpr {
205  fn get_root_name(&self) -> Option<Atom> {
206    match self.kind {
207      MetaPropKind::NewTarget => Some("new.target".into()),
208      MetaPropKind::ImportMeta => Some("import.meta".into()),
209    }
210  }
211}
212
213pub struct NameInfo<'a> {
214  pub name: &'a Atom,
215  pub info: Option<&'a VariableInfo>,
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq)]
219pub enum ScopeTerminated {
220  Return,
221  Throw,
222}
223
224#[derive(Clone, Copy, Debug)]
225pub enum TopLevelScope {
226  Top,
227  ArrowFunction,
228  False,
229}
230
231#[derive(Debug, Clone, Copy)]
232pub struct StatementPath {
233  span: Span,
234}
235
236impl Spanned for StatementPath {
237  fn span(&self) -> Span {
238    self.span
239  }
240}
241
242impl StatementPath {
243  fn from_span(span: Span) -> Self {
244    Self { span }
245  }
246}
247
248impl From<Span> for StatementPath {
249  fn from(value: Span) -> Self {
250    Self::from_span(value)
251  }
252}
253
254#[cacheable]
255#[derive(Debug, Clone, Hash, PartialEq, Eq)]
256pub struct DestructuringAssignmentProperty {
257  pub range: DependencyRange,
258  #[cacheable(with=AsPreset)]
259  pub id: Atom,
260  #[cacheable(omit_bounds, with=AsOption<AsCacheable>)]
261  pub pattern: Option<DestructuringAssignmentProperties>,
262  pub shorthand: bool,
263}
264
265#[cacheable]
266#[derive(Debug, Default, Clone, PartialEq, Eq)]
267pub struct DestructuringAssignmentProperties {
268  #[cacheable(with=AsVec<AsCacheable>)]
269  inner: FxIndexSet<DestructuringAssignmentProperty>,
270}
271
272impl Hash for DestructuringAssignmentProperties {
273  fn hash<H: Hasher>(&self, state: &mut H) {
274    for prop in &self.inner {
275      prop.hash(state);
276    }
277  }
278}
279
280impl DestructuringAssignmentProperties {
281  pub fn new(properties: FxIndexSet<DestructuringAssignmentProperty>) -> Self {
282    Self { inner: properties }
283  }
284
285  pub fn insert(&mut self, prop: DestructuringAssignmentProperty) -> bool {
286    self.inner.insert(prop)
287  }
288
289  pub fn extend(&mut self, other: Self) {
290    self.inner.extend(other.inner);
291  }
292
293  pub fn iter(&self) -> impl Iterator<Item = &DestructuringAssignmentProperty> {
294    self.inner.iter()
295  }
296
297  pub fn traverse_on_leaf<'a, F>(&'a self, on_leaf_node: &mut F)
298  where
299    F: FnMut(&mut Vec<&'a DestructuringAssignmentProperty>),
300  {
301    self.traverse_impl(on_leaf_node, &mut |_| {}, &mut Vec::new());
302  }
303
304  pub fn traverse_on_enter<'a, F>(&'a self, on_enter_node: &mut F)
305  where
306    F: FnMut(&mut Vec<&'a DestructuringAssignmentProperty>),
307  {
308    self.traverse_impl(&mut |_| {}, on_enter_node, &mut Vec::new());
309  }
310
311  fn traverse_impl<'a, L, E>(
312    &'a self,
313    on_leaf_node: &mut L,
314    on_enter_node: &mut E,
315    stack: &mut Vec<&'a DestructuringAssignmentProperty>,
316  ) where
317    L: FnMut(&mut Vec<&'a DestructuringAssignmentProperty>),
318    E: FnMut(&mut Vec<&'a DestructuringAssignmentProperty>),
319  {
320    for prop in &self.inner {
321      stack.push(prop);
322      on_enter_node(stack);
323      if let Some(pattern) = &prop.pattern {
324        pattern.traverse_impl(on_leaf_node, on_enter_node, stack);
325      } else {
326        on_leaf_node(stack);
327      }
328      stack.pop();
329    }
330  }
331}
332
333#[derive(Debug, Default)]
334pub struct DestructuringAssignmentPropertiesMap {
335  inner: FxHashMap<Span, DestructuringAssignmentProperties>,
336}
337
338impl DestructuringAssignmentPropertiesMap {
339  pub fn add(&mut self, span: Span, props: DestructuringAssignmentProperties) {
340    self.inner.entry(span).or_default().extend(props)
341  }
342
343  pub fn get(&self, span: &Span) -> Option<&DestructuringAssignmentProperties> {
344    self.inner.get(span)
345  }
346}
347
348pub struct JavascriptParser<'parser> {
349  // ===== results =======
350  errors: Vec<Diagnostic>,
351  warning_diagnostics: Vec<Diagnostic>,
352  dependencies: Vec<BoxDependency>,
353  presentational_dependencies: Vec<BoxDependencyTemplate>,
354  // Vec<Box<T: Sized>> makes sense if T is a large type (see #3530, 1st comment).
355  // #3530: https://github.com/rust-lang/rust-clippy/issues/3530
356  #[allow(clippy::vec_box)]
357  blocks: Vec<Box<AsyncDependenciesBlock>>,
358  // ===== inputs =======
359  pub(crate) source: &'parser str,
360  pub parse_meta: ParseMeta,
361  pub comments: Option<&'parser dyn Comments>,
362  pub factory_meta: Option<&'parser FactoryMeta>,
363  pub build_meta: &'parser mut BuildMeta,
364  pub build_info: &'parser mut BuildInfo,
365  pub resource_data: &'parser ResourceData,
366  pub(crate) compiler_options: &'parser CompilerOptions,
367  pub(crate) javascript_options: &'parser JavascriptParserOptions,
368  pub parser_runtime_requirements: &'parser ParserRuntimeRequirementsData,
369  pub module_type: &'parser ModuleType,
370  pub(crate) module_layer: Option<&'parser ModuleLayer>,
371  pub module_identifier: &'parser ModuleIdentifier,
372  pub(crate) plugin_drive: Rc<JavaScriptParserPluginDrive>,
373  // ===== states =======
374  pub(crate) definitions_db: ScopeInfoDB,
375  pub(crate) definitions: ScopeInfoId,
376  pub(crate) top_level_scope: TopLevelScope,
377  pub(crate) current_tag_info: Option<TagInfoId>,
378  pub in_try: bool,
379  pub(crate) terminated: Option<ScopeTerminated>,
380  pub(crate) in_short_hand: bool,
381  pub(crate) in_tagged_template_tag: bool,
382  pub(crate) member_expr_in_optional_chain: bool,
383  pub(crate) semicolons: &'parser mut FxHashSet<BytePos>,
384  pub(crate) statement_path: Vec<StatementPath>,
385  pub(crate) prev_statement: Option<StatementPath>,
386  pub is_esm: bool,
387  pub(crate) destructuring_assignment_properties: DestructuringAssignmentPropertiesMap,
388  pub(crate) dynamic_import_references: ImportsReferencesState,
389  pub(crate) common_js_require_references: RequireReferencesState,
390  pub(crate) worker_index: u32,
391  pub(crate) parser_exports_state: Option<bool>,
392  pub(crate) local_modules: Vec<LocalModule>,
393  pub(crate) last_esm_import_order: i32,
394  pub(crate) inner_graph: InnerGraphState,
395  pub(crate) side_effects_item: Option<SideEffectsBailoutItemWithSpan>,
396  pub(crate) is_renaming: Option<Atom>,
397  pub(crate) location_advancer: DependencyLocationAdvancer,
398  pub(crate) collecting_dependencies_for_block: Option<usize>,
399  pub(crate) dependency_branch_guards: Vec<DependencyBranchGuard>,
400}
401
402impl<'parser> JavascriptParser<'parser> {
403  #[allow(clippy::too_many_arguments)]
404  pub fn new(
405    source: &'parser str,
406    compiler_options: &'parser CompilerOptions,
407    javascript_options: &'parser JavascriptParserOptions,
408    comments: Option<&'parser dyn Comments>,
409    module_identifier: &'parser ModuleIdentifier,
410    module_type: &'parser ModuleType,
411    module_layer: Option<&'parser ModuleLayer>,
412    resource_data: &'parser ResourceData,
413    factory_meta: Option<&'parser FactoryMeta>,
414    build_meta: &'parser mut BuildMeta,
415    build_info: &'parser mut BuildInfo,
416    semicolons: &'parser mut FxHashSet<BytePos>,
417    unresolved_mark: Mark,
418    parser_plugins: &'parser mut Vec<BoxJavascriptParserPlugin>,
419    parse_meta: ParseMeta,
420    parser_runtime_requirements: &'parser ParserRuntimeRequirementsData,
421  ) -> Self {
422    let warning_diagnostics: Vec<Diagnostic> = Vec::with_capacity(4);
423    let errors = Vec::with_capacity(4);
424    let dependencies = Vec::with_capacity(64);
425    let blocks = Vec::with_capacity(64);
426    let presentational_dependencies = Vec::with_capacity(64);
427    let parser_exports_state: Option<bool> = None;
428
429    let mut plugins: Vec<BoxJavascriptParserPlugin> = Vec::with_capacity(32 + parser_plugins.len());
430
431    plugins.append(parser_plugins);
432
433    plugins.push(Box::new(parser_plugin::InitializeEvaluating));
434    plugins.push(Box::new(parser_plugin::JavascriptMetaInfoPlugin));
435    plugins.push(Box::new(parser_plugin::ConstPlugin));
436    plugins.push(Box::new(parser_plugin::UseStrictPlugin));
437
438    if matches!(module_type, ModuleType::JsAuto | ModuleType::JsDynamic) {
439      plugins.push(Box::new(
440        parser_plugin::RequireContextDependencyParserPlugin,
441      ));
442      plugins.push(Box::new(
443        parser_plugin::RequireEnsureDependenciesBlockParserPlugin,
444      ));
445    }
446    plugins.push(Box::new(parser_plugin::CompatibilityPlugin));
447
448    if module_type.is_js_auto() || module_type.is_js_esm() {
449      plugins.push(Box::new(parser_plugin::ESMTopLevelThisParserPlugin));
450      plugins.push(Box::<parser_plugin::ESMDetectionParserPlugin>::default());
451      plugins.push(Box::new(
452        parser_plugin::ImportMetaContextDependencyParserPlugin,
453      ));
454      if matches!(
455        javascript_options.import_meta,
456        Some(ImportMeta::Enabled | ImportMeta::PreserveUnknown)
457      ) {
458        plugins.push(Box::new(parser_plugin::ImportMetaPlugin(
459          javascript_options.import_meta.expect("should have value"),
460        )));
461      } else {
462        plugins.push(Box::new(parser_plugin::ImportMetaDisabledPlugin));
463      }
464
465      plugins.push(Box::new(parser_plugin::ESMImportDependencyParserPlugin));
466      plugins.push(Box::new(parser_plugin::ESMExportDependencyParserPlugin));
467    }
468
469    if compiler_options.amd.is_some() && (module_type.is_js_auto() || module_type.is_js_dynamic()) {
470      plugins.push(Box::new(
471        parser_plugin::AMDRequireDependenciesBlockParserPlugin,
472      ));
473      plugins.push(Box::new(parser_plugin::AMDDefineDependencyParserPlugin));
474      plugins.push(Box::new(parser_plugin::AMDParserPlugin));
475    }
476
477    if module_type.is_js_auto() || module_type.is_js_dynamic() {
478      plugins.push(Box::new(parser_plugin::CommonJsImportsParserPlugin));
479      plugins.push(Box::new(parser_plugin::CommonJsPlugin));
480      let commonjs_exports = javascript_options
481        .commonjs
482        .as_ref()
483        .map_or(JavascriptParserCommonjsExportsOption::Enable, |commonjs| {
484          commonjs.exports
485        });
486      if commonjs_exports != JavascriptParserCommonjsExportsOption::Disable {
487        plugins.push(Box::new(parser_plugin::CommonJsExportsParserPlugin::new(
488          commonjs_exports == JavascriptParserCommonjsExportsOption::SkipInEsm,
489        )));
490      }
491    }
492
493    // NodeStuffPlugin: handle __dirname/__filename/global (CJS) and import.meta.dirname/filename (ESM)
494    // CJS features require node options; ESM features are always available for ESM-capable modules
495    let handle_cjs =
496      (module_type.is_js_auto() || module_type.is_js_dynamic()) && compiler_options.node.is_some();
497    let handle_esm = module_type.is_js_auto() || module_type.is_js_esm();
498    if handle_cjs || handle_esm {
499      plugins.push(Box::new(parser_plugin::NodeStuffPlugin::new(
500        handle_cjs, handle_esm,
501      )));
502    }
503
504    if module_type.is_js_auto() || module_type.is_js_dynamic() || module_type.is_js_esm() {
505      plugins.push(Box::new(parser_plugin::IsIncludedPlugin));
506      plugins.push(Box::new(parser_plugin::ExportsInfoApiPlugin));
507      plugins.push(Box::new(parser_plugin::APIPlugin::new(
508        compiler_options.output.module,
509      )));
510      plugins.push(Box::new(parser_plugin::ImportParserPlugin));
511      plugins.push(Box::new(parser_plugin::WorkerPlugin::new(
512        javascript_options
513          .worker
514          .as_ref()
515          .expect("should have worker"),
516      )));
517      plugins.push(Box::new(parser_plugin::OverrideStrictPlugin));
518    }
519
520    if compiler_options.optimization.inline_exports {
521      build_info.inline_exports = true;
522      plugins.push(Box::new(parser_plugin::InlineConstPlugin));
523    }
524    if compiler_options.optimization.inner_graph {
525      plugins.push(Box::new(parser_plugin::InnerGraphParserPlugin::new(
526        unresolved_mark,
527        compiler_options.experiments.pure_functions,
528      )));
529    }
530
531    if compiler_options.optimization.side_effects.is_true() {
532      plugins.push(Box::new(parser_plugin::SideEffectsParserPlugin::new(
533        unresolved_mark,
534        compiler_options.experiments.pure_functions,
535      )));
536    }
537
538    let plugin_drive = Rc::new(JavaScriptParserPluginDrive::new(plugins));
539    let mut db = ScopeInfoDB::new();
540
541    Self {
542      last_esm_import_order: 0,
543      comments,
544      javascript_options,
545      source,
546      errors,
547      warning_diagnostics,
548      dependencies,
549      presentational_dependencies,
550      blocks,
551      in_try: false,
552      terminated: None,
553      in_short_hand: false,
554      top_level_scope: TopLevelScope::Top,
555      is_esm: matches!(module_type, ModuleType::JsEsm),
556      in_tagged_template_tag: false,
557      definitions: db.create(),
558      definitions_db: db,
559      plugin_drive,
560      resource_data,
561      factory_meta,
562      build_meta,
563      build_info,
564      compiler_options,
565      module_type,
566      module_layer,
567      parser_exports_state,
568      worker_index: 0,
569      module_identifier,
570      member_expr_in_optional_chain: false,
571      destructuring_assignment_properties: Default::default(),
572      dynamic_import_references: Default::default(),
573      common_js_require_references: Default::default(),
574      semicolons,
575      statement_path: Default::default(),
576      current_tag_info: None,
577      prev_statement: None,
578      inner_graph: InnerGraphState::new(),
579      parse_meta,
580      local_modules: Default::default(),
581      side_effects_item: None,
582      parser_runtime_requirements,
583      is_renaming: None,
584      location_advancer: DependencyLocationAdvancer::new(),
585      collecting_dependencies_for_block: None,
586      dependency_branch_guards: Vec::new(),
587    }
588  }
589
590  pub fn into_results(mut self) -> Result<ScanDependenciesResult, Vec<Diagnostic>> {
591    if self.errors.is_empty() {
592      InnerGraphParserPlugin::finalize_dependency_usage(
593        &mut self.inner_graph,
594        &mut self.dependencies,
595      );
596      Ok(ScanDependenciesResult {
597        dependencies: self.dependencies,
598        blocks: self.blocks,
599        presentational_dependencies: self.presentational_dependencies,
600        warning_diagnostics: self.warning_diagnostics,
601        side_effects_item: self.side_effects_item,
602      })
603    } else {
604      Err(self.errors)
605    }
606  }
607
608  pub fn add_dependency(&mut self, mut dep: BoxDependency) {
609    if !self.dependency_branch_guards.is_empty() {
610      set_dependency_branch_guards(dep.as_mut(), &self.dependency_branch_guards);
611    }
612    self.dependencies.push(dep);
613  }
614
615  pub fn add_dependencies(&mut self, deps: impl IntoIterator<Item = BoxDependency>) {
616    if self.dependency_branch_guards.is_empty() {
617      self.dependencies.extend(deps);
618    } else {
619      let branch_guards = self.dependency_branch_guards.clone();
620      self.dependencies.extend(deps.into_iter().map(|mut dep| {
621        set_dependency_branch_guards(dep.as_mut(), &branch_guards);
622        dep
623      }));
624    }
625  }
626
627  pub fn pop_dependency(&mut self) -> Option<BoxDependency> {
628    self.dependencies.pop()
629  }
630
631  pub fn next_dependency_idx(&self) -> usize {
632    self.dependencies.len()
633  }
634
635  pub fn get_dependencies(&self) -> &[BoxDependency] {
636    &self.dependencies
637  }
638
639  pub fn get_dependency_mut(&mut self, idx: usize) -> Option<&mut BoxDependency> {
640    self.dependencies.get_mut(idx)
641  }
642
643  pub fn collect_dependencies_for_block(
644    &mut self,
645    block_idx: usize,
646    deps: Vec<BoxDependency>,
647    f: impl FnOnce(&mut JavascriptParser),
648  ) -> Vec<BoxDependency> {
649    let old_deps = std::mem::replace(&mut self.dependencies, deps);
650    let old_block_idx = self.collecting_dependencies_for_block.replace(block_idx);
651    f(self);
652    self.collecting_dependencies_for_block = old_block_idx;
653    std::mem::replace(&mut self.dependencies, old_deps)
654  }
655
656  pub fn add_presentational_dependency(&mut self, dep: BoxDependencyTemplate) {
657    self.presentational_dependencies.push(dep);
658  }
659
660  pub fn add_presentational_dependencies(
661    &mut self,
662    deps: impl IntoIterator<Item = BoxDependencyTemplate>,
663  ) {
664    self.presentational_dependencies.extend(deps);
665  }
666
667  pub fn next_presentational_dependency_idx(&self) -> usize {
668    self.presentational_dependencies.len()
669  }
670
671  pub fn get_presentational_dependency_mut(
672    &mut self,
673    idx: usize,
674  ) -> Option<&mut BoxDependencyTemplate> {
675    self.presentational_dependencies.get_mut(idx)
676  }
677
678  pub fn add_block(&mut self, mut block: Box<AsyncDependenciesBlock>) {
679    if !self.dependency_branch_guards.is_empty() {
680      for dep in block.dependencies_mut() {
681        set_dependency_branch_guards(dep.as_mut(), &self.dependency_branch_guards);
682      }
683    }
684    self.blocks.push(block);
685  }
686
687  pub fn next_block_idx(&self) -> usize {
688    self.blocks.len()
689  }
690
691  pub fn get_block_mut(&mut self, idx: usize) -> Option<&mut Box<AsyncDependenciesBlock>> {
692    self.blocks.get_mut(idx)
693  }
694
695  pub fn add_error(&mut self, error: Diagnostic) {
696    self.errors.push(error);
697  }
698
699  pub fn add_warning(&mut self, warning: Diagnostic) {
700    self.warning_diagnostics.push(warning);
701  }
702
703  pub fn add_warnings(&mut self, warnings: impl IntoIterator<Item = Diagnostic>) {
704    self.warning_diagnostics.extend(warnings);
705  }
706
707  pub fn source(&self) -> &str {
708    self.source
709  }
710
711  pub fn is_top_level_scope(&self) -> bool {
712    matches!(self.top_level_scope, TopLevelScope::Top)
713  }
714
715  pub fn is_top_level_this(&self) -> bool {
716    !matches!(self.top_level_scope, TopLevelScope::False)
717  }
718
719  pub fn add_local_module(&mut self, name: &Atom, dep_idx: usize) {
720    self.local_modules.push(LocalModule::new(
721      name.clone(),
722      self.local_modules.len(),
723      dep_idx,
724    ));
725  }
726
727  pub fn get_local_module_mut(&mut self, name: &str) -> Option<&mut LocalModule> {
728    self.local_modules.iter_mut().find(|m| m.get_name() == name)
729  }
730
731  pub fn is_asi_position(&self, pos: BytePos) -> bool {
732    let curr_path = self.statement_path.last().expect("Should in statement");
733    if curr_path.span_hi() == pos && self.semicolons.contains(&pos) {
734      true
735    } else if curr_path.span_lo() == pos
736      && let Some(prev) = &self.prev_statement
737      && self.semicolons.contains(&prev.span_hi())
738    {
739      true
740    } else {
741      false
742    }
743  }
744
745  pub fn set_asi_position(&mut self, pos: BytePos) -> bool {
746    self.semicolons.insert(pos)
747  }
748
749  pub fn unset_asi_position(&mut self, pos: BytePos) -> bool {
750    self.semicolons.remove(&pos)
751  }
752
753  pub fn is_statement_level_expression(&self, expr_span: Span) -> bool {
754    let Some(curr_path) = self.statement_path.last() else {
755      return false;
756    };
757    curr_path.span() == expr_span
758  }
759
760  pub fn get_module_layer(&self) -> Option<&ModuleLayer> {
761    self.module_layer
762  }
763
764  pub fn get_variable_info(&mut self, name: &Atom) -> Option<&VariableInfo> {
765    let id = self.definitions_db.get(self.definitions, name)?;
766    Some(self.definitions_db.expect_get_variable(id))
767  }
768
769  fn get_tag_data_by_id<Data: TagInfoData>(
770    &self,
771    tag_info_id: TagInfoId,
772    tag: &'static str,
773  ) -> Option<&Data> {
774    let mut tag_info = Some(self.definitions_db.expect_get_tag_info(tag_info_id));
775
776    while let Some(cur_tag_info) = tag_info {
777      if cur_tag_info.tag == tag {
778        return cur_tag_info
779          .data
780          .as_deref()
781          .map(|data| TagInfoData::downcast_ref(data));
782      }
783      tag_info = cur_tag_info
784        .next
785        .map(|tag_info_id| self.definitions_db.expect_get_tag_info(tag_info_id))
786    }
787
788    None
789  }
790
791  pub fn get_tag_data<Data: TagInfoData>(
792    &mut self,
793    name: &Atom,
794    tag: &'static str,
795  ) -> Option<&Data> {
796    self
797      .get_variable_info(name)
798      .and_then(|variable_info| variable_info.tag_info)
799      .and_then(|tag_info_id| self.get_tag_data_by_id(tag_info_id, tag))
800  }
801
802  pub fn get_variable_tag_data<Data: TagInfoData>(
803    &self,
804    id: VariableInfoId,
805    tag: &'static str,
806  ) -> Option<&Data> {
807    self
808      .definitions_db
809      .expect_get_variable(id)
810      .tag_info
811      .and_then(|tag_info_id| self.get_tag_data_by_id(tag_info_id, tag))
812  }
813
814  pub fn get_free_info_from_variable<'a>(&'a mut self, name: &'a Atom) -> Option<NameInfo<'a>> {
815    let Some(info) = self.get_variable_info(name) else {
816      return Some(NameInfo { name, info: None });
817    };
818    let Some(name) = &info.name else {
819      return None;
820    };
821    if !info.is_free() {
822      return None;
823    }
824    Some(NameInfo {
825      name,
826      info: Some(info),
827    })
828  }
829
830  pub fn get_name_info_from_variable<'a>(&'a mut self, name: &'a Atom) -> Option<NameInfo<'a>> {
831    let Some(info) = self.get_variable_info(name) else {
832      return Some(NameInfo { name, info: None });
833    };
834    let Some(name) = &info.name else {
835      return None;
836    };
837    if !info.is_free() && !info.is_tagged() {
838      return None;
839    }
840    Some(NameInfo {
841      name,
842      info: Some(info),
843    })
844  }
845
846  pub fn get_all_variables_from_current_scope(
847    &self,
848  ) -> impl Iterator<Item = (&str, &VariableInfoId)> {
849    let scope = self.definitions_db.expect_get_scope(self.definitions);
850    scope.variables()
851  }
852
853  pub fn define_variable(&mut self, name: Atom) {
854    let definitions = self.definitions;
855    if let Some(variable_info) = self.get_variable_info(&name)
856      && variable_info.tag_info.is_some()
857      && definitions == variable_info.declared_scope
858    {
859      return;
860    }
861    let info = VariableInfo::create(
862      &mut self.definitions_db,
863      definitions,
864      None,
865      VariableInfoFlags::NORMAL,
866      None,
867    );
868    self.definitions_db.set(definitions, name, info);
869  }
870
871  pub fn set_variable(&mut self, name: Atom, variable: ExportedVariableInfo) {
872    let scope_id = self.definitions;
873    match variable {
874      ExportedVariableInfo::Name(variable) => {
875        if name == variable {
876          self.definitions_db.delete(scope_id, &name);
877        } else {
878          let variable = VariableInfo::create(
879            &mut self.definitions_db,
880            scope_id,
881            Some(variable),
882            VariableInfoFlags::FREE,
883            None,
884          );
885          self.definitions_db.set(scope_id, name, variable);
886        }
887      }
888      ExportedVariableInfo::VariableInfo(variable) => {
889        self.definitions_db.set(scope_id, name, variable);
890      }
891    }
892  }
893
894  fn undefined_variable(&mut self, name: &Atom) {
895    self.definitions_db.delete(self.definitions, name)
896  }
897
898  pub fn tag_variable<Data: TagInfoData>(
899    &mut self,
900    name: Atom,
901    tag: &'static str,
902    data: Option<Data>,
903  ) {
904    self.tag_variable_impl(name, tag, data, None);
905  }
906
907  pub fn tag_variable_with_flags<Data: TagInfoData>(
908    &mut self,
909    name: Atom,
910    tag: &'static str,
911    data: Option<Data>,
912    flags: VariableInfoFlags,
913  ) {
914    self.tag_variable_impl(name, tag, data, Some(flags));
915  }
916
917  fn tag_variable_impl<Data: TagInfoData>(
918    &mut self,
919    name: Atom,
920    tag: &'static str,
921    data: Option<Data>,
922    flags: Option<VariableInfoFlags>,
923  ) {
924    let flags = flags.unwrap_or(VariableInfoFlags::TAGGED);
925    let data = data.map(|data| TagInfoData::into_any(data));
926    let new_info = if let Some(old_info_id) = self.definitions_db.get(self.definitions, &name) {
927      let old_info = self.definitions_db.expect_get_variable(old_info_id);
928      if let Some(old_tag_info) = old_info.tag_info {
929        let declared_scope = old_info.declared_scope;
930        // FIXME: remove `.clone`
931        let name = old_info.name.clone();
932        let flags = old_info.flags | flags;
933        let tag_info = Some(TagInfo::create(
934          &mut self.definitions_db,
935          tag,
936          data,
937          Some(old_tag_info),
938        ));
939        VariableInfo::create(
940          &mut self.definitions_db,
941          declared_scope,
942          name,
943          flags,
944          tag_info,
945        )
946      } else {
947        let declared_scope = old_info.declared_scope;
948        let tag_info = Some(TagInfo::create(&mut self.definitions_db, tag, data, None));
949        VariableInfo::create(
950          &mut self.definitions_db,
951          declared_scope,
952          Some(name.clone()),
953          flags,
954          tag_info,
955        )
956      }
957    } else {
958      let tag_info = Some(TagInfo::create(&mut self.definitions_db, tag, data, None));
959      VariableInfo::create(
960        &mut self.definitions_db,
961        self.definitions,
962        Some(name.clone()),
963        flags,
964        tag_info,
965      )
966    };
967    self.definitions_db.set(self.definitions, name, new_info);
968  }
969
970  fn _get_member_expression_info<'ast>(
971    &mut self,
972    object: ExprRef<'ast>,
973    mut members: AtomMembers,
974    mut members_optionals: OptionalMembers,
975    mut member_ranges: MemberRanges,
976    allowed_types: AllowedMemberTypes,
977  ) -> Option<MemberExpressionInfo<'ast>> {
978    match object {
979      ExprRef::Call(expr) => {
980        if !allowed_types.contains(AllowedMemberTypes::CallExpression) {
981          return None;
982        }
983        let callee = expr.callee.as_expr()?;
984        let (root_name, mut root_members) = if let Some(member) = callee.as_member() {
985          let extracted = self.extract_member_expression_chain(ExprRef::Member(member));
986          let root_name = extracted.object.get_root_name()?;
987          (root_name, extracted.members)
988        } else {
989          (callee.get_root_name()?, AtomMembers::new())
990        };
991        let NameInfo {
992          info: root_info, ..
993        } = self.get_name_info_from_variable(&root_name)?;
994
995        root_members.reverse();
996        members.reverse();
997        members_optionals.reverse();
998        member_ranges.reverse();
999        let root_name_for_info = root_name.clone();
1000        Some(MemberExpressionInfo::Call(CallExpressionInfo {
1001          call: expr,
1002          root_info: root_info.map_or_else(
1003            || ExportedVariableInfo::Name(root_name_for_info),
1004            |i| ExportedVariableInfo::VariableInfo(i.id()),
1005          ),
1006          callee_members: root_members,
1007          members,
1008          members_optionals,
1009          member_ranges,
1010        }))
1011      }
1012      ExprRef::MetaProp(_) | ExprRef::Ident(_) | ExprRef::This(_) => {
1013        if !allowed_types.contains(AllowedMemberTypes::Expression) {
1014          return None;
1015        }
1016        let root_name = object.get_root_name()?;
1017
1018        let NameInfo {
1019          name: resolved_root,
1020          info: root_info,
1021        } = self.get_name_info_from_variable(&root_name)?;
1022
1023        let name = object_and_members_to_name(resolved_root, &members);
1024        members.reverse();
1025        members_optionals.reverse();
1026        member_ranges.reverse();
1027        let root_name_for_info = root_name.clone();
1028        Some(MemberExpressionInfo::Expression(ExpressionExpressionInfo {
1029          name,
1030          root_info: root_info.map_or_else(
1031            || ExportedVariableInfo::Name(root_name_for_info),
1032            |i| ExportedVariableInfo::VariableInfo(i.id()),
1033          ),
1034          members,
1035          members_optionals,
1036          member_ranges,
1037        }))
1038      }
1039      _ => None,
1040    }
1041  }
1042
1043  pub fn get_member_expression_info_from_expr<'ast>(
1044    &mut self,
1045    expr: &'ast Expr,
1046    allowed_types: AllowedMemberTypes,
1047  ) -> Option<MemberExpressionInfo<'ast>> {
1048    match expr {
1049      Expr::Member(_) | Expr::OptChain(_) => {
1050        self.get_member_expression_info(expr.into(), allowed_types)
1051      }
1052      _ => self._get_member_expression_info(
1053        expr.into(),
1054        AtomMembers::new(),
1055        OptionalMembers::new(),
1056        MemberRanges::new(),
1057        allowed_types,
1058      ),
1059    }
1060  }
1061
1062  pub fn get_member_expression_info<'ast>(
1063    &mut self,
1064    expr: ExprRef<'ast>,
1065    allowed_types: AllowedMemberTypes,
1066  ) -> Option<MemberExpressionInfo<'ast>> {
1067    let ExtractedMemberExpressionChainData {
1068      object,
1069      members,
1070      members_optionals,
1071      member_ranges,
1072    } = self.extract_member_expression_chain(expr);
1073    self._get_member_expression_info(
1074      object,
1075      members,
1076      members_optionals,
1077      member_ranges,
1078      allowed_types,
1079    )
1080  }
1081
1082  pub fn extract_member_expression_chain<'ast>(
1083    &self,
1084    expr: ExprRef<'ast>,
1085  ) -> ExtractedMemberExpressionChainData<'ast> {
1086    let mut object = expr;
1087    let mut members = AtomMembers::new();
1088    let mut members_optionals = OptionalMembers::new();
1089    let mut member_ranges = MemberRanges::new();
1090    let mut in_optional_chain = self.member_expr_in_optional_chain;
1091    loop {
1092      match object {
1093        ExprRef::Member(expr) => {
1094          if let Some(computed) = expr.prop.as_computed() {
1095            let Expr::Lit(lit) = &*computed.expr else {
1096              break;
1097            };
1098            let value = match lit {
1099              Lit::Str(s) => s.value.clone(),
1100              Lit::Bool(b) => if b.value { "true" } else { "false" }.into(),
1101              Lit::Null(_) => "null".into(),
1102              Lit::Num(n) => n.value.to_string().into(),
1103              Lit::BigInt(i) => i.value.to_string().into(),
1104              Lit::Regex(r) => r.exp.clone().into(),
1105              Lit::JSXText(_) => unreachable!(),
1106            };
1107            // Since members are not used across rspack javascript parser plugin,
1108            // we directly makes it atom here
1109            members.push(value.to_atom_lossy().into_owned());
1110            member_ranges.push(expr.obj.span());
1111          } else if let Some(ident) = expr.prop.as_ident() {
1112            members.push(ident.sym.clone());
1113            member_ranges.push(expr.obj.span());
1114          } else {
1115            break;
1116          }
1117          members_optionals.push(in_optional_chain);
1118          object = expr.obj.as_ref().into();
1119          in_optional_chain = false;
1120        }
1121        ExprRef::OptChain(expr) => {
1122          in_optional_chain = expr.optional;
1123          if let OptChainBase::Member(member) = expr.base.as_ref() {
1124            object = ExprRef::Member(member);
1125          } else {
1126            break;
1127          }
1128        }
1129        _ => break,
1130      }
1131    }
1132    ExtractedMemberExpressionChainData {
1133      object,
1134      members,
1135      members_optionals,
1136      member_ranges,
1137    }
1138  }
1139
1140  fn enter_ident<F>(&mut self, ident: &Ident, on_ident: F)
1141  where
1142    F: FnOnce(&mut Self, &Ident),
1143  {
1144    let drive = self.plugin_drive.clone();
1145    if !ident
1146      .sym
1147      .call_hooks_name(self, |parser, for_name| {
1148        drive.pattern(parser, ident, for_name)
1149      })
1150      .unwrap_or_default()
1151    {
1152      on_ident(self, ident);
1153    }
1154  }
1155
1156  fn enter_array_pattern<F>(&mut self, array_pat: &ArrayPat, on_ident: F)
1157  where
1158    F: FnOnce(&mut Self, &Ident) + Copy,
1159  {
1160    array_pat
1161      .elems
1162      .iter()
1163      .flatten()
1164      .for_each(|ele| self.enter_pattern(Cow::Borrowed(ele), on_ident));
1165  }
1166
1167  fn enter_assignment_pattern<F>(&mut self, assign: &AssignPat, on_ident: F)
1168  where
1169    F: FnOnce(&mut Self, &Ident) + Copy,
1170  {
1171    self.enter_pattern(Cow::Borrowed(&assign.left), on_ident);
1172  }
1173
1174  fn enter_object_pattern<F>(&mut self, obj: &ObjectPat, on_ident: F)
1175  where
1176    F: FnOnce(&mut Self, &Ident) + Copy,
1177  {
1178    for prop in &obj.props {
1179      match prop {
1180        ObjectPatProp::KeyValue(kv) => self.enter_pattern(Cow::Borrowed(&kv.value), on_ident),
1181        ObjectPatProp::Assign(assign) => {
1182          let old = self.in_short_hand;
1183          if assign.value.is_none() {
1184            self.in_short_hand = true;
1185          }
1186          self.enter_ident(&assign.key, on_ident);
1187          self.in_short_hand = old;
1188        }
1189        ObjectPatProp::Rest(rest) => self.enter_rest_pattern(rest, on_ident),
1190      }
1191    }
1192  }
1193
1194  fn enter_rest_pattern<F>(&mut self, rest: &RestPat, on_ident: F)
1195  where
1196    F: FnOnce(&mut Self, &Ident) + Copy,
1197  {
1198    self.enter_pattern(Cow::Borrowed(&rest.arg), on_ident)
1199  }
1200
1201  fn enter_pattern<F>(&mut self, pattern: Cow<Pat>, on_ident: F)
1202  where
1203    F: FnOnce(&mut Self, &Ident) + Copy,
1204  {
1205    match &*pattern {
1206      Pat::Ident(ident) => self.enter_ident(&ident.id, on_ident),
1207      Pat::Array(array) => self.enter_array_pattern(array, on_ident),
1208      Pat::Assign(assign) => self.enter_assignment_pattern(assign, on_ident),
1209      Pat::Object(obj) => self.enter_object_pattern(obj, on_ident),
1210      Pat::Rest(rest) => self.enter_rest_pattern(rest, on_ident),
1211      Pat::Invalid(_) => (),
1212      Pat::Expr(_) => (),
1213    }
1214  }
1215
1216  fn enter_assign_target_pattern<F>(&mut self, pattern: Cow<AssignTargetPat>, on_ident: F)
1217  where
1218    F: FnOnce(&mut Self, &Ident) + Copy,
1219  {
1220    match &*pattern {
1221      AssignTargetPat::Array(array) => self.enter_array_pattern(array, on_ident),
1222      AssignTargetPat::Object(obj) => self.enter_object_pattern(obj, on_ident),
1223      AssignTargetPat::Invalid(_) => (),
1224    }
1225  }
1226
1227  fn enter_patterns<'a, I, F>(&mut self, patterns: I, on_ident: F)
1228  where
1229    F: FnOnce(&mut Self, &Ident) + Copy,
1230    I: Iterator<Item = Cow<'a, Pat>>,
1231  {
1232    for pattern in patterns {
1233      self.enter_pattern(pattern, on_ident);
1234    }
1235  }
1236
1237  fn enter_optional_chain<'a, C, M, R>(
1238    &mut self,
1239    expr: &'a OptChainExpr,
1240    on_call: C,
1241    on_member: M,
1242  ) -> R
1243  where
1244    C: FnOnce(&mut Self, &'a OptCall) -> R,
1245    M: FnOnce(&mut Self, &'a MemberExpr) -> R,
1246  {
1247    let member_expr_in_optional_chain = self.member_expr_in_optional_chain;
1248    let ret = match &*expr.base {
1249      OptChainBase::Call(call) => {
1250        if call.callee.is_member() {
1251          self.member_expr_in_optional_chain = expr.optional;
1252        }
1253        on_call(self, call)
1254      }
1255      OptChainBase::Member(member) => {
1256        self.member_expr_in_optional_chain = expr.optional;
1257        on_member(self, member)
1258      }
1259    };
1260    self.member_expr_in_optional_chain = member_expr_in_optional_chain;
1261    ret
1262  }
1263
1264  fn enter_declaration<F>(&mut self, decl: &Decl, on_ident: F)
1265  where
1266    F: FnOnce(&mut Self, &Ident) + Copy,
1267  {
1268    match decl {
1269      Decl::Class(c) => {
1270        self.enter_ident(&c.ident, on_ident);
1271      }
1272      Decl::Fn(f) => {
1273        self.enter_ident(&f.ident, on_ident);
1274      }
1275      Decl::Var(var) => {
1276        for decl in &var.decls {
1277          self.enter_pattern(Cow::Borrowed(&decl.name), on_ident);
1278        }
1279      }
1280      Decl::Using(_) => (),
1281      _ => unreachable!(),
1282    }
1283  }
1284
1285  fn enter_statement<S, H, F>(&mut self, statement: &S, call_hook: H, on_statement: F)
1286  where
1287    S: Spanned,
1288    H: FnOnce(&mut Self, &S) -> bool,
1289    F: FnOnce(&mut Self, &S),
1290  {
1291    self.statement_path.push(statement.span().into());
1292    if call_hook(self, statement) {
1293      self.prev_statement = self.statement_path.pop();
1294      return;
1295    }
1296    on_statement(self, statement);
1297    self.prev_statement = self.statement_path.pop();
1298  }
1299
1300  pub fn enter_destructuring_assignment<'a>(
1301    &mut self,
1302    pattern: &ObjectPat,
1303    expr: &'a Expr,
1304  ) -> Option<&'a Expr> {
1305    let drive = self.plugin_drive.clone();
1306    let expr = if let Some(await_expr) = expr.as_await_expr() {
1307      &await_expr.arg
1308    } else {
1309      expr
1310    };
1311    let destructuring = if let Some(assign) = expr.as_assign()
1312      && let Some(pat) = assign.left.as_pat()
1313      && let Some(obj_pat) = pat.as_object()
1314    {
1315      self.enter_destructuring_assignment(obj_pat, &assign.right)
1316    } else {
1317      let can_collect = drive
1318        .can_collect_destructuring_assignment_properties(self, expr)
1319        .unwrap_or_default();
1320      can_collect.then_some(expr)
1321    };
1322    if let Some(destructuring) = destructuring
1323      && let Some(keys) =
1324        self.collect_destructuring_assignment_properties_from_object_pattern(pattern)
1325    {
1326      self
1327        .destructuring_assignment_properties
1328        .add(destructuring.span(), keys);
1329    }
1330    destructuring
1331  }
1332
1333  pub fn walk_program(&mut self, ast: &Program) {
1334    let drive = self.plugin_drive.clone();
1335    if drive.program(self, ast).is_none() {
1336      match ast {
1337        Program::Module(m) => {
1338          self.set_strict(true);
1339          self.prev_statement = None;
1340          self.module_pre_walk_module_items(&m.body);
1341          self.prev_statement = None;
1342          self.pre_walk_module_items(&m.body);
1343          self.prev_statement = None;
1344          self.block_pre_walk_module_items(&m.body);
1345          self.prev_statement = None;
1346          self.walk_module_items(&m.body);
1347        }
1348        Program::Script(s) => {
1349          self.detect_mode(&s.body);
1350          self.prev_statement = None;
1351          self.pre_walk_statements(&s.body);
1352          self.prev_statement = None;
1353          self.block_pre_walk_statements(&s.body);
1354          self.prev_statement = None;
1355          self.walk_statements(&s.body);
1356        }
1357      }
1358    }
1359    drive.finish(self);
1360  }
1361
1362  fn set_strict(&mut self, value: bool) {
1363    let current_scope = self.definitions_db.expect_get_mut_scope(self.definitions);
1364    current_scope.is_strict = value;
1365  }
1366
1367  pub fn detect_mode(&mut self, stmts: &[Stmt]) {
1368    let Some(Lit::Str(str)) = stmts
1369      .first()
1370      .and_then(|stmt| stmt.as_expr())
1371      .and_then(|expr_stmt| expr_stmt.expr.as_lit())
1372    else {
1373      return;
1374    };
1375
1376    if str.value == "use strict" {
1377      self.set_strict(true);
1378    }
1379  }
1380
1381  pub fn is_strict(&mut self) -> bool {
1382    let scope = self.definitions_db.expect_get_scope(self.definitions);
1383    scope.is_strict
1384  }
1385
1386  pub fn is_variable_defined(&mut self, name: &Atom) -> bool {
1387    let Some(info) = self.get_variable_info(name) else {
1388      return false;
1389    };
1390    !info.is_free()
1391  }
1392}
1393
1394impl JavascriptParser<'_> {
1395  pub fn evaluate_expression<'a>(&mut self, expr: &'a Expr) -> BasicEvaluatedExpression<'a> {
1396    match self.evaluating(expr) {
1397      Some(evaluated) => evaluated.with_expression(Some(expr)),
1398      None => BasicEvaluatedExpression::with_range(expr.span().real_lo(), expr.span().real_hi())
1399        .with_expression(Some(expr)),
1400    }
1401  }
1402
1403  pub fn evaluate<T: Display>(
1404    &mut self,
1405    source: String,
1406    error_title: T,
1407  ) -> Option<BasicEvaluatedExpression<'static>> {
1408    eval::eval_source(self, source, error_title.to_string())
1409  }
1410
1411  // same as `JavascriptParser._initializeEvaluating` in webpack
1412  // FIXME: should mv it to plugin(for example `parse.hooks.evaluate for`)
1413  fn evaluating<'a>(&mut self, expr: &'a Expr) -> Option<BasicEvaluatedExpression<'a>> {
1414    match expr {
1415      Expr::Tpl(tpl) => eval::eval_tpl_expression(self, tpl),
1416      Expr::TaggedTpl(tagged_tpl) => eval::eval_tagged_tpl_expression(self, tagged_tpl),
1417      Expr::Lit(lit) => eval::eval_lit_expr(lit),
1418      Expr::Cond(cond) => eval::eval_cond_expression(self, cond),
1419      Expr::Unary(unary) => eval::eval_unary_expression(self, unary),
1420      Expr::Bin(binary) => eval::eval_binary_expression(self, binary),
1421      Expr::Array(array) => eval::eval_array_expression(self, array),
1422      Expr::New(new) => eval::eval_new_expression(self, new),
1423      Expr::Call(call) => eval::eval_call_expression(self, call),
1424      Expr::OptChain(opt_chain) => self.enter_optional_chain(
1425        opt_chain,
1426        |parser, call| {
1427          let expr = Expr::Call(CallExpr {
1428            ctxt: call.ctxt,
1429            span: call.span,
1430            callee: call.callee.clone().as_callee(),
1431            args: call.args.clone(),
1432            type_args: None,
1433          });
1434          BasicEvaluatedExpression::with_owned_expression(expr, |expr| {
1435            #[allow(clippy::unwrap_used)]
1436            let call_expr = expr.as_call().unwrap();
1437            eval::eval_call_expression(parser, call_expr)
1438          })
1439        },
1440        |parser, member| eval::eval_member_expression(parser, member, expr),
1441      ),
1442      Expr::Member(member) => eval::eval_member_expression(self, member, expr),
1443      Expr::Ident(ident) => {
1444        let name = &ident.sym;
1445        if name.eq("undefined") {
1446          let mut eval =
1447            BasicEvaluatedExpression::with_range(ident.span.real_lo(), ident.span.real_hi());
1448          eval.set_undefined();
1449          return Some(eval);
1450        }
1451        let drive = self.plugin_drive.clone();
1452        name
1453          .call_hooks_name(self, |parser, name| {
1454            drive.evaluate_identifier(parser, name, ident.span.real_lo(), ident.span.real_hi())
1455          })
1456          .or_else(|| {
1457            let info = self.get_variable_info(name);
1458            if let Some(info) = info {
1459              if let Some(name) = &info.name
1460                && (info.is_free() || info.is_tagged())
1461              {
1462                let mut eval =
1463                  BasicEvaluatedExpression::with_range(ident.span.real_lo(), ident.span.real_hi());
1464                eval.set_identifier(
1465                  name.to_owned(),
1466                  ExportedVariableInfo::VariableInfo(info.id()),
1467                  None,
1468                  None,
1469                  None,
1470                );
1471                Some(eval)
1472              } else {
1473                None
1474              }
1475            } else {
1476              let mut eval =
1477                BasicEvaluatedExpression::with_range(ident.span.real_lo(), ident.span.real_hi());
1478              eval.set_identifier(
1479                ident.sym.clone(),
1480                ExportedVariableInfo::Name(name.clone()),
1481                None,
1482                None,
1483                None,
1484              );
1485              Some(eval)
1486            }
1487          })
1488      }
1489      Expr::This(this) => {
1490        let drive = self.plugin_drive.clone();
1491        let default_eval = || {
1492          let mut eval =
1493            BasicEvaluatedExpression::with_range(this.span.real_lo(), this.span.real_hi());
1494          eval.set_identifier(
1495            "this".into(),
1496            ExportedVariableInfo::Name("this".into()),
1497            None,
1498            None,
1499            None,
1500          );
1501          Some(eval)
1502        };
1503        let Some(info) = self.get_variable_info(&"this".into()) else {
1504          // use `ident.sym` as fallback for global variable(or maybe just a undefined variable)
1505          return drive
1506            .evaluate_identifier(self, "this", this.span.real_lo(), this.span.real_hi())
1507            .or_else(default_eval);
1508        };
1509        if let Some(name) = &info.name
1510          && (info.is_free() || info.is_tagged())
1511        {
1512          let name = name.clone();
1513          return drive
1514            .evaluate_identifier(self, &name, this.span.real_lo(), this.span.real_hi())
1515            .or_else(default_eval);
1516        }
1517        None
1518      }
1519      _ => None,
1520    }
1521  }
1522
1523  pub fn to_dependency_location(&mut self, range: DependencyRange) -> Option<DependencyLocation> {
1524    self
1525      .location_advancer
1526      .compute_dependency_location(self.source, range)
1527  }
1528}