Skip to main content

fallow_types/
trace.rs

1//! Shared trace output contracts for analysis and integration surfaces.
2
3use std::path::PathBuf;
4
5use serde::Serialize;
6
7use crate::duplicates::{CloneInstance, RefactoringSuggestion};
8use crate::serde_path;
9
10/// Result of tracing an export: why it is considered used or unused.
11#[derive(Debug, Serialize)]
12pub struct ExportTrace {
13    /// The file containing the export.
14    #[serde(serialize_with = "serde_path::serialize")]
15    pub file: PathBuf,
16    /// The export name being traced.
17    pub export_name: String,
18    /// Whether the file is reachable from an entry point.
19    pub file_reachable: bool,
20    /// Whether the file is an entry point.
21    pub is_entry_point: bool,
22    /// Whether the export is considered used.
23    pub is_used: bool,
24    /// Files that reference this export directly.
25    pub direct_references: Vec<ExportReference>,
26    /// Re-export chains that pass through this export.
27    pub re_export_chains: Vec<ReExportChain>,
28    /// Human-readable reason summary.
29    pub reason: String,
30}
31
32/// A direct reference to an export.
33#[derive(Debug, Serialize)]
34pub struct ExportReference {
35    /// File that contains the reference.
36    #[serde(serialize_with = "serde_path::serialize")]
37    pub from_file: PathBuf,
38    /// Reference kind, such as named import, default import, or re-export.
39    pub kind: String,
40}
41
42/// A re-export chain showing how an export is propagated.
43#[derive(Debug, Serialize)]
44pub struct ReExportChain {
45    /// The barrel file that re-exports this symbol.
46    #[serde(serialize_with = "serde_path::serialize")]
47    pub barrel_file: PathBuf,
48    /// The name it is re-exported as.
49    pub exported_as: String,
50    /// Number of references on the barrel's re-exported symbol.
51    pub reference_count: usize,
52}
53
54/// Result of tracing all edges for a file.
55#[derive(Debug, Serialize)]
56pub struct FileTrace {
57    /// The traced file.
58    #[serde(serialize_with = "serde_path::serialize")]
59    pub file: PathBuf,
60    /// Whether this file is reachable from entry points.
61    pub is_reachable: bool,
62    /// Whether this file is an entry point.
63    pub is_entry_point: bool,
64    /// Exports declared by this file.
65    pub exports: Vec<TracedExport>,
66    /// Files that this file imports from.
67    #[serde(serialize_with = "serde_path::serialize_vec")]
68    pub imports_from: Vec<PathBuf>,
69    /// Files that import from this file.
70    #[serde(serialize_with = "serde_path::serialize_vec")]
71    pub imported_by: Vec<PathBuf>,
72    /// Re-exports declared by this file.
73    pub re_exports: Vec<TracedReExport>,
74}
75
76/// An export with usage information.
77#[derive(Debug, Serialize)]
78pub struct TracedExport {
79    /// Export name.
80    pub name: String,
81    /// Whether the export is type-only.
82    pub is_type_only: bool,
83    /// Number of references to this export.
84    pub reference_count: usize,
85    /// Files that reference this export.
86    pub referenced_by: Vec<ExportReference>,
87}
88
89/// A re-export with source information.
90#[derive(Debug, Serialize)]
91pub struct TracedReExport {
92    /// Source file being re-exported from.
93    #[serde(serialize_with = "serde_path::serialize")]
94    pub source_file: PathBuf,
95    /// Imported symbol name.
96    pub imported_name: String,
97    /// Exported symbol name.
98    pub exported_name: String,
99}
100
101/// Result of tracing a dependency: where it is used.
102#[derive(Debug, Serialize)]
103pub struct DependencyTrace {
104    /// The dependency name being traced.
105    pub package_name: String,
106    /// Files that import this dependency.
107    #[serde(serialize_with = "serde_path::serialize_vec")]
108    pub imported_by: Vec<PathBuf>,
109    /// Files that import this dependency with type-only imports.
110    #[serde(serialize_with = "serde_path::serialize_vec")]
111    pub type_only_imported_by: Vec<PathBuf>,
112    /// Whether the dependency is invoked from package.json scripts or CI configs.
113    pub used_in_scripts: bool,
114    /// Whether the dependency is used at all.
115    pub is_used: bool,
116    /// Total import count.
117    pub import_count: usize,
118}
119
120/// Pipeline performance timings.
121#[derive(Debug, Clone, Serialize)]
122pub struct PipelineTimings {
123    /// Time spent discovering files.
124    pub discover_files_ms: f64,
125    /// Number of discovered files.
126    pub file_count: usize,
127    /// Time spent discovering workspaces.
128    pub workspaces_ms: f64,
129    /// Number of discovered workspaces.
130    pub workspace_count: usize,
131    /// Time spent running plugin discovery.
132    pub plugins_ms: f64,
133    /// Time spent analyzing package scripts and CI configuration.
134    pub script_analysis_ms: f64,
135    /// Wall-clock time spent parsing and extracting modules.
136    pub parse_extract_ms: f64,
137    /// Summed parser CPU time across workers.
138    pub parse_cpu_ms: f64,
139    /// Number of extracted modules.
140    pub module_count: usize,
141    /// Number of files loaded from the parse cache.
142    pub cache_hits: usize,
143    /// Number of files parsed without a cache hit.
144    pub cache_misses: usize,
145    /// Time spent updating the parse cache.
146    pub cache_update_ms: f64,
147    /// Time spent categorizing entry points.
148    pub entry_points_ms: f64,
149    /// Number of entry points considered.
150    pub entry_point_count: usize,
151    /// Time spent resolving imports.
152    pub resolve_imports_ms: f64,
153    /// Time spent building the module graph.
154    pub build_graph_ms: f64,
155    /// Time spent running analysis.
156    pub analyze_ms: f64,
157    /// Time spent running duplicate-code analysis, when included.
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub duplication_ms: Option<f64>,
160    /// Total pipeline time.
161    pub total_ms: f64,
162}
163
164/// Result of computing the impact closure for a single file as the seed.
165#[derive(Debug, Serialize)]
166pub struct ImpactClosureTrace {
167    /// The seed file, root-relative.
168    pub seed: String,
169    /// Root-relative paths transitively affected by the seed.
170    pub affected_not_shown: Vec<String>,
171    /// Coordination gaps between the seed and consumers.
172    pub coordination_gap: Vec<ImpactClosureGap>,
173}
174
175/// One coordination-gap entry in an [`ImpactClosureTrace`].
176#[derive(Debug, Serialize)]
177pub struct ImpactClosureGap {
178    /// Root-relative path of the consumer module.
179    pub consumer_file: String,
180    /// Exported symbol names the consumer references.
181    pub consumed_symbols: Vec<String>,
182    /// Scope note for the syntactic trace.
183    pub note: String,
184}
185
186/// Result of tracing a clone: all groups containing the code at a source
187/// location or addressed by a stable clone fingerprint.
188#[derive(Debug, Serialize)]
189pub struct CloneTrace {
190    /// File passed to the trace request, root-relative when a group matches.
191    #[serde(serialize_with = "serde_path::serialize")]
192    pub file: PathBuf,
193    /// 1-based line passed to the trace request or representative group line.
194    pub line: usize,
195    /// The matched clone instance, if one exists.
196    pub matched_instance: Option<CloneInstance>,
197    /// Clone groups matched by the trace request.
198    pub clone_groups: Vec<TracedCloneGroup>,
199}
200
201/// One clone group returned from a clone trace request.
202#[derive(Debug, Serialize)]
203pub struct TracedCloneGroup {
204    /// Stable content fingerprint, usually `dup:<8hex>` and widened on rare
205    /// report collisions.
206    pub fingerprint: String,
207    /// Number of tokens in the duplicated block.
208    pub token_count: usize,
209    /// Number of lines in the duplicated block.
210    pub line_count: usize,
211    /// Root-relative clone instances in this group.
212    pub instances: Vec<CloneInstance>,
213    /// Group-level refactoring suggestion.
214    pub suggestion: RefactoringSuggestion,
215    /// Best-effort name for the extracted function. Advisory only.
216    #[serde(skip_serializing_if = "Option::is_none")]
217    pub suggested_name: Option<String>,
218}