diff --git a/changelog.md b/changelog.md index 9f03fafe41..67cf6446ec 100644 --- a/changelog.md +++ b/changelog.md @@ -20,6 +20,7 @@ - [#4327](https://github.com/ignite/cli/pull/4327) Use the TxConfig from simState instead create a new one - [#4326](https://github.com/ignite/cli/pull/4326) Add `buf.build` version to `ignite version` command - [#4436](https://github.com/ignite/cli/pull/4436) Return tx hash to the faucet API +- [#4437](https://github.com/ignite/cli/pull/4437) Remove module placeholders - [#4289](https://github.com/ignite/cli/pull/4289), [#4423](https://github.com/ignite/cli/pull/4423), [#4432](https://github.com/ignite/cli/pull/4432) Cosmos SDK v0.52 support ### Changes diff --git a/docs/docs/02-guide/04-ibc.md b/docs/docs/02-guide/04-ibc.md index 6dea8c93ca..e351f85ace 100644 --- a/docs/docs/02-guide/04-ibc.md +++ b/docs/docs/02-guide/04-ibc.md @@ -223,48 +223,48 @@ the `msg.Creator` value to the IBC `packet`. package keeper func (k msgServer) SendIbcPost(goCtx context.Context, msg *types.MsgSendIbcPost) (*types.MsgSendIbcPostResponse, error) { - // validate incoming message - if _, err := k.addressCodec.StringToBytes(msg.Creator); err != nil { - return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, fmt.Sprintf("invalid address: %s", err)) - } - - if msg.Port == "" { - return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid packet port") - } - - if msg.ChannelID == "" { - return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid packet channel") - } - - if msg.TimeoutTimestamp == 0 { - return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid packet timeout") - } - - // TODO: logic before transmitting the packet - - // Construct the packet - var packet types.IbcPostPacketData - - packet.Title = msg.Title - packet.Content = msg.Content - // highlight-next-line - packet.Creator = msg.Creator - - // Transmit the packet - ctx := sdk.UnwrapSDKContext(goCtx) - _, err := k.TransmitIbcPostPacket( - ctx, - packet, - msg.Port, - msg.ChannelID, - clienttypes.ZeroHeight(), - msg.TimeoutTimestamp, - ) - if err != nil { - return nil, err - } - - return &types.MsgSendIbcPostResponse{}, nil + // validate incoming message + if _, err := k.addressCodec.StringToBytes(msg.Creator); err != nil { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress, fmt.Sprintf("invalid address: %s", err)) + } + + if msg.Port == "" { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid packet port") + } + + if msg.ChannelID == "" { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid packet channel") + } + + if msg.TimeoutTimestamp == 0 { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid packet timeout") + } + + // TODO: logic before transmitting the packet + + // Construct the packet + var packet types.IbcPostPacketData + + packet.Title = msg.Title + packet.Content = msg.Content + // highlight-next-line + packet.Creator = msg.Creator + + // Transmit the packet + ctx := sdk.UnwrapSDKContext(goCtx) + _, err := k.TransmitIbcPostPacket( + ctx, + packet, + msg.Port, + msg.ChannelID, + clienttypes.ZeroHeight(), + msg.TimeoutTimestamp, + ) + if err != nil { + return nil, err + } + + return &types.MsgSendIbcPostResponse{}, nil } ``` @@ -315,11 +315,11 @@ Then modify the `OnRecvIbcPostPacket` keeper function with the following code: package keeper func (k Keeper) OnRecvIbcPostPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IbcPostPacketData) (packetAck types.IbcPostPacketAck, err error) { - packetAck.PostId, err = k.PostSeq.Next(ctx) - if err != nil { - return packetAck, err - } - return packetAck, k.Post.Set(ctx, packetAck.PostId, types.Post{Title: data.Title, Content: data.Content}) + packetAck.PostId, err = k.PostSeq.Next(ctx) + if err != nil { + return packetAck, err + } + return packetAck, k.Post.Set(ctx, packetAck.PostId, types.Post{Title: data.Title, Content: data.Content}) } ``` @@ -339,33 +339,33 @@ from the packet. package keeper func (k Keeper) OnAcknowledgementIbcPostPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IbcPostPacketData, ack channeltypes.Acknowledgement) error { - switch dispatchedAck := ack.Response.(type) { - case *channeltypes.Acknowledgement_Error: - // We will not treat acknowledgment error in this tutorial - return nil - case *channeltypes.Acknowledgement_Result: - // Decode the packet acknowledgment - var packetAck types.IbcPostPacketAck - if err := types.ModuleCdc.UnmarshalJSON(dispatchedAck.Result, &packetAck); err != nil { - // The counter-party module doesn't implement the correct acknowledgment format - return errors.New("cannot unmarshal acknowledgment") - } - - seq, err := k.SentPostSeq.Next(ctx) - if err != nil { - return err - } - - return k.SentPost.Set(ctx, seq, - types.SentPost{ - PostId: packetAck.PostId, - Title: data.Title, - Chain: packet.DestinationPort + "-" + packet.DestinationChannel, - }, - ) - default: - return errors.New("the counter-party module does not implement the correct acknowledgment format") - } + switch dispatchedAck := ack.Response.(type) { + case *channeltypes.Acknowledgement_Error: + // We will not treat acknowledgment error in this tutorial + return nil + case *channeltypes.Acknowledgement_Result: + // Decode the packet acknowledgment + var packetAck types.IbcPostPacketAck + if err := types.ModuleCdc.UnmarshalJSON(dispatchedAck.Result, &packetAck); err != nil { + // The counter-party module doesn't implement the correct acknowledgment format + return errors.New("cannot unmarshal acknowledgment") + } + + seq, err := k.SentPostSeq.Next(ctx) + if err != nil { + return err + } + + return k.SentPost.Set(ctx, seq, + types.SentPost{ + PostId: packetAck.PostId, + Title: data.Title, + Chain: packet.DestinationPort + "-" + packet.DestinationChannel, + }, + ) + default: + return errors.New("the counter-party module does not implement the correct acknowledgment format") + } } ``` @@ -376,17 +376,17 @@ posts. This logic follows the same format as `sentPost`. ```go title="x/blog/keeper/ibc_post.go" func (k Keeper) OnTimeoutIbcPostPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IbcPostPacketData) error { - seq, err := k.TimeoutPostSeq.Next(ctx) - if err != nil { - return err - } - - return k.TimeoutPost.Set(ctx, seq, - types.TimeoutPost{ - Title: data.Title, - Chain: packet.DestinationPort + "-" + packet.DestinationChannel, - }, - ) + seq, err := k.TimeoutPostSeq.Next(ctx) + if err != nil { + return err + } + + return k.TimeoutPost.Set(ctx, seq, + types.TimeoutPost{ + Title: data.Title, + Chain: packet.DestinationPort + "-" + packet.DestinationChannel, + }, + ) } ``` diff --git a/ignite/pkg/xast/function.go b/ignite/pkg/xast/function.go index 630b388022..bd6f238630 100644 --- a/ignite/pkg/xast/function.go +++ b/ignite/pkg/xast/function.go @@ -15,35 +15,36 @@ import ( type ( // functionOpts represent the options for functions. functionOpts struct { - newParams []param - body string - newLines []line - insideCall []call - insideStruct []str - appendCode []string - returnVars []string + newParams []functionParam + body string + newLines []functionLine + insideCall []functionCall + insideStruct []functionStruct + appendTestCase []string + appendCode []string + returnVars []string } // FunctionOptions configures code generation. FunctionOptions func(*functionOpts) - str struct { - structName string - paramName string - code string - index int + functionStruct struct { + name string + param string + code string + index int } - call struct { + functionCall struct { name string code string index int } - param struct { + functionParam struct { name string varType string index int } - line struct { + functionLine struct { code string number uint64 } @@ -52,7 +53,7 @@ type ( // AppendFuncParams add a new param value. func AppendFuncParams(name, varType string, index int) FunctionOptions { return func(c *functionOpts) { - c.newParams = append(c.newParams, param{ + c.newParams = append(c.newParams, functionParam{ name: name, varType: varType, index: index, @@ -67,6 +68,13 @@ func ReplaceFuncBody(body string) FunctionOptions { } } +// AppendFuncTestCase append test a new test case, if exists, of a function in Go source code content. +func AppendFuncTestCase(testCase string) FunctionOptions { + return func(c *functionOpts) { + c.appendTestCase = append(c.appendTestCase, testCase) + } +} + // AppendFuncCode append code before the end or the return, if exists, of a function in Go source code content. func AppendFuncCode(code string) FunctionOptions { return func(c *functionOpts) { @@ -77,7 +85,7 @@ func AppendFuncCode(code string) FunctionOptions { // AppendFuncAtLine append a new code at line. func AppendFuncAtLine(code string, lineNumber uint64) FunctionOptions { return func(c *functionOpts) { - c.newLines = append(c.newLines, line{ + c.newLines = append(c.newLines, functionLine{ code: code, number: lineNumber, }) @@ -88,7 +96,7 @@ func AppendFuncAtLine(code string, lineNumber uint64) FunctionOptions { // call 'New(param1, param2)' and we want to add the param3 the result will be 'New(param1, param2, param3)'. func AppendInsideFuncCall(callName, code string, index int) FunctionOptions { return func(c *functionOpts) { - c.insideCall = append(c.insideCall, call{ + c.insideCall = append(c.insideCall, functionCall{ name: callName, code: code, index: index, @@ -96,16 +104,16 @@ func AppendInsideFuncCall(callName, code string, index int) FunctionOptions { } } -// AppendInsideFuncStruct add code inside another function call. For instances, +// AppendFuncStruct add code inside another function call. For instances, // the struct have only one parameter 'Params{Param1: param1}' and we want to add // the param2 the result will be 'Params{Param1: param1, Param2: param2}'. -func AppendInsideFuncStruct(structName, paramName, code string, index int) FunctionOptions { +func AppendFuncStruct(name, param, code string, index int) FunctionOptions { return func(c *functionOpts) { - c.insideStruct = append(c.insideStruct, str{ - structName: structName, - paramName: paramName, - code: code, - index: index, + c.insideStruct = append(c.insideStruct, functionStruct{ + name: name, + param: param, + code: code, + index: index, }) } } @@ -119,13 +127,14 @@ func NewFuncReturn(returnVars ...string) FunctionOptions { func newFunctionOptions() functionOpts { return functionOpts{ - newParams: make([]param, 0), - body: "", - newLines: make([]line, 0), - insideCall: make([]call, 0), - insideStruct: make([]str, 0), - appendCode: make([]string, 0), - returnVars: make([]string, 0), + newParams: make([]functionParam, 0), + body: "", + newLines: make([]functionLine, 0), + insideCall: make([]functionCall, 0), + insideStruct: make([]functionStruct, 0), + appendTestCase: make([]string, 0), + appendCode: make([]string, 0), + returnVars: make([]string, 0), } } @@ -148,23 +157,20 @@ func ModifyFunction(fileContent, functionName string, functions ...FunctionOptio // Parse the content of the new function into an ast. var newFunctionBody *ast.BlockStmt if opts.body != "" { - newFuncContent := fmt.Sprintf("package p; func _() { %s }", strings.TrimSpace(opts.body)) - newContent, err := parser.ParseFile(fileSet, "", newFuncContent, parser.ParseComments) + newFunctionBody, err = codeToBlockStmt(fileSet, opts.body) if err != nil { return "", err } - newFunctionBody = newContent.Decls[0].(*ast.FuncDecl).Body } // Parse the content of the append code an ast. appendCode := make([]ast.Stmt, 0) for _, codeToInsert := range opts.appendCode { - newFuncContent := fmt.Sprintf("package p; func _() { %s }", strings.TrimSpace(codeToInsert)) - newContent, err := parser.ParseFile(fileSet, "", newFuncContent, parser.ParseComments) + body, err := codeToBlockStmt(fileSet, codeToInsert) if err != nil { return "", err } - appendCode = append(appendCode, newContent.Decls[0].(*ast.FuncDecl).Body.List...) + appendCode = append(appendCode, body.List...) } // Parse the content of the return vars into an ast. @@ -178,26 +184,26 @@ func ModifyFunction(fileContent, functionName string, functions ...FunctionOptio returnStmts = append(returnStmts, newRetExpr) } - callMap := make(map[string][]call) - callMapCheck := make(map[string][]call) + callMap := make(map[string][]functionCall) + callMapCheck := make(map[string][]functionCall) for _, c := range opts.insideCall { calls, ok := callMap[c.name] if !ok { - calls = []call{} + calls = []functionCall{} } callMap[c.name] = append(calls, c) callMapCheck[c.name] = append(calls, c) } - structMap := make(map[string][]str) - structMapCheck := make(map[string][]str) + structMap := make(map[string][]functionStruct) + structMapCheck := make(map[string][]functionStruct) for _, s := range opts.insideStruct { - structs, ok := structMap[s.structName] + structs, ok := structMap[s.name] if !ok { - structs = []str{} + structs = []functionStruct{} } - structMap[s.structName] = append(structs, s) - structMapCheck[s.structName] = append(structs, s) + structMap[s.name] = append(structs, s) + structMapCheck[s.name] = append(structs, s) } // Parse the Go code to insert. @@ -235,6 +241,7 @@ func ModifyFunction(fileContent, functionName string, functions ...FunctionOptio // Check if the function has the code you want to replace. if newFunctionBody != nil { funcDecl.Body = newFunctionBody + funcDecl.Body.Rbrace = funcDecl.Body.Pos() // Re-adjust positions if necessary. } // Add the new code at line. @@ -352,9 +359,9 @@ func ModifyFunction(fileContent, functionName string, functions ...FunctionOptio // Construct the new argument to be added for _, s := range structs { var newArg ast.Expr = ast.NewIdent(s.code) - if s.paramName != "" { + if s.param != "" { newArg = &ast.KeyValueExpr{ - Key: ast.NewIdent(s.paramName), + Key: ast.NewIdent(s.param), Colon: token.Pos(s.index), Value: ast.NewIdent(s.code), } @@ -390,6 +397,37 @@ func ModifyFunction(fileContent, functionName string, functions ...FunctionOptio return false } + // Locate the `tests` variable inside the function + for _, stmt := range funcDecl.Body.List { + assignStmt, ok := stmt.(*ast.AssignStmt) + if !ok || len(assignStmt.Lhs) == 0 { + continue + } + + // Check if the `tests` variable is being declared + ident, ok := assignStmt.Lhs[0].(*ast.Ident) + if !ok || ident.Name != "tests" { + continue + } + + // Find the composite literal (slice) for the `tests` variable + compositeLit, ok := assignStmt.Rhs[0].(*ast.CompositeLit) + if !ok { + continue + } + + for _, testCase := range opts.appendTestCase { + // Parse the new test case into an AST expression + testCaseStmt, err := structToBlockStmt(testCase) + if err != nil { + errInspect = err + return false + } + // Append the new test case to the list + compositeLit.Elts = append(compositeLit.Elts, testCaseStmt) + } + } + // everything is ok, mark as found and stop the inspect found = true return false @@ -410,3 +448,38 @@ func ModifyFunction(fileContent, functionName string, functions ...FunctionOptio // Return the modified content. return buf.String(), nil } + +func codeToBlockStmt(fileSet *token.FileSet, code string) (*ast.BlockStmt, error) { + newFuncContent := toCode(code) + newContent, err := parser.ParseFile(fileSet, "", newFuncContent, parser.ParseComments) + if err != nil { + return nil, err + } + return newContent.Decls[0].(*ast.FuncDecl).Body, nil +} + +func toCode(code string) string { + return fmt.Sprintf("package p; func _() { %s }", strings.TrimSpace(code)) +} + +func structToBlockStmt(code string) (ast.Expr, error) { + newFuncContent := toStruct(code) + newContent, err := parser.ParseExpr(newFuncContent) + if err != nil { + return nil, err + } + newCompositeList, ok := newContent.(*ast.CompositeLit) + if !ok { + return nil, errors.New("not a composite literal") + } + + if len(newCompositeList.Elts) != 1 { + return nil, errors.New("composite literal has more than one element or zero") + } + + return newCompositeList.Elts[0], nil +} + +func toStruct(code string) string { + return fmt.Sprintf(`struct {}{ %s }`, strings.TrimSpace(code)) +} diff --git a/ignite/pkg/xast/function_test.go b/ignite/pkg/xast/function_test.go index ffbed93dcf..1853ac5003 100644 --- a/ignite/pkg/xast/function_test.go +++ b/ignite/pkg/xast/function_test.go @@ -1,6 +1,7 @@ package xast import ( + "fmt" "strconv" "strings" "testing" @@ -26,6 +27,28 @@ func anotherFunction() bool { p := bla.NewParam() p.CallSomething("Another call") return true +} + +func TestValidate(t *testing.T) { + tests := []struct { + desc string + genState types.GenesisState + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + }, + { + desc: "valid genesis state", + genState: types.GenesisState{}, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + require.NoError(t, err) + }) + } }` type args struct { @@ -55,7 +78,11 @@ func anotherFunction() bool { AppendInsideFuncCall("SimpleCall", "baz", 0), AppendInsideFuncCall("SimpleCall", "bla", -1), AppendInsideFuncCall("Println", strconv.Quote("test"), -1), - AppendInsideFuncStruct("Param", "Bar", strconv.Quote("bar"), -1), + AppendFuncStruct("Param", "Bar", strconv.Quote("bar"), -1), + AppendFuncTestCase(`{ + desc: "valid first genesis state", + genState: GenesisState{}, + }`), }, }, want: `package main @@ -76,6 +103,28 @@ func anotherFunction(param1 string) bool { Param{Baz: baz, Foo: foo, Bar: "bar"} return 1 } + +func TestValidate(t *testing.T) { + tests := []struct { + desc string + genState types.GenesisState + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + }, + { + desc: "valid genesis state", + genState: types.GenesisState{}, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + require.NoError(t, err) + }) + } +} `, }, { @@ -97,6 +146,150 @@ func main() { } func anotherFunction() bool { return false } + +func TestValidate(t *testing.T) { + tests := []struct { + desc string + genState types.GenesisState + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + }, + { + desc: "valid genesis state", + genState: types.GenesisState{}, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + require.NoError(t, err) + }) + } +} +`, + }, + { + name: "add a new test case", + args: args{ + fileContent: existingContent, + functionName: "TestValidate", + functions: []FunctionOptions{ + AppendFuncTestCase(`{ + desc: "valid genesis state", + genState: GenesisState{}, + }`), + }, + }, + want: `package main + +import ( + "fmt" +) + +func main() { + fmt.Println("Hello, world!") + New(param1, param2) +} + +func anotherFunction() bool { + p := bla.NewParam() + p.CallSomething("Another call") + return true +} + +func TestValidate(t *testing.T) { + tests := []struct { + desc string + genState types.GenesisState + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + }, + { + desc: "valid genesis state", + genState: types.GenesisState{}, + }, { + + desc: "valid genesis state", + + genState: GenesisState{}}, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + require.NoError(t, err) + }) + } +} +`, + }, + { + name: "add two test cases", + args: args{ + fileContent: existingContent, + functionName: "TestValidate", + functions: []FunctionOptions{ + AppendFuncTestCase(`{ + desc: "valid first genesis state", + genState: GenesisState{}, + }`), + AppendFuncTestCase(`{ + desc: "valid second genesis state", + genState: GenesisState{}, + }`), + }, + }, + want: `package main + +import ( + "fmt" +) + +func main() { + fmt.Println("Hello, world!") + New(param1, param2) +} + +func anotherFunction() bool { + p := bla.NewParam() + p.CallSomething("Another call") + return true +} + +func TestValidate(t *testing.T) { + tests := []struct { + desc string + genState types.GenesisState + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + }, + { + desc: "valid genesis state", + genState: types.GenesisState{}, + }, { + + desc: "valid first genesis state", + + genState: GenesisState{}, + }, { + + desc: "valid second genesis state", + + genState: GenesisState{}, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + require.NoError(t, err) + }) + } +} `, }, { @@ -131,6 +324,28 @@ func anotherFunction() bool { return true } + +func TestValidate(t *testing.T) { + tests := []struct { + desc string + genState types.GenesisState + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + }, + { + desc: "valid genesis state", + genState: types.GenesisState{}, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + require.NoError(t, err) + }) + } +} `, }, { @@ -170,6 +385,28 @@ func anotherFunction() bool { p.CallSomething("test2", "Another call", "test1") return true } + +func TestValidate(t *testing.T) { + tests := []struct { + desc string + genState types.GenesisState + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + }, + { + desc: "valid genesis state", + genState: types.GenesisState{}, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + require.NoError(t, err) + }) + } +} `, }, { @@ -185,12 +422,35 @@ func anotherFunction() bool { Param{Baz: baz, Foo: foo} Client{baz, foo} return true -}`, +} + +func TestValidate(t *testing.T) { + tests := []struct { + desc string + genState types.GenesisState + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + }, + { + desc: "valid genesis state", + genState: types.GenesisState{}, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + require.NoError(t, err) + }) + } +} +`, functionName: "anotherFunction", functions: []FunctionOptions{ - AppendInsideFuncStruct("Param", "Bar", "bar", -1), - AppendInsideFuncStruct("Param", "Bla", "bla", 1), - AppendInsideFuncStruct("Client", "", "bar", 0), + AppendFuncStruct("Param", "Bar", "bar", -1), + AppendFuncStruct("Param", "Bla", "bla", 1), + AppendFuncStruct("Client", "", "bar", 0), }, }, want: `package main @@ -204,8 +464,44 @@ func anotherFunction() bool { Client{bar, baz, foo} return true } + +func TestValidate(t *testing.T) { + tests := []struct { + desc string + genState types.GenesisState + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + }, + { + desc: "valid genesis state", + genState: types.GenesisState{}, + }, + } + for _, tc := range tests { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + require.NoError(t, err) + }) + } +} `, }, + { + name: "function without test case assertion", + args: args{ + fileContent: existingContent, + functionName: "anotherFunction", + functions: []FunctionOptions{ + AppendFuncTestCase(`{ + desc: "valid second genesis state", + genState: GenesisState{}, + }`), + }, + }, + want: fmt.Sprintln(existingContent), + }, { name: "params out of range", args: args{ @@ -285,7 +581,7 @@ func anotherFunction() bool { functionName: "anotherFunction", functions: []FunctionOptions{AppendInsideFuncCall("NewParam", "9#.(c", 0)}, }, - err: errors.New("format.Node internal error (13:21: illegal character U+0023 '#' (and 2 more errors))"), + err: errors.New("format.Node internal error (13:21: illegal character U+0023 '#' (and 4 more errors))"), }, { name: "call params out of range", diff --git a/ignite/pkg/xast/global.go b/ignite/pkg/xast/global.go index bd6895eba9..a3e69bd1c6 100644 --- a/ignite/pkg/xast/global.go +++ b/ignite/pkg/xast/global.go @@ -179,3 +179,101 @@ func AppendFunction(fileContent string, function string) (modifiedContent string return buf.String(), nil } + +type ( + // structOpts represent the options for structs. + structOpts struct { + values []structValue + } + + // StructOpts configures code generation. + StructOpts func(*structOpts) + + structValue struct { + value string + valueType string + } +) + +// AppendStructValue add a new value inside struct. For instances, +// the struct have only one field 'test struct{ test1 string }' and we want to add +// the `test2 int` the result will be 'test struct{ test1 string, test int }'. +func AppendStructValue(value, valueType string) StructOpts { + return func(c *structOpts) { + c.values = append(c.values, structValue{ + value: value, + valueType: valueType, + }) + } +} + +func newStructOptions() structOpts { + return structOpts{ + values: make([]structValue, 0), + } +} + +// ModifyStruct modifies a struct in the provided Go source code. +func ModifyStruct(fileContent, structName string, options ...StructOpts) (string, error) { + // Apply struct options. + opts := newStructOptions() + for _, o := range options { + o(&opts) + } + + fileSet := token.NewFileSet() + + // Parse the Go source code content. + f, err := parser.ParseFile(fileSet, "", fileContent, parser.ParseComments) + if err != nil { + return "", err + } + + // Locate and modify the struct declaration. + var found bool + ast.Inspect(f, func(n ast.Node) bool { + genDecl, ok := n.(*ast.GenDecl) + if !ok { + return true // Not a general declaration, continue searching. + } + + for _, spec := range genDecl.Specs { + // Check for type specification. + typeSpec, ok := spec.(*ast.TypeSpec) + if !ok || typeSpec.Name.Name != structName { + continue + } + + // Check if the type is a struct. + structType, ok := typeSpec.Type.(*ast.StructType) + if !ok { + continue + } + + for _, v := range opts.values { + // Add the new field to the struct. + newField := &ast.Field{ + Names: []*ast.Ident{ast.NewIdent(v.value)}, + Type: ast.NewIdent(v.valueType), + } + structType.Fields.List = append(structType.Fields.List, newField) + } + + found = true + return false // Stop searching once we modify the struct. + } + return true + }) + if !found { + return "", errors.Errorf("struct %q not found in file content", structName) + } + + // Format the modified AST. + var buf bytes.Buffer + if err := format.Node(&buf, fileSet, f); err != nil { + return "", err + } + + // Return the modified content. + return buf.String(), nil +} diff --git a/ignite/pkg/xast/global_test.go b/ignite/pkg/xast/global_test.go index 2f02015127..0c4da58746 100644 --- a/ignite/pkg/xast/global_test.go +++ b/ignite/pkg/xast/global_test.go @@ -350,3 +350,144 @@ func add(a, b int) int { }) } } + +func TestModifyStruct(t *testing.T) { + type args struct { + fileContent string + structName string + options []StructOpts + } + tests := []struct { + name string + args args + want string + err error + }{ + { + name: "Add field to existing struct", + args: args{ + fileContent: `package main + +type MyStruct struct { + ExistingField int +} +`, + structName: "MyStruct", + options: []StructOpts{AppendStructValue("NewField", "string")}, + }, + want: `package main + +type MyStruct struct { + ExistingField int + NewField string +} +`, + }, + { + name: "Add field to empty struct", + args: args{ + fileContent: `package main + +type EmptyStruct struct { +} +`, + structName: "EmptyStruct", + options: []StructOpts{AppendStructValue("NewField", "string")}, + }, + want: `package main + +type EmptyStruct struct { + NewField string +} +`, + }, + { + name: "Struct not found", + args: args{ + fileContent: `package main + +type AnotherStruct struct { + ExistingField int +} +`, + structName: "NonExistentStruct", + options: []StructOpts{AppendStructValue("NewField", "string")}, + }, + err: errors.New(`struct "NonExistentStruct" not found in file content`), + }, + { + name: "Invalid Go code", + args: args{ + fileContent: `package main + +type MyStruct`, + structName: "MyStruct", + options: []StructOpts{AppendStructValue("NewField", "string")}, + }, + err: errors.New("3:14: expected type, found newline"), + }, + { + name: "Add field after multiple existing fields", + args: args{ + fileContent: `package main + +type MyStruct struct { + Field1 int + Field2 string +} +`, + structName: "MyStruct", + options: []StructOpts{AppendStructValue("Field3", "bool")}, + }, + want: `package main + +type MyStruct struct { + Field1 int + Field2 string + Field3 bool +} +`, + }, + { + name: "Empty file input", + args: args{ + fileContent: ``, + structName: "MyStruct", + options: []StructOpts{AppendStructValue("NewField", "string")}, + }, + err: errors.New("1:1: expected 'package', found 'EOF'"), + }, + { + name: "Add field with pointer type", + args: args{ + fileContent: `package main + +type MyStruct struct { + ExistingField int +} +`, + structName: "MyStruct", + options: []StructOpts{AppendStructValue("PointerField", "*int")}, + }, + want: `package main + +type MyStruct struct { + ExistingField int + PointerField *int +} +`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ModifyStruct(tt.args.fileContent, tt.args.structName, tt.args.options...) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/ignite/templates/ibc/packet.go b/ignite/templates/ibc/packet.go index cdfc066137..d6440d8d21 100644 --- a/ignite/templates/ibc/packet.go +++ b/ignite/templates/ibc/packet.go @@ -13,11 +13,11 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/multiformatname" "github.com/ignite/cli/v29/ignite/pkg/placeholder" "github.com/ignite/cli/v29/ignite/pkg/protoanalysis/protoutil" + "github.com/ignite/cli/v29/ignite/pkg/xast" "github.com/ignite/cli/v29/ignite/pkg/xgenny" "github.com/ignite/cli/v29/ignite/pkg/xstrings" "github.com/ignite/cli/v29/ignite/templates/field" "github.com/ignite/cli/v29/ignite/templates/field/plushhelpers" - "github.com/ignite/cli/v29/ignite/templates/module" "github.com/ignite/cli/v29/ignite/templates/testutil" "github.com/ignite/cli/v29/ignite/templates/typed" ) @@ -78,8 +78,8 @@ func NewPacket(replacer placeholder.Replacer, opts *PacketOptions) (*genny.Gener // Add the send message if !opts.NoMessage { g.RunFn(protoTxModify(opts)) - g.RunFn(clientCliTxModify(replacer, opts)) - g.RunFn(codecModify(replacer, opts)) + g.RunFn(clientCliTxModify(opts)) + g.RunFn(codecModify(opts)) if err := g.Box(messagesTemplate); err != nil { return g, err } @@ -362,23 +362,29 @@ func protoTxModify(opts *PacketOptions) genny.RunFn { } // clientCliTxModify does not use AutoCLI here, because it as a better UX as it is. -func clientCliTxModify(replacer placeholder.Replacer, opts *PacketOptions) genny.RunFn { +func clientCliTxModify(opts *PacketOptions) genny.RunFn { return func(r *genny.Runner) error { filePath := filepath.Join(opts.AppPath, "x", opts.ModuleName, "client/cli/tx.go") f, err := r.Disk.Find(filePath) if err != nil { return err } - template := `cmd.AddCommand(CmdSend%[2]v()) -%[1]v` - replacement := fmt.Sprintf(template, Placeholder, opts.PacketName.UpperCamel) - content := replacer.Replace(f.String(), Placeholder, replacement) + replacement := fmt.Sprintf("cmd.AddCommand(CmdSend%[1]v())", opts.PacketName.UpperCamel) + content, err := xast.ModifyFunction( + f.String(), + "GetTxCmd", + xast.AppendFuncCode(replacement), + ) + if err != nil { + return err + } + newFile := genny.NewFileS(filePath, content) return r.File(newFile) } } -func codecModify(replacer placeholder.Replacer, opts *PacketOptions) genny.RunFn { +func codecModify(opts *PacketOptions) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/codec.go") f, err := r.Disk.Find(path) @@ -387,16 +393,24 @@ func codecModify(replacer placeholder.Replacer, opts *PacketOptions) genny.RunFn } // Set import if not set yet - replacement := `sdk "github.com/cosmos/cosmos-sdk/types"` - content := replacer.ReplaceOnce(f.String(), module.Placeholder, replacement) + content, err := xast.AppendImports(f.String(), xast.WithLastNamedImport("sdk", "github.com/cosmos/cosmos-sdk/types")) + if err != nil { + return err + } // Register the module packet interface templateInterface := `registrar.RegisterImplementations((*sdk.Msg)(nil), - &MsgSend%[2]v{}, -) -%[1]v` - replacementInterface := fmt.Sprintf(templateInterface, module.Placeholder3, opts.PacketName.UpperCamel) - content = replacer.Replace(content, module.Placeholder3, replacementInterface) + &MsgSend%[1]v{}, +)` + replacementInterface := fmt.Sprintf(templateInterface, opts.PacketName.UpperCamel) + content, err = xast.ModifyFunction( + content, + "RegisterInterfaces", + xast.AppendFuncAtLine(replacementInterface, 0), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) diff --git a/ignite/templates/ibc/placeholders.go b/ignite/templates/ibc/placeholders.go index d1dfd154b9..d6f2be019c 100644 --- a/ignite/templates/ibc/placeholders.go +++ b/ignite/templates/ibc/placeholders.go @@ -2,8 +2,6 @@ package ibc //nolint:godot const ( - Placeholder = "// this line is used by starport scaffolding # 1" - // Placeholders IBC packets PlaceholderIBCPacketEvent = "// this line is used by starport scaffolding # ibc/packet/event" PlaceholderIBCPacketModuleRecv = "// this line is used by starport scaffolding # ibc/packet/module/recv" diff --git a/ignite/templates/message/message.go b/ignite/templates/message/message.go index f9806d6feb..09b55b2d5d 100644 --- a/ignite/templates/message/message.go +++ b/ignite/templates/message/message.go @@ -14,6 +14,7 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/errors" "github.com/ignite/cli/v29/ignite/pkg/placeholder" "github.com/ignite/cli/v29/ignite/pkg/protoanalysis/protoutil" + "github.com/ignite/cli/v29/ignite/pkg/xast" "github.com/ignite/cli/v29/ignite/pkg/xgenny" "github.com/ignite/cli/v29/ignite/templates/field/plushhelpers" "github.com/ignite/cli/v29/ignite/templates/testutil" @@ -61,7 +62,7 @@ func NewGenerator(replacer placeholder.Replacer, opts *Options) (*genny.Generato g.RunFn(protoTxRPCModify(opts)) g.RunFn(protoTxMessageModify(opts)) - g.RunFn(typesCodecModify(replacer, opts)) + g.RunFn(typesCodecModify(opts)) g.RunFn(clientCliTxModify(replacer, opts)) template := xgenny.NewEmbedWalker( @@ -71,7 +72,7 @@ func NewGenerator(replacer placeholder.Replacer, opts *Options) (*genny.Generato ) if !opts.NoSimulation { - g.RunFn(moduleSimulationModify(replacer, opts)) + g.RunFn(moduleSimulationModify(opts)) simappTemplate := xgenny.NewEmbedWalker( fsSimapp, "files/simapp", @@ -169,26 +170,36 @@ func protoTxMessageModify(opts *Options) genny.RunFn { } } -func typesCodecModify(replacer placeholder.Replacer, opts *Options) genny.RunFn { +func typesCodecModify(opts *Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/codec.go") f, err := r.Disk.Find(path) if err != nil { return err } - replacementImport := `sdk "github.com/cosmos/cosmos-sdk/types"` - content := replacer.ReplaceOnce(f.String(), Placeholder, replacementImport) + + // Import + content, err := xast.AppendImports(f.String(), xast.WithLastNamedImport("sdk", "github.com/cosmos/cosmos-sdk/types")) + if err != nil { + return err + } templateRegisterImplementations := `registrar.RegisterImplementations((*sdk.Msg)(nil), - &Msg%[2]v{}, -) -%[1]v` + &Msg%[1]v{}, +)` replacementRegisterImplementations := fmt.Sprintf( templateRegisterImplementations, - Placeholder3, opts.MsgName.UpperCamel, ) - content = replacer.Replace(content, Placeholder3, replacementRegisterImplementations) + + content, err = xast.ModifyFunction( + content, + "RegisterInterfaces", + xast.AppendFuncAtLine(replacementRegisterImplementations, 0), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) @@ -231,7 +242,7 @@ func clientCliTxModify(replacer placeholder.Replacer, opts *Options) genny.RunFn } } -func moduleSimulationModify(replacer placeholder.Replacer, opts *Options) genny.RunFn { +func moduleSimulationModify(opts *Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "module/simulation.go") f, err := r.Disk.Find(path) @@ -239,12 +250,14 @@ func moduleSimulationModify(replacer placeholder.Replacer, opts *Options) genny. return err } - content := typed.ModuleSimulationMsgModify( - replacer, + content, err := typed.ModuleSimulationMsgModify( f.String(), opts.MsgName, opts.MsgSigner, ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) diff --git a/ignite/templates/message/placeholders.go b/ignite/templates/message/placeholders.go deleted file mode 100644 index c6cf265b8a..0000000000 --- a/ignite/templates/message/placeholders.go +++ /dev/null @@ -1,6 +0,0 @@ -package message - -const ( - Placeholder = "// this line is used by starport scaffolding # 1" - Placeholder3 = "// this line is used by starport scaffolding # 3" -) diff --git a/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/genesis.go.plush b/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/genesis.go.plush index 04a3a06bfe..1dd1c745a6 100644 --- a/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/genesis.go.plush +++ b/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/genesis.go.plush @@ -8,7 +8,6 @@ import ( // InitGenesis initializes the module's state from a provided genesis state. func (k Keeper) InitGenesis(ctx context.Context, genState types.GenesisState) error { - // this line is used by starport scaffolding # genesis/module/init return k.Params.Set(ctx, genState.Params) } @@ -22,7 +21,6 @@ func (k Keeper) ExportGenesis(ctx context.Context) (*types.GenesisState, error) return nil, err } - // this line is used by starport scaffolding # genesis/module/export return genesis, nil } diff --git a/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/genesis_test.go.plush b/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/genesis_test.go.plush index 4bef36433a..a870f35c27 100644 --- a/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/genesis_test.go.plush +++ b/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/genesis_test.go.plush @@ -13,7 +13,6 @@ func TestGenesis(t *testing.T) { genesisState := types.GenesisState{ Params: types.DefaultParams(), <%= if (isIBC) { %>PortId: types.PortID,<% } %> - // this line is used by starport scaffolding # genesis/test/state } f := initFixture(t) @@ -28,5 +27,4 @@ func TestGenesis(t *testing.T) { <%= if (isIBC) { %>require.Equal(t, genesisState.PortId, got.PortId)<% } %> require.Equal(t, genesisState.Params, got.Params) - // this line is used by starport scaffolding # genesis/test/assert } \ No newline at end of file diff --git a/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/keeper.go.plush b/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/keeper.go.plush index 5d4aba712e..fc7cbad347 100644 --- a/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/keeper.go.plush +++ b/ignite/templates/module/create/files/base/x/{{moduleName}}/keeper/keeper.go.plush @@ -33,7 +33,6 @@ type Keeper struct { Schema collections.Schema Params collections.Item[types.Params] - // this line is used by starport scaffolding # collection/type <%= if (isIBC) { %> ibcKeeperFn func() *ibckeeper.Keeper @@ -68,7 +67,6 @@ func NewKeeper( <%= for (dependency) in dependencies { %> <%= toVariableName(dependency.KeeperName()) %>: <%= toVariableName(dependency.KeeperName()) %>,<% } %> Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)), - // this line is used by starport scaffolding # collection/instantiate } schema, err := sb.Build() diff --git a/ignite/templates/module/create/files/base/x/{{moduleName}}/module/depinject.go.plush b/ignite/templates/module/create/files/base/x/{{moduleName}}/module/depinject.go.plush index c1c6f72984..6c0a4884f9 100644 --- a/ignite/templates/module/create/files/base/x/{{moduleName}}/module/depinject.go.plush +++ b/ignite/templates/module/create/files/base/x/{{moduleName}}/module/depinject.go.plush @@ -12,8 +12,6 @@ import ( <%= if (isIBC) { %>capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper"<% } %> - // this line is used by starport scaffolding # 1 - "<%= modulePath %>/x/<%= moduleName %>/keeper" "<%= modulePath %>/x/<%= moduleName %>/types" ) diff --git a/ignite/templates/module/create/files/base/x/{{moduleName}}/module/module.go.plush b/ignite/templates/module/create/files/base/x/{{moduleName}}/module/module.go.plush index 475dce8ff5..1841525f7d 100644 --- a/ignite/templates/module/create/files/base/x/{{moduleName}}/module/module.go.plush +++ b/ignite/templates/module/create/files/base/x/{{moduleName}}/module/module.go.plush @@ -14,8 +14,6 @@ import ( <%= if (isIBC) { %>porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" "github.com/spf13/cobra"<% } %> - // this line is used by starport scaffolding # 1 - "<%= modulePath %>/x/<%= moduleName %>/keeper" "<%= modulePath %>/x/<%= moduleName %>/types" <%= if (isIBC) { %>"<%= modulePath %>/x/<%= moduleName %>/client/cli"<% } %> diff --git a/ignite/templates/module/create/files/base/x/{{moduleName}}/module/simulation.go.plush b/ignite/templates/module/create/files/base/x/{{moduleName}}/module/simulation.go.plush index efc0cc72f9..e7bd1b2790 100644 --- a/ignite/templates/module/create/files/base/x/{{moduleName}}/module/simulation.go.plush +++ b/ignite/templates/module/create/files/base/x/{{moduleName}}/module/simulation.go.plush @@ -21,10 +21,6 @@ var ( _ = sdk.AccAddress{} ) -const ( - // this line is used by starport scaffolding # simapp/module/const -) - // GenerateGenesisState creates a randomized GenState of the module. func (AppModule) GenerateGenesisState(simState *module.SimulationState) { accs := make([]string, len(simState.Accounts)) @@ -34,7 +30,6 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { <%= moduleName %>Genesis := types.GenesisState{ Params: types.DefaultParams(),<%= if (isIBC) { %> PortId: types.PortID,<% } %> - // this line is used by starport scaffolding # simapp/module/genesisState } simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(&<%= moduleName %>Genesis) } @@ -45,10 +40,8 @@ func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry) {} // ProposalMsgsX returns msgs used for governance proposals for simulations. func (am AppModule) ProposalMsgsX(weights simsx.WeightSource, reg simsx.Registry) { reg.Add(weights.Get("msg_update_params", 100), simulation.MsgUpdateParamsFactory()) - // this line is used by starport scaffolding # simapp/module/proposalSimulation } -// WeightedOperations returns the all the module operations with their respective weights. +// WeightedOperationsX returns the all the module operations with their respective weights. func (am AppModule) WeightedOperationsX(weights simsx.WeightSource, reg simsx.Registry) { - // this line is used by starport scaffolding # simapp/module/operation } diff --git a/ignite/templates/module/create/files/base/x/{{moduleName}}/types/codec.go.plush b/ignite/templates/module/create/files/base/x/{{moduleName}}/types/codec.go.plush index 301948bdb7..a19449d7dd 100644 --- a/ignite/templates/module/create/files/base/x/{{moduleName}}/types/codec.go.plush +++ b/ignite/templates/module/create/files/base/x/{{moduleName}}/types/codec.go.plush @@ -7,13 +7,9 @@ import ( cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" - - // this line is used by starport scaffolding # 1 ) func RegisterInterfaces(registrar registry.InterfaceRegistrar) { - // this line is used by starport scaffolding # 3 - registrar.RegisterImplementations((*sdk.Msg)(nil), &MsgUpdateParams{}, ) diff --git a/ignite/templates/module/create/files/base/x/{{moduleName}}/types/genesis.go.plush b/ignite/templates/module/create/files/base/x/{{moduleName}}/types/genesis.go.plush index 9c741f7f66..d7e9110548 100644 --- a/ignite/templates/module/create/files/base/x/{{moduleName}}/types/genesis.go.plush +++ b/ignite/templates/module/create/files/base/x/{{moduleName}}/types/genesis.go.plush @@ -3,7 +3,6 @@ package types // DefaultGenesis returns the default genesis state func DefaultGenesis() *GenesisState { return &GenesisState{ - // this line is used by starport scaffolding # genesis/types/default Params: DefaultParams(), } } @@ -11,7 +10,5 @@ func DefaultGenesis() *GenesisState { // Validate performs basic genesis state validation returning an error upon any // failure. func (gs GenesisState) Validate() error { - // this line is used by starport scaffolding # genesis/types/validate - return gs.Params.Validate() } diff --git a/ignite/templates/module/create/files/base/x/{{moduleName}}/types/genesis_test.go.plush b/ignite/templates/module/create/files/base/x/{{moduleName}}/types/genesis_test.go.plush index 8a53260a3e..064c6830c6 100644 --- a/ignite/templates/module/create/files/base/x/{{moduleName}}/types/genesis_test.go.plush +++ b/ignite/templates/module/create/files/base/x/{{moduleName}}/types/genesis_test.go.plush @@ -22,11 +22,9 @@ func TestGenesisState_Validate(t *testing.T) { desc: "valid genesis state", genState: &types.GenesisState{ <%= if (isIBC) { %>PortId: types.PortID,<% } %> - // this line is used by starport scaffolding # types/genesis/validField }, valid: true, }, - // this line is used by starport scaffolding # types/genesis/testcase } for _, tc := range tests { t.Run(tc.desc, func(t *testing.T) { diff --git a/ignite/templates/module/create/ibc.go b/ignite/templates/module/create/ibc.go index 3e5ad04196..e51b2d7050 100644 --- a/ignite/templates/module/create/ibc.go +++ b/ignite/templates/module/create/ibc.go @@ -16,7 +16,6 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/xstrings" "github.com/ignite/cli/v29/ignite/templates/field/plushhelpers" "github.com/ignite/cli/v29/ignite/templates/module" - "github.com/ignite/cli/v29/ignite/templates/typed" ) // NewIBC returns the generator to scaffold the implementation of the IBCModule interface inside a module. @@ -26,8 +25,8 @@ func NewIBC(replacer placeholder.Replacer, opts *CreateOptions) (*genny.Generato template = xgenny.NewEmbedWalker(fsIBC, "files/ibc/", opts.AppPath) ) - g.RunFn(genesisModify(replacer, opts)) - g.RunFn(genesisTypesModify(replacer, opts)) + g.RunFn(genesisModify(opts)) + g.RunFn(genesisTypesModify(opts)) g.RunFn(genesisProtoModify(opts)) g.RunFn(keysModify(replacer, opts)) @@ -56,7 +55,7 @@ func NewIBC(replacer placeholder.Replacer, opts *CreateOptions) (*genny.Generato return g, nil } -func genesisModify(replacer placeholder.Replacer, opts *CreateOptions) genny.RunFn { +func genesisModify(opts *CreateOptions) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/genesis.go") f, err := r.Disk.Find(path) @@ -74,8 +73,7 @@ func genesisModify(replacer placeholder.Replacer, opts *CreateOptions) genny.Run } // Genesis init - templateInit := `%s -k.SetPort(ctx, genState.PortId) + replacementModuleInit := `k.SetPort(ctx, genState.PortId) // Only try to bind to port if it is not already bound, since we may already own // port capability from capability InitGenesis if k.ShouldBound(ctx, genState.PortId) { @@ -86,21 +84,32 @@ if k.ShouldBound(ctx, genState.PortId) { return errors.Wrap(err, "could not claim port capability") } }` - replacementInit := fmt.Sprintf(templateInit, typed.PlaceholderGenesisModuleInit) - content = replacer.Replace(content, typed.PlaceholderGenesisModuleInit, replacementInit) + content, err = xast.ModifyFunction( + content, + "InitGenesis", + xast.AppendFuncCode(replacementModuleInit), + ) + if err != nil { + return err + } // Genesis export - templateExport := `genesis.PortId = k.GetPort(ctx) -%s` - replacementExport := fmt.Sprintf(templateExport, typed.PlaceholderGenesisModuleExport) - content = replacer.Replace(content, typed.PlaceholderGenesisModuleExport, replacementExport) + replacementModuleExport := "genesis.PortId = k.GetPort(ctx)" + content, err = xast.ModifyFunction( + content, + "ExportGenesis", + xast.AppendFuncCode(replacementModuleExport), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisTypesModify(replacer placeholder.Replacer, opts *CreateOptions) genny.RunFn { +func genesisTypesModify(opts *CreateOptions) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/genesis.go") f, err := r.Disk.Find(path) @@ -118,19 +127,28 @@ func genesisTypesModify(replacer placeholder.Replacer, opts *CreateOptions) genn } // Default genesis - templateDefault := `PortId: PortID, -%s` - replacementDefault := fmt.Sprintf(templateDefault, typed.PlaceholderGenesisTypesDefault) - content = replacer.Replace(content, typed.PlaceholderGenesisTypesDefault, replacementDefault) + content, err = xast.ModifyFunction( + content, + "DefaultGenesis", + xast.AppendFuncStruct("GenesisState", "PortId", "PortID", -1), + ) + if err != nil { + return err + } // Validate genesis // PlaceholderIBCGenesisTypeValidate - templateValidate := `if err := host.PortIdentifierValidator(gs.PortId); err != nil { + replacementTypesValidate := `if err := host.PortIdentifierValidator(gs.PortId); err != nil { return err -} -%s` - replacementValidate := fmt.Sprintf(templateValidate, typed.PlaceholderGenesisTypesValidate) - content = replacer.Replace(content, typed.PlaceholderGenesisTypesValidate, replacementValidate) +}` + content, err = xast.ModifyFunction( + content, + "Validate", + xast.AppendFuncCode(replacementTypesValidate), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) diff --git a/ignite/templates/module/create/msgserver.go b/ignite/templates/module/create/msgserver.go index d2e2b8a9f0..a5d5bc0e08 100644 --- a/ignite/templates/module/create/msgserver.go +++ b/ignite/templates/module/create/msgserver.go @@ -9,6 +9,7 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/gomodulepath" "github.com/ignite/cli/v29/ignite/pkg/placeholder" + "github.com/ignite/cli/v29/ignite/pkg/xast" "github.com/ignite/cli/v29/ignite/pkg/xgenny" "github.com/ignite/cli/v29/ignite/templates/field/plushhelpers" "github.com/ignite/cli/v29/ignite/templates/module" @@ -64,11 +65,14 @@ func codecPath(replacer placeholder.Replacer, appPath, moduleName string) genny. content := replacer.Replace(f.String(), oldImport, newImport) // Add RegisterMsgServiceDesc method call - template := `%[1]v - -msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)` - replacement := fmt.Sprintf(template, module.Placeholder3) - content = replacer.Replace(content, module.Placeholder3, replacement) + content, err = xast.ModifyFunction( + content, + "RegisterInterfaces", + xast.AppendFuncCode("msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)"), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } diff --git a/ignite/templates/module/create/params.go b/ignite/templates/module/create/params.go index d6b89a4103..e8c2575f9e 100644 --- a/ignite/templates/module/create/params.go +++ b/ignite/templates/module/create/params.go @@ -81,7 +81,7 @@ func paramsTypesModify(opts ParamsOptions) genny.RunFn { newParamsModifier = append( newParamsModifier, xast.AppendFuncParams(param.Name.LowerCamel, param.DataType(), -1), - xast.AppendInsideFuncStruct( + xast.AppendFuncStruct( "Params", param.Name.UpperCamel, param.Name.LowerCamel, diff --git a/ignite/templates/module/placeholders.go b/ignite/templates/module/placeholders.go index 84c4040443..7bc358efb8 100644 --- a/ignite/templates/module/placeholders.go +++ b/ignite/templates/module/placeholders.go @@ -2,9 +2,6 @@ package module //nolint:godot const ( - Placeholder = "// this line is used by starport scaffolding # 1" - Placeholder3 = "// this line is used by starport scaffolding # 3" - // Placeholders in app.go PlaceholderSgAppKeeperDeclaration = "// this line is used by starport scaffolding # stargate/app/keeperDeclaration" PlaceholderSgAppInitGenesis = "// this line is used by starport scaffolding # stargate/app/initGenesis" @@ -17,10 +14,4 @@ const ( PlaceholderIBCKeysName = "// this line is used by starport scaffolding # ibc/keys/name" PlaceholderIBCKeysPort = "// this line is used by starport scaffolding # ibc/keys/port" PlaceholderIBCNewModule = "// this line is used by starport scaffolding # ibc/app/module" - - // Genesis test - PlaceholderTypesGenesisTestcase = "// this line is used by starport scaffolding # types/genesis/testcase" - PlaceholderTypesGenesisValidField = "// this line is used by starport scaffolding # types/genesis/validField" - PlaceholderGenesisTestState = "// this line is used by starport scaffolding # genesis/test/state" - PlaceholderGenesisTestAssert = "// this line is used by starport scaffolding # genesis/test/assert" ) diff --git a/ignite/templates/typed/list/genesis.go b/ignite/templates/typed/list/genesis.go index bf60552b23..48fa10663c 100644 --- a/ignite/templates/typed/list/genesis.go +++ b/ignite/templates/typed/list/genesis.go @@ -7,19 +7,17 @@ import ( "github.com/gobuffalo/genny/v2" "github.com/ignite/cli/v29/ignite/pkg/errors" - "github.com/ignite/cli/v29/ignite/pkg/placeholder" "github.com/ignite/cli/v29/ignite/pkg/protoanalysis/protoutil" "github.com/ignite/cli/v29/ignite/pkg/xast" - "github.com/ignite/cli/v29/ignite/templates/module" "github.com/ignite/cli/v29/ignite/templates/typed" ) -func genesisModify(replacer placeholder.Replacer, opts *typed.Options, g *genny.Generator) { +func genesisModify(opts *typed.Options, g *genny.Generator) { g.RunFn(genesisProtoModify(opts)) - g.RunFn(genesisTypesModify(replacer, opts)) - g.RunFn(genesisModuleModify(replacer, opts)) - g.RunFn(genesisTestsModify(replacer, opts)) - g.RunFn(genesisTypesTestsModify(replacer, opts)) + g.RunFn(genesisTypesModify(opts)) + g.RunFn(genesisModuleModify(opts)) + g.RunFn(genesisTestsModify(opts)) + g.RunFn(genesisTypesTestsModify(opts)) } // Modifies the genesis.proto file to add a new field. @@ -67,7 +65,7 @@ func genesisProtoModify(opts *typed.Options) genny.RunFn { } } -func genesisTypesModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisTypesModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/genesis.go") f, err := r.Disk.Find(path) @@ -80,42 +78,49 @@ func genesisTypesModify(replacer placeholder.Replacer, opts *typed.Options) genn return err } - templateTypesDefault := `%[2]vList: []%[2]v{}, -%[1]v` - replacementTypesDefault := fmt.Sprintf( - templateTypesDefault, - typed.PlaceholderGenesisTypesDefault, - opts.TypeName.UpperCamel, - ) - content = replacer.Replace(content, typed.PlaceholderGenesisTypesDefault, replacementTypesDefault) + // add parameter to the struct into the new method. + content, err = xast.ModifyFunction(content, "DefaultGenesis", xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vList", opts.TypeName.UpperCamel), + fmt.Sprintf("[]%[1]v{}", opts.TypeName.UpperCamel), + -1, + )) + if err != nil { + return err + } - templateTypesValidate := `// Check for duplicated ID in %[2]v -%[2]vIdMap := make(map[uint64]bool) -%[2]vCount := gs.Get%[3]vCount() -for _, elem := range gs.%[3]vList { - if _, ok := %[2]vIdMap[elem.Id]; ok { - return fmt.Errorf("duplicated id for %[2]v") + templateTypesValidate := `// Check for duplicated ID in %[1]v +%[1]vIdMap := make(map[uint64]bool) +%[1]vCount := gs.Get%[2]vCount() +for _, elem := range gs.%[2]vList { + if _, ok := %[1]vIdMap[elem.Id]; ok { + return fmt.Errorf("duplicated id for %[1]v") } - if elem.Id >= %[2]vCount { - return fmt.Errorf("%[2]v id should be lower or equal than the last id") + if elem.Id >= %[1]vCount { + return fmt.Errorf("%[1]v id should be lower or equal than the last id") } - %[2]vIdMap[elem.Id] = true -} -%[1]v` + %[1]vIdMap[elem.Id] = true +}` replacementTypesValidate := fmt.Sprintf( templateTypesValidate, - typed.PlaceholderGenesisTypesValidate, opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, ) - content = replacer.Replace(content, typed.PlaceholderGenesisTypesValidate, replacementTypesValidate) + content, err = xast.ModifyFunction( + content, + "Validate", + xast.AppendFuncCode(replacementTypesValidate), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisModuleModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisModuleModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/genesis.go") f, err := r.Disk.Find(path) @@ -123,54 +128,63 @@ func genesisModuleModify(replacer placeholder.Replacer, opts *typed.Options) gen return err } - templateModuleInit := `// Set all the %[2]v -for _, elem := range genState.%[3]vList { - if err := k.%[3]v.Set(ctx, elem.Id, elem); err != nil { + templateModuleInit := `// Set all the %[1]v +for _, elem := range genState.%[2]vList { + if err := k.%[2]v.Set(ctx, elem.Id, elem); err != nil { return err } } -// Set %[2]v count -if err := k.%[3]vSeq.Set(ctx, genState.%[3]vCount); err != nil { +// Set %[1]v count +if err := k.%[2]vSeq.Set(ctx, genState.%[2]vCount); err != nil { return err -} -%[1]v` +}` replacementModuleInit := fmt.Sprintf( templateModuleInit, - typed.PlaceholderGenesisModuleInit, opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, ) - content := replacer.Replace(f.String(), typed.PlaceholderGenesisModuleInit, replacementModuleInit) + content, err := xast.ModifyFunction( + f.String(), + "InitGenesis", + xast.AppendFuncCode(replacementModuleInit), + ) + if err != nil { + return err + } templateModuleExport := ` -err = k.%[2]v.Walk(ctx, nil, func(key uint64, elem types.%[2]v) (bool, error) { - genesis.%[2]vList = append(genesis.%[2]vList, elem) +err = k.%[1]v.Walk(ctx, nil, func(key uint64, elem types.%[1]v) (bool, error) { + genesis.%[1]vList = append(genesis.%[1]vList, elem) return false, nil }) if err != nil { return nil, err } -genesis.%[2]vCount, err = k.%[2]vSeq.Peek(ctx) +genesis.%[1]vCount, err = k.%[1]vSeq.Peek(ctx) if err != nil { return nil, err -} - -%[1]v` +}` replacementModuleExport := fmt.Sprintf( templateModuleExport, - typed.PlaceholderGenesisModuleExport, opts.TypeName.UpperCamel, ) - content = replacer.Replace(content, typed.PlaceholderGenesisModuleExport, replacementModuleExport) + content, err = xast.ModifyFunction( + content, + "ExportGenesis", + xast.AppendFuncCode(replacementModuleExport), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisTestsModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisTestsModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/genesis_test.go") f, err := r.Disk.Find(path) @@ -178,39 +192,37 @@ func genesisTestsModify(replacer placeholder.Replacer, opts *typed.Options) genn return err } - templateState := `%[2]vList: []types.%[2]v{ - { - Id: 0, - }, - { - Id: 1, - }, - }, - %[2]vCount: 2, - %[1]v` - replacementValid := fmt.Sprintf( - templateState, - module.PlaceholderGenesisTestState, - opts.TypeName.UpperCamel, - ) - content := replacer.Replace(f.String(), module.PlaceholderGenesisTestState, replacementValid) + replacementAssert := fmt.Sprintf(`require.ElementsMatch(t, genesisState.%[1]vList, got.%[1]vList) +require.Equal(t, genesisState.%[1]vCount, got.%[1]vCount)`, opts.TypeName.UpperCamel) - templateAssert := `require.ElementsMatch(t, genesisState.%[2]vList, got.%[2]vList) -require.Equal(t, genesisState.%[2]vCount, got.%[2]vCount) -%[1]v` - replacementTests := fmt.Sprintf( - templateAssert, - module.PlaceholderGenesisTestAssert, - opts.TypeName.UpperCamel, + // add parameter to the struct into the new method. + content, err := xast.ModifyFunction( + f.String(), + "TestGenesis", + xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vList", opts.TypeName.UpperCamel), + fmt.Sprintf("[]types.%[1]v{{ Id: 0 }, { Id: 1 }}", opts.TypeName.UpperCamel), + -1, + ), + xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vCount", opts.TypeName.UpperCamel), + "2", + -1, + ), + xast.AppendFuncCode(replacementAssert), ) - content = replacer.Replace(content, module.PlaceholderGenesisTestAssert, replacementTests) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisTypesTestsModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisTypesTestsModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/genesis_test.go") f, err := r.Disk.Find(path) @@ -218,27 +230,10 @@ func genesisTypesTestsModify(replacer placeholder.Replacer, opts *typed.Options) return err } - templateValid := `%[2]vList: []types.%[2]v{ - { - Id: 0, - }, - { - Id: 1, - }, -}, -%[2]vCount: 2, -%[1]v` - replacementValid := fmt.Sprintf( - templateValid, - module.PlaceholderTypesGenesisValidField, - opts.TypeName.UpperCamel, - ) - content := replacer.Replace(f.String(), module.PlaceholderTypesGenesisValidField, replacementValid) - - templateTests := `{ - desc: "duplicated %[2]v", + templateTestDuplicated := `{ + desc: "duplicated %[1]v", genState: &types.GenesisState{ - %[3]vList: []types.%[3]v{ + %[2]vList: []types.%[2]v{ { Id: 0, }, @@ -248,27 +243,53 @@ func genesisTypesTestsModify(replacer placeholder.Replacer, opts *typed.Options) }, }, valid: false, -}, -{ - desc: "invalid %[2]v count", +}` + replacementTestDuplicated := fmt.Sprintf( + templateTestDuplicated, + opts.TypeName.LowerCamel, + opts.TypeName.UpperCamel, + ) + + templateTestInvalidCount := `{ + desc: "invalid %[1]v count", genState: &types.GenesisState{ - %[3]vList: []types.%[3]v{ + %[2]vList: []types.%[2]v{ { Id: 1, }, }, - %[3]vCount: 0, + %[2]vCount: 0, }, valid: false, -}, -%[1]v` - replacementTests := fmt.Sprintf( - templateTests, - module.PlaceholderTypesGenesisTestcase, +}` + replacementInvalidCount := fmt.Sprintf( + templateTestInvalidCount, opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, ) - content = replacer.Replace(content, module.PlaceholderTypesGenesisTestcase, replacementTests) + + // add parameter to the struct into the new method. + content, err := xast.ModifyFunction( + f.String(), + "TestGenesisState_Validate", + xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vList", opts.TypeName.UpperCamel), + fmt.Sprintf("[]types.%[1]v{{ Id: 0 }, { Id: 1 }}", opts.TypeName.UpperCamel), + -1, + ), + xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vCount", opts.TypeName.UpperCamel), + "2", + -1, + ), + xast.AppendFuncTestCase(replacementTestDuplicated), + xast.AppendFuncTestCase(replacementInvalidCount), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) diff --git a/ignite/templates/typed/list/list.go b/ignite/templates/typed/list/list.go index c3aa8f94f8..0ed1cf6843 100644 --- a/ignite/templates/typed/list/list.go +++ b/ignite/templates/typed/list/list.go @@ -14,6 +14,7 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/gomodulepath" "github.com/ignite/cli/v29/ignite/pkg/placeholder" "github.com/ignite/cli/v29/ignite/pkg/protoanalysis/protoutil" + "github.com/ignite/cli/v29/ignite/pkg/xast" "github.com/ignite/cli/v29/ignite/pkg/xgenny" "github.com/ignite/cli/v29/ignite/templates/typed" ) @@ -53,20 +54,20 @@ func NewGenerator(replacer placeholder.Replacer, opts *typed.Options) (*genny.Ge g.RunFn(protoQueryModify(opts)) g.RunFn(typesKeyModify(opts)) - g.RunFn(keeperModify(replacer, opts)) + g.RunFn(keeperModify(opts)) g.RunFn(clientCliQueryModify(replacer, opts)) // Genesis modifications - genesisModify(replacer, opts, g) + genesisModify(opts, g) if !opts.NoMessage { // Modifications for new messages g.RunFn(protoTxModify(opts)) - g.RunFn(typesCodecModify(replacer, opts)) + g.RunFn(typesCodecModify(opts)) g.RunFn(clientCliTxModify(replacer, opts)) if !opts.NoSimulation { - g.RunFn(moduleSimulationModify(replacer, opts)) + g.RunFn(moduleSimulationModify(opts)) if err := typed.Box(simappTemplate, opts, g); err != nil { return nil, err } @@ -307,7 +308,7 @@ var ( } // keeperModify modifies the keeper to add a new collections item type. -func keeperModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func keeperModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/keeper.go") f, err := r.Disk.Find(path) @@ -315,33 +316,55 @@ func keeperModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunF return err } - templateKeeperType := `%[2]vSeq collections.Sequence - %[2]v collections.Map[uint64, types.%[2]v] - %[1]v` - replacementModuleType := fmt.Sprintf( - templateKeeperType, - typed.PlaceholderCollectionType, - opts.TypeName.UpperCamel, + content, err := xast.ModifyStruct( + f.String(), + "Keeper", + xast.AppendStructValue( + fmt.Sprintf("%[1]vSeq", opts.TypeName.UpperCamel), + "collections.Sequence", + ), + xast.AppendStructValue( + opts.TypeName.UpperCamel, + fmt.Sprintf("collections.Map[uint64, types.%[1]v]", opts.TypeName.UpperCamel), + ), ) - content := replacer.Replace(f.String(), typed.PlaceholderCollectionType, replacementModuleType) - - templateKeeperInstantiate := `%[2]vSeq: collections.NewSequence(sb, types.%[2]vCountKey, "%[3]v_seq"), - %[2]v: collections.NewMap(sb, types.%[2]vKey, "%[3]v", collections.Uint64Key, codec.CollValue[types.%[2]v](cdc)), - %[1]v` - replacementInstantiate := fmt.Sprintf( - templateKeeperInstantiate, - typed.PlaceholderCollectionInstantiate, - opts.TypeName.UpperCamel, - opts.TypeName.LowerCamel, + if err != nil { + return err + } + + // add parameter to the struct into the new keeper method. + content, err = xast.ModifyFunction( + content, + "NewKeeper", + xast.AppendFuncStruct( + "Keeper", + fmt.Sprintf("%[1]vSeq", opts.TypeName.UpperCamel), + fmt.Sprintf(`collections.NewSequence(sb, types.%[1]vCountKey, "%[2]v_seq")`, + opts.TypeName.UpperCamel, + opts.TypeName.LowerCamel, + ), + -1, + ), + xast.AppendFuncStruct( + "Keeper", + opts.TypeName.UpperCamel, + fmt.Sprintf(`collections.NewMap(sb, types.%[1]vKey, "%[2]v", collections.Uint64Key, codec.CollValue[types.%[1]v](cdc))`, + opts.TypeName.UpperCamel, + opts.TypeName.LowerCamel, + ), + -1, + ), ) - content = replacer.Replace(content, typed.PlaceholderCollectionInstantiate, replacementInstantiate) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func typesCodecModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func typesCodecModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/codec.go") f, err := r.Disk.Find(path) @@ -350,18 +373,26 @@ func typesCodecModify(replacer placeholder.Replacer, opts *typed.Options) genny. } // Import - replacementImport := `sdk "github.com/cosmos/cosmos-sdk/types"` - content := replacer.ReplaceOnce(f.String(), typed.Placeholder, replacementImport) + content, err := xast.AppendImports(f.String(), xast.WithLastNamedImport("sdk", "github.com/cosmos/cosmos-sdk/types")) + if err != nil { + return err + } // Interface templateInterface := `registrar.RegisterImplementations((*sdk.Msg)(nil), - &MsgCreate%[2]v{}, - &MsgUpdate%[2]v{}, - &MsgDelete%[2]v{}, -) -%[1]v` - replacementInterface := fmt.Sprintf(templateInterface, typed.Placeholder3, opts.TypeName.UpperCamel) - content = replacer.Replace(content, typed.Placeholder3, replacementInterface) + &MsgCreate%[1]v{}, + &MsgUpdate%[1]v{}, + &MsgDelete%[1]v{}, +)` + replacementInterface := fmt.Sprintf(templateInterface, opts.TypeName.UpperCamel) + content, err = xast.ModifyFunction( + content, + "RegisterInterfaces", + xast.AppendFuncAtLine(replacementInterface, 0), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) diff --git a/ignite/templates/typed/list/simulation.go b/ignite/templates/typed/list/simulation.go index 3dcf1a2d3c..56b17f8bdd 100644 --- a/ignite/templates/typed/list/simulation.go +++ b/ignite/templates/typed/list/simulation.go @@ -6,11 +6,11 @@ import ( "github.com/gobuffalo/genny/v2" - "github.com/ignite/cli/v29/ignite/pkg/placeholder" + "github.com/ignite/cli/v29/ignite/pkg/xast" "github.com/ignite/cli/v29/ignite/templates/typed" ) -func moduleSimulationModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func moduleSimulationModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "module/simulation.go") f, err := r.Disk.Find(path) @@ -22,32 +22,39 @@ func moduleSimulationModify(replacer placeholder.Replacer, opts *typed.Options) msgField := fmt.Sprintf("%s: sample.AccAddress(),\n", opts.MsgSigner.UpperCamel) // simulation genesis state - templateGs := ` %[2]vList: []types.%[2]v{ - { - Id: 0, - %[3]v - }, - { - Id: 1, - %[3]v - }, - }, - %[2]vCount: 2, - %[1]v` - replacementGs := fmt.Sprintf( - templateGs, - typed.PlaceholderSimappGenesisState, - opts.TypeName.UpperCamel, - msgField, + content, err := xast.ModifyFunction( + f.String(), + "GenerateGenesisState", + xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vList", opts.TypeName.UpperCamel), + fmt.Sprintf( + "[]types.%[1]v{{ Id: 0, %[2]v }, { Id: 1, %[2]v }}", + opts.TypeName.UpperCamel, + msgField, + ), + -1, + ), + xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vCount", opts.TypeName.UpperCamel), + "2", + -1, + ), ) - content := replacer.Replace(f.String(), typed.PlaceholderSimappGenesisState, replacementGs) - content = typed.ModuleSimulationMsgModify( - replacer, + if err != nil { + return err + } + + content, err = typed.ModuleSimulationMsgModify( content, opts.TypeName, opts.MsgSigner, "Create", "Update", "Delete", ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) diff --git a/ignite/templates/typed/map/map.go b/ignite/templates/typed/map/map.go index 2dd0408242..bfa5b50b23 100644 --- a/ignite/templates/typed/map/map.go +++ b/ignite/templates/typed/map/map.go @@ -16,7 +16,6 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/xast" "github.com/ignite/cli/v29/ignite/pkg/xgenny" "github.com/ignite/cli/v29/ignite/templates/field/datatype" - "github.com/ignite/cli/v29/ignite/templates/module" "github.com/ignite/cli/v29/ignite/templates/typed" ) @@ -77,22 +76,22 @@ func NewGenerator(replacer placeholder.Replacer, opts *typed.Options) (*genny.Ge ) g.RunFn(protoRPCModify(opts)) - g.RunFn(keeperModify(replacer, opts)) + g.RunFn(keeperModify(opts)) g.RunFn(clientCliQueryModify(replacer, opts)) g.RunFn(genesisProtoModify(opts)) - g.RunFn(genesisTypesModify(replacer, opts)) - g.RunFn(genesisModuleModify(replacer, opts)) - g.RunFn(genesisTestsModify(replacer, opts)) - g.RunFn(genesisTypesTestsModify(replacer, opts)) + g.RunFn(genesisTypesModify(opts)) + g.RunFn(genesisModuleModify(opts)) + g.RunFn(genesisTestsModify(opts)) + g.RunFn(genesisTypesTestsModify(opts)) // Modifications for new messages if !opts.NoMessage { g.RunFn(protoTxModify(opts)) g.RunFn(clientCliTxModify(replacer, opts)) - g.RunFn(typesCodecModify(replacer, opts)) + g.RunFn(typesCodecModify(opts)) if !opts.NoSimulation { - g.RunFn(moduleSimulationModify(replacer, opts)) + g.RunFn(moduleSimulationModify(opts)) if err := typed.Box(simappTemplate, opts, g); err != nil { return nil, err } @@ -117,7 +116,7 @@ func NewGenerator(replacer placeholder.Replacer, opts *typed.Options) (*genny.Ge } // keeperModify modifies the keeper to add a new collections map type. -func keeperModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func keeperModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/keeper.go") f, err := r.Disk.Find(path) @@ -125,26 +124,36 @@ func keeperModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunF return err } - templateKeeperType := `%[2]v collections.Map[%[3]v, types.%[2]v] - %[1]v` - replacementModuleType := fmt.Sprintf( - templateKeeperType, - typed.PlaceholderCollectionType, - opts.TypeName.UpperCamel, - opts.Index.DataType(), + content, err := xast.ModifyStruct( + f.String(), + "Keeper", + xast.AppendStructValue( + opts.TypeName.UpperCamel, + fmt.Sprintf("collections.Map[%[1]v, types.%[2]v]", opts.Index.DataType(), opts.TypeName.UpperCamel), + ), ) - content := replacer.Replace(f.String(), typed.PlaceholderCollectionType, replacementModuleType) + if err != nil { + return err + } - templateKeeperInstantiate := `%[2]v: collections.NewMap(sb, types.%[2]vKey, "%[3]v", %[4]v, codec.CollValue[types.%[2]v](cdc)), - %[1]v` - replacementInstantiate := fmt.Sprintf( - templateKeeperInstantiate, - typed.PlaceholderCollectionInstantiate, - opts.TypeName.UpperCamel, - opts.TypeName.LowerCamel, - opts.Index.CollectionsKeyValueType(), + // add parameter to the struct into the new keeper method. + content, err = xast.ModifyFunction( + content, + "NewKeeper", + xast.AppendFuncStruct( + "Keeper", + opts.TypeName.UpperCamel, + fmt.Sprintf(`collections.NewMap(sb, types.%[1]vKey, "%[2]v", %[3]v, codec.CollValue[types.%[1]v](cdc))`, + opts.TypeName.UpperCamel, + opts.TypeName.LowerCamel, + opts.Index.CollectionsKeyValueType(), + ), + -1, + ), ) - content = replacer.Replace(content, typed.PlaceholderCollectionInstantiate, replacementInstantiate) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) @@ -342,7 +351,7 @@ func genesisProtoModify(opts *typed.Options) genny.RunFn { } } -func genesisTypesModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisTypesModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/genesis.go") f, err := r.Disk.Find(path) @@ -355,44 +364,49 @@ func genesisTypesModify(replacer placeholder.Replacer, opts *typed.Options) genn return err } - templateTypesDefault := `%[2]vList: []%[2]v{}, -%[1]v` - replacementTypesDefault := fmt.Sprintf( - templateTypesDefault, - typed.PlaceholderGenesisTypesDefault, - opts.TypeName.UpperCamel, - ) - content = replacer.Replace(content, typed.PlaceholderGenesisTypesDefault, replacementTypesDefault) + content, err = xast.ModifyFunction(content, "DefaultGenesis", xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vList", opts.TypeName.UpperCamel), + fmt.Sprintf("[]%[1]v{}", opts.TypeName.UpperCamel), + -1, + )) + if err != nil { + return err + } // lines of code to call the key function with the indexes of the element keyCall := fmt.Sprintf(`fmt.Sprint(elem.%s)`, opts.Index.Name.UpperCamel) + templateTypesValidate := `// Check for duplicated index in %[1]v +%[1]vIndexMap := make(map[string]struct{}) - templateTypesValidate := `// Check for duplicated index in %[2]v -%[2]vIndexMap := make(map[string]struct{}) - -for _, elem := range gs.%[3]vList { - index := %[4]v - if _, ok := %[2]vIndexMap[index]; ok { - return fmt.Errorf("duplicated index for %[2]v") +for _, elem := range gs.%[2]vList { + index := %[3]v + if _, ok := %[1]vIndexMap[index]; ok { + return fmt.Errorf("duplicated index for %[1]v") } - %[2]vIndexMap[index] = struct{}{} -} -%[1]v` + %[1]vIndexMap[index] = struct{}{} +}` replacementTypesValidate := fmt.Sprintf( templateTypesValidate, - typed.PlaceholderGenesisTypesValidate, opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, keyCall, ) - content = replacer.Replace(content, typed.PlaceholderGenesisTypesValidate, replacementTypesValidate) + content, err = xast.ModifyFunction( + content, + "Validate", + xast.AppendFuncCode(replacementTypesValidate), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisModuleModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisModuleModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/genesis.go") f, err := r.Disk.Find(path) @@ -400,43 +414,53 @@ func genesisModuleModify(replacer placeholder.Replacer, opts *typed.Options) gen return err } - templateModuleInit := `// Set all the %[2]v -for _, elem := range genState.%[3]vList { - if err := k.%[3]v.Set(ctx, elem.%[4]v, elem); err != nil { + templateModuleInit := `// Set all the %[1]v +for _, elem := range genState.%[2]vList { + if err := k.%[2]v.Set(ctx, elem.%[3]v, elem); err != nil { return err } -} -%[1]v` +}` replacementModuleInit := fmt.Sprintf( templateModuleInit, - typed.PlaceholderGenesisModuleInit, opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, opts.Index.Name.UpperCamel, ) - content := replacer.Replace(f.String(), typed.PlaceholderGenesisModuleInit, replacementModuleInit) + content, err := xast.ModifyFunction( + f.String(), + "InitGenesis", + xast.AppendFuncCode(replacementModuleInit), + ) + if err != nil { + return err + } - templateModuleExport := `if err := k.%[2]v.Walk(ctx, nil, func(_ %[3]v, val types.%[2]v) (stop bool, err error) { - genesis.%[2]vList = append(genesis.%[2]vList, val) + templateModuleExport := `if err := k.%[1]v.Walk(ctx, nil, func(_ %[2]v, val types.%[1]v) (stop bool, err error) { + genesis.%[1]vList = append(genesis.%[1]vList, val) return false, nil }); err != nil { return nil, err - } -%[1]v` + }` replacementModuleExport := fmt.Sprintf( templateModuleExport, - typed.PlaceholderGenesisModuleExport, opts.TypeName.UpperCamel, opts.Index.DataType(), ) - content = replacer.Replace(content, typed.PlaceholderGenesisModuleExport, replacementModuleExport) + content, err = xast.ModifyFunction( + content, + "ExportGenesis", + xast.AppendFuncCode(replacementModuleExport), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisTestsModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisTestsModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/genesis_test.go") f, err := r.Disk.Find(path) @@ -450,37 +474,33 @@ func genesisTestsModify(replacer placeholder.Replacer, opts *typed.Options) genn sampleIndexes[i] = opts.Index.GenesisArgs(i) } - templateState := `%[2]vList: []types.%[2]v{ - { - %[3]v}, - { - %[4]v}, - }, - %[1]v` - replacementState := fmt.Sprintf( - templateState, - module.PlaceholderGenesisTestState, - opts.TypeName.UpperCamel, - sampleIndexes[0], - sampleIndexes[1], - ) - content := replacer.Replace(f.String(), module.PlaceholderGenesisTestState, replacementState) - - templateAssert := `require.ElementsMatch(t, genesisState.%[2]vList, got.%[2]vList) -%[1]v` - replacementTests := fmt.Sprintf( - templateAssert, - module.PlaceholderGenesisTestAssert, - opts.TypeName.UpperCamel, + // add parameter to the struct into the new method. + content, err := xast.ModifyFunction( + f.String(), + "TestGenesis", + xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vList", opts.TypeName.UpperCamel), + fmt.Sprintf( + "[]types.%[1]v{{ %[2]v }, { %[3]v }}", + opts.TypeName.UpperCamel, + sampleIndexes[0], + sampleIndexes[1], + ), + -1, + ), + xast.AppendFuncCode(fmt.Sprintf("require.ElementsMatch(t, genesisState.%[1]vList, got.%[1]vList)", opts.TypeName.UpperCamel)), ) - content = replacer.Replace(content, module.PlaceholderGenesisTestAssert, replacementTests) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisTypesTestsModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisTypesTestsModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/genesis_test.go") f, err := r.Disk.Find(path) @@ -494,43 +514,45 @@ func genesisTypesTestsModify(replacer placeholder.Replacer, opts *typed.Options) sampleIndexes[i] = opts.Index.GenesisArgs(i) } - templateValid := `%[2]vList: []types.%[2]v{ - { - %[3]v}, - { - %[4]v}, -}, -%[1]v` - replacementValid := fmt.Sprintf( - templateValid, - module.PlaceholderTypesGenesisValidField, - opts.TypeName.UpperCamel, - sampleIndexes[0], - sampleIndexes[1], - ) - content := replacer.Replace(f.String(), module.PlaceholderTypesGenesisValidField, replacementValid) - templateDuplicated := `{ - desc: "duplicated %[2]v", + desc: "duplicated %[1]v", genState: &types.GenesisState{ - %[3]vList: []types.%[3]v{ + %[2]vList: []types.%[2]v{ { - %[4]v}, + %[3]v}, { - %[4]v}, + %[3]v}, }, }, valid: false, -}, -%[1]v` +}` replacementDuplicated := fmt.Sprintf( templateDuplicated, - module.PlaceholderTypesGenesisTestcase, opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, sampleIndexes[0], ) - content = replacer.Replace(content, module.PlaceholderTypesGenesisTestcase, replacementDuplicated) + + // add parameter to the struct into the new method. + content, err := xast.ModifyFunction( + f.String(), + "TestGenesisState_Validate", + xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vList", opts.TypeName.UpperCamel), + fmt.Sprintf( + "[]types.%[1]v{{ %[2]v }, { %[3]v }}", + opts.TypeName.UpperCamel, + sampleIndexes[0], + sampleIndexes[1], + ), + -1, + ), + xast.AppendFuncTestCase(replacementDuplicated), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) @@ -695,7 +717,7 @@ func clientCliTxModify(replacer placeholder.Replacer, opts *typed.Options) genny } } -func typesCodecModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func typesCodecModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/codec.go") f, err := r.Disk.Find(path) @@ -703,25 +725,30 @@ func typesCodecModify(replacer placeholder.Replacer, opts *typed.Options) genny. return err } - content := f.String() - // Import - replacementImport := `sdk "github.com/cosmos/cosmos-sdk/types"` - content = replacer.ReplaceOnce(content, typed.Placeholder, replacementImport) + content, err := xast.AppendImports(f.String(), xast.WithLastNamedImport("sdk", "github.com/cosmos/cosmos-sdk/types")) + if err != nil { + return err + } // Interface templateInterface := `registrar.RegisterImplementations((*sdk.Msg)(nil), - &MsgCreate%[2]v{}, - &MsgUpdate%[2]v{}, - &MsgDelete%[2]v{}, -) -%[1]v` + &MsgCreate%[1]v{}, + &MsgUpdate%[1]v{}, + &MsgDelete%[1]v{}, +)` replacementInterface := fmt.Sprintf( templateInterface, - typed.Placeholder3, opts.TypeName.UpperCamel, ) - content = replacer.Replace(content, typed.Placeholder3, replacementInterface) + content, err = xast.ModifyFunction( + content, + "RegisterInterfaces", + xast.AppendFuncAtLine(replacementInterface, 0), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) diff --git a/ignite/templates/typed/map/simulation.go b/ignite/templates/typed/map/simulation.go index f9bc4da530..ccd96dc1a1 100644 --- a/ignite/templates/typed/map/simulation.go +++ b/ignite/templates/typed/map/simulation.go @@ -6,11 +6,11 @@ import ( "github.com/gobuffalo/genny/v2" - "github.com/ignite/cli/v29/ignite/pkg/placeholder" + "github.com/ignite/cli/v29/ignite/pkg/xast" "github.com/ignite/cli/v29/ignite/templates/typed" ) -func moduleSimulationModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func moduleSimulationModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "module/simulation.go") f, err := r.Disk.Find(path) @@ -26,29 +26,34 @@ func moduleSimulationModify(replacer placeholder.Replacer, opts *typed.Options) } // simulation genesis state - templateGs := `%[2]vList: []types.%[2]v{ - { - %[3]v}, - { - %[4]v}, - }, - %[1]v` - replacementGs := fmt.Sprintf( - templateGs, - typed.PlaceholderSimappGenesisState, - opts.TypeName.UpperCamel, - sampleIndexes[0], - sampleIndexes[1], + content, err := xast.ModifyFunction( + f.String(), + "GenerateGenesisState", + xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]vList", opts.TypeName.UpperCamel), + fmt.Sprintf( + "[]types.%[1]v{{ %[2]v }, { %[3]v }}", + opts.TypeName.UpperCamel, + sampleIndexes[0], + sampleIndexes[1], + ), + -1, + ), ) - content := replacer.Replace(f.String(), typed.PlaceholderSimappGenesisState, replacementGs) + if err != nil { + return err + } - content = typed.ModuleSimulationMsgModify( - replacer, + content, err = typed.ModuleSimulationMsgModify( content, opts.TypeName, opts.MsgSigner, "Create", "Update", "Delete", ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) diff --git a/ignite/templates/typed/placeholders.go b/ignite/templates/typed/placeholders.go index 085790320a..311bfb4c0f 100644 --- a/ignite/templates/typed/placeholders.go +++ b/ignite/templates/typed/placeholders.go @@ -2,25 +2,9 @@ package typed //nolint:godot const ( - Placeholder = "// this line is used by starport scaffolding # 1" - Placeholder3 = "// this line is used by starport scaffolding # 3" Placeholder4 = "" - // Genesis - PlaceholderGenesisTypesDefault = "// this line is used by starport scaffolding # genesis/types/default" - PlaceholderGenesisTypesValidate = "// this line is used by starport scaffolding # genesis/types/validate" - PlaceholderGenesisModuleInit = "// this line is used by starport scaffolding # genesis/module/init" - PlaceholderGenesisModuleExport = "// this line is used by starport scaffolding # genesis/module/export" - - PlaceholderSimappGenesisState = "// this line is used by starport scaffolding # simapp/module/genesisState" - PlaceholderSimappOperation = "// this line is used by starport scaffolding # simapp/module/operation" - PlaceholderSimappOperationProposalSimulation = "// this line is used by starport scaffolding # simapp/module/proposalSimulation" - // Placeholders AutoCLI PlaceholderAutoCLIQuery = "// this line is used by ignite scaffolding # autocli/query" PlaceholderAutoCLITx = "// this line is used by ignite scaffolding # autocli/tx" - - // Placeholders Collections - PlaceholderCollectionType = "// this line is used by starport scaffolding # collection/type" - PlaceholderCollectionInstantiate = "// this line is used by starport scaffolding # collection/instantiate" ) diff --git a/ignite/templates/typed/simulation.go b/ignite/templates/typed/simulation.go index dc5e4c0dbb..011733af4d 100644 --- a/ignite/templates/typed/simulation.go +++ b/ignite/templates/typed/simulation.go @@ -5,34 +5,46 @@ import ( "strings" "github.com/ignite/cli/v29/ignite/pkg/multiformatname" - "github.com/ignite/cli/v29/ignite/pkg/placeholder" + "github.com/ignite/cli/v29/ignite/pkg/xast" ) func ModuleSimulationMsgModify( - replacer placeholder.Replacer, content string, typeName, msgSigner multiformatname.Name, msgs ...string, -) string { +) (string, error) { if len(msgs) == 0 { msgs = append(msgs, "") } + var err error for _, msg := range msgs { // simulation operations - templateOp := `reg.Add(weights.Get("msg_%[4]v", 100 /* determine the simulation weight value */), simulation.Msg%[2]v%[3]vFactory(am.keeper)) - %[1]v` - replacementOp := fmt.Sprintf(templateOp, PlaceholderSimappOperation, msg, typeName.UpperCamel, fmt.Sprintf("%s_%s", strings.ToLower(msg), typeName.Snake)) - content = replacer.Replace(content, PlaceholderSimappOperation, replacementOp) + replacementOp := fmt.Sprintf( + `reg.Add(weights.Get("msg_%[3]v", 100 /* determine the simulation weight value */), simulation.Msg%[1]v%[2]vFactory(am.keeper))`, + msg, + typeName.UpperCamel, + fmt.Sprintf("%s_%s", strings.ToLower(msg), typeName.Snake), + ) + content, err = xast.ModifyFunction(content, "WeightedOperationsX", xast.AppendFuncCode(replacementOp)) + if err != nil { + return "", err + } // add proposal simulation operations for msgs having an authority as signer. - if strings.Contains(content, PlaceholderSimappOperationProposalSimulation) && strings.EqualFold(msgSigner.Original, "authority") { - templateOpMsg := `reg.Add(weights.Get("msg_%[4]v", 100), simulation.Msg%[2]v%[3]vFactory(am.keeper)) - %[1]v` - replacementOpMsg := fmt.Sprintf(templateOpMsg, PlaceholderSimappOperationProposalSimulation, msg, typeName.UpperCamel, fmt.Sprintf("%s_%s", strings.ToLower(msg), typeName.Snake)) - content = replacer.Replace(content, PlaceholderSimappOperationProposalSimulation, replacementOpMsg) + if strings.Contains(content, "ProposalMsgsX") && strings.EqualFold(msgSigner.Original, "authority") { + replacementOpMsg := fmt.Sprintf( + `reg.Add(weights.Get("msg_%[2]v", 100), simulation.Msg%[1]v%[2]vFactory(am.keeper))`, + msg, + typeName.UpperCamel, + fmt.Sprintf("%s_%s", strings.ToLower(msg), typeName.Snake), + ) + content, err = xast.ModifyFunction(content, "ProposalMsgsX", xast.AppendFuncCode(replacementOpMsg)) + if err != nil { + return "", err + } } } - return content + return content, nil } diff --git a/ignite/templates/typed/singleton/simulation.go b/ignite/templates/typed/singleton/simulation.go index 833fd36b53..9838038fff 100644 --- a/ignite/templates/typed/singleton/simulation.go +++ b/ignite/templates/typed/singleton/simulation.go @@ -5,11 +5,10 @@ import ( "github.com/gobuffalo/genny/v2" - "github.com/ignite/cli/v29/ignite/pkg/placeholder" "github.com/ignite/cli/v29/ignite/templates/typed" ) -func moduleSimulationModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func moduleSimulationModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "module/simulation.go") f, err := r.Disk.Find(path) @@ -17,13 +16,15 @@ func moduleSimulationModify(replacer placeholder.Replacer, opts *typed.Options) return err } - content := typed.ModuleSimulationMsgModify( - replacer, + content, err := typed.ModuleSimulationMsgModify( f.String(), opts.TypeName, opts.MsgSigner, "Create", "Update", "Delete", ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) diff --git a/ignite/templates/typed/singleton/singleton.go b/ignite/templates/typed/singleton/singleton.go index dd8b855329..736bf193c2 100644 --- a/ignite/templates/typed/singleton/singleton.go +++ b/ignite/templates/typed/singleton/singleton.go @@ -15,8 +15,8 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/gomodulepath" "github.com/ignite/cli/v29/ignite/pkg/placeholder" "github.com/ignite/cli/v29/ignite/pkg/protoanalysis/protoutil" + "github.com/ignite/cli/v29/ignite/pkg/xast" "github.com/ignite/cli/v29/ignite/pkg/xgenny" - "github.com/ignite/cli/v29/ignite/templates/module" "github.com/ignite/cli/v29/ignite/templates/typed" ) @@ -55,22 +55,22 @@ func NewGenerator(replacer placeholder.Replacer, opts *typed.Options) (*genny.Ge g.RunFn(protoRPCModify(opts)) g.RunFn(typesKeyModify(opts)) - g.RunFn(keeperModify(replacer, opts)) + g.RunFn(keeperModify(opts)) g.RunFn(clientCliQueryModify(replacer, opts)) g.RunFn(genesisProtoModify(opts)) - g.RunFn(genesisTypesModify(replacer, opts)) - g.RunFn(genesisModuleModify(replacer, opts)) - g.RunFn(genesisTestsModify(replacer, opts)) - g.RunFn(genesisTypesTestsModify(replacer, opts)) + g.RunFn(genesisTypesModify(opts)) + g.RunFn(genesisModuleModify(opts)) + g.RunFn(genesisTestsModify(opts)) + g.RunFn(genesisTypesTestsModify(opts)) // Modifications for new messages if !opts.NoMessage { g.RunFn(protoTxModify(opts)) g.RunFn(clientCliTxModify(replacer, opts)) - g.RunFn(typesCodecModify(replacer, opts)) + g.RunFn(typesCodecModify(opts)) if !opts.NoSimulation { - g.RunFn(moduleSimulationModify(replacer, opts)) + g.RunFn(moduleSimulationModify(opts)) if err := typed.Box(simappTemplate, opts, g); err != nil { return nil, err } @@ -106,7 +106,7 @@ var ( } // keeperModify modifies the keeper to add a new collections item type. -func keeperModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func keeperModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/keeper.go") f, err := r.Disk.Find(path) @@ -114,24 +114,35 @@ func keeperModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunF return err } - templateKeeperType := `%[2]v collections.Item[types.%[2]v] - %[1]v` - replacementModuleType := fmt.Sprintf( - templateKeeperType, - typed.PlaceholderCollectionType, - opts.TypeName.UpperCamel, + content, err := xast.ModifyStruct( + f.String(), + "Keeper", + xast.AppendStructValue( + opts.TypeName.UpperCamel, + fmt.Sprintf("collections.Item[types.%[1]v]", opts.TypeName.UpperCamel), + ), ) - content := replacer.Replace(f.String(), typed.PlaceholderCollectionType, replacementModuleType) + if err != nil { + return err + } - templateKeeperInstantiate := `%[2]v: collections.NewItem(sb, types.%[2]vKey, "%[3]v", codec.CollValue[types.%[2]v](cdc)), - %[1]v` - replacementInstantiate := fmt.Sprintf( - templateKeeperInstantiate, - typed.PlaceholderCollectionInstantiate, - opts.TypeName.UpperCamel, - opts.TypeName.LowerCamel, + // add parameter to the struct into the new keeper method. + content, err = xast.ModifyFunction( + content, + "NewKeeper", + xast.AppendFuncStruct( + "Keeper", + opts.TypeName.UpperCamel, + fmt.Sprintf(`collections.NewItem(sb, types.%[1]vKey, "%[2]v", codec.CollValue[types.%[1]v](cdc))`, + opts.TypeName.UpperCamel, + opts.TypeName.LowerCamel, + ), + -1, + ), ) - content = replacer.Replace(content, typed.PlaceholderCollectionInstantiate, replacementInstantiate) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) @@ -265,7 +276,7 @@ func genesisProtoModify(opts *typed.Options) genny.RunFn { } } -func genesisTypesModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisTypesModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/genesis.go") f, err := r.Disk.Find(path) @@ -273,21 +284,22 @@ func genesisTypesModify(replacer placeholder.Replacer, opts *typed.Options) genn return err } - templateTypesDefault := `%[2]v: nil, -%[1]v` - replacementTypesDefault := fmt.Sprintf( - templateTypesDefault, - typed.PlaceholderGenesisTypesDefault, - opts.TypeName.UpperCamel, - ) - content := replacer.Replace(f.String(), typed.PlaceholderGenesisTypesDefault, replacementTypesDefault) + content, err := xast.ModifyFunction(f.String(), "DefaultGenesis", xast.AppendFuncStruct( + "GenesisState", + fmt.Sprintf("%[1]v", opts.TypeName.UpperCamel), + "nil", + -1, + )) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisTestsModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisTestsModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/genesis_test.go") f, err := r.Disk.Find(path) @@ -304,33 +316,30 @@ func genesisTestsModify(replacer placeholder.Replacer, opts *typed.Options) genn } sampleFields += field.GenesisArgs(int(n.Int64()) + 1) } - - templateState := `%[2]v: &types.%[2]v{ - %[3]v}, - %[1]v` - replacementState := fmt.Sprintf( - templateState, - module.PlaceholderGenesisTestState, - opts.TypeName.UpperCamel, - sampleFields, - ) - content := replacer.Replace(f.String(), module.PlaceholderGenesisTestState, replacementState) - - templateAssert := `require.Equal(t, genesisState.%[2]v, got.%[2]v) -%[1]v` - replacementTests := fmt.Sprintf( - templateAssert, - module.PlaceholderGenesisTestAssert, - opts.TypeName.UpperCamel, + // add parameter to the struct into the new method. + content, err := xast.ModifyFunction( + f.String(), + "TestGenesis", + xast.AppendFuncStruct( + "GenesisState", + opts.TypeName.UpperCamel, + fmt.Sprintf("&types.%[1]v{ %[2]v }", opts.TypeName.UpperCamel, sampleFields), + -1, + ), + xast.AppendFuncCode( + fmt.Sprintf("require.Equal(t, genesisState.%[1]v, got.%[1]v)", opts.TypeName.UpperCamel), + ), ) - content = replacer.Replace(content, module.PlaceholderGenesisTestAssert, replacementTests) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisTypesTestsModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisTypesTestsModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/genesis_test.go") f, err := r.Disk.Find(path) @@ -348,23 +357,27 @@ func genesisTypesTestsModify(replacer placeholder.Replacer, opts *typed.Options) sampleFields += field.GenesisArgs(int(n.Int64()) + 1) } - templateValid := `%[2]v: &types.%[2]v{ - %[3]v}, -%[1]v` - replacementValid := fmt.Sprintf( - templateValid, - module.PlaceholderTypesGenesisValidField, - opts.TypeName.UpperCamel, - sampleFields, + // add parameter to the struct into the new method. + content, err := xast.ModifyFunction( + f.String(), + "TestGenesisState_Validate", + xast.AppendFuncStruct( + "GenesisState", + opts.TypeName.UpperCamel, + fmt.Sprintf("&types.%[1]v{ %[2]v }", opts.TypeName.UpperCamel, sampleFields), + -1, + ), ) - content := replacer.Replace(f.String(), module.PlaceholderTypesGenesisValidField, replacementValid) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) } } -func genesisModuleModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func genesisModuleModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/genesis.go") f, err := r.Disk.Find(path) @@ -373,34 +386,43 @@ func genesisModuleModify(replacer placeholder.Replacer, opts *typed.Options) gen } templateModuleInit := `// Set if defined -if genState.%[3]v != nil { - if err := k.%[3]v.Set(ctx, *genState.%[3]v); err != nil { +if genState.%[1]v != nil { + if err := k.%[1]v.Set(ctx, *genState.%[1]v); err != nil { return err } -} -%[1]v` +}` replacementModuleInit := fmt.Sprintf( templateModuleInit, - typed.PlaceholderGenesisModuleInit, - opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, ) - content := replacer.Replace(f.String(), typed.PlaceholderGenesisModuleInit, replacementModuleInit) + content, err := xast.ModifyFunction( + f.String(), + "InitGenesis", + xast.AppendFuncCode(replacementModuleInit), + ) + if err != nil { + return err + } - templateModuleExport := `// Get all %[2]v -%[2]v, err := k.%[3]v.Get(ctx) + templateModuleExport := `// Get all %[1]v +%[1]v, err := k.%[2]v.Get(ctx) if err != nil { return nil, err } -genesis.%[3]v = &%[2]v -%[1]v` +genesis.%[2]v = &%[1]v` replacementModuleExport := fmt.Sprintf( templateModuleExport, - typed.PlaceholderGenesisModuleExport, opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, ) - content = replacer.Replace(content, typed.PlaceholderGenesisModuleExport, replacementModuleExport) + content, err = xast.ModifyFunction( + content, + "ExportGenesis", + xast.AppendFuncCode(replacementModuleExport), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile) @@ -550,7 +572,7 @@ func clientCliTxModify(replacer placeholder.Replacer, opts *typed.Options) genny } } -func typesCodecModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { +func typesCodecModify(opts *typed.Options) genny.RunFn { return func(r *genny.Runner) error { path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "types/codec.go") f, err := r.Disk.Find(path) @@ -558,25 +580,30 @@ func typesCodecModify(replacer placeholder.Replacer, opts *typed.Options) genny. return err } - content := f.String() - // Import - replacementImport := `sdk "github.com/cosmos/cosmos-sdk/types"` - content = replacer.ReplaceOnce(content, typed.Placeholder, replacementImport) + content, err := xast.AppendImports(f.String(), xast.WithLastNamedImport("sdk", "github.com/cosmos/cosmos-sdk/types")) + if err != nil { + return err + } // Interface templateInterface := `registrar.RegisterImplementations((*sdk.Msg)(nil), - &MsgCreate%[2]v{}, - &MsgUpdate%[2]v{}, - &MsgDelete%[2]v{}, -) -%[1]v` + &MsgCreate%[1]v{}, + &MsgUpdate%[1]v{}, + &MsgDelete%[1]v{}, +)` replacementInterface := fmt.Sprintf( templateInterface, - typed.Placeholder3, opts.TypeName.UpperCamel, ) - content = replacer.Replace(content, typed.Placeholder3, replacementInterface) + content, err = xast.ModifyFunction( + content, + "RegisterInterfaces", + xast.AppendFuncAtLine(replacementInterface, 0), + ) + if err != nil { + return err + } newFile := genny.NewFileS(path, content) return r.File(newFile)