返回

async-validator 源码解析(四):Schema 类

前端

在上一篇文章中,我们分析了 async-validator 校验库的 validator 目录下的代码。这次,我们将继续自底向上进入到最上层 index.js,分析 async-validator 校验库的核心 Schema 类。

Schema 类

Schema 类是 async-validator 校验库的核心类,负责解析规则、验证数据、收集错误信息等核心功能。Schema 类的构造函数如下:

export default class Schema {
  constructor() {
    this.rules = null;
    this.messages = {};
    this._messages = [];
    this._errorClass = Error;
    this.silent = false;
  }
}

从构造函数可以看出,Schema 类具有以下属性和方法:

  • rules:存储校验规则的对象。
  • messages:存储校验错误信息的国际化文案。
  • _messages:存储校验错误信息。
  • _errorClass:自定义的错误类,默认为 Error
  • silent:是否静默模式,默认为 false

解析规则

Schema 类提供了 add 方法来解析校验规则:

add(field, rule) {
    if (Array.isArray(field)) {
      field.forEach(field => {
        this.add(field, rule);
      });
      return this;
    }

    const { message, ...ruleWithoutMessage } = normalizeRule(rule);
    if (message) {
      this._messages.push({
        field,
        message
      });
    }
    this.rules = this.rules || {};
    this.rules[field] = ruleWithoutMessage;
    return this;
  }

add 方法可以接受两个参数:fieldrulefield 是要校验的字段,可以是字符串或数组,rule 是校验规则,可以是对象或函数。

如果 field 是数组,add 方法会对数组中的每个字段分别添加校验规则。

如果 rule 是对象,add 方法会将 rule 中的 message 属性单独提取出来,并将其存储在 _messages 数组中。然后,add 方法会将 rule 中除了 message 属性以外的其他属性存储在 rules 对象中。

如果 rule 是函数,add 方法会直接将 rule 存储在 rules 对象中。

验证数据

Schema 类提供了 validate 方法来验证数据:

async validate(data, options = {}) {
    const opts = Object.assign({}, this.options, options);
    await Promise.all(
      Object.keys(this.rules).map(async field => {
        const fieldValidationPromises = this._validateField(field, data[field], opts);
        const fieldErrors = await Promise.all(fieldValidationPromises);
        // Concatenate all errors of this field to `_errors`
        this._errors = this._errors.concat(
          this._processErrors(fieldErrors, field, opts)
        );
      })
    );
    return this._errors;
  }

validate 方法可以接受两个参数:dataoptionsdata 是要验证的数据,options 是可选的配置项。

validate 方法首先会将 optionsthis.options 合并,然后对 this.rules 对象中的每个字段进行校验。

对于每个字段,validate 方法会调用 _validateField 方法来验证字段的值。_validateField 方法会返回一个 Promise,该 Promise 会在校验完成后被解析。

validate 方法会等待所有字段的校验完成,然后将所有字段的校验错误信息收集到 _errors 数组中。最后,validate 方法会返回 _errors 数组。

收集错误信息

Schema 类提供了 _processErrors 方法来收集错误信息:

_processErrors(errors, field, options = {}) {
    if (!errors.length) {
      return [];
    }

    const processedErrors = errors
      .map(({ message, rule, type }) => {
        if (typeof message === 'function') {
          message = message(
            options.messages || this.messages,
            field,
            type
          );
        } else if (typeof message === 'string') {
          message = i18n(
            options.messages || this.messages,
            message,
            field,
            type
          );
        }

        return {
          message,
          field,
          rule,
          type
        };
      })
      .filter(
        ({ message, field }) => !this.silent && this._checkFieldInSchema(field)
      );

    if (this.silent) {
      return [];
    }

    if (this._hasRulesInSchema(field)) {
      return processedErrors;
    }

    return [];
  }

_processErrors 方法可以接受三个参数:errorsfieldoptionserrors 是要处理的错误信息数组,field 是校验字段,options 是可选的配置项。

_processErrors 方法首先会检查 errors 数组是否为空。如果为空,则直接返回空数组。

如果 errors 数组不为空,_processErrors 方法会对数组中的每个错误信息进行处理。

对于每个错误信息,_processErrors 方法会先检查 message 属性是否为函数。如果是函数,则会调用 message 函数来获取错误信息。否则,_processErrors 方法会直接使用 message 属性作为错误信息。

然后,_processErrors 方法会检查 this.silent 属性是否为 true。如果是,则会过滤掉所有错误信息。

最后,_processErrors 方法会检查 field 字段在 this.rules 对象中是否存在。如果存在,则会将处理后的错误信息返回。否则,会返回空数组。

总结

Schema 类是 async-validator 校验库的核心类,负责解析规则、验证数据、收集错误信息等核心功能。通过分析 Schema 类的源码,我们可以更好地理解 async-validator 校验库的工作原理。