feat(Form): add Standard Schema support (#2303)

Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
Fabian Hiller
2024-10-07 17:25:52 -04:00
committed by GitHub
parent aa8fa5be3a
commit 0955c07edd
5 changed files with 264 additions and 247 deletions

View File

@@ -68,6 +68,7 @@
"@nuxt/module-builder": "^0.8.4", "@nuxt/module-builder": "^0.8.4",
"@nuxt/test-utils": "^3.14.3", "@nuxt/test-utils": "^3.14.3",
"@release-it/conventional-changelog": "^8.0.2", "@release-it/conventional-changelog": "^8.0.2",
"@standard-schema/spec": "1.0.0-beta.0",
"@vue/test-utils": "^2.4.6", "@vue/test-utils": "^2.4.6",
"eslint": "^9.11.1", "eslint": "^9.11.1",
"happy-dom": "^15.7.4", "happy-dom": "^15.7.4",

484
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@ export interface FormSlots {
import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId, readonly } from 'vue' import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId, readonly } from 'vue'
import { useEventBus } from '@vueuse/core' import { useEventBus } from '@vueuse/core'
import { formOptionsInjectionKey, formInputsInjectionKey, formBusInjectionKey, formLoadingInjectionKey } from '../composables/useFormField' import { formOptionsInjectionKey, formInputsInjectionKey, formBusInjectionKey, formLoadingInjectionKey } from '../composables/useFormField'
import { getYupErrors, isYupSchema, getValibotError, isValibotSchema, getZodErrors, isZodSchema, getJoiErrors, isJoiSchema } from '../utils/form' import { getYupErrors, isYupSchema, getValibotErrors, isValibotSchema, getZodErrors, isZodSchema, getJoiErrors, isJoiSchema, getStandardErrors, isStandardSchema } from '../utils/form'
import { FormValidationException } from '../types/form' import { FormValidationException } from '../types/form'
const props = withDefaults(defineProps<FormProps<T>>(), { const props = withDefaults(defineProps<FormProps<T>>(), {
@@ -112,7 +112,9 @@ async function getErrors(): Promise<FormErrorWithId[]> {
} else if (isJoiSchema(props.schema)) { } else if (isJoiSchema(props.schema)) {
errs = errs.concat(await getJoiErrors(props.state, props.schema)) errs = errs.concat(await getJoiErrors(props.state, props.schema))
} else if (isValibotSchema(props.schema)) { } else if (isValibotSchema(props.schema)) {
errs = errs.concat(await getValibotError(props.state, props.schema)) errs = errs.concat(await getValibotErrors(props.state, props.schema))
} else if (isStandardSchema(props.schema)) {
errs = errs.concat(await getStandardErrors(props.state, props.schema))
} else { } else {
throw new Error('Form validation failed: Unsupported form schema') throw new Error('Form validation failed: Unsupported form schema')
} }

View File

@@ -1,3 +1,4 @@
import type { StandardSchema } from '@standard-schema/spec'
import type { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import type { ZodSchema } from 'zod' import type { ZodSchema } from 'zod'
import type { Schema as JoiSchema } from 'joi' import type { Schema as JoiSchema } from 'joi'
@@ -21,6 +22,7 @@ export type FormSchema<T extends Record<string, any>> =
| ValibotSchema | ValibotSchemaAsync | ValibotSchema | ValibotSchemaAsync
| ValibotSafeParser<any, any> | ValibotSafeParserAsync<any, any> | ValibotSafeParser<any, any> | ValibotSafeParserAsync<any, any>
| JoiSchema<T> | JoiSchema<T>
| StandardSchema
export type FormInputEvents = 'input' | 'blur' | 'change' export type FormInputEvents = 'input' | 'blur' | 'change'

View File

@@ -1,3 +1,4 @@
import type { StandardSchema } from '@standard-schema/spec'
import type { ZodSchema } from 'zod' import type { ZodSchema } from 'zod'
import type { ValidationError as JoiError, Schema as JoiSchema } from 'joi' import type { ValidationError as JoiError, Schema as JoiSchema } from 'joi'
import type { ObjectSchema as YupObjectSchema, ValidationError as YupError } from 'yup' import type { ObjectSchema as YupObjectSchema, ValidationError as YupError } from 'yup'
@@ -71,7 +72,7 @@ export function isValibotSchema(schema: any): schema is ValibotSchema | ValibotS
return '_run' in schema || (typeof schema === 'function' && 'schema' in schema) return '_run' in schema || (typeof schema === 'function' && 'schema' in schema)
} }
export async function getValibotError( export async function getValibotErrors(
state: any, state: any,
schema: ValibotSchema | ValibotSchemaAsync | ValibotSafeParser<any, any> | ValibotSafeParserAsync<any, any> schema: ValibotSchema | ValibotSchemaAsync | ValibotSafeParser<any, any> | ValibotSafeParserAsync<any, any>
): Promise<FormError[]> { ): Promise<FormError[]> {
@@ -82,3 +83,18 @@ export async function getValibotError(
message: issue.message message: issue.message
})) || [] })) || []
} }
export function isStandardSchema(schema: any): schema is StandardSchema {
return '~standard' in schema
}
export async function getStandardErrors(
state: any,
schema: StandardSchema
): Promise<FormError[]> {
const result = await schema['~validate']({ value: state })
return result.issues?.map(issue => ({
name: issue.path?.map(item => typeof item === 'object' ? item.key : item).join('.') || '',
message: issue.message
})) || []
}