105 lines
1.6 KiB
Go
105 lines
1.6 KiB
Go
|
package list
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// KeyValue represents a key-value attribute.
|
||
|
type KeyValue struct {
|
||
|
Key string
|
||
|
Value string
|
||
|
}
|
||
|
|
||
|
// ParseKeyValue creates a new key-value attribute from a string.
|
||
|
func ParseKeyValue(s string) *KeyValue {
|
||
|
f := KeyValue{}
|
||
|
|
||
|
return f.Parse(s)
|
||
|
}
|
||
|
|
||
|
// Key returns the sanitized attribute key.
|
||
|
func Key(s string) string {
|
||
|
var i = 0
|
||
|
|
||
|
// Remove non-alphanumeric characters.
|
||
|
result := strings.Map(func(r rune) rune {
|
||
|
switch r {
|
||
|
case '.', '@', '-', '+', '_', '#':
|
||
|
return r
|
||
|
}
|
||
|
if r >= '0' && r <= '9' {
|
||
|
return r
|
||
|
} else if (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') || r == 127 {
|
||
|
return -1
|
||
|
}
|
||
|
i++
|
||
|
return r
|
||
|
}, s)
|
||
|
|
||
|
if i == 0 {
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// Value returns the sanitized attribute value.
|
||
|
func Value(s string) string {
|
||
|
// Remove control characters.
|
||
|
return strings.Map(func(r rune) rune {
|
||
|
if r <= 32 || r == 127 {
|
||
|
return -1
|
||
|
}
|
||
|
switch r {
|
||
|
case '(', ')', '<', '>', '\'', '"':
|
||
|
return r
|
||
|
}
|
||
|
return r
|
||
|
}, s)
|
||
|
}
|
||
|
|
||
|
// Parse parses a string attribute into key and value.
|
||
|
func (f *KeyValue) Parse(s string) *KeyValue {
|
||
|
k, v, _ := strings.Cut(s, ":")
|
||
|
|
||
|
// Set key.
|
||
|
if k = Key(k); k == "" {
|
||
|
return nil
|
||
|
} else {
|
||
|
f.Key = k
|
||
|
}
|
||
|
|
||
|
// Default?
|
||
|
if v = Value(v); v == "" {
|
||
|
f.Value = True
|
||
|
return f
|
||
|
}
|
||
|
|
||
|
// Set value.
|
||
|
if b := Bool[strings.ToLower(v)]; b != "" {
|
||
|
f.Value = b
|
||
|
} else {
|
||
|
f.Value = v
|
||
|
}
|
||
|
|
||
|
return f
|
||
|
}
|
||
|
|
||
|
// String return the attribute as string.
|
||
|
func (f *KeyValue) String() string {
|
||
|
if f == nil {
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
if Bool[strings.ToLower(f.Value)] == True {
|
||
|
return f.Key
|
||
|
}
|
||
|
|
||
|
if s := fmt.Sprintf("%s:%s", f.Key, f.Value); len(s) < StringLengthLimit {
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
return ""
|
||
|
}
|