github.com/42z-io/confik@v0.0.2-0.20231103050132-21d8f377356c/tag.go (about) 1 package confik 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 type tag struct { 9 Name string 10 Flags []string 11 Settings map[string]string 12 } 13 14 // ConfigTag represents the name, flags and settings on the struct field. 15 type ConfigTag struct { 16 Name string // name of the environment variable 17 Validator *string // field validator name 18 Optional bool // is the environment variable optional? 19 Default *string // default value to use if the environment variable does not exist 20 Unset bool // clear the environment variable after load? 21 } 22 23 // NewConfigTag will create a new [ConfigTag] with the default values. 24 func NewConfigTag(name string) ConfigTag { 25 return ConfigTag{ 26 Name: name, 27 Validator: nil, 28 Optional: false, 29 Default: nil, 30 Unset: false, 31 } 32 } 33 34 func parseSetting(expressionStr string) (string, string, error) { 35 parts := strings.Split(expressionStr, "=") 36 if len(parts) != 2 { 37 return "", "", fmt.Errorf("invalid setting %s: invalid syntax", expressionStr) 38 } 39 return parts[0], parts[1], nil 40 } 41 42 func parseTag(tagStr string) (*tag, error) { 43 if len(tagStr) == 0 { 44 return nil, fmt.Errorf("invalid tag: empty tag") 45 } 46 parts := strings.Split(tagStr, ",") 47 var tag tag 48 tag.Name = parts[0] 49 tag.Settings = make(map[string]string) 50 tag.Flags = make([]string, 0) 51 for _, expressionStr := range parts[1:] { 52 if strings.Contains(expressionStr, "=") { 53 settingName, settingValue, err := parseSetting(expressionStr) 54 if err != nil { 55 return nil, fmt.Errorf("invalid tag: %w", err) 56 } 57 tag.Settings[settingName] = settingValue 58 } else { 59 tag.Flags = append(tag.Flags, expressionStr) 60 } 61 } 62 return &tag, nil 63 64 } 65 66 func parseEnvTag(tagStr string) (*ConfigTag, error) { 67 tag, err := parseTag(tagStr) 68 if err != nil { 69 return nil, fmt.Errorf("invalid env tag: %w", err) 70 } 71 72 if err := verifyEnvName(tag.Name); err != nil { 73 return nil, fmt.Errorf("invalid env tag: %w", err) 74 } 75 76 configTag := NewConfigTag(tag.Name) 77 for _, flagName := range tag.Flags { 78 switch flagName { 79 case "optional": 80 configTag.Optional = true 81 case "unset": 82 configTag.Unset = true 83 default: 84 return nil, fmt.Errorf("invalid env tag: unknown flag %s", flagName) 85 } 86 } 87 88 for settingName, settingValue := range tag.Settings { 89 // TODO remove in Go 1.22 90 settingValue := settingValue 91 switch settingName { 92 case "validate": 93 configTag.Validator = &settingValue 94 case "default": 95 configTag.Default = &settingValue 96 default: 97 return nil, fmt.Errorf("invalid env tag: unknown setting %s", settingName) 98 } 99 } 100 101 return &configTag, nil 102 }