github.com/josephspurrier/go-swagger@v0.2.1-0.20221129144919-1f672a142a00/scan/validators.go (about)

     1  //go:build !go1.11
     2  // +build !go1.11
     3  
     4  // Copyright 2015 go-swagger maintainers
     5  //
     6  // Licensed under the Apache License, Version 2.0 (the "License");
     7  // you may not use this file except in compliance with the License.
     8  // You may obtain a copy of the License at
     9  //
    10  //    http://www.apache.org/licenses/LICENSE-2.0
    11  //
    12  // Unless required by applicable law or agreed to in writing, software
    13  // distributed under the License is distributed on an "AS IS" BASIS,
    14  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  package scan
    19  
    20  import (
    21  	"encoding/json"
    22  	"fmt"
    23  	"regexp"
    24  	"strconv"
    25  	"strings"
    26  
    27  	"github.com/go-openapi/spec"
    28  )
    29  
    30  type validationBuilder interface {
    31  	SetMaximum(float64, bool)
    32  	SetMinimum(float64, bool)
    33  	SetMultipleOf(float64)
    34  
    35  	SetMinItems(int64)
    36  	SetMaxItems(int64)
    37  
    38  	SetMinLength(int64)
    39  	SetMaxLength(int64)
    40  	SetPattern(string)
    41  
    42  	SetUnique(bool)
    43  	SetEnum(string)
    44  	SetDefault(interface{})
    45  	SetExample(interface{})
    46  }
    47  
    48  type valueParser interface {
    49  	Parse([]string) error
    50  	Matches(string) bool
    51  }
    52  
    53  type setMaximum struct {
    54  	builder validationBuilder
    55  	rx      *regexp.Regexp
    56  }
    57  
    58  func (sm *setMaximum) Parse(lines []string) error {
    59  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
    60  		return nil
    61  	}
    62  	matches := sm.rx.FindStringSubmatch(lines[0])
    63  	if len(matches) > 2 && len(matches[2]) > 0 {
    64  		max, err := strconv.ParseFloat(matches[2], 64)
    65  		if err != nil {
    66  			return err
    67  		}
    68  		sm.builder.SetMaximum(max, matches[1] == "<")
    69  	}
    70  	return nil
    71  }
    72  
    73  func (sm *setMaximum) Matches(line string) bool {
    74  	return sm.rx.MatchString(line)
    75  }
    76  
    77  type setMinimum struct {
    78  	builder validationBuilder
    79  	rx      *regexp.Regexp
    80  }
    81  
    82  func (sm *setMinimum) Matches(line string) bool {
    83  	return sm.rx.MatchString(line)
    84  }
    85  
    86  func (sm *setMinimum) Parse(lines []string) error {
    87  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
    88  		return nil
    89  	}
    90  	matches := sm.rx.FindStringSubmatch(lines[0])
    91  	if len(matches) > 2 && len(matches[2]) > 0 {
    92  		min, err := strconv.ParseFloat(matches[2], 64)
    93  		if err != nil {
    94  			return err
    95  		}
    96  		sm.builder.SetMinimum(min, matches[1] == ">")
    97  	}
    98  	return nil
    99  }
   100  
   101  type setMultipleOf struct {
   102  	builder validationBuilder
   103  	rx      *regexp.Regexp
   104  }
   105  
   106  func (sm *setMultipleOf) Matches(line string) bool {
   107  	return sm.rx.MatchString(line)
   108  }
   109  
   110  func (sm *setMultipleOf) Parse(lines []string) error {
   111  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   112  		return nil
   113  	}
   114  	matches := sm.rx.FindStringSubmatch(lines[0])
   115  	if len(matches) > 2 && len(matches[1]) > 0 {
   116  		multipleOf, err := strconv.ParseFloat(matches[1], 64)
   117  		if err != nil {
   118  			return err
   119  		}
   120  		sm.builder.SetMultipleOf(multipleOf)
   121  	}
   122  	return nil
   123  }
   124  
   125  type setMaxItems struct {
   126  	builder validationBuilder
   127  	rx      *regexp.Regexp
   128  }
   129  
   130  func (sm *setMaxItems) Matches(line string) bool {
   131  	return sm.rx.MatchString(line)
   132  }
   133  
   134  func (sm *setMaxItems) Parse(lines []string) error {
   135  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   136  		return nil
   137  	}
   138  	matches := sm.rx.FindStringSubmatch(lines[0])
   139  	if len(matches) > 1 && len(matches[1]) > 0 {
   140  		maxItems, err := strconv.ParseInt(matches[1], 10, 64)
   141  		if err != nil {
   142  			return err
   143  		}
   144  		sm.builder.SetMaxItems(maxItems)
   145  	}
   146  	return nil
   147  }
   148  
   149  type setMinItems struct {
   150  	builder validationBuilder
   151  	rx      *regexp.Regexp
   152  }
   153  
   154  func (sm *setMinItems) Matches(line string) bool {
   155  	return sm.rx.MatchString(line)
   156  }
   157  
   158  func (sm *setMinItems) Parse(lines []string) error {
   159  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   160  		return nil
   161  	}
   162  	matches := sm.rx.FindStringSubmatch(lines[0])
   163  	if len(matches) > 1 && len(matches[1]) > 0 {
   164  		minItems, err := strconv.ParseInt(matches[1], 10, 64)
   165  		if err != nil {
   166  			return err
   167  		}
   168  		sm.builder.SetMinItems(minItems)
   169  	}
   170  	return nil
   171  }
   172  
   173  type setMaxLength struct {
   174  	builder validationBuilder
   175  	rx      *regexp.Regexp
   176  }
   177  
   178  func (sm *setMaxLength) Parse(lines []string) error {
   179  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   180  		return nil
   181  	}
   182  	matches := sm.rx.FindStringSubmatch(lines[0])
   183  	if len(matches) > 1 && len(matches[1]) > 0 {
   184  		maxLength, err := strconv.ParseInt(matches[1], 10, 64)
   185  		if err != nil {
   186  			return err
   187  		}
   188  		sm.builder.SetMaxLength(maxLength)
   189  	}
   190  	return nil
   191  }
   192  
   193  func (sm *setMaxLength) Matches(line string) bool {
   194  	return sm.rx.MatchString(line)
   195  }
   196  
   197  type setMinLength struct {
   198  	builder validationBuilder
   199  	rx      *regexp.Regexp
   200  }
   201  
   202  func (sm *setMinLength) Parse(lines []string) error {
   203  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   204  		return nil
   205  	}
   206  	matches := sm.rx.FindStringSubmatch(lines[0])
   207  	if len(matches) > 1 && len(matches[1]) > 0 {
   208  		minLength, err := strconv.ParseInt(matches[1], 10, 64)
   209  		if err != nil {
   210  			return err
   211  		}
   212  		sm.builder.SetMinLength(minLength)
   213  	}
   214  	return nil
   215  }
   216  
   217  func (sm *setMinLength) Matches(line string) bool {
   218  	return sm.rx.MatchString(line)
   219  }
   220  
   221  type setPattern struct {
   222  	builder validationBuilder
   223  	rx      *regexp.Regexp
   224  }
   225  
   226  func (sm *setPattern) Parse(lines []string) error {
   227  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   228  		return nil
   229  	}
   230  	matches := sm.rx.FindStringSubmatch(lines[0])
   231  	if len(matches) > 1 && len(matches[1]) > 0 {
   232  		sm.builder.SetPattern(matches[1])
   233  	}
   234  	return nil
   235  }
   236  
   237  func (sm *setPattern) Matches(line string) bool {
   238  	return sm.rx.MatchString(line)
   239  }
   240  
   241  type setCollectionFormat struct {
   242  	builder operationValidationBuilder
   243  	rx      *regexp.Regexp
   244  }
   245  
   246  func (sm *setCollectionFormat) Parse(lines []string) error {
   247  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   248  		return nil
   249  	}
   250  	matches := sm.rx.FindStringSubmatch(lines[0])
   251  	if len(matches) > 1 && len(matches[1]) > 0 {
   252  		sm.builder.SetCollectionFormat(matches[1])
   253  	}
   254  	return nil
   255  }
   256  
   257  func (sm *setCollectionFormat) Matches(line string) bool {
   258  	return sm.rx.MatchString(line)
   259  }
   260  
   261  type setUnique struct {
   262  	builder validationBuilder
   263  	rx      *regexp.Regexp
   264  }
   265  
   266  func (su *setUnique) Matches(line string) bool {
   267  	return su.rx.MatchString(line)
   268  }
   269  
   270  func (su *setUnique) Parse(lines []string) error {
   271  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   272  		return nil
   273  	}
   274  	matches := su.rx.FindStringSubmatch(lines[0])
   275  	if len(matches) > 1 && len(matches[1]) > 0 {
   276  		req, err := strconv.ParseBool(matches[1])
   277  		if err != nil {
   278  			return err
   279  		}
   280  		su.builder.SetUnique(req)
   281  	}
   282  	return nil
   283  }
   284  
   285  type setEnum struct {
   286  	builder validationBuilder
   287  	rx      *regexp.Regexp
   288  }
   289  
   290  func (se *setEnum) Matches(line string) bool {
   291  	return se.rx.MatchString(line)
   292  }
   293  
   294  func (se *setEnum) Parse(lines []string) error {
   295  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   296  		return nil
   297  	}
   298  	matches := se.rx.FindStringSubmatch(lines[0])
   299  	if len(matches) > 1 && len(matches[1]) > 0 {
   300  		se.builder.SetEnum(matches[1])
   301  	}
   302  	return nil
   303  }
   304  
   305  func parseValueFromSchema(s string, schema *spec.SimpleSchema) (interface{}, error) {
   306  	if schema != nil {
   307  		switch strings.Trim(schema.TypeName(), "\"") {
   308  		case "integer", "int", "int64", "int32", "int16":
   309  			return strconv.Atoi(s)
   310  		case "bool", "boolean":
   311  			return strconv.ParseBool(s)
   312  		case "number", "float64", "float32":
   313  			return strconv.ParseFloat(s, 64)
   314  		case "object":
   315  			var obj map[string]interface{}
   316  			if err := json.Unmarshal([]byte(s), &obj); err != nil {
   317  				// If we can't parse it, just return the string.
   318  				return s, nil
   319  			}
   320  			return obj, nil
   321  		case "array":
   322  			var slice []interface{}
   323  			if err := json.Unmarshal([]byte(s), &slice); err != nil {
   324  				// If we can't parse it, just return the string.
   325  				return s, nil
   326  			}
   327  			return slice, nil
   328  		default:
   329  			return s, nil
   330  		}
   331  	} else {
   332  		return s, nil
   333  	}
   334  }
   335  
   336  type setDefault struct {
   337  	scheme  *spec.SimpleSchema
   338  	builder validationBuilder
   339  	rx      *regexp.Regexp
   340  }
   341  
   342  func (sd *setDefault) Matches(line string) bool {
   343  	return sd.rx.MatchString(line)
   344  }
   345  
   346  func (sd *setDefault) Parse(lines []string) error {
   347  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   348  		return nil
   349  	}
   350  	matches := sd.rx.FindStringSubmatch(lines[0])
   351  	if len(matches) > 1 && len(matches[1]) > 0 {
   352  		d, err := parseValueFromSchema(matches[1], sd.scheme)
   353  		if err != nil {
   354  			return err
   355  		}
   356  		sd.builder.SetDefault(d)
   357  	}
   358  	return nil
   359  }
   360  
   361  type setExample struct {
   362  	scheme  *spec.SimpleSchema
   363  	builder validationBuilder
   364  	rx      *regexp.Regexp
   365  }
   366  
   367  func (se *setExample) Matches(line string) bool {
   368  	return se.rx.MatchString(line)
   369  }
   370  
   371  func (se *setExample) Parse(lines []string) error {
   372  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   373  		return nil
   374  	}
   375  	matches := se.rx.FindStringSubmatch(lines[0])
   376  	if len(matches) > 1 && len(matches[1]) > 0 {
   377  		d, err := parseValueFromSchema(matches[1], se.scheme)
   378  		if err != nil {
   379  			return err
   380  		}
   381  		se.builder.SetExample(d)
   382  	}
   383  	return nil
   384  }
   385  
   386  type matchOnlyParam struct {
   387  	tgt *spec.Parameter
   388  	rx  *regexp.Regexp
   389  }
   390  
   391  func (mo *matchOnlyParam) Matches(line string) bool {
   392  	return mo.rx.MatchString(line)
   393  }
   394  
   395  func (mo *matchOnlyParam) Parse(lines []string) error {
   396  	return nil
   397  }
   398  
   399  type setRequiredParam struct {
   400  	tgt *spec.Parameter
   401  }
   402  
   403  func (su *setRequiredParam) Matches(line string) bool {
   404  	return rxRequired.MatchString(line)
   405  }
   406  
   407  func (su *setRequiredParam) Parse(lines []string) error {
   408  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   409  		return nil
   410  	}
   411  	matches := rxRequired.FindStringSubmatch(lines[0])
   412  	if len(matches) > 1 && len(matches[1]) > 0 {
   413  		req, err := strconv.ParseBool(matches[1])
   414  		if err != nil {
   415  			return err
   416  		}
   417  		su.tgt.Required = req
   418  	}
   419  	return nil
   420  }
   421  
   422  type setReadOnlySchema struct {
   423  	tgt *spec.Schema
   424  }
   425  
   426  func (su *setReadOnlySchema) Matches(line string) bool {
   427  	return rxReadOnly.MatchString(line)
   428  }
   429  
   430  func (su *setReadOnlySchema) Parse(lines []string) error {
   431  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   432  		return nil
   433  	}
   434  	matches := rxReadOnly.FindStringSubmatch(lines[0])
   435  	if len(matches) > 1 && len(matches[1]) > 0 {
   436  		req, err := strconv.ParseBool(matches[1])
   437  		if err != nil {
   438  			return err
   439  		}
   440  		su.tgt.ReadOnly = req
   441  	}
   442  	return nil
   443  }
   444  
   445  type setDiscriminator struct {
   446  	schema *spec.Schema
   447  	field  string
   448  }
   449  
   450  func (su *setDiscriminator) Matches(line string) bool {
   451  	return rxDiscriminator.MatchString(line)
   452  }
   453  
   454  func (su *setDiscriminator) Parse(lines []string) error {
   455  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   456  		return nil
   457  	}
   458  	matches := rxDiscriminator.FindStringSubmatch(lines[0])
   459  	if len(matches) > 1 && len(matches[1]) > 0 {
   460  		req, err := strconv.ParseBool(matches[1])
   461  		if err != nil {
   462  			return err
   463  		}
   464  		if req {
   465  			su.schema.Discriminator = su.field
   466  		} else {
   467  			if su.schema.Discriminator == su.field {
   468  				su.schema.Discriminator = ""
   469  			}
   470  		}
   471  	}
   472  	return nil
   473  }
   474  
   475  type setRequiredSchema struct {
   476  	schema *spec.Schema
   477  	field  string
   478  }
   479  
   480  func (su *setRequiredSchema) Matches(line string) bool {
   481  	return rxRequired.MatchString(line)
   482  }
   483  
   484  func (su *setRequiredSchema) Parse(lines []string) error {
   485  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   486  		return nil
   487  	}
   488  	matches := rxRequired.FindStringSubmatch(lines[0])
   489  	if len(matches) > 1 && len(matches[1]) > 0 {
   490  		req, err := strconv.ParseBool(matches[1])
   491  		if err != nil {
   492  			return err
   493  		}
   494  		midx := -1
   495  		for i, nm := range su.schema.Required {
   496  			if nm == su.field {
   497  				midx = i
   498  				break
   499  			}
   500  		}
   501  		if req {
   502  			if midx < 0 {
   503  				su.schema.Required = append(su.schema.Required, su.field)
   504  			}
   505  		} else if midx >= 0 {
   506  			su.schema.Required = append(su.schema.Required[:midx], su.schema.Required[midx+1:]...)
   507  		}
   508  	}
   509  	return nil
   510  }
   511  
   512  func newMultilineDropEmptyParser(rx *regexp.Regexp, set func([]string)) *multiLineDropEmptyParser {
   513  	return &multiLineDropEmptyParser{
   514  		rx:  rx,
   515  		set: set,
   516  	}
   517  }
   518  
   519  type multiLineDropEmptyParser struct {
   520  	set func([]string)
   521  	rx  *regexp.Regexp
   522  }
   523  
   524  func (m *multiLineDropEmptyParser) Matches(line string) bool {
   525  	return m.rx.MatchString(line)
   526  }
   527  
   528  func (m *multiLineDropEmptyParser) Parse(lines []string) error {
   529  	m.set(removeEmptyLines(lines))
   530  	return nil
   531  }
   532  
   533  func newSetSchemes(set func([]string)) *setSchemes {
   534  	return &setSchemes{
   535  		set: set,
   536  		rx:  rxSchemes,
   537  	}
   538  }
   539  
   540  type setSchemes struct {
   541  	set func([]string)
   542  	rx  *regexp.Regexp
   543  }
   544  
   545  func (ss *setSchemes) Matches(line string) bool {
   546  	return ss.rx.MatchString(line)
   547  }
   548  
   549  func (ss *setSchemes) Parse(lines []string) error {
   550  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   551  		return nil
   552  	}
   553  	matches := ss.rx.FindStringSubmatch(lines[0])
   554  	if len(matches) > 1 && len(matches[1]) > 0 {
   555  		sch := strings.Split(matches[1], ", ")
   556  
   557  		var schemes []string
   558  		for _, s := range sch {
   559  			ts := strings.TrimSpace(s)
   560  			if ts != "" {
   561  				schemes = append(schemes, ts)
   562  			}
   563  		}
   564  		ss.set(schemes)
   565  	}
   566  	return nil
   567  }
   568  
   569  func newSetSecurity(rx *regexp.Regexp, setter func([]map[string][]string)) *setSecurity {
   570  	return &setSecurity{
   571  		set: setter,
   572  		rx:  rx,
   573  	}
   574  }
   575  
   576  type setSecurity struct {
   577  	set func([]map[string][]string)
   578  	rx  *regexp.Regexp
   579  }
   580  
   581  func (ss *setSecurity) Matches(line string) bool {
   582  	return ss.rx.MatchString(line)
   583  }
   584  
   585  func (ss *setSecurity) Parse(lines []string) error {
   586  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   587  		return nil
   588  	}
   589  
   590  	var result []map[string][]string
   591  	for _, line := range lines {
   592  		kv := strings.SplitN(line, ":", 2)
   593  		scopes := []string{}
   594  		var key string
   595  
   596  		if len(kv) > 1 {
   597  			scs := strings.Split(kv[1], ",")
   598  			for _, scope := range scs {
   599  				tr := strings.TrimSpace(scope)
   600  				if tr != "" {
   601  					tr = strings.SplitAfter(tr, " ")[0]
   602  					scopes = append(scopes, strings.TrimSpace(tr))
   603  				}
   604  			}
   605  
   606  			key = strings.TrimSpace(kv[0])
   607  
   608  			result = append(result, map[string][]string{key: scopes})
   609  		}
   610  	}
   611  	ss.set(result)
   612  	return nil
   613  }
   614  
   615  func newSetResponses(definitions map[string]spec.Schema, responses map[string]spec.Response, setter func(*spec.Response, map[int]spec.Response)) *setOpResponses {
   616  	return &setOpResponses{
   617  		set:         setter,
   618  		rx:          rxResponses,
   619  		definitions: definitions,
   620  		responses:   responses,
   621  	}
   622  }
   623  
   624  type setOpResponses struct {
   625  	set         func(*spec.Response, map[int]spec.Response)
   626  	rx          *regexp.Regexp
   627  	definitions map[string]spec.Schema
   628  	responses   map[string]spec.Response
   629  }
   630  
   631  func (ss *setOpResponses) Matches(line string) bool {
   632  	return ss.rx.MatchString(line)
   633  }
   634  
   635  // ResponseTag used when specifying a response to point to a defined swagger:response
   636  const ResponseTag = "response"
   637  
   638  // BodyTag used when specifying a response to point to a model/schema
   639  const BodyTag = "body"
   640  
   641  // DescriptionTag used when specifying a response that gives a description of the response
   642  const DescriptionTag = "description"
   643  
   644  func parseTags(line string) (modelOrResponse string, arrays int, isDefinitionRef bool, description string, err error) {
   645  	tags := strings.Split(line, " ")
   646  	parsedModelOrResponse := false
   647  
   648  	for i, tagAndValue := range tags {
   649  		tagValList := strings.SplitN(tagAndValue, ":", 2)
   650  		var tag, value string
   651  		if len(tagValList) > 1 {
   652  			tag = tagValList[0]
   653  			value = tagValList[1]
   654  		} else {
   655  			//TODO: Print a warning, and in the long term, do not support not tagged values
   656  			//Add a default tag if none is supplied
   657  			if i == 0 {
   658  				tag = ResponseTag
   659  			} else {
   660  				tag = DescriptionTag
   661  			}
   662  			value = tagValList[0]
   663  		}
   664  
   665  		foundModelOrResponse := false
   666  		if !parsedModelOrResponse {
   667  			if tag == BodyTag {
   668  				foundModelOrResponse = true
   669  				isDefinitionRef = true
   670  			}
   671  			if tag == ResponseTag {
   672  				foundModelOrResponse = true
   673  				isDefinitionRef = false
   674  			}
   675  		}
   676  		if foundModelOrResponse {
   677  			//Read the model or response tag
   678  			parsedModelOrResponse = true
   679  			//Check for nested arrays
   680  			arrays = 0
   681  			for strings.HasPrefix(value, "[]") {
   682  				arrays++
   683  				value = value[2:]
   684  			}
   685  			//What's left over is the model name
   686  			modelOrResponse = value
   687  		} else {
   688  			foundDescription := false
   689  			if tag == DescriptionTag {
   690  				foundDescription = true
   691  			}
   692  			if foundDescription {
   693  				//Descriptions are special, they make they read the rest of the line
   694  				descriptionWords := []string{value}
   695  				if i < len(tags)-1 {
   696  					descriptionWords = append(descriptionWords, tags[i+1:]...)
   697  				}
   698  				description = strings.Join(descriptionWords, " ")
   699  				break
   700  			} else {
   701  				if tag == ResponseTag || tag == BodyTag || tag == DescriptionTag {
   702  					err = fmt.Errorf("Found valid tag %s, but not in a valid position", tag)
   703  				} else {
   704  					err = fmt.Errorf("Found invalid tag: %s", tag)
   705  				}
   706  				//return error
   707  				return
   708  			}
   709  		}
   710  	}
   711  
   712  	//TODO: Maybe do, if !parsedModelOrResponse {return some error}
   713  	return
   714  }
   715  
   716  func (ss *setOpResponses) Parse(lines []string) error {
   717  	if len(lines) == 0 || (len(lines) == 1 && len(lines[0]) == 0) {
   718  		return nil
   719  	}
   720  
   721  	var def *spec.Response
   722  	var scr map[int]spec.Response
   723  
   724  	for _, line := range lines {
   725  		kv := strings.SplitN(line, ":", 2)
   726  		var key, value string
   727  
   728  		if len(kv) > 1 {
   729  			key = strings.TrimSpace(kv[0])
   730  			if key == "" {
   731  				// this must be some weird empty line
   732  				continue
   733  			}
   734  			value = strings.TrimSpace(kv[1])
   735  			if value == "" {
   736  				var resp spec.Response
   737  				if strings.EqualFold("default", key) {
   738  					if def == nil {
   739  						def = &resp
   740  					}
   741  				} else {
   742  					if sc, err := strconv.Atoi(key); err == nil {
   743  						if scr == nil {
   744  							scr = make(map[int]spec.Response)
   745  						}
   746  						scr[sc] = resp
   747  					}
   748  				}
   749  				continue
   750  			}
   751  			refTarget, arrays, isDefinitionRef, description, err := parseTags(value)
   752  			if err != nil {
   753  				return err
   754  			}
   755  			//A possible exception for having a definition
   756  			if _, ok := ss.responses[refTarget]; !ok {
   757  				if _, ok := ss.definitions[refTarget]; ok {
   758  					isDefinitionRef = true
   759  				}
   760  			}
   761  
   762  			var ref spec.Ref
   763  			if isDefinitionRef {
   764  				if description == "" {
   765  					description = refTarget
   766  				}
   767  				ref, err = spec.NewRef("#/definitions/" + refTarget)
   768  			} else {
   769  				ref, err = spec.NewRef("#/responses/" + refTarget)
   770  			}
   771  			if err != nil {
   772  				return err
   773  			}
   774  
   775  			// description should used on anyway.
   776  			resp := spec.Response{ResponseProps: spec.ResponseProps{Description: description}}
   777  
   778  			if isDefinitionRef {
   779  				resp.Schema = new(spec.Schema)
   780  				resp.Description = description
   781  				if arrays == 0 {
   782  					resp.Schema.Ref = ref
   783  				} else {
   784  					cs := resp.Schema
   785  					for i := 0; i < arrays; i++ {
   786  						cs.Typed("array", "")
   787  						cs.Items = new(spec.SchemaOrArray)
   788  						cs.Items.Schema = new(spec.Schema)
   789  						cs = cs.Items.Schema
   790  					}
   791  					cs.Ref = ref
   792  				}
   793  				// ref. could be empty while use description tag
   794  			} else if len(refTarget) > 0 {
   795  				resp.Ref = ref
   796  			}
   797  
   798  			if strings.EqualFold("default", key) {
   799  				if def == nil {
   800  					def = &resp
   801  				}
   802  			} else {
   803  				if sc, err := strconv.Atoi(key); err == nil {
   804  					if scr == nil {
   805  						scr = make(map[int]spec.Response)
   806  					}
   807  					scr[sc] = resp
   808  				}
   809  			}
   810  		}
   811  	}
   812  	ss.set(def, scr)
   813  	return nil
   814  }
   815  
   816  func parseEnum(val string, s *spec.SimpleSchema) []interface{} {
   817  	list := strings.Split(val, ",")
   818  	interfaceSlice := make([]interface{}, len(list))
   819  	for i, d := range list {
   820  		v, err := parseValueFromSchema(d, s)
   821  		if err != nil {
   822  			interfaceSlice[i] = d
   823  			continue
   824  		}
   825  
   826  		interfaceSlice[i] = v
   827  	}
   828  	return interfaceSlice
   829  }