github.com/avenga/couper@v1.12.2/errors/generate/types.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "path/filepath" 8 "regexp" 9 10 "github.com/avenga/couper/errors" 11 ) 12 13 var couperErrors []string 14 15 func main() { 16 println("generating error types:\n") 17 18 // hold list of possible base kinds which can be skipped for type definitions 19 b, err := os.ReadFile(filepath.Join("errors", "couper.go")) 20 must(err) 21 result := regexp.MustCompile(`\t(\w+)\s+= &Error.+\n`).FindAllStringSubmatch(string(b), -1) 22 for _, r := range result { 23 couperErrors = append(couperErrors, r[1]) 24 } 25 26 errTypes := map[string]int{} 27 sortedErrTypes := make([]string, len(errors.Definitions)) 28 for idx, errImpl := range errors.Definitions { 29 kinds := errImpl.Kinds() 30 if len(kinds) == 0 { 31 must(fmt.Errorf("error kind must be defined")) 32 } 33 34 kind := kinds[0] 35 if _, exist := errTypes[kind]; exist { 36 must(fmt.Errorf("error kind already defined: %s", kind)) 37 } 38 errTypes[kind] = idx 39 sortedErrTypes[idx] = kind 40 } 41 42 for _, kind := range sortedErrTypes { 43 println("\t", kind, "-->", errors.SnakeToCamel(kind)) 44 } 45 46 generated, err := os.Create(filepath.Join("errors", "types_generated.go")) 47 must(err) 48 defer generated.Close() 49 50 _, err = io.WriteString(generated, `// Code generated by go generate; DO NOT EDIT. 51 52 package errors 53 54 var ( 55 `) 56 must(err) 57 58 for idx, kind := range sortedErrTypes { 59 if isDefined(kind) { 60 continue 61 } 62 _, err = io.WriteString(generated, fmt.Sprintf("\t%s = Definitions[%d]\n", errors.SnakeToCamel(kind), idx)) 63 must(err) 64 } 65 66 _, err = io.WriteString(generated, `) 67 68 // typeDefinitions holds all related error definitions which are 69 // catchable with an error_handler definition. 70 type typeDefinitions map[string]*Error 71 72 // types holds all implemented ones. The name must match the structs 73 // snake-name for fallback purposes. See TypeToSnake usage and reference. 74 var types = typeDefinitions{ 75 `) 76 77 must(err) 78 79 for _, kind := range sortedErrTypes { 80 _, err = io.WriteString(generated, fmt.Sprintf("\t%q: %s,\n", kind, errors.SnakeToCamel(kind))) 81 must(err) 82 } 83 84 _, err = io.WriteString(generated, `} 85 86 // IsKnown tells the configuration callee if Couper 87 // has a defined error type with the given name. 88 func IsKnown(errorType string) bool { 89 _, known := types[errorType] 90 return known 91 } 92 93 `) 94 must(err) 95 96 var superKindsMapsByContext = make(map[string]map[string][]string) 97 98 for _, def := range errors.Definitions { 99 if def.IsParent() || def.Contexts == nil || len(def.Contexts) == 0 { 100 continue 101 } 102 // use only leaf types with context(s) 103 for _, context := range def.Contexts { 104 superKindsMaps, exists := superKindsMapsByContext[context] 105 if !exists { 106 superKindsMaps = make(map[string][]string) 107 superKindsMapsByContext[context] = superKindsMaps 108 } 109 kinds := append(def.Kinds(), "*") 110 kind := kinds[0] 111 kinds = kinds[1:] 112 for _, k := range kinds { 113 superKindsMaps[k] = append(superKindsMaps[k], kind) 114 } 115 } 116 } 117 118 _, err = io.WriteString(generated, ` 119 // SuperTypesMapsByContext holds maps for error super-types to sub-types 120 // by a given context block type (e.g. api or endpoint). 121 var SuperTypesMapsByContext = `) 122 must(err) 123 _, err = io.WriteString(generated, fmt.Sprintf("%#v\n", superKindsMapsByContext)) 124 must(err) 125 } 126 127 // isDefined checks if the given typeName is defined and must be skipped for declaration with true result. 128 func isDefined(typeName string) bool { 129 for _, t := range couperErrors { 130 if errors.SnakeToCamel(typeName) == t { 131 return true 132 } 133 } 134 return false 135 } 136 137 func must(err error) { 138 if err != nil { 139 println(err.Error()) 140 os.Exit(1) 141 } 142 }