rs_hack/
operations.rs

1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4/// Edit mode for operations - controls how changes are applied to source files
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum EditMode {
8    /// Surgical mode: preserve all formatting, only change specific locations
9    /// This is the recommended default for minimal diffs
10    Surgical,
11    /// Reformat mode: use prettyplease to reformat the entire file
12    /// Use this if you want consistent formatting across the file
13    Reformat,
14}
15
16impl Default for EditMode {
17    fn default() -> Self {
18        EditMode::Surgical
19    }
20}
21
22impl std::fmt::Display for EditMode {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        match self {
25            EditMode::Surgical => write!(f, "surgical"),
26            EditMode::Reformat => write!(f, "reformat"),
27        }
28    }
29}
30
31impl std::str::FromStr for EditMode {
32    type Err = String;
33
34    fn from_str(s: &str) -> Result<Self, Self::Err> {
35        match s.to_lowercase().as_str() {
36            "surgical" => Ok(EditMode::Surgical),
37            "reformat" => Ok(EditMode::Reformat),
38            _ => Err(format!("Invalid edit mode: {}. Valid values are 'surgical' or 'reformat'", s)),
39        }
40    }
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44#[serde(tag = "type")]
45pub enum Operation {
46    AddStructField(AddStructFieldOp),
47    UpdateStructField(UpdateStructFieldOp),
48    RemoveStructField(RemoveStructFieldOp),
49    AddStructLiteralField(AddStructLiteralFieldOp),
50    AddEnumVariant(AddEnumVariantOp),
51    UpdateEnumVariant(UpdateEnumVariantOp),
52    RemoveEnumVariant(RemoveEnumVariantOp),
53    AddMatchArm(AddMatchArmOp),
54    UpdateMatchArm(UpdateMatchArmOp),
55    RemoveMatchArm(RemoveMatchArmOp),
56    AddImplMethod(AddImplMethodOp),
57    AddUseStatement(AddUseStatementOp),
58    AddDerive(AddDeriveOp),
59    Transform(TransformOp),
60    RenameEnumVariant(RenameEnumVariantOp),
61    RenameFunction(RenameFunctionOp),
62    AddDocComment(AddDocCommentOp),
63    UpdateDocComment(UpdateDocCommentOp),
64    RemoveDocComment(RemoveDocCommentOp),
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct AddStructFieldOp {
69    pub struct_name: String,
70    pub field_def: String, // e.g., "new_field: Option<String>" or just "new_field" if literal_default is provided
71    pub position: InsertPosition,
72    #[serde(default)]
73    pub literal_default: Option<String>, // If provided: tries to add to definition (idempotent), always updates literals
74    #[serde(default)]
75    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct UpdateStructFieldOp {
80    pub struct_name: String,
81    pub field_def: String, // e.g., "field_name: NewType" (field name is parsed from this)
82    #[serde(default)]
83    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct RemoveStructFieldOp {
88    pub struct_name: String,
89    pub field_name: String, // Name of the field to remove
90    #[serde(default)]
91    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct AddStructLiteralFieldOp {
96    pub struct_name: String,
97    pub field_def: String, // e.g., "return_type: None"
98    pub position: InsertPosition,
99    #[serde(default)]
100    pub struct_path: Option<String>,  // Optional canonical path (e.g., "crate::types::Rectangle")
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct AddEnumVariantOp {
105    pub enum_name: String,
106    pub variant_def: String, // e.g., "NewVariant" or "NewVariant { x: i32 }"
107    pub position: InsertPosition,
108    #[serde(default)]
109    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct UpdateEnumVariantOp {
114    pub enum_name: String,
115    pub variant_def: String, // e.g., "UpdatedVariant { new_field: Type }" (variant name parsed from this)
116    #[serde(default)]
117    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct RemoveEnumVariantOp {
122    pub enum_name: String,
123    pub variant_name: String, // Name of the variant to remove
124    #[serde(default)]
125    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct AddMatchArmOp {
130    pub pattern: String, // e.g., "MyEnum::NewVariant"
131    pub body: String,    // e.g., "todo!()"
132    pub function_name: Option<String>, // Optional: specific function containing match
133    #[serde(default)]
134    pub auto_detect: bool, // Auto-detect missing enum variants
135    pub enum_name: Option<String>, // Enum name for auto-detection
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct UpdateMatchArmOp {
140    pub pattern: String, // Pattern to find (e.g., "MyEnum::Variant")
141    pub new_body: String, // New body for the arm
142    pub function_name: Option<String>, // Optional: specific function containing match
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct RemoveMatchArmOp {
147    pub pattern: String, // Pattern to remove (e.g., "MyEnum::Variant")
148    pub function_name: Option<String>, // Optional: specific function containing match
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct AddImplMethodOp {
153    pub target: String, // e.g., "MyStruct" or "impl MyTrait for MyStruct"
154    pub method_def: String, // Full method definition
155    pub position: InsertPosition,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct AddUseStatementOp {
160    pub use_path: String, // e.g., "std::collections::HashMap"
161    pub position: InsertPosition,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct AddDeriveOp {
166    pub target_name: String, // Name of struct or enum
167    pub target_type: String, // "struct" or "enum"
168    pub derives: Vec<String>, // e.g., ["Clone", "Debug", "Serialize"]
169    #[serde(default)]
170    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub enum InsertPosition {
175    First,
176    Last,
177    After(String),  // After named item
178    Before(String), // Before named item
179}
180
181#[derive(Debug, Serialize, Deserialize)]
182pub struct BatchSpec {
183    pub base_path: PathBuf,
184    pub operations: Vec<Operation>,
185}
186
187#[derive(Debug, Serialize, Deserialize, Clone)]
188pub struct NodeLocation {
189    pub line: usize,
190    pub column: usize,
191    pub end_line: usize,
192    pub end_column: usize,
193}
194
195/// Backup of a single AST node before modification
196#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct BackupNode {
198    pub node_type: String,        // "ItemStruct", "ItemEnum", "ItemImpl", "ExprStruct", "ExprMatch"
199    pub identifier: String,        // "User", "Status::Draft", "process_event", etc.
200    pub original_content: String,  // Original AST node as formatted code
201    pub location: NodeLocation,
202}
203
204/// Result of applying an operation
205#[derive(Debug)]
206pub struct ModificationResult {
207    pub changed: bool,
208    pub modified_nodes: Vec<BackupNode>,
209}
210
211/// Result of inspecting/listing AST nodes
212#[derive(Debug, Serialize, Deserialize)]
213pub struct InspectResult {
214    pub file_path: String,
215    pub node_type: String,      // "ExprStruct", "ExprMatch", etc.
216    pub identifier: String,      // "Shadow", "Config", etc.
217    pub location: NodeLocation,
218    pub snippet: String,         // Formatted code snippet
219}
220
221/// Generic transformation operation
222#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct TransformOp {
224    pub node_type: String,           // "macro-call", "method-call", etc.
225    pub name_filter: Option<String>, // Filter by name (e.g., "eprintln")
226    pub content_filter: Option<String>, // Filter by content (e.g., "[SHADOW RENDER]")
227    pub action: TransformAction,     // What to do with matching nodes
228}
229
230/// Actions that can be performed on AST nodes
231#[derive(Debug, Clone, Serialize, Deserialize)]
232#[serde(tag = "type")]
233pub enum TransformAction {
234    Comment,                    // Wrap in // comment
235    Remove,                     // Delete the node entirely
236    Replace { with: String },   // Replace with provided code
237}
238
239/// Rename an enum variant across the codebase
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct RenameEnumVariantOp {
242    pub enum_name: String,      // Name of the enum (e.g., "IRValue")
243    pub old_variant: String,    // Current variant name (e.g., "HashMapV2")
244    pub new_variant: String,    // New variant name (e.g., "HashMap")
245    #[serde(default)]
246    pub enum_path: Option<String>,  // Optional canonical path (e.g., "crate::compiler::types::IRValue")
247    #[serde(default)]
248    pub edit_mode: EditMode,    // How to apply changes (surgical vs reformat)
249}
250
251/// Rename a function across the codebase
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct RenameFunctionOp {
254    pub old_name: String,       // Current function name (e.g., "process_v2")
255    pub new_name: String,       // New function name (e.g., "process")
256    #[serde(default)]
257    pub function_path: Option<String>,  // Optional canonical path (e.g., "crate::utils::process_v2")
258    #[serde(default)]
259    pub edit_mode: EditMode,    // How to apply changes (surgical vs reformat)
260}
261
262/// Add documentation comment to an item
263#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct AddDocCommentOp {
265    pub target_type: String,    // "struct", "enum", "function", "field", "variant"
266    pub name: String,           // Name of the target (e.g., "User", "Status::Draft")
267    pub doc_comment: String,    // Documentation text (without /// prefix)
268    #[serde(default)]
269    pub style: DocCommentStyle, // Line (///) or Block (/** */)
270}
271
272/// Update existing documentation comment
273#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct UpdateDocCommentOp {
275    pub target_type: String,    // "struct", "enum", "function", "field", "variant"
276    pub name: String,           // Name of the target
277    pub doc_comment: String,    // New documentation text
278}
279
280/// Remove documentation comment from an item
281#[derive(Debug, Clone, Serialize, Deserialize)]
282pub struct RemoveDocCommentOp {
283    pub target_type: String,    // "struct", "enum", "function", "field", "variant"
284    pub name: String,           // Name of the target
285}
286
287/// Documentation comment style
288#[derive(Debug, Clone, Serialize, Deserialize)]
289#[serde(rename_all = "lowercase")]
290pub enum DocCommentStyle {
291    Line,   // /// or //!
292    Block,  // /** */ or /*! */
293}
294
295impl Default for DocCommentStyle {
296    fn default() -> Self {
297        DocCommentStyle::Line
298    }
299}
300
301impl std::str::FromStr for DocCommentStyle {
302    type Err = String;
303
304    fn from_str(s: &str) -> Result<Self, Self::Err> {
305        match s.to_lowercase().as_str() {
306            "line" => Ok(DocCommentStyle::Line),
307            "block" => Ok(DocCommentStyle::Block),
308            _ => Err(format!("Invalid doc comment style: {}. Valid values are 'line' or 'block'", s)),
309        }
310    }
311}