-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathformat.go
218 lines (197 loc) · 5.67 KB
/
format.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
package cogs
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/pelletier/go-toml"
"gopkg.in/yaml.v3"
)
// ReadType represents the logic used to derive the deserliazied value for a given Link
type ReadType string
const (
// read format overrides
rDotenv ReadType = "dotenv"
rJSON ReadType = "json"
rYAML ReadType = "yaml"
rTOML ReadType = "toml"
// complex values of a given markup type are appended with "{}"
rJSONComplex ReadType = "json{}" // complex JSON key value pair: {"k":{"v1":[],"v2":[]}}
rYAMLComplex ReadType = "yaml{}" // complex YAML key value pair: {k: {v1: [], v2: []}}
rTOMLComplex ReadType = "toml{}" // complex TOML key value pair: k = {v1 = [], v2 = []}
// read format derived from filepath suffix
deferred ReadType = "" // defer file config type to filename suffix
rWhole ReadType = "whole" // indicates to associate the entirety of a file to the given key name
rGear ReadType = "gear" // treat TOML table as a nested gear object
)
// Validate ensures that a string is a valid readType enum
func (t ReadType) Validate() error {
switch t {
case rDotenv, rJSON, rYAML, rTOML,
rJSONComplex, rYAMLComplex, rTOMLComplex, rWhole,
deferred:
return nil
default: // deferred readType should not be validated
return fmt.Errorf("%s is an invalid linkType", t.String())
}
}
// isComplex returns true if the readType is complex
func (t ReadType) isComplex() bool {
switch t {
case rJSONComplex, rYAMLComplex, rTOMLComplex, rWhole:
return true
}
return false
}
type unmarshalFn func([]byte, interface{}) error
// getUnmarshal returns the corresponding function to unmarshal a given read type
func (t ReadType) getUnmarshal() (unmarshalFn, error) {
switch t {
case rJSON, rJSONComplex:
return json.Unmarshal, nil
case rTOML, rTOMLComplex:
return toml.Unmarshal, nil
case rYAML, rYAMLComplex:
return yaml.Unmarshal, nil
}
return nil, fmt.Errorf("unsupported type for GetUnmarshal: %s", t)
}
func (t ReadType) String() string {
switch t {
case rDotenv:
return string(rDotenv)
case rJSON:
return "flat json"
case rYAML:
return "flat yaml"
case rTOML:
return "flat toml"
case rJSONComplex:
return "complex json"
case rYAMLComplex:
return "complex yaml"
case rTOMLComplex:
return "complex toml"
case rWhole:
return "whole file"
case rGear:
return "gear object"
case deferred:
return "deferred"
default:
return "unknown"
}
}
// Format represents the final marshalled k/v output type from a resolved Gear
// TODO reconcile readType and Format patterns
type Format string
// Formats for respective object notation
const (
JSON Format = "json"
YAML Format = "yaml"
TOML Format = "toml"
Dotenv Format = "dotenv"
Raw Format = "raw"
)
// Validate ensures that a string maps to a valid Format
func (t Format) Validate() error {
switch t {
case JSON, YAML, TOML, Dotenv, Raw:
return nil
default: // deferred readType should not be validated
return fmt.Errorf("%s is an invalid Format", string(t))
}
}
// FormatForPath returns the correct format given the path to a file
func FormatForPath(path string) Format {
format := Raw
switch {
case IsYAMLFile(path):
format = YAML
case IsTOMLFile(path):
format = TOML
case IsJSONFile(path):
format = JSON
case IsEnvFile(path):
format = Dotenv
}
return format
}
// FormatLinkInput returns the correct format given the readType
func FormatLinkInput(link *Link) (format Format) {
switch link.readType {
case rJSON, rJSONComplex:
format = JSON
case rDotenv:
format = Dotenv
// grab Format from filepath suffix if there are no explicit type overrides
default:
format = FormatForPath(link.Path)
}
return format
}
// IsYAMLFile returns true if a given file path corresponds to a YAML file
func IsYAMLFile(path string) bool {
return strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")
}
// IsTOMLFile returns true if a given file path corresponds to a TOML file
func IsTOMLFile(path string) bool {
return strings.HasSuffix(path, ".toml") || strings.HasSuffix(path, ".tml")
}
// IsJSONFile returns true if a given file path corresponds to a JSON file
func IsJSONFile(path string) bool {
return strings.HasSuffix(path, ".json")
}
// IsEnvFile returns true if a given file path corresponds to a .env file
func IsEnvFile(path string) bool {
return strings.HasSuffix(path, ".env")
}
// IsSimpleValue is intended to see if the underlying value allows a flat map to be retained
func IsSimpleValue(i interface{}) bool {
switch i.(type) {
case string,
float32, float64,
uint, uint8, uint16, uint32, uint64,
int, int8, int16, int32, int64,
bool:
return true
}
return false
}
// TODO ErrNotASimpleValue = errorW{fmt:"%s of type %T is not a simple value"}
// SimpleValueToString converts an underlying type to a string, returning an error if it is not a simple value
func SimpleValueToString(i interface{}) (str string, err error) {
switch t := i.(type) {
case string:
str = t
case int:
str = strconv.Itoa(t)
case int8:
str = strconv.FormatInt(int64(t), 10)
case int16:
str = strconv.FormatInt(int64(t), 10)
case int32:
str = strconv.FormatInt(int64(t), 10)
case int64:
str = strconv.FormatInt(int64(t), 10)
case uint:
str = strconv.FormatUint(uint64(t), 10)
case uint8:
str = strconv.FormatUint(uint64(t), 10)
case uint16:
str = strconv.FormatUint(uint64(t), 10)
case uint32:
str = strconv.FormatUint(uint64(t), 10)
case uint64:
str = strconv.FormatUint(uint64(t), 10)
case bool:
str = strconv.FormatBool(t)
case float32:
str = strconv.FormatFloat(float64(t), 'E', -1, 64)
case float64:
str = strconv.FormatFloat(t, 'E', -1, 32)
default:
err = fmt.Errorf("%s of type %T is not a simple value", t, t)
}
return str, err
}