mirror of
https://github.com/wavetermdev/wails.git
synced 2026-08-05 13:53:43 -07:00
Js package generation (#554)
* WIP * Generation of index.js * Add RelativeToCwd * Add JSDoc comments * Convert to ES6 syntax * Fix typo * Initial generation of typescript declarations * Typescript improvements * Improved @returns jsdoc * Improved declaration files * Simplified output * Rename file * Tidy up * Revert "Simplified output" This reverts commit 15cdf7382b21a15a36616adbca13c9b034a1907b. * Now parsing actual code * Support Array types * Reimagined parser * Wrap parsing in Parser * Rewritten module generator (TS Only) * Final touches * Slight refactor to improve output * Struct comments. External struct literal binding * Reworked project parser *working* * remove debug info * Refactor of parser * remove the spew * Better Ts support * Better project generation logic * Support local functions in bind() * JS Object generation. Linting. * Support json tags in module generation * Updated mod files * Support vscode file generation * Better global.d.ts * add ts-check to templates * Support TS declaration files * improved 'generate' command for module
This commit is contained in:
@@ -25,3 +25,4 @@ v2/test/hidden/icon.png
|
||||
v2/internal/ffenestri/runtime.c
|
||||
v2/internal/runtime/assets/desktop.js
|
||||
v2/test/kitchensink/frontend/public/bundle.*
|
||||
v2/pkg/parser/testproject/frontend/wails
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||
)
|
||||
|
||||
// AddSubcommand adds the `dev` command for the Wails application
|
||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
command := app.NewSubCommand("generate", "Code Generation Tools")
|
||||
|
||||
// Backend API
|
||||
backendAPI := command.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
|
||||
|
||||
// Quiet Init
|
||||
quiet := false
|
||||
backendAPI.BoolFlag("q", "Supress output to console", &quiet)
|
||||
|
||||
backendAPI.Action(func() error {
|
||||
|
||||
// Create logger
|
||||
logger := clilogger.New(w)
|
||||
logger.Mute(quiet)
|
||||
|
||||
app.PrintBanner()
|
||||
|
||||
logger.Print("Generating Javascript module for Go code...")
|
||||
|
||||
// Start Time
|
||||
start := time.Now()
|
||||
|
||||
p, err := parser.GenerateWailsFrontendPackage()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Println("done.")
|
||||
logger.Println("")
|
||||
|
||||
elapsed := time.Since(start)
|
||||
packages := p.Packages
|
||||
|
||||
// Print report
|
||||
for _, pkg := range p.Packages {
|
||||
if pkg.ShouldGenerate() {
|
||||
logPackage(pkg, logger)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
|
||||
|
||||
return nil
|
||||
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func logPackage(pkg *parser.Package, logger *clilogger.CLILogger) {
|
||||
|
||||
logger.Println("Processed Go package '" + pkg.Gopackage.Name + "' as '" + pkg.Name + "'")
|
||||
for _, strct := range pkg.Structs() {
|
||||
logger.Println("")
|
||||
logger.Println(" Processed struct '" + strct.Name + "'")
|
||||
if strct.IsBound {
|
||||
for _, method := range strct.Methods {
|
||||
logger.Println(" Bound method '" + method.Name + "'")
|
||||
}
|
||||
}
|
||||
if strct.IsUsedAsData {
|
||||
for _, field := range strct.Fields {
|
||||
if !field.Ignored {
|
||||
logger.Print(" Processed ")
|
||||
if field.IsOptional {
|
||||
logger.Print("optional ")
|
||||
}
|
||||
logger.Println("field '" + field.Name + "' as '" + field.JSName() + "'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Println("")
|
||||
|
||||
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
|
||||
// logger.Println(" Original Go Package Path:", pkg.Gopackage.PkgPath)
|
||||
}
|
||||
@@ -32,13 +32,17 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
command.StringFlag("n", "Name of project", &projectName)
|
||||
|
||||
// Setup project directory
|
||||
projectDirectory := "."
|
||||
projectDirectory := ""
|
||||
command.StringFlag("d", "Project directory", &projectDirectory)
|
||||
|
||||
// Quiet Init
|
||||
quiet := false
|
||||
command.BoolFlag("q", "Supress output to console", &quiet)
|
||||
|
||||
// VSCode project files
|
||||
vscode := false
|
||||
command.BoolFlag("vscode", "Generate VSCode project files", &vscode)
|
||||
|
||||
// List templates
|
||||
list := false
|
||||
command.BoolFlag("l", "List templates", &list)
|
||||
@@ -83,10 +87,11 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
// Create Template Options
|
||||
options := &templates.Options{
|
||||
ProjectName: projectName,
|
||||
TargetDir: projectDirectory,
|
||||
TemplateName: templateName,
|
||||
Logger: logger,
|
||||
ProjectName: projectName,
|
||||
TargetDir: projectDirectory,
|
||||
TemplateName: templateName,
|
||||
Logger: logger,
|
||||
GenerateVSCode: vscode,
|
||||
}
|
||||
|
||||
return initProject(options)
|
||||
@@ -110,6 +115,14 @@ func initProject(options *templates.Options) error {
|
||||
// Output stats
|
||||
elapsed := time.Since(start)
|
||||
options.Logger.Println("")
|
||||
options.Logger.Println("Project Name: " + options.ProjectName)
|
||||
options.Logger.Println("Project Directory: " + options.TargetDir)
|
||||
options.Logger.Println("Project Template: " + options.TemplateName)
|
||||
options.Logger.Println("")
|
||||
if options.GenerateVSCode {
|
||||
options.Logger.Println("VSCode config files generated.")
|
||||
}
|
||||
options.Logger.Println("")
|
||||
options.Logger.Println(fmt.Sprintf("Initialised project '%s' in %s.", options.ProjectName, elapsed.Round(time.Millisecond).String()))
|
||||
options.Logger.Println("")
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/build"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/dev"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/doctor"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/initialise"
|
||||
)
|
||||
|
||||
@@ -37,6 +38,11 @@ func main() {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
err = generate.AddSubcommand(app, os.Stdout)
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
err = app.Run()
|
||||
if err != nil {
|
||||
println("\n\nERROR: " + err.Error())
|
||||
|
||||
@@ -3,19 +3,23 @@ module github.com/wailsapp/wails/v2
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/fatih/structtag v1.2.0
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/imdario/mergo v0.3.11
|
||||
github.com/leaanthony/clir v1.0.4
|
||||
github.com/leaanthony/gosod v0.0.4
|
||||
github.com/leaanthony/slicer v1.4.1
|
||||
github.com/leaanthony/slicer v1.5.0
|
||||
github.com/matryer/is v1.4.0
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/tdewolff/minify v2.3.6+incompatible
|
||||
github.com/tdewolff/minify/v2 v2.9.5
|
||||
github.com/tdewolff/parse v2.3.4+incompatible // indirect
|
||||
github.com/tdewolff/test v1.0.6 // indirect
|
||||
github.com/xyproto/xpm v1.2.1
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
|
||||
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||
nhooyr.io/websocket v1.8.6
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
|
||||
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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
@@ -44,13 +44,12 @@ github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU
|
||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||
github.com/leaanthony/gosod v0.0.4 h1:v4hepo4IyL8E8c9qzDsvYcA0KGh7Npf8As74K5ibQpI=
|
||||
github.com/leaanthony/gosod v0.0.4/go.mod h1:nGMCb1PJfXwBDbOAike78jEYlpqge+xUKFf0iBKjKxU=
|
||||
github.com/leaanthony/slicer v1.4.1 h1:X/SmRIDhkUAolP79mSTO0jTcVX1k504PJBqvV6TwP0w=
|
||||
github.com/leaanthony/slicer v1.4.1/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
@@ -63,23 +62,19 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tdewolff/minify v1.1.0 h1:nxHQi1ML+g3ZbZHffiZ6eC7vMqNvSRfX3KB5Y5y/kfw=
|
||||
github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=
|
||||
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
|
||||
github.com/tdewolff/minify/v2 v2.9.5 h1:+fHvqLencVdv14B+zgxQGhetF9qXl/nRTN/1mcyQwpM=
|
||||
github.com/tdewolff/minify/v2 v2.9.5/go.mod h1:jshtBj/uUJH6JX1fuxTLnnHOA1RVJhF5MM+leJzDKb4=
|
||||
github.com/tdewolff/parse v1.1.0 h1:tMjj9GCK8zzwjWyxdZ4pabzdWO1VG+G3bvCnG6aUIyQ=
|
||||
github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=
|
||||
github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ=
|
||||
github.com/tdewolff/parse/v2 v2.5.3 h1:fnPIstKgEfxd3+wwHnH73sAYydsR0o/jYhcQ6c5PkrA=
|
||||
github.com/tdewolff/parse/v2 v2.5.3/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
|
||||
@@ -68,6 +68,8 @@ func getMethods(value interface{}) ([]*BoundMethod, error) {
|
||||
boundMethod.Inputs = inputs
|
||||
|
||||
// Iterate outputs
|
||||
// TODO: Determine what to do about limiting return types
|
||||
// especially around errors.
|
||||
outputParamCount := methodType.NumOut()
|
||||
var outputs []*Parameter
|
||||
for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ {
|
||||
|
||||
@@ -20,6 +20,17 @@ func LocalDirectory() string {
|
||||
return filepath.Dir(thisFile)
|
||||
}
|
||||
|
||||
// RelativeToCwd returns an absolute path based on the cwd
|
||||
// and the given relative path
|
||||
func RelativeToCwd(relativePath string) (string, error) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return filepath.Join(cwd, relativePath), nil
|
||||
}
|
||||
|
||||
// Mkdir will create the given directory
|
||||
func Mkdir(dirname string) error {
|
||||
return os.Mkdir(dirname, 0755)
|
||||
@@ -169,3 +180,23 @@ func GetSubdirectories(rootDir string) (*slicer.StringSlicer, error) {
|
||||
})
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func DirIsEmpty(dir string) (bool, error) {
|
||||
|
||||
if !DirExists(dir) {
|
||||
return false, fmt.Errorf("DirIsEmpty called with a non-existant directory: %s", dir)
|
||||
}
|
||||
|
||||
// CREDIT: https://stackoverflow.com/a/30708914/8325411
|
||||
f, err := os.Open(dir)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Readdirnames(1) // Or f.Readdir(1)
|
||||
if err == io.EOF {
|
||||
return true, nil
|
||||
}
|
||||
return false, err // Either not empty or error, suits both cases
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ func ParseProject(projectPath string) (BoundStructs, error) {
|
||||
var wailsPkgVar = ""
|
||||
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
var s string
|
||||
switch x := n.(type) {
|
||||
// Parse import declarations
|
||||
case *ast.ImportSpec:
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package operatingsystem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
func platformInfo() (*OS, error) {
|
||||
// Default value
|
||||
var result OS
|
||||
result.ID = "Unknown"
|
||||
result.Name = "Windows"
|
||||
result.Version = "Unknown"
|
||||
|
||||
// Credit: https://stackoverflow.com/a/33288328
|
||||
// Ignore errors as it isn't a showstopper
|
||||
key, _ := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
||||
|
||||
defer key.Close()
|
||||
|
||||
fmt.Printf("%+v\n", key)
|
||||
|
||||
// Ignore errors as it isn't a showstopper
|
||||
productName, _, _ := key.GetStringValue("ProductName")
|
||||
fmt.Println(productName)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
@@ -2,14 +2,20 @@
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
import "github.com/wailsapp/wails/v2/internal/system/operatingsystem"
|
||||
|
||||
func (i *Info) discover() {
|
||||
dll := syscall.MustLoadDLL("kernel32.dll")
|
||||
p := dll.MustFindProc("GetVersion")
|
||||
v, _, _ := p.Call()
|
||||
fmt.Printf("Windows version %d.%d (Build %d)\n", byte(v), uint8(v>>8), uint16(v>>16))
|
||||
func (i *Info) discover() error {
|
||||
|
||||
var err error
|
||||
osinfo, err := operatingsystem.Info()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.OS = osinfo
|
||||
|
||||
// dll := syscall.MustLoadDLL("kernel32.dll")
|
||||
// p := dll.MustFindProc("GetVersion")
|
||||
// v, _, _ := p.Call()
|
||||
// fmt.Printf("Windows version %d.%d (Build %d)\n", byte(v), uint8(v>>8), uint16(v>>16))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Wails: Debug {{.ProjectName}} (Desktop)",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "exec",
|
||||
"program": "${workspaceFolder}/{{.PathToDesktopBinary}}",
|
||||
"preLaunchTask": "build_desktop",
|
||||
"cwd": "",
|
||||
"env": {},
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "Wails: Debug {{.ProjectName}} (Server)",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "exec",
|
||||
"program": "${workspaceFolder}/{{.PathToServerBinary}}",
|
||||
"preLaunchTask": "build_server",
|
||||
"cwd": "",
|
||||
"env": {},
|
||||
"args": []
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build_desktop",
|
||||
"type": "shell",
|
||||
"options": {
|
||||
"cwd": "{{.TargetDir}}"
|
||||
},
|
||||
"command": "wails build"
|
||||
},
|
||||
{
|
||||
"label": "build_server",
|
||||
"type": "shell",
|
||||
"options": {
|
||||
"cwd": "{{.TargetDir}}"
|
||||
},
|
||||
"command": "wails build -t server"
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/gosod"
|
||||
@@ -31,11 +32,14 @@ type Data struct {
|
||||
|
||||
// Options for installing a template
|
||||
type Options struct {
|
||||
ProjectName string
|
||||
TemplateName string
|
||||
BinaryName string
|
||||
TargetDir string
|
||||
Logger *clilogger.CLILogger
|
||||
ProjectName string
|
||||
TemplateName string
|
||||
BinaryName string
|
||||
TargetDir string
|
||||
Logger *clilogger.CLILogger
|
||||
GenerateVSCode bool
|
||||
PathToDesktopBinary string
|
||||
PathToServerBinary string
|
||||
}
|
||||
|
||||
// Template holds data relating to a template
|
||||
@@ -162,9 +166,24 @@ func Install(options *Options) error {
|
||||
}
|
||||
|
||||
// Did the user want to install in current directory?
|
||||
if options.TargetDir == "." {
|
||||
// Yes - use cwd
|
||||
options.TargetDir = cwd
|
||||
if options.TargetDir == "" {
|
||||
|
||||
// If the current directory is empty, use it
|
||||
isEmpty, err := fs.DirIsEmpty(cwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isEmpty {
|
||||
// Yes - use cwd
|
||||
options.TargetDir = cwd
|
||||
} else {
|
||||
options.TargetDir = filepath.Join(cwd, options.ProjectName)
|
||||
if fs.DirExists(options.TargetDir) {
|
||||
return fmt.Errorf("cannot create project directory. Dir exists: %s", options.TargetDir)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Get the absolute path of the given directory
|
||||
targetDir, err := filepath.Abs(filepath.Join(cwd, options.TargetDir))
|
||||
@@ -213,7 +232,11 @@ func Install(options *Options) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Calculate the directory name
|
||||
err = generateIDEFiles(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -243,3 +266,40 @@ func OutputList(logger *clilogger.CLILogger) error {
|
||||
table.Render()
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateIDEFiles(options *Options) error {
|
||||
|
||||
if options.GenerateVSCode {
|
||||
return generateVSCodeFiles(options)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateVSCodeFiles(options *Options) error {
|
||||
|
||||
targetDir := filepath.Join(options.TargetDir, ".vscode")
|
||||
sourceDir := fs.RelativePath(filepath.Join("./ides/vscode"))
|
||||
|
||||
// Use Gosod to install the template
|
||||
installer, err := gosod.TemplateDir(sourceDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
binaryName := filepath.Base(options.TargetDir)
|
||||
if runtime.GOOS == "windows" {
|
||||
// yay windows
|
||||
binaryName += ".exe"
|
||||
}
|
||||
|
||||
options.PathToDesktopBinary = filepath.Join("build", runtime.GOOS, "desktop", binaryName)
|
||||
options.PathToServerBinary = filepath.Join("build", runtime.GOOS, "server", binaryName)
|
||||
|
||||
err = installer.Extract(targetDir, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/internal/project"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||
)
|
||||
|
||||
// Mode is the type used to indicate the build modes
|
||||
@@ -89,6 +90,13 @@ func Build(options *Options) (string, error) {
|
||||
// Initialise Builder
|
||||
builder.SetProjectData(projectData)
|
||||
|
||||
// Generate Frontend JS Package
|
||||
outputLogger.Println(" - Generating Backend JS Package")
|
||||
// Ignore the parser report coming back
|
||||
_, err = parser.GenerateWailsFrontendPackage()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !options.IgnoreFrontend {
|
||||
outputLogger.Println(" - Building Wails Frontend")
|
||||
err = builder.BuildFrontend(outputLogger)
|
||||
@@ -115,6 +123,7 @@ func Build(options *Options) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
outputLogger.Println("done.")
|
||||
|
||||
// Do we need to pack the app?
|
||||
if options.Pack {
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package build
|
||||
|
||||
func packageApplication(options *Options) error {
|
||||
// TBD
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package parser
|
||||
|
||||
import "go/ast"
|
||||
|
||||
func (p *Package) getApplicationVariableName(file *ast.File, wailsImportName string) string {
|
||||
|
||||
// Iterate through the whole file looking for the application name
|
||||
applicationVariableName := ""
|
||||
|
||||
// Inspect the file
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
// Parse Assignments looking for application name
|
||||
if assignStmt, ok := n.(*ast.AssignStmt); ok {
|
||||
|
||||
// Check the RHS is of the form:
|
||||
// `app := wails.CreateApp()` or
|
||||
// `app := wails.CreateAppWithOptions`
|
||||
for _, rhs := range assignStmt.Rhs {
|
||||
ce, ok := rhs.(*ast.CallExpr)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
se, ok := ce.Fun.(*ast.SelectorExpr)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
i, ok := se.X.(*ast.Ident)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// Have we found the wails import name?
|
||||
if i.Name == wailsImportName {
|
||||
// Check we are calling a function to create the app
|
||||
if se.Sel.Name == "CreateApp" || se.Sel.Name == "CreateAppWithOptions" {
|
||||
if len(assignStmt.Lhs) == 1 {
|
||||
i, ok := assignStmt.Lhs[0].(*ast.Ident)
|
||||
if ok {
|
||||
// Found the app variable name
|
||||
applicationVariableName = i.Name
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return applicationVariableName
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parseComments(comments *ast.CommentGroup) []string {
|
||||
var result []string
|
||||
|
||||
if comments == nil {
|
||||
return result
|
||||
}
|
||||
|
||||
for _, comment := range comments.List {
|
||||
commentText := strings.TrimPrefix(comment.Text, "//")
|
||||
result = append(result, commentText)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
|
||||
// JSType represents a javascript type
|
||||
type JSType string
|
||||
|
||||
const (
|
||||
// JsString is a JS string
|
||||
JsString JSType = "string"
|
||||
// JsBoolean is a JS bool
|
||||
JsBoolean = "boolean"
|
||||
// JsInt is a JS number
|
||||
JsInt = "number"
|
||||
// JsFloat is a JS number
|
||||
JsFloat = "number"
|
||||
// JsArray is a JS array
|
||||
JsArray = "Array"
|
||||
// JsObject is a JS object
|
||||
JsObject = "Object"
|
||||
// JsUnsupported represents a type that cannot be converted
|
||||
JsUnsupported = "*"
|
||||
)
|
||||
|
||||
func goTypeToJS(input *Field) string {
|
||||
switch input.Type {
|
||||
case "string":
|
||||
return "string"
|
||||
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
|
||||
return "number"
|
||||
case "float32", "float64":
|
||||
return "number"
|
||||
case "bool":
|
||||
return "boolean"
|
||||
// case reflect.Array, reflect.Slice:
|
||||
// return JsArray
|
||||
// case reflect.Ptr, reflect.Struct, reflect.Map, reflect.Interface:
|
||||
// return JsObject
|
||||
case "struct":
|
||||
return input.Struct.Name
|
||||
default:
|
||||
fmt.Printf("Unsupported input to goTypeToJS: %+v", input)
|
||||
return "*"
|
||||
}
|
||||
}
|
||||
|
||||
// goTypeToTS converts the given field into a Typescript type
|
||||
// The pkgName is the package that the field is being output in.
|
||||
// This is used to ensure we don't qualify local structs.
|
||||
func goTypeToTS(input *Field, pkgName string) string {
|
||||
var result string
|
||||
switch input.Type {
|
||||
case "string":
|
||||
result = "string"
|
||||
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
|
||||
result = "number"
|
||||
case "float32", "float64":
|
||||
result = "number"
|
||||
case "bool":
|
||||
result = "boolean"
|
||||
case "struct":
|
||||
if input.Struct.Package.Name != "" {
|
||||
if input.Struct.Package.Name != pkgName {
|
||||
result = input.Struct.Package.Name + "."
|
||||
}
|
||||
}
|
||||
result += input.Struct.Name
|
||||
// case reflect.Array, reflect.Slice:
|
||||
// return string(JsArray)
|
||||
// case reflect.Ptr, reflect.Struct:
|
||||
// fqt := input.Type().String()
|
||||
// return strings.Split(fqt, ".")[1]
|
||||
// case reflect.Map, reflect.Interface:
|
||||
// return string(JsObject)
|
||||
default:
|
||||
fmt.Printf("Unsupported input to goTypeToTS: %+v", input)
|
||||
return JsUnsupported
|
||||
}
|
||||
|
||||
if input.IsArray {
|
||||
result = result + "[]"
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func goTypeToTSDeclaration(input *Field, pkgName string) string {
|
||||
var result string
|
||||
switch input.Type {
|
||||
case "string":
|
||||
result = "string"
|
||||
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
|
||||
result = "number"
|
||||
case "float32", "float64":
|
||||
result = "number"
|
||||
case "bool":
|
||||
result = "boolean"
|
||||
case "struct":
|
||||
if input.Struct.Package.Name != "" {
|
||||
if input.Struct.Package.Name != pkgName {
|
||||
result = `import("./_` + input.Struct.Package.Name + `").`
|
||||
}
|
||||
}
|
||||
result += input.Struct.Name
|
||||
// case reflect.Array, reflect.Slice:
|
||||
// return string(JsArray)
|
||||
// case reflect.Ptr, reflect.Struct:
|
||||
// fqt := input.Type().String()
|
||||
// return strings.Split(fqt, ".")[1]
|
||||
// case reflect.Map, reflect.Interface:
|
||||
// return string(JsObject)
|
||||
default:
|
||||
fmt.Printf("Unsupported input to goTypeToTS: %+v", input)
|
||||
return JsUnsupported
|
||||
}
|
||||
|
||||
if input.IsArray {
|
||||
result = result + "[]"
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func isUnresolvedType(typeName string) bool {
|
||||
switch typeName {
|
||||
case "string":
|
||||
return false
|
||||
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
|
||||
return false
|
||||
case "float32", "float64":
|
||||
return false
|
||||
case "bool":
|
||||
return false
|
||||
case "struct":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
var reservedJSWords []string = []string{"abstract", "arguments", "await", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default", "delete", "do", "double", "else", "enum", "eval", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", "implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof", "var", "void", "volatile", "while", "with", "yield", "Array", "Date", "eval", "function", "hasOwnProperty", "Infinity", "isFinite", "isNaN", "isPrototypeOf", "length", "Math", "NaN", "Number", "Object", "prototype", "String", "toString", "undefined", "valueOf"}
|
||||
var jsReservedWords *slicer.StringSlicer = slicer.String(reservedJSWords)
|
||||
|
||||
func isJSReservedWord(input string) bool {
|
||||
return jsReservedWords.Contains(input)
|
||||
}
|
||||
|
||||
func startsWithLowerCaseLetter(input string) bool {
|
||||
firstLetter := string(input[0])
|
||||
return strings.ToLower(firstLetter) == firstLetter
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"strings"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/fatih/structtag"
|
||||
)
|
||||
|
||||
// Field defines a parsed struct field
|
||||
type Field struct {
|
||||
|
||||
// Name of the field
|
||||
Name string
|
||||
|
||||
// The type of the field.
|
||||
// "struct" if it's a struct
|
||||
Type string
|
||||
|
||||
// A pointer to the struct if the Type is "struct"
|
||||
Struct *Struct
|
||||
|
||||
// User comments on the field
|
||||
Comments []string
|
||||
|
||||
// Indicates if the Field is an array of type "Type"
|
||||
IsArray bool
|
||||
|
||||
// JSON field name defined by a json tag
|
||||
JSONOptions
|
||||
}
|
||||
|
||||
type JSONOptions struct {
|
||||
Name string
|
||||
IsOptional bool
|
||||
Ignored bool
|
||||
}
|
||||
|
||||
// JSType returns the Javascript type for this field
|
||||
func (f *Field) JSType() string {
|
||||
return string(goTypeToJS(f))
|
||||
}
|
||||
|
||||
// JSName returns the Javascript name for this field
|
||||
func (f *Field) JSName() string {
|
||||
if f.JSONOptions.Name != "" {
|
||||
return f.JSONOptions.Name
|
||||
}
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// TSName returns the Typescript name for this field
|
||||
func (f *Field) TSName() string {
|
||||
result := f.Name
|
||||
if f.JSONOptions.Name != "" {
|
||||
result = f.JSONOptions.Name
|
||||
}
|
||||
if f.IsOptional {
|
||||
result += "?"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// AsTSDeclaration returns a TS definition of a single type field
|
||||
func (f *Field) AsTSDeclaration(pkgName string) string {
|
||||
return f.TSName() + ": " + f.TypeAsTSType(pkgName)
|
||||
}
|
||||
|
||||
// NameForPropertyDoc returns a formatted name for the jsdoc @property declaration
|
||||
func (f *Field) NameForPropertyDoc() string {
|
||||
if f.IsOptional {
|
||||
return "[" + f.JSName() + "]"
|
||||
}
|
||||
return f.JSName()
|
||||
}
|
||||
|
||||
// TypeForPropertyDoc returns a formatted name for the jsdoc @property declaration
|
||||
func (f *Field) TypeForPropertyDoc() string {
|
||||
result := goTypeToJS(f)
|
||||
if f.IsArray {
|
||||
result += "[]"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// TypeAsTSType converts the Field type to something TS wants
|
||||
func (f *Field) TypeAsTSType(pkgName string) string {
|
||||
var result = ""
|
||||
switch f.Type {
|
||||
case "string":
|
||||
result = "string"
|
||||
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
|
||||
result = "number"
|
||||
case "float32", "float64":
|
||||
result = "number"
|
||||
case "bool":
|
||||
result = "boolean"
|
||||
case "struct":
|
||||
if f.Struct.Package != nil {
|
||||
if f.Struct.Package.Name != pkgName {
|
||||
result = f.Struct.Package.Name + "."
|
||||
}
|
||||
}
|
||||
result = result + f.Struct.Name
|
||||
default:
|
||||
result = "any"
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *Parser) parseField(file *ast.File, field *ast.Field, pkg *Package) ([]*Field, error) {
|
||||
var result []*Field
|
||||
|
||||
var fieldType string
|
||||
var strct *Struct
|
||||
var isArray bool
|
||||
|
||||
var jsonOptions JSONOptions
|
||||
|
||||
// Determine type
|
||||
switch t := field.Type.(type) {
|
||||
case *ast.Ident:
|
||||
fieldType = t.Name
|
||||
|
||||
unresolved := isUnresolvedType(fieldType)
|
||||
|
||||
// Check if this type is actually a struct
|
||||
if unresolved {
|
||||
// Assume it is a struct
|
||||
// Parse the struct
|
||||
var err error
|
||||
strct, err = p.parseStruct(pkg, t.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strct == nil {
|
||||
fieldName := "<anonymous>"
|
||||
if len(field.Names) > 0 {
|
||||
fieldName = field.Names[0].Name
|
||||
}
|
||||
return nil, fmt.Errorf("unresolved type in field %s: %s", fieldName, fieldType)
|
||||
}
|
||||
|
||||
fieldType = "struct"
|
||||
|
||||
}
|
||||
case *ast.StarExpr:
|
||||
fieldType = "struct"
|
||||
packageName, structName, err := parseStructNameFromStarExpr(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If this is an external package, find it
|
||||
if packageName != "" {
|
||||
referencedGoPackage := pkg.getImportByName(packageName, file)
|
||||
referencedPackage := p.getPackageByID(referencedGoPackage.ID)
|
||||
|
||||
// If we found the struct, save it as an external package reference
|
||||
if referencedPackage != nil {
|
||||
pkg.addExternalReference(referencedPackage)
|
||||
}
|
||||
|
||||
// We save this to pkg anyway, because we want to know if this package
|
||||
// was NOT found
|
||||
pkg = referencedPackage
|
||||
}
|
||||
|
||||
// If this is a package in our project, parse the struct!
|
||||
if pkg != nil {
|
||||
|
||||
// Parse the struct
|
||||
strct, err = p.parseStruct(pkg, structName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case *ast.ArrayType:
|
||||
isArray = true
|
||||
// Parse the Elt (There must be a better way!)
|
||||
switch t := t.Elt.(type) {
|
||||
case *ast.Ident:
|
||||
fieldType = t.Name
|
||||
case *ast.StarExpr:
|
||||
fieldType = "struct"
|
||||
packageName, structName, err := parseStructNameFromStarExpr(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If this is an external package, find it
|
||||
if packageName != "" {
|
||||
referencedGoPackage := pkg.getImportByName(packageName, file)
|
||||
referencedPackage := p.getPackageByID(referencedGoPackage.ID)
|
||||
|
||||
// If we found the struct, save it as an external package reference
|
||||
if referencedPackage != nil {
|
||||
pkg.addExternalReference(referencedPackage)
|
||||
}
|
||||
|
||||
// We save this to pkg anyway, because we want to know if this package
|
||||
// was NOT found
|
||||
pkg = referencedPackage
|
||||
}
|
||||
|
||||
// If this is a package in our project, parse the struct!
|
||||
if pkg != nil {
|
||||
|
||||
// Parse the struct
|
||||
strct, err = p.parseStruct(pkg, structName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
default:
|
||||
// We will default to "Array<any>" for eg nested arrays
|
||||
fieldType = "any"
|
||||
}
|
||||
|
||||
default:
|
||||
spew.Dump(t)
|
||||
return nil, fmt.Errorf("unsupported field found in struct: %+v", t)
|
||||
}
|
||||
|
||||
// Parse json tag if available
|
||||
if field.Tag != nil {
|
||||
err := parseJSONOptions(field.Tag.Value, &jsonOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over names if we have
|
||||
if len(field.Names) > 0 {
|
||||
|
||||
for _, name := range field.Names {
|
||||
|
||||
// TODO: Check field names are valid in JS
|
||||
if isJSReservedWord(name.Name) {
|
||||
return nil, fmt.Errorf("unable to use field name %s - reserved word in Javascript", name.Name)
|
||||
}
|
||||
|
||||
// Create a field per name
|
||||
thisField := &Field{
|
||||
Comments: parseComments(field.Doc),
|
||||
}
|
||||
thisField.Name = name.Name
|
||||
thisField.Type = fieldType
|
||||
thisField.Struct = strct
|
||||
thisField.IsArray = isArray
|
||||
thisField.JSONOptions = jsonOptions
|
||||
|
||||
result = append(result, thisField)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// When we have no name
|
||||
thisField := &Field{
|
||||
Comments: parseComments(field.Doc),
|
||||
}
|
||||
thisField.Type = fieldType
|
||||
thisField.Struct = strct
|
||||
thisField.IsArray = isArray
|
||||
result = append(result, thisField)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func parseJSONOptions(fieldTag string, jsonOptions *JSONOptions) error {
|
||||
|
||||
// Remove backticks
|
||||
fieldTag = strings.Trim(fieldTag, "`")
|
||||
|
||||
// Parse the tag
|
||||
tags, err := structtag.Parse(fieldTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonTag, err := tags.Get("json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if jsonTag == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save the name
|
||||
jsonOptions.Name = jsonTag.Name
|
||||
|
||||
// Check if this field is ignored
|
||||
if jsonTag.Name == "-" {
|
||||
jsonOptions.Ignored = true
|
||||
}
|
||||
|
||||
// Check if this field is optional
|
||||
if jsonTag.HasOption("omitempty") {
|
||||
jsonOptions.IsOptional = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user