<commit_before>import React from 'react';
import {
  reduceValues,
  reduceErrors,
  reduceChanged,
  isEqualObjects,
  getComponentName,
  getKeyValueFromElement,
} from './helpers';

export default function Refova(
  {
    mapPropsToValues = () => ({}),
    validations = {},
    resetWhenPropsChange = true,
    validateWhenPropsChange = false,
  } = {}
) {
  /**
   * Validate single value.
   * @param {String} key - Key for rules.
   * @param {*} value - Value to validate.
   * @param {Object} payload - Payload for validation rule.
   * @returns {(Boolean|String)} - 'true' if a value passed validation, otherwise error message.
   */
  const _validateValue = (key, value, payload) => {
    const rules = validations[key];
    if (rules && rules.length) {
      for (let i = 0, len = rules.length; i < len; i++) {
        const { test, message } = rules[i];
        if (test(value, payload) === true) continue;
        return typeof message === 'function'
          ? message(value, payload)
          : message;
      }
    }
    return true;
  };

  /**
   * Validate multiple values.
   * @param {Object} values - Values to validate.
   * @param {Object} payload - Payload for validation rule.
   * @returns {Object} - Validations result.
   */
  const _validateValues = (values, payload) => {
    return Object.keys(values).reduce((acc, key) => {
      acc[key] = _validateValue(key, values[key], payload);
      return acc;
    }, {});
  };

  /**
   * Get Refova state from component props.
   * @param {Object} props - Component props.
   * @returns {{values: Object, errors: Object, changed: []}}
   */
  const _getStateFromProps = props => {
    const values = mapPropsToValues(props);
    const changed = [];
    const errors = validateWhenPropsChange
      ? reduceErrors({}, _validateValues(values, { values, changed, props }))
      : {};
    return { values, errors, changed };
  };

  return Wrapped => {
    class Refova extends React.Component {
      constructor(props) {
        super(props);
        this.state = _getStateFromProps(props);
      }

      /**
       * Set and (optional) validate value.
       * @param {string} key - Key for value.
       * @param {*} value - Value to set.
       * @param {Boolean} [validate=true] - Optional validation.
       */
      setValue = (key, value, validate = true) => {
        this.setValues({ [key]: value }, validate);
      };

      /**
       * Set and (optional) validate multiple value.
       * @param {Object} values - Values.
       * @param {Boolean} [validate=true] - Optional validation.
       */
      setValues = (values, validate = true) => {
        const nextState = {
          values: reduceValues(this.state.values, values),
          changed: reduceChanged(this.state.changed, Object.keys(values)),
        };
        if (validate) {
          const payload = this._getPayload(nextState);
          nextState.errors = reduceErrors(
            this.state.errors,
            _validateValues(values, payload)
          );
        }
        this.setState(nextState);
      };

      /**
       * Reset error/errors by given key/keys.
       * @param {(String|String[])} key - Key/keys for which need to reset errors.
       */
      resetError = key => {
        let errors = [].concat(key).reduce((acc, key) => {
          acc[key] = true;
          return acc;
        }, {});<commit_msg>provided callback for setValue/setValues methods<commit_after>import React from 'react';
import {
  reduceValues,
  reduceErrors,
  reduceChanged,
  isEqualObjects,
  getComponentName,
  getKeyValueFromElement,
} from './helpers';

export default function Refova(
  {
    mapPropsToValues = () => ({}),
    validations = {},
    resetWhenPropsChange = true,
    validateWhenPropsChange = false,
  } = {}
) {
  /**
   * Validate single value.
   * @param {String} key - Key for rules.
   * @param {*} value - Value to validate.
   * @param {Object} payload - Payload for validation rule.
   * @returns {(Boolean|String)} - 'true' if a value passed validation, otherwise error message.
   */
  const _validateValue = (key, value, payload) => {
    const rules = validations[key];
    if (rules && rules.length) {
      for (let i = 0, len = rules.length; i < len; i++) {
        const { test, message } = rules[i];
        if (test(value, payload) === true) continue;
        return typeof message === 'function'
          ? message(value, payload)
          : message;
      }
    }
    return true;
  };

  /**
   * Validate multiple values.
   * @param {Object} values - Values to validate.
   * @param {Object} payload - Payload for validation rule.
   * @returns {Object} - Validations result.
   */
  const _validateValues = (values, payload) => {
    return Object.keys(values).reduce((acc, key) => {
      acc[key] = _validateValue(key, values[key], payload);
      return acc;
    }, {});
  };

  /**
   * Get Refova state from component props.
   * @param {Object} props - Component props.
   * @returns {{values: Object, errors: Object, changed: []}}
   */
  const _getStateFromProps = props => {
    const values = mapPropsToValues(props);
    const changed = [];
    const errors = validateWhenPropsChange
      ? reduceErrors({}, _validateValues(values, { values, changed, props }))
      : {};
    return { values, errors, changed };
  };

  return Wrapped => {
    class Refova extends React.Component {
      constructor(props) {
        super(props);
        this.state = _getStateFromProps(props);
      }

      /**
       * Set and (optional) validate value.
       * @param {string} key - Key for value.
       * @param {*} value - Value to set.
       * @param {Boolean} [validate=true] - Optional validation.
       * @param {Function} cb - The callback function for react setState.
       */
      setValue = (key, value, validate = true, cb) => {
        this.setValues({ [key]: value }, validate, cb);
      };

      /**
       * Set and (optional) validate multiple value.
       * @param {Object} values - Values.
       * @param {Boolean} [validate=true] - Optional validation.
       * @param {Function} cb - The callback function for react setState.
       * @callback
       */
      setValues = (values, validate = true, cb) => {
        const nextState = {
          values: reduceValues(this.state.values, values),
          changed: reduceChanged(this.state.changed, Object.keys(values)),
        };
        if (validate) {
          const payload = this._getPayload(nextState);
          nextState.errors = reduceErrors(
            this.state.errors,
            _validateValues(values, payload)
          );
        }
        this.setState(nextState, cb);
      };

      /**
       * Reset error/errors by given key/keys.
       * @param {(String|String[])} key - Key/keys for which need to reset errors.
       */
      resetError = key => {
        let errors = [].concat(key).reduce((acc, key) => {
          acc[key] = true;
          return acc;
        }, {});
{'fraction_non_alphanumeric': 0.1365456105233057, 'fraction_numerical': 0.00028595939376608524, 'mean_word_length': 2.316737790422001, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 23, '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': '7097846', 'n_tokens_mistral': 2003, 'n_tokens_neox': 1987, 'n_words': 559}