Skip to content

Commit

Permalink
Merge pull request #12 from onflow/add-binding-gen
Browse files Browse the repository at this point in the history
Add binding gen js for remote and local
  • Loading branch information
bthaile authored Oct 23, 2023
2 parents b78b24a + 6619788 commit 06e2391
Show file tree
Hide file tree
Showing 16 changed files with 854 additions and 87 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# ignore all .DS_Store files
.DS_Store
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
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])

```
145 changes: 145 additions & 0 deletions bindings/fcl-js.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 06e2391

Please sign in to comment.