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  }