docs: function (Vue) {
    var ValidityGroup = Group(Vue);
  
    var Validation = function Validation (options) {
      if ( options === void 0 ) options = {};
  
      this._result = {};
      this._host = options.host;
      this._named = Object.create(null);
      this._group = Object.create(null);
      this._validities = Object.create(null);
      this._beginDestroy = false;
      Vue.util.defineReactive(this._host, '$validation', this._result);
    };
  
    Validation.prototype.register = function register (
      field,
      validity,
      options
    ) {
        if ( options === void 0 ) options = {};
  
      // NOTE: lazy setup (in constructor, occured callstack recursive errors ...)
      if (!this._validityManager) {
        this._validityManager = new Vue(ValidityGroup);
        this._watchValidityResult();
      }
  
      if (this._validities[field]) {
        // TODO: should be output console.error
        return
      }
      this._validities[field] = validity;
  
      var named = options.named;
        var group = options.group;
      var groupValidity = group
        ? this._getValidityGroup('group', group) || this._registerValidityGroup('group', group)
        : null;
      var namedValidity = named
        ? this._getValidityGroup('named', named) || this._registerValidityGroup('named', named)
        : null;
      if (named && group && namedValidity && groupValidity) {
        groupValidity.register(field, validity);
        !namedValidity.isRegistered(group) && namedValidity.register(group, groupValidity);
        !this._validityManager.isRegistered(named) && this._validityManager.register(named, namedValidity);
      } else if (namedValidity) {
        namedValidity.register(field, validity);
        !this._validityManager.isRegistered(named) && this._validityManager.register(named, namedValidity);
      } else if (groupValidity) {
        groupValidity.register(field, validity);
        !this._validityManager.isRegistered(group) && this._validityManager.register(group, groupValidity);
      } else {
        this._validityManager.register(field, validity);
      }
    };
  
    Validation.prototype.unregister = function unregister (
      field,
      options
    ) {
        if ( options === void 0 ) options = {};
  
      if (!this._validityManager) {
        // TODO: should be output error
        return
      }
  
      if (!this._validities[field]) {
        // TODO: should be output error
        return
      }
      delete this._validities[field];
  
      var named = options.named;
        var group = options.group;
      var groupValidity = group ? this._getValidityGroup('group', group) : null;
      var namedValidity = named ? this._getValidityGroup('named', named) : null;
      if (named && group && namedValidity && groupValidity) {
        groupValidity.unregister(field);
        if (groupValidity.validityCount() === 0) {
          namedValidity.isRegistered(group) && namedValidity.unregister(group);
          this._unregisterValidityGroup('group', group);
        }
        if (namedValidity.validityCount() === 0) {
          this._validityManager.isRegistered(named) && this._validityManager.unregister(named);
          this._unregisterValidityGroup('named', named);
        }
      } else if (named && namedValidity) {
        namedValidity.unregister(field);
        if (namedValidity.validityCount() === 0) {
          this._validityManager.isRegistered(named) && this._validityManager.unregister(named);
          this._unregisterValidityGroup('named', named);
        }
      } else if (group && groupValidity) {
        groupValidity.unregister(field);
        if (groupValidity.validityCount() === 0) {
          this._validityManager.isRegistered(group) && this._validityManager.unregister(group);
          this._unregisterValidityGroup('group', group);
        }
      } else {
        this._validityManager.unregister(field);
      }
    };
  
    Validation.prototype.destroy = function destroy () {
        var this$1 = this;
  
      var validityKeys = Object.keys(this._validities);
      var namedKeys = Object.keys(this._named);
      var groupKeys = Object.keys(this._group);
  
      // unregister validity
      validityKeys.forEach(function (validityKey) {
        groupKeys.forEach(function (groupKey) {
          var group = this$1._getValidityGroup('group', groupKey);
          if (group && group.isRegistered(groupKey)) {
            group.unregister(validityKey);
          }
        });
        namedKeys.forEach(function (namedKey) {
          var named = this$1._getValidityGroup('named', namedKey);
          if (named && named.isRegistered(validityKey)) {
            named.unregister(validityKey);
          }
        });
        if (this$1._validityManager.isRegistered(validityKey)) {
          this$1._validityManager.unregister(validityKey);
        }
        delete this$1._validities[validityKey];
      });
  
      // unregister grouped validity
      groupKeys.forEach(function (groupKey) {
        namedKeys.forEach(function (namedKey) {
          var named = this$1._getValidityGroup('named', namedKey);
          if (named && named.isRegistered(groupKey)) {
            named.unregister(groupKey);
          }
        });
        if (this$1._validityManager.isRegistered(groupKey)) {
          this$1._validityManager.unregister(groupKey);
        }
        this$1._unregisterValidityGroup('group', groupKey);
      });
  
      // unregister named validity
      namedKeys.forEach(function (namedKey) {
        if (this$1._validityManager.isRegistered(namedKey)) {
          this$1._validityManager.unregister(namedKey);
        }
        this$1._unregisterValidityGroup('named', namedKey);
      });
  
      this._beginDestroy = true;
    };
  
    Validation.prototype._getValidityGroup = function _getValidityGroup (type, name) {
      return type === 'named' ? this._named[name] : this._group[name]
    };
  
    Validation.prototype._registerValidityGroup = function _registerValidityGroup (type, name) {
      var groups = type === 'named' ? this._named : this._group;
      groups[name] = new Vue(ValidityGroup);
      return groups[name]
    };
  
    Validation.prototype._unregisterValidityGroup = function _unregisterValidityGroup (type, name) {
      var groups = type === 'named' ? this._named : this._group;
      if (!groups[name]) {
        // TODO: should be warn
        return
      }
  
      groups[name].$destroy();
      delete groups[name];
    };
  
    Validation.prototype._watchValidityResult = function _watchValidityResult () {
        var this$1 = this;
  
      this._watcher = this._validityManager.$watch('results', function (val, old) {
        Vue.set(this$1._host, '$validation', val);
        if (this$1._beginDestroy) {
          this$1._destroyValidityMananger();
        }
      }, { deep: true });
    };
  
    Validation.prototype._unwatchValidityResult = function _unwatchValidityResult () {
      this._watcher();
      delete this._watcher;
    };
  
    Validation.prototype._destroyValidityMananger = function _destroyValidityMananger () {
      this._unwatchValidityResult();
      this._validityManager.$destroy();
      this._validityManager = null;
    };
  
    return Validation
  }