github.com/rzurga/go-swagger@v0.28.1-0.20211109195225-5d1f453ffa3a/scan/validators.go (about)

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