1pub use fallow_types::output_dead_code::{
2 BoundaryCallViolationFinding, BoundaryCoverageViolationFinding, BoundaryViolationFinding,
3 CircularDependencyFinding, DevDependencyInProductionFinding, DuplicateExportFinding,
4 DuplicatePropShapeFinding, DynamicSegmentNameConflictFinding, EmptyCatalogGroupFinding,
5 InvalidClientExportFinding, MisconfiguredDependencyOverrideFinding, MisplacedDirectiveFinding,
6 MixedClientServerBarrelFinding, PolicyViolationFinding, PrivateTypeLeakFinding,
7 ReExportCycleFinding, RouteCollisionFinding, TestOnlyDependencyFinding,
8 TypeOnlyDependencyFinding, UnlistedDependencyFinding, UnprovidedInjectFinding,
9 UnrenderedComponentFinding, UnresolvedCatalogReferenceFinding, UnresolvedImportFinding,
10 UnusedCatalogEntryFinding, UnusedClassMemberFinding, UnusedComponentEmitFinding,
11 UnusedComponentInputFinding, UnusedComponentOutputFinding, UnusedComponentPropFinding,
12 UnusedDependencyFinding, UnusedDependencyOverrideFinding, UnusedDevDependencyFinding,
13 UnusedEnumMemberFinding, UnusedExportFinding, UnusedFileFinding, UnusedLoadDataKeyFinding,
14 UnusedOptionalDependencyFinding, UnusedServerActionFinding, UnusedStoreMemberFinding,
15 UnusedSvelteEventFinding, UnusedTypeFinding,
16};
17pub use fallow_types::results::{
18 ActiveSuppression, AnalysisResults, BoundaryCallViolation, BoundaryCoverageViolation,
19 BoundaryViolation, CircularDependency, CircularDependencyEdge, DependencyLocation,
20 DependencyOverrideMisconfigReason, DependencyOverrideSource, DevDependencyInProduction,
21 DuplicateExport, DuplicateLocation, DuplicatePropShape, DuplicatePropShapeMember,
22 DynamicSegmentNameConflict, EmptyCatalogGroup, EntryPointSummary, ExportUsage, FeatureFlag,
23 FlagConfidence, FlagKind, ImportSite, InvalidClientExport, MisconfiguredDependencyOverride,
24 MisplacedDirective, MixedClientServerBarrel, PolicyRuleKind, PolicyViolation,
25 PolicyViolationSeverity, PrivateTypeLeak, PropDrillHop, PropDrillingChain, ReExportCycle,
26 ReExportCycleKind, ReactComponentIntel, ReactHookSummary, ReactPropDrill, ReactPropIntel,
27 ReferenceLocation, RenderFanInComponent, RenderFanInMetric, RouteCollision,
28 SecurityAttackSurfaceEntry, SecurityCandidate, SecurityCandidateBoundary,
29 SecurityCandidateSink, SecurityDeadCodeContext, SecurityDeadCodeKind,
30 SecurityDefensiveBoundary, SecurityDefensiveControl, SecurityFinding, SecurityFindingKind,
31 SecurityNetworkContext, SecurityReachability, SecuritySeverity, SecurityTaintFlow,
32 SecurityUnresolvedCalleeDiagnostic, SecurityZoneCrossing, StaleSuppression, SuppressionOrigin,
33 TaintConfidence, TaintEndpoint, TaintPath, TestOnlyDependency, ThinWrapper, TraceHop,
34 TraceHopRole, TypeOnlyDependency, UnlistedDependency, UnprovidedInject, UnrenderedComponent,
35 UnresolvedCatalogReference, UnresolvedImport, UnusedCatalogEntry, UnusedComponentEmit,
36 UnusedComponentInput, UnusedComponentOutput, UnusedComponentProp, UnusedDependency,
37 UnusedDependencyOverride, UnusedExport, UnusedFile, UnusedLoadDataKey, UnusedMember,
38 UnusedServerAction, UnusedSvelteEvent,
39};
40
41#[cfg(test)]
42mod tests {
43 use std::path::PathBuf;
44
45 use super::*;
46 use crate::extract::MemberKind;
47 use fallow_types::output_dead_code::{UnresolvedImportFinding, UnusedFileFinding};
48
49 #[test]
50 fn empty_results_no_issues() {
51 let results = AnalysisResults::default();
52 assert_eq!(results.total_issues(), 0);
53 assert!(!results.has_issues());
54 }
55
56 #[test]
57 fn results_with_unused_file() {
58 let mut results = AnalysisResults::default();
59 results
60 .unused_files
61 .push(UnusedFileFinding::with_actions(UnusedFile {
62 path: PathBuf::from("test.ts"),
63 }));
64 assert_eq!(results.total_issues(), 1);
65 assert!(results.has_issues());
66 }
67
68 #[test]
69 fn results_with_unused_export() {
70 let mut results = AnalysisResults::default();
71 results
72 .unused_exports
73 .push(UnusedExportFinding::with_actions(UnusedExport {
74 path: PathBuf::from("test.ts"),
75 export_name: "foo".to_string(),
76 is_type_only: false,
77 line: 1,
78 col: 0,
79 span_start: 0,
80 is_re_export: false,
81 }));
82 assert_eq!(results.total_issues(), 1);
83 assert!(results.has_issues());
84 }
85
86 #[test]
87 #[expect(
88 clippy::too_many_lines,
89 reason = "test fixture; linear setup/assert, length is not a maintainability concern"
90 )]
91 fn results_total_counts_all_types() {
92 let mut results = AnalysisResults::default();
93 results
94 .unused_files
95 .push(UnusedFileFinding::with_actions(UnusedFile {
96 path: PathBuf::from("a.ts"),
97 }));
98 results
99 .unused_exports
100 .push(UnusedExportFinding::with_actions(UnusedExport {
101 path: PathBuf::from("b.ts"),
102 export_name: "x".to_string(),
103 is_type_only: false,
104 line: 1,
105 col: 0,
106 span_start: 0,
107 is_re_export: false,
108 }));
109 results
110 .unused_types
111 .push(UnusedTypeFinding::with_actions(UnusedExport {
112 path: PathBuf::from("c.ts"),
113 export_name: "T".to_string(),
114 is_type_only: true,
115 line: 1,
116 col: 0,
117 span_start: 0,
118 is_re_export: false,
119 }));
120 results
121 .unused_dependencies
122 .push(UnusedDependencyFinding::with_actions(UnusedDependency {
123 package_name: "dep".to_string(),
124 location: DependencyLocation::Dependencies,
125 path: PathBuf::from("package.json"),
126 line: 5,
127 used_in_workspaces: Vec::new(),
128 }));
129 results
130 .unused_dev_dependencies
131 .push(UnusedDevDependencyFinding::with_actions(UnusedDependency {
132 package_name: "dev".to_string(),
133 location: DependencyLocation::DevDependencies,
134 path: PathBuf::from("package.json"),
135 line: 5,
136 used_in_workspaces: Vec::new(),
137 }));
138 results
139 .unused_enum_members
140 .push(UnusedEnumMemberFinding::with_actions(UnusedMember {
141 path: PathBuf::from("d.ts"),
142 parent_name: "E".to_string(),
143 member_name: "A".to_string(),
144 kind: MemberKind::EnumMember,
145 line: 1,
146 col: 0,
147 }));
148 results
149 .unused_class_members
150 .push(UnusedClassMemberFinding::with_actions(UnusedMember {
151 path: PathBuf::from("e.ts"),
152 parent_name: "C".to_string(),
153 member_name: "m".to_string(),
154 kind: MemberKind::ClassMethod,
155 line: 1,
156 col: 0,
157 }));
158 results
159 .unresolved_imports
160 .push(UnresolvedImportFinding::with_actions(UnresolvedImport {
161 path: PathBuf::from("f.ts"),
162 specifier: "./missing".to_string(),
163 line: 1,
164 col: 0,
165 specifier_col: 0,
166 }));
167 results
168 .unlisted_dependencies
169 .push(UnlistedDependencyFinding::with_actions(
170 UnlistedDependency {
171 package_name: "unlisted".to_string(),
172 imported_from: vec![ImportSite {
173 path: PathBuf::from("g.ts"),
174 line: 1,
175 col: 0,
176 }],
177 },
178 ));
179 results
180 .duplicate_exports
181 .push(DuplicateExportFinding::with_actions(DuplicateExport {
182 export_name: "dup".to_string(),
183 locations: vec![
184 DuplicateLocation {
185 path: PathBuf::from("h.ts"),
186 line: 15,
187 col: 0,
188 },
189 DuplicateLocation {
190 path: PathBuf::from("i.ts"),
191 line: 30,
192 col: 0,
193 },
194 ],
195 }));
196
197 assert_eq!(results.total_issues(), 10);
198 assert!(results.has_issues());
199 }
200}