2020-05-27 18:28:00 +00:00
|
|
|
package random
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/mitchellh/mapstructure"
|
|
|
|
)
|
|
|
|
|
|
|
|
// serializableRules is a slice of rules that can be marshalled to JSON in an HCL format
|
|
|
|
type serializableRules []Rule
|
|
|
|
|
|
|
|
// MarshalJSON in an HCL-friendly way
|
|
|
|
func (r serializableRules) MarshalJSON() (b []byte, err error) {
|
|
|
|
// Example:
|
|
|
|
// [
|
|
|
|
// {
|
|
|
|
// "testrule": [
|
|
|
|
// {
|
|
|
|
// "string": "teststring",
|
|
|
|
// "int": 123
|
|
|
|
// }
|
|
|
|
// ]
|
|
|
|
// },
|
|
|
|
// {
|
|
|
|
// "charset": [
|
|
|
|
// {
|
|
|
|
// "charset": "abcde",
|
|
|
|
// "min-chars": 2
|
|
|
|
// }
|
|
|
|
// ]
|
|
|
|
// }
|
|
|
|
// ]
|
|
|
|
data := []map[string][]map[string]interface{}{} // Totally not confusing at all
|
|
|
|
for _, rule := range r {
|
|
|
|
ruleData := map[string]interface{}{}
|
|
|
|
err = mapstructure.Decode(rule, &ruleData)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to decode rule: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ruleMap := map[string][]map[string]interface{}{
|
2021-04-08 16:43:39 +00:00
|
|
|
rule.Type(): {
|
2020-05-27 18:28:00 +00:00
|
|
|
ruleData,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
data = append(data, ruleMap)
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err = json.Marshal(data)
|
|
|
|
return b, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *serializableRules) UnmarshalJSON(data []byte) (err error) {
|
|
|
|
mapData := []map[string]interface{}{}
|
|
|
|
err = json.Unmarshal(data, &mapData)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
rules, err := parseRules(defaultRegistry, mapData)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
*r = rules
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type runes []rune
|
|
|
|
|
|
|
|
func (r runes) Len() int { return len(r) }
|
|
|
|
func (r runes) Less(i, j int) bool { return r[i] < r[j] }
|
|
|
|
func (r runes) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
|
|
|
|
|
|
|
// MarshalJSON converts the runes to a string for smaller JSON and easier readability
|
|
|
|
func (r runes) MarshalJSON() (b []byte, err error) {
|
|
|
|
return json.Marshal(string(r))
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON converts a string to []rune
|
|
|
|
func (r *runes) UnmarshalJSON(data []byte) (err error) {
|
|
|
|
var str string
|
|
|
|
err = json.Unmarshal(data, &str)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
*r = []rune(str)
|
|
|
|
return nil
|
|
|
|
}
|