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/// Result of tracing a class / enum / store MEMBER: the `--trace FILE:NAME`
33/// fallback when `NAME` is not a top-level export but a member declared on one
34/// (issue #1744). The trace runs on the module graph only, so it reports the
35/// OWNING export's reachability and usage (the gating precondition for
36/// member-level crediting) plus a pointer to the right `--unused-*-members`
37/// command, rather than per-member crediting provenance.
38#[derive(Debug, Serialize)]
39pub struct ClassMemberTrace {
40    /// The file containing the member.
41    #[serde(serialize_with = "serde_path::serialize")]
42    pub file: PathBuf,
43    /// The member name being traced.
44    pub member_name: String,
45    /// The member kind: `class-method`, `class-property`, `enum-member`,
46    /// `store-member`, or `namespace-member`.
47    pub member_kind: String,
48    /// The export that declares this member (the class / enum / store name).
49    pub owner_export: String,
50    /// Whether the owning export is considered used.
51    pub owner_is_used: bool,
52    /// Whether the file is reachable from an entry point.
53    pub owner_file_reachable: bool,
54    /// Whether the file is an entry point.
55    pub owner_is_entry_point: bool,
56    /// Files that reference the owning export directly.
57    pub owner_direct_references: Vec<ExportReference>,
58    /// Re-export chains through which the owning export is reachable. Populated
59    /// so a machine consumer can tell "used via a barrel" (empty direct refs but
60    /// non-empty chains) from "genuinely unreferenced".
61    pub owner_re_export_chains: Vec<ReExportChain>,
62    /// Human-readable reason summary plus the follow-up command to inspect the
63    /// member finding.
64    pub reason: String,
65}
66
67/// A direct reference to an export.
68#[derive(Debug, Serialize)]
69pub struct ExportReference {
70    /// File that contains the reference.
71    #[serde(serialize_with = "serde_path::serialize")]
72    pub from_file: PathBuf,
73    /// Reference kind, such as named import, default import, or re-export.
74    pub kind: String,
75}
76
77/// A re-export chain showing how an export is propagated.
78#[derive(Debug, Serialize)]
79pub struct ReExportChain {
80    /// The barrel file that re-exports this symbol.
81    #[serde(serialize_with = "serde_path::serialize")]
82    pub barrel_file: PathBuf,
83    /// The name it is re-exported as.
84    pub exported_as: String,
85    /// Number of references on the barrel's re-exported symbol.
86    pub reference_count: usize,
87}
88
89/// Result of tracing all edges for a file.
90#[derive(Debug, Serialize)]
91pub struct FileTrace {
92    /// The traced file.
93    #[serde(serialize_with = "serde_path::serialize")]
94    pub file: PathBuf,
95    /// Whether this file is reachable from entry points.
96    pub is_reachable: bool,
97    /// Whether this file is an entry point.
98    pub is_entry_point: bool,
99    /// Exports declared by this file.
100    pub exports: Vec<TracedExport>,
101    /// Files that this file imports from.
102    #[serde(serialize_with = "serde_path::serialize_vec")]
103    pub imports_from: Vec<PathBuf>,
104    /// Files that import from this file.
105    #[serde(serialize_with = "serde_path::serialize_vec")]
106    pub imported_by: Vec<PathBuf>,
107    /// Re-exports declared by this file.
108    pub re_exports: Vec<TracedReExport>,
109}
110
111/// An export with usage information.
112#[derive(Debug, Serialize)]
113pub struct TracedExport {
114    /// Export name.
115    pub name: String,
116    /// Whether the export is type-only.
117    pub is_type_only: bool,
118    /// Number of references to this export.
119    pub reference_count: usize,
120    /// Files that reference this export.
121    pub referenced_by: Vec<ExportReference>,
122}
123
124/// A re-export with source information.
125#[derive(Debug, Serialize)]
126pub struct TracedReExport {
127    /// Source file being re-exported from.
128    #[serde(serialize_with = "serde_path::serialize")]
129    pub source_file: PathBuf,
130    /// Imported symbol name.
131    pub imported_name: String,
132    /// Exported symbol name.
133    pub exported_name: String,
134}
135
136/// Result of tracing a dependency: where it is used.
137#[derive(Debug, Serialize)]
138pub struct DependencyTrace {
139    /// The dependency name being traced.
140    pub package_name: String,
141    /// Files that import this dependency.
142    #[serde(serialize_with = "serde_path::serialize_vec")]
143    pub imported_by: Vec<PathBuf>,
144    /// Files that import this dependency with type-only imports.
145    #[serde(serialize_with = "serde_path::serialize_vec")]
146    pub type_only_imported_by: Vec<PathBuf>,
147    /// Whether the dependency is invoked from package.json scripts or CI configs.
148    pub used_in_scripts: bool,
149    /// Whether the dependency is used at all.
150    pub is_used: bool,
151    /// Total import count.
152    pub import_count: usize,
153}
154
155/// Pipeline performance timings.
156#[derive(Debug, Clone, Serialize)]
157pub struct PipelineTimings {
158    /// Time spent discovering files.
159    pub discover_files_ms: f64,
160    /// Number of discovered files.
161    pub file_count: usize,
162    /// Time spent discovering workspaces.
163    pub workspaces_ms: f64,
164    /// Number of discovered workspaces.
165    pub workspace_count: usize,
166    /// Time spent running plugin discovery.
167    pub plugins_ms: f64,
168    /// Time spent analyzing package scripts and CI configuration.
169    pub script_analysis_ms: f64,
170    /// Wall-clock time spent parsing and extracting modules.
171    pub parse_extract_ms: f64,
172    /// Summed parser CPU time across workers.
173    pub parse_cpu_ms: f64,
174    /// Number of extracted modules.
175    pub module_count: usize,
176    /// Number of files loaded from the parse cache.
177    pub cache_hits: usize,
178    /// Number of files parsed without a cache hit.
179    pub cache_misses: usize,
180    /// Time spent updating the parse cache.
181    pub cache_update_ms: f64,
182    /// Time spent categorizing entry points.
183    pub entry_points_ms: f64,
184    /// Number of entry points considered.
185    pub entry_point_count: usize,
186    /// Time spent resolving imports.
187    pub resolve_imports_ms: f64,
188    /// Time spent building the module graph.
189    pub build_graph_ms: f64,
190    /// Time spent running analysis.
191    pub analyze_ms: f64,
192    /// Time spent running duplicate-code analysis, when included.
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub duplication_ms: Option<f64>,
195    /// Total pipeline time.
196    pub total_ms: f64,
197}
198
199/// Result of computing the impact closure for a single file as the seed.
200#[derive(Debug, Serialize)]
201pub struct ImpactClosureTrace {
202    /// The seed file, root-relative.
203    pub seed: String,
204    /// Root-relative paths transitively affected by the seed.
205    pub affected_not_shown: Vec<String>,
206    /// Coordination gaps between the seed and consumers.
207    pub coordination_gap: Vec<ImpactClosureGap>,
208}
209
210/// One coordination-gap entry in an [`ImpactClosureTrace`].
211#[derive(Debug, Serialize)]
212pub struct ImpactClosureGap {
213    /// Root-relative path of the consumer module.
214    pub consumer_file: String,
215    /// Exported symbol names the consumer references.
216    pub consumed_symbols: Vec<String>,
217    /// Scope note for the syntactic trace.
218    pub note: String,
219}
220
221/// Result of tracing a clone: all groups containing the code at a source
222/// location or addressed by a stable clone fingerprint.
223#[derive(Debug, Serialize)]
224pub struct CloneTrace {
225    /// File passed to the trace request, root-relative when a group matches.
226    #[serde(serialize_with = "serde_path::serialize")]
227    pub file: PathBuf,
228    /// 1-based line passed to the trace request or representative group line.
229    pub line: usize,
230    /// The matched clone instance, if one exists.
231    pub matched_instance: Option<CloneInstance>,
232    /// Clone groups matched by the trace request.
233    pub clone_groups: Vec<TracedCloneGroup>,
234}
235
236/// One clone group returned from a clone trace request.
237#[derive(Debug, Serialize)]
238pub struct TracedCloneGroup {
239    /// Stable content fingerprint, usually `dup:<8hex>` and widened on rare
240    /// report collisions.
241    pub fingerprint: String,
242    /// Number of tokens in the duplicated block.
243    pub token_count: usize,
244    /// Number of lines in the duplicated block.
245    pub line_count: usize,
246    /// Root-relative clone instances in this group.
247    pub instances: Vec<CloneInstance>,
248    /// Group-level refactoring suggestion.
249    pub suggestion: RefactoringSuggestion,
250    /// Best-effort name for the extracted function. Advisory only.
251    #[serde(skip_serializing_if = "Option::is_none")]
252    pub suggested_name: Option<String>,
253}