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
94pub 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 errors: Vec<Diagnostic>,
351 warning_diagnostics: Vec<Diagnostic>,
352 dependencies: Vec<BoxDependency>,
353 presentational_dependencies: Vec<BoxDependencyTemplate>,
354 #[allow(clippy::vec_box)]
357 blocks: Vec<Box<AsyncDependenciesBlock>>,
358 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 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 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 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 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 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 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}