Schemas libraries
Regle supports the Standard Schema Spec.
This means any Standard Schema compliant RPC library can be used with Regle.
Official list of supported libraries:
- Zod
3.24+
. - Valibot
1+
. - ArkType
2+
- Any library following the Standard Schema Spec
pnpm add @regle/schemas
npm install @regle/schemas
yarn add @regle/schemas
bun add @regle/schemas
Usage
Instead of using the core useRegle
, use useRegleSchema
export from @regle/schemas
.
import { useRegleSchema } from '@regle/schemas';
import { z } from 'zod';
const { r$ } = useRegleSchema({ name: '' }, z.object({
name: z.string().min(1)
}))
import { useRegleSchema } from '@regle/schemas';
import * as v from 'valibot';
const { r$ } = useRegleSchema({ name: '' }, v.object({
name: v.pipe(v.string(), v.minLength(3))
}))
import { useRegleSchema } from '@regle/schemas';
import { type } from 'arktype';
const { r$ } = useRegleSchema({ name: '' }, type({
name: "string > 1"
}))
WARNING
Limitations from the core behaviour
Using schema libraries uses a different mechanism than the core "rules" one. Regle will parse the entire tree instead of doing it per-field. Than means that properties or methods are not available in nested values:
$validate
(only at root)$pending
(only at root)
Computed schema
You can also have a computed schema that can be based on other state values.
WARNING
When doing refinements or transform, Vue can't track what the schema depends on because you're in a function callback.
Same way as withParams
from @regle/rules
, you can use the withDeps
helper to force dependencies on any schema
import { useRegleSchema, inferSchema, withDeps } from '@regle/schemas';
import { z } from 'zod';
import { ref, computed } from 'vue';
type Form = {
firstName?: string;
lastName?: string
}
const form = ref<Form>({ firstName: '', lastName: '' })
const schema = computed(() =>
inferSchema(form, z.object({
firstName: z.string(),
/**
* Important to keep track of the depency change
* Without it, the validator wouldn't run if `firstName` changed
*/
lastName: withDeps(
z.string().refine((v) => v !== form.value.firstName, {
message: "Last name can't be equal to first name",
}),
[() => form.value.firstName]
),
}))
);
const { r$ } = useRegleSchema(form, schema);
import { useRegleSchema, inferSchema, withDeps} from '@regle/schemas';
import * as v from 'valibot';
import { ref, computed } from 'vue';
type Form = {
firstName?: string;
lastName?: string
}
const form = ref<Form>({ firstName: '', lastName: '' })
const schema = computed(() =>
inferSchema(form, v.object({
firstName: v.string(),
/**
* Important to keep track of the depency change
* Without it, the validator wouldn't run if `firstName` changed
*/
lastName: withDeps(
v.pipe(
v.string(),
v.check((v) => v !== form.value.firstName, "Last name can't be equal to first name")
),
[() => form.value.firstName]
),
}))
)
const { r$ } = useRegleSchema(form, schema);
Type safe output
Similar to the main useRegle
composable, r$.$validate
also returns a type-safe output using Zod type schema parser.
import { useRegleSchema, inferSchema } from '@regle/schemas';
import { z } from 'zod';
import { ref, computed } from 'vue';
type Form = {
firstName?: string;
lastName?: string
}
const form = ref<Form>({ firstName: '', lastName: '' })
const schema = computed(() => inferSchema(form, z.object({
firstName: z.string().optional(),
lastName: z.string().min(1).refine(v => v !== form.value.firstName, {
message: "Last name can't be equal to first name"
}),
})))
const { r$ } = useRegleSchema(form, schema);
async function submit() {
const { result, data } = await r$.$validate();
if (result) {
console.log(data);
}
}
import { useRegleSchema, inferSchema } from '@regle/schemas';
import * as v from 'valibot';
import { ref, computed } from 'vue';
type Form = {
firstName?: string;
lastName?: string
}
const form = ref<Form>({ firstName: '', lastName: '' })
const schema = computed(() => {
return inferSchema(form, v.object({
firstName: v.optional(v.string()),
lastName: v.pipe(
v.string(),
v.minLength(3),
v.check((v) => v !== form.value.firstName, "Last name can't be equal to first name")
)
}))
})
const { r$ } = useRegleSchema(form, schema);
async function submit() {
const { result, data } = await r$.$validate();
if (result) {
console.log(data);
}
}
import { useRegleSchema, inferSchema } from '@regle/schemas';
import { type } from 'arktype';
import { ref, computed } from 'vue';
type Form = {
firstName?: string;
lastName?: string
}
const form = ref<Form>({ firstName: '', lastName: '' })
const schema = computed(() => {
return inferSchema(form, type({
'firstName?': 'string',
lastName: 'string > 3',
}).narrow((data, ctx) => {
if (data.firstName !== data.lastName) {
return true;
}
return ctx.reject({
expected: 'different than firstName',
path: ['lastName'],
});
}))
})
const { r$ } = useRegleSchema(form, schema);
async function submit() {
const { result, data } = await r$.$validate();
if (result) {
console.log(data);
}
}