fallow_extract/cache/types.rs
1//! Serialization types for the incremental parse cache.
2//!
3//! All types use bitcode `Encode`/`Decode` for fast binary serialization.
4
5use bitcode::{Decode, Encode};
6
7use crate::MemberKind;
8
9/// Cache version. Bump it when the serialized cache shape or the cached
10/// extraction semantics change, and give the reason in the commit message and
11/// the CHANGELOG. A stale version serves old extraction results from a warm
12/// cache. The `assert_cached_type_size!` guards below catch shape changes.
13pub(super) const CACHE_VERSION: u32 = 339;
14
15/// Duplication token cache version. Bump it when duplicate tokenization,
16/// normalization, or the on-disk token cache schema changes, and give the
17/// reason in the commit message and the CHANGELOG.
18pub const DUPES_CACHE_VERSION: u32 = 15;
19
20/// Default maximum cache size (256 MB). Overridable per-project via
21/// `cache.maxSizeMb` in the config file or `FALLOW_CACHE_MAX_SIZE` env var.
22/// Also used as the hard ceiling on load-time deserialization as a defence
23/// against pathological on-disk files.
24pub const DEFAULT_CACHE_MAX_SIZE: usize = 256 * 1024 * 1024;
25
26/// Trigger LRU eviction when the serialized cache exceeds 80% of the cap.
27/// Basis points (1/100 of a percent) for integer arithmetic without floats.
28pub(super) const EVICTION_TRIGGER_BPS: usize = 8000;
29
30/// Evict down to 60% of the cap so subsequent saves leave headroom.
31pub(super) const EVICTION_TARGET_BPS: usize = 6000;
32
33/// Promote the eviction log from `debug!` to `info!` when at least 25% of
34/// entries are removed in a single save. Default-noise concerns mean
35/// small-turnover saves should not be visible without `RUST_LOG=debug`.
36pub(super) const EVICTION_SIGNIFICANT_BPS: usize = 2500;
37
38/// Import kind discriminant for `CachedImport`:
39/// 0 = Named, 1 = Default, 2 = Namespace, 3 = `SideEffect`.
40pub(super) const IMPORT_KIND_NAMED: u8 = 0;
41pub(super) const IMPORT_KIND_DEFAULT: u8 = 1;
42pub(super) const IMPORT_KIND_NAMESPACE: u8 = 2;
43pub(super) const IMPORT_KIND_SIDE_EFFECT: u8 = 3;
44
45macro_rules! assert_cached_type_size {
46 ($ty:ty, $size:expr) => {
47 const _: () = assert!(
48 std::mem::size_of::<$ty>() == $size,
49 concat!(
50 stringify!($ty),
51 " size changed; bump CACHE_VERSION if the cached wire shape or extraction semantics changed, then update this assertion"
52 )
53 );
54 };
55}
56
57assert_cached_type_size!(CachedModule, 1496);
58assert_cached_type_size!(CachedNamespaceObjectAlias, 72);
59assert_cached_type_size!(CachedLocalTypeDeclaration, 32);
60assert_cached_type_size!(CachedPublicSignatureTypeReference, 64);
61assert_cached_type_size!(CachedSuppression, 88);
62assert_cached_type_size!(CachedUnknownSuppressionKind, 56);
63assert_cached_type_size!(CachedExport, 152);
64assert_cached_type_size!(CachedImport, 96);
65assert_cached_type_size!(CachedDynamicImport, 88);
66assert_cached_type_size!(CachedRequireCall, 96);
67assert_cached_type_size!(CachedReExport, 104);
68assert_cached_type_size!(CachedMember, 64);
69assert_cached_type_size!(CachedDynamicImportPattern, 64);
70assert_cached_type_size!(crate::MemberAccess, 48);
71assert_cached_type_size!(fallow_types::extract::SemanticFact, 96);
72assert_cached_type_size!(fallow_types::extract::CalleeUse, 32);
73assert_cached_type_size!(fallow_types::extract::ImportedCallSite, 80);
74assert_cached_type_size!(fallow_types::extract::ImportBindingReference, 64);
75assert_cached_type_size!(fallow_types::extract::MisplacedDirectiveSite, 8);
76assert_cached_type_size!(fallow_types::extract::SinkSite, 216);
77assert_cached_type_size!(fallow_types::extract::FunctionComplexity, 96);
78assert_cached_type_size!(fallow_types::extract::ComplexityContribution, 16);
79assert_cached_type_size!(fallow_types::extract::FlagUse, 80);
80assert_cached_type_size!(fallow_types::extract::ClassHeritageInfo, 168);
81assert_cached_type_size!(fallow_types::extract::FactoryReturnExport, 56);
82assert_cached_type_size!(fallow_types::extract::TypeMemberTypeEntry, 72);
83assert_cached_type_size!(fallow_types::extract::LoadReturnKey, 32);
84
85/// Cached data for a single module.
86#[derive(Debug, Clone, Encode, Decode)]
87pub struct CachedModule {
88 /// xxh3 hash of the file content.
89 pub content_hash: u64,
90 /// File modification time in nanoseconds for fast cache validation.
91 /// When mtime+ctime+size match the on-disk file, we skip reading file
92 /// content entirely.
93 pub mtime_ns: u64,
94 /// File inode change time in nanoseconds, or `0` on platforms that do not
95 /// report one. Stored beside `mtime_ns` because mtime is writer-controlled:
96 /// a same-length rewrite with a restored mtime is invisible to
97 /// `(mtime, size)` alone, and the metadata-only fast path would then hand
98 /// back analysis of the previous content.
99 pub ctime_ns: u64,
100 /// File size in bytes for fast cache validation.
101 pub file_size: u64,
102 /// Seconds-since-epoch at the time this entry was last WRITTEN
103 /// (first parse or content-change refresh). NOT updated on cache-hit
104 /// reads: `update_cache` already iterates every in-scope file every run,
105 /// so refreshing on read would collapse the LRU to "last run this file
106 /// was discovered" for every retained entry. With write-only refresh,
107 /// the LRU genuinely targets stale (in-scope-but-unchanged-for-many-runs)
108 /// entries. Used by `CacheStore::save` for write-time eviction ordering.
109 pub last_access_secs: u64,
110 /// Exported symbols.
111 pub exports: Vec<CachedExport>,
112 /// Import specifiers.
113 pub imports: Vec<CachedImport>,
114 /// Re-export specifiers.
115 pub re_exports: Vec<CachedReExport>,
116 /// Dynamic import specifiers.
117 pub dynamic_imports: Vec<CachedDynamicImport>,
118 /// `require()` specifiers.
119 pub require_calls: Vec<CachedRequireCall>,
120 /// Package names statically referenced through package path resolution.
121 pub package_path_references: Box<[String]>,
122 /// Package names that a module augmentation (`declare module 'pkg'` in a
123 /// module file) names. They credit the package as a type-only use.
124 pub type_package_references: Box<[String]>,
125 /// Binary names found in `node_modules/.bin/<name>` paths in string
126 /// literals and template quasis. The analysis maps each name to the
127 /// package that declares the binary.
128 pub bin_path_references: Box<[String]>,
129 /// Package names from direct `require.resolve` calls, with call offsets.
130 pub package_resolve_sites: Box<[(String, u32)]>,
131 /// Static member accesses (e.g., `Status.Active`).
132 pub member_accesses: Vec<crate::MemberAccess>,
133 /// Typed semantic facts produced by extraction for cross-layer analysis.
134 /// `None` means no facts, which keeps the common warm-cache payload lean.
135 pub semantic_facts: Option<Box<[fallow_types::extract::SemanticFact]>>,
136 /// Identifiers used as whole objects (Object.values, for..in, spread, etc.).
137 pub whole_object_uses: Box<[String]>,
138 /// Dynamic import patterns with partial static resolution.
139 pub dynamic_import_patterns: Vec<CachedDynamicImportPattern>,
140 /// Number of parser diagnostics the parse of this file produced.
141 /// Round-trips so a warm load still reports `source-parse-degraded`
142 /// instead of silently inheriting a partial parse.
143 pub parse_error_count: u32,
144 /// Whether the parser abandoned this file instead of recovering.
145 pub parse_panicked: bool,
146 /// Whether this module uses CJS exports.
147 pub has_cjs_exports: bool,
148 /// Whether this module declares at least one Angular `@Component({
149 /// templateUrl: ... })` decorator. Mirrors `ModuleInfo.has_angular_component_template_url`
150 /// so the CRAP-inherit walker's gate survives a warm-cache load.
151 pub has_angular_component_template_url: bool,
152 /// Local names of import bindings that are never referenced in this file.
153 pub unused_import_bindings: Vec<String>,
154 /// Local import bindings referenced from type positions.
155 pub type_referenced_import_bindings: Vec<String>,
156 /// Local import bindings referenced from value positions.
157 pub value_referenced_import_bindings: Vec<String>,
158 /// Inline suppression directives.
159 pub suppressions: Vec<CachedSuppression>,
160 /// Suppression tokens that did not parse to any known `IssueKind`. See #449.
161 pub unknown_suppression_kinds: Vec<CachedUnknownSuppressionKind>,
162 /// Pre-computed line-start byte offsets for O(log N) byte-to-line/col conversion.
163 pub line_offsets: Vec<u32>,
164 /// Per-function complexity metrics.
165 pub complexity: Vec<fallow_types::extract::FunctionComplexity>,
166 /// Whether the run that wrote this entry actually extracted complexity.
167 ///
168 /// An empty `complexity` vector is ambiguous on its own: a `dead-code` run
169 /// passes `need_complexity == false` and produces one, and so does a file
170 /// with no functions at all. Reading emptiness as "not cached" made every
171 /// later `health` run pay a full cold parse for a file that was already
172 /// analyzed. This flag is the honest answer, so a complexity consumer can
173 /// hit on a rich entry and a complexity-blind run can refuse to downgrade
174 /// one.
175 pub complexity_extracted: bool,
176 /// Feature flag use sites.
177 pub flag_uses: Vec<fallow_types::extract::FlagUse>,
178 /// Flag-key registries and registry reads.
179 pub flag_registry_facts: Option<Box<fallow_types::extract::FlagRegistryFacts>>,
180 /// Heritage metadata for exported classes.
181 pub class_heritage: Vec<fallow_types::extract::ClassHeritageInfo>,
182 /// Exported free-function factories that provably return one class instance
183 /// (`export function useApi() { return new RESTApi() }`). Compacted to `None`
184 /// when empty so the common no-factory module pays no payload. See #1441 Part A.
185 pub exported_factory_returns: Option<Box<[fallow_types::extract::FactoryReturnExport]>>,
186 /// Object-literal factory-return shapes (`export function createUi() {
187 /// return { orders: factory.ordersPage } }`). Compacted to `None` when empty
188 /// so the common no-object-factory module pays no payload. See issue #1858.
189 pub exported_factory_return_object_shapes:
190 Option<Box<[fallow_types::extract::FactoryReturnObjectShapeExport]>>,
191 /// Named-type property types declared by top-level interfaces and
192 /// type-literal aliases (`interface Opts { c: OptDep }`). Compacted to
193 /// `None` when empty so the common no-interface module pays no payload.
194 /// See issue #1785.
195 pub type_member_types: Option<Box<[fallow_types::extract::TypeMemberTypeEntry]>>,
196 /// Angular `InjectionToken<Interface>` `(token, interface)` pairs (#920).
197 pub injection_tokens: Vec<(String, String)>,
198 /// Local type-capable declarations.
199 pub local_type_declarations: Vec<CachedLocalTypeDeclaration>,
200 /// Type references from exported public signatures.
201 pub public_signature_type_references: Vec<CachedPublicSignatureTypeReference>,
202 /// Namespace-import aliases re-exported through an object literal
203 /// (`export const API = { foo }` where `foo` is `import * as foo from './bar'`).
204 pub namespace_object_aliases: Vec<CachedNamespaceObjectAlias>,
205 /// Iconify collection prefixes found in static icon props (issue #608).
206 pub iconify_prefixes: Vec<String>,
207 /// Nuxt UI icon class suffixes found in static script-side icon properties
208 /// (issue #955).
209 pub iconify_icon_names: Vec<String>,
210 /// Bare identifier names that are candidates for convention auto-import
211 /// resolution (issue #704). Content-local, so they round-trip through the
212 /// cache; resolution against the plugin table happens at graph-build time.
213 pub auto_import_candidates: Vec<String>,
214 /// File-level string directives (`"use client"`, `"use server"`). Content-local,
215 /// round-trips through the cache so the security `client-server-leak` detector
216 /// sees directives on warm-cache loads.
217 pub directives: Vec<String>,
218 /// Byte-offset starts of `next/dynamic(..., { ssr: false })` dynamic imports.
219 /// Content-local, round-trips so the security `client-server-leak` BFS sees
220 /// the ssr:false client-only escape hatch on warm-cache loads.
221 pub client_only_dynamic_import_spans: Vec<u32>,
222 /// Captured security sink sites (category-blind). Round-trips through the
223 /// cache so the catalogue-driven `tainted_sink` detector sees sinks on
224 /// warm-cache loads.
225 pub security_sinks: Vec<fallow_types::extract::SinkSite>,
226 /// Count of sink-shaped nodes whose callee could not be flattened to a
227 /// static path. Round-trips so the in-band blind-spot count is stable.
228 pub security_sinks_skipped: u32,
229 /// Span-level diagnostics for skipped security sink callees.
230 pub security_unresolved_callee_sites: Vec<fallow_types::extract::SkippedSecurityCalleeSite>,
231 /// Local bindings tied to the member-access path they were sourced from.
232 /// Round-trips so the security `tainted_sink` source-to-sink association
233 /// sees source-tainted bindings on warm-cache loads.
234 pub tainted_bindings: Vec<fallow_types::extract::TaintedBinding>,
235 /// Direct sink arguments recognized as sanitizer calls.
236 pub sanitized_sink_args: Vec<fallow_types::extract::SanitizedSinkArg>,
237 /// Defensive control call sites for security surface output.
238 pub security_control_sites: Vec<fallow_types::extract::SecurityControlSite>,
239 /// Deduped statically flattenable callee paths. Round-trips so the
240 /// `boundaries.calls.forbidden` detector sees call sites on warm-cache
241 /// loads.
242 pub callee_uses: Vec<fallow_types::extract::CalleeUse>,
243 /// Scope-resolved imported calls, preserving each occurrence and argument.
244 pub imported_call_sites: Vec<fallow_types::extract::ImportedCallSite>,
245 /// Import binding references for `fallow trace --dependency`. Round-trips
246 /// so the dependency usage trace sees them on warm-cache loads.
247 pub import_binding_references: Vec<fallow_types::extract::ImportBindingReference>,
248 /// Misplaced `"use client"` / `"use server"` directive sites.
249 /// Round-trips so the `misplaced-directive` detector sees them on
250 /// warm-cache loads.
251 pub misplaced_directives: Vec<fallow_types::extract::MisplacedDirectiveSite>,
252 /// Export local names of inline `"use server"` body Server Actions.
253 /// Round-trips so the `unused-server-action` reclassifier sees them on
254 /// warm-cache loads.
255 pub inline_server_action_exports: Vec<String>,
256 /// Vue `provide`/`inject` and Svelte `setContext`/`getContext` key sites.
257 /// Round-trips so the `unprovided-inject` detector sees them on warm-cache
258 /// loads.
259 pub di_key_sites: Vec<fallow_types::extract::DiKeySite>,
260 /// Whether the module had an unknowable-key provide. Round-trips so the
261 /// `unprovided-inject` project-wide abstain holds on warm-cache loads.
262 pub has_dynamic_provide: bool,
263 /// All-action `"use server"` module flag. Round-trips so the security
264 /// `client-server-leak` BFS sees the action boundary on warm-cache loads.
265 pub is_server_action_module: bool,
266 /// Global-scope declaration flag. Mirrors `ModuleInfo.has_global_declarations`.
267 pub has_global_declarations: bool,
268 /// `/// <reference path>` values. Mirrors `ModuleInfo.triple_slash_reference_paths`.
269 pub triple_slash_reference_paths: Box<[String]>,
270 /// Config JSX runtime flag. Mirrors `ModuleInfo.jsx_runtime_from_config`.
271 pub jsx_runtime_from_config: bool,
272 /// Vue `<script setup>` `defineProps` and Svelte 5 `$props()` declared props.
273 /// Round-trips so the `unused-component-prop` detector sees them on
274 /// warm-cache loads.
275 pub component_props: Vec<fallow_types::extract::ComponentProp>,
276 /// Framework-neutral input contracts and inspected caller evidence.
277 pub component_contracts: Option<Box<fallow_types::extract::ComponentContractFacts>>,
278 /// Whether the template spreads `$attrs`/`$props`/`props` or the
279 /// `defineProps` return is rest-destructured. Round-trips for the abstain.
280 pub has_props_attrs_fallthrough: bool,
281 /// Whether the SFC calls `defineExpose(...)`. Round-trips for the abstain.
282 pub has_define_expose: bool,
283 /// Whether the SFC calls `defineModel(...)`. Round-trips for the abstain.
284 pub has_define_model: bool,
285 /// Whether `defineProps` had an unharvestable type-reference argument.
286 /// Round-trips for the abstain.
287 pub has_unharvestable_props: bool,
288 /// Vue `<script setup>` `defineEmits` declared events. Round-trips so the
289 /// `unused-component-emit` detector sees them on warm-cache loads.
290 pub component_emits: Vec<fallow_types::extract::ComponentEmit>,
291 /// Angular component/directive inputs (`@Input()` decorators and signal
292 /// `input()` / `model()` initializers). Round-trips so the
293 /// `unused-component-input` detector sees them on warm-cache loads.
294 pub angular_inputs: Vec<fallow_types::extract::AngularInputMember>,
295 /// Angular component/directive outputs (`@Output()` decorators and signal
296 /// `output()` / `outputFromObservable()` initializers). Round-trips so the
297 /// `unused-component-output` detector sees them on warm-cache loads.
298 pub angular_outputs: Vec<fallow_types::extract::AngularOutputMember>,
299 /// Angular `@Component` declarations with their `selector` value(s).
300 /// Round-trips so the Angular `unrendered-component` arm sees them on
301 /// warm-cache loads.
302 pub angular_component_selectors: Vec<fallow_types::extract::AngularComponentSelector>,
303 /// Lit / web-component custom elements registered in this file. Round-trips so
304 /// the Lit `unrendered-component` arm sees them on warm-cache loads.
305 pub registered_custom_elements: Vec<fallow_types::extract::RegisteredCustomElement>,
306 /// Custom-element tag names used (rendered) in this file's `html` templates.
307 /// Round-trips for the Lit `unrendered-component` rendered-tag union.
308 pub used_custom_element_tags: Vec<String>,
309 /// Custom element selector tags referenced in this file's Angular templates.
310 /// Round-trips for the Angular `unrendered-component` used-selector union.
311 pub angular_used_selectors: Vec<String>,
312 /// Angular route / bootstrap component class references. Round-trips for the
313 /// Angular `unrendered-component` entry-point abstain.
314 pub angular_entry_component_refs: Vec<String>,
315 /// Whether this file dynamically renders a component (project-wide abstain
316 /// signal for the Angular `unrendered-component` detector). Round-trips.
317 pub has_dynamic_component_render: bool,
318 /// Whether `defineEmits` had an unharvestable argument. Round-trips for the
319 /// abstain.
320 pub has_unharvestable_emits: bool,
321 /// Whether an `emit(<nonLiteral>)` call was seen. Round-trips for the abstain.
322 pub has_dynamic_emit: bool,
323 /// Whether the emit binding was used as a whole value. Round-trips for the
324 /// abstain.
325 pub has_emit_whole_object_use: bool,
326 /// SvelteKit `load()` return-object keys. Round-trips so the
327 /// `unused-load-data-key` detector sees them on warm-cache loads.
328 pub load_return_keys: Vec<fallow_types::extract::LoadReturnKey>,
329 /// Whether this file's `load()` body could not be harvested safely.
330 /// Round-trips for the abstain.
331 pub has_unharvestable_load: bool,
332 /// Whether this file passes the whole `data` object opaquely. Round-trips
333 /// for the `unused-load-data-key` abstain.
334 pub has_load_data_whole_use: bool,
335 /// React/JSX component definitions. Round-trips so the React-health phases
336 /// see them on warm-cache loads.
337 pub component_functions: Vec<fallow_types::extract::ComponentFunction>,
338 /// React component props. Round-trips so the React `unused-component-prop`
339 /// arm sees them on warm-cache loads.
340 pub react_props: Vec<fallow_types::extract::ComponentProp>,
341 /// React hook call sites. Round-trips for the complexity-fold phase.
342 pub hook_uses: Vec<fallow_types::extract::HookUse>,
343 /// React render edges (child name captured; resolution deferred to graph
344 /// build). Round-trips so the render graph survives a warm cache.
345 pub render_edges: Vec<fallow_types::extract::RenderEdge>,
346 /// Svelte custom events dispatched via `dispatch('<name>')`. Round-trips so
347 /// the `unused-svelte-event` detector sees them on warm-cache loads.
348 pub svelte_dispatched_events: Vec<fallow_types::extract::DispatchedEvent>,
349 /// Svelte template `on:<name>` listener names on component tags. Round-trips
350 /// so the project-wide listened set is correct on warm-cache loads.
351 pub svelte_listened_events: Vec<String>,
352 /// Whether a `dispatch(<nonLiteral>)` call or whole-`dispatch`-value use was
353 /// seen. Round-trips for the `unused-svelte-event` abstain.
354 pub has_dynamic_dispatch: bool,
355}
356
357impl CachedModule {
358 /// Source metadata fingerprint stored with this cache entry.
359 ///
360 #[must_use]
361 pub fn source_fingerprint(&self) -> fallow_types::source_fingerprint::SourceFingerprint {
362 fallow_types::source_fingerprint::SourceFingerprint::with_ctime(
363 self.mtime_ns,
364 self.ctime_ns,
365 self.file_size,
366 )
367 }
368}
369
370/// Cached namespace-object alias.
371#[derive(Debug, Clone, Encode, Decode)]
372pub struct CachedNamespaceObjectAlias {
373 /// Canonical export name on this module.
374 pub via_export_name: String,
375 /// Dotted suffix of the property path relative to the export.
376 pub suffix: String,
377 /// Local name of the namespace import on this module.
378 pub namespace_local: String,
379}
380
381/// Cached local type declaration.
382#[derive(Debug, Clone, Encode, Decode)]
383pub struct CachedLocalTypeDeclaration {
384 /// Local declaration name.
385 pub name: String,
386 /// Byte offset of the declaration span start.
387 pub span_start: u32,
388 /// Byte offset of the declaration span end.
389 pub span_end: u32,
390}
391
392/// Cached public signature type reference.
393#[derive(Debug, Clone, Encode, Decode)]
394pub struct CachedPublicSignatureTypeReference {
395 /// Exported symbol whose signature contains the reference.
396 pub export_name: String,
397 /// Referenced type name.
398 pub type_name: String,
399 /// Byte offset of the reference span start.
400 pub span_start: u32,
401 /// Byte offset of the reference span end.
402 pub span_end: u32,
403 /// True when the reference comes from a `satisfies` clause.
404 pub from_satisfies: bool,
405}
406
407/// Cached suppression directive.
408#[derive(Debug, Clone, Encode, Decode)]
409pub struct CachedSuppression {
410 /// 1-based line this suppression applies to. 0 = file-wide.
411 pub(crate) line: u32,
412 /// 1-based line where the comment itself appears.
413 pub(crate) comment_line: u32,
414 /// 0 = suppress all, otherwise `IssueKind` discriminant.
415 pub(crate) kind: u8,
416 /// Rule-pack name for scoped policy suppressions. Empty for all other
417 /// suppression targets.
418 pub(crate) policy_pack: String,
419 /// Rule id for scoped policy suppressions. Empty for all other suppression
420 /// targets.
421 pub(crate) policy_rule_id: String,
422 /// Human-authored reason after `--`, when present.
423 pub(crate) reason: Option<String>,
424}
425
426/// Cached unknown suppression kind token (see #449).
427#[derive(Debug, Clone, Encode, Decode)]
428pub struct CachedUnknownSuppressionKind {
429 /// 1-based line where the comment itself appears.
430 pub comment_line: u32,
431 /// True when the marker was `fallow-ignore-file`.
432 pub is_file_level: bool,
433 /// The verbatim token that did not parse.
434 pub token: String,
435 /// Human-authored reason after `--`, when present.
436 pub reason: Option<String>,
437}
438
439/// Cached export data for a single export declaration.
440#[derive(Debug, Clone, Encode, Decode)]
441pub struct CachedExport {
442 /// Export name (or "default" for default exports).
443 pub(crate) name: String,
444 /// Whether this is a default export.
445 pub(crate) is_default: bool,
446 /// Whether this is a type-only export.
447 pub(crate) is_type_only: bool,
448 /// Whether this export is registered through a runtime side effect at
449 /// module load time (Lit `@customElement` decorator or
450 /// `customElements.define` call). Persisted so warm-cache runs continue
451 /// to skip unused-export reporting for these classes.
452 pub(crate) is_side_effect_used: bool,
453 /// Visibility tag discriminant (0=None, 1=Public, 2=Internal, 3=Beta, 4=Alpha).
454 pub(crate) visibility: u8,
455 /// Human-authored reason on `@expected-unused -- <reason>`, when present.
456 pub(crate) expected_unused_reason: Option<String>,
457 /// Whether the leading JSDoc carries a `@deprecated` tag.
458 pub(crate) deprecated: bool,
459 /// Plain-text `@deprecated` message, `None` for a bare tag.
460 pub(crate) deprecated_reason: Option<Box<str>>,
461 /// The local binding name, if different.
462 pub(crate) local_name: Option<String>,
463 /// Byte offset of the export span start.
464 pub(crate) span_start: u32,
465 /// Byte offset of the export span end.
466 pub(crate) span_end: u32,
467 /// Members of this export (for enums and classes).
468 pub(crate) members: Vec<CachedMember>,
469 /// The local name of the parent class from `extends` clause, if any.
470 pub(crate) super_class: Option<String>,
471}
472
473/// Cached import data for a single import declaration.
474#[derive(Debug, Clone, Encode, Decode)]
475pub struct CachedImport {
476 /// The import specifier.
477 pub(crate) source: String,
478 /// For Named imports, the imported symbol name. Empty for other kinds.
479 pub(crate) imported_name: String,
480 /// The local binding name.
481 pub(crate) local_name: String,
482 /// Whether this is a type-only import.
483 pub(crate) is_type_only: bool,
484 /// Whether this whole-module import forwards type meanings only
485 /// (`export type *` inside a `declare module '...'` body).
486 pub(crate) is_type_only_star: bool,
487 /// Whether this import originated from an SFC `<style>` block / `<style src>` (CSS context).
488 pub(crate) from_style: bool,
489 /// Import kind: 0=Named, 1=Default, 2=Namespace, 3=SideEffect.
490 pub(crate) kind: u8,
491 /// Byte offset of the import span start.
492 pub(crate) span_start: u32,
493 /// Byte offset of the import span end.
494 pub(crate) span_end: u32,
495 /// Byte offset of the source string literal span start.
496 pub(crate) source_span_start: u32,
497 /// Byte offset of the source string literal span end.
498 pub(crate) source_span_end: u32,
499}
500
501/// Cached dynamic import data.
502#[derive(Debug, Clone, Encode, Decode)]
503pub struct CachedDynamicImport {
504 /// The import specifier.
505 pub(crate) source: String,
506 /// Byte offset of the span start.
507 pub(crate) span_start: u32,
508 /// Byte offset of the span end.
509 pub(crate) span_end: u32,
510 /// Names destructured from the import result.
511 pub(crate) destructured_names: Vec<String>,
512 /// Local variable name for namespace imports.
513 pub(crate) local_name: Option<String>,
514 /// True when this dynamic import was synthesised by fallow (see
515 /// `DynamicImportInfo::is_speculative`).
516 pub(crate) is_speculative: bool,
517}
518
519/// Cached `require()` call data.
520#[derive(Debug, Clone, Encode, Decode)]
521pub struct CachedRequireCall {
522 /// The require specifier.
523 pub(crate) source: String,
524 /// Byte offset of the span start.
525 pub(crate) span_start: u32,
526 /// Byte offset of the span end.
527 pub(crate) span_end: u32,
528 /// Byte offset of the specifier string-literal span start.
529 pub(crate) source_span_start: u32,
530 /// Byte offset of the specifier string-literal span end.
531 pub(crate) source_span_end: u32,
532 /// Names destructured from the require result.
533 pub(crate) destructured_names: Vec<String>,
534 /// Local variable name for namespace requires.
535 pub(crate) local_name: Option<String>,
536 /// `true` for the type-erased `import type X = require('...')` spelling.
537 pub(crate) is_type_only: bool,
538}
539
540/// Cached re-export data.
541#[derive(Debug, Clone, Encode, Decode)]
542pub struct CachedReExport {
543 /// The module being re-exported from.
544 pub(crate) source: String,
545 /// Name imported from the source.
546 pub(crate) imported_name: String,
547 /// Name exported from this module.
548 pub(crate) exported_name: String,
549 /// Whether this is a type-only re-export.
550 pub(crate) is_type_only: bool,
551 /// Byte offset of the re-export span start (for line-number reporting).
552 pub(crate) span_start: u32,
553 /// Byte offset of the re-export span end.
554 pub(crate) span_end: u32,
555 /// Byte offset of the enclosing statement span start.
556 pub(crate) statement_span_start: u32,
557 /// Byte offset of the enclosing statement span end.
558 pub(crate) statement_span_end: u32,
559 /// Byte offset of the source string-literal span start.
560 pub(crate) source_span_start: u32,
561 /// Byte offset of the source string-literal span end.
562 pub(crate) source_span_end: u32,
563}
564
565/// Cached enum or class member data.
566#[derive(Debug, Clone, Encode, Decode)]
567pub struct CachedMember {
568 /// Member name.
569 pub(crate) name: String,
570 /// Member kind (enum, method, or property).
571 pub(crate) kind: MemberKind,
572 /// Byte offset of the span start.
573 pub(crate) span_start: u32,
574 /// Byte offset of the span end.
575 pub(crate) span_end: u32,
576 /// Whether this member has decorators.
577 pub(crate) has_decorator: bool,
578 /// Full dotted path of each decorator (e.g. `step`, `ns.foo`).
579 /// Empty for undecorated members and decorators with non-identifier
580 /// expressions.
581 pub(crate) decorator_names: Vec<String>,
582 /// True when this is a static method that returns a fresh instance of
583 /// the class: body returns `new this()` / `new <SameClassName>()`, or the
584 /// declared return type matches the class name. Treated as a factory.
585 /// See issues #346, #387.
586 pub(crate) is_instance_returning_static: bool,
587 /// True when this instance method's call result is an instance of the
588 /// same class (declared return type matches the class name, or body's
589 /// last statement is `return this`). Drives fluent-chain credit. See
590 /// issue #387.
591 pub(crate) is_self_returning: bool,
592}
593
594/// Cached dynamic import pattern data (template literals, `import.meta.glob`).
595#[derive(Debug, Clone, Encode, Decode)]
596pub struct CachedDynamicImportPattern {
597 /// Static prefix of the import path.
598 pub(crate) prefix: String,
599 /// Static suffix, if any.
600 pub(crate) suffix: Option<String>,
601 /// Byte offset of the span start.
602 pub(crate) span_start: u32,
603 /// Byte offset of the span end.
604 pub(crate) span_end: u32,
605 /// Runtime mechanism used to load modules matching this pattern.
606 pub(crate) mechanism: crate::ModuleLoadMechanism,
607}