<commit_before>package validation

import (
	"errors"
	"fmt"
	"regexp"

	"github.com/Clever/wag/swagger"
	swaggererrors "github.com/go-openapi/errors"
	"github.com/go-openapi/loads"
	"github.com/go-openapi/spec"
	"github.com/go-openapi/strfmt"
	"github.com/go-openapi/validate"
)

// A regex requiring the field to be start with a letter and be alphanumeric
var alphaNumRegex = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]*$")

// Validate checks if the swagger operation has any fields we don't support
func validateOp(path, method string, op *spec.Operation) error {
	if len(op.Consumes) != 0 {
		return fmt.Errorf("%s %s cannot have a consumes field. WAG does not support the consumes field "+
			"on operations", method, path)
	}
	if len(op.Produces) != 0 {
		return fmt.Errorf("%s %s cannot have a produces field. WAG does not support the produces field "+
			"on operations", method, path)
	}
	if len(op.Schemes) != 0 {
		return fmt.Errorf("%s %s cannot have a schemes field. WAG does not support the schemes field "+
			"on operations", method, path)
	}
	if len(op.Security) != 0 {
		return fmt.Errorf("%s %s cannot have a security field. WAG does not support the security field "+
			"on operations", method, path)
	}

	if op.ID == "" {
		return fmt.Errorf("%s %s must have an operationId field, "+
			"see http://swagger.io/specification/#operationObject", method, path)
	}

	if !alphaNumRegex.MatchString(op.ID) {
		// We need this because we build function / struct names with the operationID.
		// We could strip out the special characters, but it seems clearly to just enforce
		// this.
		return fmt.Errorf("The operationId for %s %s must be alphanumeric and start with a letter",
			method, path)
	}

	for _, statusCode := range swagger.SortedStatusCodeKeys(op.Responses.StatusCodeResponses) {
		if statusCode < 200 || statusCode > 599 {
			return fmt.Errorf("Response map key must be an integer between 200 and 599 or "+
				"the string 'default'. Was %d", statusCode)
		}
		_, err := swagger.TypeFromSchema(op.Responses.StatusCodeResponses[statusCode].Schema, false)
		if err != nil {
			return err
		}
	}

	for _, param := range op.Parameters {
		if param.In == "path" && !param.Required {
			return fmt.Errorf("%s for %s %s is a path parameter so it must be required",
				param.Name, method, path)
		}

		if param.Type == "string" && param.Format != "" {
			if param.MaxLength != nil || param.MinLength != nil || param.Pattern != "" || len(param.Enum) > 0 {
				return fmt.Errorf("%s for %s %s cannot have min/max length, pattern, or enum fields. "+
					"Only string type parameters without a format can have additional validation.",
					param.Name, method, path)
			}
		}

		if param.Type == "array" && param.Items.Type != "string" {
			return fmt.Errorf("Array parameters must have string sub-types")
		}
	}

	return nil
}

// Validate returns an error if the swagger file is invalid or uses fields
// we don't support. Note that this isn't a comprehensive check for all things
// we don't support, so this may not return an error, but the Swagger file might
// have values we don't support
func Validate(d loads.Document) error {
	s := d.Spec()

	goSwaggerError := validate.Spec(&d, strfmt.Default)<commit_msg>Update validation<commit_after>package validation

import (
	"errors"
	"fmt"
	"regexp"

	"github.com/Clever/wag/swagger"
	swaggererrors "github.com/go-openapi/errors"
	"github.com/go-openapi/loads"
	"github.com/go-openapi/spec"
	"github.com/go-openapi/strfmt"
	"github.com/go-openapi/validate"
)

// A regex requiring the field to be start with a letter and be alphanumeric
var alphaNumRegex = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]*$")

