diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c60b9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# ignore all .DS_Store files +.DS_Store diff --git a/README.md b/README.md index 56a7be7..57e6de5 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,34 @@ fmt.Println(template) Note: Remember to replace "transfer-flow" with the actual name of the template you wish to fetch. -To read more about Flow Interaction Templates, [see the docs](https://developers.flow.com/tooling/fcl-js/interaction-templates). \ No newline at end of file +To read more about Flow Interaction Templates, [see the docs](https://developers.flow.com/tooling/fcl-js/interaction-templates). + + +## Bindings + +> Binding files are code files that bind consuming code with FLIX. The `bindings` module in Flixkit generates code that calls the FLIX cadence code. FLIX cadence is primarily transactions and scripts. + +### Usage + +The `bindings` module has two public methods `Generate` and `NewFclJSGenerator`. `FclJSGenerator` takes a template directory. `bindings` has fcl-js templates. + + + - `NewFclJSGenerator() *FclJSGenerator` // uses default fcl-js vanilla javascript + - `Generate(flix *flixkit.FlowInteractionTemplate, templateLocation string, isLocal bool) (string, error)` // flix is the hydrated template struct, templateLocation is the file location of the flix json file, isLocal is a flag that indicates if the template is local or on remote server + +### Example + +```go + +// uses default fcl-js templates +fclJsGen := bindings.NewFclJSGenerator() + +output, err := fclJsGen.Generate(template, flixQuery, isLocal) +if err != nil { + log.Fatal(err) +} + +// output is the javascript binding code +fmt.Println(output]) + +``` \ No newline at end of file diff --git a/bindings/fcl-js.go b/bindings/fcl-js.go new file mode 100644 index 0000000..3833dc3 --- /dev/null +++ b/bindings/fcl-js.go @@ -0,0 +1,145 @@ +package bindings + +import ( + "bytes" + "os" + "path/filepath" + "runtime" + "sort" + "text/template" + + "github.com/onflow/flixkit-go" + "github.com/stoewer/go-strcase" +) + +type simpleParameter struct { + Name string + JsType string + Description string + FclType string + CadType string +} + +type templateData struct { + Version string + Parameters []simpleParameter + Title string + Description string + Location string + IsScript bool + IsLocalTemplate bool +} + +type FclJSGenerator struct { + TemplateDir string +} + +func NewFclJSGenerator() *FclJSGenerator { + _, currentFilePath, _, _ := runtime.Caller(0) + baseDir := filepath.Dir(currentFilePath) + templateDir := filepath.Join(baseDir, "templates") + + return &FclJSGenerator{ + TemplateDir: templateDir, + } +} + +func (g FclJSGenerator) Generate(flix *flixkit.FlowInteractionTemplate, templateLocation string, isLocal bool) (string, error) { + templateFiles, err := getAllFiles(g.TemplateDir) + if err != nil { + return "", err + } + tmpl, err := template.ParseFiles(templateFiles...) + if err != nil { + return "", err + } + + methodName := strcase.LowerCamelCase(flix.Data.Messages.GetTitleValue("Request")) + description := flix.GetDescription() + data := templateData{ + Version: flix.FVersion, + Parameters: transformArguments(flix.Data.Arguments), + Title: methodName, + Description: description, + Location: templateLocation, + IsScript: flix.IsScript(), + IsLocalTemplate: isLocal, + } + + var buf bytes.Buffer + err = tmpl.Execute(&buf, data) + return buf.String(), err +} + +func transformArguments(args flixkit.Arguments) []simpleParameter { + simpleArgs := []simpleParameter{} + var keys []string + // get keys for sorting + for k := range args { + keys = append(keys, k) + } + + sort.SliceStable(keys, func(i, j int) bool { + return args[keys[i]].Index < args[keys[j]].Index + }) + for _, key := range keys { + arg := args[key] + isArray, cType, jsType := isArrayParameter(arg) + desciption := arg.Messages.GetTitleValue("") + if isArray { + simpleArgs = append(simpleArgs, simpleParameter{Name: key, CadType: cType, JsType: jsType, FclType: "Array(t." + cType + ")", Description: desciption}) + } else { + jsType := convertCadenceTypeToJS(arg.Type) + simpleArgs = append(simpleArgs, simpleParameter{Name: key, CadType: arg.Type, JsType: jsType, FclType: arg.Type, Description: desciption}) + } + } + return simpleArgs +} + +func isArrayParameter(arg flixkit.Argument) (isArray bool, cType string, jsType string) { + if arg.Type == "" || arg.Type[0] != '[' { + return false, "", "" + } + cadenceType := arg.Type[1 : len(arg.Type)-1] + javascriptType := "Array<" + convertCadenceTypeToJS(cadenceType) + ">" + return true, cadenceType, javascriptType +} + +func convertCadenceTypeToJS(cadenceType string) string { + // need to determine js type based on fcl supported types + // looking at fcl types and how arguments work as parameters + // https://github.com/onflow/fcl-js/blob/master/packages/types/src/types.js + switch cadenceType { + case "Bool": + return "boolean" + case "Void": + return "void" + case "Dictionary": + return "object" + case "Struct": + return "object" + case "Enum": + return "object" + default: + return "string" + } +} + +func getAllFiles(dir string) ([]string, error) { + var files []string + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + // If it's a directory, skip it + if info.IsDir() { + return nil + } + files = append(files, path) + return nil + }) + if err != nil { + return nil, err + } + return files, nil +} diff --git a/bindings/fcl-js_test.go b/bindings/fcl-js_test.go new file mode 100644 index 0000000..c969973 --- /dev/null +++ b/bindings/fcl-js_test.go @@ -0,0 +1,219 @@ +package bindings + +import ( + "testing" + + "github.com/hexops/autogold/v2" + "github.com/onflow/flixkit-go" + "github.com/stretchr/testify/assert" +) + +var parsedTemplateTX = &flixkit.FlowInteractionTemplate{ + FType: "InteractionTemplate", + FVersion: "1.0.0", + ID: "290b6b6222b2a77b16db896a80ddf29ebd1fa3038c9e6625a933fa213fce51fa", + Data: flixkit.Data{ + Type: "transaction", + Interface: "", + Messages: flixkit.Messages{ + Title: &flixkit.Title{ + I18N: map[string]string{ + "en-US": "Transfer Tokens", + }, + }, + Description: &flixkit.Description{ + I18N: map[string]string{ + "en-US": "Transfer tokens from one account to another", + }, + }, + }, + Cadence: "import FungibleToken from 0xFUNGIBLETOKENADDRESS\ntransaction(amount: UFix64, to: Address) {\nlet vault: @FungibleToken.Vault\nprepare(signer: AuthAccount) {\nself.vault <- signer\n.borrow<&{FungibleToken.Provider}>(from: /storage/flowTokenVault)!\n.withdraw(amount: amount)\n}\nexecute {\ngetAccount(to)\n.getCapability(/public/flowTokenReceiver)!\n.borrow<&{FungibleToken.Receiver}>()!\n.deposit(from: <-self.vault)\n}\n}", + Dependencies: flixkit.Dependencies{ + "0xFUNGIBLETOKENADDRESS": flixkit.Contracts{ + "FungibleToken": flixkit.Networks{ + "mainnet": flixkit.Network{ + Address: "0xf233dcee88fe0abe", + FqAddress: "A.0xf233dcee88fe0abe.FungibleToken", + Contract: "FungibleToken", + Pin: "83c9e3d61d3b5ebf24356a9f17b5b57b12d6d56547abc73e05f820a0ae7d9cf5", + PinBlockHeight: 34166296, + }, + "testnet": flixkit.Network{ + Address: "0x9a0766d93b6608b7", + FqAddress: "A.0x9a0766d93b6608b7.FungibleToken", + Contract: "FungibleToken", + Pin: "83c9e3d61d3b5ebf24356a9f17b5b57b12d6d56547abc73e05f820a0ae7d9cf5", + PinBlockHeight: 74776482, + }, + }, + }, + }, + Arguments: flixkit.Arguments{ + "amount": flixkit.Argument{ + Index: 0, + Type: "UFix64", + Messages: flixkit.Messages{ + Title: &flixkit.Title{ + I18N: map[string]string{ + "en-US": "The amount of FLOW tokens to send", + }, + }, + }, + Balance: "", + }, + "to": flixkit.Argument{ + Index: 1, + Type: "Address", + Messages: flixkit.Messages{ + Title: &flixkit.Title{ + I18N: map[string]string{ + "en-US": "The Flow account the tokens will go to", + }, + }, + }, + Balance: "", + }, + }, + }, +} + +var parsedTemplateScript = &flixkit.FlowInteractionTemplate{ + FType: "InteractionTemplate", + FVersion: "1.0.0", + ID: "290b6b6222b2a77b16db896a80ddf29ebd1fa3038c9e6625a933fa213fce51fa", + Data: flixkit.Data{ + Type: "script", + Interface: "", + Messages: flixkit.Messages{ + Title: &flixkit.Title{ + I18N: map[string]string{ + "en-US": "Multiply Two Integers", + }, + }, + Description: &flixkit.Description{ + I18N: map[string]string{ + "en-US": "Multiply two numbers to another", + }, + }, + }, + Cadence: "pub fun main(x: Int, y: Int): Int { return x * y }", + Arguments: flixkit.Arguments{ + "x": flixkit.Argument{ + Index: 0, + Type: "Int", + Messages: flixkit.Messages{ + Title: &flixkit.Title{ + I18N: map[string]string{ + "en-US": "number to be multiplied", + }, + }, + }, + Balance: "", + }, + "y": flixkit.Argument{ + Index: 1, + Type: "Int", + Messages: flixkit.Messages{ + Title: &flixkit.Title{ + I18N: map[string]string{ + "en-US": "second number to be multiplied", + }, + }, + }, + Balance: "", + }, + }, + }, +} + +var ArrayTypeScript = &flixkit.FlowInteractionTemplate{ + FType: "InteractionTemplate", + FVersion: "1.0.0", + ID: "290b6b6222b2a77b16db896a80ddf29ebd1fa3038c9e6625a933fa213fce51fa", + Data: flixkit.Data{ + Type: "script", + Interface: "", + Messages: flixkit.Messages{ + Title: &flixkit.Title{ + I18N: map[string]string{ + "en-US": "Multiply Numbers", + }, + }, + Description: &flixkit.Description{ + I18N: map[string]string{ + "en-US": "Multiply numbers in an array", + }, + }, + }, + Cadence: "pub fun main(numbers: [Int]): Int { var total = 1; for x in numbers { total = total * x }; return total }", + Arguments: flixkit.Arguments{ + "numbers": flixkit.Argument{ + Index: 0, + Type: "[Int]", + Messages: flixkit.Messages{ + Title: &flixkit.Title{ + I18N: map[string]string{ + "en-US": "Array of numbers to be multiplied", + }, + }, + }, + Balance: "", + }, + }, + }, +} + +var minimumTemplate = &flixkit.FlowInteractionTemplate{ + FType: "InteractionTemplate", + FVersion: "1.0.0", + ID: "290b6b6222b2a77b16db896a80ddf29ebd1fa3038c9e6625a933fa213fce51fa", + Data: flixkit.Data{ + Type: "script", + Interface: "", + Cadence: "pub fun main(numbers: [Int]): Int { var total = 1; for x in numbers { total = total * x }; return total }", + Arguments: flixkit.Arguments{ + "numbers": flixkit.Argument{ + Index: 0, + Type: "[Int]", + }, + }, + }, +} + +func TestJSGenTransaction(t *testing.T) { + generator := FclJSGenerator{ + TemplateDir: "./templates", + } + got, _ := generator.Generate(parsedTemplateTX, "./transfer_token.json", true) + autogold.ExpectFile(t, got) +} + +func TestJSGenScript(t *testing.T) { + generator := FclJSGenerator{ + TemplateDir: "./templates", + } + assert := assert.New(t) + got, err := generator.Generate(parsedTemplateScript, "./multiply_two_integers.template.json", true) + assert.NoError(err, "ParseTemplate should not return an error") + autogold.ExpectFile(t, got) +} + +func TestJSGenArrayScript(t *testing.T) { + generator := FclJSGenerator{ + TemplateDir: "./templates", + } + assert := assert.New(t) + + out, err := generator.Generate(ArrayTypeScript, "./multiply-numbers.template.json", true) + assert.NoError(err, "ParseTemplate should not return an error") + autogold.ExpectFile(t, out) +} + +func TestJSGenMinScript(t *testing.T) { + generator := NewFclJSGenerator() + assert := assert.New(t) + + out, err := generator.Generate(minimumTemplate, "./min.template.json", true) + assert.NoError(err, "ParseTemplate should not return an error") + autogold.ExpectFile(t, out) +} diff --git a/bindings/templates/js_fcl_main.tmpl b/bindings/templates/js_fcl_main.tmpl new file mode 100644 index 0000000..b094bba --- /dev/null +++ b/bindings/templates/js_fcl_main.tmpl @@ -0,0 +1,33 @@ +/** + This binding file was auto generated based on FLIX template v{{.Version}}. + Changes to this file might get overwritten. + Note fcl version 1.3.0 or higher is required to use templates. +**/ + +import * as fcl from "@onflow/fcl" +{{- if .IsLocalTemplate }} +import flixTemplate from "{{.Location}}" +{{- else}} +const flixTemplate = "{{.Location}}" +{{- end}} + +{{"\n"}}/** +* {{.Description}}{{"\n"}} + {{- if gt (len .Parameters) 0 -}} +* @param {Object} Parameters - parameters for the cadence + {{- range $index, $ele := .Parameters -}} +{{"\n"}}* @param {{"{"}} {{$ele.JsType}} {{"}"}} Parameters.{{$ele.Name}} - {{$ele.Description}}: {{$ele.CadType}} + {{- end -}} + {{ end -}} + {{- if not .IsScript -}} +{{"\n"}}* @returns {Promise} - returns a promise which resolves to the transaction id + {{- end -}} +{{"\n"}}*/ +{{if .IsScript}} +{{- template "js_fcl_script.tmpl" .}} +{{else}} +{{- template "js_fcl_tx.tmpl" .}} +{{- end}} + + + diff --git a/bindings/templates/js_fcl_script.tmpl b/bindings/templates/js_fcl_script.tmpl new file mode 100644 index 0000000..79f1904 --- /dev/null +++ b/bindings/templates/js_fcl_script.tmpl @@ -0,0 +1,20 @@ +export async function {{.Title}}({ + {{- if len .Parameters -}} + {{- range $index, $ele := .Parameters -}} + {{if $index}}, {{end}}{{.Name}} + {{- end -}} + {{- end -}} +}) { + const info = await fcl.query({ + template: flixTemplate, + {{ if len .Parameters -}} + args: (arg, t) => [ + {{- range $index, $ele := .Parameters -}} + {{if $index}}, {{end}}arg({{.Name}}, t.{{.FclType}}) + {{- end -}} + ] + {{- end }} + }); + + return info +} diff --git a/bindings/templates/js_fcl_tx.tmpl b/bindings/templates/js_fcl_tx.tmpl new file mode 100644 index 0000000..bb31a70 --- /dev/null +++ b/bindings/templates/js_fcl_tx.tmpl @@ -0,0 +1,20 @@ +export async function {{.Title}}({ + {{- if len .Parameters -}} + {{- range $index, $ele := .Parameters -}} + {{if $index}}, {{end}}{{.Name}} + {{- end -}} + {{- end -}} +}) { + const transactionId = await fcl.mutate({ + template: flixTemplate, + {{ if len .Parameters -}} + args: (arg, t) => [ + {{- range $index, $ele := .Parameters -}} + {{if $index}}, {{end}}arg({{.Name}}, t.{{.FclType}}) + {{- end -}} + ] + {{- end }} + }); + + return transactionId +} diff --git a/bindings/testdata/TestJSGenArrayScript.golden b/bindings/testdata/TestJSGenArrayScript.golden new file mode 100644 index 0000000..4e43f9e --- /dev/null +++ b/bindings/testdata/TestJSGenArrayScript.golden @@ -0,0 +1,29 @@ +`/** + This binding file was auto generated based on FLIX template v1.0.0. + Changes to this file might get overwritten. + Note fcl version 1.3.0 or higher is required to use templates. +**/ + +import * as fcl from "@onflow/fcl" +import flixTemplate from "./multiply-numbers.template.json" + + +/** +* Multiply numbers in an array +* @param {Object} Parameters - parameters for the cadence +* @param { Array } Parameters.numbers - Array of numbers to be multiplied: Int +*/ +export async function multiplyNumbers({numbers}) { + const info = await fcl.query({ + template: flixTemplate, + args: (arg, t) => [arg(numbers, t.Array(t.Int))] + }); + + return info +} + + + + + +` diff --git a/bindings/testdata/TestJSGenMinScript.golden b/bindings/testdata/TestJSGenMinScript.golden new file mode 100644 index 0000000..f9dc189 --- /dev/null +++ b/bindings/testdata/TestJSGenMinScript.golden @@ -0,0 +1,29 @@ +`/** + This binding file was auto generated based on FLIX template v1.0.0. + Changes to this file might get overwritten. + Note fcl version 1.3.0 or higher is required to use templates. +**/ + +import * as fcl from "@onflow/fcl" +import flixTemplate from "./min.template.json" + + +/** +* +* @param {Object} Parameters - parameters for the cadence +* @param { Array } Parameters.numbers - : Int +*/ +export async function request({numbers}) { + const info = await fcl.query({ + template: flixTemplate, + args: (arg, t) => [arg(numbers, t.Array(t.Int))] + }); + + return info +} + + + + + +` diff --git a/bindings/testdata/TestJSGenScript.golden b/bindings/testdata/TestJSGenScript.golden new file mode 100644 index 0000000..4e930ad --- /dev/null +++ b/bindings/testdata/TestJSGenScript.golden @@ -0,0 +1,30 @@ +`/** + This binding file was auto generated based on FLIX template v1.0.0. + Changes to this file might get overwritten. + Note fcl version 1.3.0 or higher is required to use templates. +**/ + +import * as fcl from "@onflow/fcl" +import flixTemplate from "./multiply_two_integers.template.json" + + +/** +* Multiply two numbers to another +* @param {Object} Parameters - parameters for the cadence +* @param { string } Parameters.x - number to be multiplied: Int +* @param { string } Parameters.y - second number to be multiplied: Int +*/ +export async function multiplyTwoIntegers({x, y}) { + const info = await fcl.query({ + template: flixTemplate, + args: (arg, t) => [arg(x, t.Int), arg(y, t.Int)] + }); + + return info +} + + + + + +` diff --git a/bindings/testdata/TestJSGenTransaction.golden b/bindings/testdata/TestJSGenTransaction.golden new file mode 100644 index 0000000..98407d9 --- /dev/null +++ b/bindings/testdata/TestJSGenTransaction.golden @@ -0,0 +1,30 @@ +`/** + This binding file was auto generated based on FLIX template v1.0.0. + Changes to this file might get overwritten. + Note fcl version 1.3.0 or higher is required to use templates. +**/ + +import * as fcl from "@onflow/fcl" +import flixTemplate from "./transfer_token.json" + + +/** +* Transfer tokens from one account to another +* @param {Object} Parameters - parameters for the cadence +* @param { string } Parameters.amount - The amount of FLOW tokens to send: UFix64 +* @param { string } Parameters.to - The Flow account the tokens will go to: Address +* @returns {Promise} - returns a promise which resolves to the transaction id +*/ +export async function transferTokens({amount, to}) { + const transactionId = await fcl.mutate({ + template: flixTemplate, + args: (arg, t) => [arg(amount, t.UFix64), arg(to, t.Address)] + }); + + return transactionId +} + + + + +` diff --git a/flixkit.go b/flixkit.go index 1d977ee..8a26eca 100644 --- a/flixkit.go +++ b/flixkit.go @@ -5,58 +5,13 @@ import ( "encoding/json" "fmt" "io" + "io/fs" "log" "net/http" - "regexp" ) -type Network struct { - Address string `json:"address"` - FqAddress string `json:"fq_address"` - Contract string `json:"contract"` - Pin string `json:"pin"` - PinBlockHeight uint64 `json:"pin_block_height"` -} - -type Argument struct { - Index int `json:"index"` - Type string `json:"type"` - Messages Messages `json:"messages"` - Balance string `json:"balance"` -} - -type Title struct { - I18N map[string]string `json:"i18n"` -} - -type Description struct { - I18N map[string]string `json:"i18n"` -} - -type Messages struct { - Title *Title `json:"title,omitempty"` - Description *Description `json:"description,omitempty"` -} - -type Dependencies map[string]Contracts -type Contracts map[string]Networks -type Networks map[string]Network -type Arguments map[string]Argument - -type Data struct { - Type string `json:"type"` - Interface string `json:"interface"` - Messages Messages `json:"messages"` - Cadence string `json:"cadence"` - Dependencies Dependencies `json:"dependencies"` - Arguments Arguments `json:"arguments"` -} - -type FlowInteractionTemplate struct { - FType string `json:"f_type"` - FVersion string `json:"f_version"` - ID string `json:"id"` - Data Data `json:"data"` +type Generator interface { + Generate(flix *FlowInteractionTemplate, templateLocation string, isLocal bool) (string, error) } type FlixService interface { @@ -74,6 +29,7 @@ var _ FlixService = (*flixServiceImpl)(nil) type Config struct { FlixServerURL string + FileReader fs.ReadFileFS } func NewFlixService(config *Config) FlixService { @@ -124,38 +80,6 @@ func (s *flixServiceImpl) GetFlixByID(ctx context.Context, templateID string) (* return parsedTemplate, nil } -func (t *FlowInteractionTemplate) IsScript() bool { - return t.Data.Type == "script" -} - -func (t *FlowInteractionTemplate) IsTransaction() bool { - return t.Data.Type == "transaction" -} - -func (t *FlowInteractionTemplate) GetAndReplaceCadenceImports(networkName string) (string, error) { - cadence := t.Data.Cadence - - for dependencyAddress, contracts := range t.Data.Dependencies { - for contractName, networks := range contracts { - network, ok := networks[networkName] - if !ok { - return "", fmt.Errorf("network %s not found for contract %s", networkName, contractName) - } - - pattern := fmt.Sprintf(`import\s*%s\s*from\s*%s`, contractName, dependencyAddress) - re, err := regexp.Compile(pattern) - if err != nil { - return "", fmt.Errorf("invalid regex pattern: %v", err) - } - - replacement := fmt.Sprintf("import %s from %s", contractName, network.Address) - cadence = re.ReplaceAllString(cadence, replacement) - } - } - - return cadence, nil -} - func ParseFlix(template string) (*FlowInteractionTemplate, error) { var flowTemplate FlowInteractionTemplate diff --git a/flixkit_test.go b/flixkit_test.go index 7d8bf2e..06fb662 100644 --- a/flixkit_test.go +++ b/flixkit_test.go @@ -2,13 +2,15 @@ package flixkit import ( "context" - "github.com/stretchr/testify/assert" + "io/fs" "net/http" "net/http/httptest" "testing" + + "github.com/stretchr/testify/assert" ) -var template = `{ +var flix_template = `{ "f_type": "InteractionTemplate", "f_version": "1.0.0", "id": "290b6b6222b2a77b16db896a80ddf29ebd1fa3038c9e6625a933fa213fce51fa", @@ -149,7 +151,7 @@ var parsedTemplate = &FlowInteractionTemplate{ func TestParseFlix(t *testing.T) { assert := assert.New(t) - parsedTemplate, err := ParseFlix(template) + parsedTemplate, err := ParseFlix(flix_template) assert.NoError(err, "ParseTemplate should not return an error") assert.NotNil(parsedTemplate, "Parsed template should not be nil") @@ -270,7 +272,7 @@ func TestGetFlix(t *testing.T) { assert := assert.New(t) server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - rw.Write([]byte(template)) + rw.Write([]byte(flix_template)) })) defer server.Close() @@ -302,7 +304,7 @@ func TestGetFlixByID(t *testing.T) { assert := assert.New(t) server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - rw.Write([]byte(template)) + rw.Write([]byte(flix_template)) })) defer server.Close() @@ -313,3 +315,7 @@ func TestGetFlixByID(t *testing.T) { assert.NotNil(flix, "GetParsedFlixByID should not return a nil Flix") assert.Equal(parsedTemplate, flix, "GetParsedFlixByID should return the correct Flix") } + +type MapFsReader struct { + FS fs.FS +} diff --git a/go.mod b/go.mod index 156de73..1d6a19e 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,25 @@ module github.com/onflow/flixkit-go go 1.20 +require ( + github.com/hexops/autogold/v2 v2.2.1 + github.com/stoewer/go-strcase v1.3.0 + github.com/stretchr/testify v1.8.4 +) + require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/hexops/gotextdiff v1.0.3 // indirect + github.com/hexops/valast v1.4.4 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/nightlyone/lockfile v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/tools v0.13.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + mvdan.cc/gofumpt v0.5.0 // indirect ) diff --git a/go.sum b/go.sum index 8cf6655..253210d 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,129 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hexops/autogold v0.8.1 h1:wvyd/bAJ+Dy+DcE09BoLk6r4Fa5R5W+O+GUzmR985WM= +github.com/hexops/autogold v0.8.1/go.mod h1:97HLDXyG23akzAoRYJh/2OBs3kd80eHyKPvZw0S5ZBY= +github.com/hexops/autogold/v2 v2.2.1 h1:JPUXuZQGkcQMv7eeDXuNMovjfoRYaa0yVcm+F3voaGY= +github.com/hexops/autogold/v2 v2.2.1/go.mod h1:IJwxtUfj1BGLm0YsR/k+dIxYi6xbeLjqGke2bzcOTMI= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/hexops/valast v1.4.4 h1:rETyycw+/L2ZVJHHNxEBgh8KUn+87WugH9MxcEv9PGs= +github.com/hexops/valast v1.4.4/go.mod h1:Jcy1pNH7LNraVaAZDLyv21hHg2WBv9Nf9FL6fGxU7o4= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/nightlyone/lockfile v1.0.0 h1:RHep2cFKK4PonZJDdEl4GmkabuhbsRMgk/k3uAmxBiA= +github.com/nightlyone/lockfile v1.0.0/go.mod h1:rywoIealpdNse2r832aiD9jRk8ErCatROs6LzC841CI= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= +mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E= +mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js= diff --git a/types.go b/types.go new file mode 100644 index 0000000..b69edc2 --- /dev/null +++ b/types.go @@ -0,0 +1,114 @@ +package flixkit + +import ( + "fmt" + "regexp" +) + +type Network struct { + Address string `json:"address"` + FqAddress string `json:"fq_address"` + Contract string `json:"contract"` + Pin string `json:"pin"` + PinBlockHeight uint64 `json:"pin_block_height"` +} + +type Argument struct { + Index int `json:"index"` + Type string `json:"type"` + Messages Messages `json:"messages"` + Balance string `json:"balance"` +} + +type Title struct { + I18N map[string]string `json:"i18n"` +} + +type Description struct { + I18N map[string]string `json:"i18n"` +} + +type Messages struct { + Title *Title `json:"title,omitempty"` + Description *Description `json:"description,omitempty"` +} + +type Dependencies map[string]Contracts +type Contracts map[string]Networks +type Networks map[string]Network +type Arguments map[string]Argument + +type Data struct { + Type string `json:"type"` + Interface string `json:"interface"` + Messages Messages `json:"messages"` + Cadence string `json:"cadence"` + Dependencies Dependencies `json:"dependencies"` + Arguments Arguments `json:"arguments"` +} + +type FlowInteractionTemplate struct { + FType string `json:"f_type"` + FVersion string `json:"f_version"` + ID string `json:"id"` + Data Data `json:"data"` +} + +func (t *FlowInteractionTemplate) IsScript() bool { + return t.Data.Type == "script" +} + +func (t *FlowInteractionTemplate) IsTransaction() bool { + return t.Data.Type == "transaction" +} + +func (t *FlowInteractionTemplate) GetAndReplaceCadenceImports(networkName string) (string, error) { + cadence := t.Data.Cadence + + for dependencyAddress, contracts := range t.Data.Dependencies { + for contractName, networks := range contracts { + network, ok := networks[networkName] + if !ok { + return "", fmt.Errorf("network %s not found for contract %s", networkName, contractName) + } + + pattern := fmt.Sprintf(`import\s*%s\s*from\s*%s`, contractName, dependencyAddress) + re, err := regexp.Compile(pattern) + if err != nil { + return "", fmt.Errorf("invalid regex pattern: %v", err) + } + + replacement := fmt.Sprintf("import %s from %s", contractName, network.Address) + cadence = re.ReplaceAllString(cadence, replacement) + } + } + + return cadence, nil +} + +func (t *FlowInteractionTemplate) GetDescription() string { + s := "" + if t.Data.Messages.Description != nil && + t.Data.Messages.Description.I18N != nil { + + // relying on en-US for now, future we need to know what language to use + value, exists := t.Data.Messages.Description.I18N["en-US"] + if exists { + s = value + } + } + return s +} + +func (msgs *Messages) GetTitleValue(placeholder string) string { + s := placeholder + if msgs.Title != nil && + msgs.Title.I18N != nil { + // relying on en-US for now, future we need to know what language to use + value, exists := msgs.Title.I18N["en-US"] + if exists { + s = value + } + } + return s +}