Skip to main content

fallow_extract/cache/
conversion.rs

1//! Conversion between [`ModuleInfo`](crate::ModuleInfo) and [`CachedModule`].
2
3use oxc_span::Span;
4
5use crate::ExportName;
6
7use super::types::*;
8
9/// Reconstruct a [`ModuleInfo`](crate::ModuleInfo) from a [`CachedModule`].
10#[must_use]
11pub fn cached_to_module(
12    cached: &CachedModule,
13    file_id: fallow_types::discover::FileId,
14) -> crate::ModuleInfo {
15    use crate::*;
16
17    let exports = cached
18        .exports
19        .iter()
20        .map(|e| ExportInfo {
21            name: if e.is_default {
22                ExportName::Default
23            } else {
24                ExportName::Named(e.name.clone())
25            },
26            local_name: e.local_name.clone(),
27            is_type_only: e.is_type_only,
28            is_public: e.is_public,
29            span: Span::new(e.span_start, e.span_end),
30            members: e
31                .members
32                .iter()
33                .map(|m| MemberInfo {
34                    name: m.name.clone(),
35                    kind: m.kind.clone(),
36                    span: Span::new(m.span_start, m.span_end),
37                    has_decorator: m.has_decorator,
38                })
39                .collect(),
40        })
41        .collect();
42
43    let imports = cached
44        .imports
45        .iter()
46        .map(|i| ImportInfo {
47            source: i.source.clone(),
48            imported_name: match i.kind {
49                IMPORT_KIND_DEFAULT => ImportedName::Default,
50                IMPORT_KIND_NAMESPACE => ImportedName::Namespace,
51                IMPORT_KIND_SIDE_EFFECT => ImportedName::SideEffect,
52                // IMPORT_KIND_NAMED (0) and any unknown value default to Named
53                _ => ImportedName::Named(i.imported_name.clone()),
54            },
55            local_name: i.local_name.clone(),
56            is_type_only: i.is_type_only,
57            span: Span::new(i.span_start, i.span_end),
58            source_span: Span::new(i.source_span_start, i.source_span_end),
59        })
60        .collect();
61
62    let re_exports = cached
63        .re_exports
64        .iter()
65        .map(|r| ReExportInfo {
66            source: r.source.clone(),
67            imported_name: r.imported_name.clone(),
68            exported_name: r.exported_name.clone(),
69            is_type_only: r.is_type_only,
70        })
71        .collect();
72
73    let dynamic_imports = cached
74        .dynamic_imports
75        .iter()
76        .map(|d| DynamicImportInfo {
77            source: d.source.clone(),
78            span: Span::new(d.span_start, d.span_end),
79            destructured_names: d.destructured_names.clone(),
80            local_name: d.local_name.clone(),
81        })
82        .collect();
83
84    let require_calls = cached
85        .require_calls
86        .iter()
87        .map(|r| RequireCallInfo {
88            source: r.source.clone(),
89            span: Span::new(r.span_start, r.span_end),
90            destructured_names: r.destructured_names.clone(),
91            local_name: r.local_name.clone(),
92        })
93        .collect();
94
95    let dynamic_import_patterns = cached
96        .dynamic_import_patterns
97        .iter()
98        .map(|p| crate::DynamicImportPattern {
99            prefix: p.prefix.clone(),
100            suffix: p.suffix.clone(),
101            span: Span::new(p.span_start, p.span_end),
102        })
103        .collect();
104
105    let suppressions = cached
106        .suppressions
107        .iter()
108        .map(|s| crate::suppress::Suppression {
109            line: s.line,
110            kind: if s.kind == 0 {
111                None
112            } else {
113                crate::suppress::IssueKind::from_discriminant(s.kind)
114            },
115        })
116        .collect();
117
118    ModuleInfo {
119        file_id,
120        exports,
121        imports,
122        re_exports,
123        dynamic_imports,
124        dynamic_import_patterns,
125        require_calls,
126        member_accesses: cached.member_accesses.clone(),
127        whole_object_uses: cached.whole_object_uses.clone(),
128        has_cjs_exports: cached.has_cjs_exports,
129        content_hash: cached.content_hash,
130        suppressions,
131        unused_import_bindings: cached.unused_import_bindings.clone(),
132        line_offsets: cached.line_offsets.clone(),
133        complexity: cached.complexity.clone(),
134    }
135}
136
137/// Convert a [`ModuleInfo`](crate::ModuleInfo) to a [`CachedModule`] for storage.
138///
139/// `mtime_secs` and `file_size` come from `std::fs::metadata()` at parse time
140/// and enable fast cache validation on subsequent runs (skip file read when
141/// mtime+size match).
142#[must_use]
143pub fn module_to_cached(
144    module: &crate::ModuleInfo,
145    mtime_secs: u64,
146    file_size: u64,
147) -> CachedModule {
148    CachedModule {
149        content_hash: module.content_hash,
150        mtime_secs,
151        file_size,
152        exports: module
153            .exports
154            .iter()
155            .map(|e| CachedExport {
156                name: match &e.name {
157                    ExportName::Named(n) => n.clone(),
158                    ExportName::Default => String::new(),
159                },
160                is_default: matches!(e.name, ExportName::Default),
161                is_type_only: e.is_type_only,
162                is_public: e.is_public,
163                local_name: e.local_name.clone(),
164                span_start: e.span.start,
165                span_end: e.span.end,
166                members: e
167                    .members
168                    .iter()
169                    .map(|m| CachedMember {
170                        name: m.name.clone(),
171                        kind: m.kind.clone(),
172                        span_start: m.span.start,
173                        span_end: m.span.end,
174                        has_decorator: m.has_decorator,
175                    })
176                    .collect(),
177            })
178            .collect(),
179        imports: module
180            .imports
181            .iter()
182            .map(|i| {
183                let (kind, imported_name) = match &i.imported_name {
184                    crate::ImportedName::Named(n) => (IMPORT_KIND_NAMED, n.clone()),
185                    crate::ImportedName::Default => (IMPORT_KIND_DEFAULT, String::new()),
186                    crate::ImportedName::Namespace => (IMPORT_KIND_NAMESPACE, String::new()),
187                    crate::ImportedName::SideEffect => (IMPORT_KIND_SIDE_EFFECT, String::new()),
188                };
189                CachedImport {
190                    source: i.source.clone(),
191                    imported_name,
192                    local_name: i.local_name.clone(),
193                    is_type_only: i.is_type_only,
194                    kind,
195                    span_start: i.span.start,
196                    span_end: i.span.end,
197                    source_span_start: i.source_span.start,
198                    source_span_end: i.source_span.end,
199                }
200            })
201            .collect(),
202        re_exports: module
203            .re_exports
204            .iter()
205            .map(|r| CachedReExport {
206                source: r.source.clone(),
207                imported_name: r.imported_name.clone(),
208                exported_name: r.exported_name.clone(),
209                is_type_only: r.is_type_only,
210            })
211            .collect(),
212        dynamic_imports: module
213            .dynamic_imports
214            .iter()
215            .map(|d| CachedDynamicImport {
216                source: d.source.clone(),
217                span_start: d.span.start,
218                span_end: d.span.end,
219                destructured_names: d.destructured_names.clone(),
220                local_name: d.local_name.clone(),
221            })
222            .collect(),
223        require_calls: module
224            .require_calls
225            .iter()
226            .map(|r| CachedRequireCall {
227                source: r.source.clone(),
228                span_start: r.span.start,
229                span_end: r.span.end,
230                destructured_names: r.destructured_names.clone(),
231                local_name: r.local_name.clone(),
232            })
233            .collect(),
234        member_accesses: module.member_accesses.clone(),
235        whole_object_uses: module.whole_object_uses.clone(),
236        dynamic_import_patterns: module
237            .dynamic_import_patterns
238            .iter()
239            .map(|p| CachedDynamicImportPattern {
240                prefix: p.prefix.clone(),
241                suffix: p.suffix.clone(),
242                span_start: p.span.start,
243                span_end: p.span.end,
244            })
245            .collect(),
246        has_cjs_exports: module.has_cjs_exports,
247        unused_import_bindings: module.unused_import_bindings.clone(),
248        suppressions: module
249            .suppressions
250            .iter()
251            .map(|s| CachedSuppression {
252                line: s.line,
253                kind: s
254                    .kind
255                    .map_or(0, crate::suppress::IssueKind::to_discriminant),
256            })
257            .collect(),
258        line_offsets: module.line_offsets.clone(),
259        complexity: module.complexity.clone(),
260    }
261}