Update binding generator to new internal API

This commit is contained in:
Fabio Massaioli 2025-02-25 03:32:51 +01:00
commit 14fb7ed4f7
7 changed files with 75 additions and 60 deletions

View file

@ -213,17 +213,22 @@ func (m *module) PostponedCreates() []string {
m.postponedCreates.Iterate(func(key types.Type, value any) {
pp := value.(*postponed)
pre := ""
pre, post := "", ""
if pp.params != "" {
pre = pp.params + " => "
if m.TS {
pre = createParamRegex.ReplaceAllString(pp.params, "${0}: any") + " => "
} else {
pre = "/** @type {(...args: any[]) => any} */(" + pp.params + " => "
post = ")"
}
}
switch t := key.(type) {
case *types.Array, *types.Slice:
result[pp.index] = fmt.Sprintf("%s$Create.Array(%s)", pre, m.JSCreateWithParams(t.(interface{ Elem() types.Type }).Elem(), pp.params))
result[pp.index] = fmt.Sprintf("%s$Create.Array(%s)%s", pre, m.JSCreateWithParams(t.(interface{ Elem() types.Type }).Elem(), pp.params), post)
case *types.Map:
result[pp.index] = fmt.Sprintf("%s$Create.Map($Create.Any, %s)", pre, m.JSCreateWithParams(t.Elem(), pp.params))
result[pp.index] = fmt.Sprintf("%s$Create.Map($Create.Any, %s)%s", pre, m.JSCreateWithParams(t.Elem(), pp.params), post)
case *types.Named:
if !collect.IsClass(key) {
@ -231,23 +236,24 @@ func (m *module) PostponedCreates() []string {
// require an indirect assignment to break cycles.
// Typescript cannot infer the return type on its own: add hints.
cast, returnType := "", ""
cast, argType, returnType := "", "", ""
if m.TS {
argType = ": any[]"
returnType = ": any"
} else {
cast = "/** @type {(...args: any[]) => any} */"
}
result[pp.index] = fmt.Sprintf(`
%s(function $$initCreateType%d(...args)%s {
%s(function $$initCreateType%d(...args%s)%s {
if ($$createType%d === $$initCreateType%d) {
$$createType%d = %s%s;
$$createType%d = %s%s%s;
}
return $$createType%d(...args);
})`,
cast, pp.index, returnType,
cast, pp.index, argType, returnType,
pp.index, pp.index,
pp.index, pre, m.JSCreateWithParams(t.Underlying(), pp.params),
pp.index, pre, m.JSCreateWithParams(t.Underlying(), pp.params), post,
pp.index,
)[1:] // Remove initial newline.
@ -280,11 +286,12 @@ func (m *module) PostponedCreates() []string {
}
builder.WriteString(")")
}
builder.WriteString(post)
result[pp.index] = builder.String()
case *types.Pointer:
result[pp.index] = fmt.Sprintf("%s$Create.Nullable(%s)", pre, m.JSCreateWithParams(t.Elem(), pp.params))
result[pp.index] = fmt.Sprintf("%s$Create.Nullable(%s)%s", pre, m.JSCreateWithParams(t.Elem(), pp.params), post)
case *types.Struct:
info := m.collector.Struct(t)
@ -311,11 +318,12 @@ func (m *module) PostponedCreates() []string {
builder.WriteRune('\n')
}
builder.WriteString("})")
builder.WriteString(post)
result[pp.index] = builder.String()
default:
result[pp.index] = pre + "$Create.Any"
result[pp.index] = pre + "$Create.Any" + post
}
})

View file

@ -1,6 +1,7 @@
package render
import (
"regexp"
"strings"
"github.com/wailsapp/wails/v3/internal/generator/collect"
@ -26,6 +27,9 @@ type modelInfo struct {
}
}
// createParamRegex must match type parameter creation strings as generated by [modelinfo].
var createParamRegex = regexp.MustCompile(`\$\$createParam[^\s,)]*`)
// modelinfo gathers and returns useful information about the given model.
func modelinfo(model *collect.ModelInfo, useInterfaces bool) (info modelInfo) {
info.HasValues = len(model.Values) > 0

View file

@ -9,7 +9,7 @@
{{if not $useInterfaces}}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import {Create as $Create} from "{{js $runtime}}";
import { Create as $Create } from "{{js $runtime}}";
{{end -}}
{{range $imports.External}}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View file

@ -8,7 +8,7 @@
{{if not $useInterfaces}}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import {Create as $Create} from "{{js $runtime}}";
import { Create as $Create } from "{{js $runtime}}";
{{end -}}
{{range $imports.External}}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View file

@ -22,7 +22,7 @@
{{end}}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import {Call as $Call{{if not $useInterfaces}}, Create as $Create{{end -}} } from "{{js $runtime}}";
import { Call as $Call, CancellablePromise as $CancellablePromise{{if not $useInterfaces}}, Create as $Create{{end}} } from "{{js $runtime}}";
{{range $imports.External}}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
@ -46,7 +46,7 @@ import * as $models from "./{{js $models}}";
{{- range $i, $param := .Params}}
* @param { {{- $module.JSType .Type}}{{if .Variadic}}[]{{end -}} } {{jsparam $i .}}
{{- end}}
* @returns {Promise<
* @returns {$CancellablePromise<
{{- if eq 0 (len .Results) -}}
void
{{- else if eq 1 (len .Results)}}
@ -56,7 +56,7 @@ import * as $models from "./{{js $models}}";
{{- if gt $i 0}}, {{end}}
{{- $module.JSType $result}}
{{- end}}]
{{- end}}> & { cancel(): void }}
{{- end}}>}
*/
{{if not .Internal}}export {{end}}function {{.Name}}({{range $i, $param := .Params -}}
{{- if gt $i 0}}, {{end}}
@ -64,14 +64,14 @@ import * as $models from "./{{js $models}}";
{{- jsparam $i .}}
{{- end}}) {
{{- if $useNames}}
let $resultPromise = /** @type {any} */($Call.ByName("{{js .FQN}}"
return $Call.ByName("{{js .FQN}}"
{{- else}}
let $resultPromise = /** @type {any} */($Call.ByID({{.ID}}
{{- end}}{{range $i, $param := .Params}}, {{jsparam $i .}}{{end}}));
{{- if or $useInterfaces (not .Results) ($module.SkipCreate .Results)}}
return $resultPromise;
{{- else}}
let $typingPromise = /** @type {any} */($resultPromise.then(($result) => {
return $Call.ByID({{.ID}}
{{- end}}{{range $i, $param := .Params}}, {{jsparam $i .}}{{end}})
{{- if or $useInterfaces (not .Results) ($module.SkipCreate .Results) -}}
;
{{- else -}}
.then(/** @type {($result: any) => any} */(($result) => {
{{- if eq 1 (len .Results)}}
return {{$module.JSCreate (index .Results 0)}}($result);
{{- else}}
@ -83,8 +83,6 @@ import * as $models from "./{{js $models}}";
return $result;
{{- end}}
}));
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
return $typingPromise;
{{- end}}
}
{{end}}

View file

@ -21,7 +21,7 @@
{{end}}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import {Call as $Call{{if not $useInterfaces}}, Create as $Create{{end -}} } from "{{js $runtime}}";
import { Call as $Call, CancellablePromise as $CancellablePromise{{if not $useInterfaces}}, Create as $Create{{end}} } from "{{js $runtime}}";
{{range $imports.External}}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
@ -49,7 +49,7 @@ import * as $models from "./{{js $models}}";
{{- if gt $i 0}}, {{end}}
{{- if .Variadic}}...{{end}}
{{- jsparam $i .}}: {{$module.JSType .Type}}{{if .Variadic}}[]{{end}}
{{- end}}): Promise<
{{- end}}): $CancellablePromise<
{{- if eq 0 (len .Results) -}}
void
{{- else if eq 1 (len .Results)}}
@ -59,16 +59,16 @@ import * as $models from "./{{js $models}}";
{{- if gt $i 0}}, {{end}}
{{- $module.JSType $result}}
{{- end}}]
{{- end}}> & { cancel(): void } {
{{- end}}> {
{{- if $useNames}}
let $resultPromise = $Call.ByName("{{js .FQN}}"
return $Call.ByName("{{js .FQN}}"
{{- else}}
let $resultPromise = $Call.ByID({{.ID}}
{{- end}}{{range $i, $param := .Params}}, {{jsparam $i .}}{{end}}) as any;
{{- if or $useInterfaces (not .Results) ($module.SkipCreate .Results)}}
return $resultPromise;
{{- else}}
let $typingPromise = $resultPromise.then(($result: any) => {
return $Call.ByID({{.ID}}
{{- end}}{{range $i, $param := .Params}}, {{jsparam $i .}}{{end}})
{{- if or $useInterfaces (not .Results) ($module.SkipCreate .Results) -}}
;
{{- else -}}
.then(($result: any) => {
{{- if eq 1 (len .Results)}}
return {{$module.JSCreate (index .Results 0)}}($result);
{{- else}}
@ -79,9 +79,7 @@ import * as $models from "./{{js $models}}";
{{- end}}{{end}}
return $result;
{{- end}}
}) as any;
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
return $typingPromise;
});
{{- end}}
}
{{end}}

View file

@ -1,28 +1,35 @@
{
"compilerOptions": {
"allowJs": true,
"noEmit": true,
"skipLibCheck": true,
"include": ["output/**/*.js", "output/**/*.ts"],
"exclude": ["output/**/*.got.?s"],
"references": [
{ "path": "../../runtime/desktop/@wailsio/runtime" }
],
"compilerOptions": {
"allowJs": true,
"target": "ES6",
"lib": ["ES6", "DOM"],
"noEmit": true,
"skipLibCheck": true,
"module": "ES6",
"moduleResolution": "Node",
"isolatedModules": true,
"esModuleInterop": true,
"target": "ES2015",
"module": "ES2015",
"moduleResolution": "bundler",
"isolatedModules": true,
"verbatimModuleSyntax": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": false,
"noImplicitAny": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"lib": [
"DOM",
"ESNext"
],
"paths": {
"/wails/runtime.js": ["../../runtime/desktop/@wailsio/runtime/types/index.d.ts"]
}
},
"include": ["output/**/*"],
"exclude": ["output/**/*.got.?s"]
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": false,
"noImplicitAny": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"paths": {
"/wails/runtime.js": ["../../runtime/desktop/@wailsio/runtime/src/index.ts"]
}
}
}