config/dict.go   A
last analyzed

Size/Duplication

Total Lines 144
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 38
eloc 81
dl 0
loc 144
rs 9.36
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A config.DictSchema.Parse 0 12 2
A config.oneOf 0 8 5
A config.notFound 0 2 1
C config.DictConfig.Find 0 27 11
A config.tagEquals 0 2 2
B config.known 0 14 7
A config.DictConfig.MergeDefault 0 11 4
A config.DictConfig.Schema 0 2 1
A config.found 0 2 1
A config.DictConfig.IsList 0 2 1
A config.truncatePrefix 0 9 2
A config.DictConfig.IsBoolean 0 2 1
1
package config
2
3
import (
4
	"github.com/vvval/go-metadata-scanner/configuration"
5
	"github.com/vvval/go-metadata-scanner/util"
6
	"github.com/vvval/go-metadata-scanner/vars"
7
	"gopkg.in/yaml.v2"
8
	"regexp"
9
	"strings"
10
)
11
12
type DictSchema struct {
13
	Known    map[string][]string `yaml:"known"`
14
	Groups   map[string]string   `yaml:"groups"`
15
	Booleans []string            `yaml:"booleans"`
16
	Lists    []string            `yaml:"lists"`
17
}
18
19
func (c DictConfig) Schema() configuration.Schema {
20
	return DictSchema{}
21
}
22
23
func (s DictSchema) Parse(data []byte) (configuration.Config, error) {
24
	err := yaml.Unmarshal(data, &s)
25
	if err != nil {
26
		return DictConfig{}, err
27
	}
28
29
	return DictConfig{
30
		known:    s.Known,
31
		groups:   s.Groups,
32
		booleans: s.Booleans,
33
		lists:    s.Lists,
34
	}, nil
35
}
36
37
func (c DictConfig) MergeDefault(conf configuration.Config) configuration.Config {
38
	for k, v := range conf.(DictConfig).known {
39
		if _, ok := c.known[k]; !ok {
40
			c.known[k] = v
41
		}
42
	}
43
44
	c.booleans = util.UniqueValues(append(c.booleans, conf.(DictConfig).booleans...))
45
	c.lists = util.UniqueValues(append(c.lists, conf.(DictConfig).lists...))
46
47
	return c
48
}
49
50
type DictConfig struct {
51
	known    map[string][]string
52
	groups   map[string]string
53
	booleans []string
54
	lists    []string
55
}
56
57
func (c DictConfig) Find(name string) (vars.Tag, bool) {
58
	if tag, found := known(name, c.known); found {
59
		return tag, found
60
	}
61
62
	for _, b := range c.booleans {
63
		if strings.EqualFold(b, name) {
64
			return found("", name, []string{name})
65
		}
66
	}
67
68
	for _, l := range c.lists {
69
		if strings.EqualFold(l, name) {
70
			return found("", name, []string{name})
71
		}
72
	}
73
74
	var reg = &regexp.Regexp{}
75
	for key, expr := range c.groups {
76
		reg = regexp.MustCompile("(?i)^" + expr + "$")
77
78
		if reg.MatchString(name) {
79
			return known(key, c.known)
80
		}
81
	}
82
83
	return notFound(name)
84
}
85
86
func (c DictConfig) IsBoolean(key, tag string) bool {
87
	return oneOf(key, tag, c.booleans)
88
}
89
90
func (c DictConfig) IsList(key, tag string) bool {
91
	return oneOf(key, tag, c.lists)
92
}
93
94
func known(name string, lists map[string][]string) (vars.Tag, bool) {
95
	for key, list := range lists {
96
		if strings.EqualFold(key, name) {
97
			return found(key, name, list)
98
		}
99
100
		for _, val := range list {
101
			if tagEquals(val, name) {
102
				return found(key, name, list)
103
			}
104
		}
105
	}
106
107
	return notFound(name)
108
}
109
110
func found(key, name string, list []string) (vars.Tag, bool) {
111
	return vars.NewFoundTag(key, name, list), true
112
}
113
114
func notFound(name string) (vars.Tag, bool) {
115
	return vars.NewNotFoundTag(name), false
116
}
117
118
func oneOf(key, tag string, set []string) bool {
119
	for _, val := range set {
120
		if strings.EqualFold(tag, val) || strings.EqualFold(key, val) {
121
			return true
122
		}
123
	}
124
125
	return false
126
}
127
128
// Name or truncated name (without "<GROUP>:" prefix) equals
129
// Tag argument is a tag name from the dict
130
// Name argument is a searchable input+
131
func tagEquals(tag, name string) bool {
132
	return strings.EqualFold(tag, name) || strings.EqualFold(tag, truncatePrefix(name))
133
}
134
135
// Cut "<group>:" prefix if found
136
func truncatePrefix(tag string) string {
137
	prefixEnding := strings.Index(tag, ":")
138
	if prefixEnding == -1 {
139
		return tag
140
	}
141
142
	runes := []rune(tag)
143
144
	return string(runes[prefixEnding+1:])
145
}
146