// Validate checks if the swagger operation has any fields we don't support
func validateOp(path, method string, op *spec.Operation) error {
	if len(op.Consumes) != 0 {
		return fmt.Errorf("%s %s cannot have a consumes field. WAG does not support the consumes field "+
			"on operations", method, path)
	}
	if len(op.Produces) != 0 {
		return fmt.Errorf("%s %s cannot have a produces field. WAG does not support the produces field "+
			"on operations", method, path)
	}
	if len(op.Schemes) != 0 {
		return fmt.Errorf("%s %s cannot have a schemes field. WAG does not support the schemes field "+
			"on operations", method, path)
	}
	if len(op.Security) != 0 {
		return fmt.Errorf("%s %s cannot have a security field. WAG does not support the security field "+
			"on operations", method, path)
	}

	if op.ID == "" {
		return fmt.Errorf("%s %s must have an operationId field, "+
			"see http://swagger.io/specification/#operationObject", method, path)
	}

	if !alphaNumRegex.MatchString(op.ID) {
		// We need this because we build function / struct names with the operationID.
		// We could strip out the special characters, but it seems clearly to just enforce
		// this.
		return fmt.Errorf("The operationId for %s %s must be alphanumeric and start with a letter",
			method, path)
	}

	for _, statusCode := range swagger.SortedStatusCodeKeys(op.Responses.StatusCodeResponses) {
		if statusCode < 200 || statusCode > 599 {
			return fmt.Errorf("Response map key must be an integer between 200 and 599 or "+
				"the string 'default'. Was %d", statusCode)
		}
		_, err := swagger.TypeFromSchema(op.Responses.StatusCodeResponses[statusCode].Schema, false)
		if err != nil {
			return err
		}
	}

	for _, param := range op.Parameters {

		switch param.In {
		case "path":
			if !param.Required {
				return fmt.Errorf("%s for %s %s is a path parameter so it must be required",
					param.Name, method, path)
			}
			if param.Type == "array" || param.Type == "object" {
				return fmt.Errorf("%s for %s %s is a path parameter so it must have a primitive type",
					param.Name, method, path)
			}
		case "body":
			if param.Default != nil {
				return fmt.Errorf("%s for %s %s is a body parameter so it must not have a default",
					param.Name, method, path)
			}
			if param.Schema == nil {
				return fmt.Errorf("%s for %s %s is a body parameter so it must reference a schema",
					param.Name, method, path)
			}
		case "query":
			if param.Type == "object" {
				return fmt.Errorf("%s for %s %s is a query param so it can't have the type 'object'",
					param.Name, method, path)
			}
			if param.Type == "array" && param.Items.Type != "string" {
				return fmt.Errorf("array parameters must have string sub-types")
			}
		case "header":
			if param.Type == "array" || param.Type == "object" {
				return fmt.Errorf("%s for %s %s is a path parameter so it must have a primitive type",
					param.Name, method, path)
			}
		default:
			return fmt.Errorf("unsupported param type: %s", param.In)
		}

		if param.Type == "string" && param.Format != "" {
			if param.MaxLength != nil || param.MinLength != nil || param.Pattern != "" || len(param.Enum) > 0 {
				return fmt.Errorf("%s for %s %s cannot have min/max length, pattern, or enum fields. "+
					"Only string type parameters without a format can have additional validation.",
					param.Name, method, path)
			}
		}
	}

	return nil
}

// Validate returns an error if the swagger file is invalid or uses fields
// we don't support. Note that this isn't a comprehensive check for all things
// we don't support, so this may not return an error, but the Swagger file might
// have values we don't support
func Validate(d loads.Document) error {
	s := d.Spec()

	goSwaggerError := validate.Spec(&d, strfmt.Default)
{'fraction_non_alphanumeric': 0.12315138478085506, 'fraction_numerical': 0.005108900242000538, 'mean_word_length': 3.4732411304870716, 'pattern_counts': {'":': 4, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7555758', 'n_tokens_mistral': 2575, 'n_tokens_neox': 2334, 'n_words': 868}