@@ -16,20 +16,30 @@ import (
1616type (
1717 // functionOpts represent the options for functions.
1818 functionOpts struct {
19- funcName string // Name of the function to modify .
20- newParams [] functionParam // Parameters to add to the function.
21- body string // New function body content .
22- newLines [] functionLine // Lines to insert at specific positions .
23- insideCall functionCalls // Function calls to modify.
24- insideStruct functionStructs // Struct literals to modify .
25- appendTestCase []string // Test cases to append.
26- appendCode []string // Code to append at the end .
27- returnVars [] string // Return variables to modify .
19+ newParams [] functionParam // Parameters to add to the function .
20+ body string // New function body content .
21+ newLines [] functionLine // Lines to insert at specific positions .
22+ insideCall functionCalls // Function calls to modify .
23+ insideStruct functionStructs // Struct literals to modify.
24+ appendTestCase [] string // Test cases to append .
25+ appendCode []string // Code to append at the end .
26+ returnVars []string // Return variables to modify .
27+ appendSwitch functionSwitches // Switch cases to append .
2828 }
2929
3030 // FunctionOptions configures code generation.
3131 FunctionOptions func (* functionOpts )
3232
33+ // functionStruct represents a struct literal to modify.
34+ functionSwitch struct {
35+ condition string // Condition to find.
36+ switchCase string // Switch case to insert.
37+ switchBody string // Code to insert.
38+ }
39+
40+ functionSwitches []functionSwitch
41+ functionSwitchesMap map [string ]functionSwitches
42+
3343 // functionStruct represents a struct literal to modify.
3444 functionStruct struct {
3545 name string // Name of the struct type.
@@ -83,6 +93,19 @@ func (s functionStructs) Map() functionStructsMap {
8393 return structMap
8494}
8595
96+ // Map converts a slice of functionStructs to a map keyed by struct name.
97+ func (s functionSwitches ) Map () functionSwitchesMap {
98+ switchesMap := make (functionSwitchesMap )
99+ for _ , c := range s {
100+ switches , ok := switchesMap [c .condition ]
101+ if ! ok {
102+ switches = make (functionSwitches , 0 )
103+ }
104+ switchesMap [c .condition ] = append (switches , c )
105+ }
106+ return switchesMap
107+ }
108+
86109// Map converts a slice of functionCalls to a map keyed by function name.
87110func (c functionCalls ) Map () functionCallsMap {
88111 callMap := make (functionCallsMap )
@@ -173,10 +196,20 @@ func NewFuncReturn(returnVars ...string) FunctionOptions {
173196 }
174197}
175198
199+ // AppendSwitchCase inserts a new case with the code at a specific switch condition statement.
200+ func AppendSwitchCase (condition , switchCase , switchBody string ) FunctionOptions {
201+ return func (c * functionOpts ) {
202+ c .appendSwitch = append (c .appendSwitch , functionSwitch {
203+ condition : condition ,
204+ switchCase : switchCase ,
205+ switchBody : switchBody ,
206+ })
207+ }
208+ }
209+
176210// newFunctionOptions creates a new functionOpts with defaults.
177- func newFunctionOptions (funcName string ) functionOpts {
211+ func newFunctionOptions () functionOpts {
178212 return functionOpts {
179- funcName : funcName ,
180213 newParams : make ([]functionParam , 0 ),
181214 body : "" ,
182215 newLines : make ([]functionLine , 0 ),
@@ -191,7 +224,7 @@ func newFunctionOptions(funcName string) functionOpts {
191224// ModifyFunction modifies a function in Go source code using functional options.
192225func ModifyFunction (content string , funcName string , functions ... FunctionOptions ) (string , error ) {
193226 // Collect all function options.
194- opts := newFunctionOptions (funcName )
227+ opts := newFunctionOptions ()
195228 for _ , fn := range functions {
196229 fn (& opts )
197230 }
@@ -256,6 +289,55 @@ func modifyReturnVars(fileSet *token.FileSet, returnVars []string) ([]ast.Expr,
256289 return stmts , nil
257290}
258291
292+ // appendSwitchCase appends a new case to a switch statement.
293+ func appendSwitchCase (fileSet * token.FileSet , stmt ast.Node , fs functionSwitches ) error {
294+ for _ , f := range fs {
295+ // Parse the new case code
296+ newRetExpr , err := parser .ParseExprFrom (fileSet , "" , []byte (f .switchCase ), parser .ParseComments )
297+ if err != nil {
298+ return err
299+ }
300+
301+ bodyStmt , err := codeToBlockStmt (fileSet , f .switchBody )
302+ if err != nil {
303+ return err
304+ }
305+
306+ // Create a new case clause
307+ newCase := & ast.CaseClause {
308+ List : []ast.Expr {newRetExpr },
309+ Body : bodyStmt .List ,
310+ Case : token .NoPos , // Keep first item aligned with case keyword
311+ Colon : token .NoPos , // Keep colon aligned with case keyword
312+ }
313+
314+ // Handle different types of switch statements
315+ switch statement := stmt .(type ) {
316+ case * ast.TypeSwitchStmt :
317+ statement .Body .List = appendCaseToList (statement .Body .List , newCase )
318+ case * ast.SwitchStmt :
319+ statement .Body .List = appendCaseToList (statement .Body .List , newCase )
320+ default :
321+ return errors .Errorf ("unsupported switch statement type: %T" , stmt )
322+ }
323+ }
324+ return nil
325+ }
326+
327+ // appendCaseToList handles inserting a case clause into a list of statements,
328+ // placing it before any default case if one exists.
329+ func appendCaseToList (list []ast.Stmt , newCase * ast.CaseClause ) []ast.Stmt {
330+ if len (list ) > 0 {
331+ lastCase , isDefault := list [len (list )- 1 ].(* ast.CaseClause )
332+ if isDefault && len (lastCase .List ) == 0 {
333+ // Insert before default.
334+ return append (list [:len (list )- 1 ], newCase , list [len (list )- 1 ])
335+ }
336+ }
337+
338+ return append (list , newCase )
339+ }
340+
259341// addParams adds new parameters to a function declaration.
260342func addParams (funcDecl * ast.FuncDecl , newParams []functionParam ) error {
261343 for _ , p := range newParams {
@@ -371,7 +453,7 @@ func addTestCase(fSet *token.FileSet, funcDecl *ast.FuncDecl, testCase []string)
371453// structToBlockStmt parses struct literal code into AST expression.
372454func structToBlockStmt (fSet * token.FileSet , code string ) (ast.Expr , error ) {
373455 newFuncContent := toStruct (code )
374- newContent , err := parser .ParseExprFrom (fSet , "temp.go " , newFuncContent , parser .AllErrors )
456+ newContent , err := parser .ParseExprFrom (fSet , "" , newFuncContent , parser .AllErrors )
375457 if err != nil {
376458 return nil , err
377459 }
@@ -498,7 +580,8 @@ func formatNode(fileSet *token.FileSet, n ast.Node) (string, error) {
498580 return "" , err
499581 }
500582
501- return buf .String (), nil
583+ node := strings .TrimSpace (buf .String ())
584+ return node , nil
502585}
503586
504587// applyFunctionOptions applies all modifications to a function.
@@ -526,20 +609,19 @@ func applyFunctionOptions(fileSet *token.FileSet, f *ast.FuncDecl, opts *functio
526609
527610 // Create maps for tracking modifications.
528611 var (
529- callMap = opts .insideCall .Map ()
530- callMapCheck = opts .insideCall .Map ()
531- structMap = opts .insideStruct .Map ()
532- structMapCheck = opts .insideStruct .Map ()
612+ callMap = opts .insideCall .Map ()
613+ callMapCheck = opts .insideCall .Map ()
614+ structMap = opts .insideStruct .Map ()
615+ structMapCheck = opts .insideStruct .Map ()
616+ switchesCasesMap = opts .appendSwitch .Map ()
617+ switchesCasesMapCheck = opts .appendSwitch .Map ()
533618 )
534619
535620 // Apply all modifications.
536- var (
537- found bool
538- errInspect error
539- )
621+ var errInspect error
540622 ast .Inspect (f , func (n ast.Node ) bool {
541623 funcDecl , ok := n .(* ast.FuncDecl )
542- if ! ok || funcDecl . Name . Name != opts . funcName {
624+ if ! ok {
543625 return true
544626 }
545627
@@ -567,6 +649,39 @@ func applyFunctionOptions(fileSet *token.FileSet, f *ast.FuncDecl, opts *functio
567649 return false
568650 }
569651
652+ for _ , bodyList := range funcDecl .Body .List {
653+ var stmt ast.Stmt
654+ var buf bytes.Buffer
655+ switch expr := bodyList .(type ) {
656+ case * ast.TypeSwitchStmt :
657+ stmt = expr
658+ if err := format .Node (& buf , fileSet , expr .Assign ); err != nil {
659+ errInspect = err
660+ return false
661+ }
662+ case * ast.SwitchStmt :
663+ stmt = expr
664+ if err := format .Node (& buf , fileSet , expr .Tag ); err != nil {
665+ errInspect = err
666+ return false
667+ }
668+ default :
669+ continue
670+ }
671+
672+ switchCase , ok := switchesCasesMap [buf .String ()]
673+ if ! ok {
674+ continue
675+ }
676+
677+ if err := appendSwitchCase (fileSet , stmt , switchCase ); err != nil {
678+ errInspect = err
679+ return false
680+ }
681+
682+ delete (switchesCasesMapCheck , buf .String ())
683+ }
684+
570685 // Modify function calls and struct literals.
571686 ast .Inspect (funcDecl , func (n ast.Node ) bool {
572687 switch expr := n .(type ) {
@@ -610,31 +725,28 @@ func applyFunctionOptions(fileSet *token.FileSet, f *ast.FuncDecl, opts *functio
610725 return false
611726 }
612727
613- // Verify all modifications were applied.
614- if len (callMapCheck ) > 0 {
615- errInspect = errors .Errorf ("function calls not found: %v" , callMapCheck )
616- return false
617- }
618- if len (structMapCheck ) > 0 {
619- errInspect = errors .Errorf ("function structs not found: %v" , structMapCheck )
620- return false
621- }
622-
623728 // Add test cases.
624729 if err := addTestCase (fileSet , funcDecl , opts .appendTestCase ); err != nil {
625730 errInspect = err
626731 return false
627732 }
628733
629- found = true
630734 return false
631735 })
632736
633737 if errInspect != nil {
634738 return errInspect
635739 }
636- if ! found {
637- return errors .Errorf ("function %s not found in file content" , opts .funcName )
740+
741+ // Verify all modifications were applied.
742+ if len (callMapCheck ) > 0 {
743+ return errors .Errorf ("function calls not found: %v" , callMapCheck )
744+ }
745+ if len (structMapCheck ) > 0 {
746+ return errors .Errorf ("function structs not found: %v" , structMapCheck )
747+ }
748+ if len (switchesCasesMapCheck ) > 0 {
749+ return errors .Errorf ("function switch not found: %v" , switchesCasesMapCheck )
638750 }
639751
640752 return nil
0 commit comments