balm-ui
Version:
A modular and customizable UI library based on Material Design and Vue 3
190 lines (159 loc) • 5.29 kB
JavaScript
import { getCurrentInstance } from 'vue';
import getType from '../utils/typeof';
const defaultRules = {
required: {
validate(value) {
return value && value.length > 0;
},
message: '%s is required'
}
};
// Define validator constants
const LABEL_PLACEHOLDER = '%s';
let globalValidationRules = {};
function upgradeMessage(from, to) {
console.warn(
'[$validator]',
`The '${from}' has been deprecated. Use the '${to}' instead`
);
}
class UiValidator {
constructor() {
const currentInstance = getCurrentInstance();
this.instance = currentInstance;
this.validations = [];
this.customValidations = [];
}
validate(formData = {}, customFieldset = []) {
let result = {
valid: true,
validFields: [], // Valid field names
invalidFields: [], // Invalid field names
messages: [], // All invalid fields' messages
message: '', // First invalid field's message
validMsg: {}
};
let currentValidations = [];
if (this.instance) {
const { setupState, data } = this.instance;
currentValidations = setupState.validations || data.validations || [];
}
this.validations = this.customValidations.length
? this.customValidations
: currentValidations;
if (!Array.isArray(this.validations)) {
throw new Error('[$validator]: validations must be an array in 10.7.0');
}
for (let i = 0, fieldCount = this.validations.length; i < fieldCount; i++) {
const fieldOption = this.validations[i]; // The validation option of current field
const { key, label, validator } = fieldOption;
const fieldName = key; // Field name
const needValidator =
!customFieldset.length || customFieldset.includes(fieldName);
if (needValidator) {
const fieldLabel = label || fieldName; // Field alias name
const fieldRules = validator
.split(',')
.map((validator) => validator.trim()); // All validation methods of current field
let isAllValidOfField = true;
for (let j = 0, rulesCount = fieldRules.length; j < rulesCount; j++) {
let ruleName = fieldRules[j];
let localValidationRule = fieldOption[ruleName];
let rule =
getType(localValidationRule) === 'object'
? localValidationRule
: globalValidationRules[ruleName]; // Current validation method
if (rule && getType(rule.validate) === 'function') {
let fieldValue = formData[fieldName];
let fieldArgs = [fieldValue, formData];
if (!rule.validate(...fieldArgs)) {
isAllValidOfField = false;
let message = '';
switch (getType(rule.message)) {
case 'string':
message = rule.message.replace(LABEL_PLACEHOLDER, fieldLabel);
break;
case 'function':
message = rule.message(...fieldArgs);
break;
default:
console.warn(
'[$validator]',
`'${fieldName}.message' must be a string or function`
);
break;
}
if (message) {
result.messages.push(message);
}
break;
}
} else {
console.warn(
'[$validator]',
`The field '${fieldName}' is missing a validation rule: '${ruleName}'`
);
}
}
if (isAllValidOfField) {
result.validFields.push(fieldName);
} else {
result.invalidFields.push(fieldName);
}
}
}
if (result.messages.length) {
result.valid = false;
result.message = result.messages[0];
result.invalidFields.forEach((field, index) => {
result.validMsg[field] = result.messages[index];
});
}
result.validFields.forEach((field) => {
result.validMsg[field] = '';
});
return result;
}
resetValidations() {
upgradeMessage('resetValidations', 'clear');
}
setValidations() {
upgradeMessage('setValidations', 'set');
}
clear() {
this.customValidations = [];
}
get(fieldName = '') {
return fieldName
? this.customValidations.find(({ key }) => key === fieldName)
: this.customValidations;
}
set(fieldName, validationRule = {}) {
if (Array.isArray(fieldName)) {
this.customValidations = fieldName;
} else {
const index = this.customValidations.findIndex(
({ key }) => key === fieldName
);
if (~index) {
this.customValidations[index] = Object.assign({}, validationRule);
} else {
this.customValidations = [
Object.assign({ key: fieldName }, validationRule)
];
}
}
}
}
function install(app, customRules = {}) {
globalValidationRules = Object.assign({}, defaultRules, customRules);
const validator = new UiValidator();
app.config.globalProperties.$validator = validator;
app.provide('validator', validator);
}
const $validator = {
install
};
const useValidator = () => new UiValidator();
export default $validator;
export { install, useValidator };