1use std::sync::LazyLock;
4
5use crate::suppress::IssueKind;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct IssueKindMeta {
14 pub kind: Option<IssueKind>,
16 pub code: &'static str,
18 pub aliases: &'static [&'static str],
20 pub label: &'static str,
22 pub config_key: Option<&'static str>,
24 pub filter_flag: Option<&'static str>,
26 pub mcp_issue_type: Option<&'static str>,
28 pub suppress_token: Option<&'static str>,
30 pub suppress_file_level: bool,
32 pub lsp: bool,
35 pub docs_category: &'static str,
37}
38
39impl IssueKindMeta {
40 #[must_use]
42 pub const fn mcp_pair(self) -> Option<(&'static str, &'static str)> {
43 match (self.mcp_issue_type, self.filter_flag) {
44 (Some(issue_type), Some(flag)) => Some((issue_type, flag)),
45 _ => None,
46 }
47 }
48
49 #[must_use]
51 pub fn has_result_contract(self) -> bool {
52 issue_result_meta_by_code(self.code).is_some()
53 }
54
55 #[must_use]
57 pub fn sarif_rule_ids(self) -> Vec<String> {
58 issue_sarif_rule_ids(self.code)
59 }
60
61 #[must_use]
63 pub fn codeclimate_check_names(self) -> Vec<String> {
64 issue_codeclimate_check_names(self.code)
65 }
66
67 #[must_use]
69 pub fn docs_anchor(self) -> Option<&'static str> {
70 issue_docs_anchor(self.code)
71 }
72
73 #[must_use]
75 pub fn ts_alias(self) -> Option<TsAliasMeta> {
76 issue_ts_alias(self.code)
77 }
78}
79
80pub const ISSUE_KIND_META: &[IssueKindMeta] = &[
82 IssueKindMeta {
83 kind: Some(IssueKind::CodeDuplication),
84 code: "code-duplication",
85 aliases: &[],
86 label: "Code Duplication",
87 config_key: None,
88 filter_flag: None,
89 mcp_issue_type: None,
90 suppress_token: Some("code-duplication"),
91 suppress_file_level: false,
92 lsp: true,
93 docs_category: "dupes",
94 },
95 IssueKindMeta {
96 kind: Some(IssueKind::UnusedFile),
97 code: "unused-file",
98 aliases: &[],
99 label: "Unused Files",
100 config_key: Some("unused-files"),
101 filter_flag: Some("--unused-files"),
102 mcp_issue_type: Some("unused-files"),
103 suppress_token: Some("unused-file"),
104 suppress_file_level: true,
105 lsp: true,
106 docs_category: "source",
107 },
108 IssueKindMeta {
109 kind: Some(IssueKind::UnusedExport),
110 code: "unused-export",
111 aliases: &[],
112 label: "Unused Exports",
113 config_key: Some("unused-exports"),
114 filter_flag: Some("--unused-exports"),
115 mcp_issue_type: Some("unused-exports"),
116 suppress_token: Some("unused-export"),
117 suppress_file_level: false,
118 lsp: true,
119 docs_category: "source",
120 },
121 IssueKindMeta {
122 kind: Some(IssueKind::UnusedType),
123 code: "unused-type",
124 aliases: &[],
125 label: "Unused Types",
126 config_key: Some("unused-types"),
127 filter_flag: Some("--unused-types"),
128 mcp_issue_type: Some("unused-types"),
129 suppress_token: Some("unused-type"),
130 suppress_file_level: false,
131 lsp: true,
132 docs_category: "source",
133 },
134 IssueKindMeta {
135 kind: Some(IssueKind::PrivateTypeLeak),
136 code: "private-type-leak",
137 aliases: &[],
138 label: "Private Type Leaks",
139 config_key: Some("private-type-leaks"),
140 filter_flag: Some("--private-type-leaks"),
141 mcp_issue_type: Some("private-type-leaks"),
142 suppress_token: Some("private-type-leak"),
143 suppress_file_level: false,
144 lsp: true,
145 docs_category: "source",
146 },
147 IssueKindMeta {
148 kind: Some(IssueKind::DeprecatedExportInUse),
149 code: "deprecated-export-in-use",
150 aliases: &[],
151 label: "Deprecated Exports in Use",
152 config_key: Some("deprecated-exports-in-use"),
153 filter_flag: Some("--deprecated-exports-in-use"),
154 mcp_issue_type: Some("deprecated-exports-in-use"),
155 suppress_token: Some("deprecated-export-in-use"),
156 suppress_file_level: false,
157 lsp: false,
158 docs_category: "source",
159 },
160 IssueKindMeta {
161 kind: Some(IssueKind::UnusedDependency),
162 code: "unused-dependency",
163 aliases: &[],
164 label: "Unused Dependencies",
165 config_key: Some("unused-dependencies"),
166 filter_flag: Some("--unused-deps"),
167 mcp_issue_type: Some("unused-deps"),
168 suppress_token: None,
169 suppress_file_level: false,
170 lsp: true,
171 docs_category: "dependency",
172 },
173 IssueKindMeta {
174 kind: Some(IssueKind::UnusedDevDependency),
175 code: "unused-dev-dependency",
176 aliases: &["unused-dev-deps", "unused-dev-dependencies"],
177 label: "Unused Dev Dependencies",
178 config_key: Some("unused-dev-dependencies"),
179 filter_flag: Some("--unused-deps"),
180 mcp_issue_type: None,
181 suppress_token: None,
182 suppress_file_level: false,
183 lsp: true,
184 docs_category: "dependency",
185 },
186 IssueKindMeta {
187 kind: None,
188 code: "unused-optional-dependency",
189 aliases: &["unused-optional-deps", "unused-optional-dependencies"],
190 label: "Unused Optional Dependencies",
191 config_key: Some("unused-optional-dependencies"),
192 filter_flag: Some("--unused-deps"),
193 mcp_issue_type: None,
194 suppress_token: None,
195 suppress_file_level: false,
196 lsp: true,
197 docs_category: "dependency",
198 },
199 IssueKindMeta {
200 kind: Some(IssueKind::UnusedEnumMember),
201 code: "unused-enum-member",
202 aliases: &[],
203 label: "Unused Enum Members",
204 config_key: Some("unused-enum-members"),
205 filter_flag: Some("--unused-enum-members"),
206 mcp_issue_type: Some("unused-enum-members"),
207 suppress_token: Some("unused-enum-member"),
208 suppress_file_level: false,
209 lsp: true,
210 docs_category: "source",
211 },
212 IssueKindMeta {
213 kind: Some(IssueKind::UnusedClassMember),
214 code: "unused-class-member",
215 aliases: &[],
216 label: "Unused Class Members",
217 config_key: Some("unused-class-members"),
218 filter_flag: Some("--unused-class-members"),
219 mcp_issue_type: Some("unused-class-members"),
220 suppress_token: Some("unused-class-member"),
221 suppress_file_level: false,
222 lsp: true,
223 docs_category: "source",
224 },
225 IssueKindMeta {
226 kind: Some(IssueKind::UnusedStoreMember),
227 code: "unused-store-member",
228 aliases: &["unused-store-members"],
229 label: "Unused Store Members",
230 config_key: Some("unused-store-members"),
231 filter_flag: Some("--unused-store-members"),
232 mcp_issue_type: Some("unused-store-members"),
233 suppress_token: Some("unused-store-member"),
234 suppress_file_level: false,
235 lsp: true,
236 docs_category: "framework",
237 },
238 IssueKindMeta {
239 kind: Some(IssueKind::UnresolvedImport),
240 code: "unresolved-import",
241 aliases: &[],
242 label: "Unresolved Imports",
243 config_key: Some("unresolved-imports"),
244 filter_flag: Some("--unresolved-imports"),
245 mcp_issue_type: Some("unresolved-imports"),
246 suppress_token: Some("unresolved-import"),
247 suppress_file_level: false,
248 lsp: true,
249 docs_category: "dependency",
250 },
251 IssueKindMeta {
252 kind: Some(IssueKind::UnlistedDependency),
253 code: "unlisted-dependency",
254 aliases: &[],
255 label: "Unlisted Dependencies",
256 config_key: Some("unlisted-dependencies"),
257 filter_flag: Some("--unlisted-deps"),
258 mcp_issue_type: Some("unlisted-deps"),
259 suppress_token: None,
260 suppress_file_level: false,
261 lsp: true,
262 docs_category: "dependency",
263 },
264 IssueKindMeta {
265 kind: Some(IssueKind::DuplicateExport),
266 code: "duplicate-export",
267 aliases: &[],
268 label: "Duplicate Exports",
269 config_key: Some("duplicate-exports"),
270 filter_flag: Some("--duplicate-exports"),
271 mcp_issue_type: Some("duplicate-exports"),
272 suppress_token: Some("duplicate-export"),
273 suppress_file_level: true,
274 lsp: true,
275 docs_category: "source",
276 },
277 IssueKindMeta {
278 kind: Some(IssueKind::TypeOnlyDependency),
279 code: "type-only-dependency",
280 aliases: &[],
281 label: "Type-Only Dependencies",
282 config_key: Some("type-only-dependencies"),
283 filter_flag: Some("--unused-deps"),
284 mcp_issue_type: None,
285 suppress_token: None,
286 suppress_file_level: false,
287 lsp: true,
288 docs_category: "dependency",
289 },
290 IssueKindMeta {
291 kind: Some(IssueKind::TestOnlyDependency),
292 code: "test-only-dependency",
293 aliases: &[],
294 label: "Test-Only Dependencies",
295 config_key: Some("test-only-dependencies"),
296 filter_flag: Some("--unused-deps"),
297 mcp_issue_type: None,
298 suppress_token: None,
299 suppress_file_level: false,
300 lsp: true,
301 docs_category: "dependency",
302 },
303 IssueKindMeta {
304 kind: Some(IssueKind::DevDependencyInProduction),
305 code: "dev-dependency-in-production",
306 aliases: &[],
307 label: "Dev Dependencies Used in Production",
308 config_key: Some("dev-dependencies-in-production"),
309 filter_flag: Some("--unused-deps"),
310 mcp_issue_type: None,
311 suppress_token: None,
312 suppress_file_level: false,
313 lsp: true,
314 docs_category: "dependency",
315 },
316 IssueKindMeta {
317 kind: Some(IssueKind::CircularDependency),
318 code: "circular-dependency",
319 aliases: &["circular-dependencies"],
320 label: "Circular Dependencies",
321 config_key: Some("circular-dependencies"),
322 filter_flag: Some("--circular-deps"),
323 mcp_issue_type: Some("circular-deps"),
324 suppress_token: Some("circular-dependency"),
325 suppress_file_level: false,
326 lsp: true,
327 docs_category: "architecture",
328 },
329 IssueKindMeta {
330 kind: Some(IssueKind::ReExportCycle),
331 code: "re-export-cycle",
332 aliases: &["re-export-cycles", "reexport-cycle", "reexport-cycles"],
333 label: "Re-Export Cycles",
334 config_key: Some("re-export-cycle"),
335 filter_flag: Some("--re-export-cycles"),
336 mcp_issue_type: Some("re-export-cycles"),
337 suppress_token: Some("re-export-cycle"),
338 suppress_file_level: true,
339 lsp: true,
340 docs_category: "architecture",
341 },
342 IssueKindMeta {
343 kind: Some(IssueKind::PackageCycle),
344 code: "package-cycle",
345 aliases: &["package-cycles"],
346 label: "Package Cycles",
347 config_key: Some("package-cycle"),
348 filter_flag: Some("--package-cycles"),
349 mcp_issue_type: Some("package-cycles"),
350 suppress_token: Some("package-cycle"),
351 suppress_file_level: false,
352 lsp: true,
353 docs_category: "architecture",
354 },
355 IssueKindMeta {
356 kind: Some(IssueKind::BoundaryViolation),
357 code: "boundary-violation",
358 aliases: &[],
359 label: "Boundary Violations",
360 config_key: Some("boundary-violation"),
361 filter_flag: Some("--boundary-violations"),
362 mcp_issue_type: Some("boundary-violations"),
363 suppress_token: Some("boundary-violation"),
364 suppress_file_level: false,
365 lsp: true,
366 docs_category: "architecture",
367 },
368 IssueKindMeta {
369 kind: None,
370 code: "boundary-coverage",
371 aliases: &["boundary-coverage-violations"],
372 label: "Boundary Coverage",
373 config_key: Some("boundary-violation"),
374 filter_flag: Some("--boundary-violations"),
375 mcp_issue_type: None,
376 suppress_token: Some("boundary-violation"),
377 suppress_file_level: true,
378 lsp: false,
379 docs_category: "architecture",
380 },
381 IssueKindMeta {
382 kind: Some(IssueKind::BoundaryViolation),
383 code: "boundary-call-violation",
384 aliases: &["boundary-calls", "boundary-call-violations"],
385 label: "Boundary Call Violations",
386 config_key: Some("boundary-violation"),
387 filter_flag: Some("--boundary-violations"),
388 mcp_issue_type: None,
389 suppress_token: Some("boundary-call-violation"),
390 suppress_file_level: false,
391 lsp: false,
392 docs_category: "architecture",
393 },
394 IssueKindMeta {
395 kind: Some(IssueKind::PolicyViolation),
396 code: "policy-violation",
397 aliases: &["policy-violations"],
398 label: "Policy Violations",
399 config_key: Some("policy-violation"),
400 filter_flag: Some("--policy-violations"),
401 mcp_issue_type: Some("policy-violations"),
402 suppress_token: Some("policy-violation"),
403 suppress_file_level: false,
404 lsp: true,
405 docs_category: "architecture",
406 },
407 IssueKindMeta {
408 kind: Some(IssueKind::InvalidClientExport),
409 code: "invalid-client-export",
410 aliases: &["invalid-client-exports"],
411 label: "Invalid Client Exports",
412 config_key: Some("invalid-client-export"),
413 filter_flag: None,
414 mcp_issue_type: None,
415 suppress_token: Some("invalid-client-export"),
416 suppress_file_level: false,
417 lsp: true,
418 docs_category: "framework",
419 },
420 IssueKindMeta {
421 kind: Some(IssueKind::MixedClientServerBarrel),
422 code: "mixed-client-server-barrel",
423 aliases: &["mixed-client-server-barrels"],
424 label: "Mixed Client/Server Barrels",
425 config_key: Some("mixed-client-server-barrel"),
426 filter_flag: None,
427 mcp_issue_type: None,
428 suppress_token: Some("mixed-client-server-barrel"),
429 suppress_file_level: false,
430 lsp: true,
431 docs_category: "framework",
432 },
433 IssueKindMeta {
434 kind: Some(IssueKind::MisplacedDirective),
435 code: "misplaced-directive",
436 aliases: &["misplaced-directives"],
437 label: "Misplaced Directives",
438 config_key: Some("misplaced-directive"),
439 filter_flag: None,
440 mcp_issue_type: None,
441 suppress_token: Some("misplaced-directive"),
442 suppress_file_level: false,
443 lsp: true,
444 docs_category: "framework",
445 },
446 IssueKindMeta {
447 kind: Some(IssueKind::UnprovidedInject),
448 code: "unprovided-inject",
449 aliases: &["unprovided-injects"],
450 label: "Unprovided Injects",
451 config_key: Some("unprovided-injects"),
452 filter_flag: Some("--unprovided-injects"),
453 mcp_issue_type: Some("unprovided-injects"),
454 suppress_token: Some("unprovided-inject"),
455 suppress_file_level: false,
456 lsp: true,
457 docs_category: "framework",
458 },
459 IssueKindMeta {
460 kind: Some(IssueKind::UnrenderedComponent),
461 code: "unrendered-component",
462 aliases: &["unrendered-components"],
463 label: "Unrendered Components",
464 config_key: Some("unrendered-components"),
465 filter_flag: Some("--unrendered-components"),
466 mcp_issue_type: Some("unrendered-components"),
467 suppress_token: Some("unrendered-component"),
468 suppress_file_level: false,
469 lsp: true,
470 docs_category: "framework",
471 },
472 IssueKindMeta {
473 kind: Some(IssueKind::UnusedComponentProp),
474 code: "unused-component-prop",
475 aliases: &["unused-component-props"],
476 label: "Unused Component Props",
477 config_key: Some("unused-component-props"),
478 filter_flag: Some("--unused-component-props"),
479 mcp_issue_type: Some("unused-component-props"),
480 suppress_token: Some("unused-component-prop"),
481 suppress_file_level: false,
482 lsp: true,
483 docs_category: "framework",
484 },
485 IssueKindMeta {
486 kind: Some(IssueKind::UnusedComponentEmit),
487 code: "unused-component-emit",
488 aliases: &["unused-component-emits"],
489 label: "Unused Component Emits",
490 config_key: Some("unused-component-emits"),
491 filter_flag: Some("--unused-component-emits"),
492 mcp_issue_type: Some("unused-component-emits"),
493 suppress_token: Some("unused-component-emit"),
494 suppress_file_level: false,
495 lsp: true,
496 docs_category: "framework",
497 },
498 IssueKindMeta {
499 kind: Some(IssueKind::UnusedComponentInput),
500 code: "unused-component-input",
501 aliases: &["unused-component-inputs"],
502 label: "Unused Component Inputs",
503 config_key: Some("unused-component-inputs"),
504 filter_flag: Some("--unused-component-inputs"),
505 mcp_issue_type: Some("unused-component-inputs"),
506 suppress_token: Some("unused-component-input"),
507 suppress_file_level: false,
508 lsp: true,
509 docs_category: "framework",
510 },
511 IssueKindMeta {
512 kind: Some(IssueKind::UnusedComponentOutput),
513 code: "unused-component-output",
514 aliases: &["unused-component-outputs"],
515 label: "Unused Component Outputs",
516 config_key: Some("unused-component-outputs"),
517 filter_flag: Some("--unused-component-outputs"),
518 mcp_issue_type: Some("unused-component-outputs"),
519 suppress_token: Some("unused-component-output"),
520 suppress_file_level: false,
521 lsp: true,
522 docs_category: "framework",
523 },
524 IssueKindMeta {
525 kind: Some(IssueKind::UnusedSvelteEvent),
526 code: "unused-svelte-event",
527 aliases: &["unused-svelte-events"],
528 label: "Unused Svelte Events",
529 config_key: Some("unused-svelte-events"),
530 filter_flag: Some("--unused-svelte-events"),
531 mcp_issue_type: Some("unused-svelte-events"),
532 suppress_token: Some("unused-svelte-event"),
533 suppress_file_level: false,
534 lsp: true,
535 docs_category: "framework",
536 },
537 IssueKindMeta {
538 kind: Some(IssueKind::UnusedServerAction),
539 code: "unused-server-action",
540 aliases: &["unused-server-actions"],
541 label: "Unused Server Actions",
542 config_key: Some("unused-server-actions"),
543 filter_flag: Some("--unused-server-actions"),
544 mcp_issue_type: Some("unused-server-actions"),
545 suppress_token: Some("unused-server-action"),
546 suppress_file_level: false,
547 lsp: true,
548 docs_category: "framework",
549 },
550 IssueKindMeta {
551 kind: Some(IssueKind::UnusedLoadDataKey),
552 code: "unused-load-data-key",
553 aliases: &["unused-load-data-keys"],
554 label: "Unused Load Data Keys",
555 config_key: Some("unused-load-data-keys"),
556 filter_flag: Some("--unused-load-data-keys"),
557 mcp_issue_type: Some("unused-load-data-keys"),
558 suppress_token: Some("unused-load-data-key"),
559 suppress_file_level: false,
560 lsp: true,
561 docs_category: "framework",
562 },
563 IssueKindMeta {
564 kind: Some(IssueKind::RouteCollision),
565 code: "route-collision",
566 aliases: &["route-collisions"],
567 label: "Route Collisions",
568 config_key: Some("route-collision"),
569 filter_flag: None,
570 mcp_issue_type: None,
571 suppress_token: Some("route-collision"),
572 suppress_file_level: true,
573 lsp: true,
574 docs_category: "framework",
575 },
576 IssueKindMeta {
577 kind: Some(IssueKind::DynamicSegmentNameConflict),
578 code: "dynamic-segment-name-conflict",
579 aliases: &["dynamic-segment-name-conflicts"],
580 label: "Dynamic Segment Conflicts",
581 config_key: Some("dynamic-segment-name-conflict"),
582 filter_flag: None,
583 mcp_issue_type: None,
584 suppress_token: Some("dynamic-segment-name-conflict"),
585 suppress_file_level: true,
586 lsp: true,
587 docs_category: "framework",
588 },
589 IssueKindMeta {
590 kind: Some(IssueKind::StaleSuppression),
591 code: "stale-suppression",
592 aliases: &[],
593 label: "Stale Suppressions",
594 config_key: Some("stale-suppressions"),
595 filter_flag: Some("--stale-suppressions"),
596 mcp_issue_type: Some("stale-suppressions"),
597 suppress_token: None,
598 suppress_file_level: false,
599 lsp: true,
600 docs_category: "source",
601 },
602 IssueKindMeta {
603 kind: Some(IssueKind::StaleSuppression),
604 code: "missing-suppression-reason",
605 aliases: &["missing-suppression-reasons"],
606 label: "Missing Suppression Reasons",
607 config_key: Some("require-suppression-reason"),
608 filter_flag: Some("--stale-suppressions"),
609 mcp_issue_type: None,
610 suppress_token: None,
611 suppress_file_level: false,
612 lsp: false,
613 docs_category: "source",
614 },
615 IssueKindMeta {
616 kind: Some(IssueKind::PnpmCatalogEntry),
617 code: "unused-catalog-entry",
618 aliases: &["catalog", "unused-catalog-entries"],
619 label: "Unused Catalog Entries",
620 config_key: Some("unused-catalog-entries"),
621 filter_flag: Some("--unused-catalog-entries"),
622 mcp_issue_type: Some("unused-catalog-entries"),
623 suppress_token: None,
624 suppress_file_level: false,
625 lsp: true,
626 docs_category: "dependency",
627 },
628 IssueKindMeta {
629 kind: Some(IssueKind::EmptyCatalogGroup),
630 code: "empty-catalog-group",
631 aliases: &["empty-catalog", "empty-catalog-groups"],
632 label: "Empty Catalog Groups",
633 config_key: Some("empty-catalog-groups"),
634 filter_flag: Some("--empty-catalog-groups"),
635 mcp_issue_type: Some("empty-catalog-groups"),
636 suppress_token: None,
637 suppress_file_level: false,
638 lsp: true,
639 docs_category: "dependency",
640 },
641 IssueKindMeta {
642 kind: Some(IssueKind::UnresolvedCatalogReference),
643 code: "unresolved-catalog-reference",
644 aliases: &["unresolved-catalog", "unresolved-catalog-references"],
645 label: "Unresolved Catalog References",
646 config_key: Some("unresolved-catalog-references"),
647 filter_flag: Some("--unresolved-catalog-references"),
648 mcp_issue_type: Some("unresolved-catalog-references"),
649 suppress_token: None,
650 suppress_file_level: false,
651 lsp: true,
652 docs_category: "dependency",
653 },
654 IssueKindMeta {
655 kind: Some(IssueKind::UnusedDependencyOverride),
656 code: "unused-dependency-override",
657 aliases: &[
658 "unused-dependency-overrides",
659 "unused-override",
660 "unused-overrides",
661 ],
662 label: "Unused Dependency Overrides",
663 config_key: Some("unused-dependency-overrides"),
664 filter_flag: Some("--unused-dependency-overrides"),
665 mcp_issue_type: Some("unused-dependency-overrides"),
666 suppress_token: None,
667 suppress_file_level: false,
668 lsp: true,
669 docs_category: "dependency",
670 },
671 IssueKindMeta {
672 kind: Some(IssueKind::MisconfiguredDependencyOverride),
673 code: "misconfigured-dependency-override",
674 aliases: &[
675 "misconfigured-dependency-overrides",
676 "misconfigured-override",
677 "misconfigured-overrides",
678 ],
679 label: "Misconfigured Dependency Overrides",
680 config_key: Some("misconfigured-dependency-overrides"),
681 filter_flag: Some("--misconfigured-dependency-overrides"),
682 mcp_issue_type: Some("misconfigured-dependency-overrides"),
683 suppress_token: None,
684 suppress_file_level: false,
685 lsp: true,
686 docs_category: "dependency",
687 },
688 IssueKindMeta {
689 kind: Some(IssueKind::SecuritySink),
690 code: "security-sink",
691 aliases: &[],
692 label: "Security Sink Candidates",
693 config_key: Some("security-sink"),
694 filter_flag: None,
695 mcp_issue_type: None,
696 suppress_token: Some("security-sink"),
697 suppress_file_level: false,
698 lsp: true,
699 docs_category: "security",
700 },
701 IssueKindMeta {
702 kind: Some(IssueKind::SecurityClientServerLeak),
703 code: "security-client-server-leak",
704 aliases: &[],
705 label: "Security Client-Server Leaks",
706 config_key: Some("security-client-server-leak"),
707 filter_flag: None,
708 mcp_issue_type: None,
709 suppress_token: Some("security-client-server-leak"),
710 suppress_file_level: true,
711 lsp: true,
712 docs_category: "security",
713 },
714 IssueKindMeta {
715 kind: Some(IssueKind::CoverageGaps),
716 code: "coverage-gaps",
717 aliases: &[],
718 label: "Coverage Gaps",
719 config_key: Some("coverage-gaps"),
720 filter_flag: None,
721 mcp_issue_type: None,
722 suppress_token: Some("coverage-gaps"),
723 suppress_file_level: true,
724 lsp: false,
725 docs_category: "health",
726 },
727 IssueKindMeta {
728 kind: Some(IssueKind::FeatureFlag),
729 code: "feature-flag",
730 aliases: &[],
731 label: "Feature Flags",
732 config_key: Some("feature-flags"),
733 filter_flag: None,
734 mcp_issue_type: None,
735 suppress_token: Some("feature-flag"),
736 suppress_file_level: false,
737 lsp: false,
738 docs_category: "flags",
739 },
740 IssueKindMeta {
741 kind: Some(IssueKind::Complexity),
742 code: "complexity",
743 aliases: &[],
744 label: "Complexity",
745 config_key: None,
746 filter_flag: None,
747 mcp_issue_type: None,
748 suppress_token: Some("complexity"),
749 suppress_file_level: false,
750 lsp: false,
751 docs_category: "health",
752 },
753 IssueKindMeta {
754 kind: Some(IssueKind::PropDrilling),
755 code: "prop-drilling",
756 aliases: &[],
757 label: "Prop Drilling",
758 config_key: Some("prop-drilling"),
759 filter_flag: None,
760 mcp_issue_type: None,
761 suppress_token: Some("prop-drilling"),
762 suppress_file_level: false,
763 lsp: true,
764 docs_category: "source",
765 },
766 IssueKindMeta {
767 kind: Some(IssueKind::ThinWrapper),
768 code: "thin-wrapper",
769 aliases: &["thin-wrappers"],
770 label: "Thin Wrappers",
771 config_key: Some("thin-wrapper"),
772 filter_flag: None,
773 mcp_issue_type: None,
774 suppress_token: Some("thin-wrapper"),
775 suppress_file_level: false,
776 lsp: true,
777 docs_category: "source",
778 },
779 IssueKindMeta {
780 kind: Some(IssueKind::DuplicatePropShape),
781 code: "duplicate-prop-shape",
782 aliases: &["duplicate-prop-shapes"],
783 label: "Duplicate Prop Shapes",
784 config_key: Some("duplicate-prop-shape"),
785 filter_flag: None,
786 mcp_issue_type: None,
787 suppress_token: Some("duplicate-prop-shape"),
788 suppress_file_level: false,
789 lsp: true,
790 docs_category: "source",
791 },
792 IssueKindMeta {
793 kind: Some(IssueKind::CssTokenDrift),
794 code: "css-token-drift",
795 aliases: &[],
796 label: "CSS Token Drift",
797 config_key: Some("css-token-drift"),
798 filter_flag: None,
799 mcp_issue_type: None,
800 suppress_token: Some("css-token-drift"),
801 suppress_file_level: false,
802 lsp: false,
803 docs_category: "health",
804 },
805 IssueKindMeta {
806 kind: Some(IssueKind::CssDuplicateBlock),
807 code: "css-duplicate-block",
808 aliases: &[],
809 label: "CSS Duplicate Block",
810 config_key: Some("css-duplicate-block"),
811 filter_flag: None,
812 mcp_issue_type: None,
813 suppress_token: Some("css-duplicate-block"),
814 suppress_file_level: false,
815 lsp: false,
816 docs_category: "health",
817 },
818 IssueKindMeta {
819 kind: Some(IssueKind::CssSelectorComplexity),
820 code: "css-selector-complexity",
821 aliases: &[],
822 label: "CSS Selector Complexity",
823 config_key: Some("css-selector-complexity"),
824 filter_flag: None,
825 mcp_issue_type: None,
826 suppress_token: Some("css-selector-complexity"),
827 suppress_file_level: false,
828 lsp: false,
829 docs_category: "health",
830 },
831 IssueKindMeta {
832 kind: Some(IssueKind::CssDeadSurface),
833 code: "css-dead-surface",
834 aliases: &[],
835 label: "CSS Dead Surface",
836 config_key: Some("css-dead-surface"),
837 filter_flag: None,
838 mcp_issue_type: None,
839 suppress_token: Some("css-dead-surface"),
840 suppress_file_level: false,
841 lsp: false,
842 docs_category: "health",
843 },
844 IssueKindMeta {
845 kind: Some(IssueKind::CssBrokenReference),
846 code: "css-broken-reference",
847 aliases: &[],
848 label: "CSS Broken Reference",
849 config_key: Some("css-broken-reference"),
850 filter_flag: None,
851 mcp_issue_type: None,
852 suppress_token: Some("css-broken-reference"),
853 suppress_file_level: false,
854 lsp: false,
855 docs_category: "health",
856 },
857];
858
859#[derive(Debug, Clone, Copy, PartialEq, Eq)]
861#[non_exhaustive]
862pub struct IssueResultMeta {
863 pub code: &'static str,
865 pub sarif_description: &'static str,
867 pub meta_description: &'static str,
869 pub meta_docs_path: &'static str,
871 pub meta_name: &'static str,
873 pub summary_label: &'static str,
875 pub docs_anchor: &'static str,
877 pub result_key: &'static str,
879 pub counts_in_total: bool,
881}
882
883#[derive(Debug, Clone, Copy, PartialEq, Eq)]
885pub struct TsAliasMeta {
886 pub name: &'static str,
888 pub parent: &'static str,
890}
891
892#[derive(Debug, Clone, Copy, PartialEq, Eq)]
894pub struct IssueTsAliasMeta {
895 pub code: &'static str,
897 pub alias: TsAliasMeta,
899}
900
901pub const ISSUE_TS_ALIAS_META: &[IssueTsAliasMeta] = &[
903 IssueTsAliasMeta {
904 code: "unused-file",
905 alias: TsAliasMeta {
906 name: "UnusedFile",
907 parent: "UnusedFileFinding",
908 },
909 },
910 IssueTsAliasMeta {
911 code: "unused-export",
912 alias: TsAliasMeta {
913 name: "UnusedExport",
914 parent: "UnusedExportFinding",
915 },
916 },
917 IssueTsAliasMeta {
918 code: "private-type-leak",
919 alias: TsAliasMeta {
920 name: "PrivateTypeLeak",
921 parent: "PrivateTypeLeakFinding",
922 },
923 },
924 IssueTsAliasMeta {
925 code: "deprecated-export-in-use",
926 alias: TsAliasMeta {
927 name: "DeprecatedExportInUse",
928 parent: "DeprecatedExportInUseFinding",
929 },
930 },
931 IssueTsAliasMeta {
932 code: "unused-dependency",
933 alias: TsAliasMeta {
934 name: "UnusedDependency",
935 parent: "UnusedDependencyFinding",
936 },
937 },
938 IssueTsAliasMeta {
939 code: "unused-dev-dependency",
940 alias: TsAliasMeta {
941 name: "UnusedDependency",
942 parent: "UnusedDevDependencyFinding",
943 },
944 },
945 IssueTsAliasMeta {
946 code: "unused-optional-dependency",
947 alias: TsAliasMeta {
948 name: "UnusedDependency",
949 parent: "UnusedOptionalDependencyFinding",
950 },
951 },
952 IssueTsAliasMeta {
953 code: "unused-enum-member",
954 alias: TsAliasMeta {
955 name: "UnusedMember",
956 parent: "UnusedEnumMemberFinding",
957 },
958 },
959 IssueTsAliasMeta {
960 code: "unused-class-member",
961 alias: TsAliasMeta {
962 name: "UnusedMember",
963 parent: "UnusedClassMemberFinding",
964 },
965 },
966 IssueTsAliasMeta {
967 code: "unused-store-member",
968 alias: TsAliasMeta {
969 name: "UnusedMember",
970 parent: "UnusedStoreMemberFinding",
971 },
972 },
973 IssueTsAliasMeta {
974 code: "unresolved-import",
975 alias: TsAliasMeta {
976 name: "UnresolvedImport",
977 parent: "UnresolvedImportFinding",
978 },
979 },
980 IssueTsAliasMeta {
981 code: "unlisted-dependency",
982 alias: TsAliasMeta {
983 name: "UnlistedDependency",
984 parent: "UnlistedDependencyFinding",
985 },
986 },
987 IssueTsAliasMeta {
988 code: "duplicate-export",
989 alias: TsAliasMeta {
990 name: "DuplicateExport",
991 parent: "DuplicateExportFinding",
992 },
993 },
994 IssueTsAliasMeta {
995 code: "type-only-dependency",
996 alias: TsAliasMeta {
997 name: "TypeOnlyDependency",
998 parent: "TypeOnlyDependencyFinding",
999 },
1000 },
1001 IssueTsAliasMeta {
1002 code: "test-only-dependency",
1003 alias: TsAliasMeta {
1004 name: "TestOnlyDependency",
1005 parent: "TestOnlyDependencyFinding",
1006 },
1007 },
1008 IssueTsAliasMeta {
1009 code: "dev-dependency-in-production",
1010 alias: TsAliasMeta {
1011 name: "DevDependencyInProduction",
1012 parent: "DevDependencyInProductionFinding",
1013 },
1014 },
1015 IssueTsAliasMeta {
1016 code: "circular-dependency",
1017 alias: TsAliasMeta {
1018 name: "CircularDependency",
1019 parent: "CircularDependencyFinding",
1020 },
1021 },
1022 IssueTsAliasMeta {
1023 code: "re-export-cycle",
1024 alias: TsAliasMeta {
1025 name: "ReExportCycle",
1026 parent: "ReExportCycleFinding",
1027 },
1028 },
1029 IssueTsAliasMeta {
1030 code: "package-cycle",
1031 alias: TsAliasMeta {
1032 name: "PackageCycle",
1033 parent: "PackageCycleFinding",
1034 },
1035 },
1036 IssueTsAliasMeta {
1037 code: "boundary-violation",
1038 alias: TsAliasMeta {
1039 name: "BoundaryViolation",
1040 parent: "BoundaryViolationFinding",
1041 },
1042 },
1043 IssueTsAliasMeta {
1044 code: "unused-catalog-entry",
1045 alias: TsAliasMeta {
1046 name: "UnusedCatalogEntry",
1047 parent: "UnusedCatalogEntryFinding",
1048 },
1049 },
1050 IssueTsAliasMeta {
1051 code: "empty-catalog-group",
1052 alias: TsAliasMeta {
1053 name: "EmptyCatalogGroup",
1054 parent: "EmptyCatalogGroupFinding",
1055 },
1056 },
1057 IssueTsAliasMeta {
1058 code: "unresolved-catalog-reference",
1059 alias: TsAliasMeta {
1060 name: "UnresolvedCatalogReference",
1061 parent: "UnresolvedCatalogReferenceFinding",
1062 },
1063 },
1064 IssueTsAliasMeta {
1065 code: "unused-dependency-override",
1066 alias: TsAliasMeta {
1067 name: "UnusedDependencyOverride",
1068 parent: "UnusedDependencyOverrideFinding",
1069 },
1070 },
1071 IssueTsAliasMeta {
1072 code: "misconfigured-dependency-override",
1073 alias: TsAliasMeta {
1074 name: "MisconfiguredDependencyOverride",
1075 parent: "MisconfiguredDependencyOverrideFinding",
1076 },
1077 },
1078];
1079
1080pub const ISSUE_RESULT_META: &[IssueResultMeta] = &[
1082 IssueResultMeta {
1083 code: "unused-file",
1084 sarif_description: "File is not reachable from any entry point",
1085 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.",
1086 meta_docs_path: "explanations/dead-code#unused-files",
1087 meta_name: "Unused Files",
1088 summary_label: "Unused files",
1089 docs_anchor: "unused-files",
1090 result_key: "unused_files",
1091 counts_in_total: true,
1092 },
1093 IssueResultMeta {
1094 code: "unused-export",
1095 sarif_description: "Export is never imported",
1096 meta_description: "Named exports that are never imported by any other module in the project, including direct exports and re-exports through barrel files.",
1097 meta_docs_path: "explanations/dead-code#unused-exports",
1098 meta_name: "Unused Exports",
1099 summary_label: "Unused exports",
1100 docs_anchor: "unused-exports",
1101 result_key: "unused_exports",
1102 counts_in_total: true,
1103 },
1104 IssueResultMeta {
1105 code: "unused-type",
1106 sarif_description: "Type export is never imported",
1107 meta_description: "Type-only exports that are never imported. These do not generate runtime code but add maintenance burden.",
1108 meta_docs_path: "explanations/dead-code#unused-types",
1109 meta_name: "Unused Type Exports",
1110 summary_label: "Unused types",
1111 docs_anchor: "unused-types",
1112 result_key: "unused_types",
1113 counts_in_total: true,
1114 },
1115 IssueResultMeta {
1116 code: "private-type-leak",
1117 sarif_description: "Exported signature references a private type",
1118 meta_description: "Exported values or types whose public TypeScript signature references a same-file type declaration that is not exported.",
1119 meta_docs_path: "explanations/dead-code#private-type-leaks",
1120 meta_name: "Private Type Leaks",
1121 summary_label: "Private type leaks",
1122 docs_anchor: "private-type-leaks",
1123 result_key: "private_type_leaks",
1124 counts_in_total: true,
1125 },
1126 IssueResultMeta {
1127 code: "deprecated-export-in-use",
1128 sarif_description: "Export marked @deprecated is still referenced",
1129 meta_description: "Exports whose leading JSDoc carries @deprecated and that still have at least one consumer in a reachable file. Each finding lists the consumer count and a capped consumer sample.",
1130 meta_docs_path: "explanations/dead-code#deprecated-exports-in-use",
1131 meta_name: "Deprecated Exports in Use",
1132 summary_label: "Deprecated exports in use",
1133 docs_anchor: "deprecated-exports-in-use",
1134 result_key: "deprecated_exports_in_use",
1135 counts_in_total: true,
1136 },
1137 IssueResultMeta {
1138 code: "unused-dependency",
1139 sarif_description: "Dependency listed but never imported",
1140 meta_description: "Packages listed in dependencies that are never imported or required by any source file.",
1141 meta_docs_path: "explanations/dead-code#unused-dependencies",
1142 meta_name: "Unused Dependencies",
1143 summary_label: "Unused dependencies",
1144 docs_anchor: "unused-dependencies",
1145 result_key: "unused_dependencies",
1146 counts_in_total: true,
1147 },
1148 IssueResultMeta {
1149 code: "unused-dev-dependency",
1150 sarif_description: "Dev dependency listed but never imported",
1151 meta_description: "Packages listed in devDependencies that are never imported by test files, config files, or scripts.",
1152 meta_docs_path: "explanations/dead-code#unused-devdependencies",
1153 meta_name: "Unused Dev Dependencies",
1154 summary_label: "Unused devDependencies",
1155 docs_anchor: "unused-dependencies",
1156 result_key: "unused_dev_dependencies",
1157 counts_in_total: true,
1158 },
1159 IssueResultMeta {
1160 code: "unused-optional-dependency",
1161 sarif_description: "Optional dependency listed but never imported",
1162 meta_description: "Packages listed in optionalDependencies that are never imported.",
1163 meta_docs_path: "explanations/dead-code#unused-optionaldependencies",
1164 meta_name: "Unused Optional Dependencies",
1165 summary_label: "Unused optionalDependencies",
1166 docs_anchor: "unused-dependencies",
1167 result_key: "unused_optional_dependencies",
1168 counts_in_total: true,
1169 },
1170 IssueResultMeta {
1171 code: "unused-enum-member",
1172 sarif_description: "Enum member is never referenced",
1173 meta_description: "Enum members that are never referenced in the codebase.",
1174 meta_docs_path: "explanations/dead-code#unused-enum-members",
1175 meta_name: "Unused Enum Members",
1176 summary_label: "Unused enum members",
1177 docs_anchor: "unused-enum-members",
1178 result_key: "unused_enum_members",
1179 counts_in_total: true,
1180 },
1181 IssueResultMeta {
1182 code: "unused-class-member",
1183 sarif_description: "Class member is never referenced",
1184 meta_description: "Class methods and properties that are never referenced outside the class.",
1185 meta_docs_path: "explanations/dead-code#unused-class-members",
1186 meta_name: "Unused Class Members",
1187 summary_label: "Unused class members",
1188 docs_anchor: "unused-class-members",
1189 result_key: "unused_class_members",
1190 counts_in_total: true,
1191 },
1192 IssueResultMeta {
1193 code: "unused-store-member",
1194 sarif_description: "Store member is never accessed by any consumer",
1195 meta_description: "Pinia store members declared but never accessed by any consumer project-wide.",
1196 meta_docs_path: "explanations/dead-code#unused-store-members",
1197 meta_name: "Unused Store Members",
1198 summary_label: "Unused store members",
1199 docs_anchor: "unused-store-members",
1200 result_key: "unused_store_members",
1201 counts_in_total: true,
1202 },
1203 IssueResultMeta {
1204 code: "unresolved-import",
1205 sarif_description: "Import could not be resolved",
1206 meta_description: "Import specifiers that could not be resolved to a file on disk.",
1207 meta_docs_path: "explanations/dead-code#unresolved-imports",
1208 meta_name: "Unresolved Imports",
1209 summary_label: "Unresolved imports",
1210 docs_anchor: "unresolved-imports",
1211 result_key: "unresolved_imports",
1212 counts_in_total: true,
1213 },
1214 IssueResultMeta {
1215 code: "unlisted-dependency",
1216 sarif_description: "Dependency used but not in package.json",
1217 meta_description: "Packages imported in source code but not listed in package.json.",
1218 meta_docs_path: "explanations/dead-code#unlisted-dependencies",
1219 meta_name: "Unlisted Dependencies",
1220 summary_label: "Unlisted dependencies",
1221 docs_anchor: "unlisted-dependencies",
1222 result_key: "unlisted_dependencies",
1223 counts_in_total: true,
1224 },
1225 IssueResultMeta {
1226 code: "duplicate-export",
1227 sarif_description: "Export name appears in multiple modules",
1228 meta_description: "The same export name is defined in multiple modules.",
1229 meta_docs_path: "explanations/dead-code#duplicate-exports",
1230 meta_name: "Duplicate Exports",
1231 summary_label: "Duplicate exports",
1232 docs_anchor: "duplicate-exports",
1233 result_key: "duplicate_exports",
1234 counts_in_total: true,
1235 },
1236 IssueResultMeta {
1237 code: "type-only-dependency",
1238 sarif_description: "Production dependency only used via type-only imports",
1239 meta_description: "Production dependencies that are only imported via type-only imports.",
1240 meta_docs_path: "explanations/dead-code#type-only-dependencies",
1241 meta_name: "Type-only Dependencies",
1242 summary_label: "Type-only dependencies",
1243 docs_anchor: "type-only-dependencies",
1244 result_key: "type_only_dependencies",
1245 counts_in_total: true,
1246 },
1247 IssueResultMeta {
1248 code: "test-only-dependency",
1249 sarif_description: "Production dependency only imported by test files",
1250 meta_description: "Production dependencies that are only imported from test files.",
1251 meta_docs_path: "explanations/dead-code#test-only-dependencies",
1252 meta_name: "Test-only Dependencies",
1253 summary_label: "Test-only dependencies",
1254 docs_anchor: "test-only-dependencies",
1255 result_key: "test_only_dependencies",
1256 counts_in_total: true,
1257 },
1258 IssueResultMeta {
1259 code: "dev-dependency-in-production",
1260 sarif_description: "devDependency imported by production code with a runtime import",
1261 meta_description: "devDependencies imported by production source code via a runtime/value import; they should be promoted to dependencies.",
1262 meta_docs_path: "explanations/dead-code#dev-dependencies-in-production",
1263 meta_name: "Dev Dependencies Used in Production",
1264 summary_label: "Dev dependencies used in production",
1265 docs_anchor: "dev-dependencies-in-production",
1266 result_key: "dev_dependencies_in_production",
1267 counts_in_total: true,
1268 },
1269 IssueResultMeta {
1270 code: "circular-dependency",
1271 sarif_description: "Circular dependency chain detected",
1272 meta_description: "A cycle in the module import graph.",
1273 meta_docs_path: "explanations/dead-code#circular-dependencies",
1274 meta_name: "Circular Dependencies",
1275 summary_label: "Circular dependencies",
1276 docs_anchor: "circular-dependencies",
1277 result_key: "circular_dependencies",
1278 counts_in_total: true,
1279 },
1280 IssueResultMeta {
1281 code: "re-export-cycle",
1282 sarif_description: "Two or more barrel files re-export from each other in a loop",
1283 meta_description: "A barrel file re-exports from another barrel that ultimately re-exports back.",
1284 meta_docs_path: "explanations/dead-code#re-export-cycles",
1285 meta_name: "Re-Export Cycles",
1286 summary_label: "Re-export cycles",
1287 docs_anchor: "re-export-cycles",
1288 result_key: "re_export_cycles",
1289 counts_in_total: true,
1290 },
1291 IssueResultMeta {
1292 code: "package-cycle",
1293 sarif_description: "Two or more workspace packages import each other in a loop",
1294 meta_description: "Workspace packages whose resolved imports form a cycle, even when no file-level cycle exists.",
1295 meta_docs_path: "explanations/dead-code#package-cycles",
1296 meta_name: "Package Cycles",
1297 summary_label: "Package cycles",
1298 docs_anchor: "package-cycles",
1299 result_key: "package_cycles",
1300 counts_in_total: true,
1301 },
1302 IssueResultMeta {
1303 code: "boundary-violation",
1304 sarif_description: "Import crosses a configured architecture boundary",
1305 meta_description: "A module imports from a zone that its configured boundary rules do not allow.",
1306 meta_docs_path: "explanations/dead-code#boundary-violations",
1307 meta_name: "Boundary Violations",
1308 summary_label: "Boundary violations",
1309 docs_anchor: "boundary-violations",
1310 result_key: "boundary_violations",
1311 counts_in_total: true,
1312 },
1313 IssueResultMeta {
1314 code: "boundary-coverage",
1315 sarif_description: "Source file matches no configured architecture boundary zone",
1316 meta_description: "A reachable source file is not assigned to any configured boundary zone while boundary coverage is required.",
1317 meta_docs_path: "explanations/dead-code#boundary-violations",
1318 meta_name: "Boundary Coverage",
1319 summary_label: "Boundary coverage",
1320 docs_anchor: "boundary-violations",
1321 result_key: "boundary_coverage_violations",
1322 counts_in_total: true,
1323 },
1324 IssueResultMeta {
1325 code: "boundary-call-violation",
1326 sarif_description: "Zoned file calls a callee its zone forbids",
1327 meta_description: "A file classified into a boundary zone calls a callee matching one of the zone's forbidden call patterns.",
1328 meta_docs_path: "explanations/dead-code#boundary-violations",
1329 meta_name: "Boundary Call Violation",
1330 summary_label: "Boundary calls",
1331 docs_anchor: "boundary-violations",
1332 result_key: "boundary_call_violations",
1333 counts_in_total: true,
1334 },
1335 IssueResultMeta {
1336 code: "policy-violation",
1337 sarif_description: "Banned usage matched a rule-pack rule",
1338 meta_description: "A call site, import, or catalogue-derived effect matched a configured rule pack rule.",
1339 meta_docs_path: "explanations/dead-code#policy-violations",
1340 meta_name: "Policy Violation",
1341 summary_label: "Policy violations",
1342 docs_anchor: "policy-violations",
1343 result_key: "policy_violations",
1344 counts_in_total: true,
1345 },
1346 IssueResultMeta {
1347 code: "invalid-client-export",
1348 sarif_description: "\"use client\" file exports a server-only / route-config name",
1349 meta_description: "A file carrying the use client directive also exports a Next.js server-only or route-segment config name.",
1350 meta_docs_path: "explanations/dead-code#invalid-client-exports",
1351 meta_name: "Invalid client export",
1352 summary_label: "Invalid client exports",
1353 docs_anchor: "invalid-client-exports",
1354 result_key: "invalid_client_exports",
1355 counts_in_total: true,
1356 },
1357 IssueResultMeta {
1358 code: "mixed-client-server-barrel",
1359 sarif_description: "Barrel re-exports both a \"use client\" module and a server-only module",
1360 meta_description: "A barrel file forwards a name from a use client module alongside a name from a server-only module.",
1361 meta_docs_path: "explanations/dead-code#mixed-client-server-barrels",
1362 meta_name: "Mixed client/server barrel",
1363 summary_label: "Mixed client/server barrels",
1364 docs_anchor: "mixed-client-server-barrels",
1365 result_key: "mixed_client_server_barrels",
1366 counts_in_total: true,
1367 },
1368 IssueResultMeta {
1369 code: "misplaced-directive",
1370 sarif_description: "\"use client\" / \"use server\" directive is not in the leading position and is ignored",
1371 meta_description: "A use client or use server directive string appears after a non-directive statement and is ignored.",
1372 meta_docs_path: "explanations/dead-code#misplaced-directives",
1373 meta_name: "Misplaced directive",
1374 summary_label: "Misplaced directives",
1375 docs_anchor: "misplaced-directives",
1376 result_key: "misplaced_directives",
1377 counts_in_total: true,
1378 },
1379 IssueResultMeta {
1380 code: "unprovided-inject",
1381 sarif_description: "inject() / getContext() reads a key that no provide() / setContext() supplies",
1382 meta_description: "A Vue inject or Svelte getContext reads a dependency-injection key that no matching provider supplies.",
1383 meta_docs_path: "explanations/dead-code#unprovided-injects",
1384 meta_name: "Unprovided injects",
1385 summary_label: "Unprovided injects",
1386 docs_anchor: "unprovided-inject",
1387 result_key: "unprovided_injects",
1388 counts_in_total: true,
1389 },
1390 IssueResultMeta {
1391 code: "unrendered-component",
1392 sarif_description: "A Vue / Svelte component is reachable through a barrel but rendered nowhere",
1393 meta_description: "A Vue or Svelte single-file component is reachable through the graph but rendered nowhere in the project.",
1394 meta_docs_path: "explanations/dead-code#unrendered-components",
1395 meta_name: "Unrendered components",
1396 summary_label: "Unrendered components",
1397 docs_anchor: "unrendered-component",
1398 result_key: "unrendered_components",
1399 counts_in_total: true,
1400 },
1401 IssueResultMeta {
1402 code: "unused-component-prop",
1403 sarif_description: "A Vue, Svelte, or React component prop is referenced nowhere in its own component",
1404 meta_description: "A declared Vue, Svelte, React, or Preact component prop is referenced nowhere inside its own component.",
1405 meta_docs_path: "explanations/dead-code#unused-component-props",
1406 meta_name: "Unused component props",
1407 summary_label: "Unused component props",
1408 docs_anchor: "unused-component-prop",
1409 result_key: "unused_component_props",
1410 counts_in_total: true,
1411 },
1412 IssueResultMeta {
1413 code: "unused-component-emit",
1414 sarif_description: "A Vue <script setup> defineEmits event is emitted nowhere in its own component",
1415 meta_description: "A Vue script setup defineEmits event is emitted nowhere in its own component.",
1416 meta_docs_path: "explanations/dead-code#unused-component-emits",
1417 meta_name: "Unused component emits",
1418 summary_label: "Unused component emits",
1419 docs_anchor: "unused-component-emit",
1420 result_key: "unused_component_emits",
1421 counts_in_total: true,
1422 },
1423 IssueResultMeta {
1424 code: "unused-component-input",
1425 sarif_description: "An Angular @Input() / signal input() / model() input is read nowhere in its own component",
1426 meta_description: "An Angular input is read nowhere in its own component.",
1427 meta_docs_path: "explanations/dead-code#unused-component-inputs",
1428 meta_name: "Unused component inputs",
1429 summary_label: "Unused component inputs",
1430 docs_anchor: "unused-component-input",
1431 result_key: "unused_component_inputs",
1432 counts_in_total: true,
1433 },
1434 IssueResultMeta {
1435 code: "unused-component-output",
1436 sarif_description: "An Angular @Output() / signal output() output is emitted nowhere in its own component",
1437 meta_description: "An Angular output is emitted nowhere in its own component.",
1438 meta_docs_path: "explanations/dead-code#unused-component-outputs",
1439 meta_name: "Unused component outputs",
1440 summary_label: "Unused component outputs",
1441 docs_anchor: "unused-component-output",
1442 result_key: "unused_component_outputs",
1443 counts_in_total: true,
1444 },
1445 IssueResultMeta {
1446 code: "unused-svelte-event",
1447 sarif_description: "A Svelte component dispatches a createEventDispatcher event whose name is listened to nowhere in the project",
1448 meta_description: "A Svelte component dispatches a custom event whose name is listened to nowhere in the analyzed project.",
1449 meta_docs_path: "explanations/dead-code#unused-svelte-events",
1450 meta_name: "Unused Svelte events",
1451 summary_label: "Unused Svelte events",
1452 docs_anchor: "unused-svelte-event",
1453 result_key: "unused_svelte_events",
1454 counts_in_total: true,
1455 },
1456 IssueResultMeta {
1457 code: "unused-server-action",
1458 sarif_description: "A Next.js Server Action exported from a \"use server\" file is referenced by no code in the project",
1459 meta_description: "A Next.js Server Action exported from a use server file is referenced by no code in the project.",
1460 meta_docs_path: "explanations/dead-code#unused-server-actions",
1461 meta_name: "Unused server actions",
1462 summary_label: "Unused server actions",
1463 docs_anchor: "unused-server-action",
1464 result_key: "unused_server_actions",
1465 counts_in_total: true,
1466 },
1467 IssueResultMeta {
1468 code: "unused-load-data-key",
1469 sarif_description: "A SvelteKit load() return-object key is read by no consumer",
1470 meta_description: "A SvelteKit load return-object key is read by no route or project-wide consumer.",
1471 meta_docs_path: "explanations/dead-code#unused-load-data-keys",
1472 meta_name: "Unused load data keys",
1473 summary_label: "Unused load data keys",
1474 docs_anchor: "unused-load-data-key",
1475 result_key: "unused_load_data_keys",
1476 counts_in_total: true,
1477 },
1478 IssueResultMeta {
1479 code: "route-collision",
1480 sarif_description: "Two or more Next.js App Router route files resolve to the same URL",
1481 meta_description: "Two or more Next.js App Router route files resolve to the same URL within one app root.",
1482 meta_docs_path: "explanations/dead-code#route-collisions",
1483 meta_name: "Route collision",
1484 summary_label: "Route collisions",
1485 docs_anchor: "route-collisions",
1486 result_key: "route_collisions",
1487 counts_in_total: true,
1488 },
1489 IssueResultMeta {
1490 code: "dynamic-segment-name-conflict",
1491 sarif_description: "Sibling Next.js dynamic route segments use different slug names at the same position",
1492 meta_description: "Sibling Next.js dynamic route segments use different slug names at the same position.",
1493 meta_docs_path: "explanations/dead-code#dynamic-segment-name-conflicts",
1494 meta_name: "Dynamic segment name conflict",
1495 summary_label: "Dynamic segment conflicts",
1496 docs_anchor: "dynamic-segment-name-conflicts",
1497 result_key: "dynamic_segment_name_conflicts",
1498 counts_in_total: true,
1499 },
1500 IssueResultMeta {
1501 code: "stale-suppression",
1502 sarif_description: "Suppression comment or tag no longer matches any issue",
1503 meta_description: "A fallow suppression comment or tag no longer matches any active issue.",
1504 meta_docs_path: "explanations/dead-code#stale-suppressions",
1505 meta_name: "Stale Suppressions",
1506 summary_label: "Stale suppressions",
1507 docs_anchor: "stale-suppressions",
1508 result_key: "stale_suppressions",
1509 counts_in_total: true,
1510 },
1511 IssueResultMeta {
1512 code: "unused-catalog-entry",
1513 sarif_description: "Catalog entry not referenced by any workspace package",
1514 meta_description: "A package manager catalog entry is not referenced by any workspace package.json.",
1515 meta_docs_path: "explanations/dead-code#unused-catalog-entries",
1516 meta_name: "Unused catalog entry",
1517 summary_label: "Unused catalog entries",
1518 docs_anchor: "unused-catalog-entries",
1519 result_key: "unused_catalog_entries",
1520 counts_in_total: true,
1521 },
1522 IssueResultMeta {
1523 code: "empty-catalog-group",
1524 sarif_description: "Named catalog group has no entries",
1525 meta_description: "A named package manager catalog group has no package entries.",
1526 meta_docs_path: "explanations/dead-code#empty-catalog-groups",
1527 meta_name: "Empty catalog group",
1528 summary_label: "Empty catalog groups",
1529 docs_anchor: "empty-catalog-groups",
1530 result_key: "empty_catalog_groups",
1531 counts_in_total: true,
1532 },
1533 IssueResultMeta {
1534 code: "unresolved-catalog-reference",
1535 sarif_description: "package.json references a catalog that does not declare the package",
1536 meta_description: "A workspace package.json uses a catalog protocol reference that no catalog declares.",
1537 meta_docs_path: "explanations/dead-code#unresolved-catalog-references",
1538 meta_name: "Unresolved catalog reference",
1539 summary_label: "Unresolved catalog references",
1540 docs_anchor: "unresolved-catalog-references",
1541 result_key: "unresolved_catalog_references",
1542 counts_in_total: true,
1543 },
1544 IssueResultMeta {
1545 code: "unused-dependency-override",
1546 sarif_description: "Package-manager override target is not declared or resolved",
1547 meta_description: "A dependency override targets a package not declared by any workspace package and not present in the active readable lockfile.",
1548 meta_docs_path: "explanations/dead-code#unused-dependency-overrides",
1549 meta_name: "Unused dependency override",
1550 summary_label: "Unused dependency overrides",
1551 docs_anchor: "unused-dependency-overrides",
1552 result_key: "unused_dependency_overrides",
1553 counts_in_total: true,
1554 },
1555 IssueResultMeta {
1556 code: "misconfigured-dependency-override",
1557 sarif_description: "Package-manager override has an unparsable key or value",
1558 meta_description: "A dependency override key or value does not parse according to its package manager's grammar.",
1559 meta_docs_path: "explanations/dead-code#misconfigured-dependency-overrides",
1560 meta_name: "Misconfigured dependency override",
1561 summary_label: "Misconfigured dependency overrides",
1562 docs_anchor: "misconfigured-dependency-overrides",
1563 result_key: "misconfigured_dependency_overrides",
1564 counts_in_total: true,
1565 },
1566 IssueResultMeta {
1567 code: "prop-drilling",
1568 sarif_description: "A React/Preact prop is forwarded unchanged through 3+ pass-through components to a distant consumer",
1569 meta_description: "A React or Preact prop is forwarded unchanged through multiple pass-through components to a distant consumer.",
1570 meta_docs_path: "explanations/dead-code#prop-drilling",
1571 meta_name: "Prop drilling",
1572 summary_label: "Prop drilling",
1573 docs_anchor: "prop-drilling",
1574 result_key: "prop_drilling_chains",
1575 counts_in_total: false,
1576 },
1577 IssueResultMeta {
1578 code: "thin-wrapper",
1579 sarif_description: "A React/Preact component whose whole body is a single spread-forwarded child render (a candidate for inlining)",
1580 meta_description: "A React or Preact component is structural indirection around a single spread-forwarded child render.",
1581 meta_docs_path: "explanations/dead-code#thin-wrapper",
1582 meta_name: "Thin wrapper",
1583 summary_label: "Thin wrappers",
1584 docs_anchor: "thin-wrapper",
1585 result_key: "thin_wrappers",
1586 counts_in_total: false,
1587 },
1588 IssueResultMeta {
1589 code: "duplicate-prop-shape",
1590 sarif_description: "Three or more React/Preact components across two or more files declare an identical prop-name set (a missing shared Props type)",
1591 meta_description: "Multiple React or Preact components declare an identical significant prop-name set.",
1592 meta_docs_path: "explanations/dead-code#duplicate-prop-shape",
1593 meta_name: "Duplicate prop shape",
1594 summary_label: "Duplicate prop shapes",
1595 docs_anchor: "duplicate-prop-shape",
1596 result_key: "duplicate_prop_shapes",
1597 counts_in_total: false,
1598 },
1599];
1600
1601pub static KNOWN_ISSUE_KIND_NAMES: LazyLock<Vec<&'static str>> =
1603 LazyLock::new(known_issue_kind_names_from_meta);
1604
1605pub static DEAD_CODE_FILTER_FLAGS: LazyLock<Vec<&'static str>> =
1607 LazyLock::new(dead_code_filter_flags_from_meta);
1608
1609pub static MCP_ISSUE_TYPE_FLAGS: LazyLock<Vec<(&'static str, &'static str)>> =
1611 LazyLock::new(mcp_issue_type_flags_from_meta);
1612
1613pub static CODECLIMATE_RESULT_CODES: LazyLock<Vec<&'static str>> =
1615 LazyLock::new(codeclimate_result_codes_from_meta);
1616
1617fn known_issue_kind_names_from_meta() -> Vec<&'static str> {
1618 let mut names = Vec::new();
1619 for meta in ISSUE_KIND_META.iter().filter(|meta| meta.kind.is_some()) {
1620 push_unique(&mut names, meta.code);
1621 for alias in meta.aliases {
1622 push_unique(&mut names, *alias);
1623 }
1624 }
1625 names
1626}
1627
1628fn dead_code_filter_flags_from_meta() -> Vec<&'static str> {
1629 let mut flags = Vec::new();
1630 for meta in ISSUE_KIND_META {
1631 if let Some(flag) = meta.filter_flag {
1632 push_unique(&mut flags, flag);
1633 }
1634 }
1635 flags
1636}
1637
1638fn mcp_issue_type_flags_from_meta() -> Vec<(&'static str, &'static str)> {
1639 ISSUE_KIND_META
1640 .iter()
1641 .filter_map(|meta| meta.mcp_pair())
1642 .collect()
1643}
1644
1645fn codeclimate_result_codes_from_meta() -> Vec<&'static str> {
1646 ISSUE_RESULT_META
1647 .iter()
1648 .filter(|meta| meta.counts_in_total)
1649 .map(|meta| meta.code)
1650 .collect()
1651}
1652
1653fn push_unique<T: Copy + PartialEq>(items: &mut Vec<T>, item: T) {
1654 if !items.contains(&item) {
1655 items.push(item);
1656 }
1657}
1658
1659#[must_use]
1661pub fn issue_meta_by_code(code: &str) -> Option<&'static IssueKindMeta> {
1662 ISSUE_KIND_META.iter().find(|meta| meta.code == code)
1663}
1664
1665#[must_use]
1667pub fn issue_meta_for_token(token: &str) -> Option<&'static IssueKindMeta> {
1668 ISSUE_KIND_META
1669 .iter()
1670 .find(|meta| meta.code == token || meta.aliases.contains(&token))
1671}
1672
1673#[must_use]
1676pub fn issue_meta_for_contract_token(token: &str) -> Option<&'static IssueKindMeta> {
1677 let normalized = token.trim().trim_start_matches("--").replace('_', "-");
1678 ISSUE_KIND_META
1679 .iter()
1680 .find(|meta| issue_meta_matches_contract_token(meta, &normalized))
1681}
1682
1683#[must_use]
1685pub fn issue_meta_matches_contract_token(meta: &IssueKindMeta, token: &str) -> bool {
1686 let normalized = token.trim().trim_start_matches("--").replace('_', "-");
1687 meta.code == normalized
1688 || meta.aliases.contains(&normalized.as_str())
1689 || meta.config_key == Some(normalized.as_str())
1690 || meta.mcp_issue_type == Some(normalized.as_str())
1691 || meta.suppress_token == Some(normalized.as_str())
1692 || meta.filter_flag.map(|flag| flag.trim_start_matches("--")) == Some(normalized.as_str())
1693}
1694
1695#[must_use]
1697pub fn issue_meta_by_kind(kind: IssueKind) -> Option<&'static IssueKindMeta> {
1698 ISSUE_KIND_META.iter().find(|meta| meta.kind == Some(kind))
1699}
1700
1701#[must_use]
1703pub fn issue_result_meta_by_code(code: &str) -> Option<&'static IssueResultMeta> {
1704 ISSUE_RESULT_META.iter().find(|meta| meta.code == code)
1705}
1706
1707#[must_use]
1709pub fn issue_sarif_rule_ids(code: &str) -> Vec<String> {
1710 let mut ids = vec![format!("fallow/{code}")];
1711 if code == "stale-suppression" {
1712 ids.push("fallow/missing-suppression-reason".to_string());
1713 }
1714 ids
1715}
1716
1717#[must_use]
1719pub fn issue_sarif_rule_description(rule_id: &str) -> Option<&'static str> {
1720 let code = rule_id.strip_prefix("fallow/")?;
1721 if code == "missing-suppression-reason" {
1722 return Some("Suppression comment omits a required reason");
1723 }
1724 issue_result_meta_by_code(code).map(|meta| meta.sarif_description)
1725}
1726
1727#[must_use]
1729pub fn issue_codeclimate_check_names(code: &str) -> Vec<String> {
1730 if !CODECLIMATE_RESULT_CODES.contains(&code) {
1731 return Vec::new();
1732 }
1733 issue_sarif_rule_ids(code)
1734}
1735
1736#[must_use]
1739pub fn issue_docs_anchor(code: &str) -> Option<&'static str> {
1740 issue_result_meta_by_code(code).map(|meta| meta.docs_anchor)
1741}
1742
1743#[must_use]
1745pub fn issue_ts_alias(code: &str) -> Option<TsAliasMeta> {
1746 ISSUE_TS_ALIAS_META
1747 .iter()
1748 .find(|meta| meta.code == code)
1749 .map(|meta| meta.alias)
1750}
1751
1752pub fn diagnostic_issue_metas() -> impl Iterator<Item = &'static IssueKindMeta> {
1754 ISSUE_KIND_META.iter().filter(|meta| meta.lsp)
1755}
1756
1757pub fn result_issue_metas() -> impl Iterator<Item = &'static IssueResultMeta> {
1759 ISSUE_RESULT_META.iter()
1760}
1761
1762pub fn counted_result_issue_metas() -> impl Iterator<Item = &'static IssueResultMeta> {
1764 result_issue_metas().filter(|meta| meta.counts_in_total)
1765}
1766
1767pub const FIXABLE_ISSUE_CODES: &[&str] = &[
1771 "unused-export",
1772 "unused-enum-member",
1773 "unused-dependency",
1774 "unused-dev-dependency",
1775 "unused-optional-dependency",
1776 "unused-catalog-entry",
1777];
1778
1779#[must_use]
1781pub fn issue_is_fixable(code: &str) -> bool {
1782 FIXABLE_ISSUE_CODES.contains(&code)
1783}
1784
1785#[cfg(test)]
1786mod tests {
1787 use std::collections::BTreeSet;
1788
1789 use crate::results::TOTAL_ISSUE_RESULT_KEYS;
1790
1791 use super::*;
1792
1793 #[test]
1794 fn fixable_codes_are_canonical_issue_codes() {
1795 for code in FIXABLE_ISSUE_CODES {
1796 assert!(
1797 issue_meta_by_code(code).is_some(),
1798 "fixable code {code} is not a canonical ISSUE_KIND_META code"
1799 );
1800 }
1801 assert!(issue_is_fixable("unused-export"));
1802 assert!(!issue_is_fixable("unused-file"));
1803 }
1804
1805 #[test]
1806 fn known_names_round_trip_through_metadata() {
1807 for name in KNOWN_ISSUE_KIND_NAMES.iter() {
1808 let meta = issue_meta_for_token(name)
1809 .unwrap_or_else(|| panic!("known issue name {name} missing metadata row"));
1810 assert!(
1811 meta.kind.is_some(),
1812 "known issue name {name} maps to non-IssueKind metadata"
1813 );
1814 }
1815 }
1816
1817 #[test]
1818 fn issue_kind_variants_have_metadata() {
1819 for &kind in IssueKind::ALL {
1820 assert!(
1821 issue_meta_by_kind(kind).is_some(),
1822 "IssueKind {kind:?} has no metadata row"
1823 );
1824 }
1825 }
1826
1827 #[test]
1828 fn dead_code_filter_flags_match_metadata() {
1829 let from_constants: BTreeSet<&str> = DEAD_CODE_FILTER_FLAGS.iter().copied().collect();
1830 let from_meta: BTreeSet<&str> = ISSUE_KIND_META
1831 .iter()
1832 .filter_map(|meta| meta.filter_flag)
1833 .collect();
1834 assert_eq!(from_constants, from_meta);
1835 }
1836
1837 #[test]
1838 fn mcp_issue_type_flags_match_metadata() {
1839 let from_constants: BTreeSet<(&str, &str)> = MCP_ISSUE_TYPE_FLAGS.iter().copied().collect();
1840 let from_meta: BTreeSet<(&str, &str)> = ISSUE_KIND_META
1841 .iter()
1842 .filter_map(|meta| meta.mcp_pair())
1843 .collect();
1844 assert_eq!(from_constants, from_meta);
1845 }
1846
1847 #[test]
1848 fn lsp_exposes_only_actual_diagnostic_codes() {
1849 let codes: BTreeSet<&str> = diagnostic_issue_metas().map(|meta| meta.code).collect();
1850 assert!(codes.contains("boundary-violation"));
1851 assert!(!codes.contains("boundary-coverage"));
1852 assert!(!codes.contains("boundary-call-violation"));
1853 }
1854
1855 #[test]
1856 fn issue_codes_are_unique() {
1857 let mut seen = BTreeSet::new();
1858 for meta in ISSUE_KIND_META {
1859 assert!(seen.insert(meta.code), "duplicate issue code {}", meta.code);
1860 }
1861 }
1862
1863 #[test]
1864 fn contract_tokens_resolve_through_metadata() {
1865 for meta in ISSUE_KIND_META {
1866 assert_eq!(
1867 issue_meta_for_contract_token(meta.code).map(|resolved| resolved.code),
1868 Some(meta.code),
1869 "canonical issue code {} should resolve through contract token lookup",
1870 meta.code
1871 );
1872 for token in meta.aliases {
1873 assert!(
1874 issue_meta_matches_contract_token(meta, token),
1875 "alias {token} should match {}",
1876 meta.code
1877 );
1878 }
1879 for token in [
1880 meta.config_key,
1881 meta.mcp_issue_type,
1882 meta.suppress_token,
1883 meta.filter_flag,
1884 ]
1885 .into_iter()
1886 .flatten()
1887 {
1888 assert!(
1889 issue_meta_for_contract_token(token).is_some(),
1890 "contract token {token} should resolve through metadata"
1891 );
1892 assert!(
1893 issue_meta_matches_contract_token(meta, token),
1894 "contract token {token} should match {}",
1895 meta.code
1896 );
1897 }
1898 }
1899 }
1900
1901 #[test]
1902 fn sarif_rule_descriptions_cover_result_metadata() {
1903 for meta in result_issue_metas() {
1904 for rule_id in issue_sarif_rule_ids(meta.code) {
1905 assert!(
1906 issue_sarif_rule_description(&rule_id).is_some(),
1907 "SARIF rule {rule_id} for {} needs a central description",
1908 meta.code
1909 );
1910 }
1911 }
1912 }
1913
1914 #[test]
1915 fn result_meta_codes_have_issue_metadata() {
1916 for meta in ISSUE_RESULT_META {
1917 assert!(
1918 issue_meta_by_code(meta.code).is_some(),
1919 "result metadata code {} has no issue metadata row",
1920 meta.code
1921 );
1922 }
1923 }
1924
1925 #[test]
1926 fn result_meta_codes_have_docs_anchors() {
1927 for meta in ISSUE_RESULT_META {
1928 let issue = issue_meta_by_code(meta.code)
1929 .unwrap_or_else(|| panic!("result metadata code {} has no issue row", meta.code));
1930 assert_eq!(
1931 issue.docs_anchor(),
1932 Some(meta.docs_anchor),
1933 "result metadata code {} has mismatched docs anchor",
1934 meta.code
1935 );
1936 }
1937 }
1938
1939 #[test]
1940 fn result_meta_codes_have_summary_labels() {
1941 for meta in ISSUE_RESULT_META {
1942 assert!(
1943 !meta.summary_label.is_empty(),
1944 "result metadata code {} has no summary label",
1945 meta.code
1946 );
1947 }
1948 }
1949
1950 #[test]
1951 fn result_meta_codes_have_meta_names() {
1952 for meta in ISSUE_RESULT_META {
1953 assert!(
1954 !meta.meta_name.is_empty(),
1955 "result metadata code {} has no meta name",
1956 meta.code
1957 );
1958 }
1959 }
1960
1961 #[test]
1962 fn result_meta_codes_have_meta_docs_paths() {
1963 for meta in ISSUE_RESULT_META {
1964 assert!(
1965 meta.meta_docs_path.starts_with("explanations/dead-code#"),
1966 "result metadata code {} has invalid meta docs path",
1967 meta.code
1968 );
1969 }
1970 }
1971
1972 #[test]
1973 fn result_meta_codes_have_meta_descriptions() {
1974 for meta in ISSUE_RESULT_META {
1975 assert!(
1976 !meta.meta_description.is_empty(),
1977 "result metadata code {} has no meta description",
1978 meta.code
1979 );
1980 }
1981 }
1982
1983 #[test]
1984 fn ci_format_ids_are_prefixed_and_known() {
1985 let result_codes: BTreeSet<&str> = result_issue_metas().map(|meta| meta.code).collect();
1986 let codeclimate_codes: BTreeSet<&str> = CODECLIMATE_RESULT_CODES.iter().copied().collect();
1987 assert!(codeclimate_codes.is_subset(&result_codes));
1988
1989 for meta in result_issue_metas() {
1990 let issue = issue_meta_by_code(meta.code)
1991 .unwrap_or_else(|| panic!("result metadata code {} has no issue row", meta.code));
1992 assert!(issue.has_result_contract());
1993 let sarif_ids = issue.sarif_rule_ids();
1994 assert!(sarif_ids.contains(&format!("fallow/{}", meta.code)));
1995 for rule_id in sarif_ids {
1996 assert!(
1997 rule_id.starts_with("fallow/"),
1998 "result metadata code {} has unprefixed SARIF rule id {rule_id}",
1999 meta.code
2000 );
2001 }
2002 for check_name in issue.codeclimate_check_names() {
2003 assert!(
2004 check_name.starts_with("fallow/"),
2005 "result metadata code {} has unprefixed CodeClimate check name {check_name}",
2006 meta.code
2007 );
2008 }
2009 }
2010 }
2011
2012 #[test]
2013 fn ts_alias_policy_is_explicit() {
2014 let aliases: BTreeSet<(&str, &str)> = ISSUE_TS_ALIAS_META
2015 .iter()
2016 .map(|meta| (meta.alias.name, meta.alias.parent))
2017 .collect();
2018
2019 assert_eq!(
2020 BTreeSet::from([
2021 ("BoundaryViolation", "BoundaryViolationFinding"),
2022 ("CircularDependency", "CircularDependencyFinding"),
2023 ("DeprecatedExportInUse", "DeprecatedExportInUseFinding"),
2024 (
2025 "DevDependencyInProduction",
2026 "DevDependencyInProductionFinding",
2027 ),
2028 ("DuplicateExport", "DuplicateExportFinding"),
2029 ("EmptyCatalogGroup", "EmptyCatalogGroupFinding"),
2030 (
2031 "MisconfiguredDependencyOverride",
2032 "MisconfiguredDependencyOverrideFinding",
2033 ),
2034 ("PrivateTypeLeak", "PrivateTypeLeakFinding"),
2035 ("PackageCycle", "PackageCycleFinding"),
2036 ("ReExportCycle", "ReExportCycleFinding"),
2037 ("TestOnlyDependency", "TestOnlyDependencyFinding"),
2038 ("TypeOnlyDependency", "TypeOnlyDependencyFinding"),
2039 (
2040 "UnresolvedCatalogReference",
2041 "UnresolvedCatalogReferenceFinding",
2042 ),
2043 ("UnresolvedImport", "UnresolvedImportFinding"),
2044 ("UnlistedDependency", "UnlistedDependencyFinding"),
2045 ("UnusedCatalogEntry", "UnusedCatalogEntryFinding"),
2046 ("UnusedDependency", "UnusedDependencyFinding"),
2047 ("UnusedDependency", "UnusedDevDependencyFinding"),
2048 ("UnusedDependency", "UnusedOptionalDependencyFinding"),
2049 (
2050 "UnusedDependencyOverride",
2051 "UnusedDependencyOverrideFinding",
2052 ),
2053 ("UnusedExport", "UnusedExportFinding"),
2054 ("UnusedFile", "UnusedFileFinding"),
2055 ("UnusedMember", "UnusedClassMemberFinding"),
2056 ("UnusedMember", "UnusedEnumMemberFinding"),
2057 ("UnusedMember", "UnusedStoreMemberFinding"),
2058 ]),
2059 aliases
2060 );
2061 }
2062
2063 #[test]
2064 fn ts_alias_registry_rows_match_result_metadata() {
2065 let result_codes: BTreeSet<&str> = result_issue_metas().map(|meta| meta.code).collect();
2066 let mut seen_codes = BTreeSet::new();
2067 for meta in ISSUE_TS_ALIAS_META {
2068 assert!(
2069 seen_codes.insert(meta.code),
2070 "duplicate TypeScript alias row for {}",
2071 meta.code
2072 );
2073 assert!(
2074 result_codes.contains(meta.code),
2075 "TypeScript alias row {} has no result metadata",
2076 meta.code
2077 );
2078 assert!(
2079 meta.alias.parent.ends_with("Finding"),
2080 "TypeScript alias row {} must point at a generated Finding wrapper",
2081 meta.code
2082 );
2083 assert_eq!(
2084 Some(meta.alias),
2085 issue_meta_by_code(meta.code).and_then(|issue| issue.ts_alias()),
2086 "IssueKindMeta helper must resolve TypeScript alias row {} through the registry",
2087 meta.code
2088 );
2089 }
2090 }
2091
2092 #[test]
2093 fn result_keys_are_unique() {
2094 let mut seen = BTreeSet::new();
2095 for meta in ISSUE_RESULT_META {
2096 assert!(
2097 seen.insert(meta.result_key),
2098 "duplicate result key {}",
2099 meta.result_key
2100 );
2101 }
2102 }
2103
2104 #[test]
2105 fn counted_result_keys_match_total_issue_fields() {
2106 let from_total: BTreeSet<&str> = TOTAL_ISSUE_RESULT_KEYS.iter().copied().collect();
2107 let from_meta: BTreeSet<&str> = counted_result_issue_metas()
2108 .map(|meta| meta.result_key)
2109 .collect();
2110 assert_eq!(from_total, from_meta);
2111 }
2112
2113 #[test]
2114 fn advisory_result_keys_are_explicitly_excluded_from_total() {
2115 let expected = BTreeSet::from([
2116 "duplicate_prop_shapes",
2117 "prop_drilling_chains",
2118 "thin_wrappers",
2119 ]);
2120 let from_meta: BTreeSet<&str> = result_issue_metas()
2121 .filter(|meta| !meta.counts_in_total)
2122 .map(|meta| meta.result_key)
2123 .collect();
2124 assert_eq!(expected, from_meta);
2125 }
2126}