1use std::{borrow::Cow, hash::Hash};
2
3use rspack_cacheable::{
4 cacheable, cacheable_dyn,
5 with::{AsOption, AsPreset},
6};
7use rspack_collections::{Identifiable, IdentifierMap, IdentifierSet};
8use rspack_error::{Result, impl_empty_diagnosable_trait};
9use rspack_hash::{RspackHash, RspackHashDigest};
10use rspack_macros::impl_source_map_config;
11use rspack_sources::{BoxSource, OriginalSource, RawStringSource, SourceExt};
12use rspack_util::source_map::{ModuleSourceMapConfig, SourceMapKind};
13
14use crate::{
15 BoxModule, BuildContext, BuildInfo, BuildMeta, BuildResult, CodeGenerationResult, Compilation,
16 ConnectionState, Context, DependenciesBlock, DependencyId, FactoryMeta, Module,
17 ModuleCodeGenerationContext, ModuleGraph, ModuleGraphCacheArtifact, ModuleIdentifier, ModuleType,
18 RuntimeGlobals, RuntimeSpec, SideEffectsStateArtifact, SourceType,
19 dependencies_block::AsyncDependenciesBlockIdentifier, impl_module_meta_info,
20 module_declared_side_effect_free, module_update_hash,
21};
22
23#[impl_source_map_config]
24#[cacheable]
25#[derive(Debug)]
26pub struct RawModule {
27 blocks: Vec<AsyncDependenciesBlockIdentifier>,
28 dependencies: Vec<DependencyId>,
29 source_str: String,
30 #[cacheable(with=AsOption<AsPreset>)]
31 source: Option<BoxSource>,
32 identifier: ModuleIdentifier,
33 readable_identifier: String,
34 runtime_requirements: RuntimeGlobals,
35 factory_meta: Option<FactoryMeta>,
36 build_info: BuildInfo,
37 build_meta: BuildMeta,
38}
39
40static RAW_MODULE_SOURCE_TYPES: &[SourceType] = &[SourceType::JavaScript];
41
42impl RawModule {
43 pub fn new(
44 source_str: String,
45 identifier: ModuleIdentifier,
46 readable_identifier: String,
47 runtime_requirements: RuntimeGlobals,
48 ) -> Self {
49 Self {
50 blocks: Default::default(),
51 dependencies: Default::default(),
52 source_str,
53 source: None,
54 identifier,
55 readable_identifier,
56 runtime_requirements,
57 factory_meta: None,
58 build_info: BuildInfo {
59 cacheable: true,
60 strict: true,
61 ..Default::default()
62 },
63 build_meta: Default::default(),
64 source_map_kind: SourceMapKind::empty(),
65 }
66 }
67}
68
69impl Identifiable for RawModule {
70 fn identifier(&self) -> ModuleIdentifier {
71 self.identifier
72 }
73}
74
75impl DependenciesBlock for RawModule {
76 fn add_block_id(&mut self, block: AsyncDependenciesBlockIdentifier) {
77 self.blocks.push(block)
78 }
79
80 fn get_blocks(&self) -> &[AsyncDependenciesBlockIdentifier] {
81 &self.blocks
82 }
83
84 fn add_dependency_id(&mut self, dependency: DependencyId) {
85 self.dependencies.push(dependency)
86 }
87
88 fn remove_dependency_id(&mut self, dependency: DependencyId) {
89 self.dependencies.retain(|d| d != &dependency)
90 }
91
92 fn get_dependencies(&self) -> &[DependencyId] {
93 &self.dependencies
94 }
95}
96
97#[cacheable_dyn]
98#[async_trait::async_trait]
99impl Module for RawModule {
100 impl_module_meta_info!();
101
102 fn module_type(&self) -> &ModuleType {
103 &ModuleType::JsAuto
104 }
105
106 fn source_types(&self, _module_graph: &ModuleGraph) -> &[SourceType] {
107 RAW_MODULE_SOURCE_TYPES
108 }
109
110 fn source(&self) -> Option<&BoxSource> {
111 self.source.as_ref()
112 }
113
114 fn readable_identifier(&self, _context: &Context) -> Cow<'_, str> {
115 Cow::Borrowed(&self.readable_identifier)
116 }
117
118 fn size(&self, _source_type: Option<&SourceType>, _compilation: Option<&Compilation>) -> f64 {
119 f64::max(1.0, self.source_str.len() as f64)
120 }
121
122 async fn code_generation(
124 &self,
125 code_generation_context: &mut ModuleCodeGenerationContext,
126 ) -> Result<CodeGenerationResult> {
127 let mut cgr = CodeGenerationResult::default();
128 code_generation_context
129 .runtime_template
130 .runtime_requirements_mut()
131 .insert(self.runtime_requirements);
132 if self.get_source_map_kind().enabled() {
133 cgr.add(
134 SourceType::JavaScript,
135 OriginalSource::new(self.source_str.clone(), self.identifier.to_string()).boxed(),
136 );
137 } else {
138 cgr.add(
139 SourceType::JavaScript,
140 RawStringSource::from(self.source_str.clone()).boxed(),
141 );
142 };
143 Ok(cgr)
144 }
145
146 async fn get_runtime_hash(
147 &self,
148 compilation: &Compilation,
149 runtime: Option<&RuntimeSpec>,
150 ) -> Result<RspackHashDigest> {
151 let mut hasher = RspackHash::from(&compilation.options.output);
152 self.source_str.hash(&mut hasher);
153 module_update_hash(self, &mut hasher, compilation, runtime);
154 Ok(hasher.digest(&compilation.options.output.hash_digest))
155 }
156
157 fn get_side_effects_connection_state(
158 &self,
159 _module_graph: &ModuleGraph,
160 _module_graph_cache: &ModuleGraphCacheArtifact,
161 _side_effects_state_artifact: &SideEffectsStateArtifact,
162 _module_chain: &mut IdentifierSet,
163 _connection_state_cache: &mut IdentifierMap<ConnectionState>,
164 ) -> ConnectionState {
165 if let Some(side_effect_free) = module_declared_side_effect_free(self) {
166 return ConnectionState::Active(!side_effect_free);
167 }
168 ConnectionState::Active(true)
169 }
170
171 async fn build(
172 self: Box<Self>,
173 _build_context: BuildContext,
174 _compilation: Option<&Compilation>,
175 ) -> Result<BuildResult> {
176 Ok(BuildResult {
177 module: BoxModule::new(self),
178 dependencies: vec![],
179 blocks: vec![],
180 optimization_bailouts: vec![],
181 })
182 }
183}
184
185impl_empty_diagnosable_trait!(RawModule);