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