1use oxc_span::Span;
11
12use crate::ExportName;
13use fallow_types::extract::{NamespaceObjectAlias, VisibilityTag};
14
15use super::types::{
16 CachedDynamicImport, CachedDynamicImportPattern, CachedExport, CachedImport,
17 CachedLocalTypeDeclaration, CachedMember, CachedModule, CachedNamespaceObjectAlias,
18 CachedPublicSignatureTypeReference, CachedReExport, CachedRequireCall, CachedSuppression,
19 IMPORT_KIND_DEFAULT, IMPORT_KIND_NAMED, IMPORT_KIND_NAMESPACE, IMPORT_KIND_SIDE_EFFECT,
20};
21
22#[must_use]
24pub fn cached_to_module(
25 cached: &CachedModule,
26 file_id: fallow_types::discover::FileId,
27) -> crate::ModuleInfo {
28 cached_to_module_opts(cached, file_id, true)
29}
30
31#[must_use]
36#[expect(
37 clippy::too_many_lines,
38 reason = "single flat field-by-field deserialization; splitting it harms readability"
39)]
40pub fn cached_to_module_opts(
41 cached: &CachedModule,
42 file_id: fallow_types::discover::FileId,
43 need_complexity: bool,
44) -> crate::ModuleInfo {
45 use crate::{
46 DynamicImportInfo, ExportInfo, ImportInfo, ImportedName, LocalTypeDeclaration, MemberInfo,
47 ModuleInfo, PublicSignatureTypeReference, ReExportInfo, RequireCallInfo,
48 };
49
50 let exports = cached
51 .exports
52 .iter()
53 .map(|e| ExportInfo {
54 name: if e.is_default {
55 ExportName::Default
56 } else {
57 ExportName::Named(e.name.clone())
58 },
59 local_name: e.local_name.clone(),
60 is_type_only: e.is_type_only,
61 is_side_effect_used: e.is_side_effect_used,
62 visibility: match e.visibility {
63 1 => VisibilityTag::Public,
64 2 => VisibilityTag::Internal,
65 3 => VisibilityTag::Beta,
66 4 => VisibilityTag::Alpha,
67 5 => VisibilityTag::ExpectedUnused,
68 _ => VisibilityTag::None,
69 },
70 span: Span::new(e.span_start, e.span_end),
71 members: e
72 .members
73 .iter()
74 .map(|m| MemberInfo {
75 name: m.name.clone(),
76 kind: m.kind,
77 span: Span::new(m.span_start, m.span_end),
78 has_decorator: m.has_decorator,
79 is_instance_returning_static: m.is_instance_returning_static,
80 })
81 .collect(),
82 super_class: e.super_class.clone(),
83 })
84 .collect();
85
86 let imports = cached
87 .imports
88 .iter()
89 .map(|i| ImportInfo {
90 source: i.source.clone(),
91 imported_name: match i.kind {
92 IMPORT_KIND_DEFAULT => ImportedName::Default,
93 IMPORT_KIND_NAMESPACE => ImportedName::Namespace,
94 IMPORT_KIND_SIDE_EFFECT => ImportedName::SideEffect,
95 _ => ImportedName::Named(i.imported_name.clone()),
97 },
98 local_name: i.local_name.clone(),
99 is_type_only: i.is_type_only,
100 from_style: i.from_style,
101 span: Span::new(i.span_start, i.span_end),
102 source_span: Span::new(i.source_span_start, i.source_span_end),
103 })
104 .collect();
105
106 let re_exports = cached
107 .re_exports
108 .iter()
109 .map(|r| ReExportInfo {
110 source: r.source.clone(),
111 imported_name: r.imported_name.clone(),
112 exported_name: r.exported_name.clone(),
113 is_type_only: r.is_type_only,
114 span: Span::new(r.span_start, r.span_end),
115 })
116 .collect();
117
118 let dynamic_imports = cached
119 .dynamic_imports
120 .iter()
121 .map(|d| DynamicImportInfo {
122 source: d.source.clone(),
123 span: Span::new(d.span_start, d.span_end),
124 destructured_names: d.destructured_names.clone(),
125 local_name: d.local_name.clone(),
126 is_speculative: d.is_speculative,
127 })
128 .collect();
129
130 let require_calls = cached
131 .require_calls
132 .iter()
133 .map(|r| RequireCallInfo {
134 source: r.source.clone(),
135 span: Span::new(r.span_start, r.span_end),
136 destructured_names: r.destructured_names.clone(),
137 local_name: r.local_name.clone(),
138 })
139 .collect();
140
141 let dynamic_import_patterns = cached
142 .dynamic_import_patterns
143 .iter()
144 .map(|p| crate::DynamicImportPattern {
145 prefix: p.prefix.clone(),
146 suffix: p.suffix.clone(),
147 span: Span::new(p.span_start, p.span_end),
148 })
149 .collect();
150
151 let suppressions = cached
152 .suppressions
153 .iter()
154 .map(|s| crate::suppress::Suppression {
155 line: s.line,
156 comment_line: s.comment_line,
157 kind: if s.kind == 0 {
158 None
159 } else {
160 crate::suppress::IssueKind::from_discriminant(s.kind)
161 },
162 })
163 .collect();
164
165 ModuleInfo {
166 file_id,
167 exports,
168 imports,
169 re_exports,
170 dynamic_imports,
171 dynamic_import_patterns,
172 require_calls,
173 member_accesses: cached.member_accesses.clone(),
174 whole_object_uses: cached.whole_object_uses.clone(),
175 has_cjs_exports: cached.has_cjs_exports,
176 content_hash: cached.content_hash,
177 suppressions,
178 unused_import_bindings: cached.unused_import_bindings.clone(),
179 type_referenced_import_bindings: cached.type_referenced_import_bindings.clone(),
180 value_referenced_import_bindings: cached.value_referenced_import_bindings.clone(),
181 line_offsets: cached.line_offsets.clone(),
182 complexity: if need_complexity {
183 cached.complexity.clone()
184 } else {
185 Vec::new()
186 },
187 flag_uses: cached.flag_uses.clone(),
188 class_heritage: cached.class_heritage.clone(),
189 local_type_declarations: cached
190 .local_type_declarations
191 .iter()
192 .map(|decl| LocalTypeDeclaration {
193 name: decl.name.clone(),
194 span: Span::new(decl.span_start, decl.span_end),
195 })
196 .collect(),
197 public_signature_type_references: cached
198 .public_signature_type_references
199 .iter()
200 .map(|reference| PublicSignatureTypeReference {
201 export_name: reference.export_name.clone(),
202 type_name: reference.type_name.clone(),
203 span: Span::new(reference.span_start, reference.span_end),
204 })
205 .collect(),
206 namespace_object_aliases: cached
207 .namespace_object_aliases
208 .iter()
209 .map(|alias| NamespaceObjectAlias {
210 via_export_name: alias.via_export_name.clone(),
211 suffix: alias.suffix.clone(),
212 namespace_local: alias.namespace_local.clone(),
213 })
214 .collect(),
215 }
216}
217
218#[must_use]
224#[expect(
225 clippy::too_many_lines,
226 reason = "single flat field-by-field serialization; splitting it harms readability"
227)]
228pub fn module_to_cached(
229 module: &crate::ModuleInfo,
230 mtime_secs: u64,
231 file_size: u64,
232) -> CachedModule {
233 CachedModule {
234 content_hash: module.content_hash,
235 mtime_secs,
236 file_size,
237 exports: module
238 .exports
239 .iter()
240 .map(|e| CachedExport {
241 name: match &e.name {
242 ExportName::Named(n) => n.clone(),
243 ExportName::Default => String::new(),
244 },
245 is_default: matches!(e.name, ExportName::Default),
246 is_type_only: e.is_type_only,
247 is_side_effect_used: e.is_side_effect_used,
248 visibility: e.visibility as u8,
249 local_name: e.local_name.clone(),
250 span_start: e.span.start,
251 span_end: e.span.end,
252 members: e
253 .members
254 .iter()
255 .map(|m| CachedMember {
256 name: m.name.clone(),
257 kind: m.kind,
258 span_start: m.span.start,
259 span_end: m.span.end,
260 has_decorator: m.has_decorator,
261 is_instance_returning_static: m.is_instance_returning_static,
262 })
263 .collect(),
264 super_class: e.super_class.clone(),
265 })
266 .collect(),
267 imports: module
268 .imports
269 .iter()
270 .map(|i| {
271 let (kind, imported_name) = match &i.imported_name {
272 crate::ImportedName::Named(n) => (IMPORT_KIND_NAMED, n.clone()),
273 crate::ImportedName::Default => (IMPORT_KIND_DEFAULT, String::new()),
274 crate::ImportedName::Namespace => (IMPORT_KIND_NAMESPACE, String::new()),
275 crate::ImportedName::SideEffect => (IMPORT_KIND_SIDE_EFFECT, String::new()),
276 };
277 CachedImport {
278 source: i.source.clone(),
279 imported_name,
280 local_name: i.local_name.clone(),
281 is_type_only: i.is_type_only,
282 from_style: i.from_style,
283 kind,
284 span_start: i.span.start,
285 span_end: i.span.end,
286 source_span_start: i.source_span.start,
287 source_span_end: i.source_span.end,
288 }
289 })
290 .collect(),
291 re_exports: module
292 .re_exports
293 .iter()
294 .map(|r| CachedReExport {
295 source: r.source.clone(),
296 imported_name: r.imported_name.clone(),
297 exported_name: r.exported_name.clone(),
298 is_type_only: r.is_type_only,
299 span_start: r.span.start,
300 span_end: r.span.end,
301 })
302 .collect(),
303 dynamic_imports: module
304 .dynamic_imports
305 .iter()
306 .map(|d| CachedDynamicImport {
307 source: d.source.clone(),
308 span_start: d.span.start,
309 span_end: d.span.end,
310 destructured_names: d.destructured_names.clone(),
311 local_name: d.local_name.clone(),
312 is_speculative: d.is_speculative,
313 })
314 .collect(),
315 require_calls: module
316 .require_calls
317 .iter()
318 .map(|r| CachedRequireCall {
319 source: r.source.clone(),
320 span_start: r.span.start,
321 span_end: r.span.end,
322 destructured_names: r.destructured_names.clone(),
323 local_name: r.local_name.clone(),
324 })
325 .collect(),
326 member_accesses: module.member_accesses.clone(),
327 whole_object_uses: module.whole_object_uses.clone(),
328 dynamic_import_patterns: module
329 .dynamic_import_patterns
330 .iter()
331 .map(|p| CachedDynamicImportPattern {
332 prefix: p.prefix.clone(),
333 suffix: p.suffix.clone(),
334 span_start: p.span.start,
335 span_end: p.span.end,
336 })
337 .collect(),
338 has_cjs_exports: module.has_cjs_exports,
339 unused_import_bindings: module.unused_import_bindings.clone(),
340 type_referenced_import_bindings: module.type_referenced_import_bindings.clone(),
341 value_referenced_import_bindings: module.value_referenced_import_bindings.clone(),
342 suppressions: module
343 .suppressions
344 .iter()
345 .map(|s| CachedSuppression {
346 line: s.line,
347 comment_line: s.comment_line,
348 kind: s
349 .kind
350 .map_or(0, crate::suppress::IssueKind::to_discriminant),
351 })
352 .collect(),
353 line_offsets: module.line_offsets.clone(),
354 complexity: module.complexity.clone(),
355 flag_uses: module.flag_uses.clone(),
356 class_heritage: module.class_heritage.clone(),
357 local_type_declarations: module
358 .local_type_declarations
359 .iter()
360 .map(|decl| CachedLocalTypeDeclaration {
361 name: decl.name.clone(),
362 span_start: decl.span.start,
363 span_end: decl.span.end,
364 })
365 .collect(),
366 public_signature_type_references: module
367 .public_signature_type_references
368 .iter()
369 .map(|reference| CachedPublicSignatureTypeReference {
370 export_name: reference.export_name.clone(),
371 type_name: reference.type_name.clone(),
372 span_start: reference.span.start,
373 span_end: reference.span.end,
374 })
375 .collect(),
376 namespace_object_aliases: module
377 .namespace_object_aliases
378 .iter()
379 .map(|alias| CachedNamespaceObjectAlias {
380 via_export_name: alias.via_export_name.clone(),
381 suffix: alias.suffix.clone(),
382 namespace_local: alias.namespace_local.clone(),
383 })
384 .collect(),
385 }
386}