remove panic call from one ExecuteScriptOption

Changed the shape of the ExecuteScriptOption option to return an error,
which allows validation of the Option parameters. This allowed removing
a panic call from one of the options.

Panic calls are common in the standard library. However, Datastar calls
return errors. Mixing panics and error returns in the same construct is
slight code smell. More importantly, the mixing produces a less
intuitive and predictable API.
This commit is contained in:
Dmitry Kotik 2025-04-14 20:14:58 +03:00
parent 3e30d61417
commit 6e9e9e027c
1 changed files with 25 additions and 17 deletions

View File

@ -1,6 +1,7 @@
package datastar
import (
"errors"
"fmt"
"strconv"
"strings"
@ -16,7 +17,7 @@ type executeScriptOptions struct {
}
// ExecuteScriptOption configures script execution event that will be sent to the client.
type ExecuteScriptOption func(*executeScriptOptions)
type ExecuteScriptOption func(*executeScriptOptions) error
// WithExecuteScriptEventID configures an optional event ID for the script execution event.
// The client message field [lastEventId] will be set to this value.
@ -24,16 +25,18 @@ type ExecuteScriptOption func(*executeScriptOptions)
//
// [lastEventId]: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/lastEventId
func WithExecuteScriptEventID(id string) ExecuteScriptOption {
return func(o *executeScriptOptions) {
return func(o *executeScriptOptions) error {
o.EventID = id
return nil
}
}
// WithExecuteScriptRetryDuration overrides the [DefaultSseRetryDuration] for this script
// execution only.
func WithExecuteScriptRetryDuration(retryDuration time.Duration) ExecuteScriptOption {
return func(o *executeScriptOptions) {
return func(o *executeScriptOptions) error {
o.RetryDuration = retryDuration
return nil
}
}
@ -42,40 +45,46 @@ func WithExecuteScriptRetryDuration(retryDuration time.Duration) ExecuteScriptOp
// Each attribute should include a pair of plain words representing the attribute name and value
// without any formatting.
func WithExecuteScriptAttributes(attributes ...string) ExecuteScriptOption {
return func(o *executeScriptOptions) {
return func(o *executeScriptOptions) error {
o.Attributes = attributes
return nil
}
}
// WithExecuteScriptAttributeKVs is an alternative option for [WithExecuteScriptAttributes].
// Even parameters are keys, odd parameters are their values.
func WithExecuteScriptAttributeKVs(kvs ...string) ExecuteScriptOption {
return func(o *executeScriptOptions) error {
if len(kvs)%2 != 0 {
panic("WithExecuteScriptAttributeKVs requires an even number of arguments")
return errors.New("WithExecuteScriptAttributeKVs option requires an even number of arguments")
}
attributes := make([]string, 0, len(kvs)/2)
for i := 0; i < len(kvs); i += 2 {
attribute := fmt.Sprintf("%s %s", kvs[i], kvs[i+1])
attributes = append(attributes, attribute)
}
return WithExecuteScriptAttributes(attributes...)
return WithExecuteScriptAttributes(attributes...)(o)
}
}
// WithExecuteScriptAutoRemove requires the client to eliminate the script element after its execution.
func WithExecuteScriptAutoRemove(autoremove bool) ExecuteScriptOption {
return func(o *executeScriptOptions) {
return func(o *executeScriptOptions) error {
o.AutoRemove = &autoremove
return nil
}
}
// ExecuteScript runs a script in the client browser. Seperate commands with semicolons.
func (sse *ServerSentEventGenerator) ExecuteScript(scriptContents string, opts ...ExecuteScriptOption) error {
func (sse *ServerSentEventGenerator) ExecuteScript(scriptContents string, opts ...ExecuteScriptOption) (err error) {
options := &executeScriptOptions{
RetryDuration: DefaultSseRetryDuration,
Attributes: []string{"type module"},
}
for _, opt := range opts {
opt(options)
if err = opt(options); err != nil {
return err
}
}
sendOpts := make([]SSEEventOption, 0, 2)
@ -99,8 +108,7 @@ func (sse *ServerSentEventGenerator) ExecuteScript(scriptContents string, opts .
}
}
scriptLines := strings.Split(scriptContents, NewLine)
for _, line := range scriptLines {
for line := range strings.SplitSeq(scriptContents, NewLine) {
dataLines = append(dataLines, ScriptDatalineLiteral+line)
}