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