1use crate::format::RuleCategory;
4
5#[derive(Debug, Clone)]
7pub struct ParsedRule {
8 pub source: Option<std::path::PathBuf>,
10 pub line: Option<usize>,
12 pub rule: UnifiedRule,
14}
15
16#[derive(Debug, Clone)]
18pub struct WorkflowStepData {
19 pub name: String,
21 pub description: String,
23 pub condition: Option<String>,
25 pub actions: Vec<String>,
27}
28
29#[derive(Debug, Clone)]
31pub enum UnifiedRule {
32 Persona {
34 name: String,
36 role: String,
38 identity: Option<String>,
40 style: Option<String>,
42 traits: Vec<String>,
44 principles: Vec<String>,
46 },
47
48 Standard {
50 category: RuleCategory,
52 priority: u8,
54 description: String,
56 pattern: Option<String>,
58 },
59
60 Context {
62 includes: Vec<String>,
64 excludes: Vec<String>,
66 focus: Vec<String>,
68 },
69
70 Workflow {
72 name: String,
74 steps: Vec<WorkflowStepData>,
76 },
77
78 Raw {
80 content: String,
82 },
83}
84
85impl UnifiedRule {
86 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 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 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 pub fn workflow(name: impl Into<String>, steps: Vec<WorkflowStepData>) -> Self {
119 Self::Workflow {
120 name: name.into(),
121 steps,
122 }
123 }
124
125 pub fn raw(content: impl Into<String>) -> Self {
127 Self::Raw {
128 content: content.into(),
129 }
130 }
131
132 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}