1use std::time::{SystemTime, UNIX_EPOCH};
11
12use oxc_span::Span;
13
14use crate::ExportName;
15use fallow_types::extract::{NamespaceObjectAlias, VisibilityTag};
16
17#[must_use]
23pub fn current_unix_seconds() -> u64 {
24 SystemTime::now()
25 .duration_since(UNIX_EPOCH)
26 .map_or(0, |d| d.as_secs())
27}
28
29use super::types::{
30 CachedDynamicImport, CachedDynamicImportPattern, CachedExport, CachedImport,
31 CachedLocalTypeDeclaration, CachedMember, CachedModule, CachedNamespaceObjectAlias,
32 CachedPublicSignatureTypeReference, CachedReExport, CachedRequireCall, CachedSuppression,
33 CachedUnknownSuppressionKind, IMPORT_KIND_DEFAULT, IMPORT_KIND_NAMED, IMPORT_KIND_NAMESPACE,
34 IMPORT_KIND_SIDE_EFFECT,
35};
36
37#[must_use]
39pub fn cached_to_module(
40 cached: &CachedModule,
41 file_id: fallow_types::discover::FileId,
42) -> crate::ModuleInfo {
43 cached_to_module_opts(cached, file_id, true)
44}
45
46fn cached_exports_to_module(exports: &[CachedExport]) -> Vec<crate::ExportInfo> {
47 exports
48 .iter()
49 .map(|export| crate::ExportInfo {
50 name: if export.is_default {
51 ExportName::Default
52 } else {
53 ExportName::Named(export.name.clone())
54 },
55 local_name: export.local_name.clone(),
56 is_type_only: export.is_type_only,
57 is_side_effect_used: export.is_side_effect_used,
58 visibility: match export.visibility {
59 1 => VisibilityTag::Public,
60 2 => VisibilityTag::Internal,
61 3 => VisibilityTag::Beta,
62 4 => VisibilityTag::Alpha,
63 5 => VisibilityTag::ExpectedUnused,
64 _ => VisibilityTag::None,
65 },
66 span: Span::new(export.span_start, export.span_end),
67 members: export
68 .members
69 .iter()
70 .map(|member| crate::MemberInfo {
71 name: member.name.clone(),
72 kind: member.kind,
73 span: Span::new(member.span_start, member.span_end),
74 has_decorator: member.has_decorator,
75 decorator_names: member.decorator_names.clone(),
76 is_instance_returning_static: member.is_instance_returning_static,
77 is_self_returning: member.is_self_returning,
78 })
79 .collect(),
80 super_class: export.super_class.clone(),
81 })
82 .collect()
83}
84
85fn cached_imports_to_module(imports: &[CachedImport]) -> Vec<crate::ImportInfo> {
86 imports
87 .iter()
88 .map(|import| crate::ImportInfo {
89 source: import.source.clone(),
90 imported_name: match import.kind {
91 IMPORT_KIND_DEFAULT => crate::ImportedName::Default,
92 IMPORT_KIND_NAMESPACE => crate::ImportedName::Namespace,
93 IMPORT_KIND_SIDE_EFFECT => crate::ImportedName::SideEffect,
94 _ => crate::ImportedName::Named(import.imported_name.clone()),
95 },
96 local_name: import.local_name.clone(),
97 is_type_only: import.is_type_only,
98 from_style: import.from_style,
99 span: Span::new(import.span_start, import.span_end),
100 source_span: Span::new(import.source_span_start, import.source_span_end),
101 })
102 .collect()
103}
104
105fn cached_re_exports_to_module(re_exports: &[CachedReExport]) -> Vec<crate::ReExportInfo> {
106 re_exports
107 .iter()
108 .map(|re_export| crate::ReExportInfo {
109 source: re_export.source.clone(),
110 imported_name: re_export.imported_name.clone(),
111 exported_name: re_export.exported_name.clone(),
112 is_type_only: re_export.is_type_only,
113 span: Span::new(re_export.span_start, re_export.span_end),
114 })
115 .collect()
116}
117
118fn cached_dynamic_imports_to_module(
119 dynamic_imports: &[CachedDynamicImport],
120) -> Vec<crate::DynamicImportInfo> {
121 dynamic_imports
122 .iter()
123 .map(|dynamic_import| crate::DynamicImportInfo {
124 source: dynamic_import.source.clone(),
125 span: Span::new(dynamic_import.span_start, dynamic_import.span_end),
126 destructured_names: dynamic_import.destructured_names.clone(),
127 local_name: dynamic_import.local_name.clone(),
128 is_speculative: dynamic_import.is_speculative,
129 })
130 .collect()
131}
132
133fn cached_require_calls_to_module(
134 require_calls: &[CachedRequireCall],
135) -> Vec<crate::RequireCallInfo> {
136 require_calls
137 .iter()
138 .map(|require_call| crate::RequireCallInfo {
139 source: require_call.source.clone(),
140 span: Span::new(require_call.span_start, require_call.span_end),
141 source_span: Span::new(require_call.source_span_start, require_call.source_span_end),
142 destructured_names: require_call.destructured_names.clone(),
143 local_name: require_call.local_name.clone(),
144 })
145 .collect()
146}
147
148fn cached_dynamic_patterns_to_module(
149 dynamic_import_patterns: &[CachedDynamicImportPattern],
150) -> Vec<crate::DynamicImportPattern> {
151 dynamic_import_patterns
152 .iter()
153 .map(|pattern| crate::DynamicImportPattern {
154 prefix: pattern.prefix.clone(),
155 suffix: pattern.suffix.clone(),
156 span: Span::new(pattern.span_start, pattern.span_end),
157 })
158 .collect()
159}
160
161fn cached_suppressions_to_module(
162 suppressions: &[CachedSuppression],
163) -> Vec<crate::suppress::Suppression> {
164 suppressions
165 .iter()
166 .map(|suppression| crate::suppress::Suppression {
167 line: suppression.line,
168 comment_line: suppression.comment_line,
169 kind: if suppression.kind == 0 {
170 None
171 } else {
172 crate::suppress::IssueKind::from_discriminant(suppression.kind)
173 },
174 })
175 .collect()
176}
177
178fn cached_unknown_suppressions_to_module(
179 unknown_suppression_kinds: &[CachedUnknownSuppressionKind],
180) -> Vec<fallow_types::suppress::UnknownSuppressionKind> {
181 unknown_suppression_kinds
182 .iter()
183 .map(|unknown| fallow_types::suppress::UnknownSuppressionKind {
184 comment_line: unknown.comment_line,
185 is_file_level: unknown.is_file_level,
186 token: unknown.token.clone(),
187 })
188 .collect()
189}
190
191fn cached_local_types_to_module(
192 local_type_declarations: &[CachedLocalTypeDeclaration],
193) -> Vec<crate::LocalTypeDeclaration> {
194 local_type_declarations
195 .iter()
196 .map(|declaration| crate::LocalTypeDeclaration {
197 name: declaration.name.clone(),
198 span: Span::new(declaration.span_start, declaration.span_end),
199 })
200 .collect()
201}
202
203fn cached_signature_refs_to_module(
204 public_signature_type_references: &[CachedPublicSignatureTypeReference],
205) -> Vec<crate::PublicSignatureTypeReference> {
206 public_signature_type_references
207 .iter()
208 .map(|reference| crate::PublicSignatureTypeReference {
209 export_name: reference.export_name.clone(),
210 type_name: reference.type_name.clone(),
211 span: Span::new(reference.span_start, reference.span_end),
212 })
213 .collect()
214}
215
216fn cached_namespace_aliases_to_module(
217 namespace_object_aliases: &[CachedNamespaceObjectAlias],
218) -> Vec<NamespaceObjectAlias> {
219 namespace_object_aliases
220 .iter()
221 .map(|alias| NamespaceObjectAlias {
222 via_export_name: alias.via_export_name.clone(),
223 suffix: alias.suffix.clone(),
224 namespace_local: alias.namespace_local.clone(),
225 })
226 .collect()
227}
228
229fn module_exports_to_cached(exports: &[crate::ExportInfo]) -> Vec<CachedExport> {
230 exports
231 .iter()
232 .map(|export| CachedExport {
233 name: match &export.name {
234 ExportName::Named(name) => name.clone(),
235 ExportName::Default => String::new(),
236 },
237 is_default: matches!(export.name, ExportName::Default),
238 is_type_only: export.is_type_only,
239 is_side_effect_used: export.is_side_effect_used,
240 visibility: export.visibility as u8,
241 local_name: export.local_name.clone(),
242 span_start: export.span.start,
243 span_end: export.span.end,
244 members: export
245 .members
246 .iter()
247 .map(|member| CachedMember {
248 name: member.name.clone(),
249 kind: member.kind,
250 span_start: member.span.start,
251 span_end: member.span.end,
252 has_decorator: member.has_decorator,
253 decorator_names: member.decorator_names.clone(),
254 is_instance_returning_static: member.is_instance_returning_static,
255 is_self_returning: member.is_self_returning,
256 })
257 .collect(),
258 super_class: export.super_class.clone(),
259 })
260 .collect()
261}
262
263fn module_imports_to_cached(imports: &[crate::ImportInfo]) -> Vec<CachedImport> {
264 imports
265 .iter()
266 .map(|import| {
267 let (kind, imported_name) = match &import.imported_name {
268 crate::ImportedName::Named(name) => (IMPORT_KIND_NAMED, name.clone()),
269 crate::ImportedName::Default => (IMPORT_KIND_DEFAULT, String::new()),
270 crate::ImportedName::Namespace => (IMPORT_KIND_NAMESPACE, String::new()),
271 crate::ImportedName::SideEffect => (IMPORT_KIND_SIDE_EFFECT, String::new()),
272 };
273 CachedImport {
274 source: import.source.clone(),
275 imported_name,
276 local_name: import.local_name.clone(),
277 is_type_only: import.is_type_only,
278 from_style: import.from_style,
279 kind,
280 span_start: import.span.start,
281 span_end: import.span.end,
282 source_span_start: import.source_span.start,
283 source_span_end: import.source_span.end,
284 }
285 })
286 .collect()
287}
288
289fn module_re_exports_to_cached(re_exports: &[crate::ReExportInfo]) -> Vec<CachedReExport> {
290 re_exports
291 .iter()
292 .map(|re_export| CachedReExport {
293 source: re_export.source.clone(),
294 imported_name: re_export.imported_name.clone(),
295 exported_name: re_export.exported_name.clone(),
296 is_type_only: re_export.is_type_only,
297 span_start: re_export.span.start,
298 span_end: re_export.span.end,
299 })
300 .collect()
301}
302
303fn module_dynamic_imports_to_cached(
304 dynamic_imports: &[crate::DynamicImportInfo],
305) -> Vec<CachedDynamicImport> {
306 dynamic_imports
307 .iter()
308 .map(|dynamic_import| CachedDynamicImport {
309 source: dynamic_import.source.clone(),
310 span_start: dynamic_import.span.start,
311 span_end: dynamic_import.span.end,
312 destructured_names: dynamic_import.destructured_names.clone(),
313 local_name: dynamic_import.local_name.clone(),
314 is_speculative: dynamic_import.is_speculative,
315 })
316 .collect()
317}
318
319fn module_require_calls_to_cached(
320 require_calls: &[crate::RequireCallInfo],
321) -> Vec<CachedRequireCall> {
322 require_calls
323 .iter()
324 .map(|require_call| CachedRequireCall {
325 source: require_call.source.clone(),
326 span_start: require_call.span.start,
327 span_end: require_call.span.end,
328 source_span_start: require_call.source_span.start,
329 source_span_end: require_call.source_span.end,
330 destructured_names: require_call.destructured_names.clone(),
331 local_name: require_call.local_name.clone(),
332 })
333 .collect()
334}
335
336fn module_dynamic_patterns_to_cached(
337 dynamic_import_patterns: &[crate::DynamicImportPattern],
338) -> Vec<CachedDynamicImportPattern> {
339 dynamic_import_patterns
340 .iter()
341 .map(|pattern| CachedDynamicImportPattern {
342 prefix: pattern.prefix.clone(),
343 suffix: pattern.suffix.clone(),
344 span_start: pattern.span.start,
345 span_end: pattern.span.end,
346 })
347 .collect()
348}
349
350fn module_suppressions_to_cached(
351 suppressions: &[crate::suppress::Suppression],
352) -> Vec<CachedSuppression> {
353 suppressions
354 .iter()
355 .map(|suppression| CachedSuppression {
356 line: suppression.line,
357 comment_line: suppression.comment_line,
358 kind: suppression
359 .kind
360 .map_or(0, crate::suppress::IssueKind::to_discriminant),
361 })
362 .collect()
363}
364
365fn module_unknown_suppressions_to_cached(
366 unknown_suppression_kinds: &[fallow_types::suppress::UnknownSuppressionKind],
367) -> Vec<CachedUnknownSuppressionKind> {
368 unknown_suppression_kinds
369 .iter()
370 .map(|unknown| CachedUnknownSuppressionKind {
371 comment_line: unknown.comment_line,
372 is_file_level: unknown.is_file_level,
373 token: unknown.token.clone(),
374 })
375 .collect()
376}
377
378fn module_local_types_to_cached(
379 local_type_declarations: &[crate::LocalTypeDeclaration],
380) -> Vec<CachedLocalTypeDeclaration> {
381 local_type_declarations
382 .iter()
383 .map(|declaration| CachedLocalTypeDeclaration {
384 name: declaration.name.clone(),
385 span_start: declaration.span.start,
386 span_end: declaration.span.end,
387 })
388 .collect()
389}
390
391fn module_signature_refs_to_cached(
392 public_signature_type_references: &[crate::PublicSignatureTypeReference],
393) -> Vec<CachedPublicSignatureTypeReference> {
394 public_signature_type_references
395 .iter()
396 .map(|reference| CachedPublicSignatureTypeReference {
397 export_name: reference.export_name.clone(),
398 type_name: reference.type_name.clone(),
399 span_start: reference.span.start,
400 span_end: reference.span.end,
401 })
402 .collect()
403}
404
405fn module_namespace_aliases_to_cached(
406 namespace_object_aliases: &[NamespaceObjectAlias],
407) -> Vec<CachedNamespaceObjectAlias> {
408 namespace_object_aliases
409 .iter()
410 .map(|alias| CachedNamespaceObjectAlias {
411 via_export_name: alias.via_export_name.clone(),
412 suffix: alias.suffix.clone(),
413 namespace_local: alias.namespace_local.clone(),
414 })
415 .collect()
416}
417
418#[must_use]
423pub fn cached_to_module_opts(
424 cached: &CachedModule,
425 file_id: fallow_types::discover::FileId,
426 need_complexity: bool,
427) -> crate::ModuleInfo {
428 crate::ModuleInfo {
429 file_id,
430 exports: cached_exports_to_module(&cached.exports),
431 imports: cached_imports_to_module(&cached.imports),
432 re_exports: cached_re_exports_to_module(&cached.re_exports),
433 dynamic_imports: cached_dynamic_imports_to_module(&cached.dynamic_imports),
434 dynamic_import_patterns: cached_dynamic_patterns_to_module(&cached.dynamic_import_patterns),
435 require_calls: cached_require_calls_to_module(&cached.require_calls),
436 package_path_references: cached.package_path_references.clone(),
437 member_accesses: cached.member_accesses.clone(),
438 whole_object_uses: cached.whole_object_uses.clone(),
439 has_cjs_exports: cached.has_cjs_exports,
440 has_angular_component_template_url: cached.has_angular_component_template_url,
441 content_hash: cached.content_hash,
442 suppressions: cached_suppressions_to_module(&cached.suppressions),
443 unknown_suppression_kinds: cached_unknown_suppressions_to_module(
444 &cached.unknown_suppression_kinds,
445 ),
446 unused_import_bindings: cached.unused_import_bindings.clone(),
447 type_referenced_import_bindings: cached.type_referenced_import_bindings.clone(),
448 value_referenced_import_bindings: cached.value_referenced_import_bindings.clone(),
449 line_offsets: cached.line_offsets.clone(),
450 complexity: if need_complexity {
451 cached.complexity.clone()
452 } else {
453 Vec::new()
454 },
455 flag_uses: cached.flag_uses.clone(),
456 class_heritage: cached.class_heritage.clone(),
457 injection_tokens: cached.injection_tokens.clone(),
458 local_type_declarations: cached_local_types_to_module(&cached.local_type_declarations),
459 public_signature_type_references: cached_signature_refs_to_module(
460 &cached.public_signature_type_references,
461 ),
462 namespace_object_aliases: cached_namespace_aliases_to_module(
463 &cached.namespace_object_aliases,
464 ),
465 iconify_prefixes: cached.iconify_prefixes.clone(),
466 iconify_icon_names: cached.iconify_icon_names.clone(),
467 auto_import_candidates: cached.auto_import_candidates.clone(),
468 directives: cached.directives.clone(),
469 security_sinks: cached.security_sinks.clone(),
470 security_sinks_skipped: cached.security_sinks_skipped,
471 security_unresolved_callee_sites: cached.security_unresolved_callee_sites.clone(),
472 tainted_bindings: cached.tainted_bindings.clone(),
473 sanitized_sink_args: cached.sanitized_sink_args.clone(),
474 security_control_sites: cached.security_control_sites.clone(),
475 callee_uses: cached.callee_uses.clone(),
476 }
477}
478
479#[must_use]
485pub fn module_to_cached(
486 module: &crate::ModuleInfo,
487 mtime_secs: u64,
488 file_size: u64,
489) -> CachedModule {
490 CachedModule {
491 content_hash: module.content_hash,
492 mtime_secs,
493 file_size,
494 last_access_secs: current_unix_seconds(),
495 exports: module_exports_to_cached(&module.exports),
496 imports: module_imports_to_cached(&module.imports),
497 re_exports: module_re_exports_to_cached(&module.re_exports),
498 dynamic_imports: module_dynamic_imports_to_cached(&module.dynamic_imports),
499 require_calls: module_require_calls_to_cached(&module.require_calls),
500 package_path_references: module.package_path_references.clone(),
501 member_accesses: module.member_accesses.clone(),
502 whole_object_uses: module.whole_object_uses.clone(),
503 dynamic_import_patterns: module_dynamic_patterns_to_cached(&module.dynamic_import_patterns),
504 has_cjs_exports: module.has_cjs_exports,
505 has_angular_component_template_url: module.has_angular_component_template_url,
506 unused_import_bindings: module.unused_import_bindings.clone(),
507 type_referenced_import_bindings: module.type_referenced_import_bindings.clone(),
508 value_referenced_import_bindings: module.value_referenced_import_bindings.clone(),
509 suppressions: module_suppressions_to_cached(&module.suppressions),
510 unknown_suppression_kinds: module_unknown_suppressions_to_cached(
511 &module.unknown_suppression_kinds,
512 ),
513 line_offsets: module.line_offsets.clone(),
514 complexity: module.complexity.clone(),
515 flag_uses: module.flag_uses.clone(),
516 class_heritage: module.class_heritage.clone(),
517 injection_tokens: module.injection_tokens.clone(),
518 local_type_declarations: module_local_types_to_cached(&module.local_type_declarations),
519 public_signature_type_references: module_signature_refs_to_cached(
520 &module.public_signature_type_references,
521 ),
522 namespace_object_aliases: module_namespace_aliases_to_cached(
523 &module.namespace_object_aliases,
524 ),
525 iconify_prefixes: module.iconify_prefixes.clone(),
526 iconify_icon_names: module.iconify_icon_names.clone(),
527 auto_import_candidates: module.auto_import_candidates.clone(),
528 directives: module.directives.clone(),
529 security_sinks: module.security_sinks.clone(),
530 security_sinks_skipped: module.security_sinks_skipped,
531 security_unresolved_callee_sites: module.security_unresolved_callee_sites.clone(),
532 tainted_bindings: module.tainted_bindings.clone(),
533 sanitized_sink_args: module.sanitized_sink_args.clone(),
534 security_control_sites: module.security_control_sites.clone(),
535 callee_uses: module.callee_uses.clone(),
536 }
537}