mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 07:40:17 +08:00
Add support for interface generation and enums (#3047)
* Add support to output ts models as interfaces * Add support to generate enums from golang * cleanup logs * add missing documentation * fix package names for enum. Fix processing enums that are in separate packages * revert golang 1.21 * Fix spelling * Add support for simplified version of Enum for typescriptify * update docs * removed unused logs * Add tests. Fix imported enums types in models --------- Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
This commit is contained in:
parent
929dfb4123
commit
b9de31e38e
@ -43,10 +43,15 @@ func generateModule(f *flags.GenerateModule) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if projectConfig.Bindings.TsGeneration.OutputType == "" {
|
||||||
|
projectConfig.Bindings.TsGeneration.OutputType = "classes"
|
||||||
|
}
|
||||||
|
|
||||||
_, err = bindings.GenerateBindings(bindings.Options{
|
_, err = bindings.GenerateBindings(bindings.Options{
|
||||||
Tags: buildTags,
|
Tags: buildTags,
|
||||||
TsPrefix: projectConfig.Bindings.TsGeneration.Prefix,
|
TsPrefix: projectConfig.Bindings.TsGeneration.Prefix,
|
||||||
TsSuffix: projectConfig.Bindings.TsGeneration.Suffix,
|
TsSuffix: projectConfig.Bindings.TsGeneration.Suffix,
|
||||||
|
TsOutputType: projectConfig.Bindings.TsGeneration.OutputType,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -31,6 +31,7 @@ func (a *App) Run() error {
|
|||||||
|
|
||||||
var tsPrefixFlag *string
|
var tsPrefixFlag *string
|
||||||
var tsPostfixFlag *string
|
var tsPostfixFlag *string
|
||||||
|
var tsOutputTypeFlag *string
|
||||||
|
|
||||||
tsPrefix := os.Getenv("tsprefix")
|
tsPrefix := os.Getenv("tsprefix")
|
||||||
if tsPrefix == "" {
|
if tsPrefix == "" {
|
||||||
@ -42,6 +43,11 @@ func (a *App) Run() error {
|
|||||||
tsPostfixFlag = bindingFlags.String("tssuffix", "", "Suffix for generated typescript entities")
|
tsPostfixFlag = bindingFlags.String("tssuffix", "", "Suffix for generated typescript entities")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tsOutputType := os.Getenv("tsoutputtype")
|
||||||
|
if tsOutputType == "" {
|
||||||
|
tsOutputTypeFlag = bindingFlags.String("tsoutputtype", "", "Output type for generated typescript entities (classes|interfaces)")
|
||||||
|
}
|
||||||
|
|
||||||
_ = bindingFlags.Parse(os.Args[1:])
|
_ = bindingFlags.Parse(os.Args[1:])
|
||||||
if tsPrefixFlag != nil {
|
if tsPrefixFlag != nil {
|
||||||
tsPrefix = *tsPrefixFlag
|
tsPrefix = *tsPrefixFlag
|
||||||
@ -49,11 +55,15 @@ func (a *App) Run() error {
|
|||||||
if tsPostfixFlag != nil {
|
if tsPostfixFlag != nil {
|
||||||
tsSuffix = *tsPostfixFlag
|
tsSuffix = *tsPostfixFlag
|
||||||
}
|
}
|
||||||
|
if tsOutputTypeFlag != nil {
|
||||||
|
tsOutputType = *tsOutputTypeFlag
|
||||||
|
}
|
||||||
|
|
||||||
appBindings := binding.NewBindings(a.logger, a.options.Bind, bindingExemptions, IsObfuscated())
|
appBindings := binding.NewBindings(a.logger, a.options.Bind, bindingExemptions, IsObfuscated(), a.options.EnumBind)
|
||||||
|
|
||||||
appBindings.SetTsPrefix(tsPrefix)
|
appBindings.SetTsPrefix(tsPrefix)
|
||||||
appBindings.SetTsSuffix(tsSuffix)
|
appBindings.SetTsSuffix(tsSuffix)
|
||||||
|
appBindings.SetOutputType(tsOutputType)
|
||||||
|
|
||||||
err := generateBindings(appBindings)
|
err := generateBindings(appBindings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -209,7 +209,7 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
|||||||
appoptions.OnDomReady,
|
appoptions.OnDomReady,
|
||||||
appoptions.OnBeforeClose,
|
appoptions.OnBeforeClose,
|
||||||
}
|
}
|
||||||
appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions, false)
|
appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions, false, appoptions.EnumBind)
|
||||||
|
|
||||||
eventHandler := runtime.NewEvents(myLogger)
|
eventHandler := runtime.NewEvents(myLogger)
|
||||||
ctx = context.WithValue(ctx, "events", eventHandler)
|
ctx = context.WithValue(ctx, "events", eventHandler)
|
||||||
|
@ -72,7 +72,7 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
|||||||
appoptions.OnDomReady,
|
appoptions.OnDomReady,
|
||||||
appoptions.OnBeforeClose,
|
appoptions.OnBeforeClose,
|
||||||
}
|
}
|
||||||
appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions, IsObfuscated())
|
appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions, IsObfuscated(), appoptions.EnumBind)
|
||||||
eventHandler := runtime.NewEvents(myLogger)
|
eventHandler := runtime.NewEvents(myLogger)
|
||||||
ctx = context.WithValue(ctx, "events", eventHandler)
|
ctx = context.WithValue(ctx, "events", eventHandler)
|
||||||
// Attach logger to context
|
// Attach logger to context
|
||||||
|
@ -23,17 +23,20 @@ type Bindings struct {
|
|||||||
exemptions slicer.StringSlicer
|
exemptions slicer.StringSlicer
|
||||||
|
|
||||||
structsToGenerateTS map[string]map[string]interface{}
|
structsToGenerateTS map[string]map[string]interface{}
|
||||||
|
enumsToGenerateTS map[string]map[string]interface{}
|
||||||
tsPrefix string
|
tsPrefix string
|
||||||
tsSuffix string
|
tsSuffix string
|
||||||
|
tsInterface bool
|
||||||
obfuscate bool
|
obfuscate bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBindings returns a new Bindings object
|
// NewBindings returns a new Bindings object
|
||||||
func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exemptions []interface{}, obfuscate bool) *Bindings {
|
func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exemptions []interface{}, obfuscate bool, enumsToBind []interface{}) *Bindings {
|
||||||
result := &Bindings{
|
result := &Bindings{
|
||||||
db: newDB(),
|
db: newDB(),
|
||||||
logger: logger.CustomLogger("Bindings"),
|
logger: logger.CustomLogger("Bindings"),
|
||||||
structsToGenerateTS: make(map[string]map[string]interface{}),
|
structsToGenerateTS: make(map[string]map[string]interface{}),
|
||||||
|
enumsToGenerateTS: make(map[string]map[string]interface{}),
|
||||||
obfuscate: obfuscate,
|
obfuscate: obfuscate,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +50,10 @@ func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exem
|
|||||||
result.exemptions.Add(name)
|
result.exemptions.Add(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, enum := range enumsToBind {
|
||||||
|
result.AddEnumToGenerateTS(enum)
|
||||||
|
}
|
||||||
|
|
||||||
// Add the structs to bind
|
// Add the structs to bind
|
||||||
for _, ptr := range structPointersToBind {
|
for _, ptr := range structPointersToBind {
|
||||||
err := result.Add(ptr)
|
err := result.Add(ptr)
|
||||||
@ -88,16 +95,21 @@ func (b *Bindings) ToJSON() (string, error) {
|
|||||||
func (b *Bindings) GenerateModels() ([]byte, error) {
|
func (b *Bindings) GenerateModels() ([]byte, error) {
|
||||||
models := map[string]string{}
|
models := map[string]string{}
|
||||||
var seen slicer.StringSlicer
|
var seen slicer.StringSlicer
|
||||||
|
var seenEnumsPackages slicer.StringSlicer
|
||||||
allStructNames := b.getAllStructNames()
|
allStructNames := b.getAllStructNames()
|
||||||
allStructNames.Sort()
|
allStructNames.Sort()
|
||||||
|
allEnumNames := b.getAllEnumNames()
|
||||||
|
allEnumNames.Sort()
|
||||||
for packageName, structsToGenerate := range b.structsToGenerateTS {
|
for packageName, structsToGenerate := range b.structsToGenerateTS {
|
||||||
thisPackageCode := ""
|
thisPackageCode := ""
|
||||||
w := typescriptify.New()
|
w := typescriptify.New()
|
||||||
w.WithPrefix(b.tsPrefix)
|
w.WithPrefix(b.tsPrefix)
|
||||||
w.WithSuffix(b.tsSuffix)
|
w.WithSuffix(b.tsSuffix)
|
||||||
|
w.WithInterface(b.tsInterface)
|
||||||
w.Namespace = packageName
|
w.Namespace = packageName
|
||||||
w.WithBackupDir("")
|
w.WithBackupDir("")
|
||||||
w.KnownStructs = allStructNames
|
w.KnownStructs = allStructNames
|
||||||
|
w.KnownEnums = allEnumNames
|
||||||
// sort the structs
|
// sort the structs
|
||||||
var structNames []string
|
var structNames []string
|
||||||
for structName := range structsToGenerate {
|
for structName := range structsToGenerate {
|
||||||
@ -112,6 +124,20 @@ func (b *Bindings) GenerateModels() ([]byte, error) {
|
|||||||
structInterface := structsToGenerate[structName]
|
structInterface := structsToGenerate[structName]
|
||||||
w.Add(structInterface)
|
w.Add(structInterface)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we have enums for this package, add them as well
|
||||||
|
var enums, enumsExist = b.enumsToGenerateTS[packageName]
|
||||||
|
if enumsExist {
|
||||||
|
for enumName, enum := range enums {
|
||||||
|
fqemumname := packageName + "." + enumName
|
||||||
|
if seen.Contains(fqemumname) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
w.AddEnum(enum)
|
||||||
|
}
|
||||||
|
seenEnumsPackages.Add(packageName)
|
||||||
|
}
|
||||||
|
|
||||||
str, err := w.Convert(nil)
|
str, err := w.Convert(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -121,6 +147,35 @@ func (b *Bindings) GenerateModels() ([]byte, error) {
|
|||||||
models[packageName] = thisPackageCode
|
models[packageName] = thisPackageCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add outstanding enums to the models that were not in packages with structs
|
||||||
|
for packageName, enumsToGenerate := range b.enumsToGenerateTS {
|
||||||
|
if seenEnumsPackages.Contains(packageName) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
thisPackageCode := ""
|
||||||
|
w := typescriptify.New()
|
||||||
|
w.WithPrefix(b.tsPrefix)
|
||||||
|
w.WithSuffix(b.tsSuffix)
|
||||||
|
w.WithInterface(b.tsInterface)
|
||||||
|
w.Namespace = packageName
|
||||||
|
w.WithBackupDir("")
|
||||||
|
|
||||||
|
for enumName, enum := range enumsToGenerate {
|
||||||
|
fqemumname := packageName + "." + enumName
|
||||||
|
if seen.Contains(fqemumname) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
w.AddEnum(enum)
|
||||||
|
}
|
||||||
|
str, err := w.Convert(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
thisPackageCode += str
|
||||||
|
models[packageName] = thisPackageCode
|
||||||
|
}
|
||||||
|
|
||||||
// Sort the package names first to make the output deterministic
|
// Sort the package names first to make the output deterministic
|
||||||
sortedPackageNames := make([]string, 0)
|
sortedPackageNames := make([]string, 0)
|
||||||
for packageName := range models {
|
for packageName := range models {
|
||||||
@ -163,6 +218,39 @@ func (b *Bindings) WriteModels(modelsDir string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Bindings) AddEnumToGenerateTS(e interface{}) {
|
||||||
|
enumType := reflect.TypeOf(e)
|
||||||
|
|
||||||
|
var packageName string
|
||||||
|
var enumName string
|
||||||
|
// enums should be represented as array of all possible values
|
||||||
|
if hasElements(enumType) {
|
||||||
|
enum := enumType.Elem()
|
||||||
|
// simple enum represented by struct with Value/TSName fields
|
||||||
|
if enum.Kind() == reflect.Struct {
|
||||||
|
_, tsNamePresented := enum.FieldByName("TSName")
|
||||||
|
enumT, valuePresented := enum.FieldByName("Value")
|
||||||
|
if tsNamePresented && valuePresented {
|
||||||
|
packageName = getPackageName(enumT.Type.String())
|
||||||
|
enumName = enumT.Type.Name()
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// otherwise expecting implementation with TSName() https://github.com/tkrajina/typescriptify-golang-structs#enums-with-tsname
|
||||||
|
} else {
|
||||||
|
packageName = getPackageName(enumType.Elem().String())
|
||||||
|
enumName = enumType.Elem().Name()
|
||||||
|
}
|
||||||
|
if b.enumsToGenerateTS[packageName] == nil {
|
||||||
|
b.enumsToGenerateTS[packageName] = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
if b.enumsToGenerateTS[packageName][enumName] != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.enumsToGenerateTS[packageName][enumName] = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Bindings) AddStructToGenerateTS(packageName string, structName string, s interface{}) {
|
func (b *Bindings) AddStructToGenerateTS(packageName string, structName string, s interface{}) {
|
||||||
if b.structsToGenerateTS[packageName] == nil {
|
if b.structsToGenerateTS[packageName] == nil {
|
||||||
b.structsToGenerateTS[packageName] = make(map[string]interface{})
|
b.structsToGenerateTS[packageName] = make(map[string]interface{})
|
||||||
@ -231,6 +319,13 @@ func (b *Bindings) SetTsSuffix(postfix string) *Bindings {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Bindings) SetOutputType(outputType string) *Bindings {
|
||||||
|
if outputType == "interfaces" {
|
||||||
|
b.tsInterface = true
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Bindings) getAllStructNames() *slicer.StringSlicer {
|
func (b *Bindings) getAllStructNames() *slicer.StringSlicer {
|
||||||
var result slicer.StringSlicer
|
var result slicer.StringSlicer
|
||||||
for packageName, structsToGenerate := range b.structsToGenerateTS {
|
for packageName, structsToGenerate := range b.structsToGenerateTS {
|
||||||
@ -241,6 +336,16 @@ func (b *Bindings) getAllStructNames() *slicer.StringSlicer {
|
|||||||
return &result
|
return &result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Bindings) getAllEnumNames() *slicer.StringSlicer {
|
||||||
|
var result slicer.StringSlicer
|
||||||
|
for packageName, enumsToGenerate := range b.enumsToGenerateTS {
|
||||||
|
for enumName := range enumsToGenerate {
|
||||||
|
result.Add(packageName + "." + enumName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Bindings) hasExportedJSONFields(typeOf reflect.Type) bool {
|
func (b *Bindings) hasExportedJSONFields(typeOf reflect.Type) bool {
|
||||||
for i := 0; i < typeOf.NumField(); i++ {
|
for i := 0; i < typeOf.NumField(); i++ {
|
||||||
jsonFieldName := ""
|
jsonFieldName := ""
|
||||||
|
@ -42,7 +42,7 @@ func TestConflictingPackageName(t *testing.T) {
|
|||||||
|
|
||||||
// setup
|
// setup
|
||||||
testLogger := &logger.Logger{}
|
testLogger := &logger.Logger{}
|
||||||
b := binding.NewBindings(testLogger, []interface{}{&HandlerTest{}}, []interface{}{}, false)
|
b := binding.NewBindings(testLogger, []interface{}{&HandlerTest{}}, []interface{}{}, false, []interface{}{})
|
||||||
|
|
||||||
// then
|
// then
|
||||||
err := b.GenerateGoBindings(generationDir)
|
err := b.GenerateGoBindings(generationDir)
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package binding_test
|
||||||
|
|
||||||
|
import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import"
|
||||||
|
|
||||||
|
type ImportedEnumStruct struct {
|
||||||
|
EnumValue binding_test_import.ImportedEnum `json:"EnumValue"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ImportedEnumStruct) Get() ImportedEnumStruct {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
var ImportedEnumTest = BindingTest{
|
||||||
|
name: "ImportedEnum",
|
||||||
|
structs: []interface{}{
|
||||||
|
&ImportedEnumStruct{},
|
||||||
|
},
|
||||||
|
enums: []interface{}{
|
||||||
|
binding_test_import.AllImportedEnumValues,
|
||||||
|
},
|
||||||
|
exemptions: nil,
|
||||||
|
shouldError: false,
|
||||||
|
want: `export namespace binding_test {
|
||||||
|
|
||||||
|
export class ImportedEnumStruct {
|
||||||
|
EnumValue: binding_test_import.ImportedEnum;
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new ImportedEnumStruct(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.EnumValue = source["EnumValue"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace binding_test_import {
|
||||||
|
|
||||||
|
export enum ImportedEnum {
|
||||||
|
Value1 = "value1",
|
||||||
|
Value2 = "value2",
|
||||||
|
Value3 = "value3",
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}
|
@ -59,7 +59,7 @@ func TestPromises(t *testing.T) {
|
|||||||
|
|
||||||
// setup
|
// setup
|
||||||
testLogger := &logger.Logger{}
|
testLogger := &logger.Logger{}
|
||||||
b := binding.NewBindings(testLogger, []interface{}{&PromisesTest{}}, []interface{}{}, false)
|
b := binding.NewBindings(testLogger, []interface{}{&PromisesTest{}}, []interface{}{}, false, []interface{}{})
|
||||||
|
|
||||||
// then
|
// then
|
||||||
err := b.GenerateGoBindings(generationDir)
|
err := b.GenerateGoBindings(generationDir)
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
type BindingTest struct {
|
type BindingTest struct {
|
||||||
name string
|
name string
|
||||||
structs []interface{}
|
structs []interface{}
|
||||||
|
enums []interface{}
|
||||||
exemptions []interface{}
|
exemptions []interface{}
|
||||||
want string
|
want string
|
||||||
shouldError bool
|
shouldError bool
|
||||||
@ -22,6 +23,7 @@ type BindingTest struct {
|
|||||||
type TsGenerationOptionsTest struct {
|
type TsGenerationOptionsTest struct {
|
||||||
TsPrefix string
|
TsPrefix string
|
||||||
TsSuffix string
|
TsSuffix string
|
||||||
|
TsOutputType string
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBindings_GenerateModels(t *testing.T) {
|
func TestBindings_GenerateModels(t *testing.T) {
|
||||||
@ -31,12 +33,17 @@ func TestBindings_GenerateModels(t *testing.T) {
|
|||||||
ImportedStructTest,
|
ImportedStructTest,
|
||||||
ImportedSliceTest,
|
ImportedSliceTest,
|
||||||
ImportedMapTest,
|
ImportedMapTest,
|
||||||
|
ImportedEnumTest,
|
||||||
NestedFieldTest,
|
NestedFieldTest,
|
||||||
NonStringMapKeyTest,
|
NonStringMapKeyTest,
|
||||||
SingleFieldTest,
|
SingleFieldTest,
|
||||||
MultistructTest,
|
MultistructTest,
|
||||||
EmptyStructTest,
|
EmptyStructTest,
|
||||||
GeneratedJsEntityTest,
|
GeneratedJsEntityTest,
|
||||||
|
GeneratedJsEntityWithIntEnumTest,
|
||||||
|
GeneratedJsEntityWithStringEnumTest,
|
||||||
|
GeneratedJsEntityWithEnumTsName,
|
||||||
|
GeneratedJsEntityWithNestedStructInterfacesTest,
|
||||||
AnonymousSubStructTest,
|
AnonymousSubStructTest,
|
||||||
AnonymousSubStructMultiLevelTest,
|
AnonymousSubStructMultiLevelTest,
|
||||||
GeneratedJsEntityWithNestedStructTest,
|
GeneratedJsEntityWithNestedStructTest,
|
||||||
@ -46,13 +53,14 @@ func TestBindings_GenerateModels(t *testing.T) {
|
|||||||
testLogger := &logger.Logger{}
|
testLogger := &logger.Logger{}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
b := binding.NewBindings(testLogger, tt.structs, tt.exemptions, false)
|
b := binding.NewBindings(testLogger, tt.structs, tt.exemptions, false, tt.enums)
|
||||||
for _, s := range tt.structs {
|
for _, s := range tt.structs {
|
||||||
err := b.Add(s)
|
err := b.Add(s)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
b.SetTsPrefix(tt.TsPrefix)
|
b.SetTsPrefix(tt.TsPrefix)
|
||||||
b.SetTsSuffix(tt.TsSuffix)
|
b.SetTsSuffix(tt.TsSuffix)
|
||||||
|
b.SetOutputType(tt.TsOutputType)
|
||||||
got, err := b.GenerateModels()
|
got, err := b.GenerateModels()
|
||||||
if (err != nil) != tt.shouldError {
|
if (err != nil) != tt.shouldError {
|
||||||
t.Errorf("GenerateModels() error = %v, shouldError %v", err, tt.shouldError)
|
t.Errorf("GenerateModels() error = %v, shouldError %v", err, tt.shouldError)
|
||||||
|
@ -13,3 +13,20 @@ type ASliceWrapper struct {
|
|||||||
type AMapWrapper struct {
|
type AMapWrapper struct {
|
||||||
AMap map[string]binding_test_nestedimport.A `json:"AMap"`
|
AMap map[string]binding_test_nestedimport.A `json:"AMap"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ImportedEnum string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ImportedEnumValue1 ImportedEnum = "value1"
|
||||||
|
ImportedEnumValue2 ImportedEnum = "value2"
|
||||||
|
ImportedEnumValue3 ImportedEnum = "value3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AllImportedEnumValues = []struct {
|
||||||
|
Value ImportedEnum
|
||||||
|
TSName string
|
||||||
|
}{
|
||||||
|
{ImportedEnumValue1, "Value1"},
|
||||||
|
{ImportedEnumValue2, "Value2"},
|
||||||
|
{ImportedEnumValue3, "Value3"},
|
||||||
|
}
|
||||||
|
@ -275,3 +275,235 @@ export namespace binding_test {
|
|||||||
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IntEnum int
|
||||||
|
|
||||||
|
const (
|
||||||
|
IntEnumValue1 IntEnum = iota
|
||||||
|
IntEnumValue2
|
||||||
|
IntEnumValue3
|
||||||
|
)
|
||||||
|
|
||||||
|
var AllIntEnumValues = []struct {
|
||||||
|
Value IntEnum
|
||||||
|
TSName string
|
||||||
|
}{
|
||||||
|
{IntEnumValue1, "Value1"},
|
||||||
|
{IntEnumValue2, "Value2"},
|
||||||
|
{IntEnumValue3, "Value3"},
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityWithIntEnum struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Enum IntEnum `json:"enum"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EntityWithIntEnum) Get() EntityWithIntEnum {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var GeneratedJsEntityWithIntEnumTest = BindingTest{
|
||||||
|
name: "GeneratedJsEntityWithIntEnumTest",
|
||||||
|
structs: []interface{}{
|
||||||
|
&EntityWithIntEnum{},
|
||||||
|
},
|
||||||
|
enums: []interface{}{
|
||||||
|
AllIntEnumValues,
|
||||||
|
},
|
||||||
|
exemptions: nil,
|
||||||
|
shouldError: false,
|
||||||
|
TsGenerationOptionsTest: TsGenerationOptionsTest{
|
||||||
|
TsPrefix: "MY_PREFIX_",
|
||||||
|
TsSuffix: "_MY_SUFFIX",
|
||||||
|
},
|
||||||
|
want: `export namespace binding_test {
|
||||||
|
|
||||||
|
export enum MY_PREFIX_IntEnum_MY_SUFFIX {
|
||||||
|
Value1 = 0,
|
||||||
|
Value2 = 1,
|
||||||
|
Value3 = 2,
|
||||||
|
}
|
||||||
|
export class MY_PREFIX_EntityWithIntEnum_MY_SUFFIX {
|
||||||
|
name: string;
|
||||||
|
enum: MY_PREFIX_IntEnum_MY_SUFFIX;
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new MY_PREFIX_EntityWithIntEnum_MY_SUFFIX(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.name = source["name"];
|
||||||
|
this.enum = source["enum"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
type StringEnum string
|
||||||
|
|
||||||
|
const (
|
||||||
|
StringEnumValue1 StringEnum = "value1"
|
||||||
|
StringEnumValue2 StringEnum = "value2"
|
||||||
|
StringEnumValue3 StringEnum = "value3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AllStringEnumValues = []struct {
|
||||||
|
Value StringEnum
|
||||||
|
TSName string
|
||||||
|
}{
|
||||||
|
{StringEnumValue1, "Value1"},
|
||||||
|
{StringEnumValue2, "Value2"},
|
||||||
|
{StringEnumValue3, "Value3"},
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityWithStringEnum struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Enum StringEnum `json:"enum"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EntityWithStringEnum) Get() EntityWithStringEnum {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var GeneratedJsEntityWithStringEnumTest = BindingTest{
|
||||||
|
name: "GeneratedJsEntityWithStringEnumTest",
|
||||||
|
structs: []interface{}{
|
||||||
|
&EntityWithStringEnum{},
|
||||||
|
},
|
||||||
|
enums: []interface{}{
|
||||||
|
AllStringEnumValues,
|
||||||
|
},
|
||||||
|
exemptions: nil,
|
||||||
|
shouldError: false,
|
||||||
|
TsGenerationOptionsTest: TsGenerationOptionsTest{
|
||||||
|
TsPrefix: "MY_PREFIX_",
|
||||||
|
TsSuffix: "_MY_SUFFIX",
|
||||||
|
},
|
||||||
|
want: `export namespace binding_test {
|
||||||
|
|
||||||
|
export enum MY_PREFIX_StringEnum_MY_SUFFIX {
|
||||||
|
Value1 = "value1",
|
||||||
|
Value2 = "value2",
|
||||||
|
Value3 = "value3",
|
||||||
|
}
|
||||||
|
export class MY_PREFIX_EntityWithStringEnum_MY_SUFFIX {
|
||||||
|
name: string;
|
||||||
|
enum: MY_PREFIX_StringEnum_MY_SUFFIX;
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new MY_PREFIX_EntityWithStringEnum_MY_SUFFIX(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.name = source["name"];
|
||||||
|
this.enum = source["enum"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
type EnumWithTsName string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EnumWithTsName1 EnumWithTsName = "value1"
|
||||||
|
EnumWithTsName2 EnumWithTsName = "value2"
|
||||||
|
EnumWithTsName3 EnumWithTsName = "value3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AllEnumWithTsNameValues = []EnumWithTsName{EnumWithTsName1, EnumWithTsName2, EnumWithTsName3}
|
||||||
|
|
||||||
|
func (v EnumWithTsName) TSName() string {
|
||||||
|
switch v {
|
||||||
|
case EnumWithTsName1:
|
||||||
|
return "TsName1"
|
||||||
|
case EnumWithTsName2:
|
||||||
|
return "TsName2"
|
||||||
|
case EnumWithTsName3:
|
||||||
|
return "TsName3"
|
||||||
|
default:
|
||||||
|
return "???"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityWithEnumTsName struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Enum EnumWithTsName `json:"enum"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EntityWithEnumTsName) Get() EntityWithEnumTsName {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var GeneratedJsEntityWithEnumTsName = BindingTest{
|
||||||
|
name: "GeneratedJsEntityWithEnumTsName",
|
||||||
|
structs: []interface{}{
|
||||||
|
&EntityWithEnumTsName{},
|
||||||
|
},
|
||||||
|
enums: []interface{}{
|
||||||
|
AllEnumWithTsNameValues,
|
||||||
|
},
|
||||||
|
exemptions: nil,
|
||||||
|
shouldError: false,
|
||||||
|
TsGenerationOptionsTest: TsGenerationOptionsTest{
|
||||||
|
TsPrefix: "MY_PREFIX_",
|
||||||
|
TsSuffix: "_MY_SUFFIX",
|
||||||
|
},
|
||||||
|
want: `export namespace binding_test {
|
||||||
|
|
||||||
|
export enum MY_PREFIX_EnumWithTsName_MY_SUFFIX {
|
||||||
|
TsName1 = "value1",
|
||||||
|
TsName2 = "value2",
|
||||||
|
TsName3 = "value3",
|
||||||
|
}
|
||||||
|
export class MY_PREFIX_EntityWithEnumTsName_MY_SUFFIX {
|
||||||
|
name: string;
|
||||||
|
enum: MY_PREFIX_EnumWithTsName_MY_SUFFIX;
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new MY_PREFIX_EntityWithEnumTsName_MY_SUFFIX(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.name = source["name"];
|
||||||
|
this.enum = source["enum"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
var GeneratedJsEntityWithNestedStructInterfacesTest = BindingTest{
|
||||||
|
name: "GeneratedJsEntityWithNestedStructInterfacesTest",
|
||||||
|
structs: []interface{}{
|
||||||
|
&ParentEntity{},
|
||||||
|
},
|
||||||
|
exemptions: nil,
|
||||||
|
shouldError: false,
|
||||||
|
TsGenerationOptionsTest: TsGenerationOptionsTest{
|
||||||
|
TsPrefix: "MY_PREFIX_",
|
||||||
|
TsSuffix: "_MY_SUFFIX",
|
||||||
|
TsOutputType: "interfaces",
|
||||||
|
},
|
||||||
|
want: `export namespace binding_test {
|
||||||
|
|
||||||
|
export interface MY_PREFIX_ChildEntity_MY_SUFFIX {
|
||||||
|
name: string;
|
||||||
|
childProp: number;
|
||||||
|
}
|
||||||
|
export interface MY_PREFIX_ParentEntity_MY_SUFFIX {
|
||||||
|
name: string;
|
||||||
|
ref: MY_PREFIX_ChildEntity_MY_SUFFIX;
|
||||||
|
parentProp: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
@ -41,7 +41,7 @@ func TestAliases(t *testing.T) {
|
|||||||
|
|
||||||
// setup
|
// setup
|
||||||
testLogger := &logger.Logger{}
|
testLogger := &logger.Logger{}
|
||||||
b := binding.NewBindings(testLogger, []interface{}{&AliasTest{}}, []interface{}{}, false)
|
b := binding.NewBindings(testLogger, []interface{}{&AliasTest{}}, []interface{}{}, false, []interface{}{})
|
||||||
|
|
||||||
// then
|
// then
|
||||||
err := b.GenerateGoBindings(generationDir)
|
err := b.GenerateGoBindings(generationDir)
|
||||||
|
@ -25,7 +25,7 @@ type B struct {
|
|||||||
|
|
||||||
func TestNestedStruct(t *testing.T) {
|
func TestNestedStruct(t *testing.T) {
|
||||||
bind := &BindForTest{}
|
bind := &BindForTest{}
|
||||||
testBindings := NewBindings(logger.New(nil), []interface{}{bind}, []interface{}{}, false)
|
testBindings := NewBindings(logger.New(nil), []interface{}{bind}, []interface{}{}, false, []interface{}{})
|
||||||
|
|
||||||
namesStrSlicer := testBindings.getAllStructNames()
|
namesStrSlicer := testBindings.getAllStructNames()
|
||||||
names := []string{}
|
names := []string{}
|
||||||
|
@ -244,6 +244,7 @@ type Bindings struct {
|
|||||||
type TsGeneration struct {
|
type TsGeneration struct {
|
||||||
Prefix string `json:"prefix"`
|
Prefix string `json:"prefix"`
|
||||||
Suffix string `json:"suffix"`
|
Suffix string `json:"suffix"`
|
||||||
|
OutputType string `json:"outputType"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the given JSON data into a Project struct
|
// Parse the given JSON data into a Project struct
|
||||||
|
@ -104,6 +104,7 @@ type TypeScriptify struct {
|
|||||||
|
|
||||||
Namespace string
|
Namespace string
|
||||||
KnownStructs *slicer.StringSlicer
|
KnownStructs *slicer.StringSlicer
|
||||||
|
KnownEnums *slicer.StringSlicer
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *TypeScriptify {
|
func New() *TypeScriptify {
|
||||||
@ -723,8 +724,17 @@ func (t *TypeScriptify) convertType(depth int, typeOf reflect.Type, customCode m
|
|||||||
}
|
}
|
||||||
} else { // Simple field:
|
} else { // Simple field:
|
||||||
t.logf(depth, "- simple field %s.%s", typeOf.Name(), field.Name)
|
t.logf(depth, "- simple field %s.%s", typeOf.Name(), field.Name)
|
||||||
|
// check if type is in known enum. If so, then replace TStype with enum name to avoid missing types
|
||||||
|
isKnownEnum := t.KnownEnums.Contains(getStructFQN(field.Type.String()))
|
||||||
|
if isKnownEnum {
|
||||||
|
err = builder.AddSimpleField(jsonFieldName, field, TypeOptions{
|
||||||
|
TSType: getStructFQN(field.Type.String()),
|
||||||
|
TSTransform: fldOpts.TSTransform,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
err = builder.AddSimpleField(jsonFieldName, field, fldOpts)
|
err = builder.AddSimpleField(jsonFieldName, field, fldOpts)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ type Options struct {
|
|||||||
GoModTidy bool
|
GoModTidy bool
|
||||||
TsPrefix string
|
TsPrefix string
|
||||||
TsSuffix string
|
TsSuffix string
|
||||||
|
TsOutputType string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateBindings generates bindings for the Wails project in the given ProjectDirectory.
|
// GenerateBindings generates bindings for the Wails project in the given ProjectDirectory.
|
||||||
@ -65,6 +66,7 @@ func GenerateBindings(options Options) (string, error) {
|
|||||||
env := os.Environ()
|
env := os.Environ()
|
||||||
env = shell.SetEnv(env, "tsprefix", options.TsPrefix)
|
env = shell.SetEnv(env, "tsprefix", options.TsPrefix)
|
||||||
env = shell.SetEnv(env, "tssuffix", options.TsSuffix)
|
env = shell.SetEnv(env, "tssuffix", options.TsSuffix)
|
||||||
|
env = shell.SetEnv(env, "tsoutputtype", options.TsOutputType)
|
||||||
|
|
||||||
stdout, stderr, err = shell.RunCommandWithEnv(env, workingDirectory, filename)
|
stdout, stderr, err = shell.RunCommandWithEnv(env, workingDirectory, filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -219,12 +219,17 @@ func GenerateBindings(buildOptions *Options) error {
|
|||||||
printBulletPoint("Generating bindings: ")
|
printBulletPoint("Generating bindings: ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if buildOptions.ProjectData.Bindings.TsGeneration.OutputType == "" {
|
||||||
|
buildOptions.ProjectData.Bindings.TsGeneration.OutputType = "classes"
|
||||||
|
}
|
||||||
|
|
||||||
// Generate Bindings
|
// Generate Bindings
|
||||||
output, err := bindings.GenerateBindings(bindings.Options{
|
output, err := bindings.GenerateBindings(bindings.Options{
|
||||||
Tags: buildOptions.UserTags,
|
Tags: buildOptions.UserTags,
|
||||||
GoModTidy: !buildOptions.SkipModTidy,
|
GoModTidy: !buildOptions.SkipModTidy,
|
||||||
TsPrefix: buildOptions.ProjectData.Bindings.TsGeneration.Prefix,
|
TsPrefix: buildOptions.ProjectData.Bindings.TsGeneration.Prefix,
|
||||||
TsSuffix: buildOptions.ProjectData.Bindings.TsGeneration.Suffix,
|
TsSuffix: buildOptions.ProjectData.Bindings.TsGeneration.Suffix,
|
||||||
|
TsOutputType: buildOptions.ProjectData.Bindings.TsGeneration.OutputType,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -63,6 +63,7 @@ type App struct {
|
|||||||
OnShutdown func(ctx context.Context) `json:"-"`
|
OnShutdown func(ctx context.Context) `json:"-"`
|
||||||
OnBeforeClose func(ctx context.Context) (prevent bool) `json:"-"`
|
OnBeforeClose func(ctx context.Context) (prevent bool) `json:"-"`
|
||||||
Bind []interface{}
|
Bind []interface{}
|
||||||
|
EnumBind []interface{}
|
||||||
WindowStartState WindowStartState
|
WindowStartState WindowStartState
|
||||||
|
|
||||||
// ErrorFormatter overrides the formatting of errors returned by backend methods
|
// ErrorFormatter overrides the formatting of errors returned by backend methods
|
||||||
|
@ -144,6 +144,65 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Also you might want to use Enums in your structs and have models for them on frontend.
|
||||||
|
In that case you should create array that will contain all possible enum values, instrument enum type and bind it to the app:
|
||||||
|
|
||||||
|
```go {16-18} title="app.go"
|
||||||
|
type Weekday string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Sunday Weekday = "Sunday"
|
||||||
|
Monday Weekday = "Monday"
|
||||||
|
Tuesday Weekday = "Tuesday"
|
||||||
|
Wednesday Weekday = "Wednesday"
|
||||||
|
Thursday Weekday = "Thursday"
|
||||||
|
Friday Weekday = "Friday"
|
||||||
|
Saturday Weekday = "Saturday"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AllWeekdays = []struct {
|
||||||
|
Value Weekday
|
||||||
|
TSName string
|
||||||
|
}{
|
||||||
|
{Sunday, "SUNDAY"},
|
||||||
|
{Monday, "MONDAY"},
|
||||||
|
{Tuesday, "TUESDAY"},
|
||||||
|
{Wednesday, "WEDNESDAY"},
|
||||||
|
{Thursday, "THURSDAY"},
|
||||||
|
{Friday, "FRIDAY"},
|
||||||
|
{Saturday, "SATURDAY"},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the main application configuration, the `EnumBind` key is where we can tell Wails what we want to bind enums as well:
|
||||||
|
|
||||||
|
```go {11-13} title="main.go"
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
app := NewApp()
|
||||||
|
|
||||||
|
err := wails.Run(&options.App{
|
||||||
|
Title: "My App",
|
||||||
|
Width: 800,
|
||||||
|
Height: 600,
|
||||||
|
OnStartup: app.startup,
|
||||||
|
OnShutdown: app.shutdown,
|
||||||
|
Bind: []interface{}{
|
||||||
|
app,
|
||||||
|
},
|
||||||
|
EnumBind: []interface{}{
|
||||||
|
AllWeekdays,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
This will add missing enums to your `model.ts` file.
|
||||||
|
|
||||||
More information on Binding can be found [here](../howdoesitwork.mdx#method-binding).
|
More information on Binding can be found [here](../howdoesitwork.mdx#method-binding).
|
||||||
|
|
||||||
## Application Menu
|
## Application Menu
|
||||||
|
@ -206,6 +206,57 @@ You may bind as many structs as you like. Just make sure you create an instance
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You may bind enums types as well.
|
||||||
|
In that case you should create array that will contain all possible enum values, instrument enum type and bind it to the app via `EnumBind`:
|
||||||
|
|
||||||
|
```go {16-18} title="app.go"
|
||||||
|
type Weekday string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Sunday Weekday = "Sunday"
|
||||||
|
Monday Weekday = "Monday"
|
||||||
|
Tuesday Weekday = "Tuesday"
|
||||||
|
Wednesday Weekday = "Wednesday"
|
||||||
|
Thursday Weekday = "Thursday"
|
||||||
|
Friday Weekday = "Friday"
|
||||||
|
Saturday Weekday = "Saturday"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AllWeekdays = []struct {
|
||||||
|
Value Weekday
|
||||||
|
TSName string
|
||||||
|
}{
|
||||||
|
{Sunday, "SUNDAY"},
|
||||||
|
{Monday, "MONDAY"},
|
||||||
|
{Tuesday, "TUESDAY"},
|
||||||
|
{Wednesday, "WEDNESDAY"},
|
||||||
|
{Thursday, "THURSDAY"},
|
||||||
|
{Friday, "FRIDAY"},
|
||||||
|
{Saturday, "SATURDAY"},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```go {10-12}
|
||||||
|
//...
|
||||||
|
err := wails.Run(&options.App{
|
||||||
|
Title: "Basic Demo",
|
||||||
|
Width: 1024,
|
||||||
|
Height: 768,
|
||||||
|
AssetServer: &assetserver.Options{
|
||||||
|
Assets: assets,
|
||||||
|
},
|
||||||
|
Bind: []interface{}{
|
||||||
|
app,
|
||||||
|
&mystruct1{},
|
||||||
|
&mystruct2{},
|
||||||
|
},
|
||||||
|
EnumBind: []interface{}{
|
||||||
|
AllWeekdays,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
When you run `wails dev` (or `wails generate module`), a frontend module will be generated containing the following:
|
When you run `wails dev` (or `wails generate module`), a frontend module will be generated containing the following:
|
||||||
|
|
||||||
- JavaScript bindings for all bound methods
|
- JavaScript bindings for all bound methods
|
||||||
|
@ -58,7 +58,14 @@ func main() {
|
|||||||
Bind: []interface{}{
|
Bind: []interface{}{
|
||||||
app,
|
app,
|
||||||
},
|
},
|
||||||
|
EnumBind: []interface{}{
|
||||||
|
AllWeekdays,
|
||||||
|
},
|
||||||
ErrorFormatter: func(err error) any { return err.Error() },
|
ErrorFormatter: func(err error) any { return err.Error() },
|
||||||
|
SingleInstanceLock: &options.SingleInstanceLock{
|
||||||
|
UniqueId: "c9c8fd93-6758-4144-87d1-34bdb0a8bd60",
|
||||||
|
OnSecondInstanceLaunch: app.onSecondInstanceLaunch,
|
||||||
|
},
|
||||||
Windows: &windows.Options{
|
Windows: &windows.Options{
|
||||||
WebviewIsTransparent: false,
|
WebviewIsTransparent: false,
|
||||||
WindowIsTranslucent: false,
|
WindowIsTranslucent: false,
|
||||||
@ -92,6 +99,8 @@ func main() {
|
|||||||
FullSizeContent: false,
|
FullSizeContent: false,
|
||||||
UseToolbar: false,
|
UseToolbar: false,
|
||||||
HideToolbarSeparator: true,
|
HideToolbarSeparator: true,
|
||||||
|
OnFileOpen: app.onFileOpen,
|
||||||
|
OnUrlOpen: app.onUrlOpen,
|
||||||
},
|
},
|
||||||
Appearance: mac.NSAppearanceNameDarkAqua,
|
Appearance: mac.NSAppearanceNameDarkAqua,
|
||||||
WebviewIsTransparent: true,
|
WebviewIsTransparent: true,
|
||||||
@ -479,6 +488,13 @@ A slice of struct instances defining methods that need to be bound to the fronte
|
|||||||
Name: Bind<br/>
|
Name: Bind<br/>
|
||||||
Type: `[]interface{}`
|
Type: `[]interface{}`
|
||||||
|
|
||||||
|
### EnumBind
|
||||||
|
|
||||||
|
A slice of Enum arrays that need to be bound to the frontend.
|
||||||
|
|
||||||
|
Name: EnumBind<br/>
|
||||||
|
Type: `[]interface{}`
|
||||||
|
|
||||||
### ErrorFormatter
|
### ErrorFormatter
|
||||||
|
|
||||||
A function that determines how errors are formatted when returned by a JS-to-Go
|
A function that determines how errors are formatted when returned by a JS-to-Go
|
||||||
@ -487,6 +503,28 @@ method call. The returned value will be marshalled as JSON.
|
|||||||
Name: ErrorFormatter<br/>
|
Name: ErrorFormatter<br/>
|
||||||
Type: `func (error) any`
|
Type: `func (error) any`
|
||||||
|
|
||||||
|
### SingleInstanceLock
|
||||||
|
|
||||||
|
Enables single instance locking. This means that only one instance of your application can be running at a time.
|
||||||
|
|
||||||
|
Name: SingleInstanceLock<br/>
|
||||||
|
Type: `*options.SingleInstanceLock`
|
||||||
|
|
||||||
|
#### UniqueId
|
||||||
|
|
||||||
|
This id is used to generate the mutex name on Windows and macOS and the dbus name on Linux. Use a UUID to ensure that the id is unique.
|
||||||
|
|
||||||
|
Name: UniqueId<br/>
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
#### OnSecondInstanceLaunch
|
||||||
|
|
||||||
|
Callback that is called when a second instance of your app is launched.
|
||||||
|
|
||||||
|
Name: OnSecondInstanceLaunch<br/>
|
||||||
|
Type: `func(secondInstanceData SecondInstanceData)`
|
||||||
|
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
This defines [Windows specific options](#windows).
|
This defines [Windows specific options](#windows).
|
||||||
@ -797,6 +835,20 @@ with [WebviewIsTransparent](#WebviewIsTransparent) to make frosty-looking applic
|
|||||||
Name: WindowIsTranslucent<br/>
|
Name: WindowIsTranslucent<br/>
|
||||||
Type: `bool`
|
Type: `bool`
|
||||||
|
|
||||||
|
#### OnFileOpen
|
||||||
|
|
||||||
|
Callback that is called when a file is opened with the application.
|
||||||
|
|
||||||
|
Name: OnFileOpen<br/>
|
||||||
|
Type: `func(filePath string)`
|
||||||
|
|
||||||
|
#### OnUrlOpen
|
||||||
|
|
||||||
|
Callback that is called when a URL is opened with the application.
|
||||||
|
|
||||||
|
Name: OnUrlOpen<br/>
|
||||||
|
Type: `func(filePath string)`
|
||||||
|
|
||||||
#### Preferences
|
#### Preferences
|
||||||
|
|
||||||
The Preferences struct provides the ability to configure the Webview preferences.
|
The Preferences struct provides the ability to configure the Webview preferences.
|
||||||
|
@ -73,14 +73,52 @@ The project config resides in the `wails.json` file in the project directory. Th
|
|||||||
// The copyright of the product. Default: 'Copyright.........'
|
// The copyright of the product. Default: 'Copyright.........'
|
||||||
"copyright": "",
|
"copyright": "",
|
||||||
// A short comment of the app. Default: 'Built using Wails (https://wails.app)'
|
// A short comment of the app. Default: 'Built using Wails (https://wails.app)'
|
||||||
"comments": ""
|
"comments": "",
|
||||||
|
// File associations for the app
|
||||||
|
"fileAssociations": [
|
||||||
|
{
|
||||||
|
// The extension (minus the leading period). e.g. png
|
||||||
|
"ext": "wails",
|
||||||
|
// The name. e.g. PNG File
|
||||||
|
"name": "Wails",
|
||||||
|
// Windows-only. The description. It is displayed on the `Type` column on Windows Explorer.
|
||||||
|
"description": "Wails file",
|
||||||
|
// The icon name without extension. Icons should be located in build folder. Proper icons will be generated from .png file for both macOS and Windows)
|
||||||
|
"iconName": "fileIcon",
|
||||||
|
// macOS-only. The app’s role with respect to the type. Corresponds to CFBundleTypeRole.
|
||||||
|
"role": "Editor"
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// Custom URI protocols that should be opened by the application
|
||||||
|
"protocols": [
|
||||||
|
{
|
||||||
|
// protocol scheme. e.g. myapp
|
||||||
|
"scheme": "myapp",
|
||||||
|
// Windows-only. The description. It is displayed on the `Type` column on Windows Explorer.
|
||||||
|
"description": "Myapp protocol",
|
||||||
|
// macOS-only. The app’s role with respect to the type. Corresponds to CFBundleTypeRole.
|
||||||
|
"role": "Editor"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
// 'multiple': One installer per architecture. 'single': Single universal installer for all architectures being built. Default: 'multiple'
|
// 'multiple': One installer per architecture. 'single': Single universal installer for all architectures being built. Default: 'multiple'
|
||||||
"nsisType": "",
|
"nsisType": "",
|
||||||
// Whether the app should be obfuscated. Default: false
|
// Whether the app should be obfuscated. Default: false
|
||||||
"obfuscated": "",
|
"obfuscated": "",
|
||||||
// The arguments to pass to the garble command when using the obfuscated flag
|
// The arguments to pass to the garble command when using the obfuscated flag
|
||||||
"garbleargs": ""
|
"garbleargs": "",
|
||||||
|
// Bindings configurations
|
||||||
|
"bindings": {
|
||||||
|
// model.ts file generation config
|
||||||
|
"ts_generation": {
|
||||||
|
// All generated JavaScript entities will be prefixed with this value
|
||||||
|
"prefix": "",
|
||||||
|
// All generated JavaScript entities will be suffixed with this value
|
||||||
|
"suffix": "",
|
||||||
|
// Type of output to generate (classes|interfaces)
|
||||||
|
"outputType": "classes",
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Added CPU/GPU/Memory detection for `wails doctor`. Added by @leaanthony in #d51268b8d0680430f3a614775b13e6cd2b906d1c
|
- Added CPU/GPU/Memory detection for `wails doctor`. Added by @leaanthony in #d51268b8d0680430f3a614775b13e6cd2b906d1c
|
||||||
- The [AssetServer](/docs/reference/options#assetserver) now injects the runtime/IPC into all index html files and into all html files returned when requesting a folder path. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2203)
|
- The [AssetServer](/docs/reference/options#assetserver) now injects the runtime/IPC into all index html files and into all html files returned when requesting a folder path. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2203)
|
||||||
- Added Custom Protocol Schemes associations support for macOS and Windows. Added by @APshenkin in [PR](https://github.com/wailsapp/wails/pull/3000)
|
- Added Custom Protocol Schemes associations support for macOS and Windows. Added by @APshenkin in [PR](https://github.com/wailsapp/wails/pull/3000)
|
||||||
|
– Added support for TS interfaces generation as an option. Add support for Enums in TS types. Added by @APshenkin in [PR](https://github.com/wailsapp/wails/pull/3047)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -251,6 +251,33 @@
|
|||||||
"garbleargs": {
|
"garbleargs": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The arguments to pass to the garble command when using the obfuscated flag"
|
"description": "The arguments to pass to the garble command when using the obfuscated flag"
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Bindings configurations",
|
||||||
|
"properties": {
|
||||||
|
"ts_generation": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "model.ts file generation config",
|
||||||
|
"properties": {
|
||||||
|
"prefix": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "All generated JavaScript entities will be prefixed with this value"
|
||||||
|
},
|
||||||
|
"suffix": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "All generated JavaScript entities will be suffixed with this value"
|
||||||
|
},
|
||||||
|
"outputType": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/BindingsOutputTypes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -346,26 +373,25 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"bindings": {
|
"BindingsOutputTypes": {
|
||||||
"type": "object",
|
"description": "Type of output to generate",
|
||||||
"description": "Bindings configurations",
|
"oneOf": [
|
||||||
"properties": {
|
{
|
||||||
"ts_generation": {
|
"description": "Classes",
|
||||||
"type": "object",
|
|
||||||
"description": "model.ts file generation config",
|
|
||||||
"properties": {
|
|
||||||
"prefix": {
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "All generated JavaScript entities will be prefixed with this value"
|
"enum": [
|
||||||
|
"classes"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"suffix": {
|
{
|
||||||
|
"description": "Interfaces",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "All generated JavaScript entities will be suffixed with this value"
|
"enum": [
|
||||||
}
|
"interfaces"
|
||||||
}
|
]
|
||||||
}
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user