<commit_before>/*
This package allows for easy validation of passed in json.
Val does not intend to be a robust solution but does seek to cover 95% of use cases.
Val requires a structure to use pointers for validation. This may seem odd but if a pointer is
not used you will run into some strange issues since json.Decode() will pass an int type back 
set as 0 giving no way to tell if a 0 was actually passed in or not. Using a pointer allows to
check for a nil value before doing the validation and lets you have optional json parameters.

Basic Struct Example.

    var Register struct {
        Username *string `json:"username" validate:"required"`
        Password *string `json:"password" validate:"required"`
        Email    *string `json:"email" validate:"required|email"`
        Notify   *string `json:"notify" validate:"required|in:yes,no"`
    }

Normal Use Case.

    if err := val.Bind(r.Body, &Register); err != nil {
        fmt.Println(err)
    }

*/

package val

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"reflect"
	"regexp"
	"strconv"
	"strings"
)

// Unpack JSON and call the validate function if no errors are found when unpacking it.
// Bind kicks of the validation process. Note that Request.Body impliments an io.ReadCloser.
// Look into ReadAll http://jmoiron.net/blog/crossing-streams-a-love-letter-to-ioreader/
func Bind(input io.ReadCloser, obj interface{}) error {
	// Don't go through any logic if nothing was passed in.
	if b, err := ioutil.ReadAll(input); err == nil && string(b) != "{}" && string(b) != "" {
		// Turn our string back into a io.Reader if it's valid
		decoder := json.NewDecoder(bytes.NewReader(b))

		if err := decoder.Decode(obj); err == nil {
			return Validate(obj)
		} else {
			return err
		}
	} else if err == nil {
		return errors.New("Nothing was passed in or JSON featured an empty object.")
	} else {
		return err
	}
}

