fix(generator): error-only methods in response handling

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan 2025-12-23 17:41:29 -05:00
parent 097774f9c2
commit a0a5168f5f
4 changed files with 45 additions and 12 deletions

View File

@ -22,6 +22,7 @@ func GenerateService(svc Service, pkgName string) ([]byte, error) {
"needsJSON": NeedsJSON, "needsJSON": NeedsJSON,
"needsRequestType": func(m Method) bool { return m.NeedsRequestType() }, "needsRequestType": func(m Method) bool { return m.NeedsRequestType() },
"needsRespType": func(m Method) bool { return m.NeedsResponseType() }, "needsRespType": func(m Method) bool { return m.NeedsResponseType() },
"isErrorOnly": func(m Method) bool { return m.IsErrorOnly() },
"hasErrFromRead": hasErrorFromRead, "hasErrFromRead": hasErrorFromRead,
"readParam": generateReadParam, "readParam": generateReadParam,
"writeReturn": generateWriteReturn, "writeReturn": generateWriteReturn,
@ -292,14 +293,24 @@ func new{{$.Service.Name}}{{.Name}}HostFunction(service {{$.Service.Interface}})
{{- end}} {{- end}}
{{- if .HasError}} {{- if .HasError}}
if err != nil { if err != nil {
{{- if needsRespType .}} {{- if isErrorOnly .}}
// Write error string to plugin memory
if ptr, err := p.WriteString(err.Error()); err == nil {
stack[0] = ptr
}
{{- else if needsRespType .}}
{{$.Service.Name | lower}}WriteError(p, stack, err) {{$.Service.Name | lower}}WriteError(p, stack, err)
{{- end}} {{- end}}
return return
} }
{{- end}} {{- end}}
{{- if needsRespType .}} {{- if isErrorOnly .}}
// Write empty string to indicate success
if ptr, err := p.WriteString(""); err == nil {
stack[0] = ptr
}
{{- else if needsRespType .}}
// Write JSON response to plugin memory // Write JSON response to plugin memory
resp := {{responseType .}}{ resp := {{responseType .}}{
{{- range .Returns}} {{- range .Returns}}
@ -319,7 +330,7 @@ func new{{$.Service.Name}}{{.Name}}HostFunction(service {{$.Service.Interface}})
{{- else}} {{- else}}
[]extism.ValueType{ {{- range $i, $p := .Params}}{{if $i}}, {{end}}{{valueType $p.Type}}{{end}}{{if not .HasParams}}{{end}} }, []extism.ValueType{ {{- range $i, $p := .Params}}{{if $i}}, {{end}}{{valueType $p.Type}}{{end}}{{if not .HasParams}}{{end}} },
{{- end}} {{- end}}
{{- if needsRespType .}} {{- if or (needsRespType .) (isErrorOnly .)}}
[]extism.ValueType{extism.ValueTypePTR}, []extism.ValueType{extism.ValueTypePTR},
{{- else}} {{- else}}
[]extism.ValueType{ {{- range $i, $r := .Returns}}{{if $i}}, {{end}}{{valueType $r.Type}}{{end}}{{if not .HasReturns}}{{end}} }, []extism.ValueType{ {{- range $i, $r := .Returns}}{{if $i}}, {{end}}{{valueType $r.Type}}{{end}}{{if not .HasReturns}}{{end}} },

View File

@ -176,14 +176,15 @@ func (m Method) NeedsRequestType() bool {
} }
// NeedsResponseType returns true if a response struct is needed. // NeedsResponseType returns true if a response struct is needed.
// Needed when we have complex returns that require JSON, or error handling. // Needed when we have complex returns that require JSON (but not for error-only methods).
func (m Method) NeedsResponseType() bool { func (m Method) NeedsResponseType() bool {
// If there's an error, we need a response type to serialize it // Error-only methods return a simple string, not JSON
if m.HasError { if m.IsErrorOnly() {
// But only if there are also returns, or if returns need JSON return false
if m.HasReturns() { }
return true // If there's an error with other returns, we need a response type
} if m.HasError && m.HasReturns() {
return true
} }
for _, r := range m.Returns { for _, r := range m.Returns {
if NeedsJSON(r.Type) { if NeedsJSON(r.Type) {
@ -193,6 +194,11 @@ func (m Method) NeedsResponseType() bool {
return false return false
} }
// IsErrorOnly returns true if the method only returns an error (no other return values).
func (m Method) IsErrorOnly() bool {
return m.HasError && !m.HasReturns()
}
// toJSONName converts a Go identifier to camelCase JSON field name. // toJSONName converts a Go identifier to camelCase JSON field name.
func toJSONName(name string) string { func toJSONName(name string) string {
if name == "" { if name == "" {

View File

@ -75,11 +75,19 @@ func newMetaSetHostFunction(service MetaService) extism.HostFunction {
// Call the service method // Call the service method
err = service.Set(ctx, req.Data) err = service.Set(ctx, req.Data)
if err != nil { if err != nil {
// Write error string to plugin memory
if ptr, err := p.WriteString(err.Error()); err == nil {
stack[0] = ptr
}
return return
} }
// Write empty string to indicate success
if ptr, err := p.WriteString(""); err == nil {
stack[0] = ptr
}
}, },
[]extism.ValueType{extism.ValueTypePTR}, []extism.ValueType{extism.ValueTypePTR},
[]extism.ValueType{}, []extism.ValueType{extism.ValueTypePTR},
) )
} }

View File

@ -24,10 +24,18 @@ func newPingPingHostFunction(service PingService) extism.HostFunction {
// Call the service method // Call the service method
err := service.Ping(ctx) err := service.Ping(ctx)
if err != nil { if err != nil {
// Write error string to plugin memory
if ptr, err := p.WriteString(err.Error()); err == nil {
stack[0] = ptr
}
return return
} }
// Write empty string to indicate success
if ptr, err := p.WriteString(""); err == nil {
stack[0] = ptr
}
}, },
[]extism.ValueType{}, []extism.ValueType{},
[]extism.ValueType{}, []extism.ValueType{extism.ValueTypePTR},
) )
} }