1use crate::suppress::IssueKind;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct IssueKindMeta {
12 pub kind: Option<IssueKind>,
14 pub code: &'static str,
16 pub aliases: &'static [&'static str],
18 pub label: &'static str,
20 pub config_key: Option<&'static str>,
22 pub filter_flag: Option<&'static str>,
24 pub mcp_issue_type: Option<&'static str>,
26 pub suppress_token: Option<&'static str>,
28 pub suppress_file_level: bool,
30 pub lsp: bool,
33 pub docs_category: &'static str,
35}
36
37impl IssueKindMeta {
38 #[must_use]
40 pub const fn mcp_pair(self) -> Option<(&'static str, &'static str)> {
41 match (self.mcp_issue_type, self.filter_flag) {
42 (Some(issue_type), Some(flag)) => Some((issue_type, flag)),
43 _ => None,
44 }
45 }
46}
47
48pub const ISSUE_KIND_META: &[IssueKindMeta] = &[
50 IssueKindMeta {
51 kind: Some(IssueKind::CodeDuplication),
52 code: "code-duplication",
53 aliases: &[],
54 label: "Code Duplication",
55 config_key: None,
56 filter_flag: None,
57 mcp_issue_type: None,
58 suppress_token: Some("code-duplication"),
59 suppress_file_level: false,
60 lsp: true,
61 docs_category: "dupes",
62 },
63 IssueKindMeta {
64 kind: Some(IssueKind::UnusedFile),
65 code: "unused-file",
66 aliases: &[],
67 label: "Unused Files",
68 config_key: Some("unused-files"),
69 filter_flag: Some("--unused-files"),
70 mcp_issue_type: Some("unused-files"),
71 suppress_token: Some("unused-file"),
72 suppress_file_level: true,
73 lsp: true,
74 docs_category: "source",
75 },
76 IssueKindMeta {
77 kind: Some(IssueKind::UnusedExport),
78 code: "unused-export",
79 aliases: &[],
80 label: "Unused Exports",
81 config_key: Some("unused-exports"),
82 filter_flag: Some("--unused-exports"),
83 mcp_issue_type: Some("unused-exports"),
84 suppress_token: Some("unused-export"),
85 suppress_file_level: false,
86 lsp: true,
87 docs_category: "source",
88 },
89 IssueKindMeta {
90 kind: Some(IssueKind::UnusedType),
91 code: "unused-type",
92 aliases: &[],
93 label: "Unused Types",
94 config_key: Some("unused-types"),
95 filter_flag: Some("--unused-types"),
96 mcp_issue_type: Some("unused-types"),
97 suppress_token: Some("unused-type"),
98 suppress_file_level: false,
99 lsp: true,
100 docs_category: "source",
101 },
102 IssueKindMeta {
103 kind: Some(IssueKind::PrivateTypeLeak),
104 code: "private-type-leak",
105 aliases: &[],
106 label: "Private Type Leaks",
107 config_key: Some("private-type-leaks"),
108 filter_flag: Some("--private-type-leaks"),
109 mcp_issue_type: Some("private-type-leaks"),
110 suppress_token: Some("private-type-leak"),
111 suppress_file_level: false,
112 lsp: true,
113 docs_category: "source",
114 },
115 IssueKindMeta {
116 kind: Some(IssueKind::UnusedDependency),
117 code: "unused-dependency",
118 aliases: &[],
119 label: "Unused Dependencies",
120 config_key: Some("unused-dependencies"),
121 filter_flag: Some("--unused-deps"),
122 mcp_issue_type: Some("unused-deps"),
123 suppress_token: None,
124 suppress_file_level: false,
125 lsp: true,
126 docs_category: "dependency",
127 },
128 IssueKindMeta {
129 kind: Some(IssueKind::UnusedDevDependency),
130 code: "unused-dev-dependency",
131 aliases: &[],
132 label: "Unused Dev Dependencies",
133 config_key: Some("unused-dev-dependencies"),
134 filter_flag: Some("--unused-deps"),
135 mcp_issue_type: None,
136 suppress_token: None,
137 suppress_file_level: false,
138 lsp: true,
139 docs_category: "dependency",
140 },
141 IssueKindMeta {
142 kind: None,
143 code: "unused-optional-dependency",
144 aliases: &[],
145 label: "Unused Optional Dependencies",
146 config_key: Some("unused-optional-dependencies"),
147 filter_flag: Some("--unused-deps"),
148 mcp_issue_type: None,
149 suppress_token: None,
150 suppress_file_level: false,
151 lsp: true,
152 docs_category: "dependency",
153 },
154 IssueKindMeta {
155 kind: Some(IssueKind::UnusedEnumMember),
156 code: "unused-enum-member",
157 aliases: &[],
158 label: "Unused Enum Members",
159 config_key: Some("unused-enum-members"),
160 filter_flag: Some("--unused-enum-members"),
161 mcp_issue_type: Some("unused-enum-members"),
162 suppress_token: Some("unused-enum-member"),
163 suppress_file_level: false,
164 lsp: true,
165 docs_category: "source",
166 },
167 IssueKindMeta {
168 kind: Some(IssueKind::UnusedClassMember),
169 code: "unused-class-member",
170 aliases: &[],
171 label: "Unused Class Members",
172 config_key: Some("unused-class-members"),
173 filter_flag: Some("--unused-class-members"),
174 mcp_issue_type: Some("unused-class-members"),
175 suppress_token: Some("unused-class-member"),
176 suppress_file_level: false,
177 lsp: true,
178 docs_category: "source",
179 },
180 IssueKindMeta {
181 kind: Some(IssueKind::UnusedStoreMember),
182 code: "unused-store-member",
183 aliases: &["unused-store-members"],
184 label: "Unused Store Members",
185 config_key: Some("unused-store-members"),
186 filter_flag: Some("--unused-store-members"),
187 mcp_issue_type: Some("unused-store-members"),
188 suppress_token: Some("unused-store-member"),
189 suppress_file_level: false,
190 lsp: true,
191 docs_category: "framework",
192 },
193 IssueKindMeta {
194 kind: Some(IssueKind::UnresolvedImport),
195 code: "unresolved-import",
196 aliases: &[],
197 label: "Unresolved Imports",
198 config_key: Some("unresolved-imports"),
199 filter_flag: Some("--unresolved-imports"),
200 mcp_issue_type: Some("unresolved-imports"),
201 suppress_token: Some("unresolved-import"),
202 suppress_file_level: false,
203 lsp: true,
204 docs_category: "dependency",
205 },
206 IssueKindMeta {
207 kind: Some(IssueKind::UnlistedDependency),
208 code: "unlisted-dependency",
209 aliases: &[],
210 label: "Unlisted Dependencies",
211 config_key: Some("unlisted-dependencies"),
212 filter_flag: Some("--unlisted-deps"),
213 mcp_issue_type: Some("unlisted-deps"),
214 suppress_token: None,
215 suppress_file_level: false,
216 lsp: true,
217 docs_category: "dependency",
218 },
219 IssueKindMeta {
220 kind: Some(IssueKind::DuplicateExport),
221 code: "duplicate-export",
222 aliases: &[],
223 label: "Duplicate Exports",
224 config_key: Some("duplicate-exports"),
225 filter_flag: Some("--duplicate-exports"),
226 mcp_issue_type: Some("duplicate-exports"),
227 suppress_token: Some("duplicate-export"),
228 suppress_file_level: true,
229 lsp: true,
230 docs_category: "source",
231 },
232 IssueKindMeta {
233 kind: Some(IssueKind::TypeOnlyDependency),
234 code: "type-only-dependency",
235 aliases: &[],
236 label: "Type-Only Dependencies",
237 config_key: Some("type-only-dependencies"),
238 filter_flag: Some("--unused-deps"),
239 mcp_issue_type: None,
240 suppress_token: None,
241 suppress_file_level: false,
242 lsp: true,
243 docs_category: "dependency",
244 },
245 IssueKindMeta {
246 kind: Some(IssueKind::TestOnlyDependency),
247 code: "test-only-dependency",
248 aliases: &[],
249 label: "Test-Only Dependencies",
250 config_key: Some("test-only-dependencies"),
251 filter_flag: Some("--unused-deps"),
252 mcp_issue_type: None,
253 suppress_token: None,
254 suppress_file_level: false,
255 lsp: true,
256 docs_category: "dependency",
257 },
258 IssueKindMeta {
259 kind: Some(IssueKind::CircularDependency),
260 code: "circular-dependency",
261 aliases: &["circular-dependencies"],
262 label: "Circular Dependencies",
263 config_key: Some("circular-dependencies"),
264 filter_flag: Some("--circular-deps"),
265 mcp_issue_type: Some("circular-deps"),
266 suppress_token: Some("circular-dependency"),
267 suppress_file_level: false,
268 lsp: true,
269 docs_category: "architecture",
270 },
271 IssueKindMeta {
272 kind: Some(IssueKind::ReExportCycle),
273 code: "re-export-cycle",
274 aliases: &["re-export-cycles", "reexport-cycle", "reexport-cycles"],
275 label: "Re-Export Cycles",
276 config_key: Some("re-export-cycle"),
277 filter_flag: Some("--re-export-cycles"),
278 mcp_issue_type: Some("re-export-cycles"),
279 suppress_token: Some("re-export-cycle"),
280 suppress_file_level: true,
281 lsp: true,
282 docs_category: "architecture",
283 },
284 IssueKindMeta {
285 kind: Some(IssueKind::BoundaryViolation),
286 code: "boundary-violation",
287 aliases: &[],
288 label: "Boundary Violations",
289 config_key: Some("boundary-violation"),
290 filter_flag: Some("--boundary-violations"),
291 mcp_issue_type: Some("boundary-violations"),
292 suppress_token: Some("boundary-violation"),
293 suppress_file_level: false,
294 lsp: true,
295 docs_category: "architecture",
296 },
297 IssueKindMeta {
298 kind: None,
299 code: "boundary-coverage",
300 aliases: &["boundary-coverage-violations"],
301 label: "Boundary Coverage",
302 config_key: Some("boundary-violation"),
303 filter_flag: Some("--boundary-violations"),
304 mcp_issue_type: None,
305 suppress_token: Some("boundary-violation"),
306 suppress_file_level: true,
307 lsp: false,
308 docs_category: "architecture",
309 },
310 IssueKindMeta {
311 kind: Some(IssueKind::BoundaryViolation),
312 code: "boundary-call-violation",
313 aliases: &["boundary-call-violations"],
314 label: "Boundary Call Violations",
315 config_key: Some("boundary-violation"),
316 filter_flag: Some("--boundary-violations"),
317 mcp_issue_type: None,
318 suppress_token: Some("boundary-call-violation"),
319 suppress_file_level: false,
320 lsp: false,
321 docs_category: "architecture",
322 },
323 IssueKindMeta {
324 kind: Some(IssueKind::PolicyViolation),
325 code: "policy-violation",
326 aliases: &["policy-violations"],
327 label: "Policy Violations",
328 config_key: Some("policy-violation"),
329 filter_flag: Some("--policy-violations"),
330 mcp_issue_type: Some("policy-violations"),
331 suppress_token: Some("policy-violation"),
332 suppress_file_level: false,
333 lsp: true,
334 docs_category: "architecture",
335 },
336 IssueKindMeta {
337 kind: Some(IssueKind::InvalidClientExport),
338 code: "invalid-client-export",
339 aliases: &["invalid-client-exports"],
340 label: "Invalid Client Exports",
341 config_key: Some("invalid-client-export"),
342 filter_flag: None,
343 mcp_issue_type: None,
344 suppress_token: Some("invalid-client-export"),
345 suppress_file_level: false,
346 lsp: true,
347 docs_category: "framework",
348 },
349 IssueKindMeta {
350 kind: Some(IssueKind::MixedClientServerBarrel),
351 code: "mixed-client-server-barrel",
352 aliases: &["mixed-client-server-barrels"],
353 label: "Mixed Client/Server Barrels",
354 config_key: Some("mixed-client-server-barrel"),
355 filter_flag: None,
356 mcp_issue_type: None,
357 suppress_token: Some("mixed-client-server-barrel"),
358 suppress_file_level: false,
359 lsp: true,
360 docs_category: "framework",
361 },
362 IssueKindMeta {
363 kind: Some(IssueKind::MisplacedDirective),
364 code: "misplaced-directive",
365 aliases: &["misplaced-directives"],
366 label: "Misplaced Directives",
367 config_key: Some("misplaced-directive"),
368 filter_flag: None,
369 mcp_issue_type: None,
370 suppress_token: Some("misplaced-directive"),
371 suppress_file_level: false,
372 lsp: true,
373 docs_category: "framework",
374 },
375 IssueKindMeta {
376 kind: Some(IssueKind::UnprovidedInject),
377 code: "unprovided-inject",
378 aliases: &["unprovided-injects"],
379 label: "Unprovided Injects",
380 config_key: Some("unprovided-injects"),
381 filter_flag: Some("--unprovided-injects"),
382 mcp_issue_type: Some("unprovided-injects"),
383 suppress_token: Some("unprovided-inject"),
384 suppress_file_level: false,
385 lsp: true,
386 docs_category: "framework",
387 },
388 IssueKindMeta {
389 kind: Some(IssueKind::UnrenderedComponent),
390 code: "unrendered-component",
391 aliases: &["unrendered-components"],
392 label: "Unrendered Components",
393 config_key: Some("unrendered-components"),
394 filter_flag: Some("--unrendered-components"),
395 mcp_issue_type: Some("unrendered-components"),
396 suppress_token: Some("unrendered-component"),
397 suppress_file_level: false,
398 lsp: true,
399 docs_category: "framework",
400 },
401 IssueKindMeta {
402 kind: Some(IssueKind::UnusedComponentProp),
403 code: "unused-component-prop",
404 aliases: &["unused-component-props"],
405 label: "Unused Component Props",
406 config_key: Some("unused-component-props"),
407 filter_flag: Some("--unused-component-props"),
408 mcp_issue_type: Some("unused-component-props"),
409 suppress_token: Some("unused-component-prop"),
410 suppress_file_level: false,
411 lsp: true,
412 docs_category: "framework",
413 },
414 IssueKindMeta {
415 kind: Some(IssueKind::UnusedComponentEmit),
416 code: "unused-component-emit",
417 aliases: &["unused-component-emits"],
418 label: "Unused Component Emits",
419 config_key: Some("unused-component-emits"),
420 filter_flag: Some("--unused-component-emits"),
421 mcp_issue_type: Some("unused-component-emits"),
422 suppress_token: Some("unused-component-emit"),
423 suppress_file_level: false,
424 lsp: true,
425 docs_category: "framework",
426 },
427 IssueKindMeta {
428 kind: Some(IssueKind::UnusedComponentInput),
429 code: "unused-component-input",
430 aliases: &["unused-component-inputs"],
431 label: "Unused Component Inputs",
432 config_key: Some("unused-component-inputs"),
433 filter_flag: Some("--unused-component-inputs"),
434 mcp_issue_type: Some("unused-component-inputs"),
435 suppress_token: Some("unused-component-input"),
436 suppress_file_level: false,
437 lsp: true,
438 docs_category: "framework",
439 },
440 IssueKindMeta {
441 kind: Some(IssueKind::UnusedComponentOutput),
442 code: "unused-component-output",
443 aliases: &["unused-component-outputs"],
444 label: "Unused Component Outputs",
445 config_key: Some("unused-component-outputs"),
446 filter_flag: Some("--unused-component-outputs"),
447 mcp_issue_type: Some("unused-component-outputs"),
448 suppress_token: Some("unused-component-output"),
449 suppress_file_level: false,
450 lsp: true,
451 docs_category: "framework",
452 },
453 IssueKindMeta {
454 kind: Some(IssueKind::UnusedSvelteEvent),
455 code: "unused-svelte-event",
456 aliases: &["unused-svelte-events"],
457 label: "Unused Svelte Events",
458 config_key: Some("unused-svelte-events"),
459 filter_flag: Some("--unused-svelte-events"),
460 mcp_issue_type: Some("unused-svelte-events"),
461 suppress_token: Some("unused-svelte-event"),
462 suppress_file_level: false,
463 lsp: true,
464 docs_category: "framework",
465 },
466 IssueKindMeta {
467 kind: Some(IssueKind::UnusedServerAction),
468 code: "unused-server-action",
469 aliases: &["unused-server-actions"],
470 label: "Unused Server Actions",
471 config_key: Some("unused-server-actions"),
472 filter_flag: Some("--unused-server-actions"),
473 mcp_issue_type: Some("unused-server-actions"),
474 suppress_token: Some("unused-server-action"),
475 suppress_file_level: false,
476 lsp: true,
477 docs_category: "framework",
478 },
479 IssueKindMeta {
480 kind: Some(IssueKind::UnusedLoadDataKey),
481 code: "unused-load-data-key",
482 aliases: &["unused-load-data-keys"],
483 label: "Unused Load Data Keys",
484 config_key: Some("unused-load-data-keys"),
485 filter_flag: Some("--unused-load-data-keys"),
486 mcp_issue_type: Some("unused-load-data-keys"),
487 suppress_token: Some("unused-load-data-key"),
488 suppress_file_level: false,
489 lsp: true,
490 docs_category: "framework",
491 },
492 IssueKindMeta {
493 kind: Some(IssueKind::RouteCollision),
494 code: "route-collision",
495 aliases: &["route-collisions"],
496 label: "Route Collisions",
497 config_key: Some("route-collision"),
498 filter_flag: None,
499 mcp_issue_type: None,
500 suppress_token: Some("route-collision"),
501 suppress_file_level: true,
502 lsp: true,
503 docs_category: "framework",
504 },
505 IssueKindMeta {
506 kind: Some(IssueKind::DynamicSegmentNameConflict),
507 code: "dynamic-segment-name-conflict",
508 aliases: &["dynamic-segment-name-conflicts"],
509 label: "Dynamic Segment Conflicts",
510 config_key: Some("dynamic-segment-name-conflict"),
511 filter_flag: None,
512 mcp_issue_type: None,
513 suppress_token: Some("dynamic-segment-name-conflict"),
514 suppress_file_level: true,
515 lsp: true,
516 docs_category: "framework",
517 },
518 IssueKindMeta {
519 kind: Some(IssueKind::StaleSuppression),
520 code: "stale-suppression",
521 aliases: &[],
522 label: "Stale Suppressions",
523 config_key: Some("stale-suppressions"),
524 filter_flag: Some("--stale-suppressions"),
525 mcp_issue_type: Some("stale-suppressions"),
526 suppress_token: None,
527 suppress_file_level: false,
528 lsp: true,
529 docs_category: "source",
530 },
531 IssueKindMeta {
532 kind: Some(IssueKind::PnpmCatalogEntry),
533 code: "unused-catalog-entry",
534 aliases: &["unused-catalog-entries"],
535 label: "Unused Catalog Entries",
536 config_key: Some("unused-catalog-entries"),
537 filter_flag: Some("--unused-catalog-entries"),
538 mcp_issue_type: Some("unused-catalog-entries"),
539 suppress_token: None,
540 suppress_file_level: false,
541 lsp: true,
542 docs_category: "dependency",
543 },
544 IssueKindMeta {
545 kind: Some(IssueKind::EmptyCatalogGroup),
546 code: "empty-catalog-group",
547 aliases: &["empty-catalog-groups"],
548 label: "Empty Catalog Groups",
549 config_key: Some("empty-catalog-groups"),
550 filter_flag: Some("--empty-catalog-groups"),
551 mcp_issue_type: Some("empty-catalog-groups"),
552 suppress_token: None,
553 suppress_file_level: false,
554 lsp: true,
555 docs_category: "dependency",
556 },
557 IssueKindMeta {
558 kind: Some(IssueKind::UnresolvedCatalogReference),
559 code: "unresolved-catalog-reference",
560 aliases: &["unresolved-catalog-references"],
561 label: "Unresolved Catalog References",
562 config_key: Some("unresolved-catalog-references"),
563 filter_flag: Some("--unresolved-catalog-references"),
564 mcp_issue_type: Some("unresolved-catalog-references"),
565 suppress_token: None,
566 suppress_file_level: false,
567 lsp: true,
568 docs_category: "dependency",
569 },
570 IssueKindMeta {
571 kind: Some(IssueKind::UnusedDependencyOverride),
572 code: "unused-dependency-override",
573 aliases: &["unused-dependency-overrides"],
574 label: "Unused Dependency Overrides",
575 config_key: Some("unused-dependency-overrides"),
576 filter_flag: Some("--unused-dependency-overrides"),
577 mcp_issue_type: Some("unused-dependency-overrides"),
578 suppress_token: None,
579 suppress_file_level: false,
580 lsp: true,
581 docs_category: "dependency",
582 },
583 IssueKindMeta {
584 kind: Some(IssueKind::MisconfiguredDependencyOverride),
585 code: "misconfigured-dependency-override",
586 aliases: &["misconfigured-dependency-overrides"],
587 label: "Misconfigured Dependency Overrides",
588 config_key: Some("misconfigured-dependency-overrides"),
589 filter_flag: Some("--misconfigured-dependency-overrides"),
590 mcp_issue_type: Some("misconfigured-dependency-overrides"),
591 suppress_token: None,
592 suppress_file_level: false,
593 lsp: true,
594 docs_category: "dependency",
595 },
596 IssueKindMeta {
597 kind: Some(IssueKind::SecuritySink),
598 code: "security-sink",
599 aliases: &[],
600 label: "Security Sink Candidates",
601 config_key: Some("security-sink"),
602 filter_flag: None,
603 mcp_issue_type: None,
604 suppress_token: Some("security-sink"),
605 suppress_file_level: false,
606 lsp: true,
607 docs_category: "security",
608 },
609 IssueKindMeta {
610 kind: Some(IssueKind::SecurityClientServerLeak),
611 code: "security-client-server-leak",
612 aliases: &[],
613 label: "Security Client-Server Leaks",
614 config_key: Some("security-client-server-leak"),
615 filter_flag: None,
616 mcp_issue_type: None,
617 suppress_token: Some("security-client-server-leak"),
618 suppress_file_level: true,
619 lsp: true,
620 docs_category: "security",
621 },
622 IssueKindMeta {
623 kind: Some(IssueKind::CoverageGaps),
624 code: "coverage-gaps",
625 aliases: &[],
626 label: "Coverage Gaps",
627 config_key: Some("coverage-gaps"),
628 filter_flag: None,
629 mcp_issue_type: None,
630 suppress_token: Some("coverage-gaps"),
631 suppress_file_level: true,
632 lsp: false,
633 docs_category: "health",
634 },
635 IssueKindMeta {
636 kind: Some(IssueKind::FeatureFlag),
637 code: "feature-flag",
638 aliases: &[],
639 label: "Feature Flags",
640 config_key: Some("feature-flags"),
641 filter_flag: None,
642 mcp_issue_type: None,
643 suppress_token: Some("feature-flag"),
644 suppress_file_level: false,
645 lsp: false,
646 docs_category: "flags",
647 },
648 IssueKindMeta {
649 kind: Some(IssueKind::Complexity),
650 code: "complexity",
651 aliases: &[],
652 label: "Complexity",
653 config_key: None,
654 filter_flag: None,
655 mcp_issue_type: None,
656 suppress_token: Some("complexity"),
657 suppress_file_level: false,
658 lsp: false,
659 docs_category: "health",
660 },
661 IssueKindMeta {
662 kind: Some(IssueKind::PropDrilling),
663 code: "prop-drilling",
664 aliases: &[],
665 label: "Prop Drilling",
666 config_key: Some("prop-drilling"),
667 filter_flag: None,
668 mcp_issue_type: None,
669 suppress_token: Some("prop-drilling"),
670 suppress_file_level: false,
671 lsp: false,
672 docs_category: "source",
673 },
674 IssueKindMeta {
675 kind: Some(IssueKind::ThinWrapper),
676 code: "thin-wrapper",
677 aliases: &["thin-wrappers"],
678 label: "Thin Wrappers",
679 config_key: Some("thin-wrapper"),
680 filter_flag: None,
681 mcp_issue_type: None,
682 suppress_token: Some("thin-wrapper"),
683 suppress_file_level: false,
684 lsp: false,
685 docs_category: "source",
686 },
687 IssueKindMeta {
688 kind: Some(IssueKind::DuplicatePropShape),
689 code: "duplicate-prop-shape",
690 aliases: &["duplicate-prop-shapes"],
691 label: "Duplicate Prop Shapes",
692 config_key: Some("duplicate-prop-shape"),
693 filter_flag: None,
694 mcp_issue_type: None,
695 suppress_token: Some("duplicate-prop-shape"),
696 suppress_file_level: false,
697 lsp: false,
698 docs_category: "source",
699 },
700];
701
702#[derive(Debug, Clone, Copy, PartialEq, Eq)]
704#[non_exhaustive]
705pub struct IssueResultMeta {
706 pub code: &'static str,
708 pub meta_description: &'static str,
710 pub meta_docs_path: &'static str,
712 pub meta_name: &'static str,
714 pub summary_label: &'static str,
716 pub docs_anchor: &'static str,
718 pub result_key: &'static str,
720 pub counts_in_total: bool,
722}
723
724#[derive(Debug, Clone, Copy, PartialEq, Eq)]
726pub struct TsAliasMeta {
727 pub name: &'static str,
729 pub parent: &'static str,
731}
732
733pub const ISSUE_RESULT_META: &[IssueResultMeta] = &[
735 IssueResultMeta {
736 code: "unused-file",
737 meta_description: "Source files that are not imported by any other module and are not entry points. Detection uses graph reachability from configured entry points.",
738 meta_docs_path: "explanations/dead-code#unused-files",
739 meta_name: "Unused Files",
740 summary_label: "Unused files",
741 docs_anchor: "unused-files",
742 result_key: "unused_files",
743 counts_in_total: true,
744 },
745 IssueResultMeta {
746 code: "unused-export",
747 meta_description: "Named exports that are never imported by any other module in the project, including direct exports and re-exports through barrel files.",
748 meta_docs_path: "explanations/dead-code#unused-exports",
749 meta_name: "Unused Exports",
750 summary_label: "Unused exports",
751 docs_anchor: "unused-exports",
752 result_key: "unused_exports",
753 counts_in_total: true,
754 },
755 IssueResultMeta {
756 code: "unused-type",
757 meta_description: "Type-only exports that are never imported. These do not generate runtime code but add maintenance burden.",
758 meta_docs_path: "explanations/dead-code#unused-types",
759 meta_name: "Unused Type Exports",
760 summary_label: "Unused types",
761 docs_anchor: "unused-types",
762 result_key: "unused_types",
763 counts_in_total: true,
764 },
765 IssueResultMeta {
766 code: "private-type-leak",
767 meta_description: "Exported values or types whose public TypeScript signature references a same-file type declaration that is not exported.",
768 meta_docs_path: "explanations/dead-code#private-type-leaks",
769 meta_name: "Private Type Leaks",
770 summary_label: "Private type leaks",
771 docs_anchor: "private-type-leaks",
772 result_key: "private_type_leaks",
773 counts_in_total: true,
774 },
775 IssueResultMeta {
776 code: "unused-dependency",
777 meta_description: "Packages listed in dependencies that are never imported or required by any source file.",
778 meta_docs_path: "explanations/dead-code#unused-dependencies",
779 meta_name: "Unused Dependencies",
780 summary_label: "Unused dependencies",
781 docs_anchor: "unused-dependencies",
782 result_key: "unused_dependencies",
783 counts_in_total: true,
784 },
785 IssueResultMeta {
786 code: "unused-dev-dependency",
787 meta_description: "Packages listed in devDependencies that are never imported by test files, config files, or scripts.",
788 meta_docs_path: "explanations/dead-code#unused-devdependencies",
789 meta_name: "Unused Dev Dependencies",
790 summary_label: "Unused devDependencies",
791 docs_anchor: "unused-dependencies",
792 result_key: "unused_dev_dependencies",
793 counts_in_total: true,
794 },
795 IssueResultMeta {
796 code: "unused-optional-dependency",
797 meta_description: "Packages listed in optionalDependencies that are never imported.",
798 meta_docs_path: "explanations/dead-code#unused-optionaldependencies",
799 meta_name: "Unused Optional Dependencies",
800 summary_label: "Unused optionalDependencies",
801 docs_anchor: "unused-dependencies",
802 result_key: "unused_optional_dependencies",
803 counts_in_total: true,
804 },
805 IssueResultMeta {
806 code: "unused-enum-member",
807 meta_description: "Enum members that are never referenced in the codebase.",
808 meta_docs_path: "explanations/dead-code#unused-enum-members",
809 meta_name: "Unused Enum Members",
810 summary_label: "Unused enum members",
811 docs_anchor: "unused-enum-members",
812 result_key: "unused_enum_members",
813 counts_in_total: true,
814 },
815 IssueResultMeta {
816 code: "unused-class-member",
817 meta_description: "Class methods and properties that are never referenced outside the class.",
818 meta_docs_path: "explanations/dead-code#unused-class-members",
819 meta_name: "Unused Class Members",
820 summary_label: "Unused class members",
821 docs_anchor: "unused-class-members",
822 result_key: "unused_class_members",
823 counts_in_total: true,
824 },
825 IssueResultMeta {
826 code: "unused-store-member",
827 meta_description: "Pinia store members declared but never accessed by any consumer project-wide.",
828 meta_docs_path: "explanations/dead-code#unused-store-members",
829 meta_name: "Unused Store Members",
830 summary_label: "Unused store members",
831 docs_anchor: "unused-store-members",
832 result_key: "unused_store_members",
833 counts_in_total: true,
834 },
835 IssueResultMeta {
836 code: "unresolved-import",
837 meta_description: "Import specifiers that could not be resolved to a file on disk.",
838 meta_docs_path: "explanations/dead-code#unresolved-imports",
839 meta_name: "Unresolved Imports",
840 summary_label: "Unresolved imports",
841 docs_anchor: "unresolved-imports",
842 result_key: "unresolved_imports",
843 counts_in_total: true,
844 },
845 IssueResultMeta {
846 code: "unlisted-dependency",
847 meta_description: "Packages imported in source code but not listed in package.json.",
848 meta_docs_path: "explanations/dead-code#unlisted-dependencies",
849 meta_name: "Unlisted Dependencies",
850 summary_label: "Unlisted dependencies",
851 docs_anchor: "unlisted-dependencies",
852 result_key: "unlisted_dependencies",
853 counts_in_total: true,
854 },
855 IssueResultMeta {
856 code: "duplicate-export",
857 meta_description: "The same export name is defined in multiple modules.",
858 meta_docs_path: "explanations/dead-code#duplicate-exports",
859 meta_name: "Duplicate Exports",
860 summary_label: "Duplicate exports",
861 docs_anchor: "duplicate-exports",
862 result_key: "duplicate_exports",
863 counts_in_total: true,
864 },
865 IssueResultMeta {
866 code: "type-only-dependency",
867 meta_description: "Production dependencies that are only imported via type-only imports.",
868 meta_docs_path: "explanations/dead-code#type-only-dependencies",
869 meta_name: "Type-only Dependencies",
870 summary_label: "Type-only dependencies",
871 docs_anchor: "type-only-dependencies",
872 result_key: "type_only_dependencies",
873 counts_in_total: true,
874 },
875 IssueResultMeta {
876 code: "test-only-dependency",
877 meta_description: "Production dependencies that are only imported from test files.",
878 meta_docs_path: "explanations/dead-code#test-only-dependencies",
879 meta_name: "Test-only Dependencies",
880 summary_label: "Test-only dependencies",
881 docs_anchor: "test-only-dependencies",
882 result_key: "test_only_dependencies",
883 counts_in_total: true,
884 },
885 IssueResultMeta {
886 code: "circular-dependency",
887 meta_description: "A cycle in the module import graph.",
888 meta_docs_path: "explanations/dead-code#circular-dependencies",
889 meta_name: "Circular Dependencies",
890 summary_label: "Circular dependencies",
891 docs_anchor: "circular-dependencies",
892 result_key: "circular_dependencies",
893 counts_in_total: true,
894 },
895 IssueResultMeta {
896 code: "re-export-cycle",
897 meta_description: "A barrel file re-exports from another barrel that ultimately re-exports back.",
898 meta_docs_path: "explanations/dead-code#re-export-cycles",
899 meta_name: "Re-Export Cycles",
900 summary_label: "Re-export cycles",
901 docs_anchor: "re-export-cycles",
902 result_key: "re_export_cycles",
903 counts_in_total: true,
904 },
905 IssueResultMeta {
906 code: "boundary-violation",
907 meta_description: "A module imports from a zone that its configured boundary rules do not allow.",
908 meta_docs_path: "explanations/dead-code#boundary-violations",
909 meta_name: "Boundary Violations",
910 summary_label: "Boundary violations",
911 docs_anchor: "boundary-violations",
912 result_key: "boundary_violations",
913 counts_in_total: true,
914 },
915 IssueResultMeta {
916 code: "boundary-coverage",
917 meta_description: "A reachable source file is not assigned to any configured boundary zone while boundary coverage is required.",
918 meta_docs_path: "explanations/dead-code#boundary-violations",
919 meta_name: "Boundary Coverage",
920 summary_label: "Boundary coverage",
921 docs_anchor: "boundary-violations",
922 result_key: "boundary_coverage_violations",
923 counts_in_total: true,
924 },
925 IssueResultMeta {
926 code: "boundary-call-violation",
927 meta_description: "A file classified into a boundary zone calls a callee matching one of the zone's forbidden call patterns.",
928 meta_docs_path: "explanations/dead-code#boundary-violations",
929 meta_name: "Boundary Call Violation",
930 summary_label: "Boundary calls",
931 docs_anchor: "boundary-violations",
932 result_key: "boundary_call_violations",
933 counts_in_total: true,
934 },
935 IssueResultMeta {
936 code: "policy-violation",
937 meta_description: "A call site, import, or catalogue-derived effect matched a configured rule pack rule.",
938 meta_docs_path: "explanations/dead-code#policy-violations",
939 meta_name: "Policy Violation",
940 summary_label: "Policy violations",
941 docs_anchor: "policy-violations",
942 result_key: "policy_violations",
943 counts_in_total: true,
944 },
945 IssueResultMeta {
946 code: "invalid-client-export",
947 meta_description: "A file carrying the use client directive also exports a Next.js server-only or route-segment config name.",
948 meta_docs_path: "explanations/dead-code#invalid-client-exports",
949 meta_name: "Invalid client export",
950 summary_label: "Invalid client exports",
951 docs_anchor: "invalid-client-exports",
952 result_key: "invalid_client_exports",
953 counts_in_total: true,
954 },
955 IssueResultMeta {
956 code: "mixed-client-server-barrel",
957 meta_description: "A barrel file forwards a name from a use client module alongside a name from a server-only module.",
958 meta_docs_path: "explanations/dead-code#mixed-client-server-barrels",
959 meta_name: "Mixed client/server barrel",
960 summary_label: "Mixed client/server barrels",
961 docs_anchor: "mixed-client-server-barrels",
962 result_key: "mixed_client_server_barrels",
963 counts_in_total: true,
964 },
965 IssueResultMeta {
966 code: "misplaced-directive",
967 meta_description: "A use client or use server directive string appears after a non-directive statement and is ignored.",
968 meta_docs_path: "explanations/dead-code#misplaced-directives",
969 meta_name: "Misplaced directive",
970 summary_label: "Misplaced directives",
971 docs_anchor: "misplaced-directives",
972 result_key: "misplaced_directives",
973 counts_in_total: true,
974 },
975 IssueResultMeta {
976 code: "unprovided-inject",
977 meta_description: "A Vue inject or Svelte getContext reads a dependency-injection key that no matching provider supplies.",
978 meta_docs_path: "explanations/dead-code#unprovided-injects",
979 meta_name: "Unprovided injects",
980 summary_label: "Unprovided injects",
981 docs_anchor: "unprovided-inject",
982 result_key: "unprovided_injects",
983 counts_in_total: true,
984 },
985 IssueResultMeta {
986 code: "unrendered-component",
987 meta_description: "A Vue or Svelte single-file component is reachable through the graph but rendered nowhere in the project.",
988 meta_docs_path: "explanations/dead-code#unrendered-components",
989 meta_name: "Unrendered components",
990 summary_label: "Unrendered components",
991 docs_anchor: "unrendered-component",
992 result_key: "unrendered_components",
993 counts_in_total: true,
994 },
995 IssueResultMeta {
996 code: "unused-component-prop",
997 meta_description: "A declared Vue, Svelte, React, or Preact component prop is referenced nowhere inside its own component.",
998 meta_docs_path: "explanations/dead-code#unused-component-props",
999 meta_name: "Unused component props",
1000 summary_label: "Unused component props",
1001 docs_anchor: "unused-component-prop",
1002 result_key: "unused_component_props",
1003 counts_in_total: true,
1004 },
1005 IssueResultMeta {
1006 code: "unused-component-emit",
1007 meta_description: "A Vue script setup defineEmits event is emitted nowhere in its own component.",
1008 meta_docs_path: "explanations/dead-code#unused-component-emits",
1009 meta_name: "Unused component emits",
1010 summary_label: "Unused component emits",
1011 docs_anchor: "unused-component-emit",
1012 result_key: "unused_component_emits",
1013 counts_in_total: true,
1014 },
1015 IssueResultMeta {
1016 code: "unused-component-input",
1017 meta_description: "An Angular input is read nowhere in its own component.",
1018 meta_docs_path: "explanations/dead-code#unused-component-inputs",
1019 meta_name: "Unused component inputs",
1020 summary_label: "Unused component inputs",
1021 docs_anchor: "unused-component-input",
1022 result_key: "unused_component_inputs",
1023 counts_in_total: true,
1024 },
1025 IssueResultMeta {
1026 code: "unused-component-output",
1027 meta_description: "An Angular output is emitted nowhere in its own component.",
1028 meta_docs_path: "explanations/dead-code#unused-component-outputs",
1029 meta_name: "Unused component outputs",
1030 summary_label: "Unused component outputs",
1031 docs_anchor: "unused-component-output",
1032 result_key: "unused_component_outputs",
1033 counts_in_total: true,
1034 },
1035 IssueResultMeta {
1036 code: "unused-svelte-event",
1037 meta_description: "A Svelte component dispatches a custom event whose name is listened to nowhere in the analyzed project.",
1038 meta_docs_path: "explanations/dead-code#unused-svelte-events",
1039 meta_name: "Unused Svelte events",
1040 summary_label: "Unused Svelte events",
1041 docs_anchor: "unused-svelte-event",
1042 result_key: "unused_svelte_events",
1043 counts_in_total: true,
1044 },
1045 IssueResultMeta {
1046 code: "unused-server-action",
1047 meta_description: "A Next.js Server Action exported from a use server file is referenced by no code in the project.",
1048 meta_docs_path: "explanations/dead-code#unused-server-actions",
1049 meta_name: "Unused server actions",
1050 summary_label: "Unused server actions",
1051 docs_anchor: "unused-server-action",
1052 result_key: "unused_server_actions",
1053 counts_in_total: true,
1054 },
1055 IssueResultMeta {
1056 code: "unused-load-data-key",
1057 meta_description: "A SvelteKit load return-object key is read by no route or project-wide consumer.",
1058 meta_docs_path: "explanations/dead-code#unused-load-data-keys",
1059 meta_name: "Unused load data keys",
1060 summary_label: "Unused load data keys",
1061 docs_anchor: "unused-load-data-key",
1062 result_key: "unused_load_data_keys",
1063 counts_in_total: true,
1064 },
1065 IssueResultMeta {
1066 code: "route-collision",
1067 meta_description: "Two or more Next.js App Router route files resolve to the same URL within one app root.",
1068 meta_docs_path: "explanations/dead-code#route-collisions",
1069 meta_name: "Route collision",
1070 summary_label: "Route collisions",
1071 docs_anchor: "route-collisions",
1072 result_key: "route_collisions",
1073 counts_in_total: true,
1074 },
1075 IssueResultMeta {
1076 code: "dynamic-segment-name-conflict",
1077 meta_description: "Sibling Next.js dynamic route segments use different slug names at the same position.",
1078 meta_docs_path: "explanations/dead-code#dynamic-segment-name-conflicts",
1079 meta_name: "Dynamic segment name conflict",
1080 summary_label: "Dynamic segment conflicts",
1081 docs_anchor: "dynamic-segment-name-conflicts",
1082 result_key: "dynamic_segment_name_conflicts",
1083 counts_in_total: true,
1084 },
1085 IssueResultMeta {
1086 code: "stale-suppression",
1087 meta_description: "A fallow suppression comment or tag no longer matches any active issue.",
1088 meta_docs_path: "explanations/dead-code#stale-suppressions",
1089 meta_name: "Stale Suppressions",
1090 summary_label: "Stale suppressions",
1091 docs_anchor: "stale-suppressions",
1092 result_key: "stale_suppressions",
1093 counts_in_total: true,
1094 },
1095 IssueResultMeta {
1096 code: "unused-catalog-entry",
1097 meta_description: "A package manager catalog entry is not referenced by any workspace package.json.",
1098 meta_docs_path: "explanations/dead-code#unused-catalog-entries",
1099 meta_name: "Unused catalog entry",
1100 summary_label: "Unused catalog entries",
1101 docs_anchor: "unused-catalog-entries",
1102 result_key: "unused_catalog_entries",
1103 counts_in_total: true,
1104 },
1105 IssueResultMeta {
1106 code: "empty-catalog-group",
1107 meta_description: "A named package manager catalog group has no package entries.",
1108 meta_docs_path: "explanations/dead-code#empty-catalog-groups",
1109 meta_name: "Empty catalog group",
1110 summary_label: "Empty catalog groups",
1111 docs_anchor: "empty-catalog-groups",
1112 result_key: "empty_catalog_groups",
1113 counts_in_total: true,
1114 },
1115 IssueResultMeta {
1116 code: "unresolved-catalog-reference",
1117 meta_description: "A workspace package.json uses a catalog protocol reference that no catalog declares.",
1118 meta_docs_path: "explanations/dead-code#unresolved-catalog-references",
1119 meta_name: "Unresolved catalog reference",
1120 summary_label: "Unresolved catalog references",
1121 docs_anchor: "unresolved-catalog-references",
1122 result_key: "unresolved_catalog_references",
1123 counts_in_total: true,
1124 },
1125 IssueResultMeta {
1126 code: "unused-dependency-override",
1127 meta_description: "A pnpm dependency override targets a package not declared by any workspace package and not present in the lockfile.",
1128 meta_docs_path: "explanations/dead-code#unused-dependency-overrides",
1129 meta_name: "Unused pnpm dependency override",
1130 summary_label: "Unused dependency overrides",
1131 docs_anchor: "unused-dependency-overrides",
1132 result_key: "unused_dependency_overrides",
1133 counts_in_total: true,
1134 },
1135 IssueResultMeta {
1136 code: "misconfigured-dependency-override",
1137 meta_description: "A pnpm dependency override key or value does not parse as a valid override spec.",
1138 meta_docs_path: "explanations/dead-code#misconfigured-dependency-overrides",
1139 meta_name: "Misconfigured pnpm dependency override",
1140 summary_label: "Misconfigured dependency overrides",
1141 docs_anchor: "misconfigured-dependency-overrides",
1142 result_key: "misconfigured_dependency_overrides",
1143 counts_in_total: true,
1144 },
1145 IssueResultMeta {
1146 code: "prop-drilling",
1147 meta_description: "A React or Preact prop is forwarded unchanged through multiple pass-through components to a distant consumer.",
1148 meta_docs_path: "explanations/dead-code#prop-drilling",
1149 meta_name: "Prop drilling",
1150 summary_label: "Prop drilling",
1151 docs_anchor: "prop-drilling",
1152 result_key: "prop_drilling_chains",
1153 counts_in_total: false,
1154 },
1155 IssueResultMeta {
1156 code: "thin-wrapper",
1157 meta_description: "A React or Preact component is structural indirection around a single spread-forwarded child render.",
1158 meta_docs_path: "explanations/dead-code#thin-wrapper",
1159 meta_name: "Thin wrapper",
1160 summary_label: "Thin wrappers",
1161 docs_anchor: "thin-wrapper",
1162 result_key: "thin_wrappers",
1163 counts_in_total: false,
1164 },
1165 IssueResultMeta {
1166 code: "duplicate-prop-shape",
1167 meta_description: "Multiple React or Preact components declare an identical significant prop-name set.",
1168 meta_docs_path: "explanations/dead-code#duplicate-prop-shape",
1169 meta_name: "Duplicate prop shape",
1170 summary_label: "Duplicate prop shapes",
1171 docs_anchor: "duplicate-prop-shape",
1172 result_key: "duplicate_prop_shapes",
1173 counts_in_total: false,
1174 },
1175];
1176
1177pub const KNOWN_ISSUE_KIND_NAMES: &[&str] = &[
1179 "unused-file",
1180 "unused-export",
1181 "unused-type",
1182 "private-type-leak",
1183 "unused-dependency",
1184 "unused-dev-dependency",
1185 "unused-enum-member",
1186 "unused-class-member",
1187 "unresolved-import",
1188 "unlisted-dependency",
1189 "duplicate-export",
1190 "code-duplication",
1191 "circular-dependency",
1192 "circular-dependencies",
1193 "re-export-cycle",
1194 "re-export-cycles",
1195 "reexport-cycle",
1196 "reexport-cycles",
1197 "type-only-dependency",
1198 "test-only-dependency",
1199 "boundary-violation",
1200 "boundary-call-violation",
1201 "boundary-call-violations",
1202 "coverage-gaps",
1203 "feature-flag",
1204 "complexity",
1205 "stale-suppression",
1206 "unused-catalog-entry",
1207 "unused-catalog-entries",
1208 "empty-catalog-group",
1209 "empty-catalog-groups",
1210 "unresolved-catalog-reference",
1211 "unresolved-catalog-references",
1212 "unused-dependency-override",
1213 "unused-dependency-overrides",
1214 "misconfigured-dependency-override",
1215 "misconfigured-dependency-overrides",
1216 "security-client-server-leak",
1217 "security-sink",
1218 "policy-violation",
1219 "policy-violations",
1220 "invalid-client-export",
1221 "invalid-client-exports",
1222 "mixed-client-server-barrel",
1223 "mixed-client-server-barrels",
1224 "misplaced-directive",
1225 "misplaced-directives",
1226 "unused-store-member",
1227 "unused-store-members",
1228 "unprovided-inject",
1229 "unprovided-injects",
1230 "route-collision",
1231 "route-collisions",
1232 "dynamic-segment-name-conflict",
1233 "dynamic-segment-name-conflicts",
1234 "unrendered-component",
1235 "unrendered-components",
1236 "unused-component-prop",
1237 "unused-component-props",
1238 "unused-component-emit",
1239 "unused-component-emits",
1240 "unused-component-input",
1241 "unused-component-inputs",
1242 "unused-component-output",
1243 "unused-component-outputs",
1244 "unused-server-action",
1245 "unused-server-actions",
1246 "unused-load-data-key",
1247 "unused-load-data-keys",
1248 "prop-drilling",
1249 "thin-wrapper",
1250 "thin-wrappers",
1251 "duplicate-prop-shape",
1252 "duplicate-prop-shapes",
1253 "unused-svelte-event",
1254 "unused-svelte-events",
1255];
1256
1257pub const DEAD_CODE_FILTER_FLAGS: &[&str] = &[
1259 "--unused-files",
1260 "--unused-exports",
1261 "--unused-types",
1262 "--private-type-leaks",
1263 "--unused-deps",
1264 "--unused-enum-members",
1265 "--unused-class-members",
1266 "--unused-store-members",
1267 "--unprovided-injects",
1268 "--unrendered-components",
1269 "--unused-component-props",
1270 "--unused-component-emits",
1271 "--unused-component-inputs",
1272 "--unused-component-outputs",
1273 "--unused-svelte-events",
1274 "--unused-server-actions",
1275 "--unused-load-data-keys",
1276 "--unresolved-imports",
1277 "--unlisted-deps",
1278 "--duplicate-exports",
1279 "--circular-deps",
1280 "--re-export-cycles",
1281 "--boundary-violations",
1282 "--policy-violations",
1283 "--stale-suppressions",
1284 "--unused-catalog-entries",
1285 "--empty-catalog-groups",
1286 "--unresolved-catalog-references",
1287 "--unused-dependency-overrides",
1288 "--misconfigured-dependency-overrides",
1289];
1290
1291pub const MCP_ISSUE_TYPE_FLAGS: &[(&str, &str)] = &[
1293 ("unused-files", "--unused-files"),
1294 ("unused-exports", "--unused-exports"),
1295 ("unused-types", "--unused-types"),
1296 ("private-type-leaks", "--private-type-leaks"),
1297 ("unused-deps", "--unused-deps"),
1298 ("unused-enum-members", "--unused-enum-members"),
1299 ("unused-class-members", "--unused-class-members"),
1300 ("unused-store-members", "--unused-store-members"),
1301 ("unprovided-injects", "--unprovided-injects"),
1302 ("unrendered-components", "--unrendered-components"),
1303 ("unused-component-props", "--unused-component-props"),
1304 ("unused-component-emits", "--unused-component-emits"),
1305 ("unused-component-inputs", "--unused-component-inputs"),
1306 ("unused-component-outputs", "--unused-component-outputs"),
1307 ("unused-svelte-events", "--unused-svelte-events"),
1308 ("unused-server-actions", "--unused-server-actions"),
1309 ("unused-load-data-keys", "--unused-load-data-keys"),
1310 ("unresolved-imports", "--unresolved-imports"),
1311 ("unlisted-deps", "--unlisted-deps"),
1312 ("duplicate-exports", "--duplicate-exports"),
1313 ("circular-deps", "--circular-deps"),
1314 ("re-export-cycles", "--re-export-cycles"),
1315 ("boundary-violations", "--boundary-violations"),
1316 ("policy-violations", "--policy-violations"),
1317 ("stale-suppressions", "--stale-suppressions"),
1318 ("unused-catalog-entries", "--unused-catalog-entries"),
1319 ("empty-catalog-groups", "--empty-catalog-groups"),
1320 (
1321 "unresolved-catalog-references",
1322 "--unresolved-catalog-references",
1323 ),
1324 (
1325 "unused-dependency-overrides",
1326 "--unused-dependency-overrides",
1327 ),
1328 (
1329 "misconfigured-dependency-overrides",
1330 "--misconfigured-dependency-overrides",
1331 ),
1332];
1333
1334pub const CODECLIMATE_RESULT_CODES: &[&str] = &[
1336 "unused-file",
1337 "unused-export",
1338 "unused-type",
1339 "private-type-leak",
1340 "unused-dependency",
1341 "unused-dev-dependency",
1342 "unused-optional-dependency",
1343 "unused-enum-member",
1344 "unused-class-member",
1345 "unused-store-member",
1346 "unresolved-import",
1347 "unlisted-dependency",
1348 "duplicate-export",
1349 "type-only-dependency",
1350 "test-only-dependency",
1351 "circular-dependency",
1352 "re-export-cycle",
1353 "boundary-violation",
1354 "boundary-coverage",
1355 "boundary-call-violation",
1356 "policy-violation",
1357 "invalid-client-export",
1358 "mixed-client-server-barrel",
1359 "misplaced-directive",
1360 "unprovided-inject",
1361 "unrendered-component",
1362 "unused-component-prop",
1363 "unused-component-emit",
1364 "unused-component-input",
1365 "unused-component-output",
1366 "unused-svelte-event",
1367 "unused-server-action",
1368 "unused-load-data-key",
1369 "route-collision",
1370 "dynamic-segment-name-conflict",
1371 "stale-suppression",
1372 "unused-catalog-entry",
1373 "empty-catalog-group",
1374 "unresolved-catalog-reference",
1375 "unused-dependency-override",
1376 "misconfigured-dependency-override",
1377];
1378
1379#[must_use]
1381pub fn issue_meta_by_code(code: &str) -> Option<&'static IssueKindMeta> {
1382 ISSUE_KIND_META.iter().find(|meta| meta.code == code)
1383}
1384
1385#[must_use]
1387pub fn issue_meta_for_token(token: &str) -> Option<&'static IssueKindMeta> {
1388 ISSUE_KIND_META
1389 .iter()
1390 .find(|meta| meta.code == token || meta.aliases.contains(&token))
1391}
1392
1393#[must_use]
1395pub fn issue_meta_by_kind(kind: IssueKind) -> Option<&'static IssueKindMeta> {
1396 ISSUE_KIND_META.iter().find(|meta| meta.kind == Some(kind))
1397}
1398
1399#[must_use]
1401pub fn issue_result_meta_by_code(code: &str) -> Option<&'static IssueResultMeta> {
1402 ISSUE_RESULT_META.iter().find(|meta| meta.code == code)
1403}
1404
1405#[must_use]
1407pub fn issue_sarif_rule_ids(code: &str) -> Vec<String> {
1408 let mut ids = vec![format!("fallow/{code}")];
1409 if code == "stale-suppression" {
1410 ids.push("fallow/missing-suppression-reason".to_string());
1411 }
1412 ids
1413}
1414
1415#[must_use]
1417pub fn issue_codeclimate_check_names(code: &str) -> Vec<String> {
1418 if !CODECLIMATE_RESULT_CODES.contains(&code) {
1419 return Vec::new();
1420 }
1421 issue_sarif_rule_ids(code)
1422}
1423
1424#[must_use]
1427pub fn issue_docs_anchor(code: &str) -> Option<&'static str> {
1428 issue_result_meta_by_code(code).map(|meta| meta.docs_anchor)
1429}
1430
1431#[must_use]
1433pub fn issue_ts_alias(code: &str) -> Option<TsAliasMeta> {
1434 let alias = match code {
1435 "unused-file" => TsAliasMeta {
1436 name: "UnusedFile",
1437 parent: "UnusedFileFinding",
1438 },
1439 "unused-export" => TsAliasMeta {
1440 name: "UnusedExport",
1441 parent: "UnusedExportFinding",
1442 },
1443 "private-type-leak" => TsAliasMeta {
1444 name: "PrivateTypeLeak",
1445 parent: "PrivateTypeLeakFinding",
1446 },
1447 "unused-dependency" => TsAliasMeta {
1448 name: "UnusedDependency",
1449 parent: "UnusedDependencyFinding",
1450 },
1451 "unused-dev-dependency" => TsAliasMeta {
1452 name: "UnusedDependency",
1453 parent: "UnusedDevDependencyFinding",
1454 },
1455 "unused-optional-dependency" => TsAliasMeta {
1456 name: "UnusedDependency",
1457 parent: "UnusedOptionalDependencyFinding",
1458 },
1459 "unused-enum-member" => TsAliasMeta {
1460 name: "UnusedMember",
1461 parent: "UnusedEnumMemberFinding",
1462 },
1463 "unused-class-member" => TsAliasMeta {
1464 name: "UnusedMember",
1465 parent: "UnusedClassMemberFinding",
1466 },
1467 "unused-store-member" => TsAliasMeta {
1468 name: "UnusedMember",
1469 parent: "UnusedStoreMemberFinding",
1470 },
1471 "unresolved-import" => TsAliasMeta {
1472 name: "UnresolvedImport",
1473 parent: "UnresolvedImportFinding",
1474 },
1475 "unlisted-dependency" => TsAliasMeta {
1476 name: "UnlistedDependency",
1477 parent: "UnlistedDependencyFinding",
1478 },
1479 "duplicate-export" => TsAliasMeta {
1480 name: "DuplicateExport",
1481 parent: "DuplicateExportFinding",
1482 },
1483 "type-only-dependency" => TsAliasMeta {
1484 name: "TypeOnlyDependency",
1485 parent: "TypeOnlyDependencyFinding",
1486 },
1487 "test-only-dependency" => TsAliasMeta {
1488 name: "TestOnlyDependency",
1489 parent: "TestOnlyDependencyFinding",
1490 },
1491 "circular-dependency" => TsAliasMeta {
1492 name: "CircularDependency",
1493 parent: "CircularDependencyFinding",
1494 },
1495 "re-export-cycle" => TsAliasMeta {
1496 name: "ReExportCycle",
1497 parent: "ReExportCycleFinding",
1498 },
1499 "boundary-violation" => TsAliasMeta {
1500 name: "BoundaryViolation",
1501 parent: "BoundaryViolationFinding",
1502 },
1503 "unused-catalog-entry" => TsAliasMeta {
1504 name: "UnusedCatalogEntry",
1505 parent: "UnusedCatalogEntryFinding",
1506 },
1507 "empty-catalog-group" => TsAliasMeta {
1508 name: "EmptyCatalogGroup",
1509 parent: "EmptyCatalogGroupFinding",
1510 },
1511 "unresolved-catalog-reference" => TsAliasMeta {
1512 name: "UnresolvedCatalogReference",
1513 parent: "UnresolvedCatalogReferenceFinding",
1514 },
1515 "unused-dependency-override" => TsAliasMeta {
1516 name: "UnusedDependencyOverride",
1517 parent: "UnusedDependencyOverrideFinding",
1518 },
1519 "misconfigured-dependency-override" => TsAliasMeta {
1520 name: "MisconfiguredDependencyOverride",
1521 parent: "MisconfiguredDependencyOverrideFinding",
1522 },
1523 _ => return None,
1524 };
1525 Some(alias)
1526}
1527
1528pub fn diagnostic_issue_metas() -> impl Iterator<Item = &'static IssueKindMeta> {
1530 ISSUE_KIND_META.iter().filter(|meta| meta.lsp)
1531}
1532
1533pub fn result_issue_metas() -> impl Iterator<Item = &'static IssueResultMeta> {
1535 ISSUE_RESULT_META.iter()
1536}
1537
1538pub fn counted_result_issue_metas() -> impl Iterator<Item = &'static IssueResultMeta> {
1540 result_issue_metas().filter(|meta| meta.counts_in_total)
1541}
1542
1543#[cfg(test)]
1544mod tests {
1545 use std::collections::BTreeSet;
1546
1547 use crate::results::TOTAL_ISSUE_RESULT_KEYS;
1548
1549 use super::*;
1550
1551 #[test]
1552 fn known_names_round_trip_through_metadata() {
1553 for name in KNOWN_ISSUE_KIND_NAMES {
1554 let meta = issue_meta_for_token(name)
1555 .unwrap_or_else(|| panic!("known issue name {name} missing metadata row"));
1556 assert!(
1557 meta.kind.is_some(),
1558 "known issue name {name} maps to non-IssueKind metadata"
1559 );
1560 }
1561 }
1562
1563 #[test]
1564 fn issue_kind_variants_have_metadata() {
1565 for &kind in IssueKind::ALL {
1566 assert!(
1567 issue_meta_by_kind(kind).is_some(),
1568 "IssueKind {kind:?} has no metadata row"
1569 );
1570 }
1571 }
1572
1573 #[test]
1574 fn dead_code_filter_flags_match_metadata() {
1575 let from_constants: BTreeSet<&str> = DEAD_CODE_FILTER_FLAGS.iter().copied().collect();
1576 let from_meta: BTreeSet<&str> = ISSUE_KIND_META
1577 .iter()
1578 .filter_map(|meta| meta.filter_flag)
1579 .collect();
1580 assert_eq!(from_constants, from_meta);
1581 }
1582
1583 #[test]
1584 fn mcp_issue_type_flags_match_metadata() {
1585 let from_constants: BTreeSet<(&str, &str)> = MCP_ISSUE_TYPE_FLAGS.iter().copied().collect();
1586 let from_meta: BTreeSet<(&str, &str)> = ISSUE_KIND_META
1587 .iter()
1588 .filter_map(|meta| meta.mcp_pair())
1589 .collect();
1590 assert_eq!(from_constants, from_meta);
1591 }
1592
1593 #[test]
1594 fn lsp_exposes_only_actual_diagnostic_codes() {
1595 let codes: BTreeSet<&str> = diagnostic_issue_metas().map(|meta| meta.code).collect();
1596 assert!(codes.contains("boundary-violation"));
1597 assert!(!codes.contains("boundary-coverage"));
1598 assert!(!codes.contains("boundary-call-violation"));
1599 }
1600
1601 #[test]
1602 fn issue_codes_are_unique() {
1603 let mut seen = BTreeSet::new();
1604 for meta in ISSUE_KIND_META {
1605 assert!(seen.insert(meta.code), "duplicate issue code {}", meta.code);
1606 }
1607 }
1608
1609 #[test]
1610 fn result_meta_codes_have_issue_metadata() {
1611 for meta in ISSUE_RESULT_META {
1612 assert!(
1613 issue_meta_by_code(meta.code).is_some(),
1614 "result metadata code {} has no issue metadata row",
1615 meta.code
1616 );
1617 }
1618 }
1619
1620 #[test]
1621 fn result_meta_codes_have_docs_anchors() {
1622 for meta in ISSUE_RESULT_META {
1623 assert_eq!(
1624 issue_docs_anchor(meta.code),
1625 Some(meta.docs_anchor),
1626 "result metadata code {} has mismatched docs anchor",
1627 meta.code
1628 );
1629 }
1630 }
1631
1632 #[test]
1633 fn result_meta_codes_have_summary_labels() {
1634 for meta in ISSUE_RESULT_META {
1635 assert!(
1636 !meta.summary_label.is_empty(),
1637 "result metadata code {} has no summary label",
1638 meta.code
1639 );
1640 }
1641 }
1642
1643 #[test]
1644 fn result_meta_codes_have_meta_names() {
1645 for meta in ISSUE_RESULT_META {
1646 assert!(
1647 !meta.meta_name.is_empty(),
1648 "result metadata code {} has no meta name",
1649 meta.code
1650 );
1651 }
1652 }
1653
1654 #[test]
1655 fn result_meta_codes_have_meta_docs_paths() {
1656 for meta in ISSUE_RESULT_META {
1657 assert!(
1658 meta.meta_docs_path.starts_with("explanations/dead-code#"),
1659 "result metadata code {} has invalid meta docs path",
1660 meta.code
1661 );
1662 }
1663 }
1664
1665 #[test]
1666 fn result_meta_codes_have_meta_descriptions() {
1667 for meta in ISSUE_RESULT_META {
1668 assert!(
1669 !meta.meta_description.is_empty(),
1670 "result metadata code {} has no meta description",
1671 meta.code
1672 );
1673 }
1674 }
1675
1676 #[test]
1677 fn ci_format_ids_are_prefixed_and_known() {
1678 let result_codes: BTreeSet<&str> = result_issue_metas().map(|meta| meta.code).collect();
1679 let codeclimate_codes: BTreeSet<&str> = CODECLIMATE_RESULT_CODES.iter().copied().collect();
1680 assert!(codeclimate_codes.is_subset(&result_codes));
1681
1682 for meta in result_issue_metas() {
1683 let sarif_ids = issue_sarif_rule_ids(meta.code);
1684 assert!(sarif_ids.contains(&format!("fallow/{}", meta.code)));
1685 for rule_id in sarif_ids {
1686 assert!(
1687 rule_id.starts_with("fallow/"),
1688 "result metadata code {} has unprefixed SARIF rule id {rule_id}",
1689 meta.code
1690 );
1691 }
1692 for check_name in issue_codeclimate_check_names(meta.code) {
1693 assert!(
1694 check_name.starts_with("fallow/"),
1695 "result metadata code {} has unprefixed CodeClimate check name {check_name}",
1696 meta.code
1697 );
1698 }
1699 }
1700 }
1701
1702 #[test]
1703 fn ts_alias_policy_is_explicit() {
1704 let aliases: BTreeSet<(&str, &str)> = result_issue_metas()
1705 .filter_map(|meta| issue_ts_alias(meta.code).map(|alias| (alias.name, alias.parent)))
1706 .collect();
1707
1708 assert_eq!(
1709 BTreeSet::from([
1710 ("BoundaryViolation", "BoundaryViolationFinding"),
1711 ("CircularDependency", "CircularDependencyFinding"),
1712 ("DuplicateExport", "DuplicateExportFinding"),
1713 ("EmptyCatalogGroup", "EmptyCatalogGroupFinding"),
1714 (
1715 "MisconfiguredDependencyOverride",
1716 "MisconfiguredDependencyOverrideFinding",
1717 ),
1718 ("PrivateTypeLeak", "PrivateTypeLeakFinding"),
1719 ("ReExportCycle", "ReExportCycleFinding"),
1720 ("TestOnlyDependency", "TestOnlyDependencyFinding"),
1721 ("TypeOnlyDependency", "TypeOnlyDependencyFinding"),
1722 (
1723 "UnresolvedCatalogReference",
1724 "UnresolvedCatalogReferenceFinding",
1725 ),
1726 ("UnresolvedImport", "UnresolvedImportFinding"),
1727 ("UnlistedDependency", "UnlistedDependencyFinding"),
1728 ("UnusedCatalogEntry", "UnusedCatalogEntryFinding"),
1729 ("UnusedDependency", "UnusedDependencyFinding"),
1730 ("UnusedDependency", "UnusedDevDependencyFinding"),
1731 ("UnusedDependency", "UnusedOptionalDependencyFinding"),
1732 (
1733 "UnusedDependencyOverride",
1734 "UnusedDependencyOverrideFinding",
1735 ),
1736 ("UnusedExport", "UnusedExportFinding"),
1737 ("UnusedFile", "UnusedFileFinding"),
1738 ("UnusedMember", "UnusedClassMemberFinding"),
1739 ("UnusedMember", "UnusedEnumMemberFinding"),
1740 ("UnusedMember", "UnusedStoreMemberFinding"),
1741 ]),
1742 aliases
1743 );
1744 }
1745
1746 #[test]
1747 fn result_keys_are_unique() {
1748 let mut seen = BTreeSet::new();
1749 for meta in ISSUE_RESULT_META {
1750 assert!(
1751 seen.insert(meta.result_key),
1752 "duplicate result key {}",
1753 meta.result_key
1754 );
1755 }
1756 }
1757
1758 #[test]
1759 fn counted_result_keys_match_total_issue_fields() {
1760 let from_total: BTreeSet<&str> = TOTAL_ISSUE_RESULT_KEYS.iter().copied().collect();
1761 let from_meta: BTreeSet<&str> = counted_result_issue_metas()
1762 .map(|meta| meta.result_key)
1763 .collect();
1764 assert_eq!(from_total, from_meta);
1765 }
1766
1767 #[test]
1768 fn advisory_result_keys_are_explicitly_excluded_from_total() {
1769 let expected = BTreeSet::from([
1770 "duplicate_prop_shapes",
1771 "prop_drilling_chains",
1772 "thin_wrappers",
1773 ]);
1774 let from_meta: BTreeSet<&str> = result_issue_metas()
1775 .filter(|meta| !meta.counts_in_total)
1776 .map(|meta| meta.result_key)
1777 .collect();
1778 assert_eq!(expected, from_meta);
1779 }
1780}