Skip to content

Commit

Permalink
Add valibot resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
erikshestopal committed Aug 1, 2023
1 parent 1a64cd1 commit 5b16dd4
Show file tree
Hide file tree
Showing 10 changed files with 430 additions and 13 deletions.
68 changes: 56 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,28 @@

### Supported resolvers

- [Yup](#yup)
- [Zod](#zod)
- [Superstruct](#superstruct)
- [Joi](#joi)
- [Class Validator](#class-validator)
- [io-ts](#io-ts)
- [Nope](#nope)
- [computed-types](#computed-types)
- [typanion](#typanion)
- [Ajv](#ajv)
- [TypeBox](#typebox)
- [ArkType](#arktype)
- [Install](#install)
- [Links](#links)
- [Supported resolvers](#supported-resolvers)
- [API](#api)
- [Quickstart](#quickstart)
- [Yup](#yup)
- [Zod](#zod)
- [Superstruct](#superstruct)
- [Joi](#joi)
- [Vest](#vest)
- [Class Validator](#class-validator)
- [io-ts](#io-ts)
- [Nope](#nope)
- [computed-types](#computed-types)
- [typanion](#typanion)
- [Ajv](#ajv)
- [TypeBox](#typebox)
- [ArkType](#arktype)
- [Valibot](#valibot)
- [Backers](#backers)
- [Sponsors](#sponsors)
- [Contributors](#contributors)

## API

Expand Down Expand Up @@ -532,6 +542,40 @@ const App = () => {
};
```

### [Valibot](https://github.com/fabian-hiller/valibot)

The modular and type safe schema library for validating structural data

[![npm](https://img.shields.io/bundlephobia/minzip/valibot?style=for-the-badge)](https://bundlephobia.com/result?p=valibot)

```typescript jsx
import { useForm } from 'react-hook-form';
import { valibotResolver } from '@hookform/resolvers/valibot';
import { type } from 'arktype';

const schema = object({
username: string([
minLength(3, 'Needs to be at least 3 characters'),
endsWith('cool', 'Needs to end with `cool`'),
]),
password: string(),
});

const App = () => {
const { register, handleSubmit } = useForm({
resolver: valibotResolver(schema),
});

return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
<input type="password" {...register('password')} />
<input type="submit" />
</form>
);
};
```

## Backers

Thanks goes to all our backers! [[Become a backer](https://opencollective.com/react-hook-form#backer)].
Expand Down
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@
"import": "./arktype/dist/arktype.mjs",
"require": "./arktype/dist/arktype.js"
},
"./valibot": {
"types": "./valibot/dist/index.d.ts",
"umd": "./valibot/dist/valibot.umd.js",
"import": "./valibot/dist/valibot.mjs",
"require": "./valibot/dist/valibot.js"
},
"./package.json": "./package.json",
"./*": "./*"
},
Expand Down Expand Up @@ -136,7 +142,10 @@
"typebox/dist",
"arktype/package.json",
"arktype/src",
"arktype/dist"
"arktype/dist",
"valibot/package.json",
"valibot/src",
"valibot/dist"
],
"publishConfig": {
"access": "public"
Expand All @@ -158,6 +167,7 @@
"build:ajv": "microbundle --cwd ajv --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
"build:typebox": "microbundle --cwd typebox --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm,@sinclair/typebox/value=value",
"build:arktype": "microbundle --cwd arktype --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
"build:valibot": "microbundle --cwd valibot --globals @hookform/resolvers=hookformResolvers,react-hook-form=ReactHookForm",
"postbuild": "node ./config/node-13-exports.js",
"lint": "eslint . --ext .ts,.js --ignore-path .gitignore",
"lint:types": "tsc",
Expand Down
18 changes: 18 additions & 0 deletions valibot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@hookform/resolvers/valibot",
"amdName": "hookformResolversValibot",
"version": "1.0.0",
"private": true,
"description": "React Hook Form validation resolver: valibot",
"main": "dist/valibot.js",
"module": "dist/valibot.module.js",
"umd:main": "dist/valibot.umd.js",
"source": "src/index.ts",
"types": "dist/index.d.ts",
"license": "MIT",
"peerDependencies": {
"react-hook-form": "^7.0.0",
"@hookform/resolvers": "^2.0.0",
"valibot": ">=0.8"
}
}
62 changes: 62 additions & 0 deletions valibot/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 80 additions & 0 deletions valibot/src/__tests__/__fixtures__/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Field, InternalFieldName } from 'react-hook-form';
import {
object,
string,
minLength,
maxLength,
regex,
number,
minValue,
maxValue,
email,
array,
boolean,
} from 'valibot';

export const schema = object({
username: string([minLength(2), maxLength(30), regex(/^\w+$/)]),
password: string('New Password is required', [
regex(new RegExp('.*[A-Z].*'), 'One uppercase character'),
regex(new RegExp('.*[a-z].*'), 'One lowercase character'),
regex(new RegExp('.*\\d.*'), 'One number'),
regex(
new RegExp('.*[`~<>?,./!@#$%^&*()\\-_+="\'|{}\\[\\];:\\\\].*'),
'One special character',
),
minLength(8, 'Must be at least 8 characters in length'),
]),
repeatPassword: string(),
accessToken: string(),
birthYear: number([minValue(1900), maxValue(2013)]),
email: string([email()]),
tags: array(string()),
enabled: boolean(),
like: object({
id: number(),
name: string([minLength(4)]),
}),
});

export const validData = {
username: 'Doe',
password: 'Password123_',
repeatPassword: 'Password123_',
birthYear: 2000,
email: 'john@doe.com',
tags: ['tag1', 'tag2'],
enabled: true,
accessToken: 'accessToken',
like: {
id: 1,
name: 'name',
},
};

export const invalidData = {
password: '___',
email: '',
birthYear: 'birthYear',
like: { id: 'z' },
tags: [1, 2, 3],
};

export const fields: Record<InternalFieldName, Field['_f']> = {
username: {
ref: { name: 'username' },
name: 'username',
},
password: {
ref: { name: 'password' },
name: 'password',
},
email: {
ref: { name: 'email' },
name: 'email',
},
birthday: {
ref: { name: 'birthday' },
name: 'birthday',
},
};
79 changes: 79 additions & 0 deletions valibot/src/__tests__/__snapshots__/valibot.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`valibotResolver > should return a single error from valibotResolver when validation fails 1`] = `
{
"errors": {
"accessToken": {
"message": "Invalid type",
"ref": undefined,
"type": "string",
},
"birthYear": {
"message": "Invalid type",
"ref": undefined,
"type": "number",
},
"email": {
"message": "Invalid email",
"ref": {
"name": "email",
},
"type": "email",
},
"enabled": {
"message": "Invalid type",
"ref": undefined,
"type": "boolean",
},
"like": {
"id": {
"message": "Invalid type",
"ref": undefined,
"type": "number",
},
"name": {
"message": "Invalid type",
"ref": undefined,
"type": "string",
},
},
"password": {
"message": "One uppercase character",
"ref": {
"name": "password",
},
"type": "regex",
},
"repeatPassword": {
"message": "Invalid type",
"ref": undefined,
"type": "string",
},
"tags": [
{
"message": "Invalid type",
"ref": undefined,
"type": "string",
},
{
"message": "Invalid type",
"ref": undefined,
"type": "string",
},
{
"message": "Invalid type",
"ref": undefined,
"type": "string",
},
],
"username": {
"message": "Invalid type",
"ref": {
"name": "username",
},
"type": "string",
},
},
"values": {},
}
`;
24 changes: 24 additions & 0 deletions valibot/src/__tests__/valibot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* eslint-disable no-console, @typescript-eslint/ban-ts-comment */
import { valibotResolver } from '..';
import { schema, validData, fields, invalidData } from './__fixtures__/data';

const shouldUseNativeValidation = false;
describe('valibotResolver', () => {
it('should return values from valibotResolver when validation pass', async () => {
const result = await valibotResolver(schema)(validData, undefined, {
fields,
shouldUseNativeValidation,
});

expect(result).toEqual({ errors: {}, values: validData });
});

it('should return a single error from valibotResolver when validation fails', async () => {
const result = await valibotResolver(schema)(invalidData, undefined, {
fields,
shouldUseNativeValidation,
});

expect(result).toMatchSnapshot();
});
});
2 changes: 2 additions & 0 deletions valibot/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './valibot';
export * from './types';
Loading

0 comments on commit 5b16dd4

Please sign in to comment.