github.com/kumasuke120/mockuma@v1.1.9/internal/mckmaps/vars.go (about) 1 package mckmaps 2 3 import ( 4 "encoding/csv" 5 "errors" 6 "io" 7 "os" 8 "regexp" 9 "strings" 10 11 "github.com/kumasuke120/mockuma/internal/myjson" 12 ) 13 14 var varNameRegexp = regexp.MustCompile("(?i)[a-z][a-z\\d]*") 15 16 type vars struct { 17 table map[string]interface{} 18 } 19 20 type varsJSONParser struct { 21 json myjson.Object 22 jsonPath *myjson.Path 23 Parser 24 } 25 26 func (p *varsJSONParser) parse() ([]*vars, error) { 27 if p.json == nil { 28 json, err := p.load(true, ppRemoveComment) 29 if err != nil { 30 return nil, err 31 } 32 33 p.jsonPath = myjson.NewPath() 34 switch json.(type) { 35 case myjson.Object: 36 p.json = json.(myjson.Object) 37 default: 38 return nil, p.newJSONParseError(p.jsonPath) 39 } 40 } 41 42 p.jsonPath = myjson.NewPath("") 43 p.jsonPath.SetLast(aType) 44 _type, err := p.json.GetString(aType) 45 if err != nil || string(_type) != tVars { 46 return nil, p.newJSONParseError(p.jsonPath) 47 } 48 49 p.jsonPath.SetLast(tVars) 50 p.jsonPath.Append(0) 51 varsSlice, err := p.parseVars(p.json) 52 if err != nil { 53 return nil, err 54 } 55 p.jsonPath.RemoveLast() 56 57 return varsSlice, nil 58 } 59 60 func (p *varsJSONParser) parseVars(v myjson.Object) ([]*vars, error) { 61 rawVarsArray := ensureJSONArray(v.Get(tVars)) 62 varsSlice := make([]*vars, len(rawVarsArray)) 63 for idx, rawVars := range rawVarsArray { 64 if p.json != nil { 65 p.jsonPath.SetLast(idx) 66 } 67 rVars, err := myjson.ToObject(rawVars) 68 if err != nil { 69 return nil, p.newJSONParseError(p.jsonPath) 70 } 71 varsSlice[idx], err = parseVars(rVars) 72 if err != nil { 73 return nil, p.newJSONParseError(p.jsonPath) 74 } 75 } 76 return varsSlice, nil 77 } 78 79 func parseVars(v myjson.Object) (*vars, error) { 80 vars := new(vars) 81 table := make(map[string]interface{}) 82 for name, value := range v { 83 if !varNameRegexp.MatchString(name) { 84 return nil, errors.New("invalid name for var") 85 } 86 table[name] = value 87 } 88 vars.table = table 89 return vars, nil 90 } 91 92 type varsCSVParser struct { 93 rdr *csv.Reader 94 Parser 95 } 96 97 func (p *varsCSVParser) parse() ([]*vars, error) { 98 if p.rdr == nil { 99 file, err := os.Open(p.filename) 100 if err != nil { 101 return nil, &loadError{filename: p.filename, err: err} 102 } 103 defer func() { 104 _ = file.Close() 105 }() 106 p.rdr = csv.NewReader(file) 107 } 108 109 var result []*vars 110 var varNames []string 111 for { 112 line, err := p.rdr.Read() 113 if err == io.EOF { 114 break 115 } else if err != nil { 116 return nil, &loadError{filename: p.filename, err: err} 117 } 118 119 if varNames == nil { 120 varNames = line 121 if len(varNames) != 0 { 122 varNames[0] = cleanBom(varNames[0]) 123 } 124 continue 125 } 126 127 table := make(map[string]interface{}, len(varNames)) 128 for i, c := range line { 129 if i < len(varNames) { 130 var col interface{} 131 if "undefined" != c { // pre-defined keyword which denotes non-existent value 132 json, err := myjson.Unmarshal([]byte(c)) 133 if err != nil { 134 col = myjson.String(c) // treats the non-valid json as a pure string 135 } else { 136 col = json 137 } 138 table[varNames[i]] = col 139 } 140 } 141 } 142 143 result = append(result, &vars{table: table}) 144 } 145 return result, nil 146 } 147 148 const bom = "\xef\xbb\xbf" 149 150 func cleanBom(s string) string { 151 if strings.HasPrefix(s, bom) { 152 return s[3:] 153 } 154 return s 155 }