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