/** * @summary validation-property * @version 3.0.0 * @since 1.0.0 * @author Arian Khosravi <arian.khosravi@aofl.com> */ import {ValidationFunction} from './validation-function'; /** * ValidationProperty implementation * * @memberof module:@aofl/form-validate */ class ValidationProperty { /** * Creates an instance of ValidationProperty. * * @param {Object} target * @param {Object} validators * @param {String} _propName */ constructor(target, validators, _propName = '') { Object.defineProperty(this, 'resolve', { writable: true }); Object.defineProperty(this, 'validateCompleteResolved', { writable: true }); Object.defineProperty(this, 'validateCompletePromise', { writable: true }); for (const key in validators) { /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(validators, key)) continue; /* istanbul ignore next */ if (Object.prototype.hasOwnProperty.call(this, key)) { throw new Error(`${key} is a reserved keyword and cannot be used as a validator name.`); } let propName = _propName; // @todo: move to object-utils if (propName.length === 0) { propName = key; } else { propName += '.' + key; } if (typeof validators[key] === 'function') { this[key] = new ValidationFunction(target, validators[key], propName); } else { this[key] = new ValidationProperty(target, validators[key], propName); } } this.reset(); } /** * */ reset() { this.validateCompletePromise = new Promise((resolve) => { this.resolve = resolve; }); this.validateCompleteResolved = false; for (const key in this) { /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(this, key) || !(this[key] instanceof ValidationProperty || this[key] instanceof ValidationFunction)) continue; this[key].reset(); } } /** * * @readonly * @type {Boolean} */ get valid() { for (const key in this) { /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(this, key) || !(this[key] instanceof ValidationProperty || this[key] instanceof ValidationFunction)) continue; if (this[key].valid === false) { return false; } } return true; } /** * * @readonly * @type {Boolean} */ get pending() { for (const key in this) { /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(this, key) || !(this[key] instanceof ValidationProperty || this[key] instanceof ValidationFunction)) continue; if (this[key].pending === true) { return true; } } return false; } /** * * @readonly * @type {Boolean} */ get observed() { for (const key in this) { /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(this, key) || !(this[key] instanceof ValidationProperty || this[key] instanceof ValidationFunction)) continue; if (this[key].observed === true) { return true; } } return false; } /** * * */ validate() { for (const key in this) { /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(this, key) || !(this[key] instanceof ValidationProperty || this[key] instanceof ValidationFunction)) continue; this[key].validate(); } } /** * * @readonly * @type {Promise} */ get validateComplete() { if (this.pending && this.validateCompleteResolved) { this.validateCompleteResolved = false; this.validateCompletePromise = new Promise((resolve) => { this.resolve = resolve; }); } const checkPendingPromises = () => { const promises = Object.keys(this).map((item) => this[item].validateComplete); Promise.all(promises) .then(() => { if (this.pending) { return checkPendingPromises(); } this.resolve(); this.validateCompleteResolved = true; }); }; checkPendingPromises(); return this.validateCompletePromise; } /* istanbul ignore next */ /** * * @return {Array} */ getKeys() { const keys = ['valid', 'pending', 'observed']; for (const key in this) { /* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(this, key)) continue; keys.push(key); keys.push(...this[key].getKeys()); } return keys; } /* istanbul ignore next */ /** * @return {String} */ toString() { const keys = this.getKeys(); return JSON.stringify(this, keys, 2); } } export { ValidationProperty };