ass_core/analysis/linting/rules/builtin.rs
1//! Built-in lint rule registry aggregating all rule implementations.
2//!
3//! Houses the [`BuiltinRules`] facade used to enumerate, filter, and look up
4//! the complete set of built-in linting rules.
5
6use alloc::{boxed::Box, vec, vec::Vec};
7
8use super::{
9 AccessibilityRule, EncodingRule, InvalidColorRule, InvalidTagRule, MissingStyleRule,
10 NegativeDurationRule, PerformanceRule, TimingOverlapRule,
11};
12use crate::analysis::linting::{IssueCategory, LintRule};
13
14/// Built-in lint rules registry
15///
16/// Provides access to all built-in rules that check for common issues
17/// in ASS subtitle scripts. Rules are organized by category and can be
18/// used individually or as a complete set.
19///
20/// # Performance
21///
22/// All rules are designed for efficient execution with minimal memory
23/// overhead. Most rules have O(n) or O(n log n) time complexity.
24///
25/// # Rule List
26///
27/// - `TimingOverlapRule`: Detects overlapping dialogue events
28/// - `NegativeDurationRule`: Finds events with invalid durations
29/// - `InvalidColorRule`: Validates color formats in styles and tags
30/// - `MissingStyleRule`: Checks for undefined style references
31/// - `InvalidTagRule`: Detects malformed override tags
32/// - `PerformanceRule`: Identifies performance-impacting patterns
33/// - `EncodingRule`: Validates text encoding and character usage
34/// - `AccessibilityRule`: Ensures readability and compatibility
35pub struct BuiltinRules;
36
37impl BuiltinRules {
38 /// Get all built-in linting rules
39 ///
40 /// Returns a vector of all available built-in rules ready for use.
41 /// Rules are returned in their default configuration with standard
42 /// severity levels and categories.
43 ///
44 /// # Example
45 ///
46 /// ```rust
47 /// use ass_core::analysis::linting::rules::BuiltinRules;
48 ///
49 /// let rules = BuiltinRules::all_rules();
50 /// assert_eq!(rules.len(), 8); // All built-in rules
51 /// ```
52 #[must_use]
53 pub fn all_rules() -> Vec<Box<dyn LintRule>> {
54 vec![
55 Box::new(TimingOverlapRule),
56 Box::new(NegativeDurationRule),
57 Box::new(InvalidColorRule),
58 Box::new(MissingStyleRule),
59 Box::new(InvalidTagRule),
60 Box::new(PerformanceRule),
61 Box::new(EncodingRule),
62 Box::new(AccessibilityRule),
63 ]
64 }
65
66 /// Get rules by category
67 ///
68 /// Returns only rules that check issues in the specified category.
69 /// Useful for focused linting or when only certain types of issues
70 /// need to be checked.
71 ///
72 /// # Arguments
73 ///
74 /// * `category` - The issue category to filter by
75 ///
76 /// # Example
77 ///
78 /// ```rust
79 /// use ass_core::analysis::linting::{IssueCategory, rules::BuiltinRules};
80 ///
81 /// let timing_rules = BuiltinRules::rules_for_category(IssueCategory::Timing);
82 /// // Returns timing-related rules only
83 /// ```
84 #[must_use]
85 pub fn rules_for_category(category: IssueCategory) -> Vec<Box<dyn LintRule>> {
86 Self::all_rules()
87 .into_iter()
88 .filter(|rule| rule.category() == category)
89 .collect()
90 }
91
92 /// Get rule by ID
93 ///
94 /// Returns the rule with the specified ID, or None if no such rule exists.
95 /// Rule IDs are unique identifiers used for configuration and reporting.
96 ///
97 /// # Arguments
98 ///
99 /// * `id` - The rule ID to search for
100 ///
101 /// # Example
102 ///
103 /// ```rust
104 /// use ass_core::analysis::linting::rules::BuiltinRules;
105 ///
106 /// let rule = BuiltinRules::rule_by_id("timing-overlap");
107 /// assert!(rule.is_some());
108 /// assert_eq!(rule.unwrap().id(), "timing-overlap");
109 /// ```
110 #[must_use]
111 pub fn rule_by_id(id: &str) -> Option<Box<dyn LintRule>> {
112 Self::all_rules().into_iter().find(|rule| rule.id() == id)
113 }
114
115 /// Get all rule IDs
116 ///
117 /// Returns a vector of all available rule IDs for configuration
118 /// and reporting purposes.
119 ///
120 /// # Example
121 ///
122 /// ```rust
123 /// use ass_core::analysis::linting::rules::BuiltinRules;
124 ///
125 /// let ids = BuiltinRules::all_rule_ids();
126 /// assert!(ids.contains(&"timing-overlap"));
127 /// assert!(ids.contains(&"negative-duration"));
128 /// ```
129 #[must_use]
130 pub fn all_rule_ids() -> Vec<&'static str> {
131 Self::all_rules().iter().map(|rule| rule.id()).collect()
132 }
133}