Skip to main content

driven/parser/
unified.rs

1//! Unified rule representation
2
3use crate::format::RuleCategory;
4
5/// Parsed rule from any source
6#[derive(Debug, Clone)]
7pub struct ParsedRule {
8    /// Source file
9    pub source: Option<std::path::PathBuf>,
10    /// Line number in source
11    pub line: Option<usize>,
12    /// The unified rule
13    pub rule: UnifiedRule,
14}
15
16/// Workflow step data
17#[derive(Debug, Clone)]
18pub struct WorkflowStepData {
19    /// Step name
20    pub name: String,
21    /// Step description
22    pub description: String,
23    /// Condition for this step (optional)
24    pub condition: Option<String>,
25    /// Actions to perform
26    pub actions: Vec<String>,
27}
28
29/// Unified representation of AI coding rules
30#[derive(Debug, Clone)]
31pub enum UnifiedRule {
32    /// AI persona definition
33    Persona {
34        /// Persona name
35        name: String,
36        /// Role description
37        role: String,
38        /// Identity/expertise description
39        identity: Option<String>,
40        /// Communication style
41        style: Option<String>,
42        /// Personality traits
43        traits: Vec<String>,
44        /// Core principles
45        principles: Vec<String>,
46    },
47
48    /// Coding standard rule
49    Standard {
50        /// Category of the rule
51        category: RuleCategory,
52        /// Priority (0 = highest)
53        priority: u8,
54        /// Description of the rule
55        description: String,
56        /// Example pattern (optional)
57        pattern: Option<String>,
58    },
59
60    /// Project context
61    Context {
62        /// Include patterns
63        includes: Vec<String>,
64        /// Exclude patterns
65        excludes: Vec<String>,
66        /// Focus areas
67        focus: Vec<String>,
68    },
69
70    /// Development workflow
71    Workflow {
72        /// Workflow name
73        name: String,
74        /// Workflow steps
75        steps: Vec<WorkflowStepData>,
76    },
77
78    /// Raw content (unparsed)
79    Raw {
80        /// Raw content
81        content: String,
82    },
83}
84
85impl UnifiedRule {
86    /// Create a persona rule
87    pub fn persona(name: impl Into<String>, role: impl Into<String>) -> Self {
88        Self::Persona {
89            name: name.into(),
90            role: role.into(),
91            identity: None,
92            style: None,
93            traits: Vec::new(),
94            principles: Vec::new(),
95        }
96    }
97
98    /// Create a standard rule
99    pub fn standard(category: RuleCategory, priority: u8, description: impl Into<String>) -> Self {
100        Self::Standard {
101            category,
102            priority,
103            description: description.into(),
104            pattern: None,
105        }
106    }
107
108    /// Create a context rule
109    pub fn context(includes: Vec<String>, excludes: Vec<String>) -> Self {
110        Self::Context {
111            includes,
112            excludes,
113            focus: Vec::new(),
114        }
115    }
116
117    /// Create a workflow rule
118    pub fn workflow(name: impl Into<String>, steps: Vec<WorkflowStepData>) -> Self {
119        Self::Workflow {
120            name: name.into(),
121            steps,
122        }
123    }
124
125    /// Create a raw content rule
126    pub fn raw(content: impl Into<String>) -> Self {
127        Self::Raw {
128            content: content.into(),
129        }
130    }
131
132    /// Get the type name of this rule
133    pub fn type_name(&self) -> &'static str {
134        match self {
135            UnifiedRule::Persona { .. } => "persona",
136            UnifiedRule::Standard { .. } => "standard",
137            UnifiedRule::Context { .. } => "context",
138            UnifiedRule::Workflow { .. } => "workflow",
139            UnifiedRule::Raw { .. } => "raw",
140        }
141    }
142}
143
144impl std::fmt::Display for UnifiedRule {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        match self {
147            UnifiedRule::Persona { name, role, .. } => {
148                write!(f, "Persona[{}]: {}", name, role)
149            }
150            UnifiedRule::Standard {
151                category,
152                description,
153                ..
154            } => {
155                write!(f, "Standard[{:?}]: {}", category, description)
156            }
157            UnifiedRule::Context { includes, .. } => {
158                write!(f, "Context: {} patterns", includes.len())
159            }
160            UnifiedRule::Workflow { name, steps } => {
161                write!(f, "Workflow[{}]: {} steps", name, steps.len())
162            }
163            UnifiedRule::Raw { content } => {
164                let preview: String = content.chars().take(50).collect();
165                write!(f, "Raw: {}...", preview)
166            }
167        }
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[test]
176    fn test_persona_creation() {
177        let rule = UnifiedRule::persona("Architect", "Senior system architect");
178        assert_eq!(rule.type_name(), "persona");
179
180        if let UnifiedRule::Persona { name, role, .. } = rule {
181            assert_eq!(name, "Architect");
182            assert_eq!(role, "Senior system architect");
183        } else {
184            panic!("Expected Persona variant");
185        }
186    }
187
188    #[test]
189    fn test_standard_creation() {
190        let rule = UnifiedRule::standard(RuleCategory::Naming, 1, "Use snake_case for functions");
191        assert_eq!(rule.type_name(), "standard");
192    }
193
194    #[test]
195    fn test_display() {
196        let rule = UnifiedRule::persona("Test", "Tester");
197        let display = format!("{}", rule);
198        assert!(display.contains("Persona"));
199        assert!(display.contains("Test"));
200    }
201}