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