{"version":3,"file":"useValidation.mjs","sources":["../../../../src/composables/useValidation.ts"],"sourcesContent":["import {\n  watch,\n  computed,\n  type PropType,\n  type ExtractPropTypes,\n  nextTick,\n  type WritableComputedRef,\n  ref,\n  toRef,\n  type Ref,\n  watchEffect,\n} from 'vue'\n\nimport { useSyncProp } from './useSyncProp'\nimport { useFormChild } from './useForm'\nimport { type ExtractReadonlyArrayKeys } from '../utils/types/readonly-array-keys'\nimport { watchSetter } from './../utils/watch-setter'\nimport { isFunction } from '../utils/is-function'\nimport { isString } from '../utils/is-string'\n\nexport type ValidationRule<V = any> = ((v: V) => any | string) | Promise<((v: V) => any | string)>\n\ntype UseValidationOptions = {\n  reset: () => void\n  focus: () => void\n  value: WritableComputedRef<any> | Ref<any>\n}\n\nconst normalizeValidationRules = (rules: string | ValidationRule[] = [], callArguments: unknown = null) => {\n  if (isString(rules)) { rules = [rules] as any }\n\n  return (rules as ValidationRule[])\n    .map((rule) => isFunction(rule) ? rule(callArguments) : rule)\n}\n\nexport const useValidationProps = {\n  name: { type: String, default: undefined },\n  rules: { type: Array as PropType<ValidationRule<any>[]>, default: () => [] as any },\n  dirty: { type: Boolean, default: false },\n  error: { type: Boolean, default: undefined },\n  errorMessages: { type: [Array, String] as PropType<string[] | string>, default: undefined },\n  errorCount: { type: [String, Number], default: 1 },\n  success: { type: Boolean, default: false },\n  messages: { type: [Array, String] as PropType<string[] | string>, default: () => [] },\n  immediateValidation: { type: Boolean, default: false },\n  modelValue: {},\n}\n\nexport type ValidationProps<V, RulesArgument extends V = V> = {\n  rules: { type: PropType<ValidationRule<RulesArgument>[]>, default: () => any, required: false }\n  modelValue: { type: PropType<V>, default: V }\n} & Omit<typeof useValidationProps, 'modelValue' | 'rules'>\n\nexport const useValidationEmits = ['update:error', 'update:errorMessages', 'update:dirty'] as const\n\nconst isPromise = (value: any): value is Promise<any> => {\n  return typeof value === 'object' && typeof value.then === 'function'\n}\n\nconst useDirtyValue = (\n  value: Ref<any>,\n  props: ExtractPropTypes<typeof useValidationProps>,\n  emit: (event: ExtractReadonlyArrayKeys<typeof useValidationEmits>, ...args: any[]) => void,\n) => {\n  const isDirty = ref(props.dirty || false)\n\n  watchSetter(value, () => {\n    isDirty.value = true\n    emit('update:dirty', true)\n  })\n\n  watch(value, (newValue, oldValue) => {\n    // Watch only if object keys changed, not the object itself\n    if (newValue === oldValue) {\n      isDirty.value = true\n    }\n  }, { deep: true })\n\n  watch(() => props.dirty, (newValue) => {\n    if (isDirty.value === newValue) { return }\n    isDirty.value = newValue\n  })\n\n  return { isDirty }\n}\n\nconst useTouched = () => {\n  const isTouched = ref(false)\n\n  const onBlur = () => {\n    isTouched.value = true\n  }\n\n  return { isTouched, onBlur }\n}\n\nconst useOncePerTick = <T extends (...args: any[]) => any>(fn: T) => {\n  let canBeCalled = true\n\n  return (...args: Parameters<T>) => {\n    if (!canBeCalled) { return }\n    canBeCalled = false\n    const result = fn(...args)\n    nextTick(() => { canBeCalled = true })\n    return result\n  }\n}\n\nexport const useValidation = <V, P extends ExtractPropTypes<typeof useValidationProps>>(\n  props: P,\n  emit: (event: any, ...args: any[]) => void,\n  options: UseValidationOptions,\n) => {\n  const { reset, focus } = options\n  const [isError] = useSyncProp('error', props, emit, false)\n  const [errorMessages] = useSyncProp('errorMessages', props, emit, [] as string[])\n  const isLoading = ref(false)\n  const { isTouched, onBlur } = useTouched()\n\n  const validationAriaAttributes = computed(() => ({\n    'aria-invalid': isError.value,\n    'aria-errormessage': typeof errorMessages.value === 'string'\n      ? errorMessages.value\n      : errorMessages.value.join(', '),\n  }))\n\n  const resetValidation = () => {\n    errorMessages.value = []\n    isError.value = false\n    isDirty.value = false\n    isTouched.value = false\n    isLoading.value = false\n  }\n\n  const processResults = (results: any[]) => {\n    let error = false\n    let eMessages: string[] = []\n\n    results.forEach((result: any) => {\n      if (isString(result)) {\n        eMessages = [...eMessages, result]\n        error = true\n      } else if (result === false) {\n        error = true\n      } // Ignore if result is Promise\n    })\n\n    errorMessages.value = eMessages\n    isError.value = error\n\n    return !error\n  }\n\n  const validateAsync = async (): Promise<boolean> => {\n    if (!props.rules || !props.rules.length) {\n      return true\n    }\n\n    const results = normalizeValidationRules(props.rules.flat(), options.value.value)\n    const asyncPromiseResults = results.filter((result) => isPromise(result))\n    const syncRules = results.filter((result) => !isPromise(result))\n\n    if (!asyncPromiseResults.length) { return processResults(syncRules) }\n\n    isLoading.value = true\n    return Promise.all(asyncPromiseResults)\n      .then((asyncResults) => {\n        return processResults([...syncRules, ...asyncResults])\n      })\n      .finally(() => {\n        isLoading.value = false\n      })\n  }\n\n  const validate = useOncePerTick((): boolean => {\n    if (!props.rules || !props.rules.length) {\n      return true\n    }\n\n    const rules = props.rules.flat()\n\n    const results = normalizeValidationRules(rules, options.value.value)\n    const asyncPromiseResults = results.filter((result) => isPromise(result))\n    const syncRules = results.filter((result) => !isPromise(result))\n    const isSyncedError = syncRules.some((result: string | boolean) => isString(result) ? result : result === false)\n\n    // Prevent async rules from being executed if sync rules are invalid\n    if (asyncPromiseResults.length && !isSyncedError) {\n      isLoading.value = true\n      Promise.all(asyncPromiseResults).then((asyncResults) => {\n        processResults([...syncRules, ...asyncResults]) // Process sync rules and async rules at the same time\n        isLoading.value = false\n      })\n      return isSyncedError\n    }\n\n    return processResults(syncRules)\n  })\n\n  watchEffect(() => validate())\n\n  const { isDirty } = useDirtyValue(options.value, props, emit)\n\n  const {\n    // Renamed to forceHideError because it's not clear what it does\n    forceHideErrors,\n    forceHideLoading,\n    forceHideErrorMessages,\n    forceDirty,\n    immediate: isFormImmediate,\n  } = useFormChild({\n    isTouched,\n    isDirty,\n    isValid: computed(() => !isError.value),\n    isLoading: isLoading,\n    errorMessages: errorMessages,\n    validate,\n    validateAsync,\n    resetValidation,\n    focus,\n    reset: () => {\n      reset()\n      resetValidation()\n      validate()\n    },\n    value: computed(() => options.value || props.modelValue),\n    name: toRef(props, 'name'),\n  })\n\n  const immediateValidation = computed(() => props.immediateValidation || isFormImmediate.value)\n\n  let canValidate = true\n  const withoutValidation = (cb: () => any): void => {\n    canValidate = false\n    cb()\n    // NextTick because we update props in the same tick, but they are updated in the next one\n    nextTick(() => { canValidate = true })\n  }\n  watch(options.value, () => {\n    if (!canValidate) { return }\n\n    return validate()\n  }, { immediate: immediateValidation.value })\n\n  return {\n    isDirty,\n    isValid: computed(() => !isError.value),\n    isError: isError,\n    isTouched,\n    isLoading: computed({\n      get: () => {\n        if (forceHideErrors.value) { return false }\n        if (immediateValidation.value) {\n          return isLoading.value\n        }\n\n        if (isTouched.value || isDirty.value || forceDirty.value) {\n          return isLoading.value\n        }\n\n        return false\n      },\n      set (value) {\n        isLoading.value = value\n      },\n    }),\n    computedError: computed(() => {\n      if (forceHideErrors.value) { return false }\n\n      if (immediateValidation.value) {\n        return isError.value\n      }\n\n      if (isTouched.value || isDirty.value || forceDirty.value) {\n        return isError.value\n      }\n\n      return false\n    }),\n    computedErrorMessages: computed(() => forceHideErrorMessages.value ? [] : errorMessages.value),\n    listeners: { onBlur },\n    validate,\n    resetValidation,\n    withoutValidation,\n    validationAriaAttributes,\n  }\n}\n"],"names":[],"mappings":"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"}