// Reading a tool's arguments: JSON numbers arrive as float64, and a missing argument is its default. // The same in every desktop module that carries it. package main import ( "fmt" "math" "strings" "time" ) // text is a string argument, trimmed; required says an empty one is refused. func text(args map[string]any, key string, required bool) (string, error) { v, present := args[key] if !present || v == nil { if required { return "", fmt.Errorf("%s is required", key) } return "", nil } s, ok := v.(string) if !ok { return "", fmt.Errorf("%s is a string, not %T", key, v) } s = strings.TrimSpace(s) if s == "" && required { return "", fmt.Errorf("%s is required", key) } return s, nil } // whole is a whole-number argument within [least, most], or def when absent. func whole(args map[string]any, key string, def, least, most int) (int, error) { v, present := args[key] if !present || v == nil { return def, nil } f, ok := v.(float64) if !ok { if i, isInt := v.(int); isInt { f = float64(i) } else { return 0, fmt.Errorf("%s is a number, not %T", key, v) } } if f != math.Trunc(f) { return 0, fmt.Errorf("%s is a whole number, not %v", key, f) } n := int(f) if n < least || n > most { return 0, fmt.Errorf("%s is %d; it is between %d and %d", key, n, least, most) } return n, nil } // flag is a boolean argument, or def when absent. func flag(args map[string]any, key string, def bool) (bool, error) { v, present := args[key] if !present || v == nil { return def, nil } b, ok := v.(bool) if !ok { return false, fmt.Errorf("%s is true or false, not %T", key, v) } return b, nil } // texts is a list-of-strings argument. func texts(args map[string]any, key string) ([]string, error) { v, present := args[key] if !present || v == nil { return nil, nil } list, ok := v.([]any) if !ok { if ss, isStrings := v.([]string); isStrings { return ss, nil } return nil, fmt.Errorf("%s is a list of strings, not %T", key, v) } out := make([]string, 0, len(list)) for i, item := range list { s, ok := item.(string) if !ok { return nil, fmt.Errorf("%s[%d] is a string, not %T", key, i, item) } out = append(out, s) } return out, nil } // seconds is a timeout argument in seconds, defaulted and bounded below the runtime's call limit. func seconds(args map[string]any, key string, def, most int) (time.Duration, error) { n, err := whole(args, key, def, 1, most) return time.Duration(n) * time.Second, err }