webpack_stats/v5/
module.rs1use crate::common::chunk::ChunkId;
18use crate::common::{DurationMillis, SizeBytes};
19use std::collections::{HashMap, HashSet};
20use std::iter::once;
21use crate::v5::reason::Reasons;
23use empty_type::{Empty, EmptyType};
24use serde::{Deserialize, Deserializer};
25
26use crate::common::import::{ImportType, SourceText};
27use crate::common::module::{ModuleId, ModuleIdentifier, ModuleName};
28use crate::import::ResolvedModule;
29use crate::module::{IncludedModuleNames, ModuleChunks};
30use meshed::prelude::*;
31
32#[derive(Debug, Default)]
33pub struct Modules<'a> {
34 pub modules: Vec<Module<'a>>,
35}
36
37impl<'a> crate::common::module::Modules<Module<'a>> for Modules<'a> {}
38
39impl<'de: 'a, 'a> Deserialize<'de> for Modules<'a> {
40 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
41 where
42 D: Deserializer<'de>,
43 {
44 let empty_vec: Vec<Empty<Module<'a>>> = Deserialize::deserialize(deserializer)?;
45
46 let materialized_vec = empty_vec.into_iter().map(|i| i.resolve()).collect();
47 Ok(Self {
48 modules: materialized_vec,
49 })
50 }
51}
52
53impl<'a> Query<ModuleIdentifier, Module<'a>> for Modules<'a> {
54 fn query(&self, _identifier: &ModuleIdentifier) -> Option<&Module<'a>> {
55 panic!("Query should be called on the module's index not on the modules iterator itself.")
56 }
57
58 fn all(&self) -> Vec<&Module<'a>> {
59 self.modules
60 .iter()
61 .flat_map(|module| module.modules.all().into_iter().chain(once(module)))
62 .collect()
63 }
64
65 fn create_index(&self) -> HashMap<ModuleIdentifier, Link<ModuleIdentifier, Module<'a>>> {
66 let mut map: HashMap<_, _> = Default::default();
67
68 for module in self.modules.iter() {
69 for child in module.modules.modules.iter() {
70 map.insert(child.get_id(), Link::Link(module.get_id()));
71 }
72 map.insert(module.get_id(), Link::Value(module));
73 }
74 map
75 }
76}
77
78impl<'a> ExtractData<IncludedModuleNames> for Module<'a> {
79 fn extract_data(&self) -> IncludedModuleNames {
80 let mut included_names: HashSet<_> = Default::default();
81 included_names.insert(self.name.0.to_string());
82
83 for child in self.modules.all() {
84 included_names.insert(child.name.0.to_string());
85 let data: IncludedModuleNames = child.extract_data();
86 included_names.extend(data.0.into_iter());
87 }
88
89 IncludedModuleNames(included_names)
90 }
91}
92
93impl<'a> ExtractData<ModuleChunks> for Module<'a> {
94 fn extract_data(&self) -> ModuleChunks {
95 HashSet::from_iter(self.chunks.iter().cloned())
96 }
97}
98
99impl<'a> Label for Module<'a> {
100 type Label = ModuleName;
101
102 fn label(&self) -> Self::Label {
103 self.name.clone()
104 }
105}
106
107impl<'a> crate::common::module::Module for Module<'a> {}
108
109impl<'a> Identifiable<ModuleIdentifier> for Module<'a> {
110 fn get_id(&self) -> ModuleIdentifier {
111 self.identifier.clone()
112 }
113}
114
115impl<'a> Edges<ModuleIdentifier, (ImportType, ResolvedModule)> for Module<'a> {
116 fn next_edge(
117 &self,
118 previous_edge_index: Option<usize>,
119 ) -> Option<Edge<ModuleIdentifier, (ImportType, ResolvedModule)>> {
120 let next_index = previous_edge_index.map(|e| e + 1).unwrap_or_default();
121 let reason = self.reasons.get(next_index)?;
122 Some(Edge::new(
123 self.get_id(),
124 reason.module_identifier.clone(),
125 next_index,
126 (
127 reason.r#type,
128 ResolvedModule(reason.resolved_module.clone()),
129 ),
130 ))
131 }
132}
133
134#[derive(Deserialize, Debug, EmptyType)]
135#[serde(rename_all = "camelCase")]
136#[empty(bounds = "'a", deserialize)]
137pub struct Module<'a> {
138 pub assets: Vec<serde_json::Value>,
140 pub built: bool,
143 #[empty(fail_safe)]
144 pub cacheable: bool,
145 pub chunks: Vec<ChunkId>,
146
147 #[serde(rename = "errors")]
149 pub error_count: u32,
150 #[serde(rename = "warnings")]
151 pub warning_count: u32,
152
153 pub failed: bool,
154 #[empty(fail_safe)]
157 pub id: Option<ModuleId>,
158 pub identifier: ModuleIdentifier,
159 pub name: ModuleName,
160 pub optional: bool,
161 #[serde(default)]
162 pub prefetched: bool,
163 #[serde(borrow)]
166 pub reasons: Reasons<'a>,
167 pub size: SizeBytes,
168 pub source: Option<SourceText<'a>>,
169 #[empty(default)]
170 pub profile: Profile,
171 #[empty(default)]
172 pub modules: Modules<'a>,
173}
174
175#[derive(Deserialize, Debug, Default)]
176pub struct Profile {
177 pub building: DurationMillis,
178 pub dependencies: DurationMillis,
179 pub factory: DurationMillis,
180}