From dbc3e5260f7f8d969b6ae26d80b2e2bccbb1c419 Mon Sep 17 00:00:00 2001 From: Gerben Mulder Date: Wed, 11 Dec 2024 16:22:11 +0100 Subject: [PATCH] feat: add standard schema support to UI v2 --- package.json | 1 + pnpm-lock.yaml | 8 ++++++ src/runtime/components/forms/Form.vue | 35 ++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index faef2392b7..8c807a41f0 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "@nuxt/module-builder": "^0.8.4", "@nuxt/test-utils": "^3.14.4", "@release-it/conventional-changelog": "^9.0.3", + "@standard-schema/spec": "1.0.0-beta.4", "@vue/test-utils": "^2.4.6", "eslint": "^9.16.0", "happy-dom": "^14.12.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8bd44effd1..98fe8093f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -94,6 +94,9 @@ importers: '@release-it/conventional-changelog': specifier: ^9.0.3 version: 9.0.3(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.0.0)(release-it@17.10.0(typescript@5.6.3)) + '@standard-schema/spec': + specifier: 1.0.0-beta.4 + version: 1.0.0-beta.4 '@vue/test-utils': specifier: ^2.4.6 version: 2.4.6 @@ -1706,6 +1709,9 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + '@standard-schema/spec@1.0.0-beta.4': + resolution: {integrity: sha512-d3IxtzLo7P1oZ8s8YNvxzBUXRXojSut8pbPrTYtzsc5sn4+53jVqbk66pQerSZbZSJZQux6LkclB/+8IDordHg==} + '@stylistic/eslint-plugin@2.11.0': resolution: {integrity: sha512-PNRHbydNG5EH8NK4c+izdJlxajIR6GxcUhzsYNRsn6Myep4dsZt0qFCz3rCPnkvgO5FYibDcMqgNHUT+zvjYZw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8518,6 +8524,8 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} + '@standard-schema/spec@1.0.0-beta.4': {} + '@stylistic/eslint-plugin@2.11.0(eslint@9.16.0(jiti@2.4.1))(typescript@5.6.3)': dependencies: '@typescript-eslint/utils': 8.16.0(eslint@9.16.0(jiti@2.4.1))(typescript@5.6.3) diff --git a/src/runtime/components/forms/Form.vue b/src/runtime/components/forms/Form.vue index 2eb4c9642d..3f259a0e5f 100644 --- a/src/runtime/components/forms/Form.vue +++ b/src/runtime/components/forms/Form.vue @@ -13,6 +13,7 @@ import type { ObjectSchema as YupObjectSchema, ValidationError as YupError } fro import type { BaseSchema as ValibotSchema30, BaseSchemaAsync as ValibotSchemaAsync30 } from 'valibot30' import type { GenericSchema as ValibotSchema31, GenericSchemaAsync as ValibotSchemaAsync31, SafeParser as ValibotSafeParser31, SafeParserAsync as ValibotSafeParserAsync31 } from 'valibot31' import type { GenericSchema as ValibotSchema, GenericSchemaAsync as ValibotSchemaAsync, SafeParser as ValibotSafeParser, SafeParserAsync as ValibotSafeParserAsync } from 'valibot' +import type { StandardSchemaV1 } from '@standard-schema/spec' import type { Struct } from 'superstruct' import type { FormError, FormEvent, FormEventType, FormSubmitEvent, FormErrorEvent, Form, ValidateReturnSchema } from '../../types/form' import { useId } from '#imports' @@ -33,6 +34,7 @@ type Schema = PropType | PropType | ValibotSafeParserAsync31> | PropType | PropType | ValibotSafeParserAsync> | PropType> + | PropType export default defineComponent({ props: { @@ -220,6 +222,35 @@ function isZodSchema(schema: any): schema is ZodSchema { return schema.parse !== undefined } +export function isStandardSchema(schema: any): schema is StandardSchemaV1 { + return '~standard' in schema +} + +export async function validateStandarSchema( + state: any, + schema: StandardSchemaV1 +): Promise> { + const result = await schema['~standard'].validate(state) + + if (!result.issues || result.issues.length === 0) { + const output = ('value' in result ? result.value : null) + return { + errors: null, + result: output + } + } + + const errors = result.issues.map(issue => ({ + path: issue.path?.map(item => typeof item === 'object' ? item.key : item).join('.') || '', + message: issue.message + })) + + return { + errors, + result: null + } +} + async function validateValibotSchema( state: any, schema: ValibotSchema30 | ValibotSchemaAsync30 | ValibotSchema31 | ValibotSchemaAsync31 | ValibotSafeParser31 | ValibotSafeParserAsync31 | ValibotSchema | ValibotSchemaAsync | ValibotSafeParser | ValibotSafeParserAsync @@ -346,7 +377,9 @@ async function validateYupSchema( } function parseSchema(state: any, schema: Schema): Promise> { - if (isZodSchema(schema)) { + if (isStandardSchema(schema)) { + return validateStandarSchema(state, schema) + } else if (isZodSchema(schema)) { return validateZodSchema(state, schema) } else if (isJoiSchema(schema)) { return validateJoiSchema(state, schema)