Skip to content

Commit

Permalink
feat: added async option in createRule
Browse files Browse the repository at this point in the history
  • Loading branch information
victorgarciaesgi committed Dec 30, 2024
1 parent 1b755df commit 2fdcc1d
Show file tree
Hide file tree
Showing 12 changed files with 197 additions and 11 deletions.
14 changes: 10 additions & 4 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export default defineConfig({
items: [
{ text: 'Getting Started', link: '/introduction/' },
{ text: 'Comparisons', link: '/introduction/comparisons' },
{ text: 'Migrate from Vuelidate', link: '/introduction/migrate-from-vuelidate' },
],
collapsed: false,
},
Expand Down Expand Up @@ -179,8 +180,12 @@ export default defineConfig({
return head;
},
head: [
['link', { rel: 'icon', href: '/favicon.svg' }],
['link', { rel: 'icon', href: '/favicon.ico', sizes: '48x48' }],
['link', { rel: 'icon', href: '/favicon.svg', sizes: 'any', type: 'image/svg+xml' }],
['link', { rel: 'mask-icon', href: '/logo-reglejs-favicon.svg', color: '#ffffff' }],
['link', { rel: 'apple-touch-icon', href: '/apple-touch-icon.png', sizes: '180x180' }],
['meta', { name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1' }],
['meta', { name: 'author', content: 'Victor Garcia' }],
['meta', { name: 'theme-color', content: '#00bb7f' }],
[
'meta',
Expand All @@ -193,7 +198,7 @@ export default defineConfig({
['meta', { property: 'og:url', content: 'https://regle.vercel.app' }],
['meta', { property: 'og:type', content: 'website' }],
['meta', { property: 'og:title', content: 'Regle' }],
['meta', { property: 'og:site_name', content: 'Regle - Vue form validation' }],
['meta', { property: 'og:site_name', content: 'Regle' }],
[
'meta',
{
Expand All @@ -214,17 +219,18 @@ export default defineConfig({
'meta',
{
property: 'og:image',
content: 'https://regle.vercel.app/regle-github-banner.png',
content: 'https://regle.vercel.app/banner-og.png',
},
],

['meta', { name: 'twitter:site', content: '@regle' }],
['meta', { name: 'twitter:domain', content: 'regle.vercel.app' }],
[
'meta',
{ name: 'twitter:description', content: 'Regle is a TypeScript-first form validation library made for Vue 3.' },
],
['meta', { name: 'twitter:url', content: 'https://regle.vercel.app' }],
['meta', { name: 'twitter:card', content: 'summary' }],
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
['meta', { name: 'google-site-verification', content: 'mYJKnciAjHTdI7nsB2xame8QO61IeKoXCZeGyWGjs-4' }],
],
markdown: {
Expand Down
4 changes: 4 additions & 0 deletions docs/.vitepress/theme/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ html.dark {
background-color: var(--vp-c-default-soft);
}

.vp-doc h3 > code {
color: var(--vp-badge-warning-text);
}

.item .VPFeature {
position: relative;
padding: 2px;
Expand Down
21 changes: 20 additions & 1 deletion docs/src/core-concepts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ It accepts the following inputs:
<script setup lang='ts'>
import { useRegle } from '@regle/core';
const { r$ } = useRegle(/* state */, /* rules */, /* modifiers */);
const { r$ } = useRegle(/* state */ , /* rules */ , /* modifiers */);
</script>
```

Expand All @@ -36,6 +36,25 @@ The state can be:

If you pass a reactive state, you have the flexibility to bind your model either to the original state or to the state proxy returned by useRegle.

```ts
const {r$} = useRegle({name: ''}, /* rules */)
```

```ts
const state = ref({name: ''});
const {r$} = useRegle(state, /* rules */)
```

```ts
const state = reactive({name: ''});
const {r$} = useRegle(state, /* rules */)
```

```ts
const state = {name: ref('')}
const {r$} = useRegle(state, /* rules */)
```

## Rules

The second parameter of `useRegle` is the rules declaration, you can declare a tree matching your input state.
Expand Down
6 changes: 6 additions & 0 deletions docs/src/core-concepts/rules/reusable-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ _**Type**_: `boolean | (metadata) => boolean`
Defines the `$active` state of the rule, indicating whether the rule is currently being validated. This can be computed dynamically.
For more details, see [Parameters and active mode](#parameters-and-active-mode).

### `async`
_**Type**_: `boolean`

*optional*

If your validator function is not written with `async await` syntax, you can enforce the rule to be async with this parameter.

### `tooltip`
_**Type**_: `string | string[] | (metadata) => (string | string[])`
Expand Down
142 changes: 142 additions & 0 deletions docs/src/introduction/migrate-from-vuelidate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
---
title: Migrate from Vuelidate
---

# Migrate from Vuelidate

Migrating from Vuelidate is really simple. Regle API is similar to Vuelidate's one on purpose, so the mental model stays the same.

Regle type safety will ensure you make no mistakes while making the migration.

## Imports

```ts
import { useVuelidate } from '@vuelidate/core'; // [!code --]
import { required } from '@vuelidate/validators'; // [!code --]
import { useRegle } from '@regle/core'; // [!code ++]
import { required } from '@regle/rules'; // [!code ++]
```

## Helpers

```ts
import { helpers } from '@vuelidate/validators'; // [!code --]
import { withMessage, withParams, withAsync, isEmpty, ... } from '@regle/rules'; // [!code ++]
```

Helpers which have been renamed:

- `req` -> `isFilled`
- `len` -> `getSize`
- `regex` -> `matchRegex`
- `forEach` -> Deleted, you can use `$each` directly.
- `unwrap` -> use `toValue` from [Vue](https://vuejs.org/api/reactivity-utilities#tovalue)
- Parameters are automatically unwrapped when using `createRule`


### `withMessage`

Order of parameters are swapped

```ts
const rule = helpers.withMessage('This field cannot be empty', required) // [!code --]
const rule = withMessage(required, 'This field cannot be empty') // [!code ++]
```

### `withParams`

You can create rules with parameters with [createRule](/core-concepts/rules/reusable-rules#createrule) helper

```ts
const contains = (param) => // [!code --]
helpers.withParams( // [!code --]
{ type: 'contains', value: param }, // [!code --]
(value) => !helpers.req(value) || value.includes(param) // [!code --]
) // [!code --]

const contains = createRule({ // [!code ++]
validator(value: Maybe<string>, param: Maybe<string>) { // [!code ++]
return isEmpty(value) && value.includes(param); // [!code ++]
}, // [!code ++]
message: ({$params: [param]}) => `Value must contain ${param}`; // [!code ++]
}) // [!code ++]
```

## Properties

Some properties have been renamed

- `$model` -> `$value`
- `$response` -> `$metadata` [Using metadata from rules](/advanced-usage/rule-metadata#using-metadata-from-rules)
- `$externalResults` -> `$externalErrors`

### Accessing nested fields

Nested fields are not mixed up with other properties now.

```ts
v$.nested.child // [!code --]
r$.$fields.nested.$fields.child // [!code ++]
```

## Collections

[Working with collections](/advanced-usage/collections)

```ts
const v$ = useVuelidate({ // [!code --]
collection: { // [!code --]
$each: helpers.forEach({ // [!code --]
name: { // [!code --]
required // [!code --]
} // [!code --]
}) // [!code --]
} // [!code --]
}, {collection: [{name: ''}]}) // [!code --]
const { r$ } = useRegle({collection: [{name: ''}]}, { // [!code ++]
collection: {// [!code ++]
$each: {// [!code ++]
name: {// [!code ++]
required// [!code ++]
}// [!code ++]
}// [!code ++]
}// [!code ++]
})// [!code ++]
```

## Methods

[Type safe output](/core-concepts/type-safe-output)


```ts
const result = await v$.$validate(); // [!code --]
const {result, data} = await r$.$validate(); // [!code ++]
```

## Validation groups

```ts
const rules = { // [!code --]
number: { isEven },// [!code --]
nested: {// [!code --]
word: { required: v => !!v }// [!code --]
},// [!code --]
$validationGroups: {// [!code --]
firstGroup: ['number', 'nested.word']// [!code --]
}// [!code --]
}// [!code --]
const v$ = useVuelidate(rules, ...);// [!code --]

const { r$ } = useRegle(..., { // [!code ++]
number: {isEven},// [!code ++]
nested: {// [!code ++]
word: { required: v => !!v }// [!code ++]
}// [!code ++]
}, {// [!code ++]
validationGroups: (fields) => ({// [!code ++]
firstGroup: [fields.number, fields.nested.$fields.word]// [!code ++]
})// [!code ++]
})// [!code ++]
r$.$groups.firstGroup// [!code ++]
```
3 changes: 2 additions & 1 deletion docs/src/parts/QuickUsage.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
``` vue twoslash [App.vue]
<template>
<input v-model='r$.$fields.email.$value'
<input
v-model='r$.$fields.email.$value'
:class="{ error: r$.$fields.email.$error }"
placeholder='Type your email'
/>
Expand Down
Binary file added docs/src/public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/src/public/banner-og.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/src/public/regle-github-banner.png
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/core/src/core/createRule/createRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function createRule<
let fakeParams: any[] = [];
const staticProcessors = defineRuleProcessors(definition as any, ...fakeParams);

const isAsync = definition.validator.constructor.name === 'AsyncFunction';
const isAsync = definition.async ?? definition.validator.constructor.name === 'AsyncFunction';
// For validators needing a params like maxLength or requiredIf
if (getFunctionParametersLength(definition.validator) > 1) {
// For validators with param, return a function providing params for all the rule processors
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/types/rules/rule.init.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface RegleRuleInit<
active?: RegleInitPropertyGetter<TValue, boolean, TParams, TMetadata>;
tooltip?: RegleInitPropertyGetter<TValue, string | string[], TParams, TMetadata>;
type?: string;
async?: TAsync;
}

/**
Expand Down
15 changes: 11 additions & 4 deletions tsup.common.build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,23 @@ import type { Options } from 'tsup';

export function outExtension(isMin = false): Options['outExtension'] | undefined {
return ({ format }) => {
const prefix = format === 'cjs' ? 'c' : 'm';
const min = isMin ? 'min.' : '';
let output;
const min = isMin ? '.min' : '';
if (format === 'cjs') {
output = `${min}.cjs`;
} else if (format === 'esm') {
output = `${min}.mjs`;
} else {
output = `.browser${min}.js`;
}
return {
js: `.${min}${prefix}js`,
js: output,
};
};
}

export const defaultOptions: Options = {
format: ['esm', 'cjs'],
format: ['esm', 'cjs', 'iife'],
dts: {
resolve: true,
},
Expand Down

0 comments on commit 2fdcc1d

Please sign in to comment.