// In version 1.0 I exported the Validation function. This can be used when you may
// not need to or want to have JSON first converted into a struct.
func Validate(obj interface{}) error {

	typ := reflect.TypeOf(obj)
	value := reflect.ValueOf(obj)

	// Check to ensure we are getting a valid
	// pointer for manipulation.
	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
		value = value.Elem()
	}

	// Kill process if obj did not pass in a scruct.
	// This happens when a pointer passed in.
	if value.Kind() != reflect.Struct {
		return nil
	}

	for i := 0; i < typ.NumField(); i++ {

		field := typ.Field(i)
		fieldValue := value.Field(i).Interface()
		zero := reflect.Zero(field.Type).Interface()

		// Validate nested and embedded structs (if pointer, only do so if not nil)
		if field.Type.Kind() == reflect.Struct ||
			(field.Type.Kind() == reflect.Ptr && !reflect.DeepEqual(zero, fieldValue)) {
			if err := Validate(fieldValue); err != nil {
				return err
			}
		}

		if field.Tag.Get("validate") != "" || field.Tag.Get("binding") != "" {
			// Break validate field into array
			array := strings.Split(field.Tag.Get("validate"), "|")

			// Legacy Support for binding.
			if array[0] == "" {
				array = strings.Split(field.Tag.Get("binding"), "|")
			}

			// Do the hard work of checking all assertions
			for setting := range array {

				match := array[setting]

				//Check that value was passed in and is not required.
				if match != "required" && null(fieldValue) == true {
					return nil
				}

				switch {
				case "required" == match:
					if err := required(field, fieldValue, zero); err != nil {
						return err
					}
				case "email" == match:
					if err := regex(`regex:^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$`, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "min:"):
					if err := min(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "max:"):
					if err := max(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "in:"):
					if err := in(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "regex:"):
					if err := regex(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "length:"):
					if err := length(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "length_between:"):
					if err := length_between(match, fieldValue); err != nil {
						return err
					}
				default:<commit_msg>added in alpha, alphadash, alphanumeric, url support<commit_after>/*
This package allows for easy validation of passed in json.
Val does not intend to be a robust solution but does seek to cover 95% of use cases.
Val requires a structure to use pointers for validation. This may seem odd but if a pointer is
not used you will run into some strange issues since json.Decode() will pass an int type back 
set as 0 giving no way to tell if a 0 was actually passed in or not. Using a pointer allows to
check for a nil value before doing the validation and lets you have optional json parameters.

Basic Struct Example.

    var Register struct {
        Username *string `json:"username" validate:"required"`
        Password *string `json:"password" validate:"required"`
        Email    *string `json:"email" validate:"required|email"`
        Notify   *string `json:"notify" validate:"required|in:yes,no"`
    }

Normal Use Case.

    if err := val.Bind(r.Body, &Register); err != nil {
        fmt.Println(err)
    }

*/

package val

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"reflect"
	"regexp"
	"strconv"
	"strings"
)

// Unpack JSON and call the validate function if no errors are found when unpacking it.
// Bind kicks of the validation process. Note that Request.Body impliments an io.ReadCloser.
// Look into ReadAll http://jmoiron.net/blog/crossing-streams-a-love-letter-to-ioreader/
func Bind(input io.ReadCloser, obj interface{}) error {
	// Don't go through any logic if nothing was passed in.
	if b, err := ioutil.ReadAll(input); err == nil && string(b) != "{}" && string(b) != "" {
		// Turn our string back into a io.Reader if it's valid
		decoder := json.NewDecoder(bytes.NewReader(b))

		if err := decoder.Decode(obj); err == nil {
			return Validate(obj)
		} else {
			return err
		}
	} else if err == nil {
		return errors.New("Nothing was passed in or JSON featured an empty object.")
	} else {
		return err
	}
}

// In version 1.0 I exported the Validation function. This can be used when you may
// not need to or want to have JSON first converted into a struct.
func Validate(obj interface{}) error {

	typ := reflect.TypeOf(obj)
	value := reflect.ValueOf(obj)

	// Check to ensure we are getting a valid
	// pointer for manipulation.
	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
		value = value.Elem()
	}

	// Kill process if obj did not pass in a scruct.
	// This happens when a pointer passed in.
	if value.Kind() != reflect.Struct {
		return nil
	}

	for i := 0; i < typ.NumField(); i++ {

		field := typ.Field(i)
		fieldValue := value.Field(i).Interface()
		zero := reflect.Zero(field.Type).Interface()

		// Validate nested and embedded structs (if pointer, only do so if not nil)
		if field.Type.Kind() == reflect.Struct ||
			(field.Type.Kind() == reflect.Ptr && !reflect.DeepEqual(zero, fieldValue)) {
			if err := Validate(fieldValue); err != nil {
				return err
			}
		}

		if field.Tag.Get("validate") != "" || field.Tag.Get("binding") != "" {
			// Break validate field into array
			array := strings.Split(field.Tag.Get("validate"), "|")

			// Legacy Support for binding.
			if array[0] == "" {
				array = strings.Split(field.Tag.Get("binding"), "|")
			}

			// Do the hard work of checking all assertions
			for setting := range array {

				match := array[setting]

				//Check that value was passed in and is not required.
				if match != "required" && null(fieldValue) == true {
					return nil
				}

				switch {
				case "required" == match:
					if err := required(field, fieldValue, zero); err != nil {
						return err
					}
				case "email" == match:
					if err := regex(`regex:^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$`, fieldValue); err != nil {
						return err
					}
				case "url" == match:
					if err := regex(`regex:/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/`, fieldValue); err != nil {
						return err
					}
				case "alpha" == match:
					if err := regex(`regex:\p{L}`, fieldValue); err != nil {
						return err
					}
				case "alphadash" == match:
					if err := regex(`regex:^[a-zA-Z0-9_]*$`, fieldValue); err != nil {
						return err
					}
				case "alphanumeric" == match:
					if err := regex(`regex:/[0-9a-zA-Z]/`, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "min:"):
					if err := min(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "max:"):
					if err := max(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "in:"):
					if err := in(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "regex:"):
					if err := regex(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "length:"):
					if err := length(match, fieldValue); err != nil {
						return err
					}
				case strings.HasPrefix(match, "length_between:"):
					if err := length_between(match, fieldValue); err != nil {
						return err
					}
				default:
{'fraction_non_alphanumeric': 0.1396202664428826, 'fraction_numerical': 0.0035665582712682263, 'mean_word_length': 2.8740349451442504, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '4161063', 'n_tokens_mistral': 3480, 'n_tokens_neox': 2939, 'n_words': 1041}