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