Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add binding gen js for remote and local #12

Merged
merged 35 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a2c8c05
init check in for generating binding files based on flix
bthaile Sep 1, 2023
6f03fb0
add sub templates for js files, gen binding file in same dir as templ…
bthaile Sep 1, 2023
389069b
organization of files and ignores
bthaile Sep 1, 2023
7451e2a
ignore built file
bthaile Sep 1, 2023
4ab973f
ignore template files
bthaile Sep 1, 2023
016c059
ignore template files
bthaile Sep 1, 2023
5a50239
add file reader to config for unit testing
bthaile Sep 1, 2023
50d5bcb
verify that remote templates can gen js files
bthaile Sep 5, 2023
1b9b440
fix git ignore file
bthaile Sep 5, 2023
37a9f3d
ignore cmd dir and all .DS_Store files
bthaile Sep 5, 2023
6c242b7
remove .DS_Store files
bthaile Sep 5, 2023
f9d4bf4
add testing gen js binding with remote flix
bthaile Sep 5, 2023
d15e7ca
support array of simple types
bthaile Sep 5, 2023
d4848cf
first batch of changes based on feedback
bthaile Sep 6, 2023
2098974
collapse files and keep everything in flixkit package
bthaile Sep 7, 2023
530a385
clean up
bthaile Sep 7, 2023
b7a142c
add js docs to provide types for typescript
bthaile Sep 8, 2023
870b6ff
do not rely on message to be there and that us-en exists, update temp…
bthaile Sep 8, 2023
805a993
fix consistency for testing
bthaile Sep 8, 2023
dac9742
simplify conversion to js types, fcl uses strings for all numbers
bthaile Sep 14, 2023
4a9cf9a
add golden for unit tests
bthaile Sep 26, 2023
bd1a7a9
pass in generator method to generate code
bthaile Sep 26, 2023
5aef7f0
use interface and set specific port for testing remote and use golden…
bthaile Sep 27, 2023
e7cd1bc
fixed arguments key sorting issue, that was causing test failures
bthaile Sep 27, 2023
4932623
fix case typo in generator name
bthaile Sep 28, 2023
64e11a5
remove need to read from disk to get template
bthaile Sep 28, 2023
aa66b9f
tidy
bthaile Sep 29, 2023
9d27901
move js generator to bindings module and rename js generator to fcl j…
bthaile Oct 4, 2023
8c19379
formatting
bthaile Oct 16, 2023
0593679
pass in template directory to be more flexible
bthaile Oct 18, 2023
5a9f441
add comment that fcl version 1.3.0 or greater is needed to use templates
bthaile Oct 18, 2023
8857770
add helper func to create fcl js code generator
bthaile Oct 18, 2023
9cd4a66
removed todo: added named return values from method
bthaile Oct 21, 2023
5ad7e6a
update readme to include bindings module
bthaile Oct 21, 2023
6619788
use filepath.Walk to get files from template dir
bthaile Oct 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ignore cmd directory
cmd/

# ignore all .DS_Store files
.DS_Store
23 changes: 23 additions & 0 deletions binding_generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package flixkit

import (
"fmt"
"log"
)

func Generate(lang string, flix *FlowInteractionTemplate, templateLocation string, isLocal bool) (string, error) {
bthaile marked this conversation as resolved.
Show resolved Hide resolved
var contents string
var err error
switch lang {
case "javascript", "js":
contents, err = GenerateJavaScript(flix, templateLocation, isLocal)
default:
return "", fmt.Errorf("language %s not supported", lang)
}

if err != nil {
log.Fatalf("Error generating JavaScript: %v", err)
}

return contents, err
}
118 changes: 44 additions & 74 deletions flixkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,27 @@ import (
"io"
"log"
"net/http"
"regexp"
"os"
)

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 FlixService interface {
GetFlixRaw(ctx context.Context, templateName string) (string, error)
GetFlix(ctx context.Context, templateName string) (*FlowInteractionTemplate, error)
GetFlixByIDRaw(ctx context.Context, templateID string) (string, error)
GetFlixByID(ctx context.Context, templateID string) (*FlowInteractionTemplate, error)
GenFlixBinding(ctx context.Context, templateID string, lang string, isLocal bool) (string, error)
}

// OsFileReader is a real implementation that calls os.ReadFile.
type OsFileReader struct{}
bthaile marked this conversation as resolved.
Show resolved Hide resolved

func (o OsFileReader) ReadFile(filename string) ([]byte, error) {
return os.ReadFile(filename)
}

type FileReader interface {
ReadFile(filename string) ([]byte, error)
}

