rspack_core/dependency/
context_element_dependency.rs

1use itertools::Itertools;
2use rspack_cacheable::{
3  cacheable, cacheable_dyn,
4  with::{AsOption, AsPreset, AsVec},
5};
6use rspack_util::json_stringify;
7use swc_core::ecma::atoms::Atom;
8
9use super::{AffectType, FactorizeInfo};
10use crate::{
11  AsContextDependency, AsDependencyCodeGeneration, Context, ContextMode, ContextNameSpaceObject,
12  ContextOptions, ContextTypePrefix, Dependency, DependencyCategory, DependencyId, DependencyType,
13  ExportsType, ExtendedReferencedExport, ImportAttributes, ModuleDependency, ModuleGraph,
14  ModuleGraphCacheArtifact, ModuleLayer, ReferencedExport, ResourceIdentifier, RuntimeSpec,
15  create_exports_object_referenced,
16};
17
18#[cacheable]
19#[derive(Debug, Clone)]
20pub struct ContextElementDependency {
21  pub id: DependencyId,
22  // TODO remove this async dependency mark
23  pub options: ContextOptions,
24  pub request: String,
25  pub user_request: String,
26  pub category: DependencyCategory,
27  pub context: Context,
28  pub layer: Option<ModuleLayer>,
29  pub resource_identifier: ResourceIdentifier,
30  #[cacheable(with=AsOption<AsVec<AsVec<AsPreset>>>)]
31  pub referenced_exports: Option<Vec<Vec<Atom>>>,
32  pub dependency_type: DependencyType,
33  pub attributes: Option<ImportAttributes>,
34  pub factorize_info: FactorizeInfo,
35}
36
37impl ContextElementDependency {
38  pub fn create_resource_identifier(
39    resource: &str,
40    path: &str,
41    attributes: Option<&ImportAttributes>,
42  ) -> ResourceIdentifier {
43    let mut ident = format!("context{resource}|{path}");
44    if let Some(attributes) = attributes {
45      ident += &json_stringify(&attributes);
46    }
47    ident.into()
48  }
49}
50
51#[cacheable_dyn]
52impl Dependency for ContextElementDependency {
53  fn id(&self) -> &DependencyId {
54    &self.id
55  }
56
57  fn category(&self) -> &DependencyCategory {
58    &self.category
59  }
60
61  fn dependency_type(&self) -> &DependencyType {
62    &self.dependency_type
63  }
64
65  fn get_context(&self) -> Option<&Context> {
66    Some(&self.context)
67  }
68
69  fn get_layer(&self) -> Option<&ModuleLayer> {
70    self.layer.as_ref()
71  }
72
73  fn get_attributes(&self) -> Option<&ImportAttributes> {
74    self.attributes.as_ref()
75  }
76
77  fn resource_identifier(&self) -> Option<&str> {
78    Some(&self.resource_identifier)
79  }
80
81  fn get_referenced_exports(
82    &self,
83    module_graph: &ModuleGraph,
84    module_graph_cache: &ModuleGraphCacheArtifact,
85    _runtime: Option<&RuntimeSpec>,
86  ) -> Vec<ExtendedReferencedExport> {
87    if let Some(referenced_exports) = &self.referenced_exports {
88      for referenced_export in referenced_exports {
89        if matches!(
90          self.dependency_type,
91          DependencyType::ContextElement(ContextTypePrefix::Import)
92        ) && referenced_export
93          .first()
94          .is_some_and(|export| export == "default")
95        {
96          let is_strict = module_graph
97            .get_parent_module(&self.id)
98            .and_then(|id| module_graph.module_by_identifier(id))
99            .and_then(|m| m.as_context_module())
100            .map(|m| {
101              matches!(
102                m.get_context_options().namespace_object,
103                ContextNameSpaceObject::Strict
104              )
105            });
106
107          let exports_type = is_strict.and_then(|is_strict| {
108            module_graph
109              .get_module_by_dependency_id(&self.id)
110              .map(|m| m.get_exports_type(module_graph, module_graph_cache, is_strict))
111          });
112
113          if let Some(exports_type) = exports_type
114            && matches!(
115              exports_type,
116              ExportsType::DefaultOnly | ExportsType::DefaultWithNamed
117            )
118          {
119            return create_exports_object_referenced();
120          }
121        }
122      }
123
124      referenced_exports
125        .iter()
126        .map(|export| {
127          ExtendedReferencedExport::Export(ReferencedExport::new(export.clone(), false, false))
128        })
129        .collect_vec()
130    } else {
131      create_exports_object_referenced()
132    }
133  }
134
135  fn could_affect_referencing_module(&self) -> AffectType {
136    AffectType::True
137  }
138}
139
140#[cacheable_dyn]
141impl ModuleDependency for ContextElementDependency {
142  fn request(&self) -> &str {
143    &self.request
144  }
145
146  fn user_request(&self) -> &str {
147    &self.user_request
148  }
149
150  fn weak(&self) -> bool {
151    matches!(
152      self.options.mode,
153      ContextMode::AsyncWeak | ContextMode::Weak
154    )
155  }
156
157  fn factorize_info(&self) -> &FactorizeInfo {
158    &self.factorize_info
159  }
160
161  fn factorize_info_mut(&mut self) -> &mut FactorizeInfo {
162    &mut self.factorize_info
163  }
164}
165
166impl AsDependencyCodeGeneration for ContextElementDependency {}
167impl AsContextDependency for ContextElementDependency {}