Skip to main content

fallow_extract/cache/
conversion.rs

1//! Conversion between [`ModuleInfo`](crate::ModuleInfo) and [`CachedModule`].
2//!
3//! Both functions convert between borrowed source structs and owned target structs
4//! (`&CachedModule -> ModuleInfo`, `&ModuleInfo -> CachedModule`). All `String` clones
5//! are structurally necessary: the cache store retains ownership of `CachedModule`
6//! entries (for persistence), and `ModuleInfo` must outlive the cache for the
7//! analysis pipeline. Eliminating these clones would require shared ownership
8//! (`Arc<str>`) across the entire extraction + analysis pipeline.
9
10use std::time::{SystemTime, UNIX_EPOCH};
11
12use oxc_span::Span;
13
14use crate::ExportName;
15use fallow_types::extract::{NamespaceObjectAlias, VisibilityTag};
16use fallow_types::suppress::{PolicyRuleSuppression, SuppressionTarget};
17
18/// Seconds-since-Unix-epoch from the wall clock, saturating to 0 if the
19/// system clock is set before the epoch. Used as the LRU bookkeeping
20/// timestamp on `CachedModule.last_access_secs`. Wall-clock (not monotonic)
21/// is the right source here because the value persists across process
22/// invocations.
23#[must_use]
24pub fn current_unix_seconds() -> u64 {
25    SystemTime::now()
26        .duration_since(UNIX_EPOCH)
27        .map_or(0, |d| d.as_secs())
28}
29
30use super::types::{
31    CachedDynamicImport, CachedDynamicImportPattern, CachedExport, CachedImport,
32    CachedLocalTypeDeclaration, CachedMember, CachedModule, CachedNamespaceObjectAlias,
33    CachedPublicSignatureTypeReference, CachedReExport, CachedRequireCall, CachedSuppression,
34    CachedUnknownSuppressionKind, IMPORT_KIND_DEFAULT, IMPORT_KIND_NAMED, IMPORT_KIND_NAMESPACE,
35    IMPORT_KIND_SIDE_EFFECT,
36};
37
38/// Reconstruct a [`ModuleInfo`](crate::ModuleInfo) from a [`CachedModule`].
39#[must_use]
40pub fn cached_to_module(
41    cached: &CachedModule,
42    file_id: fallow_types::discover::FileId,
43) -> crate::ModuleInfo {
44    cached_to_module_opts(cached, file_id, true)
45}
46
47fn cached_exports_to_module(exports: &[CachedExport]) -> Vec<crate::ExportInfo> {
48    exports
49        .iter()
50        .map(|export| crate::ExportInfo {
51            name: if export.is_default {
52                ExportName::Default
53            } else {
54                ExportName::Named(export.name.clone())
55            },
56            local_name: export.local_name.clone(),
57            is_type_only: export.is_type_only,
58            is_side_effect_used: export.is_side_effect_used,
59            visibility: match export.visibility {
60                1 => VisibilityTag::Public,
61                2 => VisibilityTag::Internal,
62                3 => VisibilityTag::Beta,
63                4 => VisibilityTag::Alpha,
64                5 => VisibilityTag::ExpectedUnused,
65                _ => VisibilityTag::None,
66            },
67            expected_unused_reason: export.expected_unused_reason.clone(),
68            span: Span::new(export.span_start, export.span_end),
69            members: export
70                .members
71                .iter()
72                .map(|member| crate::MemberInfo {
73                    name: member.name.clone(),
74                    kind: member.kind,
75                    span: Span::new(member.span_start, member.span_end),
76                    has_decorator: member.has_decorator,
77                    decorator_names: member.decorator_names.clone(),
78                    is_instance_returning_static: member.is_instance_returning_static,
79                    is_self_returning: member.is_self_returning,
80                })
81                .collect(),
82            super_class: export.super_class.clone(),
83        })
84        .collect()
85}
86
87fn cached_imports_to_module(imports: &[CachedImport]) -> Vec<crate::ImportInfo> {
88    imports
89        .iter()
90        .map(|import| crate::ImportInfo {
91            source: import.source.clone(),
92            imported_name: match import.kind {
93                IMPORT_KIND_DEFAULT => crate::ImportedName::Default,
94                IMPORT_KIND_NAMESPACE => crate::ImportedName::Namespace,
95                IMPORT_KIND_SIDE_EFFECT => crate::ImportedName::SideEffect,
96                _ => crate::ImportedName::Named(import.imported_name.clone()),
97            },
98            local_name: import.local_name.clone(),
99            is_type_only: import.is_type_only,
100            from_style: import.from_style,
101            span: Span::new(import.span_start, import.span_end),
102            source_span: Span::new(import.source_span_start, import.source_span_end),
103        })
104        .collect()
105}
106
107fn cached_re_exports_to_module(re_exports: &[CachedReExport]) -> Vec<crate::ReExportInfo> {
108    re_exports
109        .iter()
110        .map(|re_export| crate::ReExportInfo {
111            source: re_export.source.clone(),
112            imported_name: re_export.imported_name.clone(),
113            exported_name: re_export.exported_name.clone(),
114            is_type_only: re_export.is_type_only,
115            span: Span::new(re_export.span_start, re_export.span_end),
116        })
117        .collect()
118}
119
120fn cached_dynamic_imports_to_module(
121    dynamic_imports: &[CachedDynamicImport],
122) -> Vec<crate::DynamicImportInfo> {
123    dynamic_imports
124        .iter()
125        .map(|dynamic_import| crate::DynamicImportInfo {
126            source: dynamic_import.source.clone(),
127            span: Span::new(dynamic_import.span_start, dynamic_import.span_end),
128            destructured_names: dynamic_import.destructured_names.clone(),
129            local_name: dynamic_import.local_name.clone(),
130            is_speculative: dynamic_import.is_speculative,
131        })
132        .collect()
133}
134
135fn cached_require_calls_to_module(
136    require_calls: &[CachedRequireCall],
137) -> Vec<crate::RequireCallInfo> {
138    require_calls
139        .iter()
140        .map(|require_call| crate::RequireCallInfo {
141            source: require_call.source.clone(),
142            span: Span::new(require_call.span_start, require_call.span_end),
143            source_span: Span::new(require_call.source_span_start, require_call.source_span_end),
144            destructured_names: require_call.destructured_names.clone(),
145            local_name: require_call.local_name.clone(),
146        })
147        .collect()
148}
149
150fn cached_dynamic_patterns_to_module(
151    dynamic_import_patterns: &[CachedDynamicImportPattern],
152) -> Vec<crate::DynamicImportPattern> {
153    dynamic_import_patterns
154        .iter()
155        .map(|pattern| crate::DynamicImportPattern {
156            prefix: pattern.prefix.clone(),
157            suffix: pattern.suffix.clone(),
158            span: Span::new(pattern.span_start, pattern.span_end),
159        })
160        .collect()
161}
162
163fn cached_suppressions_to_module(
164    suppressions: &[CachedSuppression],
165) -> Vec<crate::suppress::Suppression> {
166    suppressions
167        .iter()
168        .map(|suppression| {
169            let target = if suppression.kind == 0 {
170                None
171            } else if suppression.kind
172                == crate::suppress::IssueKind::PolicyViolation.to_discriminant()
173                && !suppression.policy_pack.is_empty()
174                && !suppression.policy_rule_id.is_empty()
175            {
176                Some(SuppressionTarget::PolicyRule(PolicyRuleSuppression::new(
177                    suppression.policy_pack.clone(),
178                    suppression.policy_rule_id.clone(),
179                )))
180            } else {
181                crate::suppress::IssueKind::from_discriminant(suppression.kind)
182                    .map(SuppressionTarget::Issue)
183            };
184            crate::suppress::Suppression {
185                line: suppression.line,
186                comment_line: suppression.comment_line,
187                target,
188                reason: suppression.reason.clone(),
189            }
190        })
191        .collect()
192}
193
194fn cached_unknown_suppressions_to_module(
195    unknown_suppression_kinds: &[CachedUnknownSuppressionKind],
196) -> Vec<fallow_types::suppress::UnknownSuppressionKind> {
197    unknown_suppression_kinds
198        .iter()
199        .map(|unknown| fallow_types::suppress::UnknownSuppressionKind {
200            comment_line: unknown.comment_line,
201            is_file_level: unknown.is_file_level,
202            token: unknown.token.clone(),
203            reason: unknown.reason.clone(),
204        })
205        .collect()
206}
207
208fn cached_local_types_to_module(
209    local_type_declarations: &[CachedLocalTypeDeclaration],
210) -> Vec<crate::LocalTypeDeclaration> {
211    local_type_declarations
212        .iter()
213        .map(|declaration| crate::LocalTypeDeclaration {
214            name: declaration.name.clone(),
215            span: Span::new(declaration.span_start, declaration.span_end),
216        })
217        .collect()
218}
219
220fn cached_signature_refs_to_module(
221    public_signature_type_references: &[CachedPublicSignatureTypeReference],
222) -> Vec<crate::PublicSignatureTypeReference> {
223    public_signature_type_references
224        .iter()
225        .map(|reference| crate::PublicSignatureTypeReference {
226            export_name: reference.export_name.clone(),
227            type_name: reference.type_name.clone(),
228            span: Span::new(reference.span_start, reference.span_end),
229        })
230        .collect()
231}
232
233fn cached_namespace_aliases_to_module(
234    namespace_object_aliases: &[CachedNamespaceObjectAlias],
235) -> Vec<NamespaceObjectAlias> {
236    namespace_object_aliases
237        .iter()
238        .map(|alias| NamespaceObjectAlias {
239            via_export_name: alias.via_export_name.clone(),
240            suffix: alias.suffix.clone(),
241            namespace_local: alias.namespace_local.clone(),
242        })
243        .collect()
244}
245
246fn module_exports_to_cached(exports: &[crate::ExportInfo]) -> Vec<CachedExport> {
247    exports
248        .iter()
249        .map(|export| CachedExport {
250            name: match &export.name {
251                ExportName::Named(name) => name.clone(),
252                ExportName::Default => String::new(),
253            },
254            is_default: matches!(export.name, ExportName::Default),
255            is_type_only: export.is_type_only,
256            is_side_effect_used: export.is_side_effect_used,
257            visibility: export.visibility as u8,
258            expected_unused_reason: export.expected_unused_reason.clone(),
259            local_name: export.local_name.clone(),
260            span_start: export.span.start,
261            span_end: export.span.end,
262            members: export
263                .members
264                .iter()
265                .map(|member| CachedMember {
266                    name: member.name.clone(),
267                    kind: member.kind,
268                    span_start: member.span.start,
269                    span_end: member.span.end,
270                    has_decorator: member.has_decorator,
271                    decorator_names: member.decorator_names.clone(),
272                    is_instance_returning_static: member.is_instance_returning_static,
273                    is_self_returning: member.is_self_returning,
274                })
275                .collect(),
276            super_class: export.super_class.clone(),
277        })
278        .collect()
279}
280
281fn module_imports_to_cached(imports: &[crate::ImportInfo]) -> Vec<CachedImport> {
282    imports
283        .iter()
284        .map(|import| {
285            let (kind, imported_name) = match &import.imported_name {
286                crate::ImportedName::Named(name) => (IMPORT_KIND_NAMED, name.clone()),
287                crate::ImportedName::Default => (IMPORT_KIND_DEFAULT, String::new()),
288                crate::ImportedName::Namespace => (IMPORT_KIND_NAMESPACE, String::new()),
289                crate::ImportedName::SideEffect => (IMPORT_KIND_SIDE_EFFECT, String::new()),
290            };
291            CachedImport {
292                source: import.source.clone(),
293                imported_name,
294                local_name: import.local_name.clone(),
295                is_type_only: import.is_type_only,
296                from_style: import.from_style,
297                kind,
298                span_start: import.span.start,
299                span_end: import.span.end,
300                source_span_start: import.source_span.start,
301                source_span_end: import.source_span.end,
302            }
303        })
304        .collect()
305}
306
307fn module_re_exports_to_cached(re_exports: &[crate::ReExportInfo]) -> Vec<CachedReExport> {
308    re_exports
309        .iter()
310        .map(|re_export| CachedReExport {
311            source: re_export.source.clone(),
312            imported_name: re_export.imported_name.clone(),
313            exported_name: re_export.exported_name.clone(),
314            is_type_only: re_export.is_type_only,
315            span_start: re_export.span.start,
316            span_end: re_export.span.end,
317        })
318        .collect()
319}
320
321fn module_dynamic_imports_to_cached(
322    dynamic_imports: &[crate::DynamicImportInfo],
323) -> Vec<CachedDynamicImport> {
324    dynamic_imports
325        .iter()
326        .map(|dynamic_import| CachedDynamicImport {
327            source: dynamic_import.source.clone(),
328            span_start: dynamic_import.span.start,
329            span_end: dynamic_import.span.end,
330            destructured_names: dynamic_import.destructured_names.clone(),
331            local_name: dynamic_import.local_name.clone(),
332            is_speculative: dynamic_import.is_speculative,
333        })
334        .collect()
335}
336
337fn module_require_calls_to_cached(
338    require_calls: &[crate::RequireCallInfo],
339) -> Vec<CachedRequireCall> {
340    require_calls
341        .iter()
342        .map(|require_call| CachedRequireCall {
343            source: require_call.source.clone(),
344            span_start: require_call.span.start,
345            span_end: require_call.span.end,
346            source_span_start: require_call.source_span.start,
347            source_span_end: require_call.source_span.end,
348            destructured_names: require_call.destructured_names.clone(),
349            local_name: require_call.local_name.clone(),
350        })
351        .collect()
352}
353
354fn module_dynamic_patterns_to_cached(
355    dynamic_import_patterns: &[crate::DynamicImportPattern],
356) -> Vec<CachedDynamicImportPattern> {
357    dynamic_import_patterns
358        .iter()
359        .map(|pattern| CachedDynamicImportPattern {
360            prefix: pattern.prefix.clone(),
361            suffix: pattern.suffix.clone(),
362            span_start: pattern.span.start,
363            span_end: pattern.span.end,
364        })
365        .collect()
366}
367
368fn module_suppressions_to_cached(
369    suppressions: &[crate::suppress::Suppression],
370) -> Vec<CachedSuppression> {
371    suppressions
372        .iter()
373        .map(|suppression| {
374            let (kind, policy_pack, policy_rule_id) = match &suppression.target {
375                None => (0, String::new(), String::new()),
376                Some(SuppressionTarget::Issue(kind)) => {
377                    (kind.to_discriminant(), String::new(), String::new())
378                }
379                Some(SuppressionTarget::PolicyRule(target)) => (
380                    crate::suppress::IssueKind::PolicyViolation.to_discriminant(),
381                    target.pack.clone(),
382                    target.rule_id.clone(),
383                ),
384            };
385            CachedSuppression {
386                line: suppression.line,
387                comment_line: suppression.comment_line,
388                kind,
389                policy_pack,
390                policy_rule_id,
391                reason: suppression.reason.clone(),
392            }
393        })
394        .collect()
395}
396
397fn module_unknown_suppressions_to_cached(
398    unknown_suppression_kinds: &[fallow_types::suppress::UnknownSuppressionKind],
399) -> Vec<CachedUnknownSuppressionKind> {
400    unknown_suppression_kinds
401        .iter()
402        .map(|unknown| CachedUnknownSuppressionKind {
403            comment_line: unknown.comment_line,
404            is_file_level: unknown.is_file_level,
405            token: unknown.token.clone(),
406            reason: unknown.reason.clone(),
407        })
408        .collect()
409}
410
411fn module_local_types_to_cached(
412    local_type_declarations: &[crate::LocalTypeDeclaration],
413) -> Vec<CachedLocalTypeDeclaration> {
414    local_type_declarations
415        .iter()
416        .map(|declaration| CachedLocalTypeDeclaration {
417            name: declaration.name.clone(),
418            span_start: declaration.span.start,
419            span_end: declaration.span.end,
420        })
421        .collect()
422}
423
424fn module_signature_refs_to_cached(
425    public_signature_type_references: &[crate::PublicSignatureTypeReference],
426) -> Vec<CachedPublicSignatureTypeReference> {
427    public_signature_type_references
428        .iter()
429        .map(|reference| CachedPublicSignatureTypeReference {
430            export_name: reference.export_name.clone(),
431            type_name: reference.type_name.clone(),
432            span_start: reference.span.start,
433            span_end: reference.span.end,
434        })
435        .collect()
436}
437
438fn module_namespace_aliases_to_cached(
439    namespace_object_aliases: &[NamespaceObjectAlias],
440) -> Vec<CachedNamespaceObjectAlias> {
441    namespace_object_aliases
442        .iter()
443        .map(|alias| CachedNamespaceObjectAlias {
444            via_export_name: alias.via_export_name.clone(),
445            suffix: alias.suffix.clone(),
446            namespace_local: alias.namespace_local.clone(),
447        })
448        .collect()
449}
450
451/// Reconstruct a [`ModuleInfo`](crate::ModuleInfo) from a [`CachedModule`], skipping
452/// the per-function complexity vec when `need_complexity` is `false`. Avoids the
453/// `Vec<FunctionComplexity>` clone on warm runs of commands (e.g. `fallow dead-code`)
454/// that don't consume complexity, which adds up across tens of thousands of files.
455#[must_use]
456pub fn cached_to_module_opts(
457    cached: &CachedModule,
458    file_id: fallow_types::discover::FileId,
459    need_complexity: bool,
460) -> crate::ModuleInfo {
461    crate::ModuleInfo {
462        file_id,
463        exports: cached_exports_to_module(&cached.exports),
464        imports: cached_imports_to_module(&cached.imports),
465        re_exports: cached_re_exports_to_module(&cached.re_exports),
466        dynamic_imports: cached_dynamic_imports_to_module(&cached.dynamic_imports),
467        dynamic_import_patterns: cached_dynamic_patterns_to_module(&cached.dynamic_import_patterns),
468        require_calls: cached_require_calls_to_module(&cached.require_calls),
469        package_path_references: cached.package_path_references.clone(),
470        member_accesses: cached.member_accesses.clone(),
471        whole_object_uses: cached.whole_object_uses.clone(),
472        has_cjs_exports: cached.has_cjs_exports,
473        has_angular_component_template_url: cached.has_angular_component_template_url,
474        content_hash: cached.content_hash,
475        suppressions: cached_suppressions_to_module(&cached.suppressions),
476        unknown_suppression_kinds: cached_unknown_suppressions_to_module(
477            &cached.unknown_suppression_kinds,
478        ),
479        unused_import_bindings: cached.unused_import_bindings.clone(),
480        type_referenced_import_bindings: cached.type_referenced_import_bindings.clone(),
481        value_referenced_import_bindings: cached.value_referenced_import_bindings.clone(),
482        line_offsets: cached.line_offsets.clone(),
483        complexity: if need_complexity {
484            cached.complexity.clone()
485        } else {
486            Vec::new()
487        },
488        flag_uses: cached.flag_uses.clone(),
489        class_heritage: cached.class_heritage.clone(),
490        injection_tokens: cached.injection_tokens.clone(),
491        local_type_declarations: cached_local_types_to_module(&cached.local_type_declarations),
492        public_signature_type_references: cached_signature_refs_to_module(
493            &cached.public_signature_type_references,
494        ),
495        namespace_object_aliases: cached_namespace_aliases_to_module(
496            &cached.namespace_object_aliases,
497        ),
498        iconify_prefixes: cached.iconify_prefixes.clone(),
499        iconify_icon_names: cached.iconify_icon_names.clone(),
500        auto_import_candidates: cached.auto_import_candidates.clone(),
501        directives: cached.directives.clone(),
502        client_only_dynamic_import_spans: cached.client_only_dynamic_import_spans.clone(),
503        security_sinks: cached.security_sinks.clone(),
504        security_sinks_skipped: cached.security_sinks_skipped,
505        security_unresolved_callee_sites: cached.security_unresolved_callee_sites.clone(),
506        tainted_bindings: cached.tainted_bindings.clone(),
507        sanitized_sink_args: cached.sanitized_sink_args.clone(),
508        security_control_sites: cached.security_control_sites.clone(),
509        callee_uses: cached.callee_uses.clone(),
510        misplaced_directives: cached.misplaced_directives.clone(),
511        inline_server_action_exports: cached.inline_server_action_exports.clone(),
512        di_key_sites: cached.di_key_sites.clone(),
513        has_dynamic_provide: cached.has_dynamic_provide,
514        // Derived in `release_resolution_payload` from `imports` + `unused_import_bindings`
515        // (both cached); never persisted, so the cache-load path leaves it empty.
516        referenced_import_bindings: Vec::new(),
517        component_props: cached.component_props.clone(),
518        has_props_attrs_fallthrough: cached.has_props_attrs_fallthrough,
519        has_define_expose: cached.has_define_expose,
520        has_define_model: cached.has_define_model,
521        has_unharvestable_props: cached.has_unharvestable_props,
522        component_emits: cached.component_emits.clone(),
523        angular_inputs: cached.angular_inputs.clone(),
524        angular_outputs: cached.angular_outputs.clone(),
525        angular_component_selectors: cached.angular_component_selectors.clone(),
526        angular_used_selectors: cached.angular_used_selectors.clone(),
527        angular_entry_component_refs: cached.angular_entry_component_refs.clone(),
528        has_dynamic_component_render: cached.has_dynamic_component_render,
529        has_unharvestable_emits: cached.has_unharvestable_emits,
530        has_dynamic_emit: cached.has_dynamic_emit,
531        has_emit_whole_object_use: cached.has_emit_whole_object_use,
532        load_return_keys: cached.load_return_keys.clone(),
533        has_unharvestable_load: cached.has_unharvestable_load,
534        has_load_data_whole_use: cached.has_load_data_whole_use,
535        // Derived in `release_resolution_payload` from `whole_object_uses`.
536        has_page_data_store_whole_use: false,
537        component_functions: cached.component_functions.clone(),
538        react_props: cached.react_props.clone(),
539        hook_uses: cached.hook_uses.clone(),
540        render_edges: cached.render_edges.clone(),
541        svelte_dispatched_events: cached.svelte_dispatched_events.clone(),
542        svelte_listened_events: cached.svelte_listened_events.clone(),
543        has_dynamic_dispatch: cached.has_dynamic_dispatch,
544    }
545}
546
547/// Convert a [`ModuleInfo`](crate::ModuleInfo) to a [`CachedModule`] for storage.
548///
549/// `mtime_secs` and `file_size` come from `std::fs::metadata()` at parse time
550/// and enable fast cache validation on subsequent runs (skip file read when
551/// mtime+size match).
552#[must_use]
553pub fn module_to_cached(
554    module: &crate::ModuleInfo,
555    mtime_secs: u64,
556    file_size: u64,
557) -> CachedModule {
558    CachedModule {
559        content_hash: module.content_hash,
560        mtime_secs,
561        file_size,
562        last_access_secs: current_unix_seconds(),
563        exports: module_exports_to_cached(&module.exports),
564        imports: module_imports_to_cached(&module.imports),
565        re_exports: module_re_exports_to_cached(&module.re_exports),
566        dynamic_imports: module_dynamic_imports_to_cached(&module.dynamic_imports),
567        require_calls: module_require_calls_to_cached(&module.require_calls),
568        package_path_references: module.package_path_references.clone(),
569        member_accesses: module.member_accesses.clone(),
570        whole_object_uses: module.whole_object_uses.clone(),
571        dynamic_import_patterns: module_dynamic_patterns_to_cached(&module.dynamic_import_patterns),
572        has_cjs_exports: module.has_cjs_exports,
573        has_angular_component_template_url: module.has_angular_component_template_url,
574        unused_import_bindings: module.unused_import_bindings.clone(),
575        type_referenced_import_bindings: module.type_referenced_import_bindings.clone(),
576        value_referenced_import_bindings: module.value_referenced_import_bindings.clone(),
577        suppressions: module_suppressions_to_cached(&module.suppressions),
578        unknown_suppression_kinds: module_unknown_suppressions_to_cached(
579            &module.unknown_suppression_kinds,
580        ),
581        line_offsets: module.line_offsets.clone(),
582        complexity: module.complexity.clone(),
583        flag_uses: module.flag_uses.clone(),
584        class_heritage: module.class_heritage.clone(),
585        injection_tokens: module.injection_tokens.clone(),
586        local_type_declarations: module_local_types_to_cached(&module.local_type_declarations),
587        public_signature_type_references: module_signature_refs_to_cached(
588            &module.public_signature_type_references,
589        ),
590        namespace_object_aliases: module_namespace_aliases_to_cached(
591            &module.namespace_object_aliases,
592        ),
593        iconify_prefixes: module.iconify_prefixes.clone(),
594        iconify_icon_names: module.iconify_icon_names.clone(),
595        auto_import_candidates: module.auto_import_candidates.clone(),
596        directives: module.directives.clone(),
597        client_only_dynamic_import_spans: module.client_only_dynamic_import_spans.clone(),
598        security_sinks: module.security_sinks.clone(),
599        security_sinks_skipped: module.security_sinks_skipped,
600        security_unresolved_callee_sites: module.security_unresolved_callee_sites.clone(),
601        tainted_bindings: module.tainted_bindings.clone(),
602        sanitized_sink_args: module.sanitized_sink_args.clone(),
603        security_control_sites: module.security_control_sites.clone(),
604        callee_uses: module.callee_uses.clone(),
605        misplaced_directives: module.misplaced_directives.clone(),
606        inline_server_action_exports: module.inline_server_action_exports.clone(),
607        di_key_sites: module.di_key_sites.clone(),
608        has_dynamic_provide: module.has_dynamic_provide,
609        component_props: module.component_props.clone(),
610        has_props_attrs_fallthrough: module.has_props_attrs_fallthrough,
611        has_define_expose: module.has_define_expose,
612        has_define_model: module.has_define_model,
613        has_unharvestable_props: module.has_unharvestable_props,
614        component_emits: module.component_emits.clone(),
615        angular_inputs: module.angular_inputs.clone(),
616        angular_outputs: module.angular_outputs.clone(),
617        angular_component_selectors: module.angular_component_selectors.clone(),
618        angular_used_selectors: module.angular_used_selectors.clone(),
619        angular_entry_component_refs: module.angular_entry_component_refs.clone(),
620        has_dynamic_component_render: module.has_dynamic_component_render,
621        has_unharvestable_emits: module.has_unharvestable_emits,
622        has_dynamic_emit: module.has_dynamic_emit,
623        has_emit_whole_object_use: module.has_emit_whole_object_use,
624        load_return_keys: module.load_return_keys.clone(),
625        has_unharvestable_load: module.has_unharvestable_load,
626        has_load_data_whole_use: module.has_load_data_whole_use,
627        component_functions: module.component_functions.clone(),
628        react_props: module.react_props.clone(),
629        hook_uses: module.hook_uses.clone(),
630        render_edges: module.render_edges.clone(),
631        svelte_dispatched_events: module.svelte_dispatched_events.clone(),
632        svelte_listened_events: module.svelte_listened_events.clone(),
633        has_dynamic_dispatch: module.has_dynamic_dispatch,
634    }
635}