validator.js 8.34 KB
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }

function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }

function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

/* eslint-disable react-hooks/exhaustive-deps */
import { getDescriptorFromSchema, formatPathFromValidator, isPathRequired, getArray, getSchemaFromFlatten } from './utils';
import { defaultValidateMessagesCN } from './validateMessageCN';
import { defaultValidateMessages } from './validateMessage';
import Validator from 'async-validator';
import { get, merge } from 'lodash-es';
export var validateAll = function validateAll(_ref) {
  var formData = _ref.formData,
      flatten = _ref.flatten,
      _ref$isRequired = _ref.isRequired,
      isRequired = _ref$isRequired === void 0 ? true : _ref$isRequired,
      _ref$touchedKeys = _ref.touchedKeys,
      touchedKeys = _ref$touchedKeys === void 0 ? [] : _ref$touchedKeys,
      _ref$locale = _ref.locale,
      locale = _ref$locale === void 0 ? 'cn' : _ref$locale,
      _ref$validateMessages = _ref.validateMessages,
      validateMessages = _ref$validateMessages === void 0 ? {} : _ref$validateMessages;

  var _schema = getSchemaFromFlatten(flatten);

  if (Object.keys(_schema).length === 0) return Promise.resolve();
  var descriptor = getDescriptorFromSchema({
    schema: _schema,
    isRequired: isRequired
  }).fields;
  window.descriptor = descriptor; // console.log(descriptor, '&&&& descriptor', formData);

  var touchVerifyList = []; // 如果是最后的校验,所有key都touch了,就不用算这个了
  // 因为要整个构建validator在list的情况太复杂了,所以required单独拿出来处理,但是这边有不少单独处理逻辑,例如message

  if (!isRequired) {
    touchedKeys.forEach(function (key) {
      var keyRequired = isPathRequired(key, _schema);
      var val = get(formData, key);
      var nullValue = [undefined, null, ''].indexOf(val) > -1; // 注意 0 不是

      var isEmptyMultiSelect = Array.isArray(val) && val.length === 0;

      if ((nullValue || isEmptyMultiSelect) && keyRequired.required) {
        var _message = keyRequired.message || validateMessages.required || '${title}必填';

        touchVerifyList.push({
          name: key,
          error: [_message]
        });
      }
    });
  }

  var cn = defaultValidateMessagesCN;
  var en = defaultValidateMessages; // TODO: 有些情况会出现没有rules,需要看一下,先兜底

  var validator;

  try {
    validator = new Validator(descriptor);
  } catch (error) {
    return Promise.resolve([]);
  }

  var messageFeed = locale === 'en' ? en : cn;
  merge(messageFeed, validateMessages);
  validator.messages(messageFeed);
  return validator.validate(formData || {}).then(function (res) {
    if (touchVerifyList.length > 0) return touchVerifyList;
    return [];
  }).catch(function (_ref2) {
    var errors = _ref2.errors,
        fields = _ref2.fields;
    // error的name改成正常的path
    var normalizedErrors = getArray(errors).map(function (err) {
      var _path = formatPathFromValidator(err.field);

      return {
        name: _path,
        error: [err.message]
      };
    }); // 添加touched的required

    normalizedErrors = [].concat(_toConsumableArray(normalizedErrors), touchVerifyList); // 合并同名的error

    var _errorFields = [];
    normalizedErrors.forEach(function (item) {
      var matchIndex = _errorFields.findIndex(function (ele) {
        return ele.name === item.name;
      });

      if (matchIndex === -1) {
        _errorFields.push(item);
      } else {
        _errorFields[matchIndex].error = [].concat(_toConsumableArray(_errorFields[matchIndex].error), _toConsumableArray(item.error));
      }
    });
    return _errorFields;
  });
}; // useEffect(() => {
//   const descriptor = {
//     roles: {
//       type: 'array',
//       required: true,
//       defaultField: {
//         type: 'object',
//         fields: {
//           street: { type: 'string', required: true },
//           city: { type: 'string', required: true, message: 'invalid zip' },
//           zip: [
//             {
//               type: 'string',
//               required: true,
//               message: 'invalid zip',
//             },
//             {
//               len: 8,
//               message: 'xxx',
//             },
//           ],
//           res: {
//             type: 'array',
//             required: true,
//             defaultField: {
//               type: 'object',
//               fields: {
//                 city: { type: 'string', required: true },
//               },
//             },
//           },
//         },
//       },
//     },
//     name: {
//       type: 'string',
//       required: true,
//       validator: (rule, value) => value === 'muji',
//     },
//     age: {
//       type: 'number',
//       min: 12,
//       max: 13,
//       message: 'asdfadsf',
//       // asyncValidator: (rule, value) => {
//       //   return new Promise((resolve, reject) => {
//       //     if (value < 18) {
//       //       reject('too young'); // reject with error message
//       //     } else {
//       //       resolve();
//       //     }
//       //   });
//       // },
//     },
//   };
//   const validator = new Validator(descriptor);
//   // validator.validate({ name: 'muji' }, (errors, fields) => {
//   //   if (errors) {
//   //     // validation failed, errors is an array of all errors
//   //     // fields is an object keyed by field name with an array of
//   //     // errors per field
//   //     return handleErrors(errors, fields);
//   //   }
//   //   // validation passed
//   // });
//   validator
//     .validate({ name: 'muji', age: 16, roles: [{ zip: '123', res: [{}] }] })
//     .then(() => {
//       // validation passed or without error message
//     })
//     .catch(({ errors, fields }) => {
//       return handleErrors(errors, fields);
//     });
// }, []);

var d3 = {
  list: {
    type: 'array',
    defaultField: {
      type: 'object',
      fields: {
        userName: [{
          bind: false,
          title: 'User Name',
          type: 'string',
          rules: [{
            min: 5,
            message: '长度需要大于5'
          }, {
            max: 12
          }]
        }, {
          min: 5,
          message: '长度需要大于5'
        }, {
          max: 12
        }],
        selectName: {
          title: '单选',
          type: 'string',
          enum: ['a', 'b', 'c'],
          enumNames: ['早', '中', '晚'],
          required: true
        },
        checkboxName: {
          title: '是否判断',
          type: 'boolean',
          valuePropName: 'checked'
        }
      }
    }
  }
};
var d2 = {
  list: {
    type: 'array',
    defaultField: {
      type: 'object',
      fields: {
        userName: [{
          bind: false,
          title: 'User Name',
          type: 'string',
          rules: [{
            min: 5,
            message: '长度需要大于5'
          }, {
            max: 12
          }]
        }, {
          min: 5,
          message: '长度需要大于5'
        }, {
          max: 12
        }],
        selectName: {
          title: '单选',
          type: 'string',
          enum: ['a', 'b', 'c'],
          enumNames: ['早', '中', '晚'],
          required: true
        },
        checkboxName: {
          title: '是否判断',
          type: 'boolean',
          valuePropName: 'checked'
        }
      }
    }
  }
};