type flixServiceImpl struct {
Expand All @@ -72,13 +36,18 @@ type flixServiceImpl struct {

type Config struct {
FlixServerURL string
FileReader FileReader
}

func NewFlixService(config *Config) FlixService {
if config.FlixServerURL == "" {
config.FlixServerURL = "https://flix.flow.com/v1/templates"
}

if config.FileReader == nil {
config.FileReader = OsFileReader{}
}

return &flixServiceImpl{
config: config,
}
Expand Down Expand Up @@ -122,36 +91,29 @@ 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)
}
func (s *flixServiceImpl) GenFlixBinding(ctx context.Context, templateLocation string, lang string, isLocal bool) (string, error) {
bthaile marked this conversation as resolved.
Show resolved Hide resolved
var template string
var err error
if isLocal {
template, err = FetchFlixWithContextFromFile(s.config.FileReader, ctx, templateLocation)
bthaile marked this conversation as resolved.
Show resolved Hide resolved
bthaile marked this conversation as resolved.
Show resolved Hide resolved
} else {
template, err = FetchFlixWithContext(ctx, templateLocation)
}

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)
}
if err != nil {
fmt.Println("can not get flix:", err)
bthaile marked this conversation as resolved.
Show resolved Hide resolved
return "", err
}

replacement := fmt.Sprintf("import %s from %s", contractName, network.Address)
cadence = re.ReplaceAllString(cadence, replacement)
}
parsedTemplate, err := ParseFlix(template)
if err != nil {
return "", err
}

return cadence, nil
contents, bindingErr := Generate(lang, parsedTemplate, templateLocation, isLocal)

return contents, bindingErr
}

func ParseFlix(template string) (*FlowInteractionTemplate, error) {
Expand Down Expand Up @@ -188,3 +150,11 @@ func FetchFlixWithContext(ctx context.Context, url string) (string, error) {

return string(body), nil
}

func FetchFlixWithContextFromFile(reader FileReader, ctx context.Context, url string) (string, error) {
bthaile marked this conversation as resolved.
Show resolved Hide resolved
body, err := reader.ReadFile(url)
if err != nil {
log.Fatalf("Failed to read file: %v", err)
}
return string(body), nil
}
81 changes: 76 additions & 5 deletions flixkit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package flixkit

import (
"context"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

var template = `{
var flix_template = `{
"f_type": "InteractionTemplate",
"f_version": "1.0.0",
"id": "290b6b6222b2a77b16db896a80ddf29ebd1fa3038c9e6625a933fa213fce51fa",
Expand Down Expand Up @@ -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")

Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -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()

Expand All @@ -313,3 +315,72 @@ 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")
}

// MockFileReader is a mock implementation for tests.
type MockFileReader struct {
content []byte
err error
}

func (m MockFileReader) ReadFile(filename string) ([]byte, error) {
return m.content, m.err
}

func TestGenFlixWrongLang(t *testing.T) {
assert := assert.New(t)

server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte(flix_template))
}))
defer server.Close()

flixService := NewFlixService(&Config{FlixServerURL: server.URL, FileReader: MockFileReader{
content: []byte(flix_template),
err: nil,
},})
ctx := context.Background()
contents, err := flixService.GenFlixBinding(ctx, "./templateID", "cobal", true)
assert.Error(err, "language cobal not supported")
assert.NotNil(contents, "")
}
func TestGenFlixJS(t *testing.T) {
assert := assert.New(t)

server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte(flix_template))
}))
defer server.Close()

flixService := NewFlixService(&Config{FlixServerURL: server.URL, FileReader: MockFileReader{
content: []byte(flix_template),
err: nil,
},})

ctx := context.Background()
templatePath := "./templateID"
contents, err := flixService.GenFlixBinding(ctx, templatePath, "javascript", true)
assert.NoError(err, "GenFlixBinding should not return an error")
assert.NotNil(contents, "GenFlixBinding should not return a nil Flix")
assert.True(strings.Contains(contents, templatePath), "Expected '%s'", templatePath)
}

func TestGenRemoteFlixJS(t *testing.T) {
assert := assert.New(t)

server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte(flix_template))
}))
defer server.Close()

flixService := NewFlixService(&Config{FlixServerURL: server.URL, FileReader: MockFileReader{
content: []byte(flix_template),
err: nil,
},})

ctx := context.Background()
endpoint := server.URL + "/tempateName"
contents, err := flixService.GenFlixBinding(ctx, endpoint, "javascript", false)
assert.NoError(err, "GenFlixBinding should not return an error")
assert.NotNil(contents, "GenFlixBinding should not return a nil Flix")
assert.True(strings.Contains(contents, endpoint), "Expected '%s'", endpoint)
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ module github.com/onflow/flixkit-go

go 1.20

require github.com/stretchr/testify v1.8.4

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading