1use std::path::PathBuf;
6
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(rename_all = "lowercase")]
12#[derive(Default)]
13pub enum EditMode {
14 #[default]
17 Surgical,
18 Reformat,
21}
22
23impl std::fmt::Display for EditMode {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self {
26 Self::Surgical => write!(f, "surgical"),
27 Self::Reformat => write!(f, "reformat"),
28 }
29 }
30}
31
32impl std::str::FromStr for EditMode {
33 type Err = String;
34
35 fn from_str(s: &str) -> Result<Self, Self::Err> {
36 match s.to_lowercase().as_str() {
37 "surgical" => Ok(Self::Surgical),
38 "reformat" => Ok(Self::Reformat),
39 _ => Err(format!(
40 "Invalid edit mode: {}. Valid values are 'surgical' or 'reformat'",
41 s
42 )),
43 }
44 }
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48#[serde(tag = "type")]
49pub enum Operation {
50 AddStructField(AddStructFieldOp),
51 UpdateStructField(UpdateStructFieldOp),
52 RemoveStructField(RemoveStructFieldOp),
53 AddStructLiteralField(AddStructLiteralFieldOp),
54 AddEnumVariant(AddEnumVariantOp),
55 UpdateEnumVariant(UpdateEnumVariantOp),
56 RemoveEnumVariant(RemoveEnumVariantOp),
57 AddMatchArm(AddMatchArmOp),
58 UpdateMatchArm(UpdateMatchArmOp),
59 RemoveMatchArm(RemoveMatchArmOp),
60 AddImplMethod(AddImplMethodOp),
61 AddUseStatement(AddUseStatementOp),
62 AddDerive(AddDeriveOp),
63 Transform(TransformOp),
64 RenameEnumVariant(RenameEnumVariantOp),
65 RenameFunction(RenameFunctionOp),
66 AddDocComment(AddDocCommentOp),
67 UpdateDocComment(UpdateDocCommentOp),
68 RemoveDocComment(RemoveDocCommentOp),
69 SetStructLiteralBase(SetStructLiteralBaseOp),
70 AddCallArg(AddCallArgOp),
71 UpdateCallArg(UpdateCallArgOp),
72 RemoveCallArg(RemoveCallArgOp),
73}
74
75impl Operation {
76 pub const fn kind_name(&self) -> &'static str {
79 match self {
80 Self::AddStructField(_) => "AddStructField",
81 Self::UpdateStructField(_) => "UpdateStructField",
82 Self::RemoveStructField(_) => "RemoveStructField",
83 Self::AddStructLiteralField(_) => "AddStructLiteralField",
84 Self::AddEnumVariant(_) => "AddEnumVariant",
85 Self::UpdateEnumVariant(_) => "UpdateEnumVariant",
86 Self::RemoveEnumVariant(_) => "RemoveEnumVariant",
87 Self::RenameEnumVariant(_) => "RenameEnumVariant",
88 Self::AddMatchArm(_) => "AddMatchArm",
89 Self::UpdateMatchArm(_) => "UpdateMatchArm",
90 Self::RemoveMatchArm(_) => "RemoveMatchArm",
91 Self::AddImplMethod(_) => "AddImplMethod",
92 Self::AddUseStatement(_) => "AddUseStatement",
93 Self::AddDerive(_) => "AddDerive",
94 Self::Transform(_) => "Transform",
95 Self::RenameFunction(_) => "RenameFunction",
96 Self::AddDocComment(_) => "AddDocComment",
97 Self::UpdateDocComment(_) => "UpdateDocComment",
98 Self::RemoveDocComment(_) => "RemoveDocComment",
99 Self::SetStructLiteralBase(_) => "SetStructLiteralBase",
100 Self::AddCallArg(_) => "AddCallArg",
101 Self::UpdateCallArg(_) => "UpdateCallArg",
102 Self::RemoveCallArg(_) => "RemoveCallArg",
103 }
104 }
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct AddStructFieldOp {
109 pub struct_name: String,
110 pub field_def: String, pub position: InsertPosition,
113 #[serde(default)]
114 pub literal_default: Option<String>, #[serde(default)]
117 pub where_filter: Option<String>, }
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct UpdateStructFieldOp {
122 pub struct_name: String,
123 pub field_def: String, #[serde(default)]
125 pub where_filter: Option<String>, }
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct RemoveStructFieldOp {
130 pub struct_name: String,
131 pub field_name: String, #[serde(default)]
133 pub literal_only: bool, #[serde(default)]
135 pub where_filter: Option<String>, }
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct AddStructLiteralFieldOp {
140 pub struct_name: String,
141 pub field_def: String, pub position: InsertPosition,
143 #[serde(default)]
144 pub struct_path: Option<String>, }
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct SetStructLiteralBaseOp {
151 pub struct_name: String,
152 pub base_expr: String,
155 #[serde(default)]
156 pub struct_path: Option<String>, }
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct AddEnumVariantOp {
161 pub enum_name: String,
162 pub variant_def: String, pub position: InsertPosition,
164 #[serde(default)]
165 pub where_filter: Option<String>, }
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct UpdateEnumVariantOp {
170 pub enum_name: String,
171 pub variant_def: String, #[serde(default)]
174 pub where_filter: Option<String>, }
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct RemoveEnumVariantOp {
179 pub enum_name: String,
180 pub variant_name: String, #[serde(default)]
182 pub where_filter: Option<String>, }
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct AddMatchArmOp {
187 pub pattern: String, pub body: String, pub function_name: Option<String>, #[serde(default)]
191 pub auto_detect: bool, pub enum_name: Option<String>, }
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct UpdateMatchArmOp {
197 pub pattern: String, pub new_body: String, pub function_name: Option<String>, }
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct RemoveMatchArmOp {
204 pub pattern: String, pub function_name: Option<String>, }
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct AddImplMethodOp {
210 pub target: String, pub method_def: String, pub position: InsertPosition,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct AddUseStatementOp {
217 pub use_path: String, pub position: InsertPosition,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct AddDeriveOp {
223 pub target_name: String, pub target_type: String, pub derives: Vec<String>, #[serde(default)]
227 pub where_filter: Option<String>, }
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub enum InsertPosition {
232 First,
233 Last,
234 After(String), Before(String), }
237
238#[derive(Debug, Serialize, Deserialize)]
239pub struct BatchSpec {
240 pub base_path: PathBuf,
241 pub operations: Vec<Operation>,
242}
243
244#[derive(Debug, Serialize, Deserialize, Clone)]
245pub struct NodeLocation {
246 pub line: usize,
247 pub column: usize,
248 pub end_line: usize,
249 pub end_column: usize,
250}
251
252#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct BackupNode {
255 pub node_type: String, pub identifier: String, pub original_content: String, pub location: NodeLocation,
259}
260
261#[derive(Debug)]
263pub struct ModificationResult {
264 pub changed: bool,
265 pub modified_nodes: Vec<BackupNode>,
266 pub unmatched_qualified_paths: Option<std::collections::HashMap<String, usize>>,
269}
270
271#[derive(Debug, Serialize, Deserialize)]
273pub struct InspectResult {
274 pub file_path: String,
275 pub node_type: String, pub identifier: String, pub location: NodeLocation,
278 pub snippet: String, #[serde(skip_serializing_if = "Option::is_none")]
280 pub preceding_comment: Option<String>, }
282
283#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct TransformOp {
286 pub node_type: String, pub name_filter: Option<String>, pub content_filter: Option<String>, pub action: TransformAction, }
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
294#[serde(tag = "type")]
295pub enum TransformAction {
296 Comment, Remove, Replace { with: String }, }
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
303pub struct RenameEnumVariantOp {
304 pub enum_name: String, pub old_variant: String, pub new_variant: String, #[serde(default)]
308 pub enum_path: Option<String>, #[serde(default)]
311 pub edit_mode: EditMode, }
313
314#[derive(Debug, Clone, Serialize, Deserialize)]
316pub struct RenameFunctionOp {
317 pub old_name: String, pub new_name: String, #[serde(default)]
320 pub function_path: Option<String>, #[serde(default)]
322 pub edit_mode: EditMode, }
324
325#[derive(Debug, Clone, Serialize, Deserialize)]
327pub struct AddDocCommentOp {
328 pub target_type: String, pub name: String, pub doc_comment: String, #[serde(default)]
332 pub style: DocCommentStyle, }
334
335#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct UpdateDocCommentOp {
338 pub target_type: String, pub name: String, pub doc_comment: String, }
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct RemoveDocCommentOp {
346 pub target_type: String, pub name: String, }
349
350#[derive(Debug, Clone, Serialize, Deserialize)]
352#[serde(rename_all = "lowercase")]
353#[derive(Default)]
354pub enum DocCommentStyle {
355 #[default]
356 Line, Block, }
359
360impl std::str::FromStr for DocCommentStyle {
361 type Err = String;
362
363 fn from_str(s: &str) -> Result<Self, Self::Err> {
364 match s.to_lowercase().as_str() {
365 "line" => Ok(Self::Line),
366 "block" => Ok(Self::Block),
367 _ => Err(format!(
368 "Invalid doc comment style: {}. Valid values are 'line' or 'block'",
369 s
370 )),
371 }
372 }
373}
374
375#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct FieldLocation {
378 pub file_path: String,
379 pub line: usize,
380 pub context: FieldContext,
381}
382
383#[derive(Debug, Clone, Serialize, Deserialize, Default)]
385pub enum ArgPosition {
386 First,
388 #[default]
390 Last,
391 Index(usize),
393}
394
395impl std::fmt::Display for ArgPosition {
396 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
397 match self {
398 Self::First => write!(f, "first"),
399 Self::Last => write!(f, "last"),
400 Self::Index(i) => write!(f, "index:{}", i),
401 }
402 }
403}
404
405impl std::str::FromStr for ArgPosition {
406 type Err = String;
407
408 fn from_str(s: &str) -> Result<Self, Self::Err> {
409 match s.to_lowercase().as_str() {
410 "first" => Ok(Self::First),
411 "last" => Ok(Self::Last),
412 s if s.starts_with("index:") => {
413 let idx = s[6..]
414 .parse::<usize>()
415 .map_err(|_| format!("Invalid index in position: {}", s))?;
416 Ok(Self::Index(idx))
417 }
418 s => {
419 s.parse::<usize>().map_or_else(
421 |_| {
422 Err(format!(
423 "Invalid arg position: {}. Valid values are 'first', 'last', or 'index:N'",
424 s
425 ))
426 },
427 |idx| Ok(Self::Index(idx)),
428 )
429 }
430 }
431 }
432}
433
434#[derive(Debug, Clone, Serialize, Deserialize)]
436pub struct AddCallArgOp {
437 pub call_name: String,
439 pub arg_expr: String,
441 #[serde(default)]
443 pub position: ArgPosition,
444 #[serde(default)]
446 pub call_type: Option<String>,
447 #[serde(default)]
449 pub content_filter: Option<String>,
450}
451
452#[derive(Debug, Clone, Serialize, Deserialize)]
454pub struct UpdateCallArgOp {
455 pub call_name: String,
457 pub arg_index: usize,
459 pub new_expr: String,
461 #[serde(default)]
463 pub call_type: Option<String>,
464 #[serde(default)]
466 pub content_filter: Option<String>,
467}
468
469#[derive(Debug, Clone, Serialize, Deserialize)]
471pub struct RemoveCallArgOp {
472 pub call_name: String,
474 pub arg_index: usize,
476 #[serde(default)]
478 pub call_type: Option<String>,
479 #[serde(default)]
481 pub content_filter: Option<String>,
482}
483
484#[derive(Debug, Clone, Serialize, Deserialize)]
486#[serde(tag = "type")]
487pub enum FieldContext {
488 StructDefinition {
489 struct_name: String,
490 field_type: String,
491 },
492 EnumVariantDefinition {
493 enum_name: String,
494 variant_name: String,
495 field_type: String,
496 },
497 StructLiteral {
498 struct_name: String,
499 },
500}