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 literal_only: bool, // If true, only remove from struct literals, not the definition
92    #[serde(default)]
93    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct AddStructLiteralFieldOp {
98    pub struct_name: String,
99    pub field_def: String, // e.g., "return_type: None"
100    pub position: InsertPosition,
101    #[serde(default)]
102    pub struct_path: Option<String>,  // Optional canonical path (e.g., "crate::types::Rectangle")
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct AddEnumVariantOp {
107    pub enum_name: String,
108    pub variant_def: String, // e.g., "NewVariant" or "NewVariant { x: i32 }"
109    pub position: InsertPosition,
110    #[serde(default)]
111    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct UpdateEnumVariantOp {
116    pub enum_name: String,
117    pub variant_def: String, // e.g., "UpdatedVariant { new_field: Type }" (variant name parsed from this)
118    #[serde(default)]
119    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct RemoveEnumVariantOp {
124    pub enum_name: String,
125    pub variant_name: String, // Name of the variant to remove
126    #[serde(default)]
127    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct AddMatchArmOp {
132    pub pattern: String, // e.g., "MyEnum::NewVariant"
133    pub body: String,    // e.g., "todo!()"
134    pub function_name: Option<String>, // Optional: specific function containing match
135    #[serde(default)]
136    pub auto_detect: bool, // Auto-detect missing enum variants
137    pub enum_name: Option<String>, // Enum name for auto-detection
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct UpdateMatchArmOp {
142    pub pattern: String, // Pattern to find (e.g., "MyEnum::Variant")
143    pub new_body: String, // New body for the arm
144    pub function_name: Option<String>, // Optional: specific function containing match
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct RemoveMatchArmOp {
149    pub pattern: String, // Pattern to remove (e.g., "MyEnum::Variant")
150    pub function_name: Option<String>, // Optional: specific function containing match
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct AddImplMethodOp {
155    pub target: String, // e.g., "MyStruct" or "impl MyTrait for MyStruct"
156    pub method_def: String, // Full method definition
157    pub position: InsertPosition,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct AddUseStatementOp {
162    pub use_path: String, // e.g., "std::collections::HashMap"
163    pub position: InsertPosition,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct AddDeriveOp {
168    pub target_name: String, // Name of struct or enum
169    pub target_type: String, // "struct" or "enum"
170    pub derives: Vec<String>, // e.g., ["Clone", "Debug", "Serialize"]
171    #[serde(default)]
172    pub where_filter: Option<String>, // Optional: filter targets (e.g., "derives_trait:Clone")
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub enum InsertPosition {
177    First,
178    Last,
179    After(String),  // After named item
180    Before(String), // Before named item
181}
182
183#[derive(Debug, Serialize, Deserialize)]
184pub struct BatchSpec {
185    pub base_path: PathBuf,
186    pub operations: Vec<Operation>,
187}
188
189#[derive(Debug, Serialize, Deserialize, Clone)]
190pub struct NodeLocation {
191    pub line: usize,
192    pub column: usize,
193    pub end_line: usize,
194    pub end_column: usize,
195}
196
197/// Backup of a single AST node before modification
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct BackupNode {
200    pub node_type: String,        // "ItemStruct", "ItemEnum", "ItemImpl", "ExprStruct", "ExprMatch"
201    pub identifier: String,        // "User", "Status::Draft", "process_event", etc.
202    pub original_content: String,  // Original AST node as formatted code
203    pub location: NodeLocation,
204}
205
206/// Result of applying an operation
207#[derive(Debug)]
208pub struct ModificationResult {
209    pub changed: bool,
210    pub modified_nodes: Vec<BackupNode>,
211}
212
213/// Result of inspecting/listing AST nodes
214#[derive(Debug, Serialize, Deserialize)]
215pub struct InspectResult {
216    pub file_path: String,
217    pub node_type: String,      // "ExprStruct", "ExprMatch", etc.
218    pub identifier: String,      // "Shadow", "Config", etc.
219    pub location: NodeLocation,
220    pub snippet: String,         // Formatted code snippet
221    #[serde(skip_serializing_if = "Option::is_none")]
222    pub preceding_comment: Option<String>,  // Doc comments + regular comments before the node
223}
224
225/// Generic transformation operation
226#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct TransformOp {
228    pub node_type: String,           // "macro-call", "method-call", etc.
229    pub name_filter: Option<String>, // Filter by name (e.g., "eprintln")
230    pub content_filter: Option<String>, // Filter by content (e.g., "[SHADOW RENDER]")
231    pub action: TransformAction,     // What to do with matching nodes
232}
233
234/// Actions that can be performed on AST nodes
235#[derive(Debug, Clone, Serialize, Deserialize)]
236#[serde(tag = "type")]
237pub enum TransformAction {
238    Comment,                    // Wrap in // comment
239    Remove,                     // Delete the node entirely
240    Replace { with: String },   // Replace with provided code
241}
242
243/// Rename an enum variant across the codebase
244#[derive(Debug, Clone, Serialize, Deserialize)]
245pub struct RenameEnumVariantOp {
246    pub enum_name: String,      // Name of the enum (e.g., "IRValue")
247    pub old_variant: String,    // Current variant name (e.g., "HashMapV2")
248    pub new_variant: String,    // New variant name (e.g., "HashMap")
249    #[serde(default)]
250    pub enum_path: Option<String>,  // Optional canonical path (e.g., "crate::compiler::types::IRValue")
251    #[serde(default)]
252    pub edit_mode: EditMode,    // How to apply changes (surgical vs reformat)
253}
254
255/// Rename a function across the codebase
256#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct RenameFunctionOp {
258    pub old_name: String,       // Current function name (e.g., "process_v2")
259    pub new_name: String,       // New function name (e.g., "process")
260    #[serde(default)]
261    pub function_path: Option<String>,  // Optional canonical path (e.g., "crate::utils::process_v2")
262    #[serde(default)]
263    pub edit_mode: EditMode,    // How to apply changes (surgical vs reformat)
264}
265
266/// Add documentation comment to an item
267#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct AddDocCommentOp {
269    pub target_type: String,    // "struct", "enum", "function", "field", "variant"
270    pub name: String,           // Name of the target (e.g., "User", "Status::Draft")
271    pub doc_comment: String,    // Documentation text (without /// prefix)
272    #[serde(default)]
273    pub style: DocCommentStyle, // Line (///) or Block (/** */)
274}
275
276/// Update existing documentation comment
277#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct UpdateDocCommentOp {
279    pub target_type: String,    // "struct", "enum", "function", "field", "variant"
280    pub name: String,           // Name of the target
281    pub doc_comment: String,    // New documentation text
282}
283
284/// Remove documentation comment from an item
285#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct RemoveDocCommentOp {
287    pub target_type: String,    // "struct", "enum", "function", "field", "variant"
288    pub name: String,           // Name of the target
289}
290
291/// Documentation comment style
292#[derive(Debug, Clone, Serialize, Deserialize)]
293#[serde(rename_all = "lowercase")]
294pub enum DocCommentStyle {
295    Line,   // /// or //!
296    Block,  // /** */ or /*! */
297}
298
299impl Default for DocCommentStyle {
300    fn default() -> Self {
301        DocCommentStyle::Line
302    }
303}
304
305impl std::str::FromStr for DocCommentStyle {
306    type Err = String;
307
308    fn from_str(s: &str) -> Result<Self, Self::Err> {
309        match s.to_lowercase().as_str() {
310            "line" => Ok(DocCommentStyle::Line),
311            "block" => Ok(DocCommentStyle::Block),
312            _ => Err(format!("Invalid doc comment style: {}. Valid values are 'line' or 'block'", s)),
313        }
314    }
315}
316
317/// Location of a field in the codebase
318#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct FieldLocation {
320    pub file_path: String,
321    pub line: usize,
322    pub context: FieldContext,
323}
324
325/// Context in which a field appears
326#[derive(Debug, Clone, Serialize, Deserialize)]
327#[serde(tag = "type")]
328pub enum FieldContext {
329    StructDefinition {
330        struct_name: String,
331        field_type: String,
332    },
333    EnumVariantDefinition {
334        enum_name: String,
335        variant_name: String,
336        field_type: String,
337    },
338    StructLiteral {
339        struct_name: String,
340    },
341}