zgg-ui
Version:
2.0.1 正式版本 基于 Vue 3、UniApp 和 TypeScript 开发的多端适配移动端 UI 组件库,旨在提供丰富的组件集合,帮助开发者快速构建多端响应式的移动应用界面
304 lines (277 loc) • 7.16 kB
text/typescript
// @ts-nocheck
/* eslint no-console:0 */
import type {
ValidateError,
ValidateOption,
RuleValuePackage,
InternalRuleItem,
SyncErrorType,
RuleType,
Value,
Values,
} from './interface'
const formatRegExp = /%[sdj%]/g
declare var ASYNC_VALIDATOR_NO_WARNING
export let warning: (type: string, errors: SyncErrorType[]) => void = () => {}
// don't print warning message when in production env or node runtime
if (
typeof process !== 'undefined' &&
process.env &&
process.env.NODE_ENV !== 'production' &&
typeof window !== 'undefined' &&
typeof document !== 'undefined'
) {
warning = (type, errors) => {
if (
typeof console !== 'undefined' &&
console.warn &&
typeof ASYNC_VALIDATOR_NO_WARNING === 'undefined'
) {
if (errors.every(e => typeof e === 'string')) {
console.warn(type, errors)
}
}
}
}
export function convertFieldsError(
errors: ValidateError[]
): Record<string, ValidateError[]> {
if (!errors || !errors.length) return null
const fields = {}
errors.forEach(error => {
const field = error.field
fields[field] = fields[field] || []
fields[field].push(error)
})
return fields
}
export function format(
template: ((...args: any[]) => string) | string,
...args: any[]
): string {
let i = 0
const len = args.length
if (typeof template === 'function') {
return template.apply(null, args)
}
if (typeof template === 'string') {
let str = template.replace(formatRegExp, x => {
if (x === '%%') {
return '%'
}
if (i >= len) {
return x
}
switch (x) {
case '%s':
return String(args[i++])
case '%d':
return Number(args[i++]) as unknown as string
case '%j':
try {
return JSON.stringify(args[i++])
} catch (_) {
return '[Circular]'
}
break
default:
return x
}
})
return str
}
return template
}
function isNativeStringType(type: string) {
return (
type === 'string' ||
type === 'url' ||
type === 'hex' ||
type === 'email' ||
type === 'date' ||
type === 'pattern'
)
}
export function isEmptyValue(value: Value, type?: string) {
if (value === undefined || value === null) {
return true
}
if (type === 'array' && Array.isArray(value) && !value.length) {
return true
}
if (isNativeStringType(type) && typeof value === 'string' && !value) {
return true
}
return false
}
export function isEmptyObject(obj: object) {
return Object.keys(obj).length === 0
}
function asyncParallelArray(
arr: RuleValuePackage[],
func: ValidateFunc,
callback: (errors: ValidateError[]) => void
) {
const results: ValidateError[] = []
let total = 0
const arrLength = arr.length
function count(errors: ValidateError[]) {
results.push(...(errors || []))
total++
if (total === arrLength) {
callback(results)
}
}
arr.forEach(a => {
func(a, count)
})
}
function asyncSerialArray(
arr: RuleValuePackage[],
func: ValidateFunc,
callback: (errors: ValidateError[]) => void
) {
let index = 0
const arrLength = arr.length
function next(errors: ValidateError[]) {
if (errors && errors.length) {
callback(errors)
return
}
const original = index
index = index + 1
if (original < arrLength) {
func(arr[original], next)
} else {
callback([])
}
}
next([])
}
function flattenObjArr(objArr: Record<string, RuleValuePackage[]>) {
const ret: RuleValuePackage[] = []
Object.keys(objArr).forEach(k => {
ret.push(...(objArr[k] || []))
})
return ret
}
export class AsyncValidationError extends Error {
errors: ValidateError[]
fields: Record<string, ValidateError[]>
constructor(errors: ValidateError[], fields: Record<string, ValidateError[]>) {
super('Async Validation Error')
this.errors = errors
this.fields = fields
}
}
type ValidateFunc = (
data: RuleValuePackage,
doIt: (errors: ValidateError[]) => void
) => void
export function asyncMap(
objArr: Record<string, RuleValuePackage[]>,
option: ValidateOption,
func: ValidateFunc,
callback: (errors: ValidateError[]) => void,
source: Values
): Promise<Values> {
if (option.first) {
const pending = new Promise<Values>((resolve, reject) => {
const next = (errors: ValidateError[]) => {
callback(errors)
return errors.length
? reject(new AsyncValidationError(errors, convertFieldsError(errors)))
: resolve(source)
}
const flattenArr = flattenObjArr(objArr)
asyncSerialArray(flattenArr, func, next)
})
pending.catch(e => e)
return pending
}
const firstFields =
option.firstFields === true ? Object.keys(objArr) : option.firstFields || []
const objArrKeys = Object.keys(objArr)
const objArrLength = objArrKeys.length
let total = 0
const results: ValidateError[] = []
const pending = new Promise<Values>((resolve, reject) => {
const next = (errors: ValidateError[]) => {
results.push.apply(results, errors)
total++
if (total === objArrLength) {
callback(results)
return results.length
? reject(new AsyncValidationError(results, convertFieldsError(results)))
: resolve(source)
}
}
if (!objArrKeys.length) {
callback(results)
resolve(source)
}
objArrKeys.forEach(key => {
const arr = objArr[key]
if (firstFields.indexOf(key) !== -1) {
asyncSerialArray(arr, func, next)
} else {
asyncParallelArray(arr, func, next)
}
})
})
pending.catch(e => e)
return pending
}
function isErrorObj(
obj: ValidateError | string | (() => string)
): obj is ValidateError {
return !!(obj && (obj as ValidateError).message !== undefined)
}
function getValue(value: Values, path: string[]) {
let v = value
for (let i = 0; i < path.length; i++) {
if (v == undefined) {
return v
}
v = v[path[i]]
}
return v
}
export function complementError(rule: InternalRuleItem, source: Values) {
return (oe: ValidateError | (() => string) | string): ValidateError => {
let fieldValue
if (rule.fullFields) {
fieldValue = getValue(source, rule.fullFields)
} else {
fieldValue = source[(oe as any).field || rule.fullField]
}
if (isErrorObj(oe)) {
oe.field = oe.field || rule.fullField
oe.fieldValue = fieldValue
return oe
}
return {
message: typeof oe === 'function' ? oe() : oe,
fieldValue,
field: (oe as unknown as ValidateError).field || rule.fullField,
}
}
}
export function deepMerge<T extends object>(target: T, source: Partial<T>): T {
if (source) {
for (const s in source) {
if (source.hasOwnProperty(s)) {
const value = source[s]
if (typeof value === 'object' && typeof target[s] === 'object') {
target[s] = {
...target[s],
...value,
}
} else {
target[s] = value
}
}
}
}
return target
}