Skip to main content

fallow_types/
issue_meta.rs

1//! Shared issue-type contract metadata.
2
3use crate::suppress::IssueKind;
4
5/// Shared contract facts for issue-like diagnostics.
6///
7/// Curated prose stays with the surface that owns it. This table is only for
8/// stable machine-facing facts that otherwise drift across CLI schema, LSP,
9/// MCP, and suppression helpers.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct IssueKindMeta {
12    /// Backing suppression issue kind, when this row maps to one.
13    pub kind: Option<IssueKind>,
14    /// Canonical issue code used in output and diagnostic codes.
15    pub code: &'static str,
16    /// Accepted aliases for config, suppression, or migration compatibility.
17    pub aliases: &'static [&'static str],
18    /// User-facing label for editor and capability surfaces.
19    pub label: &'static str,
20    /// Canonical `[rules]` key when the issue is configurable.
21    pub config_key: Option<&'static str>,
22    /// Dead-code CLI filter flag, when one exists.
23    pub filter_flag: Option<&'static str>,
24    /// MCP `issue_types` selector, when this issue can be selected there.
25    pub mcp_issue_type: Option<&'static str>,
26    /// Suppression token agents should emit, when suppressible.
27    pub suppress_token: Option<&'static str>,
28    /// Whether the suppression comment should use `fallow-ignore-file`.
29    pub suppress_file_level: bool,
30    /// Whether the LSP exposes this row through initialization options and
31    /// `fallow/issueTypes`.
32    pub lsp: bool,
33    /// Broad documentation category for authoring and generated manifests.
34    pub docs_category: &'static str,
35}
36
37impl IssueKindMeta {
38    /// Return the filter flag as an MCP selector pair.
39    #[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
48/// All shared issue metadata rows.
49pub 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: &["boundary-call-violation", "boundary-call-violations"],
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: Some(IssueKind::PolicyViolation),
299        code: "policy-violation",
300        aliases: &["policy-violations"],
301        label: "Policy Violations",
302        config_key: Some("policy-violation"),
303        filter_flag: Some("--policy-violations"),
304        mcp_issue_type: Some("policy-violations"),
305        suppress_token: Some("policy-violation"),
306        suppress_file_level: false,
307        lsp: true,
308        docs_category: "architecture",
309    },
310    IssueKindMeta {
311        kind: Some(IssueKind::InvalidClientExport),
312        code: "invalid-client-export",
313        aliases: &["invalid-client-exports"],
314        label: "Invalid Client Exports",
315        config_key: Some("invalid-client-export"),
316        filter_flag: None,
317        mcp_issue_type: None,
318        suppress_token: Some("invalid-client-export"),
319        suppress_file_level: false,
320        lsp: true,
321        docs_category: "framework",
322    },
323    IssueKindMeta {
324        kind: Some(IssueKind::MixedClientServerBarrel),
325        code: "mixed-client-server-barrel",
326        aliases: &["mixed-client-server-barrels"],
327        label: "Mixed Client/Server Barrels",
328        config_key: Some("mixed-client-server-barrel"),
329        filter_flag: None,
330        mcp_issue_type: None,
331        suppress_token: Some("mixed-client-server-barrel"),
332        suppress_file_level: false,
333        lsp: true,
334        docs_category: "framework",
335    },
336    IssueKindMeta {
337        kind: Some(IssueKind::MisplacedDirective),
338        code: "misplaced-directive",
339        aliases: &["misplaced-directives"],
340        label: "Misplaced Directives",
341        config_key: Some("misplaced-directive"),
342        filter_flag: None,
343        mcp_issue_type: None,
344        suppress_token: Some("misplaced-directive"),
345        suppress_file_level: false,
346        lsp: true,
347        docs_category: "framework",
348    },
349    IssueKindMeta {
350        kind: Some(IssueKind::UnprovidedInject),
351        code: "unprovided-inject",
352        aliases: &["unprovided-injects"],
353        label: "Unprovided Injects",
354        config_key: Some("unprovided-injects"),
355        filter_flag: Some("--unprovided-injects"),
356        mcp_issue_type: Some("unprovided-injects"),
357        suppress_token: Some("unprovided-inject"),
358        suppress_file_level: false,
359        lsp: true,
360        docs_category: "framework",
361    },
362    IssueKindMeta {
363        kind: Some(IssueKind::UnrenderedComponent),
364        code: "unrendered-component",
365        aliases: &["unrendered-components"],
366        label: "Unrendered Components",
367        config_key: Some("unrendered-components"),
368        filter_flag: Some("--unrendered-components"),
369        mcp_issue_type: Some("unrendered-components"),
370        suppress_token: Some("unrendered-component"),
371        suppress_file_level: false,
372        lsp: true,
373        docs_category: "framework",
374    },
375    IssueKindMeta {
376        kind: Some(IssueKind::UnusedComponentProp),
377        code: "unused-component-prop",
378        aliases: &["unused-component-props"],
379        label: "Unused Component Props",
380        config_key: Some("unused-component-props"),
381        filter_flag: Some("--unused-component-props"),
382        mcp_issue_type: Some("unused-component-props"),
383        suppress_token: Some("unused-component-prop"),
384        suppress_file_level: false,
385        lsp: true,
386        docs_category: "framework",
387    },
388    IssueKindMeta {
389        kind: Some(IssueKind::UnusedComponentEmit),
390        code: "unused-component-emit",
391        aliases: &["unused-component-emits"],
392        label: "Unused Component Emits",
393        config_key: Some("unused-component-emits"),
394        filter_flag: Some("--unused-component-emits"),
395        mcp_issue_type: Some("unused-component-emits"),
396        suppress_token: Some("unused-component-emit"),
397        suppress_file_level: false,
398        lsp: true,
399        docs_category: "framework",
400    },
401    IssueKindMeta {
402        kind: Some(IssueKind::UnusedComponentInput),
403        code: "unused-component-input",
404        aliases: &["unused-component-inputs"],
405        label: "Unused Component Inputs",
406        config_key: Some("unused-component-inputs"),
407        filter_flag: Some("--unused-component-inputs"),
408        mcp_issue_type: Some("unused-component-inputs"),
409        suppress_token: Some("unused-component-input"),
410        suppress_file_level: false,
411        lsp: true,
412        docs_category: "framework",
413    },
414    IssueKindMeta {
415        kind: Some(IssueKind::UnusedComponentOutput),
416        code: "unused-component-output",
417        aliases: &["unused-component-outputs"],
418        label: "Unused Component Outputs",
419        config_key: Some("unused-component-outputs"),
420        filter_flag: Some("--unused-component-outputs"),
421        mcp_issue_type: Some("unused-component-outputs"),
422        suppress_token: Some("unused-component-output"),
423        suppress_file_level: false,
424        lsp: true,
425        docs_category: "framework",
426    },
427    IssueKindMeta {
428        kind: Some(IssueKind::UnusedSvelteEvent),
429        code: "unused-svelte-event",
430        aliases: &["unused-svelte-events"],
431        label: "Unused Svelte Events",
432        config_key: Some("unused-svelte-events"),
433        filter_flag: Some("--unused-svelte-events"),
434        mcp_issue_type: Some("unused-svelte-events"),
435        suppress_token: Some("unused-svelte-event"),
436        suppress_file_level: false,
437        lsp: true,
438        docs_category: "framework",
439    },
440    IssueKindMeta {
441        kind: Some(IssueKind::UnusedServerAction),
442        code: "unused-server-action",
443        aliases: &["unused-server-actions"],
444        label: "Unused Server Actions",
445        config_key: Some("unused-server-actions"),
446        filter_flag: Some("--unused-server-actions"),
447        mcp_issue_type: Some("unused-server-actions"),
448        suppress_token: Some("unused-server-action"),
449        suppress_file_level: false,
450        lsp: true,
451        docs_category: "framework",
452    },
453    IssueKindMeta {
454        kind: Some(IssueKind::UnusedLoadDataKey),
455        code: "unused-load-data-key",
456        aliases: &["unused-load-data-keys"],
457        label: "Unused Load Data Keys",
458        config_key: Some("unused-load-data-keys"),
459        filter_flag: Some("--unused-load-data-keys"),
460        mcp_issue_type: Some("unused-load-data-keys"),
461        suppress_token: Some("unused-load-data-key"),
462        suppress_file_level: false,
463        lsp: true,
464        docs_category: "framework",
465    },
466    IssueKindMeta {
467        kind: Some(IssueKind::RouteCollision),
468        code: "route-collision",
469        aliases: &["route-collisions"],
470        label: "Route Collisions",
471        config_key: Some("route-collision"),
472        filter_flag: None,
473        mcp_issue_type: None,
474        suppress_token: Some("route-collision"),
475        suppress_file_level: true,
476        lsp: true,
477        docs_category: "framework",
478    },
479    IssueKindMeta {
480        kind: Some(IssueKind::DynamicSegmentNameConflict),
481        code: "dynamic-segment-name-conflict",
482        aliases: &["dynamic-segment-name-conflicts"],
483        label: "Dynamic Segment Conflicts",
484        config_key: Some("dynamic-segment-name-conflict"),
485        filter_flag: None,
486        mcp_issue_type: None,
487        suppress_token: Some("dynamic-segment-name-conflict"),
488        suppress_file_level: true,
489        lsp: true,
490        docs_category: "framework",
491    },
492    IssueKindMeta {
493        kind: Some(IssueKind::StaleSuppression),
494        code: "stale-suppression",
495        aliases: &[],
496        label: "Stale Suppressions",
497        config_key: Some("stale-suppressions"),
498        filter_flag: Some("--stale-suppressions"),
499        mcp_issue_type: Some("stale-suppressions"),
500        suppress_token: None,
501        suppress_file_level: false,
502        lsp: true,
503        docs_category: "source",
504    },
505    IssueKindMeta {
506        kind: Some(IssueKind::PnpmCatalogEntry),
507        code: "unused-catalog-entry",
508        aliases: &["unused-catalog-entries"],
509        label: "Unused Catalog Entries",
510        config_key: Some("unused-catalog-entries"),
511        filter_flag: Some("--unused-catalog-entries"),
512        mcp_issue_type: Some("unused-catalog-entries"),
513        suppress_token: None,
514        suppress_file_level: false,
515        lsp: true,
516        docs_category: "dependency",
517    },
518    IssueKindMeta {
519        kind: Some(IssueKind::EmptyCatalogGroup),
520        code: "empty-catalog-group",
521        aliases: &["empty-catalog-groups"],
522        label: "Empty Catalog Groups",
523        config_key: Some("empty-catalog-groups"),
524        filter_flag: Some("--empty-catalog-groups"),
525        mcp_issue_type: Some("empty-catalog-groups"),
526        suppress_token: None,
527        suppress_file_level: false,
528        lsp: true,
529        docs_category: "dependency",
530    },
531    IssueKindMeta {
532        kind: Some(IssueKind::UnresolvedCatalogReference),
533        code: "unresolved-catalog-reference",
534        aliases: &["unresolved-catalog-references"],
535        label: "Unresolved Catalog References",
536        config_key: Some("unresolved-catalog-references"),
537        filter_flag: Some("--unresolved-catalog-references"),
538        mcp_issue_type: Some("unresolved-catalog-references"),
539        suppress_token: None,
540        suppress_file_level: false,
541        lsp: true,
542        docs_category: "dependency",
543    },
544    IssueKindMeta {
545        kind: Some(IssueKind::UnusedDependencyOverride),
546        code: "unused-dependency-override",
547        aliases: &["unused-dependency-overrides"],
548        label: "Unused Dependency Overrides",
549        config_key: Some("unused-dependency-overrides"),
550        filter_flag: Some("--unused-dependency-overrides"),
551        mcp_issue_type: Some("unused-dependency-overrides"),
552        suppress_token: None,
553        suppress_file_level: false,
554        lsp: true,
555        docs_category: "dependency",
556    },
557    IssueKindMeta {
558        kind: Some(IssueKind::MisconfiguredDependencyOverride),
559        code: "misconfigured-dependency-override",
560        aliases: &["misconfigured-dependency-overrides"],
561        label: "Misconfigured Dependency Overrides",
562        config_key: Some("misconfigured-dependency-overrides"),
563        filter_flag: Some("--misconfigured-dependency-overrides"),
564        mcp_issue_type: Some("misconfigured-dependency-overrides"),
565        suppress_token: None,
566        suppress_file_level: false,
567        lsp: true,
568        docs_category: "dependency",
569    },
570    IssueKindMeta {
571        kind: Some(IssueKind::SecuritySink),
572        code: "security-sink",
573        aliases: &[],
574        label: "Security Sink Candidates",
575        config_key: Some("security-sink"),
576        filter_flag: None,
577        mcp_issue_type: None,
578        suppress_token: Some("security-sink"),
579        suppress_file_level: false,
580        lsp: true,
581        docs_category: "security",
582    },
583    IssueKindMeta {
584        kind: Some(IssueKind::SecurityClientServerLeak),
585        code: "security-client-server-leak",
586        aliases: &[],
587        label: "Security Client-Server Leaks",
588        config_key: Some("security-client-server-leak"),
589        filter_flag: None,
590        mcp_issue_type: None,
591        suppress_token: Some("security-client-server-leak"),
592        suppress_file_level: true,
593        lsp: true,
594        docs_category: "security",
595    },
596    IssueKindMeta {
597        kind: Some(IssueKind::CoverageGaps),
598        code: "coverage-gaps",
599        aliases: &[],
600        label: "Coverage Gaps",
601        config_key: Some("coverage-gaps"),
602        filter_flag: None,
603        mcp_issue_type: None,
604        suppress_token: Some("coverage-gaps"),
605        suppress_file_level: true,
606        lsp: false,
607        docs_category: "health",
608    },
609    IssueKindMeta {
610        kind: Some(IssueKind::FeatureFlag),
611        code: "feature-flag",
612        aliases: &[],
613        label: "Feature Flags",
614        config_key: Some("feature-flags"),
615        filter_flag: None,
616        mcp_issue_type: None,
617        suppress_token: Some("feature-flag"),
618        suppress_file_level: false,
619        lsp: false,
620        docs_category: "flags",
621    },
622    IssueKindMeta {
623        kind: Some(IssueKind::Complexity),
624        code: "complexity",
625        aliases: &[],
626        label: "Complexity",
627        config_key: None,
628        filter_flag: None,
629        mcp_issue_type: None,
630        suppress_token: Some("complexity"),
631        suppress_file_level: false,
632        lsp: false,
633        docs_category: "health",
634    },
635    IssueKindMeta {
636        kind: Some(IssueKind::PropDrilling),
637        code: "prop-drilling",
638        aliases: &[],
639        label: "Prop Drilling",
640        config_key: Some("prop-drilling"),
641        filter_flag: None,
642        mcp_issue_type: None,
643        suppress_token: Some("prop-drilling"),
644        suppress_file_level: false,
645        lsp: false,
646        docs_category: "source",
647    },
648    IssueKindMeta {
649        kind: Some(IssueKind::ThinWrapper),
650        code: "thin-wrapper",
651        aliases: &["thin-wrappers"],
652        label: "Thin Wrappers",
653        config_key: Some("thin-wrapper"),
654        filter_flag: None,
655        mcp_issue_type: None,
656        suppress_token: Some("thin-wrapper"),
657        suppress_file_level: false,
658        lsp: false,
659        docs_category: "source",
660    },
661    IssueKindMeta {
662        kind: Some(IssueKind::DuplicatePropShape),
663        code: "duplicate-prop-shape",
664        aliases: &["duplicate-prop-shapes"],
665        label: "Duplicate Prop Shapes",
666        config_key: Some("duplicate-prop-shape"),
667        filter_flag: None,
668        mcp_issue_type: None,
669        suppress_token: Some("duplicate-prop-shape"),
670        suppress_file_level: false,
671        lsp: false,
672        docs_category: "source",
673    },
674];
675
676/// Canonical names and aliases accepted by `IssueKind::parse`.
677pub const KNOWN_ISSUE_KIND_NAMES: &[&str] = &[
678    "unused-file",
679    "unused-export",
680    "unused-type",
681    "private-type-leak",
682    "unused-dependency",
683    "unused-dev-dependency",
684    "unused-enum-member",
685    "unused-class-member",
686    "unresolved-import",
687    "unlisted-dependency",
688    "duplicate-export",
689    "code-duplication",
690    "circular-dependency",
691    "circular-dependencies",
692    "re-export-cycle",
693    "re-export-cycles",
694    "reexport-cycle",
695    "reexport-cycles",
696    "type-only-dependency",
697    "test-only-dependency",
698    "boundary-violation",
699    "boundary-call-violation",
700    "boundary-call-violations",
701    "coverage-gaps",
702    "feature-flag",
703    "complexity",
704    "stale-suppression",
705    "unused-catalog-entry",
706    "unused-catalog-entries",
707    "empty-catalog-group",
708    "empty-catalog-groups",
709    "unresolved-catalog-reference",
710    "unresolved-catalog-references",
711    "unused-dependency-override",
712    "unused-dependency-overrides",
713    "misconfigured-dependency-override",
714    "misconfigured-dependency-overrides",
715    "security-client-server-leak",
716    "security-sink",
717    "policy-violation",
718    "policy-violations",
719    "invalid-client-export",
720    "invalid-client-exports",
721    "mixed-client-server-barrel",
722    "mixed-client-server-barrels",
723    "misplaced-directive",
724    "misplaced-directives",
725    "unused-store-member",
726    "unused-store-members",
727    "unprovided-inject",
728    "unprovided-injects",
729    "route-collision",
730    "route-collisions",
731    "dynamic-segment-name-conflict",
732    "dynamic-segment-name-conflicts",
733    "unrendered-component",
734    "unrendered-components",
735    "unused-component-prop",
736    "unused-component-props",
737    "unused-component-emit",
738    "unused-component-emits",
739    "unused-component-input",
740    "unused-component-inputs",
741    "unused-component-output",
742    "unused-component-outputs",
743    "unused-server-action",
744    "unused-server-actions",
745    "unused-load-data-key",
746    "unused-load-data-keys",
747    "prop-drilling",
748    "thin-wrapper",
749    "thin-wrappers",
750    "duplicate-prop-shape",
751    "duplicate-prop-shapes",
752    "unused-svelte-event",
753    "unused-svelte-events",
754];
755
756/// CLI filter flags on `fallow dead-code` that scope output to one issue family.
757pub const DEAD_CODE_FILTER_FLAGS: &[&str] = &[
758    "--unused-files",
759    "--unused-exports",
760    "--unused-types",
761    "--private-type-leaks",
762    "--unused-deps",
763    "--unused-enum-members",
764    "--unused-class-members",
765    "--unused-store-members",
766    "--unprovided-injects",
767    "--unrendered-components",
768    "--unused-component-props",
769    "--unused-component-emits",
770    "--unused-component-inputs",
771    "--unused-component-outputs",
772    "--unused-svelte-events",
773    "--unused-server-actions",
774    "--unused-load-data-keys",
775    "--unresolved-imports",
776    "--unlisted-deps",
777    "--duplicate-exports",
778    "--circular-deps",
779    "--re-export-cycles",
780    "--boundary-violations",
781    "--policy-violations",
782    "--stale-suppressions",
783    "--unused-catalog-entries",
784    "--empty-catalog-groups",
785    "--unresolved-catalog-references",
786    "--unused-dependency-overrides",
787    "--misconfigured-dependency-overrides",
788];
789
790/// MCP issue selector names mapped to dead-code CLI flags.
791pub const MCP_ISSUE_TYPE_FLAGS: &[(&str, &str)] = &[
792    ("unused-files", "--unused-files"),
793    ("unused-exports", "--unused-exports"),
794    ("unused-types", "--unused-types"),
795    ("private-type-leaks", "--private-type-leaks"),
796    ("unused-deps", "--unused-deps"),
797    ("unused-enum-members", "--unused-enum-members"),
798    ("unused-class-members", "--unused-class-members"),
799    ("unused-store-members", "--unused-store-members"),
800    ("unprovided-injects", "--unprovided-injects"),
801    ("unrendered-components", "--unrendered-components"),
802    ("unused-component-props", "--unused-component-props"),
803    ("unused-component-emits", "--unused-component-emits"),
804    ("unused-component-inputs", "--unused-component-inputs"),
805    ("unused-component-outputs", "--unused-component-outputs"),
806    ("unused-svelte-events", "--unused-svelte-events"),
807    ("unused-server-actions", "--unused-server-actions"),
808    ("unused-load-data-keys", "--unused-load-data-keys"),
809    ("unresolved-imports", "--unresolved-imports"),
810    ("unlisted-deps", "--unlisted-deps"),
811    ("duplicate-exports", "--duplicate-exports"),
812    ("circular-deps", "--circular-deps"),
813    ("re-export-cycles", "--re-export-cycles"),
814    ("boundary-violations", "--boundary-violations"),
815    ("policy-violations", "--policy-violations"),
816    ("stale-suppressions", "--stale-suppressions"),
817    ("unused-catalog-entries", "--unused-catalog-entries"),
818    ("empty-catalog-groups", "--empty-catalog-groups"),
819    (
820        "unresolved-catalog-references",
821        "--unresolved-catalog-references",
822    ),
823    (
824        "unused-dependency-overrides",
825        "--unused-dependency-overrides",
826    ),
827    (
828        "misconfigured-dependency-overrides",
829        "--misconfigured-dependency-overrides",
830    ),
831];
832
833/// Lookup metadata by canonical code.
834#[must_use]
835pub fn issue_meta_by_code(code: &str) -> Option<&'static IssueKindMeta> {
836    ISSUE_KIND_META.iter().find(|meta| meta.code == code)
837}
838
839/// Lookup metadata by canonical code or alias.
840#[must_use]
841pub fn issue_meta_for_token(token: &str) -> Option<&'static IssueKindMeta> {
842    ISSUE_KIND_META
843        .iter()
844        .find(|meta| meta.code == token || meta.aliases.contains(&token))
845}
846
847/// Lookup metadata by backing issue kind.
848#[must_use]
849pub fn issue_meta_by_kind(kind: IssueKind) -> Option<&'static IssueKindMeta> {
850    ISSUE_KIND_META.iter().find(|meta| meta.kind == Some(kind))
851}
852
853/// Rows exposed by the LSP issue-type capability.
854pub fn diagnostic_issue_metas() -> impl Iterator<Item = &'static IssueKindMeta> {
855    ISSUE_KIND_META.iter().filter(|meta| meta.lsp)
856}
857
858#[cfg(test)]
859mod tests {
860    use std::collections::BTreeSet;
861
862    use super::*;
863
864    #[test]
865    fn known_names_round_trip_through_metadata() {
866        for name in KNOWN_ISSUE_KIND_NAMES {
867            let meta = issue_meta_for_token(name)
868                .unwrap_or_else(|| panic!("known issue name {name} missing metadata row"));
869            assert!(
870                meta.kind.is_some(),
871                "known issue name {name} maps to non-IssueKind metadata"
872            );
873        }
874    }
875
876    #[test]
877    fn issue_kind_variants_have_metadata() {
878        for discriminant in 1..=47 {
879            let kind = IssueKind::from_discriminant(discriminant).unwrap();
880            assert!(
881                issue_meta_by_kind(kind).is_some(),
882                "IssueKind {kind:?} has no metadata row"
883            );
884        }
885    }
886
887    #[test]
888    fn dead_code_filter_flags_match_metadata() {
889        let from_constants: BTreeSet<&str> = DEAD_CODE_FILTER_FLAGS.iter().copied().collect();
890        let from_meta: BTreeSet<&str> = ISSUE_KIND_META
891            .iter()
892            .filter_map(|meta| meta.filter_flag)
893            .collect();
894        assert_eq!(from_constants, from_meta);
895    }
896
897    #[test]
898    fn mcp_issue_type_flags_match_metadata() {
899        let from_constants: BTreeSet<(&str, &str)> = MCP_ISSUE_TYPE_FLAGS.iter().copied().collect();
900        let from_meta: BTreeSet<(&str, &str)> = ISSUE_KIND_META
901            .iter()
902            .filter_map(|meta| meta.mcp_pair())
903            .collect();
904        assert_eq!(from_constants, from_meta);
905    }
906}