@regle/mcp-server 1.18.2 → 1.19.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,7 +20,7 @@ var docs_data_default = {
20
20
  "title": "Global configuration",
21
21
  "category": "advanced-usage",
22
22
  "path": "advanced-usage/global-config.md",
23
- "content": "# Global configuration\n\nIf your app includes multiple forms, it can be helpful to define a global configuration that centralizes your custom validators, error messages, and modifiers. This eliminates the need to declare these settings repeatedly for every `useRegle` call, improving both code consistency and developer experience with features like autocompletion and type checking.\n\n## Replace built-in rules messages\n\nEach `@regle/rules` rule provides a default error message. You may may not want to call `withMessage` every time you need to use one with a custom error message.\n\n`defineRegleConfig` allows you to redefine the default messages of built-in rules.\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { withMessage, minLength, required } from '@regle/rules';\n\nconst { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n required: withMessage(required, 'You need to provide a value'),\n minLength: withMessage(minLength, ({ $value, $params: [max] }) => {\n return `Minimum length is ${max}. Current length: ${$value?.length}`;\n })\n })\n})\n\nconst { r$ } = useCustomRegle({ name: '' }, {\n name: {\n required,\n minLength: minLength(6)\n }\n})\n```\n\nResult: \n\n:::tip\nIf you use Nuxt, check out the [Nuxt module](/integrations/nuxt) for a even better DX. \nIt provides a way to add your custom global config to your auto-imports.\n:::\n\n### i18n\n\nYou can also use any i18n library directly inside the config.\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { withMessage, minLength, required } from '@regle/rules';\nimport { useI18n } from 'vue-i18n';\n\nconst { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => {\n const { t } = useI18n()\n\n return {\n required: withMessage(required, t('general.required')),\n minLength: withMessage(minLength, ({ $value, $params: [max] }) => {\n return t('general.minLength', {max});\n })\n }\n }\n})\n```\n\n## Declare new rules\n\nWhile `useRegle` allows you to use any rule key, adding custom rules to the global configuration provides autocompletion and type checking. This improves maintainability and consistency across your application.\n\n```ts twoslash\nconst someAsyncCall = async () => await Promise.resolve(true);\n// ---cut---\n\nimport { defineRegleConfig, createRule, Maybe } from '@regle/core';\nimport { withMessage, isFilled } from '@regle/rules';\n\nconst asyncEmail = createRule({\n async validator(value: Maybe<string>) {\n if (!isFilled(value)) {\n return true;\n }\n\n const result = await someAsyncCall();\n return result;\n },\n message: 'Email already exists',\n});\n\nconst { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n asyncEmail\n })\n})\n\nconst { r$ } = useCustomRegle({ name: '' }, {\n name: {\n asy\n\n }\n})\n```\n\n## Declare modifiers\n\nYou can include global modifiers in your configuration to automatically apply them wherever you use the `useRegle` composable. This avoids repetitive declarations and keeps your code clean.\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { withMessage, minLength, required } from '@regle/rules';\n\nexport const { useRegle: useCustomRegle } = defineRegleConfig({\n modifiers: {\n autoDirty: false,\n silent: true,\n lazy: true,\n rewardEarly: true\n }\n})\n```\n\n## Export scoped `inferRules` helper\n\n`defineRegleConfig` also returns a scoped `inferRules` helper, similar to the one exported from `@regle/core`, but that will autocomplete and check your custom rules.\n\nFor information about `inferRules`, check [Typing rules docs](/typescript/typing-rules)\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { withMessage, minLength, required } from '@regle/rules';\n\nexport const { useRegle, inferRules } = defineRegleConfig({/* */})\n```\n\n## Extend global config\n\nIt's also possible to add additional config to an already created custom `useRegle`.\n\nWith `extendRegleConfig`, you can recreate a custom one with a existing composable as an input.\n\n```ts twoslash\n\nimport { defineRegleConfig, extendRegleConfig, createRule } from '@regle/core';\nimport { withMessage, required } from '@regle/rules';\n\nconst { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n customRule: withMessage(required, 'Custom rule'),\n })\n})\n\nconst {useRegle: useExtendedRegle} = extendRegleConfig(useCustomRegle, {\n rules: () => ({\n customRuleExtended: withMessage(required, 'Custom rule 2'),\n })\n})\n\nuseExtendedRegle({name: ''}, {\n name: {\n custom\n \n }\n})\n\n```\n\n## Override default behaviors\n\nYou can override the default behaviors of Regle processors by using the `overrides` property.\n\n### `isEdited`\n\nOverride the default `$edited` property handler. Useful to handle custom comparisons for complex object types.\n\n:::warning\nIt's highly recommended to use this override with the [`markStatic`](/advanced-usage/immutable-constructors) helper to handle immutable constructors.\n:::\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { Decimal } from 'decimal.js';\n\nexport const { useRegle: useCustomRegle } = defineRegleConfig({\n overrides: {\n isEdited(currentValue, initialValue, defaultHandlerFn) {\n if (currentValue instanceof Decimal && initialValue instanceof Decimal) {\n return currentValue.toNearest(0.01).toString() !== initialValue.toNearest(0.01).toString();\n }\n // fallback to the default handler\n return defaultHandlerFn(currentValue, initialValue);\n },\n },\n})\n```"
23
+ "content": "# Global configuration\n\nIf your app includes multiple forms, it can be helpful to define a global configuration that centralizes your custom validators, error messages, and modifiers. This eliminates the need to declare these settings repeatedly for every `useRegle` call, improving both code consistency and developer experience with features like autocompletion and type checking.\n\nRegle offers two ways to define your global configuration:\n\n- **Composable** — use `defineRegleConfig` to create a custom `useRegle` composable that encapsulates your configuration. Best for scoped or modular setups.\n- **Declarative** — use `defineRegleOptions` with the `RegleVuePlugin` to provide configuration at the app level via Vue's plugin system. Best for app-wide defaults that apply everywhere, including the default `useRegle`.\n\n## Composable {#composable}\n\n`defineRegleConfig` creates and returns a custom `useRegle` composable (along with `inferRules` and `useRules`) that has your configuration baked in. This is ideal when you want strong typing and autocompletion for your custom rules.\n\n### Replace built-in rules messages\n\nEach `@regle/rules` rule provides a default error message. You may not want to call `withMessage` every time you need to use one with a custom error message.\n\n`defineRegleConfig` allows you to redefine the default messages of built-in rules.\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { withMessage, minLength, required } from '@regle/rules';\n\nconst { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n required: withMessage(required, 'You need to provide a value'),\n minLength: withMessage(minLength, ({ $value, $params: [min] }) => {\n return `Minimum length is ${min}. Current length: ${$value?.length}`;\n })\n })\n})\n\nconst { r$ } = useCustomRegle({ name: '' }, {\n name: {\n required,\n minLength: minLength(6)\n }\n})\n```\n\nResult: \n\n:::tip\nIf you use Nuxt, check out the [Nuxt module](/integrations/nuxt) for a even better DX. \nIt provides a way to add your custom global config to your auto-imports.\n:::\n\n#### i18n\n\nYou can also use any i18n library directly inside the config.\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { withMessage, minLength, required } from '@regle/rules';\nimport { useI18n } from 'vue-i18n';\n\nconst { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => {\n const { t } = useI18n()\n\n return {\n required: withMessage(required, t('general.required')),\n minLength: withMessage(minLength, ({ $value, $params: [max] }) => {\n return t('general.minLength', {max});\n })\n }\n }\n})\n```\n\n### Declare new rules\n\nWhile `useRegle` allows you to use any rule key, adding custom rules to the global configuration provides autocompletion and type checking. This improves maintainability and consistency across your application.\n\n```ts twoslash\nconst someAsyncCall = async () => await Promise.resolve(true);\n// ---cut---\n\nimport { defineRegleConfig, createRule, type Maybe } from '@regle/core';\nimport { withMessage, isFilled } from '@regle/rules';\n\nconst asyncEmail = createRule({\n async validator(value: Maybe<string>) {\n if (!isFilled(value)) {\n return true;\n }\n\n const result = await someAsyncCall();\n return result;\n },\n message: 'Email already exists',\n});\n\nconst { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n asyncEmail\n })\n})\n\nconst { r$ } = useCustomRegle({ name: '' }, {\n name: {\n asy\n\n }\n})\n```\n\n### Declare modifiers\n\nYou can include global modifiers in your configuration to automatically apply them wherever you use the `useRegle` composable. This avoids repetitive declarations and keeps your code clean.\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { withMessage, minLength, required } from '@regle/rules';\n\nexport const { useRegle: useCustomRegle } = defineRegleConfig({\n modifiers: {\n autoDirty: false,\n silent: true,\n lazy: true,\n rewardEarly: true\n }\n})\n```\n\n### Export scoped `inferRules` helper\n\n`defineRegleConfig` also returns a scoped `inferRules` helper, similar to the one exported from `@regle/core`, but that will autocomplete and check your custom rules.\n\nFor information about `inferRules`, check [Typing rules docs](/typescript/typing-rules)\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { withMessage, minLength, required } from '@regle/rules';\n\nexport const { useRegle, inferRules } = defineRegleConfig({/* */})\n```\n\n### Extend global config\n\nIt's also possible to add additional config to an already created custom `useRegle`.\n\nWith `extendRegleConfig`, you can recreate a custom one with a existing composable as an input.\n\n```ts twoslash\n\nimport { defineRegleConfig, extendRegleConfig, createRule } from '@regle/core';\nimport { withMessage, required } from '@regle/rules';\n\nconst { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n customRule: withMessage(required, 'Custom rule'),\n })\n})\n\nconst {useRegle: useExtendedRegle} = extendRegleConfig(useCustomRegle, {\n rules: () => ({\n customRuleExtended: withMessage(required, 'Custom rule 2'),\n })\n})\n\nuseExtendedRegle({name: ''}, {\n name: {\n custom\n \n }\n})\n\n```\n\n## Declarative {#declarative}\n\nThe declarative approach uses `defineRegleOptions` combined with the `RegleVuePlugin` to provide global configuration at the Vue app level. The configuration is injected via Vue's `provide/inject` mechanism, so it applies to every `useRegle` call in your application — including the default one from `@regle/core`.\n\nThis is especially useful when you want app-wide defaults without needing to import a custom composable everywhere.\n\n### Setup\n\nPass your options as the second argument to `app.use`:\n\n```ts [main.ts]\nimport { createApp } from 'vue';\nimport { RegleVuePlugin, defineRegleOptions } from '@regle/core';\nimport { withMessage, required, minLength } from '@regle/rules';\nimport App from './App.vue';\n\nconst options = defineRegleOptions({\n rules: () => ({\n required: withMessage(required, 'You need to provide a value'),\n minLength: withMessage(minLength, ({ $value, $params: [min] }) => {\n return `Minimum length is ${min}. Current length: ${$value?.length}`;\n })\n }),\n modifiers: {\n autoDirty: false,\n },\n shortcuts: {\n fields: {\n $isRequired: (field) => field.$rules.required?.$active ?? false,\n },\n },\n});\n\nconst app = createApp(App);\n\n// Add the options to the RegleVuePlugin\napp.use(RegleVuePlugin, options);\n\napp.mount('#app');\n```\n\nNow, every `useRegle` call in your app will automatically use the configured rules and modifiers — no need to import a custom composable.\n\n```vue\n\n```\n\n### Type augmentation\n\nTo get full type-safety and autocompletion with the declarative approach, you can augment Regle's interfaces using TypeScript module augmentation. This lets the default `useRegle` composable know about your custom rules and shortcut properties.\n\n```ts [regle.config.ts]\nimport { createRule } from '@regle/core';\n\nconst customRule = createRule({\n validator: (value: unknown) => value === 'custom',\n message: 'Custom rule',\n});\n\ndeclare module '@regle/core' {\n interface CustomRules {\n customRule: typeof customRule;\n }\n interface CustomFieldProperties {\n $isRequired: boolean;\n }\n interface CustomNestedProperties {\n $isEmpty: boolean;\n }\n interface CustomCollectionProperties {\n $isEmpty: boolean;\n }\n}\n```\n\n### Combining with composable configuration\n\nIf both the plugin options and a `defineRegleConfig` composable are used, the composable's configuration takes precedence and is merged on top of the plugin's. This lets you set app-wide defaults via the plugin while still allowing scoped overrides where needed.\n\n## Override default behaviors\n\nYou can override the default behaviors of Regle processors by using the `overrides` property. This works with both the composable and declarative approaches.\n\n### `isEdited`\n\nOverride the default `$edited` property handler. Useful to handle custom comparisons for complex object types.\n\n:::warning\nIt's highly recommended to use this override with the [`markStatic`](/advanced-usage/immutable-constructors) helper to handle immutable constructors.\n:::\n\n```ts\nimport { defineRegleConfig } from '@regle/core';\nimport { Decimal } from 'decimal.js';\n\nexport const { useRegle: useCustomRegle } = defineRegleConfig({\n overrides: {\n isEdited(currentValue, initialValue, defaultHandlerFn) {\n if (currentValue instanceof Decimal && initialValue instanceof Decimal) {\n return currentValue.toNearest(0.01).toString() !== initialValue.toNearest(0.01).toString();\n }\n // fallback to the default handler\n return defaultHandlerFn(currentValue, initialValue);\n },\n },\n})\n\n// Or with the declarative approach\nimport { defineRegleOptions } from '@regle/core';\n\nconst options = defineRegleOptions({\n overrides: {\n isEdited: (currentValue, initialValue, defaultHandlerFn) => {\n return currentValue !== initialValue;\n },\n },\n});\n\napp.use(RegleVuePlugin, options);\n```"
24
24
  },
25
25
  {
26
26
  "id": "advanced-usage-immutable-constructors",
@@ -34,7 +34,7 @@ var docs_data_default = {
34
34
  "title": "Merge multiple Regles",
35
35
  "category": "advanced-usage",
36
36
  "path": "advanced-usage/merge-regles.md",
37
- "content": "# Merge multiple Regles\n\nIf you need to combine multiple Regle instances into one, it's possible with the `mergeRegles` helper.\n\nit will return an output similar to the main `r$`, while still being able to call `$touch` or `$validate`.\n\nAll types are preserved.\n\n```ts twoslash\nimport {required, numeric, email} from '@regle/rules';\n// ---cut---\n\nimport { mergeRegles, useRegle } from '@regle/core';\n\nconst { r$ } = useRegle({email: ''}, {\n email: { required, email },\n});\n\nconst { r$: otherR$ } = useRegle({firstName: ''}, {\n firstName: { required },\n});\n\nconst r$Merged = mergeRegles({ r$, otherR$ });\n\nr$Merged.$value.otherR$.\n\n```"
37
+ "content": "# Merge multiple Regles\n\nIf you need to combine multiple Regle instances into one, it's possible with the `mergeRegles` helper.\n\n## When to use\n\n`mergeRegles` is useful when:\n- You have forms split across multiple components and need to validate them together\n- You want to compose smaller, reusable form sections into a larger form\n- Different parts of your form have different validation lifecycles but need unified submission\n\n## Basic usage\n\nThe helper returns an output similar to the main `r$`, while still being able to call `$touch`, `$validate`, or `$reset` on all merged instances at once.\n\nAll types are preserved, giving you full autocomplete support.\n\n```ts twoslash\nimport {required, numeric, email} from '@regle/rules';\n// ---cut---\n\nimport { mergeRegles, useRegle } from '@regle/core';\n\nconst { r$ } = useRegle({email: ''}, {\n email: { required, email },\n});\n\nconst { r$: otherR$ } = useRegle({firstName: ''}, {\n firstName: { required },\n});\n\nconst r$Merged = mergeRegles({ r$, otherR$ });\n\nr$Merged.$value.otherR$.\n\n```\n\nResult:\n\n## Accessing merged data\n\nYou can access each merged instance's data through the merged object:\n\n```ts\n// Access values\nr$Merged.$value.r$.email\nr$Merged.$value.otherR$.firstName\n\n// Access validation states\nr$Merged.r$.email.$valid\nr$Merged.otherR$.firstName.$error\n\n// Access errors\nr$Merged.$errors.r$.email\nr$Merged.$errors.otherR$.firstName\n```\n\n## Global operations\n\nThe merged instance exposes global methods that operate on all child instances:\n\n```ts\n// Validate all merged forms\nawait r$Merged.$validate()\n\n// Reset all merged forms\nr$Merged.$reset({ toInitialState: true })\n\n// Touch all fields\nr$Merged.$touch()\n```\n\n:::tip\nThe merged instance's `$valid`, `$error`, and `$pending` properties reflect the combined state of all child instances.\n:::"
38
38
  },
39
39
  {
40
40
  "id": "advanced-usage-rule-metadata",
@@ -76,7 +76,7 @@ var docs_data_default = {
76
76
  "title": "Async validations",
77
77
  "category": "common-usage",
78
78
  "path": "common-usage/async-validation.md",
79
- "content": "# Async validation\n\nA common pattern in forms is to asynchronously check for a value on the server side.\nAsync rules can perform these tasks, and they update the `$pending` state whenever invoked.\n\n:::tip\nBy default, all async rules will be debounced by `200ms`. It can be overriden with the `$debounce` modifier.\n:::\n\n## Inline Async rule\n\nTo declare an async rule, you simply have to use the `async await` syntax.\n\n```ts\nconst myAsyncRule = async (value: Maybe<number>) => {\n if (isFilled(value)) {\n return await someStuff();\n }\n return true;\n}\n```\n\nIf your rule doesn't use `async await` syntax, but still returns a `Promise`, you have to use the `withAsync` helper when using your rule in your form. Otherwise, Regle can't know it's an async rule.\n\n## Async using `createRule`\n\nIn the same way of an inline rule, your validator function must be using `async await` to be declared as an async rule.\n\n```ts\nconst myAsyncRule = createRule({\n async validator(value: Maybe<string>) {\n if (isFilled(value)) {\n return await someStuff();\n }\n return true;\n },\n message: 'Error'\n})\n```\n\n## `$pending` property\n\nEvery time you update the `$value` of the field using an async rule, the `$pending` [validation property](/core-concepts/validation-properties#pending) will be updated. The `$error` status depends on `$pending` so a field cannot be errored if it's still pending.\n\nThis can be used to display a loading icon and a custom message indicating that an operation is taking time.\n\n## Full example\n\n```vue [App.vue]\n<template>\n <div class=\"demo-container\">\n <div>\n <input\n v-model=\"form.email\"\n :class=\"{ pending: r$.email.$pending }\"\n placeholder=\"Type your email\"\n />\n\n <button type=\"button\" @click=\"r$.$reset({toInitialState: true})\">Reset</button>\n <button type=\"button\" @click=\"r$.$validate()\">Submit</button>\n </div>\n\n <span v-if=\"r$.email.$pending\"> Checking... </span>\n \n <ul v-if=\"r$.$errors.email.length\">\n <li v-for=\"error of r$.$errors.email\" :key=\"error\">\n {{ error }}\n </li>\n </ul>\n </div>\n</template>\n\n```"
79
+ "content": "# Async validation\n\nA common pattern in forms is to asynchronously check for a value on the server side.\nAsync rules can perform these tasks, and they update the `$pending` state whenever invoked.\n\n:::tip\nBy default, all async rules will be debounced by `200ms`. It can be overridden with the `$debounce` modifier.\n:::\n\n## Inline Async rule\n\nTo declare an async rule, you simply have to use the `async await` syntax.\n\n```ts\nconst myAsyncRule = async (value: Maybe<number>) => {\n if (isFilled(value)) {\n return await someStuff();\n }\n return true;\n}\n```\n\nIf your rule doesn't use `async await` syntax, but still returns a `Promise`, you have to use the `withAsync` helper when using your rule in your form. Otherwise, Regle can't know it's an async rule.\n\n## Async using `createRule`\n\nIn the same way of an inline rule, your validator function must be using `async await` to be declared as an async rule.\n\n```ts\nconst myAsyncRule = createRule({\n async validator(value: Maybe<string>) {\n if (isFilled(value)) {\n return await someStuff();\n }\n return true;\n },\n message: 'Error'\n})\n```\n\n## `$pending` property\n\nEvery time you update the `$value` of the field using an async rule, the `$pending` [validation property](/core-concepts/validation-properties#pending) will be updated. The `$error` status depends on `$pending` so a field cannot be errored if it's still pending.\n\nThis can be used to display a loading icon and a custom message indicating that an operation is taking time.\n\n## Full example\n\n```vue [App.vue]\n<template>\n <div class=\"demo-container\">\n <div>\n <input\n v-model=\"form.email\"\n :class=\"{ pending: r$.email.$pending }\"\n placeholder=\"Type your email\"\n />\n\n <button type=\"button\" @click=\"r$.$reset({toInitialState: true})\">Reset</button>\n <button type=\"button\" @click=\"r$.$validate()\">Submit</button>\n </div>\n\n <span v-if=\"r$.email.$pending\"> Checking... </span>\n \n <ul v-if=\"r$.$errors.email.length\">\n <li v-for=\"error of r$.$errors.email\" :key=\"error\">\n {{ error }}\n </li>\n </ul>\n </div>\n</template>\n\n```"
80
80
  },
81
81
  {
82
82
  "id": "common-usage-collections",
@@ -97,14 +97,14 @@ var docs_data_default = {
97
97
  "title": "Reset forms",
98
98
  "category": "common-usage",
99
99
  "path": "common-usage/reset-form.md",
100
- "content": "# Reset forms\n\nRegle offers multiple options to reset a form. It depends on your use case and what you want to achieve.\n\nIt can be either:\n- Only resetting the validation state ($dirty, $invalid, $pending etc..)\n- Only resetting the form state ($value) and keeping the validation state\n- Resetting the form state to a given state and keeping the validation state\n- Resetting the form state to a given state and clearing the validation state\n- Reset both form state and validation state to a pristine state\n\n## Basic usage, with `$reset` method\n\nThe `$reset` method is available on every nested instance of field of a form. So you can reset fields individually or the whole form.\n\n### Options\n\n### `toInitialState`\n- **Type:** `boolean`\n- **Description:** \n Reset validation status and reset form state to its initial state. \n Initial state is different from the original state, as it can be mutated when using `$reset`. This serves as the base comparison for `$edited`. \n ⚠️ This doesn't work if the state is a `reactive` object.\n\n### `toOriginalState`\n- **Type:** `boolean`\n- **Description:** \n Reset validation status and reset form state to its original state. \n Original state is the unmutated state that was passed to the form when it was initialized.\n\n### `toState`\n- **Type:** `TState` or `() => TState`\n- **Description:** \n Reset validation status and reset form state to the given state. Also sets the new state as the new initial state.\n\n### `clearExternalErrors`\n- **Type:** `boolean`\n- **Description:** \n Clears the `$externalErrors` state back to an empty object.\n\n```ts\nr$.$reset(); // Only reset validation state, set the initialValue as the current value\n```\n\n```ts\nr$.$reset({ toInitialState: true }); // Reset validation state and form state to initial state\n```\n\n```ts\nr$.$reset({ toOriginalState: true }); // Reset validation state and form state to original state\n```\n\n```ts\nr$.$reset({ toState: { email: 'test@test.com' } }); // Reset validation state and form state to the given state\n```\n\n```ts\nr$.$reset({ clearExternalErrors: true }); // Clear $externalErrors state\n```\n\n## Example\n\n```vue\n<template>\n <input\n v-model=\"r$.$value.email\"\n :class=\"{ valid: r$.email.$correct, error: r$.email.$error }\"\n placeholder=\"Type your email\"\n />\n <ul v-if=\"r$.$errors.email.length\">\n <li v-for=\"error of r$.$errors.email\" :key=\"error\">\n {{ error }}\n </li>\n </ul>\n <div>\n <button type=\"button\" @click=\"r$.$reset()\">Reset validation state</button>\n <button type=\"button\" @click=\"r$.$reset({ toInitialState: true })\">Reset to initial state</button>\n <button type=\"button\" @click=\"r$.$reset({ toOriginalState: true })\">Reset to original state</button>\n <button type=\"button\" @click=\"r$.$reset({ toState: { email: 'test@test.com' } })\"\n >Reset to a given state</button\n >\n <button class=\"primary\" type=\"button\" @click=\"r$.$validate()\">Submit</button>\n </div>\n</template>\n\n```"
100
+ "content": "# Reset forms\n\nRegle offers multiple options to reset a form. It depends on your use case and what you want to achieve.\n\nIt can be either:\n- Only resetting the validation state ($dirty, $invalid, $pending etc..)\n- Only resetting the form state ($value) and keeping the validation state\n- Resetting the form state to a given state and keeping the validation state\n- Resetting the form state to a given state and clearing the validation state\n- Reset both form state and validation state to a pristine state\n\n## Basic usage, with `$reset` method\n\nThe `$reset` method is available on every nested instance of field of a form. So you can reset fields individually or the whole form.\n\n### Options\n\nThe `$reset` method accepts an options object with the following properties:\n\n#### `toInitialState`\n- **Type:** `boolean`\n- **Description:** \n Reset validation status and reset form state to its initial state. \n Initial state is different from the original state, as it can be mutated when using `$reset`. This serves as the base comparison for `$edited`. \n ⚠️ This doesn't work if the state is a `reactive` object.\n\n#### `toOriginalState`\n- **Type:** `boolean`\n- **Description:** \n Reset validation status and reset form state to its original state. \n Original state is the unmutated state that was passed to the form when it was initialized.\n\n#### `toState`\n- **Type:** `TState` or `() => TState`\n- **Description:** \n Reset validation status and reset form state to the given state. Also sets the new state as the new initial state.\n\n#### `clearExternalErrors`\n- **Type:** `boolean`\n- **Description:** \n Clears the `$externalErrors` state back to an empty object.\n\n```ts\nr$.$reset(); // Only reset validation state, set the initialValue as the current value\n```\n\n```ts\nr$.$reset({ toInitialState: true }); // Reset validation state and form state to initial state\n```\n\n```ts\nr$.$reset({ toOriginalState: true }); // Reset validation state and form state to original state\n```\n\n```ts\nr$.$reset({ toState: { email: 'test@test.com' } }); // Reset validation state and form state to the given state\n```\n\n```ts\nr$.$reset({ clearExternalErrors: true }); // Clear $externalErrors state\n```\n\n## Example\n\n```vue\n<template>\n <input\n v-model=\"r$.$value.email\"\n :class=\"{ valid: r$.email.$correct, error: r$.email.$error }\"\n placeholder=\"Type your email\"\n />\n <ul v-if=\"r$.$errors.email.length\">\n <li v-for=\"error of r$.$errors.email\" :key=\"error\">\n {{ error }}\n </li>\n </ul>\n <div>\n <button type=\"button\" @click=\"r$.$reset()\">Reset validation state</button>\n <button type=\"button\" @click=\"r$.$reset({ toInitialState: true })\">Reset to initial state</button>\n <button type=\"button\" @click=\"r$.$reset({ toOriginalState: true })\">Reset to original state</button>\n <button type=\"button\" @click=\"r$.$reset({ toState: { email: 'test@test.com' } })\"\n >Reset to a given state</button\n >\n <button class=\"primary\" type=\"button\" @click=\"r$.$validate()\">Submit</button>\n </div>\n</template>\n\n```\n\nResult:"
101
101
  },
102
102
  {
103
103
  "id": "common-usage-standard-schema",
104
104
  "title": "Standard Schema",
105
105
  "category": "common-usage",
106
106
  "path": "common-usage/standard-schema.md",
107
- "content": "# Standard Schema\n\nRegle implements the [Standard Schema](https://standardschema.dev/) specification.\n\nThis means that you can use Regle on any third party package that supports the Standard Schema spec.\n\nRegle can also use itself as a schema library when using `useRegleSchema`.\n\n## Usage\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { required } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { required }\n})\n\nconst result = await r$.['~standard'].validate({ name: '' });\n\nconsole.log(result.issues);\n```\n\n### Schema only usage\n\n```ts\nimport { useRules } from '@regle/core';\nimport { required, string } from '@regle/rules';\n\nconst schema = useRules({\n name: { string, required }\n})\n\nconst result = await schema['~standard'].validate({ name: '' });\n```\n\n## Composition usage\n\n```vue\n<template>\n <input \n v-model='r$.$value.email' \n :class=\"{ error: r$.email.$error }\" \n placeholder='Type your email'\n />\n\n <li v-for=\"error of r$.email.$errors\" :key='error'>\n {{ error }}\n </li>\n</template>\n\n```\n\n### `InferInput`\n\n`InferInput` is an utility type that can produce a object state from any rules object.\n\nIt will try to extract the possible state type that a rule may have, prioritizing rules that have a strict input type.\n\nSome rules may have `unknown` type because it could apply to any value. To cover this, there is now type-helpers rules to help you type your state from the rules: `type`, `string`, `number`, `boolean`, `date`.\n\n:::info\nSome types like `numeric` will feel weird as it's typed `string | number`, it's normal as the rule can also validate numeric strings. You can enforce the type by applying `number` rule to it.\n:::\n\n```ts twoslash\nimport {ref} from 'vue';\n// ---cut---\nimport { defineRules, type InferInput} from '@regle/core';\nimport { required, string, numeric, type } from '@regle/rules';\n\n/* defineRules is not required, but it helps you catch errors in structure */\nconst rules = defineRules({\n firstName: { required, string },\n count: { numeric },\n enforceType: { required, type: type<'FOO' | 'BAR'>()}\n})\n\ntype State = InferInput<typeof rules>;\n\n```\n\n<br/>\n<br/>\n<br/>\n\n## `useRules`\n\n`useRules` is a composable that allows you to write your rules in a more declarative way.\n\nIt works exactly like `useRegle`, but it doesn't accept a state parameter, it will create a emp from the rules.\n\n```ts twoslash\n\nimport { useRules, type InferInput } from '@regle/core';\nimport { required, string } from '@regle/rules';\n\nconst r$ = useRules({\n name: { required, string },\n});\n```\n\n## `refineRules`\n\nRegle is state first because in real world forms, rules can depend a state values. \nThis make it a problem for dynamic rules as it would make a cyclic type error when trying to use the state inside the rules.\n\nTo cover this case and inspired by Zod's `refine`, Regle provides a `refineRules` helper to write dynamic rules that depend on the state, while making it possible to access a typed state.\n\nAnything returned by the rule refine function will override what's defined in the default rules.\n\n```ts twoslash\nimport {ref} from 'vue';\n// ---cut---\nimport { refineRules, type InferInput} from '@regle/core';\nimport { required, string, sameAs } from '@regle/rules';\n\nconst rules = refineRules({\n password: { required, string },\n}, \n (state) => ({\n confirmPassword: { required, sameAs: sameAs(() => state.value.password) }\n })\n)\n\ntype State = InferInput<typeof rules>;\n\n```"
107
+ "content": "# Standard Schema\n\nRegle implements the [Standard Schema](https://standardschema.dev/) specification.\n\nThis means that you can use Regle on any third party package that supports the Standard Schema spec.\n\nRegle can also use itself as a schema library when using `useRegleSchema`.\n\n## Usage\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { required } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { required }\n})\n\nconst result = await r$.['~standard'].validate({ name: '' });\n\nconsole.log(result.issues);\n```\n\n### Schema only usage\n\n```ts\nimport { useRules } from '@regle/core';\nimport { required, string } from '@regle/rules';\n\nconst schema = useRules({\n name: { string, required }\n})\n\nconst result = await schema['~standard'].validate({ name: '' });\n```\n\n## Composition usage\n\n```vue\n<template>\n <input \n v-model='r$.$value.email' \n :class=\"{ error: r$.email.$error }\" \n placeholder='Type your email'\n />\n\n <li v-for=\"error of r$.email.$errors\" :key='error'>\n {{ error }}\n </li>\n</template>\n\n```\n\n### `InferInput`\n\n`InferInput` is an utility type that can produce a object state from any rules object.\n\nIt will try to extract the possible state type that a rule may have, prioritizing rules that have a strict input type.\n\nSome rules may have `unknown` type because it could apply to any value. To cover this, there is now type-helpers rules to help you type your state from the rules: `type`, `string`, `number`, `boolean`, `date`.\n\n:::info\nSome types like `numeric` will feel weird as it's typed `string | number`, it's normal as the rule can also validate numeric strings. You can enforce the type by applying `number` rule to it.\n:::\n\n```ts twoslash\nimport {ref} from 'vue';\n// ---cut---\nimport { defineRules, type InferInput} from '@regle/core';\nimport { required, string, numeric, type } from '@regle/rules';\n\n/* defineRules is not required, but it helps you catch errors in structure */\nconst rules = defineRules({\n firstName: { required, string },\n count: { numeric },\n enforceType: { required, type: type<'FOO' | 'BAR'>()}\n})\n\ntype State = InferInput<typeof rules>;\n\n```\n\n<br/>\n<br/>\n<br/>\n\n## `useRules`\n\n`useRules` is a composable that allows you to write your rules in a more declarative way.\n\nIt works exactly like `useRegle`, but it doesn't accept a state parameter, it will create an empty state from the rules.\n\n```ts twoslash\n\nimport { useRules, type InferInput } from '@regle/core';\nimport { required, string } from '@regle/rules';\n\nconst r$ = useRules({\n name: { required, string },\n});\n```\n\nResult:\n\n## `refineRules`\n\nRegle is state first because in real world forms, rules can depend a state values. \nThis make it a problem for dynamic rules as it would make a cyclic type error when trying to use the state inside the rules.\n\nTo cover this case and inspired by Zod's `refine`, Regle provides a `refineRules` helper to write dynamic rules that depend on the state, while making it possible to access a typed state.\n\nAnything returned by the rule refine function will override what's defined in the default rules.\n\n```ts twoslash\nimport {ref} from 'vue';\n// ---cut---\nimport { refineRules, type InferInput} from '@regle/core';\nimport { required, string, sameAs } from '@regle/rules';\n\nconst rules = refineRules({\n password: { required, string },\n}, \n (state) => ({\n confirmPassword: { required, sameAs: sameAs(() => state.value.password) }\n })\n)\n\ntype State = InferInput<typeof rules>;\n\n```"
108
108
  },
109
109
  {
110
110
  "id": "common-usage-usage-with-pinia",
@@ -139,7 +139,7 @@ var docs_data_default = {
139
139
  "title": "Built-in rules",
140
140
  "category": "rules",
141
141
  "path": "core-concepts/rules/built-in-rules.md",
142
- "content": "# Built-in rules\n\nAll built-in rules are available through the `@regle/rules` package.\n\nDon't forget to install it if you haven't:\n\n::: code-group\n\n```sh [pnpm]\npnpm add @regle/rules\n```\n\n```sh [npm]\nnpm install @regle/rules\n```\n\n```sh [yarn]\nyarn add @regle/rules\n```\n\n```sh [bun]\nbun add @regle/rules\n```\n\n:::\n\n:::tip\nEvery built-in rule will check if the value of the field is set before checking if it's valid.\n\nThis allow to have rules even if the field is not required.\n:::\n\n## `alpha`\n\n_**Params**_\n - `allowSymbols?: MaybeRefOrGetter<boolean>`\n\nAllows only alphabetic characters.\n\n```ts\nimport { alpha } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { \n alpha,\n // or\n alpha: alpha({ allowSymbols: true }),\n },\n})\n```\n\n## `alphaNum`\n\n_**Params**_\n - `allowSymbols?: MaybeRefOrGetter<boolean>`\n\nAllows only alphanumeric characters.\n\n```ts\nimport { alphaNum } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { \n alphaNum,\n // or\n alphaNum: alphaNum({ allowSymbols: true }),\n})\n```\n\n## `atLeastOne`\n\n_**Params**_\n - `keys?: MaybeRefOrGetter<string[]>` - Optional list of keys to check. If not provided, checks if the object has at least one filled property.\n\n_**Works with**_\n - `Record | object`\n\nChecks if at least one key is filled in the object. Useful for object-level validation with `$self`.\n\n```ts\nimport { atLeastOne } from '@regle/rules';\n\nconst { r$ } = useRegle({ user: { firstName: '', lastName: '' } }, {\n user: {\n $self: {\n // Check if any property is filled\n atLeastOne,\n // or check specific keys\n atLeastOne: atLeastOne(['firstName', 'lastName']),\n },\n },\n})\n```\n\n## `between`\n\n_**Params**_\n - `min: Ref<number> | number | () => number`\n - `max: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\nChecks if a number is in specified bounds. `min` and `max` are both inclusive.\n\n```ts\nimport { between } from '@regle/rules';\n\nconst maxCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n between: between(1, 6),\n between: between(1, maxCount, {allowEqual: false}),\n between: between(() => maxCount.value, 10)\n },\n})\n```\n\n## `boolean`\n\nRequires a value to be a native boolean type. Mainly used for typing.\n\n```ts\nimport {type InferInput} from '@regle/core';\nimport { boolean } from '@regle/rules';\n\nconst rules = {\n checkbox: { boolean },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `checked`\n\nRequires a boolean value to be `true`. This is useful for checkbox inputs.\n\n### Note\n\nThis rule does not need `required` to be set, it will assert the value is set.\n\n```ts\nimport { checked } from '@regle/rules';\n\nconst { r$ } = useRegle({ confirm: false }, {\n confirm: { checked },\n})\n```\n\n## `contains`\n\n_**Params**_\n- `contain: Ref<string> | string | () => string`\n\nChecks if the string contains the specified substring.\n\n```ts\nimport { contains } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestLib: '' }, {\n bestLib: {\n contains: contains('regle')\n },\n})\n```\n\n## `date`\n\nRequires a value to be a native Date constructor. Mainly used for typing.\n\n```ts\nimport {type InferInput} from '@regle/core';\nimport { date } from '@regle/rules';\n\nconst rules = {\n birthday: { date },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `dateAfter`\n_**Params**_\n - `after: Ref<string | Date> | string | Date | () => string | Date`\n - `options?: {allowEqual?: boolean}`\n\nChecks if the date is after the given parameter.\n\n```ts\nimport { dateAfter } from '@regle/rules';\n\nconst today = ref(new Date());\n\nconst { r$ } = useRegle({ birthday: null as Date | null }, {\n birthday: {\n dateAfter: dateAfter(today),\n // or\n dateAfter: dateAfter(today, { allowEqual: false }),\n },\n})\n```\n\n## `dateBefore`\n_**Params**_\n - `before: Ref<string | Date> | string | Date | () => string | Date`\n - `options?: {allowEqual?: boolean}`\n\nChecks if the date is before the given parameter.\n\n```ts\nimport { dateBefore } from '@regle/rules';\n\nconst today = ref(new Date());\n\nconst { r$ } = useRegle({ birthday: null as Date | null }, {\n birthday: {\n dateBefore: dateBefore(today),\n // or\n dateBefore: dateBefore(today, { allowEqual: false }),\n },\n})\n```\n\n## `dateBetweeen`\n\n_**Params**_\n - `before: Ref<string | Date> | string | Date | () => string | Date`\n - `after: Ref<string | Date> | string | Date | () => string | Date`\n - `options?: {allowEqual?: boolean}`\n\nChecks if the date falls between the specified bounds.\n\n```ts\nimport { dateBetween } from '@regle/rules';\n\nconst before = ref(new Date());\nconst after = ref(new Date(2030, 3, 1));\n\nconst { r$ } = useRegle({ birthday: null as Date | null }, {\n birthday: {\n dateBetween: dateBetween(before, after),\n // or\n dateBetween: dateBetween(before, after, { allowEqual: false }),\n },\n})\n```\n\n## `decimal`\n\nAllows positive and negative decimal numbers.\n\n```ts\nimport { decimal } from '@regle/rules';\n\nconst { r$ } = useRegle({ price: 0 }, {\n price: { decimal },\n})\n```\n\n## `email`\n\nValidates email addresses. Always verify on the server to ensure the address is real and not already in use.\n\n```ts\nimport { email } from '@regle/rules';\n\nconst { r$ } = useRegle({ email: '' }, {\n email: { email },\n})\n```\n\n## `emoji`\n\nValidates emojis.\n\n```ts\nimport { emoji } from '@regle/rules';\n\nconst { r$ } = useRegle({ emoji: '' }, {\n emoji: { emoji },\n})\n```\n\n## `endsWith`\n\n_**Params**_\n- `end: Ref<string> | string | () => string`\n\nChecks if the string ends with the specified substring.\n\n```ts\nimport { endsWith } from '@regle/rules';\n\nconst { r$ } = useRegle({ firstName: '' }, {\n firstName: { endsWith: endsWith('foo') },\n})\n```\n\n## `exactDigits`\n_**Params**_\n - `count: Ref<number> | number | () => number`\n\nRequires the input value to have a strict specified number of digits.\n\n```ts\nimport { exactDigits } from '@regle/rules';\n\nconst exactValue = ref(6);\n\nconst { r$ } = useRegle({ digits: '' }, {\n digits: {\n exactDigits: exactDigits(6),\n // or with ref\n exactDigits: exactDigits(exactValue),\n // or with getter\n exactDigits: exactDigits(() => exactValue.value)\n },\n})\n```\n\n## `exactLength`\n\n_**Params**_\n - `count: Ref<number> | number | () => number`\n\nRequires the input value to have a strict specified length, inclusive. Works with arrays, objects and strings.\n\n```ts\nimport { exactLength } from '@regle/rules';\n\nconst exactValue = ref(6);\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n exactLength: exactLength(6),\n exactLength: exactLength(exactValue),\n exactLength: exactLength(() => exactValue.value)\n },\n})\n```\n\n## `exactValue`\n\n_**Params**_\n - `count: Ref<number> | number | () => number`\n\nRequires a field to have a strict numeric value.\n\n```ts\nimport { exactValue } from '@regle/rules';\n\nconst exactCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n exactValue: exactValue(6),\n exactValue: exactValue(exactCount),\n exactValue: exactValue(() => exactCount.value)\n },\n})\n```\n\n## `file`\n\nRequires a value to be a native File constructor. Mainly used for typing.\n\n```ts\nimport { file } from '@regle/rules';\n\nconst rules = {\n file: { file },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `fileType`\n\nRequires a value to be a file with a specific type.\n\n```ts\nimport { fileType } from '@regle/rules';\n\nconst { r$ } = useRegle({ file: null as File | null }, {\n file: { fileType: fileType(['image/png', 'image/jpeg']) },\n})\n```\n\n## `hexadecimal`\n\nValidates hexadecimal values.\n\n```ts\nimport { hexadecimal } from '@regle/rules';\n\nconst { r$ } = useRegle({ hexadecimal: '' }, {\n hexadecimal: { hexadecimal },\n})\n```\n\n## `hostname`\n\nValidates hostnames.\n\n```ts\nimport { hostname } from '@regle/rules';\n\nconst { r$ } = useRegle({ siteHost: '' }, {\n siteHost: { hostname },\n})\n```\n\n## `httpUrl`\n\n_**Params**_\n- `options?: {protocol?: RegExp}`\n\nValidates HTTP URLs.\n\n```ts\nimport { httpUrl } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestUrl: '' }, {\n bestUrl: { httpUrl },\n // or with custom protocol validation\n bestUrl: { httpUrl: httpUrl({ protocol: /^https$/ }) },\n})\n```\n\n## `integer`\n\nAllows only integers (positive and negative).\n\n```ts\nimport { integer } from '@regle/rules';\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: { integer },\n})\n```\n\n## `ipv4Address`\n\nValidates IPv4 addresses in dotted decimal notation *127.0.0.1*.\n\n```ts\nimport { ipv4Address } from '@regle/rules';\n\nconst { r$ } = useRegle({ address: '' }, {\n address: { ipv4Address },\n})\n```\n\n## `literal`\n\nValidates literal values.\n\n### Note\n\nThis rule does not need `required` to be set, it will assert the value is set.\n\n```ts\nimport { literal } from '@regle/rules';\n\nconst { r$ } = useRegle({ value: '' }, {\n value: { literal: literal('foo') },\n})\n```\n\n## `lowercase`\n\nValidates lowercase strings.\n\n```ts\nimport { lowercase } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { lowercase },\n})\n```\n\n## `macAddress`\n\n_**Params**_\n - `separator?: string | Ref<string> | () => string`\n\nValidates MAC addresses. Call as a function to specify a custom separator (e.g., ':' or an empty string for 00ff1122334455).\n\n```ts\n\nimport { macAddress } from '@regle/rules';\n\nconst maxCount = ref(6);\n\nconst { r$ } = useRegle({ address: '' }, {\n address: {\n macAddress,\n // or\n macAddress: macAddress('-')\n },\n})\n```\n\n## `maxFileSize`\n\nRequires a value to be a file with a maximum size.\n\n```ts\nimport { maxFileSize } from '@regle/rules';\n\nconst { r$ } = useRegle({ file: null as File | null }, {\n file: { maxFileSize: maxFileSize(10_000_000) }, // 10 MB\n})\n```\n\n## `maxLength`\n\n_**Params**_\n - `max: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\n_**Works with**_\n - `Array | Record | string | number`\n\nRequires the input value to have a maximum specified length, inclusive. Works with arrays, objects and strings.\n\n```ts\nimport { maxLength } from '@regle/rules';\n\nconst maxValue = ref(6);\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n maxLength: maxLength(6),\n maxLength: maxLength(maxValue),\n maxLength: maxLength(() => maxValue.value)\n },\n})\n```\n\n## `maxValue`\n\n_**Params**_\n - `min: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\n Requires a field to have a specified maximum numeric value.\n\n```ts\nimport { maxValue } from '@regle/rules';\n\nconst maxCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n maxValue: maxValue(6),\n maxValue: maxValue(maxCount, {allowEqual: false}),\n maxValue: maxValue(() => maxCount.value)\n },\n})\n```\n\n## `minFileSize`\n\nRequires a value to be a file with a minimum size.\n\n```ts\nimport { minFileSize } from '@regle/rules';\n\nconst { r$ } = useRegle({ file: null as File | null }, {\n file: { minFileSize: minFileSize(1_000_000) }, // 1 MB\n})\n```\n\n## `minLength`\n\n_**Params**_\n - `min: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\n_**Works with**_\n - `Array | Record | string | number`\n\nRequires the input value to have a minimum specified length, inclusive. Works with arrays, objects and strings.\n\n```ts\nimport { minLength } from '@regle/rules';\n\nconst minValue = ref(6);\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n minLength: minLength(6),\n minLength: minLength(minValue),\n minLength: minLength(() => minValue.value)\n },\n})\n```\n\n## `minValue`\n\n_**Params**_\n - `min: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\n_**Works with**_\n - `number`\n\nRequires a field to have a specified minimum numeric value.\n\n```ts\nimport { minValue } from '@regle/rules';\n\nconst minCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n minValue: minValue(6),\n minValue: minValue(minCount, {allowEqual: false}),\n minValue: minValue(() => minCount.value)\n },\n})\n```\n\n## `nativeEnum`\n\nValidate against a native Typescript enum value. Similar to Zod's `nativeEnum`\n\n```ts\nimport { nativeEnum } from '@regle/rules';\n\nenum Foo {\n Bar, Baz\n}\n\nconst { r$ } = useRegle({ type: '' }, {\n type: { nativeEnum: nativeEnum(Foo) },\n})\n```\n\n## `number`\n\nRequires a value to be a native number type. Mainly used for typing.\n\n```ts\nimport { number } from '@regle/rules';\n\nconst rules = {\n count: { number },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `numeric`\n\nAllows only numeric values (including numeric strings).\n\n```ts\nimport { numeric } from '@regle/rules';\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: { numeric },\n})\n```\n\n## `oneOf`\n\nAllow only one of the values from a fixed Array of possible entries.\n\n_**Params**_\n - `options: MaybeRefOrGetter<Array<string | number>>`\n\n```ts\nimport { oneOf } from '@regle/rules';\n\nconst { r$ } = useRegle({ aliment: 'Fish' }, {\n aliment: {\n oneOf: oneOf(['Fish', 'Meat', 'Bone'])\n },\n})\n```\n\n## `regex`\n\n_**Params**_\n- `regexps: MaybeRefOrGetter<RegExp | RegExp[]>`\n\nChecks if the value matches one or more regular expressions.\n\n```ts\nimport { regex } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n regex: regex(/^foo/),\n regex: regex([/^bar/, /baz$/]),\n },\n})\n```\n\n## `required`\n\nRequires non-empty data. Checks for empty arrays and strings containing only whitespaces.\n\n```ts\nimport {required} from '@regle/rules';\n\nconst {r$} = useRegle({name: ''}, {\n name: {required},\n})\n```\n\n## `requiredIf`\n\n_**Params**_\n - `condition: Ref<unknown> | unknown | () => unknown` - the property to base the `required` validator on.\n\nRequires non-empty data, only if provided data property, ref, or a function resolves to `true`.\n\n```ts\nimport { requiredIf } from '@regle/rules';\n\nconst form = ref({ name: '', condition: false });\n\nconst conditionRef = ref(false);\n\nconst { r$ } = useRegle(form, {\n name: {\n required: requiredIf(() => form.value.condition),\n required: requiredIf(conditionRef),\n },\n})\n```\n\n## `requiredUnless`\n\n_**Params**_\n - `condition: Ref<unknown> | unknown | () => unknown` - the property to base the `required` validator on.\n\nRequires non-empty data, only if provided data property, ref, or a function resolves to `false`.\n\n```ts\nimport { requiredUnless } from '@regle/rules';\n\nconst form = ref({ name: '', condition: false });\n\nconst conditionRef = ref(false);\n\nconst { r$ } = useRegle(form, {\n name: {\n required: requiredUnless(() => form.value.condition),\n required: requiredUnless(conditionRef)\n },\n})\n```\n\n## `sameAs`\n\n_**Params**_\n * `target: unknown`\n\nChecks if the value matches the specified property or ref.\n\n```ts\nimport { sameAs } from '@regle/rules';\n\nconst form = ref({\n password: '',\n confirmPassword: '',\n});\n\nconst { r$ } = useRegle(form, {\n confirmPassword: {\n sameAs: sameAs(() => form.value.password),\n }\n})\n```\n\n## `startsWith`\n\n_**Params**_\n- `start: Ref<string> | string | () => string`\n\nChecks if the string starts with the specified substring.\n\n```ts\nimport { startsWith } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestLib: '' }, {\n bestLib: {\n startsWith: startsWith('regle')\n },\n})\n```\n\n## `string`\n\nRequires a value to be a native string type. Mainly used for typing\n\n```ts\nimport {type InferInput} from '@regle/core';\nimport { string } from '@regle/rules';\n\nconst rules = {\n firstName: { string },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `type`\n\nDefine the input type of a rule. No runtime validation. \nOverride any input type set by other rules.\n\n```ts\nimport {type InferInput} from '@regle/core';\nimport { type } from '@regle/rules';\n\nconst rules = {\n firstName: { type: type<string>() },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `uppercase`\n\nValidates uppercase strings.\n\n```ts\nimport { uppercase } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { uppercase },\n})\n```\n\n## `url`\n\n_**Params**_\n- `options?: {protocol?: RegExp}`\n\nValidates URLs.\n\n```ts\nimport { url } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestUrl: '' }, {\n bestUrl: { url },\n // or with custom protocol validation\n bestUrl: { url: url({ protocol: /^https?$/ }) },\n})\n```"
142
+ "content": "# Built-in rules\n\nAll built-in rules are available through the `@regle/rules` package.\n\nDon't forget to install it if you haven't:\n\n::: code-group\n\n```sh [pnpm]\npnpm add @regle/rules\n```\n\n```sh [npm]\nnpm install @regle/rules\n```\n\n```sh [yarn]\nyarn add @regle/rules\n```\n\n```sh [bun]\nbun add @regle/rules\n```\n\n:::\n\n:::tip\nEvery built-in rule will check if the value of the field is set before checking if it's valid.\n\nThis allow to have rules even if the field is not required.\n:::\n\n## `alpha`\n\n_**Params**_\n - `allowSymbols?: MaybeRefOrGetter<boolean>`\n\nAllows only alphabetic characters.\n\n```ts\nimport { alpha } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { \n alpha,\n // or\n alpha: alpha({ allowSymbols: true }),\n },\n})\n```\n\n## `alphaNum`\n\n_**Params**_\n - `allowSymbols?: MaybeRefOrGetter<boolean>`\n\nAllows only alphanumeric characters.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { alphaNum } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { \n alphaNum,\n // or\n alphaNum: alphaNum({ allowSymbols: true }),\n },\n});\n```\n\n## `atLeastOne`\n\n_**Params**_\n - `keys?: MaybeRefOrGetter<string[]>` - Optional list of keys to check. If not provided, checks if the object has at least one filled property.\n\n_**Works with**_\n - `Record | object`\n\nChecks if at least one key is filled in the object. Useful for object-level validation with `$self`.\n\n```ts\nimport { atLeastOne } from '@regle/rules';\n\nconst { r$ } = useRegle({ user: { firstName: '', lastName: '' } }, {\n user: {\n $self: {\n // Check if any property is filled\n atLeastOne,\n // or check specific keys\n atLeastOne: atLeastOne(['firstName', 'lastName']),\n },\n },\n})\n```\n\n## `between`\n\n_**Params**_\n - `min: Ref<number> | number | () => number`\n - `max: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\nChecks if a number is in specified bounds. `min` and `max` are both inclusive.\n\n```ts\nimport { between } from '@regle/rules';\n\nconst maxCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n between: between(1, 6),\n between: between(1, maxCount, {allowEqual: false}),\n between: between(() => maxCount.value, 10)\n },\n})\n```\n\n## `boolean`\n\nRequires a value to be a native boolean type. Mainly used for typing.\n\n```ts\nimport {type InferInput} from '@regle/core';\nimport { boolean } from '@regle/rules';\n\nconst rules = {\n checkbox: { boolean },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `checked`\n\nRequires a boolean value to be `true`. This is useful for checkbox inputs.\n\n### Note\n\nThis rule does not need `required` to be set, it will assert the value is set.\n\n```ts\nimport { checked } from '@regle/rules';\n\nconst { r$ } = useRegle({ confirm: false }, {\n confirm: { checked },\n})\n```\n\n## `contains`\n\n_**Params**_\n- `contain: Ref<string> | string | () => string`\n\nChecks if the string contains the specified substring.\n\n```ts\nimport { contains } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestLib: '' }, {\n bestLib: {\n contains: contains('regle')\n },\n})\n```\n\n## `date`\n\nRequires a value to be a native Date constructor. Mainly used for typing.\n\n```ts\nimport {type InferInput} from '@regle/core';\nimport { date } from '@regle/rules';\n\nconst rules = {\n birthday: { date },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `dateAfter`\n_**Params**_\n - `after: Ref<string | Date> | string | Date | () => string | Date`\n - `options?: {allowEqual?: boolean}`\n\nChecks if the date is after the given parameter.\n\n```ts\nimport { dateAfter } from '@regle/rules';\n\nconst today = ref(new Date());\n\nconst { r$ } = useRegle({ birthday: null as Date | null }, {\n birthday: {\n dateAfter: dateAfter(today),\n // or\n dateAfter: dateAfter(today, { allowEqual: false }),\n },\n})\n```\n\n## `dateBefore`\n_**Params**_\n - `before: Ref<string | Date> | string | Date | () => string | Date`\n - `options?: {allowEqual?: boolean}`\n\nChecks if the date is before the given parameter.\n\n```ts\nimport { dateBefore } from '@regle/rules';\n\nconst today = ref(new Date());\n\nconst { r$ } = useRegle({ birthday: null as Date | null }, {\n birthday: {\n dateBefore: dateBefore(today),\n // or\n dateBefore: dateBefore(today, { allowEqual: false }),\n },\n})\n```\n\n## `dateBetween`\n\n_**Params**_\n - `before: Ref<string | Date> | string | Date | () => string | Date`\n - `after: Ref<string | Date> | string | Date | () => string | Date`\n - `options?: {allowEqual?: boolean}`\n\nChecks if the date falls between the specified bounds.\n\n```ts\nimport { dateBetween } from '@regle/rules';\n\nconst before = ref(new Date());\nconst after = ref(new Date(2030, 3, 1));\n\nconst { r$ } = useRegle({ birthday: null as Date | null }, {\n birthday: {\n dateBetween: dateBetween(before, after),\n // or\n dateBetween: dateBetween(before, after, { allowEqual: false }),\n },\n})\n```\n\n## `decimal`\n\nAllows positive and negative decimal numbers.\n\n```ts\nimport { decimal } from '@regle/rules';\n\nconst { r$ } = useRegle({ price: 0 }, {\n price: { decimal },\n})\n```\n\n## `email`\n\nValidates email addresses. Always verify on the server to ensure the address is real and not already in use.\n\n```ts\nimport { email } from '@regle/rules';\n\nconst { r$ } = useRegle({ email: '' }, {\n email: { email },\n})\n```\n\n## `emoji`\n\nValidates emojis.\n\n```ts\nimport { emoji } from '@regle/rules';\n\nconst { r$ } = useRegle({ emoji: '' }, {\n emoji: { emoji },\n})\n```\n\n## `endsWith`\n\n_**Params**_\n- `end: Ref<string> | string | () => string`\n\nChecks if the string ends with the specified substring.\n\n```ts\nimport { endsWith } from '@regle/rules';\n\nconst { r$ } = useRegle({ firstName: '' }, {\n firstName: { endsWith: endsWith('foo') },\n})\n```\n\n## `exactDigits`\n_**Params**_\n - `count: Ref<number> | number | () => number`\n\nRequires the input value to have a strict specified number of digits.\n\n```ts\nimport { exactDigits } from '@regle/rules';\n\nconst exactValue = ref(6);\n\nconst { r$ } = useRegle({ digits: '' }, {\n digits: {\n exactDigits: exactDigits(6),\n // or with ref\n exactDigits: exactDigits(exactValue),\n // or with getter\n exactDigits: exactDigits(() => exactValue.value)\n },\n})\n```\n\n## `exactLength`\n\n_**Params**_\n - `count: Ref<number> | number | () => number`\n\nRequires the input value to have a strict specified length, inclusive. Works with arrays, objects and strings.\n\n```ts\nimport { exactLength } from '@regle/rules';\n\nconst exactValue = ref(6);\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n exactLength: exactLength(6),\n exactLength: exactLength(exactValue),\n exactLength: exactLength(() => exactValue.value)\n },\n})\n```\n\n## `exactValue`\n\n_**Params**_\n - `count: Ref<number> | number | () => number`\n\nRequires a field to have a strict numeric value.\n\n```ts\nimport { exactValue } from '@regle/rules';\n\nconst exactCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n exactValue: exactValue(6),\n exactValue: exactValue(exactCount),\n exactValue: exactValue(() => exactCount.value)\n },\n})\n```\n\n## `file`\n\nRequires a value to be a native File constructor. Mainly used for typing.\n\n```ts\nimport { file } from '@regle/rules';\n\nconst rules = {\n file: { file },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `fileType`\n\nRequires a value to be a file with a specific type.\n\n```ts\nimport { fileType } from '@regle/rules';\n\nconst { r$ } = useRegle({ file: null as File | null }, {\n file: { fileType: fileType(['image/png', 'image/jpeg']) },\n})\n```\n\n## `hexadecimal`\n\nValidates hexadecimal values.\n\n```ts\nimport { hexadecimal } from '@regle/rules';\n\nconst { r$ } = useRegle({ hexadecimal: '' }, {\n hexadecimal: { hexadecimal },\n})\n```\n\n## `hostname`\n\nValidates hostnames.\n\n```ts\nimport { hostname } from '@regle/rules';\n\nconst { r$ } = useRegle({ siteHost: '' }, {\n siteHost: { hostname },\n})\n```\n\n## `httpUrl`\n\n_**Params**_\n- `options?: {protocol?: RegExp}`\n\nValidates HTTP URLs.\n\n```ts\nimport { httpUrl } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestUrl: '' }, {\n bestUrl: { httpUrl },\n // or with custom protocol validation\n bestUrl: { httpUrl: httpUrl({ protocol: /^https$/ }) },\n})\n```\n\n## `integer`\n\nAllows only integers (positive and negative).\n\n```ts\nimport { integer } from '@regle/rules';\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: { integer },\n})\n```\n\n## `ipv4Address`\n\nValidates IPv4 addresses in dotted decimal notation *127.0.0.1*.\n\n```ts\nimport { ipv4Address } from '@regle/rules';\n\nconst { r$ } = useRegle({ address: '' }, {\n address: { ipv4Address },\n})\n```\n\n## `literal`\n\nValidates literal values.\n\n### Note\n\nThis rule does not need `required` to be set, it will assert the value is set.\n\n```ts\nimport { literal } from '@regle/rules';\n\nconst { r$ } = useRegle({ value: '' }, {\n value: { literal: literal('foo') },\n})\n```\n\n## `lowercase`\n\nValidates lowercase strings.\n\n```ts\nimport { lowercase } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { lowercase },\n})\n```\n\n## `macAddress`\n\n_**Params**_\n - `separator?: string | Ref<string> | () => string`\n\nValidates MAC addresses. Call as a function to specify a custom separator (e.g., ':' or an empty string for 00ff1122334455).\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { macAddress } from '@regle/rules';\n\nconst { r$ } = useRegle({ address: '' }, {\n address: {\n macAddress,\n // or\n macAddress: macAddress('-')\n },\n});\n```\n\n## `maxFileSize`\n\nRequires a value to be a file with a maximum size.\n\n```ts\nimport { maxFileSize } from '@regle/rules';\n\nconst { r$ } = useRegle({ file: null as File | null }, {\n file: { maxFileSize: maxFileSize(10_000_000) }, // 10 MB\n})\n```\n\n## `maxLength`\n\n_**Params**_\n - `max: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\n_**Works with**_\n - `Array | Record | string | number`\n\nRequires the input value to have a maximum specified length, inclusive. Works with arrays, objects and strings.\n\n```ts\nimport { maxLength } from '@regle/rules';\n\nconst maxValue = ref(6);\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n maxLength: maxLength(6),\n maxLength: maxLength(maxValue),\n maxLength: maxLength(() => maxValue.value)\n },\n})\n```\n\n## `maxValue`\n\n_**Params**_\n - `min: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\n Requires a field to have a specified maximum numeric value.\n\n```ts\nimport { maxValue } from '@regle/rules';\n\nconst maxCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n maxValue: maxValue(6),\n maxValue: maxValue(maxCount, {allowEqual: false}),\n maxValue: maxValue(() => maxCount.value)\n },\n})\n```\n\n## `minFileSize`\n\nRequires a value to be a file with a minimum size.\n\n```ts\nimport { minFileSize } from '@regle/rules';\n\nconst { r$ } = useRegle({ file: null as File | null }, {\n file: { minFileSize: minFileSize(1_000_000) }, // 1 MB\n})\n```\n\n## `minLength`\n\n_**Params**_\n - `min: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\n_**Works with**_\n - `Array | Record | string | number`\n\nRequires the input value to have a minimum specified length, inclusive. Works with arrays, objects and strings.\n\n```ts\nimport { minLength } from '@regle/rules';\n\nconst minValue = ref(6);\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n minLength: minLength(6),\n minLength: minLength(minValue),\n minLength: minLength(() => minValue.value)\n },\n})\n```\n\n## `minValue`\n\n_**Params**_\n - `min: Ref<number> | number | () => number`\n - `options?: {allowEqual?: boolean}`\n\n_**Works with**_\n - `number`\n\nRequires a field to have a specified minimum numeric value.\n\n```ts\nimport { minValue } from '@regle/rules';\n\nconst minCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n minValue: minValue(6),\n minValue: minValue(minCount, {allowEqual: false}),\n minValue: minValue(() => minCount.value)\n },\n})\n```\n\n## `nativeEnum`\n\nValidate against a native Typescript enum value. Similar to Zod's `nativeEnum`\n\n```ts\nimport { nativeEnum } from '@regle/rules';\n\nenum Foo {\n Bar, Baz\n}\n\nconst { r$ } = useRegle({ type: '' }, {\n type: { nativeEnum: nativeEnum(Foo) },\n})\n```\n\n## `number`\n\nRequires a value to be a native number type. Mainly used for typing.\n\n```ts\nimport { number } from '@regle/rules';\n\nconst rules = {\n count: { number },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `numeric`\n\nAllows only numeric values (including numeric strings).\n\n```ts\nimport { numeric } from '@regle/rules';\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: { numeric },\n})\n```\n\n## `oneOf`\n\nAllow only one of the values from a fixed Array of possible entries.\n\n_**Params**_\n - `options: MaybeRefOrGetter<Array<string | number>>`\n\n```ts\nimport { oneOf } from '@regle/rules';\n\nconst { r$ } = useRegle({ aliment: 'Fish' }, {\n aliment: {\n oneOf: oneOf(['Fish', 'Meat', 'Bone'])\n },\n})\n```\n\n## `regex`\n\n_**Params**_\n- `regexps: MaybeRefOrGetter<RegExp | RegExp[]>`\n\nChecks if the value matches one or more regular expressions.\n\n```ts\nimport { regex } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n regex: regex(/^foo/),\n regex: regex([/^bar/, /baz$/]),\n },\n})\n```\n\n## `required`\n\nRequires non-empty data. Checks for empty arrays and strings containing only whitespaces.\n\n```ts\nimport {required} from '@regle/rules';\n\nconst {r$} = useRegle({name: ''}, {\n name: {required},\n})\n```\n\n## `requiredIf`\n\n_**Params**_\n - `condition: Ref<unknown> | unknown | () => unknown` - the property to base the `required` validator on.\n\nRequires non-empty data, only if provided data property, ref, or a function resolves to `true`.\n\n```ts\nimport { requiredIf } from '@regle/rules';\n\nconst form = ref({ name: '', condition: false });\n\nconst conditionRef = ref(false);\n\nconst { r$ } = useRegle(form, {\n name: {\n required: requiredIf(() => form.value.condition),\n required: requiredIf(conditionRef),\n },\n})\n```\n\n## `requiredUnless`\n\n_**Params**_\n - `condition: Ref<unknown> | unknown | () => unknown` - the property to base the `required` validator on.\n\nRequires non-empty data, only if provided data property, ref, or a function resolves to `false`.\n\n```ts\nimport { requiredUnless } from '@regle/rules';\n\nconst form = ref({ name: '', condition: false });\n\nconst conditionRef = ref(false);\n\nconst { r$ } = useRegle(form, {\n name: {\n required: requiredUnless(() => form.value.condition),\n required: requiredUnless(conditionRef)\n },\n})\n```\n\n## `sameAs`\n\n_**Params**_\n * `target: unknown`\n\nChecks if the value matches the specified property or ref.\n\n```ts\nimport { sameAs } from '@regle/rules';\n\nconst form = ref({\n password: '',\n confirmPassword: '',\n});\n\nconst { r$ } = useRegle(form, {\n confirmPassword: {\n sameAs: sameAs(() => form.value.password),\n }\n})\n```\n\n## `startsWith`\n\n_**Params**_\n- `start: Ref<string> | string | () => string`\n\nChecks if the string starts with the specified substring.\n\n```ts\nimport { startsWith } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestLib: '' }, {\n bestLib: {\n startsWith: startsWith('regle')\n },\n})\n```\n\n## `string`\n\nRequires a value to be a native string type. Mainly used for typing\n\n```ts\nimport {type InferInput} from '@regle/core';\nimport { string } from '@regle/rules';\n\nconst rules = {\n firstName: { string },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `type`\n\nDefine the input type of a rule. No runtime validation. \nOverride any input type set by other rules.\n\n```ts\nimport {type InferInput} from '@regle/core';\nimport { type } from '@regle/rules';\n\nconst rules = {\n firstName: { type: type<string>() },\n}\n\nconst state = ref<InferInput<typeof rules>>({});\n```\n\n## `uppercase`\n\nValidates uppercase strings.\n\n```ts\nimport { uppercase } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { uppercase },\n})\n```\n\n## `url`\n\n_**Params**_\n- `options?: {protocol?: RegExp}`\n\nValidates URLs.\n\n```ts\nimport { url } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestUrl: '' }, {\n bestUrl: { url },\n // or with custom protocol validation\n bestUrl: { url: url({ protocol: /^https?$/ }) },\n})\n```"
143
143
  },
144
144
  {
145
145
  "id": "core-concepts-rules-index",
@@ -167,7 +167,7 @@ var docs_data_default = {
167
167
  "title": "Rules operators",
168
168
  "category": "rules",
169
169
  "path": "core-concepts/rules/rules-operators.md",
170
- "content": "# Rules operators\n\nRegle provides tools to combine and operate on different rules. It includes the following built-in operators, available in `@regle/rules`:\n\n- `and`\n- `or`\n- `xor`\n- `not`\n- `applyIf`\n- `assignIf`\n- `pipe`\n\nThese operators work with any rules you provide, but combining rules with incompatible input types may lead to errors.\n\n:::tip\nAll operators are compatible with wrappers\n:::\n\n## `and`\n\nThe `and` operator combines multiple rules and validates successfully only if all provided rules are valid.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { and, startsWith, endsWith, withMessage } from '@regle/rules';\n\nconst { r$ } = useRegle(\n { regex: '' },\n {\n regex: {\n myError: withMessage(\n and(startsWith('^'), endsWith('$')),\n ({ $params: [start, end] }) =>\n `Regex should start with \"${start}\" and end with \"${end}\"`\n ),\n },\n }\n);\n```\n\nResult: \n\n## `or`\n\nThe `or` operator validates successfully if at least one of the provided rules is valid.\n\n```ts twoslash\nimport { useRegle } from '@regle/core';\nimport { or, startsWith, endsWith, withMessage } from '@regle/rules';\n\nconst { r$ } = useRegle(\n { regex: '' },\n {\n regex: {\n myError: withMessage(\n or(startsWith('^'), endsWith('$')),\n ({ $params: [start, end] }) =>\n `Field should start with \"${start}\" or end with \"${end}\"`\n ),\n },\n }\n);\n```\n\nResult: \n\n## `xor`\n\nThe `xor` operator (exclusive or) validates successfully if **exactly one** of the provided rules is valid. It fails when none or more than one rule passes.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { xor, contains, withMessage } from '@regle/rules';\n\nconst { r$ } = useRegle(\n { code: '' },\n {\n code: {\n myError: withMessage(\n xor(contains('A'), contains('B')),\n ({ $params: [charA, charB] }) =>\n `Field should contain either \"${charA}\" or \"${charB}\", but not both`\n ),\n },\n }\n);\n```\n\nResult: \n\n## `not`\n\nThe `not` operator passes when the provided rule fails and fails when the rule passes. It can be combined with other rules.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { not, required, sameAs, withMessage } from '@regle/rules';\nimport { ref } from 'vue';\n\nconst form = ref({ oldPassword: '', newPassword: '' });\nconst { r$ } = useRegle(form, {\n oldPassword: {\n required,\n },\n newPassword: {\n notEqual: withMessage(\n not(sameAs(() => form.value.oldPassword)),\n 'Your confirm new password must not be the same as your old password'\n ),\n },\n});\n```\n\nResult: \n\n## `applyIf`\n\nThe `applyIf` operator is similar to `requiredIf`, but it can be used with any rule. It simplifies conditional rule declarations.\n\n```ts\nimport { minLength, applyIf } from '@regle/rules';\n\nconst condition = ref(false);\n\nconst { r$ } = useRegle({name: ''}, {\n name: {\n minLength: applyIf(condition, minLength(6))\n },\n});\n```\n\n## `assignIf`\n\nThe `assignIf` is a shorthand for conditional destructuring assignment.\nIt allows to apply multiple rules to a field conditionally.\n\n```ts\nimport { required, email, minLength, assignIf } from '@regle/rules';\n\nconst condition = ref(false);\n\nconst { r$ } = useRegle(ref({ name: '', email: '' }), {\n name: assignIf(condition, { required, minLength: minLength(4) }),\n email: { email },\n});\n```\n\n## `pipe`\n\nThe `pipe` operator chains multiple rules together sequentially. Each rule only runs if all previous rules have passed. This is useful when you want to validate in a specific order and avoid running expensive validations (like async checks) until simpler ones pass.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { pipe, required, minLength, email } from '@regle/rules';\n\nconst { r$ } = useRegle(\n { email: '' },\n {\n email: pipe(required, minLength(5), email),\n }\n);\n// minLength only runs if required passes\n// email only runs if both required and minLength pass\n```\n\nResult: \n\n:::tip When to use `pipe` vs `and`\n- Use **`and`** when all rules should run simultaneously and you want all errors at once\n- Use **`pipe`** when rules should run sequentially and later rules depend on earlier ones passing (e.g., don't check email format until the field has enough characters)\n:::\n\nThe `pipe` operator also works with async rules. Subsequent rules will wait for async validators to complete before running:\n\n```ts\nimport { pipe, required, withAsync } from '@regle/rules';\n\nconst checkEmailAvailable = withAsync(async (value) => {\n const response = await fetch(`/api/check-email?email=${value}`);\n return response.ok;\n});\n\nconst { r$ } = useRegle(\n { email: '' },\n {\n email: pipe(required, email, checkEmailAvailable),\n }\n);\n// checkEmailAvailable only runs after required and email pass\n```\n\n### Debouncing async validators\n\nWhen using `pipe` with async validators, you can configure a debounce delay to prevent too many API calls while the user is typing. Use the array syntax with an options object as the second argument:\n\n```ts\nimport { pipe, required, email, withAsync } from '@regle/rules';\n\nconst checkEmailAvailable = withAsync(async (value) => {\n const response = await fetch(`/api/check-email?email=${value}`);\n return response.ok;\n});\n\nconst { r$ } = useRegle(\n { email: '' },\n {\n email: pipe(\n [required, email, checkEmailAvailable],\n { debounce: 300 } // Wait 300ms after last input before running async validators\n ),\n }\n);\n```\n\nThe debounce option only affects async validators in the pipe. Synchronous validators (`required`, `email` in the example above) run immediately, while the async validator (`checkEmailAvailable`) will be debounced.\n\n:::info Default debounce\nWhen using `pipe` with async validators, the default debounce delay is **200ms**. You can override this by passing a custom `debounce` value in the options.\n:::"
170
+ "content": "# Rules operators\n\nRegle provides tools to combine and operate on different rules. It includes the following built-in operators, available in `@regle/rules`:\n\n- `and`\n- `or`\n- `xor`\n- `not`\n- `applyIf`\n- `assignIf`\n- `pipe`\n\nThese operators work with any rules you provide, but combining rules with incompatible input types may lead to errors.\n\n:::tip\nAll operators are compatible with wrappers\n:::\n\n## `and`\n\nThe `and` operator combines multiple rules and validates successfully only if all provided rules are valid.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { and, startsWith, endsWith, withMessage } from '@regle/rules';\n\nconst { r$ } = useRegle(\n { regex: '' },\n {\n regex: {\n myError: withMessage(\n and(startsWith('^'), endsWith('$')),\n ({ $params: [start, end] }) =>\n `Regex should start with \"${start}\" and end with \"${end}\"`\n ),\n },\n }\n);\n```\n\nResult: \n\n## `or`\n\nThe `or` operator validates successfully if at least one of the provided rules is valid.\n\n```ts twoslash\nimport { useRegle } from '@regle/core';\nimport { or, startsWith, endsWith, withMessage } from '@regle/rules';\n\nconst { r$ } = useRegle(\n { regex: '' },\n {\n regex: {\n myError: withMessage(\n or(startsWith('^'), endsWith('$')),\n ({ $params: [start, end] }) =>\n `Field should start with \"${start}\" or end with \"${end}\"`\n ),\n },\n }\n);\n```\n\nResult: \n\n## `xor`\n\nThe `xor` operator (exclusive or) validates successfully if **exactly one** of the provided rules is valid. It fails when none or more than one rule passes.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { xor, contains, withMessage } from '@regle/rules';\n\nconst { r$ } = useRegle(\n { code: '' },\n {\n code: {\n myError: withMessage(\n xor(contains('A'), contains('B')),\n ({ $params: [charA, charB] }) =>\n `Field should contain either \"${charA}\" or \"${charB}\", but not both`\n ),\n },\n }\n);\n```\n\nResult: \n\n## `not`\n\nThe `not` operator passes when the provided rule fails and fails when the rule passes. It can be combined with other rules.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { not, required, sameAs, withMessage } from '@regle/rules';\nimport { ref } from 'vue';\n\nconst form = ref({ oldPassword: '', newPassword: '' });\nconst { r$ } = useRegle(form, {\n oldPassword: {\n required,\n },\n newPassword: {\n notEqual: withMessage(\n not(sameAs(() => form.value.oldPassword)),\n 'Your passwords must be different'\n ),\n },\n});\n```\n\nResult: \n\n## `applyIf`\n\nThe `applyIf` operator is similar to `requiredIf`, but it can be used with any rule. It simplifies conditional rule declarations.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { minLength, applyIf } from '@regle/rules';\nimport { ref } from 'vue';\n\nconst condition = ref(false);\n\nconst { r$ } = useRegle({name: ''}, {\n name: {\n minLength: applyIf(condition, minLength(6))\n },\n});\n```\n\nResult:\n\n## `assignIf`\n\nThe `assignIf` is a shorthand for conditional destructuring assignment.\nIt allows to apply multiple rules to a field conditionally.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { required, email, minLength, assignIf } from '@regle/rules';\nimport { ref } from 'vue';\n\nconst condition = ref(false);\n\nconst { r$ } = useRegle(ref({ name: '', email: '' }), {\n name: assignIf(condition, { required, minLength: minLength(4) }),\n email: { email },\n});\n```\n\nResult: \n\n## `pipe`\n\nThe `pipe` operator chains multiple rules together sequentially. Each rule only runs if all previous rules have passed. This is useful when you want to validate in a specific order and avoid running expensive validations (like async checks) until simpler ones pass.\n\n```ts\nimport { useRegle } from '@regle/core';\nimport { pipe, required, minLength, email } from '@regle/rules';\n\nconst { r$ } = useRegle(\n { email: '' },\n {\n email: pipe(required, minLength(5), email),\n }\n);\n// minLength only runs if required passes\n// email only runs if both required and minLength pass\n```\n\nResult: \n\n:::tip When to use `pipe` vs `and`\n- Use **`and`** when all rules should run simultaneously and you want all errors at once\n- Use **`pipe`** when rules should run sequentially and later rules depend on earlier ones passing (e.g., don't check email format until the field has enough characters)\n:::\n\nThe `pipe` operator also works with async rules. Subsequent rules will wait for async validators to complete before running:\n\n```ts\nimport { pipe, required, withAsync } from '@regle/rules';\n\nconst checkEmailAvailable = withAsync(async (value) => {\n const response = await fetch(`/api/check-email?email=${value}`);\n return response.ok;\n});\n\nconst { r$ } = useRegle(\n { email: '' },\n {\n email: pipe(required, email, checkEmailAvailable),\n }\n);\n// checkEmailAvailable only runs after required and email pass\n```\n\n### Debouncing async validators\n\nWhen using `pipe` with async validators, you can configure a debounce delay to prevent too many API calls while the user is typing. Use the array syntax with an options object as the second argument:\n\n```ts\nimport { pipe, required, email, withAsync } from '@regle/rules';\n\nconst checkEmailAvailable = withAsync(async (value) => {\n const response = await fetch(`/api/check-email?email=${value}`);\n return response.ok;\n});\n\nconst { r$ } = useRegle(\n { email: '' },\n {\n email: pipe(\n [required, email, checkEmailAvailable],\n { debounce: 300 } // Wait 300ms after last input before running async validators\n ),\n }\n);\n```\n\nResult:\n\nThe debounce option only affects async validators in the pipe. Synchronous validators (`required`, `email` in the example above) run immediately, while the async validator (`checkEmailAvailable`) will be debounced.\n\n:::info Default debounce\nWhen using `pipe` with async validators, the default debounce delay is **200ms**. You can override this by passing a custom `debounce` value in the options.\n:::"
171
171
  },
172
172
  {
173
173
  "id": "core-concepts-rules-rules-properties",
@@ -246,26 +246,33 @@ var docs_data_default = {
246
246
  "path": "examples/simple.md",
247
247
  "content": "# Simple demo\n\nYou can play with the code of this example in the stackblitz sandbox.\n\nDon't forgot to install the `Vue` extension in the online IDE.\n\n<a target='_blank' href=\"https://stackblitz.com/~/github.com/victorgarciaesgi/regle-examples/tree/main/examples/simple-example?file=examples/simple-example/src/App.vue&configPath=examples/simple-example\">\n <img\n alt=\"Open in StackBlitz\"\n src=\"https://developer.stackblitz.com/img/open_in_stackblitz.svg\"\n />\n</a>\n\n<iframe style='width: 100%; height: 700px' src=\"https://stackblitz.com/github/victorgarciaesgi/regle-examples/tree/main/examples/simple-example?embed=1&file=src%2FApp.vue&theme=dark&view=preview\" title=\"Sandbox editor\" sandbox=\"allow-modals allow-forms allow-popups allow-scripts allow-same-origin\"></iframe>"
248
248
  },
249
+ {
250
+ "id": "integrations-agent-skills",
251
+ "title": "Agent Skills",
252
+ "category": "integrations",
253
+ "path": "integrations/agent-skills.md",
254
+ "content": "# Agent Skills\n\n[Agent Skills](https://skills.sh/) are reusable capabilities for AI coding agents. They provide procedural knowledge that helps agents write Regle validation code more effectively.\n\nRegle provides three skills covering core usage, advanced patterns, and TypeScript integration.\n\n## Install\n\n```bash\nnpx skills add victorgarciaesgi/regle\n```\n\nThis installs all three Regle skills and configures them for your AI agent.\n\n## Available skills\n\n### `regle`\n\nCore Regle usage:\n\n- `useRegle` composable (state, rules, `r$` object)\n- Built-in validation rules (`required`, `email`, `minLength`, etc.)\n- Validation properties (`$invalid`, `$dirty`, `$error`, `$errors`, `$pending`)\n- Displaying errors (`getErrors`, `flatErrors`)\n- Modifiers (`autoDirty`, `lazy`, `silent`, `rewardEarly`, `validationGroups`)\n- Custom rules (`createRule`, inline rules, async rules)\n- Rule wrappers (`withMessage`, `withParams`, `withAsync`, `withTooltip`)\n- Rule operators (`and`, `or`, `not`, `pipe`, `applyIf`)\n\n### `regle-advanced`\n\nAdvanced patterns:\n\n- Collections (`$each`, array validation)\n- Async validation (`$pending`, debouncing)\n- Server errors (`externalErrors`, dot-path errors)\n- Reset forms (`$reset` options)\n- Global configuration (`defineRegleConfig`, i18n)\n- Variants (`createVariant`, `narrowVariant`, discriminated unions)\n- Scoped validation (`useScopedRegle`, `useCollectScope`)\n- Merge multiple Regles (`mergeRegles`)\n- Object self validation (`$self`)\n- Schema libraries (`useRegleSchema` with Zod, Valibot, ArkType)\n- Standard Schema spec (`useRules`, `refineRules`, `InferInput`)\n\n### `regle-typescript`\n\nTypeScript integration:\n\n- Type-safe output (`$validate` return type, `InferSafeOutput`)\n- Typing rules (`inferRules`, `RegleComputedRules`)\n- Typing component props (`InferRegleRoot`, `RegleFieldStatus`)"
255
+ },
249
256
  {
250
257
  "id": "integrations-mcp-server",
251
258
  "title": "Regle MCP server",
252
259
  "category": "integrations",
253
260
  "path": "integrations/mcp-server.md",
254
- "content": "# MCP Server\n\nRegle offers an MCP server that can be used to get documentation and autocomplete in your favorite AI assistant editor.\n\nThe MCP server provides the following features:\n\n- Create form validation rules\n- Search documentation\n- Get precise information on any rule\n- Create custom rules\n- API information on every Regle helper\n\n## Cursor\n\n<a href=\"https://cursor.com/en-US/install-mcp?name=regle&config=eyJjb21tYW5kIjoibnB4IEByZWdsZS9tY3Atc2VydmVyIn0%3D\">\n <div class=\"light-only\">\n <img src=\"https://cursor.com/deeplink/mcp-install-dark.svg\" alt=\"Install MCP Server\" />\n </div>\n <div class=\"dark-only\">\n <img src=\"https://cursor.com/deeplink/mcp-install-light.svg\" alt=\"Install MCP Server\" />\n </div>\n</a>\n\nOr add to your `.cursor/mcp.json`\n```json\n{\n \"mcpServers\": {\n \"regle\": {\n \"command\": \"npx\",\n \"args\": [\"@regle/mcp-server\"]\n }\n }\n}\n```\n\n## Claude Code\n\nFor Claude Code, run the following command:\n\n```bash\nclaude mcp add regle --scope project '{\"command\":\"npx\",\"args\":[\"-y\",\"@regle/mcp-server\"]}'\n```"
261
+ "content": "# MCP Server\n\n[MCP (Model Context Protocol)](https://modelcontextprotocol.io/) is an open standard that enables AI assistants to interact with external tools and data sources. \n\nRegle offers an MCP server that can be used to get documentation and autocomplete in your favorite AI assistant editor. This allows your AI assistant to understand Regle's API and help you write validation rules more effectively.\n\nThe MCP server provides the following features:\n\n- Create form validation rules\n- Search documentation\n- Get precise information on any rule\n- Create custom rules\n- API information on every Regle helper\n\n## Cursor\n\n<a href=\"https://cursor.com/en-US/install-mcp?name=regle&config=eyJjb21tYW5kIjoibnB4IEByZWdsZS9tY3Atc2VydmVyIn0%3D\">\n <div class=\"light-only\">\n <img src=\"https://cursor.com/deeplink/mcp-install-dark.svg\" alt=\"Install MCP Server\" />\n </div>\n <div class=\"dark-only\">\n <img src=\"https://cursor.com/deeplink/mcp-install-light.svg\" alt=\"Install MCP Server\" />\n </div>\n</a>\n\nOr add to your `.cursor/mcp.json`\n```json\n{\n \"mcpServers\": {\n \"regle\": {\n \"command\": \"npx\",\n \"args\": [\"@regle/mcp-server\"]\n }\n }\n}\n```\n\n## Claude Code\n\nFor Claude Code, run the following command:\n\n```bash\nclaude mcp add regle --scope project '{\"command\":\"npx\",\"args\":[\"-y\",\"@regle/mcp-server\"]}'\n```"
255
262
  },
256
263
  {
257
264
  "id": "integrations-nuxt",
258
265
  "title": "Nuxt",
259
266
  "category": "integrations",
260
267
  "path": "integrations/nuxt.md",
261
- "content": "# Nuxt <span data-title=\"nuxt\"></span>\n\nAdding the Nuxt module enables auto-imports for selected exports.\n\nRun the following command in your Nuxt application:\n\n```bash\nnpx nuxi module add regle\n```\n\nOr do it manually\n\n:::code-group\n<!-- ```bash [nuxt]\nnpx nuxi module add regle\n``` -->\n```sh [pnpm]\npnpm add @regle/core @regle/rules @regle/nuxt\n```\n\n```sh [npm]\nnpm install @regle/core @regle/rules @regle/nuxt\n```\n\n```sh [yarn]\nyarn add @regle/core @regle/rules @regle/nuxt\n```\n\n```sh [bun]\nbun add @regle/core @regle/rules @regle/nuxt\n```\n:::\n\nYou can then declare the module inside your `nuxt.config.ts`.\n\n```ts [nuxt.config.ts]\nexport default defineNuxtConfig({\n modules: ['@regle/nuxt']\n})\n```\n\n## `setupFile`\n\nThe Regle Nuxt module allow you to define a global configuration plugin to provide all your forms with the same translations, options and custom rules.\n\n```ts [nuxt.config.ts]\nexport default defineNuxtConfig({\n modules: ['@regle/nuxt'],\n regle: {\n setupFile: '~/regle-config.ts'\n }\n})\n```\n\n```ts [app/regle-config.ts]\nimport { defineRegleNuxtPlugin } from '@regle/nuxt/setup';\nimport { defineRegleConfig } from '@regle/core';\nimport { required, withMessage } from '@regle/rules';\n\nexport default defineRegleNuxtPlugin(() => {\n return defineRegleConfig({\n rules: () => {\n const {t} = useI18n();\n\n return {\n required: withMessage(required, t('general.required')),\n customRule: myCustomRule,\n }\n },\n });\n});\n\n```\n\nThis will inject the fellowing composables to your auto-imports and `#imports`, loaded with your custom error messages and rules: \n\n- `useRegle` \n- `inferRules` \n- `useCollectScope` \n- `useScopedRegle` \n- `type RegleFieldStatus`\n\n```vue [app.vue] {2}\n\n```\n\n## No options\n\nIf no setup file is provided, the following auto-imports will be added to your app.\n\n- `@regle/core`\n - useRegle \n - inferRules\n - createRule\n - defineRegleConfig\n - extendRegleConfig\n - createVariant\n - narrowVariant\n - useScopedRegle\n - useCollectScope\n \n- `@regle/rules` Note: Built-in rules are not auto-injected to minimize the risk of name conflicts.\n - withAsync\n - withMessage\n - withParams\n - withTooltip\n \n- `@regle/schemas` (if present)\n - useRegleSchema\n - inferSchema\n - withDeps\n - defineRegleSchemaConfig"
268
+ "content": "# Nuxt <span data-title=\"nuxt\"></span>\n\nAdding the Nuxt module enables auto-imports for selected exports.\n\nRun the following command in your Nuxt application:\n\n```bash\nnpx nuxi module add regle\n```\n\nOr do it manually\n\n:::code-group\n<!-- ```bash [nuxt]\nnpx nuxi module add regle\n``` -->\n```sh [pnpm]\npnpm add @regle/core @regle/rules @regle/nuxt\n```\n\n```sh [npm]\nnpm install @regle/core @regle/rules @regle/nuxt\n```\n\n```sh [yarn]\nyarn add @regle/core @regle/rules @regle/nuxt\n```\n\n```sh [bun]\nbun add @regle/core @regle/rules @regle/nuxt\n```\n:::\n\nYou can then declare the module inside your `nuxt.config.ts`.\n\n```ts [nuxt.config.ts]\nexport default defineNuxtConfig({\n modules: ['@regle/nuxt']\n})\n```\n\n## `setupFile`\n\nThe Regle Nuxt module allow you to define a global configuration plugin to provide all your forms with the same translations, options and custom rules.\n\n```ts [nuxt.config.ts]\nexport default defineNuxtConfig({\n modules: ['@regle/nuxt'],\n regle: {\n setupFile: '~/regle-config.ts'\n }\n})\n```\n\n```ts [app/regle-config.ts]\nimport { defineRegleNuxtPlugin } from '@regle/nuxt/setup';\nimport { defineRegleConfig } from '@regle/core';\nimport { required, withMessage } from '@regle/rules';\n\nexport default defineRegleNuxtPlugin(() => {\n return defineRegleConfig({\n rules: () => {\n const {t} = useI18n();\n\n return {\n required: withMessage(required, t('general.required')),\n customRule: myCustomRule,\n }\n },\n });\n});\n\n```\n\nThis will inject the following composables to your auto-imports and `#imports`, loaded with your custom error messages and rules: \n\n- `useRegle` \n- `inferRules` \n- `useCollectScope` \n- `useScopedRegle` \n- `type RegleFieldStatus`\n\n```vue [app.vue] {2}\n\n```\n\n## No options\n\nIf no setup file is provided, the following auto-imports will be added to your app.\n\n- `@regle/core`\n - useRegle \n - inferRules\n - createRule\n - defineRegleConfig\n - extendRegleConfig\n - createVariant\n - narrowVariant\n - useScopedRegle\n - useCollectScope\n \n- `@regle/rules` Note: Built-in rules are not auto-injected to minimize the risk of name conflicts.\n - withAsync\n - withMessage\n - withParams\n - withTooltip\n \n- `@regle/schemas` (if present)\n - useRegleSchema\n - inferSchema\n - withDeps\n - defineRegleSchemaConfig"
262
269
  },
263
270
  {
264
271
  "id": "integrations-schemas-libraries",
265
272
  "title": "Schemas libraries",
266
273
  "category": "integrations",
267
274
  "path": "integrations/schemas-libraries.md",
268
- "content": "# Schemas libraries (Zod, Valibot, ...)\n\nRegle supports the [Standard Schema Spec](https://standardschema.dev/).\n\nThis means any Standard Schema compliant RPC library can be used with Regle.\n\nOfficial list of supported libraries:\n\n- Zod [docs](https://zod.dev/) <span data-title=\"zod\"></span> `3.24+`. \n- Valibot [docs](https://valibot.dev/) <span data-title=\"valibot\"></span> `1+`.\n- ArkType [docs](https://arktype.io/) <span data-title=\"arktype\"></span> `2+`\n- Any library following the [Standard Schema Spec](https://standardschema.dev/) \n\n::: code-group\n```sh [pnpm]\npnpm add @regle/schemas\n```\n\n```sh [npm]\nnpm install @regle/schemas\n```\n\n```sh [yarn]\nyarn add @regle/schemas\n```\n\n```sh [bun]\nbun add @regle/schemas\n```\n:::\n\n## Usage\n\nInstead of using the core `useRegle`, use `useRegleSchema` export from `@regle/schemas`.\n\n:::code-group\n```ts [Zod]\nimport { useRegleSchema } from '@regle/schemas';\nimport { z } from 'zod';\n\nconst { r$ } = useRegleSchema({ name: '' }, z.object({\n name: z.string().min(1)\n}))\n```\n\n```ts [Valibot]\nimport { useRegleSchema } from '@regle/schemas';\nimport * as v from 'valibot';\n\nconst { r$ } = useRegleSchema({ name: '' }, v.object({\n name: v.pipe(v.string(), v.minLength(3))\n}))\n```\n\n```ts [ArkType]\nimport { useRegleSchema } from '@regle/schemas';\nimport { type } from 'arktype';\n\nconst { r$ } = useRegleSchema({ name: '' }, type({\n name: \"string > 1\"\n}))\n```\n\n:::\n\n:::warning\nLimitations from the core behaviour\n\nUsing 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:\n\n- `$validate` (only at root)\n- `$pending` (only at root)\n\nOne other limitation is you won't have access to any children `$rules`, so checking if a field is required with `xx.$rules.required.active` is not possible with schemas.\n:::\n\n## Computed schema\n\nYou can also have a computed schema that can be based on other state values.\n\n:::warning\nWhen doing refinements or transform, Vue can't track what the schema depends on because you're in a function callback. \n\nSame way as `withParams` from `@regle/rules`, you can use the `withDeps` helper to force dependencies on any schema\n:::\n\n:::code-group\n\n```ts [Zod]\nimport { useRegleSchema, inferSchema, withDeps } from '@regle/schemas';\nimport { z } from 'zod';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() =>\n inferSchema(form, z.object({\n firstName: z.string(),\n /** \n * Important to keep track of the depency change\n * Without it, the validator wouldn't run if `firstName` changed\n */\n lastName: withDeps(\n z.string().refine((v) => v !== form.value.firstName, {\n message: \"Last name can't be equal to first name\",\n }),\n [() => form.value.firstName]\n ),\n }))\n);\n\nconst { r$ } = useRegleSchema(form, schema);\n\n```\n```ts [Valibot]\nimport { useRegleSchema, inferSchema, withDeps} from '@regle/schemas';\nimport * as v from 'valibot';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() => \n inferSchema(form, v.object({\n firstName: v.string(),\n /** \n * Important to keep track of the depency change\n * Without it, the validator wouldn't run if `firstName` changed\n */\n lastName: withDeps(\n v.pipe(\n v.string(),\n v.check((v) => v !== form.value.firstName, \"Last name can't be equal to first name\")\n ),\n [() => form.value.firstName]\n ),\n }))\n)\n\nconst { r$ } = useRegleSchema(form, schema);\n\n```\n\n:::\n\n## `syncState`\n\nBy default, Regle doesn't allow any transforms on the state. \n\nModifiers like `default`, `catch` or `transform` will not impact the validation.\n\nIf you want to allow the schema to update your form state you can use the `syncState` option. \nThe state will only be pacthed is the parse is successful.\n\n```ts\ntype RegleSchemaBehaviourOptions = {\n syncState?: {\n /**\n * Applies every transform on every update to the state\n */\n onUpdate?: boolean;\n /**\n * Applies every transform only when calling `$validate`\n */\n onValidate?: boolean;\n };\n};\n```\n\nUsage:\n\n```vue\n\n```\n\n## Type safe output\n\nSimilar to the main `useRegle` composable, `r$.$validate` also returns a type-safe output using Zod type schema parser.\n\n:::code-group\n```ts [Zod]\nimport { useRegleSchema, inferSchema } from '@regle/schemas';\nimport { z } from 'zod';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() => inferSchema(form, z.object({\n firstName: z.string().optional(),\n lastName: z.string().min(1).refine(v => v !== form.value.firstName, {\n message: \"Last name can't be equal to first name\"\n }),\n})))\n\nconst { r$ } = useRegleSchema(form, schema);\n\nasync function submit() {\n const { valid, data } = await r$.$validate();\n if (valid) {\n console.log(data);\n }\n}\n\n```\n\n```ts [Valibot]\nimport { useRegleSchema, inferSchema } from '@regle/schemas';\nimport * as v from 'valibot';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() => {\n return inferSchema(form, v.object({\n firstName: v.optional(v.string()),\n lastName: v.pipe(\n v.string(),\n v.minLength(3),\n v.check((v) => v !== form.value.firstName, \"Last name can't be equal to first name\")\n )\n }))\n})\n\nconst { r$ } = useRegleSchema(form, schema);\n\nasync function submit() {\n const { valid, data } = await r$.$validate();\n if (valid) {\n console.log(data);\n }\n}\n\n```\n\n```ts [ArkType]\nimport { useRegleSchema, inferSchema } from '@regle/schemas';\nimport { type } from 'arktype';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() => {\n return inferSchema(form, type({\n 'firstName?': 'string',\n lastName: 'string > 3',\n }).narrow((data, ctx) => {\n if (data.firstName !== data.lastName) {\n return true;\n }\n return ctx.reject({\n expected: 'different than firstName',\n path: ['lastName'],\n });\n }))\n})\n\nconst { r$ } = useRegleSchema(form, schema);\n\nasync function submit() {\n const { valid, data } = await r$.$validate();\n if (valid) {\n console.log(data);\n }\n}\n```\n:::"
275
+ "content": "# Schemas libraries (Zod, Valibot, ...)\n\nRegle supports the [Standard Schema Spec](https://standardschema.dev/).\n\nThis means any Standard Schema compliant RPC library can be used with Regle.\n\nOfficial list of supported libraries:\n\n- Zod [docs](https://zod.dev/) <span data-title=\"zod\"></span> `3.24+`. \n- Valibot [docs](https://valibot.dev/) <span data-title=\"valibot\"></span> `1+`.\n- ArkType [docs](https://arktype.io/) <span data-title=\"arktype\"></span> `2+`\n- Any library following the [Standard Schema Spec](https://standardschema.dev/) \n\n::: code-group\n```sh [pnpm]\npnpm add @regle/schemas\n```\n\n```sh [npm]\nnpm install @regle/schemas\n```\n\n```sh [yarn]\nyarn add @regle/schemas\n```\n\n```sh [bun]\nbun add @regle/schemas\n```\n:::\n\n## Usage\n\nInstead of using the core `useRegle`, use `useRegleSchema` export from `@regle/schemas`.\n\n:::code-group\n```ts [Zod]\nimport { useRegleSchema } from '@regle/schemas';\nimport { z } from 'zod';\n\nconst { r$ } = useRegleSchema({ name: '' }, z.object({\n name: z.string().min(1)\n}))\n```\n\n```ts [Valibot]\nimport { useRegleSchema } from '@regle/schemas';\nimport * as v from 'valibot';\n\nconst { r$ } = useRegleSchema({ name: '' }, v.object({\n name: v.pipe(v.string(), v.minLength(3))\n}))\n```\n\n```ts [ArkType]\nimport { useRegleSchema } from '@regle/schemas';\nimport { type } from 'arktype';\n\nconst { r$ } = useRegleSchema({ name: '' }, type({\n name: \"string > 1\"\n}))\n```\n\n:::\n\n:::warning\nLimitations from the core behaviour\n\nUsing 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:\n\n- `$validate` (only at root)\n- `$pending` (only at root)\n\nOne other limitation is you won't have access to any children `$rules`, so checking if a field is required with `xx.$rules.required.active` is not possible with schemas.\n:::\n\n## Computed schema\n\nYou can also have a computed schema that can be based on other state values.\n\n:::warning\nWhen doing refinements or transform, Vue can't track what the schema depends on because you're in a function callback. \n\nSame way as `withParams` from `@regle/rules`, you can use the `withDeps` helper to force dependencies on any schema\n:::\n\n:::code-group\n\n```ts [Zod]\nimport { useRegleSchema, inferSchema, withDeps } from '@regle/schemas';\nimport { z } from 'zod';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() =>\n inferSchema(form, z.object({\n firstName: z.string(),\n /** \n * Important to keep track of the depency change\n * Without it, the validator wouldn't run if `firstName` changed\n */\n lastName: withDeps(\n z.string().refine((v) => v !== form.value.firstName, {\n message: \"Last name can't be equal to first name\",\n }),\n [() => form.value.firstName]\n ),\n }))\n);\n\nconst { r$ } = useRegleSchema(form, schema);\n\n```\n```ts [Valibot]\nimport { useRegleSchema, inferSchema, withDeps} from '@regle/schemas';\nimport * as v from 'valibot';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() => \n inferSchema(form, v.object({\n firstName: v.string(),\n /** \n * Important to keep track of the depency change\n * Without it, the validator wouldn't run if `firstName` changed\n */\n lastName: withDeps(\n v.pipe(\n v.string(),\n v.check((v) => v !== form.value.firstName, \"Last name can't be equal to first name\")\n ),\n [() => form.value.firstName]\n ),\n }))\n)\n\nconst { r$ } = useRegleSchema(form, schema);\n\n```\n\n:::\n\n## `syncState`\n\nBy default, Regle doesn't allow any transforms on the state. \n\nModifiers like `default`, `catch` or `transform` will not impact the validation.\n\nIf you want to allow the schema to update your form state you can use the `syncState` option. \nThe state will only be patched is the parse is successful.\n\n```ts\ntype RegleSchemaBehaviourOptions = {\n syncState?: {\n /**\n * Applies every transform on every update to the state\n */\n onUpdate?: boolean;\n /**\n * Applies every transform only when calling `$validate`\n */\n onValidate?: boolean;\n };\n};\n```\n\nUsage:\n\n```vue\n\n```\n\n## Type safe output\n\nSimilar to the main `useRegle` composable, `r$.$validate` also returns a type-safe output using Zod type schema parser.\n\n:::code-group\n```ts [Zod]\nimport { useRegleSchema, inferSchema } from '@regle/schemas';\nimport { z } from 'zod';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() => inferSchema(form, z.object({\n firstName: z.string().optional(),\n lastName: z.string().min(1).refine(v => v !== form.value.firstName, {\n message: \"Last name can't be equal to first name\"\n }),\n})))\n\nconst { r$ } = useRegleSchema(form, schema);\n\nasync function submit() {\n const { valid, data } = await r$.$validate();\n if (valid) {\n console.log(data);\n }\n}\n\n```\n\n```ts [Valibot]\nimport { useRegleSchema, inferSchema } from '@regle/schemas';\nimport * as v from 'valibot';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() => {\n return inferSchema(form, v.object({\n firstName: v.optional(v.string()),\n lastName: v.pipe(\n v.string(),\n v.minLength(3),\n v.check((v) => v !== form.value.firstName, \"Last name can't be equal to first name\")\n )\n }))\n})\n\nconst { r$ } = useRegleSchema(form, schema);\n\nasync function submit() {\n const { valid, data } = await r$.$validate();\n if (valid) {\n console.log(data);\n }\n}\n\n```\n\n```ts [ArkType]\nimport { useRegleSchema, inferSchema } from '@regle/schemas';\nimport { type } from 'arktype';\nimport { ref, computed } from 'vue';\n\ntype Form = {\n firstName?: string;\n lastName?: string\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst schema = computed(() => {\n return inferSchema(form, type({\n 'firstName?': 'string',\n lastName: 'string > 3',\n }).narrow((data, ctx) => {\n if (data.firstName !== data.lastName) {\n return true;\n }\n return ctx.reject({\n expected: 'different than firstName',\n path: ['lastName'],\n });\n }))\n})\n\nconst { r$ } = useRegleSchema(form, schema);\n\nasync function submit() {\n const { valid, data } = await r$.$validate();\n if (valid) {\n console.log(data);\n }\n}\n```\n:::"
269
276
  },
270
277
  {
271
278
  "id": "introduction-comparisons",
@@ -279,21 +286,21 @@ var docs_data_default = {
279
286
  "title": "Devtools",
280
287
  "category": "introduction",
281
288
  "path": "introduction/devtools.md",
282
- "content": "# Regle Devtools\n\nRegle offers a devtools extension for [Vue Devtools](https://devtools.vuejs.org/) to help you debug your validation tree.\n\n![Regle Devtools Screenshot](/screenshots/devtools.png)\n\n## Installation\n\nTo enable devtools, you need to install the Regle plugin in your app.\n\n:::tip\nIf you use the `@regle/nuxt` module, the devtools will be automatically enabled.\n:::\n\n```ts [main.ts]\nimport { createApp } from 'vue';\nimport App from './App.vue';\nimport { RegleVuePlugin } from '@regle/core';\n\nconst app = createApp(App);\n\napp.use(RegleVuePlugin); // <--\n\napp.mount('#app');\n```\n\n## Usage\n\nRegle devtools can inspect every variation of `useRegle`:\n\n- `useRegle`\n- `useRules`\n- `useRegleSchema`\n- `useScopedRegle`\n- `useScopedRegleSchema`\n\nYou can inspect every nested properties and rules of the `r$` instance.\n\n:::warning\nRules details inspection is not available for `useRegleSchema`\n:::\n\n### Actions\n\nYou can perform actions on the `r$` instance by clicking on the actions buttons in the devtools.\n\n![Devtools Actions Screenshot](/screenshots/devtools-actions.png)\n\n- Validate: Validate the `r$` instance (with `$validate` method)\n- Reset validation state: Reset the validation state of the `r$` instance (with `$reset` method)\n- Restore to original state: Restore the `r$` instance to the original state (with `$reset` method)\n\n## Providing custom `r$` ids to devtools\n\nBy default, the devtools will use a generic name to display the `r$` instance. \n\nYou can provide a custom name to the `useRegle` composable to display a more descriptive name in the devtools.\n\n```ts [App.vue]\nimport { useRegle } from '@regle/core';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { required }\n}, {\n id: 'my-form'\n});\n```\n\n## Devtools demo\n\nYou can go in any of the [Stablitz exemples](/examples/index) and open the devtools by clicking on the <span data-title=\"vue\"></span> \"Open Devtools\" button in the bottom middle of the page.\n\n### Vite Devtools Integration\n\nRegle devtools also integrate cleanly with [Vite](https://vitejs.dev/) when you're running your app in development mode.\n\nYou should see the Regle panel show up automatically in the Vite devtools if you've installed the plugin correctly.\n\n<img src=\"/screenshots/vite-devtools.png\" alt=\"Vite Devtools with Regle panel\" width=\"100\"/>\n\nYou will see the Regle icon showing in the devtools. Just click on it!\n\n<img src=\"/screenshots/vite-devtools-regle.png\" alt=\"Vite Devtools with Regle panel\" />"
289
+ "content": "# Regle Devtools\n\nRegle offers a devtools extension for [Vue Devtools](https://devtools.vuejs.org/) to help you debug your validation tree.\n\n![Regle Devtools Screenshot](/screenshots/devtools.png)\n\n## Installation\n\nTo enable devtools, you need to install the Regle plugin in your app.\n\n:::tip\nIf you use the `@regle/nuxt` module, the devtools will be automatically enabled.\n:::\n\n```ts [main.ts]\nimport { createApp } from 'vue';\nimport App from './App.vue';\nimport { RegleVuePlugin } from '@regle/core';\n\nconst app = createApp(App);\n\napp.use(RegleVuePlugin); // <--\n\napp.mount('#app');\n```\n\n## Usage\n\nRegle devtools can inspect every variation of `useRegle`:\n\n- `useRegle`\n- `useRules`\n- `useRegleSchema`\n- `useScopedRegle`\n- `useScopedRegleSchema`\n\nYou can inspect every nested properties and rules of the `r$` instance.\n\n:::warning\nRules details inspection is not available for `useRegleSchema`\n:::\n\n### Actions\n\nYou can perform actions on the `r$` instance by clicking on the actions buttons in the devtools.\n\n![Devtools Actions Screenshot](/screenshots/devtools-actions.png)\n\n- Validate: Validate the `r$` instance (with `$validate` method)\n- Reset validation state: Reset the validation state of the `r$` instance (with `$reset` method)\n- Restore to original state: Restore the `r$` instance to the original state (with `$reset` method)\n\n## Providing custom `r$` ids to devtools\n\nBy default, the devtools will use a generic name to display the `r$` instance. \n\nYou can provide a custom name to the `useRegle` composable to display a more descriptive name in the devtools.\n\n```ts [App.vue]\nimport { useRegle } from '@regle/core';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: { required }\n}, {\n id: 'my-form'\n});\n```\n\n## Devtools demo\n\nYou can go in any of the [StackBlitz examples](/examples/index) and open the devtools by clicking on the <span data-title=\"vue\"></span> \"Open Devtools\" button in the bottom middle of the page.\n\n### Vite Devtools Integration\n\nRegle devtools also integrate cleanly with [Vite](https://vitejs.dev/) when you're running your app in development mode.\n\nYou should see the Regle panel show up automatically in the Vite devtools if you've installed the plugin correctly.\n\n<img src=\"/screenshots/vite-devtools.png\" alt=\"Vite Devtools with Regle panel\" width=\"100\"/>\n\nYou will see the Regle icon showing in the devtools. Just click on it!\n\n<img src=\"/screenshots/vite-devtools-regle.png\" alt=\"Vite Devtools with Regle panel\" />"
283
290
  },
284
291
  {
285
292
  "id": "introduction-index",
286
293
  "title": "Introduction",
287
294
  "category": "introduction",
288
295
  "path": "introduction/index.md",
289
- "content": "# Introduction\n\n## What is Regle?\n\nIf you've ever built a forms and wrote repetitive validation logic, struggling with complex error states, or losing type safety along the way, Regle is the perfect solution.\n\nRegle is a type-safe, headless form validation library that lets you write validation rules that mirror your data structure. Think of it as the perfect evolution of Vuelidate, but with modern TypeScript support and a more intuitive API.\n\n## Why Choose Regle?\n\n- **🔒 Type Safe**: Full TypeScript inference means autocomplete everywhere and catch errors at compile time\n- **🌳 Model-Based**: Your validation tree matches your data model—no mental gymnastics required \n- **🔌 Headless**: Works with any UI framework, CSS library, or design system\n- **🔍 Devtools**: Built-in Vue devtools extention for easy debugging and testing.\n- **📦 Modular**: Use built-in rules or create custom ones that fit your exact needs\n- **⚡ Performance**: Efficient reactivity system that only updates what changed\n- **🛠 Developer Experience**: If you've used Vuelidate, you'll feel right at home\n\n## Basic example\n\nHere's a real form that you can copy and use right away:\n\nFrom `r$`, you can build any UI you want. The validation logic is completely separate from your presentation layer.\n\n**Live Result:**\n\n## What's Next?\n\nReady to dive deeper? Here's your learning path:\n\n1. **[Installation](/introduction/installation)** - Get Regle set up in your project\n2. **[Core Concepts](/core-concepts/)** - Understand how `useRegle` works\n3. **[Built-in Rules](/core-concepts/rules/built-in-rules)** - Explore all available validation rules\n4. **[Examples](/examples/simple)** - See Regle in action with real-world scenarios\n\n:::tip Coming from Vuelidate?\nRegle's API is intentionally similar to Vuelidate's. Check out our [comparison guide](/introduction/comparisons#vuelidate) to see what's changed and what's stayed the same.\n:::"
296
+ "content": "# Introduction\n\n## What is Regle?\n\nIf you've ever built a forms and wrote repetitive validation logic, struggling with complex error states, or losing type safety along the way, Regle is the perfect solution.\n\nRegle is a type-safe, headless form validation library that lets you write validation rules that mirror your data structure. Think of it as the perfect evolution of Vuelidate, but with modern TypeScript support and a more intuitive API.\n\n## Why Choose Regle?\n\n- **🔒 Type Safe**: Full TypeScript inference means autocomplete everywhere and catch errors at compile time\n- **🌳 Model-Based**: Your validation tree matches your data model—no mental gymnastics required \n- **🔌 Headless**: Works with any UI framework, CSS library, or design system\n- **🔍 Devtools**: Built-in Vue devtools extension for easy debugging and testing.\n- **📦 Modular**: Use built-in rules or create custom ones that fit your exact needs\n- **⚡ Performance**: Efficient reactivity system that only updates what changed\n- **🛠 Developer Experience**: If you've used Vuelidate, you'll feel right at home\n\n## Basic example\n\nHere's a real form that you can copy and use right away:\n\nFrom `r$`, you can build any UI you want. The validation logic is completely separate from your presentation layer.\n\n**Live Result:**\n\n## What's Next?\n\nReady to dive deeper? Here's your learning path:\n\n1. **[Installation](/introduction/installation)** - Get Regle set up in your project\n2. **[Core Concepts](/core-concepts/)** - Understand how `useRegle` works\n3. **[Built-in Rules](/core-concepts/rules/built-in-rules)** - Explore all available validation rules\n4. **[Examples](/examples/simple)** - See Regle in action with real-world scenarios\n\n:::tip Coming from Vuelidate?\nRegle's API is intentionally similar to Vuelidate's. Check out our [comparison guide](/introduction/comparisons#vuelidate) to see what's changed and what's stayed the same.\n:::"
290
297
  },
291
298
  {
292
299
  "id": "introduction-installation",
293
300
  "title": "Installation",
294
301
  "category": "introduction",
295
302
  "path": "introduction/installation.md",
296
- "content": "# Installation\n\n## Prerequisites\n\nRequired\n- [Vue](https://vuejs.org/) <span data-title=\"vue\"></span> `3.3+`.\n- [Typescript](https://www.typescriptlang.org/) <span data-title=\"ee.ts\"></span> `5.1+`. \n - Compatible with plain javascript.\n- Text Editor with Vue syntax support.\n - [VSCode](https://code.visualstudio.com/) <span data-title=\".vscode\"></span> is recommended, along with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar).\n\nOptional\n- [Nuxt](https://nuxt.com/) <span data-title=\"nuxt\"></span> \n - Nuxt `3.2.0+`, and check docs for [Nuxt module](/integrations/nuxt)\n- [Pinia](https://pinia.vuejs.org/) <span data-title=\"pinia\"></span> \n - Pinia `2.2.5+`\n\nSchema libraries: [Docs](/integrations/schemas-libraries)\n\n- [Zod](https://zod.dev/) <span data-title=\"zod\"></span> `3.24+`. \n- [Valibot](https://valibot.dev/) <span data-title=\"valibot\"></span> `1+`.\n- [ArkType](https://arktype.io/) <span data-title=\"arktype\"></span> `2+`\n- Any library using the [Standard Schema Spec](https://standardschema.dev/) \n\n<br/>\n\n::: code-group\n\n```sh [pnpm]\npnpm add @regle/core @regle/rules\n```\n\n```sh [npm]\nnpm install @regle/core @regle/rules\n```\n\n```sh [yarn]\nyarn add @regle/core @regle/rules\n```\n\n```sh [bun]\nbun add @regle/core @regle/rules\n```\n\n:::\n\n## Devtools\n\nTo enable devtools, you need to install the Regle plugin in your app.\n\n:::tip\nIf you use the `@regle/nuxt` module, the devtools will be automatically enabled.\n:::\n\n```ts [main.ts]\nimport { createApp } from 'vue';\nimport { RegleVuePlugin } from '@regle/core';\nimport App from './App.vue';\n\nconst app = createApp(App);\n\napp.use(RegleVuePlugin); // <--\n\napp.mount('#app');\n```\n\n## MCP server\n\nRegle offers an MCP server that can be used to get documentation and autocomplete for Regle.\n\nYou can install it using the following configurations:\n\n- [Cursor](/integrations/mcp-server#cursor)\n- [Claude Desktop](/integrations/mcp-server#claude-desktop)"
303
+ "content": "# Installation\n\n## Prerequisites\n\nRequired\n- [Vue](https://vuejs.org/) <span data-title=\"vue\"></span> `3.4+`.\n- [Typescript](https://www.typescriptlang.org/) <span data-title=\"ee.ts\"></span> `5.1+`. \n - Compatible with plain javascript.\n- Text Editor with Vue syntax support.\n - [VSCode](https://code.visualstudio.com/) <span data-title=\".vscode\"></span> is recommended, along with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar).\n\nOptional\n- [Nuxt](https://nuxt.com/) <span data-title=\"nuxt\"></span> \n - Nuxt `3.2.0+`, and check docs for [Nuxt module](/integrations/nuxt)\n- [Pinia](https://pinia.vuejs.org/) <span data-title=\"pinia\"></span> \n - Pinia `2.2.5+`\n\nSchema libraries: [Docs](/integrations/schemas-libraries)\n\n- [Zod](https://zod.dev/) <span data-title=\"zod\"></span> `3.24+`. \n- [Valibot](https://valibot.dev/) <span data-title=\"valibot\"></span> `1+`.\n- [ArkType](https://arktype.io/) <span data-title=\"arktype\"></span> `2+`\n- Any library using the [Standard Schema Spec](https://standardschema.dev/) \n\n<br/>\n\n::: code-group\n\n```sh [pnpm]\npnpm add @regle/core @regle/rules\n```\n\n```sh [npm]\nnpm install @regle/core @regle/rules\n```\n\n```sh [yarn]\nyarn add @regle/core @regle/rules\n```\n\n```sh [bun]\nbun add @regle/core @regle/rules\n```\n\n:::\n\n## Devtools\n\nTo enable devtools, you need to install the Regle plugin in your app.\n\n:::tip\nIf you use the `@regle/nuxt` module, the devtools will be automatically enabled.\n:::\n\n```ts [main.ts]\nimport { createApp } from 'vue';\nimport { RegleVuePlugin } from '@regle/core';\nimport App from './App.vue';\n\nconst app = createApp(App);\n\napp.use(RegleVuePlugin); // <--\n\napp.mount('#app');\n```\n\nYou can provide options to the RegleVuePlugin to customize global config.\nSee [Global configuration](/advanced-usage/global-config#declarative) for more details.\n\n## MCP server\n\nRegle offers an MCP server that can be used to get documentation and autocomplete for Regle.\n\nYou can install it using the following configurations:\n\n- [Cursor](/integrations/mcp-server#cursor)\n- [Claude Desktop](/integrations/mcp-server#claude-desktop)"
297
304
  },
298
305
  {
299
306
  "id": "introduction-migrate-from-vuelidate",
@@ -314,14 +321,14 @@ var docs_data_default = {
314
321
  "title": "Type safe output",
315
322
  "category": "typescript",
316
323
  "path": "typescript/type-safe-output.md",
317
- "content": "# Type safe output\n\nWhat would be the benefit of building a validation library without a type safe output?\n\nInspired by the `Zod` parse output type, `Regle` will also infer your validator types to know which properties are _**guaranteed**_ to be defined.\n\n## `$validate` \n\nUsing `r$.$validate` will asynchronously run and wait for all your validators to finish, and will return an object containing the status of your form.\n\n```ts\nconst { valid, data, errors, issues } = await r$.$validate();\n```\n\nIf your *_result_* is `true`, the **data** will be type safe.\n\nIt will check the rules to get the ones that ensure the value is set (`required`, `literal`, `checked`)\n\nTt will not work with `requiredIf` or `requiredUnless`, because we can't know the condition at build time.\n\n```ts twoslash\nimport { useRegle } from '@regle/core';\nimport { ref, type Ref, computed } from 'vue';\nimport { required } from '@regle/rules';\n// ---cut---\ntype Form = {\n firstName?: string;\n lastName?: string;\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst { r$ } = useRegle(form, {\n lastName: { required },\n});\n\nasync function submit() {\n const { valid, data, errors, issues } = await r$.$validate();\n\n if (valid) {\n console.log(data);\n \n }\n}\n```\n\n<br/>\n\n### `InferSafeOutput`\n\nYou can also statically infer the safe output from any `r$` instance.\n\n```ts twoslash\nimport { ref, type Ref, computed } from 'vue';\nimport { required } from '@regle/rules';\n// ---cut---\nimport { useRegle, InferSafeOutput } from '@regle/core';\ntype Form = {\n firstName?: string;\n lastName?: string;\n}\n\nconst form: Ref<Form> = ref({ firstName: '', lastName: '' })\n\nconst { r$ } = useRegle(form, {\n lastName: { required },\n});\n\ntype FormRequest = InferSafeOutput<typeof r$>;\n\n```"
324
+ "content": "# Type safe output\n\nWhat would be the benefit of building a validation library without a type safe output?\n\nInspired by the `Zod` parse output type, `Regle` will also infer your validator types to know which properties are _**guaranteed**_ to be defined.\n\n## `$validate` \n\nUsing `r$.$validate` will asynchronously run and wait for all your validators to finish, and will return an object containing the status of your form.\n\n```ts\nconst { valid, data, errors, issues } = await r$.$validate();\n```\n\nIf your *_result_* is `true`, the **data** will be type safe.\n\nIt will check the rules to get the ones that ensure the value is set (`required`, `literal`, `checked`)\n\nIt will not work with `requiredIf` or `requiredUnless`, because we can't know the condition at build time.\n\n```ts twoslash\nimport { useRegle } from '@regle/core';\nimport { ref, type Ref, computed } from 'vue';\nimport { required } from '@regle/rules';\n// ---cut---\ntype Form = {\n firstName?: string;\n lastName?: string;\n}\n\nconst form = ref<Form>({ firstName: '', lastName: '' })\n\nconst { r$ } = useRegle(form, {\n lastName: { required },\n});\n\nasync function submit() {\n const { valid, data, errors, issues } = await r$.$validate();\n\n if (valid) {\n console.log(data);\n \n }\n}\n```\n\n<br/>\n\n### `InferSafeOutput`\n\nYou can also statically infer the safe output from any `r$` instance.\n\n```ts twoslash\nimport { ref, type Ref, computed } from 'vue';\nimport { required } from '@regle/rules';\n// ---cut---\nimport { useRegle, InferSafeOutput } from '@regle/core';\ntype Form = {\n firstName?: string;\n lastName?: string;\n}\n\nconst form: Ref<Form> = ref({ firstName: '', lastName: '' })\n\nconst { r$ } = useRegle(form, {\n lastName: { required },\n});\n\ntype FormRequest = InferSafeOutput<typeof r$>;\n\n```"
318
325
  },
319
326
  {
320
327
  "id": "typescript-typing-props",
321
328
  "title": "Typing props",
322
329
  "category": "typescript",
323
330
  "path": "typescript/typing-props.md",
324
- "content": "# Typing props\n\nForms often span multiple components, and splitting your logic across components is a common practice. Regle offers tools to help type your props correctly, ensuring type safety and improving developer experience.\n\nThe best way to manage a centralized form state with inferred types is by using a Pinia store. Learn more in the Usage with Pinia guide [explained here](/common-usage/usage-with-pinia).\n\nIf you cannot use Pinia, here are the alternative approaches.\n\n## Typing component props\n\nAs Regle's types are complex and based on both your state and your rules, it's hard to replicate manually.\n\n`@regle/core` exports all its utility types, it can be long to explain each one of them, so we'll show the simplest way to type your props.\n\nTo avoid juggling with complex generic types, you can declare your form in a composable inside a file outside your component, and use this composable to type your props.\n\n:::code-group\n\n```ts twoslash include useMyForm [useMyForm.ts]\nimport { useRegle } from '@regle/core';\nimport { email, maxValue, minLength, numeric, required } from '@regle/rules';\n\nexport function useMyForm() {\n return useRegle(\n { email: '', user: { firstName: '', lastName: '' } },\n {\n email: { required, email: email },\n user: {\n firstName: {\n required,\n minLength: minLength(6),\n },\n lastName: {\n minLength: minLength(6),\n },\n },\n }\n );\n}\n```\n\n```vue twoslash [Parent.vue]\n<template>\n <input v-model=\"r$.$value.email\" placeholder=\"age\" />\n <Child :regle=\"r$\" />\n</template>\n\n```\n\n```vue twoslash [Child.vue]\n<template>\n <ul>\n <li v-for=\"error of r$.$errors.email\" :key=\"error\">\n {{ error }}\n </li>\n </ul>\n</template>\n\n```\n:::\n\n:::tip\n`InferRegleRoot` also works with `@regle/schemas`\n:::\n\n### Manually typing your state and rules\n\nIf you happen to have no way of importing the type, you can style use `RegleRoot` type, that will allow you to manually type your state and rules.\n\n```vue [MyForm.vue]\n\n```\n\n:::warning\nWhile this can be useful, be warned that `r$` will be missing the rule properties.\n:::\n\n## Typing a field prop\n\nIt's possible that you have a `MyInput` like component that contains your business logic.\nYou may want to pass regle computed properties to this component to display useful information to the user.\n\nHere's how you can do it:\n\n:::code-group\n\n```vue [MyInput.vue]\n<template>\n <div class=\"my-input\">\n <input\n v-model=\"modelValue\"\n :class=\"{ valid: field.$correct, error: field.$error }\"\n :placeholder=\"placeholder\"\n />\n\n <ul v-if=\"field.$errors.length\">\n <li v-for=\"error of field.$errors\" :key=\"error\">\n {{ error }}\n </li>\n </ul>\n </div>\n</template>\n\n```\n\n```vue [myForm.vue]\n<template>\n <form>\n <MyInput v-model=\"r$.$value.name\" :field=\"r$.name\" placeholder=\"Type your name\" />\n <MyInput v-model=\"r$.$value.email\" :field=\"r$.email\" placeholder=\"Type your email\" />\n </form>\n</template>\n\n```\n:::\n\n## Typing a field prop with global configuration\n\n:::code-group\n\n```ts twoslash include config [config.ts]\n\nimport { withMessage } from '@regle/rules';\n// ---cut---\nimport { defineRegleConfig } from '@regle/core';\n\nexport const { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n strongPassword: withMessage(() => true, 'test')\n }),\n shortcuts: {\n fields: {\n $test: () => true\n }\n }\n});\n```\n\n```vue twoslash [MyPassword.vue]\n\n```\n\n:::\n\n## Enforcing rules for a specific component\n\nOn your common Input component, you can also enforce a rule to be present in the field.\n\n```vue twoslash [MyPassword.vue]\n\n```\n\n### For a custom configurations\n\n:::code-group\n\n```ts twoslash include config [config.ts]\n\nimport { withMessage } from '@regle/rules';\n// ---cut---\nimport { defineRegleConfig } from '@regle/core';\n\nexport const { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n strongPassword: withMessage(() => true, 'test')\n }),\n shortcuts: {\n fields: {\n $test: () => true\n }\n }\n});\n```\n\n```vue twoslash [MyPassword.vue]\n\n```\n\n:::"
331
+ "content": "# Typing props\n\nForms often span multiple components, and splitting your logic across components is a common practice. Regle offers tools to help type your props correctly, ensuring type safety and improving developer experience.\n\nThe best way to manage a centralized form state with inferred types is by using a Pinia store. Learn more in the Usage with Pinia guide [explained here](/common-usage/usage-with-pinia).\n\nIf you cannot use Pinia, here are the alternative approaches.\n\n## Typing component props\n\nAs Regle's types are complex and based on both your state and your rules, it's hard to replicate manually.\n\n`@regle/core` exports all its utility types, it can be long to explain each one of them, so we'll show the simplest way to type your props.\n\nTo avoid juggling with complex generic types, you can declare your form in a composable inside a file outside your component, and use this composable to type your props.\n\n:::code-group\n\n```ts twoslash include useMyForm [useMyForm.ts]\nimport { useRegle } from '@regle/core';\nimport { email, maxValue, minLength, numeric, required } from '@regle/rules';\n\nexport function useMyForm() {\n return useRegle(\n { email: '', user: { firstName: '', lastName: '' } },\n {\n email: { required, email: email },\n user: {\n firstName: {\n required,\n minLength: minLength(6),\n },\n lastName: {\n minLength: minLength(6),\n },\n },\n }\n );\n}\n```\n\n```vue twoslash [Parent.vue]\n<template>\n <input v-model=\"r$.$value.email\" placeholder=\"age\" />\n <Child :regle=\"r$\" />\n</template>\n\n```\n\n```vue twoslash [Child.vue]\n<template>\n <ul>\n <li v-for=\"error of r$.$errors.email\" :key=\"error\">\n {{ error }}\n </li>\n </ul>\n</template>\n\n```\n:::\n\n:::tip\n`InferRegleRoot` also works with `@regle/schemas`\n:::\n\n### Manually typing your state and rules\n\nIf you happen to have no way of importing the type, you can still use `RegleRoot` type, that will allow you to manually type your state and rules.\n\n```vue [MyForm.vue]\n\n```\n\n:::warning\nWhile this can be useful, be warned that `r$` will be missing the rule properties.\n:::\n\n## Typing a field prop\n\nIt's possible that you have a `MyInput` like component that contains your business logic.\nYou may want to pass regle computed properties to this component to display useful information to the user.\n\nHere's how you can do it:\n\n:::code-group\n\n```vue [MyInput.vue]\n<template>\n <div class=\"my-input\">\n <input\n v-model=\"modelValue\"\n :class=\"{ valid: field.$correct, error: field.$error }\"\n :placeholder=\"placeholder\"\n />\n\n <ul v-if=\"field.$errors.length\">\n <li v-for=\"error of field.$errors\" :key=\"error\">\n {{ error }}\n </li>\n </ul>\n </div>\n</template>\n\n```\n\n```vue [myForm.vue]\n<template>\n <form>\n <MyInput v-model=\"r$.$value.name\" :field=\"r$.name\" placeholder=\"Type your name\" />\n <MyInput v-model=\"r$.$value.email\" :field=\"r$.email\" placeholder=\"Type your email\" />\n </form>\n</template>\n\n```\n:::\n\n## Typing a field prop with global configuration\n\n:::code-group\n\n```ts twoslash include config [config.ts]\n\nimport { withMessage } from '@regle/rules';\n// ---cut---\nimport { defineRegleConfig } from '@regle/core';\n\nexport const { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n strongPassword: withMessage(() => true, 'test')\n }),\n shortcuts: {\n fields: {\n $test: () => true\n }\n }\n});\n```\n\n```vue twoslash [MyPassword.vue]\n\n```\n\n:::\n\n## Enforcing rules for a specific component\n\nOn your common Input component, you can also enforce a rule to be present in the field.\n\n```vue twoslash [MyPassword.vue]\n\n```\n\n### For a custom configurations\n\n:::code-group\n\n```ts twoslash include config [config.ts]\n\nimport { withMessage } from '@regle/rules';\n// ---cut---\nimport { defineRegleConfig } from '@regle/core';\n\nexport const { useRegle: useCustomRegle } = defineRegleConfig({\n rules: () => ({\n strongPassword: withMessage(() => true, 'test')\n }),\n shortcuts: {\n fields: {\n $test: () => true\n }\n }\n});\n```\n\n```vue twoslash [MyPassword.vue]\n\n```\n\n:::"
325
332
  },
326
333
  {
327
334
  "id": "typescript-typing-rules",
@@ -343,7 +350,7 @@ var docs_data_default = {
343
350
  "description": "- The rule definition object containing:\n- `validator`: The validation function\n- `message`: Error message (string or function)\n- `type`: Optional rule type identifier\n- `active`: Optional function to conditionally activate the rule\n- `tooltip`: Optional tooltip message",
344
351
  "optional": false
345
352
  }],
346
- "returnType": "InferRegleRule<TType, TValue, TParams, TAsync, TMetadata, TNonEmpty>",
353
+ "returnType": "InferRegleRule<TType, TValue, TParams, TAsync, TMetadata, TNonEmpty extends true ? true : false>",
347
354
  "example": "import { createRule } from '@regle/core';\nimport { isFilled } from '@regle/rules';\n\n// Simple rule without params\nexport const isFoo = createRule({\n validator(value: Maybe<string>) {\n if (isFilled(value)) {\n return value === 'foo';\n }\n return true;\n },\n message: \"The value should be 'foo'\"\n});\n\n// Rule with parameters\nexport const minCustom = createRule({\n validator(value: Maybe<number>, min: number) {\n if (isFilled(value)) {\n return value >= min;\n }\n return true;\n },\n message: ({ $params: [min] }) => `Value must be at least ${min}`\n});\n\n// Usage\nuseRegle({ name: '' }, { name: { isFoo } });\nuseRegle({ count: 0 }, { count: { minCustom: minCustom(5) } });",
348
355
  "tags": { "see": "://reglejs.dev/core-concepts/rules/reusable-rules Documentation" }
349
356
  },
@@ -394,10 +401,24 @@ var docs_data_default = {
394
401
  "kind": "function",
395
402
  "description": "Define a global Regle configuration to customize the validation behavior across your application.\n\nFeatures:\n- Customize built-in rules messages\n- Add your custom rules with full type inference\n- Define global modifiers (lazy, rewardEarly, etc.)\n- Define shortcuts for common validation patterns",
396
403
  "parameters": [],
397
- "returnType": "{\n useRegle: useRegleFn<TCustomRules, TShortcuts>;\n inferRules: inferRulesFn<TCustomRules>;\n useRules: useRulesFn<TCustomRules, TShortcuts>;\n}",
404
+ "returnType": "{\n useRegle: useRegleFn<Omit<TCustomRules, keyof DefaultValidators>, TShortcuts>;\n inferRules: inferRulesFn<Omit<TCustomRules, keyof DefaultValidators>>;\n useRules: useRulesFn<TCustomRules, TShortc...",
398
405
  "example": "import { defineRegleConfig } from '@regle/core';\nimport { required, withMessage } from '@regle/rules';\n\nexport const { useRegle, inferRules, useRules } = defineRegleConfig({\n rules: () => ({\n // Override default required message\n required: withMessage(required, 'This field cannot be empty'),\n // Add custom rule\n myCustomRule: createRule({\n validator: (value) => value === 'valid',\n message: 'Invalid value'\n })\n }),\n modifiers: {\n lazy: true,\n rewardEarly: true\n }\n});",
399
406
  "tags": { "see": "://reglejs.dev/advanced-usage/global-config Documentation" }
400
407
  },
408
+ {
409
+ "name": "defineRegleOptions",
410
+ "kind": "function",
411
+ "description": "Define a global Regle options to customize the validation behavior across your application.\nIt's meant to be used with the Regle Vue plugin.",
412
+ "parameters": [{
413
+ "name": "options",
414
+ "type": "T",
415
+ "description": "- Configuration options",
416
+ "optional": false
417
+ }],
418
+ "returnType": "T",
419
+ "example": "import { defineRegleOptions } from '@regle/core';\n\nconst regleOptions = defineRegleOptions({\n modifiers: {\n lazy: true,\n rewardEarly: true\n }\n});",
420
+ "tags": { "see": "://reglejs.dev/advanced-usage/global-config Documentation" }
421
+ },
401
422
  {
402
423
  "name": "defineRules",
403
424
  "kind": "function",
@@ -574,7 +595,7 @@ var docs_data_default = {
574
595
  "optional": false
575
596
  }
576
597
  ],
577
- "returnType": "root is NarrowVariant<TRoot, TKey, TValue>",
598
+ "returnType": "root is NarrowVariant<NonNullable<TRoot>, TKey, TValue>",
578
599
  "example": "import { narrowVariant } from '@regle/core';\n\nif (narrowVariant(r$, 'type', 'EMAIL')) {\n // TypeScript knows r$.email exists here\n r$.email.$value = 'user@example.com';\n}",
579
600
  "tags": { "see": "://reglejs.dev/advanced-usage/variants Documentation" }
580
601
  },
@@ -672,7 +693,7 @@ var docs_data_default = {
672
693
  "description": "",
673
694
  "optional": true
674
695
  }],
675
- "returnType": "NonNullable<TState> extends PrimitiveTypes ? Omit<RegleCommonStatus<PrimitiveTypes & TState & {}, TDecl>, \"$value\" | ... 2 more ... | \"$originalValue\"> & { ...; } & { ...; } & { ...; } & StandardSchem...",
696
+ "returnType": "NonNullable<TState> extends PrimitiveTypes ? Omit<RegleCommonStatus<PrimitiveTypes & TState & {}, TDecl>, \"$value\" | ... 2 more ... | \"$originalValue\"> & ... 4 more ... & StandardSchemaV1<...> : Maybe...",
676
697
  "example": "import { useRules, type InferInput } from '@regle/core';\nimport { required, string, email } from '@regle/rules';\n\nconst r$ = useRules({\n name: { required, string },\n email: { required, email }\n});\n\n// State is automatically created and typed\nr$.$value.name // string | null\nr$.$value.email // string | null\n\n// Can be used with Standard Schema compatible libraries\nconst result = await r$['~standard'].validate({ name: '', email: '' });",
677
698
  "tags": { "see": "://reglejs.dev/common-usage/standard-schema#userules Documentation" }
678
699
  },
@@ -736,7 +757,7 @@ var docs_data_default = {
736
757
  "description": "",
737
758
  "optional": false
738
759
  }],
739
- "returnType": "RegleRuleDefinition<\"alpha\", string, [options?: CommonAlphaOptions], false, boolean, string, string, boolean>",
760
+ "returnType": "RegleRuleDefinition<\"alpha\", string, [options?: CommonAlphaOptions], false, boolean, string, string, false>",
740
761
  "example": "import { alpha } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n alpha,\n // or with symbols allowed\n alpha: alpha({ allowSymbols: true }),\n },\n})",
741
762
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#alpha Documentation" }
742
763
  },
@@ -750,7 +771,7 @@ var docs_data_default = {
750
771
  "description": "",
751
772
  "optional": false
752
773
  }],
753
- "returnType": "RegleRuleDefinition<\"alphaNum\", string | number, [options?: CommonAlphaOptions], false, boolean, string, string | number, boolean>",
774
+ "returnType": "RegleRuleDefinition<\"alphaNum\", string | number, [options?: CommonAlphaOptions], false, boolean, string, string | number, false>",
754
775
  "example": "import { alphaNum } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n alphaNum,\n // or with symbols allowed\n alphaNum: alphaNum({ allowSymbols: true }),\n },\n})",
755
776
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#alphanum Documentation" }
756
777
  },
@@ -820,7 +841,7 @@ var docs_data_default = {
820
841
  "optional": true
821
842
  }
822
843
  ],
823
- "returnType": "ComputedRef<TRulesDelc>",
844
+ "returnType": "TRulesDelc",
824
845
  "example": "import { required, email, minLength, assignIf } from '@regle/rules';\n\nconst condition = ref(false);\n\nconst { r$ } = useRegle(ref({ name: '', email: '' }), {\n name: assignIf(condition, { required, minLength: minLength(4) }),\n email: { email },\n});",
825
846
  "tags": { "see": "://reglejs.dev/core-concepts/rules/rules-operators#assignif Documentation" }
826
847
  },
@@ -848,7 +869,7 @@ var docs_data_default = {
848
869
  "description": "",
849
870
  "optional": false
850
871
  }],
851
- "returnType": "RegleRuleDefinition<\"between\", number, [min: number, max: number, options?: CommonComparisonOptions], false, boolean, number, number, boolean>",
872
+ "returnType": "RegleRuleDefinition<\"between\", number, [min: number, max: number, options?: CommonComparisonOptions], false, boolean, number, number, false>",
852
873
  "example": "import { between } from '@regle/rules';\n\nconst maxCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n between: between(1, 6),\n // or with reactive max\n between: between(1, maxCount, { allowEqual: false }),\n // or with getter\n between: between(() => maxCount.value, 10)\n },\n})",
853
874
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#between Documentation" }
854
875
  },
@@ -880,7 +901,7 @@ var docs_data_default = {
880
901
  "description": "",
881
902
  "optional": false
882
903
  }],
883
- "returnType": "RegleRuleDefinition<\"contains\", string, [part: string], false, boolean, string, string, boolean>",
904
+ "returnType": "RegleRuleDefinition<\"contains\", string, [part: string], false, boolean, string, string, false>",
884
905
  "example": "import { contains } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestLib: '' }, {\n bestLib: {\n contains: contains('regle')\n },\n})",
885
906
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#contains Documentation" }
886
907
  },
@@ -931,7 +952,7 @@ var docs_data_default = {
931
952
  "description": "",
932
953
  "optional": false
933
954
  }],
934
- "returnType": "RegleRuleDefinition<\"dateBetween\", string | Date, [before: string | Date, after: string | Date, options?: CommonComparisonOptions], false, boolean, string | Date, string | Date, boolean>",
955
+ "returnType": "RegleRuleDefinition<\"dateBetween\", string | Date, [before: string | Date, after: string | Date, options?: CommonComparisonOptions], false, boolean, string | Date, string | Date, false>",
935
956
  "example": "import { dateBetween } from '@regle/rules';\n\nconst { r$ } = useRegle({ birthday: null as Date | null }, {\n birthday: {\n dateBetween: dateBetween(new Date(), new Date(2030, 3, 1)),\n // or with options\n dateBetween: dateBetween(new Date(), new Date(2030, 3, 1), { allowEqual: false }),\n },\n})",
936
957
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#datebetween Documentation" }
937
958
  },
@@ -972,7 +993,7 @@ var docs_data_default = {
972
993
  "description": "",
973
994
  "optional": false
974
995
  }],
975
- "returnType": "RegleRuleDefinition<\"endsWith\", string, [part: string], false, boolean, string, string, boolean>",
996
+ "returnType": "RegleRuleDefinition<\"endsWith\", string, [part: string], false, boolean, string, string, false>",
976
997
  "example": "import { endsWith } from '@regle/rules';\n\nconst { r$ } = useRegle({ firstName: '' }, {\n firstName: { endsWith: endsWith('foo') },\n})",
977
998
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#endswith Documentation" }
978
999
  },
@@ -986,7 +1007,7 @@ var docs_data_default = {
986
1007
  "description": "",
987
1008
  "optional": false
988
1009
  }],
989
- "returnType": "RegleRuleDefinition<\"exactDigits\", string | number, [count: number], false, boolean, unknown, string | number, boolean>",
1010
+ "returnType": "RegleRuleDefinition<\"exactDigits\", string | number, [count: number], false, boolean, unknown, string | number, false>",
990
1011
  "example": "import { exactDigits } from '@regle/rules';\n\nconst exactValue = ref(6);\n\nconst { r$ } = useRegle({ digits: '' }, {\n digits: {\n exactDigits: exactDigits(6),\n // or with reactive value\n exactDigits: exactDigits(exactValue),\n // or with getter\n exactDigits: exactDigits(() => exactValue.value)\n },\n})",
991
1012
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#exactdigits Documentation" }
992
1013
  },
@@ -1000,7 +1021,7 @@ var docs_data_default = {
1000
1021
  "description": "",
1001
1022
  "optional": false
1002
1023
  }],
1003
- "returnType": "RegleRuleDefinition<\"exactLength\", string | any[] | Record<PropertyKey, any>, [count: number], false, boolean, unknown, string | any[] | Record<PropertyKey, any>, boolean>",
1024
+ "returnType": "RegleRuleDefinition<\"exactLength\", string | any[] | Record<PropertyKey, any>, [count: number], false, boolean, unknown, string | any[] | Record<PropertyKey, any>, false>",
1004
1025
  "example": "import { exactLength } from '@regle/rules';\n\nconst exactValue = ref(6);\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n exactLength: exactLength(6),\n // or with reactive value\n exactLength: exactLength(exactValue),\n // or with getter\n exactLength: exactLength(() => exactValue.value)\n },\n})",
1005
1026
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#exactlength Documentation" }
1006
1027
  },
@@ -1014,7 +1035,7 @@ var docs_data_default = {
1014
1035
  "description": "",
1015
1036
  "optional": false
1016
1037
  }],
1017
- "returnType": "RegleRuleDefinition<\"exactValue\", number, [count: number], false, boolean, number, number, boolean>",
1038
+ "returnType": "RegleRuleDefinition<\"exactValue\", number, [count: number], false, boolean, number, number, false>",
1018
1039
  "example": "import { exactValue } from '@regle/rules';\n\nconst exactCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n exactValue: exactValue(6),\n // or with reactive value\n exactValue: exactValue(exactCount),\n // or with getter\n exactValue: exactValue(() => exactCount.value)\n },\n})",
1019
1040
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#exactvalue Documentation" }
1020
1041
  },
@@ -1037,7 +1058,7 @@ var docs_data_default = {
1037
1058
  "description": "",
1038
1059
  "optional": false
1039
1060
  }],
1040
- "returnType": "RegleRuleDefinition<\"fileType\", File, [accept: readonly string[]], false, boolean, unknown, File, boolean>",
1061
+ "returnType": "RegleRuleDefinition<\"fileType\", File, [accept: readonly string[]], false, boolean, unknown, File, false>",
1041
1062
  "example": "import { type InferInput } from '@regle/core';\nimport { fileType } from '@regle/rules';\n\nconst {r$} = useRegle({ file: null as File | null }, {\n file: { fileType: fileType(['image/png', 'image/jpeg']) },\n})",
1042
1063
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#filetype Documentation" }
1043
1064
  },
@@ -1083,7 +1104,7 @@ var docs_data_default = {
1083
1104
  "description": "",
1084
1105
  "optional": false
1085
1106
  }],
1086
- "returnType": "RegleRuleDefinition<\"httpUrl\", string, [options?: UrlOptions], false, boolean, unknown, string, boolean>",
1107
+ "returnType": "RegleRuleDefinition<\"httpUrl\", string, [options?: UrlOptions], false, boolean, unknown, string, false>",
1087
1108
  "example": "import { httpUrl } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestUrl: '' }, {\n bestUrl: { httpUrl },\n // or to force https protocol\n bestUrl: { httpUrl: httpUrl({ protocol: /^https$/ }) },\n})",
1088
1109
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#httpurl Documentation" }
1089
1110
  },
@@ -1222,7 +1243,7 @@ var docs_data_default = {
1222
1243
  "description": "",
1223
1244
  "optional": false
1224
1245
  }],
1225
- "returnType": "RegleRuleDefinition<\"macAddress\", string, [separator?: string], false, boolean, string, string, boolean>",
1246
+ "returnType": "RegleRuleDefinition<\"macAddress\", string, [separator?: string], false, boolean, string, string, false>",
1226
1247
  "example": "import { macAddress } from '@regle/rules';\n\nconst { r$ } = useRegle({ address: '' }, {\n address: {\n macAddress,\n // or with custom separator\n macAddress: macAddress('-')\n },\n})",
1227
1248
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#macaddress Documentation" }
1228
1249
  },
@@ -1255,7 +1276,7 @@ var docs_data_default = {
1255
1276
  "description": "",
1256
1277
  "optional": false
1257
1278
  }],
1258
- "returnType": "RegleRuleDefinition<\"maxFileSize\", File, [maxSize: number], false, true | { $valid: boolean; fileSize: number; }, unknown, File, boolean>",
1279
+ "returnType": "RegleRuleDefinition<\"maxFileSize\", File, [maxSize: number], false, true | { $valid: boolean; fileSize: number; }, unknown, File, false>",
1259
1280
  "example": "import { type InferInput } from '@regle/core';\nimport { maxFileSize } from '@regle/rules';\n\nconst {r$} = useRegle({ file: null as File | null }, {\n file: { maxFileSize: maxFileSize(10_000_000) }, // 10 MB\n})",
1260
1281
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#maxfilesize Documentation" }
1261
1282
  },
@@ -1269,7 +1290,7 @@ var docs_data_default = {
1269
1290
  "description": "",
1270
1291
  "optional": false
1271
1292
  }],
1272
- "returnType": "RegleRuleDefinition<\"maxLength\", string | any[] | Record<PropertyKey, any>, [max: number, options?: CommonComparisonOptions], false, boolean, unknown, string | any[] | Record<...>, boolean>",
1293
+ "returnType": "RegleRuleDefinition<\"maxLength\", string | any[] | Record<PropertyKey, any>, [max: number, options?: CommonComparisonOptions], false, boolean, unknown, string | any[] | Record<...>, false>",
1273
1294
  "example": "import { maxLength } from '@regle/rules';\n\nconst maxValue = ref(6);\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n maxLength: maxLength(6),\n // or with reactive value\n maxLength: maxLength(maxValue),\n // or with getter\n maxLength: maxLength(() => maxValue.value)\n },\n})",
1274
1295
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#maxlength Documentation" }
1275
1296
  },
@@ -1283,7 +1304,7 @@ var docs_data_default = {
1283
1304
  "description": "",
1284
1305
  "optional": false
1285
1306
  }],
1286
- "returnType": "RegleRuleDefinition<\"maxValue\", string | number, [max: string | number, options?: CommonComparisonOptions], false, boolean, string | number, string | number, boolean>",
1307
+ "returnType": "RegleRuleDefinition<\"maxValue\", string | number, [max: string | number, options?: CommonComparisonOptions], false, boolean, string | number, string | number, false>",
1287
1308
  "example": "import { maxValue } from '@regle/rules';\n\nconst maxCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n maxValue: maxValue(6),\n // or with options\n maxValue: maxValue(maxCount, { allowEqual: false }),\n // or with getter\n maxValue: maxValue(() => maxCount.value)\n },\n})",
1288
1309
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#maxvalue Documentation" }
1289
1310
  },
@@ -1297,7 +1318,7 @@ var docs_data_default = {
1297
1318
  "description": "",
1298
1319
  "optional": false
1299
1320
  }],
1300
- "returnType": "RegleRuleDefinition<\"minFileSize\", File, [minSize: number], false, true | { $valid: boolean; fileSize: number; }, unknown, File, boolean>",
1321
+ "returnType": "RegleRuleDefinition<\"minFileSize\", File, [minSize: number], false, true | { $valid: boolean; fileSize: number; }, unknown, File, false>",
1301
1322
  "example": "import { type InferInput } from '@regle/core';\nimport { minFileSize } from '@regle/rules';\n\nconst {r$} = useRegle({ file: null as File | null }, {\n file: { minFileSize: minFileSize(1_000_000) }, // 1 MB\n})",
1302
1323
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#minfilesize Documentation" }
1303
1324
  },
@@ -1311,7 +1332,7 @@ var docs_data_default = {
1311
1332
  "description": "",
1312
1333
  "optional": false
1313
1334
  }],
1314
- "returnType": "RegleRuleDefinition<\"minLength\", string | any[] | Record<PropertyKey, any>, [min: number, options?: CommonComparisonOptions], false, boolean, unknown, string | any[] | Record<...>, boolean>",
1335
+ "returnType": "RegleRuleDefinition<\"minLength\", string | any[] | Record<PropertyKey, any>, [min: number, options?: CommonComparisonOptions], false, boolean, string | any[] | Record<...>, string | ... 1 more ... | Re...",
1315
1336
  "example": "import { minLength } from '@regle/rules';\n\nconst minValue = ref(6);\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n minLength: minLength(6),\n // or with reactive value\n minLength: minLength(minValue),\n // or with getter\n minLength: minLength(() => minValue.value)\n },\n})",
1316
1337
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#minlength Documentation" }
1317
1338
  },
@@ -1325,7 +1346,7 @@ var docs_data_default = {
1325
1346
  "description": "",
1326
1347
  "optional": false
1327
1348
  }],
1328
- "returnType": "RegleRuleDefinition<\"minValue\", string | number, [min: string | number, options?: CommonComparisonOptions], false, boolean, string | number, string | number, boolean>",
1349
+ "returnType": "RegleRuleDefinition<\"minValue\", string | number, [min: string | number, options?: CommonComparisonOptions], false, boolean, string | number, string | number, false>",
1329
1350
  "example": "import { minValue } from '@regle/rules';\n\nconst minCount = ref(6);\n\nconst { r$ } = useRegle({ count: 0 }, {\n count: {\n minValue: minValue(6),\n // or with options\n minValue: minValue(minCount, { allowEqual: false }),\n // or with getter\n minValue: minValue(() => minCount.value)\n },\n})",
1330
1351
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#minvalue Documentation" }
1331
1352
  },
@@ -1432,7 +1453,7 @@ var docs_data_default = {
1432
1453
  "description": "",
1433
1454
  "optional": false
1434
1455
  }],
1435
- "returnType": "RegleRuleDefinition<\"regex\", string | number, [regexp: RegExp | RegExp[]], false, boolean, string | number, string | number, boolean>",
1456
+ "returnType": "RegleRuleDefinition<\"regex\", string | number, [regexp: RegExp | RegExp[]], false, boolean, string | number, string | number, false>",
1436
1457
  "example": "import { regex } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n regex: regex(/^foo/),\n // or with multiple patterns\n regex: regex([/^bar/, /baz$/]),\n },\n})",
1437
1458
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#regex Documentation" }
1438
1459
  },
@@ -1455,7 +1476,7 @@ var docs_data_default = {
1455
1476
  "description": "",
1456
1477
  "optional": false
1457
1478
  }],
1458
- "returnType": "RegleRuleDefinition<\"required\", unknown, [condition: boolean], false, boolean, unknown, unknown, boolean>",
1479
+ "returnType": "RegleRuleDefinition<\"required\", unknown, [condition: boolean], false, boolean, unknown, unknown, false>",
1459
1480
  "example": "import { requiredIf } from '@regle/rules';\n\nconst form = ref({ name: '', condition: false });\nconst conditionRef = ref(false);\n\nconst { r$ } = useRegle(form, {\n name: {\n required: requiredIf(() => form.value.condition),\n // or with a ref\n required: requiredIf(conditionRef),\n },\n})",
1460
1481
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#requiredif Documentation" }
1461
1482
  },
@@ -1469,7 +1490,7 @@ var docs_data_default = {
1469
1490
  "description": "",
1470
1491
  "optional": false
1471
1492
  }],
1472
- "returnType": "RegleRuleDefinition<\"required\", unknown, [condition: boolean], false, boolean, unknown, unknown, boolean>",
1493
+ "returnType": "RegleRuleDefinition<\"required\", unknown, [condition: boolean], false, boolean, unknown, unknown, false>",
1473
1494
  "example": "import { requiredUnless } from '@regle/rules';\n\nconst form = ref({ name: '', condition: false });\nconst conditionRef = ref(false);\n\nconst { r$ } = useRegle(form, {\n name: {\n required: requiredUnless(() => form.value.condition),\n // or with a ref\n required: requiredUnless(conditionRef)\n },\n})",
1474
1495
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#requiredunless Documentation" }
1475
1496
  },
@@ -1488,7 +1509,7 @@ var docs_data_default = {
1488
1509
  "description": "- Optional name for the other field (used in error message)",
1489
1510
  "optional": true
1490
1511
  }],
1491
- "returnType": "RegleRuleDefinition<\"sameAs\", TTarget, [target: TTarget, otherName?: string], false, boolean, TTarget extends infer M ? M : TTarget, TTarget extends Date & ... 1 more ... & infer M ? M : TTarget, bool...",
1512
+ "returnType": "RegleRuleDefinition<\"sameAs\", TTarget, [target: TTarget, otherName?: string], false, boolean, TTarget extends infer M ? M : TTarget, unknown, false>",
1492
1513
  "example": "import { sameAs } from '@regle/rules';\n\nconst form = ref({\n password: '',\n confirmPassword: '',\n});\n\nconst { r$ } = useRegle(form, {\n confirmPassword: {\n sameAs: sameAs(() => form.value.password),\n }\n})",
1493
1514
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#sameas Documentation" }
1494
1515
  },
@@ -1502,7 +1523,7 @@ var docs_data_default = {
1502
1523
  "description": "",
1503
1524
  "optional": false
1504
1525
  }],
1505
- "returnType": "RegleRuleDefinition<\"startsWith\", string, [part: string], false, boolean, string, string, boolean>",
1526
+ "returnType": "RegleRuleDefinition<\"startsWith\", string, [part: string], false, boolean, string, string, false>",
1506
1527
  "example": "import { startsWith } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestLib: '' }, {\n bestLib: {\n startsWith: startsWith('regle')\n },\n})",
1507
1528
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#startswith Documentation" }
1508
1529
  },
@@ -1571,7 +1592,7 @@ var docs_data_default = {
1571
1592
  "description": "",
1572
1593
  "optional": false
1573
1594
  }],
1574
- "returnType": "RegleRuleDefinition<\"url\", string, [options?: UrlOptions], false, boolean, unknown, string, boolean>",
1595
+ "returnType": "RegleRuleDefinition<\"url\", string, [options?: UrlOptions], false, boolean, unknown, string, false>",
1575
1596
  "example": "import { url } from '@regle/rules';\n\nconst { r$ } = useRegle({ bestUrl: '' }, {\n bestUrl: { url },\n // or with custom protocol validation\n bestUrl: { url: url({ protocol: /^https?$/ }) },\n})",
1576
1597
  "tags": { "see": "://reglejs.dev/core-concepts/rules/built-in-rules#url Documentation" }
1577
1598
  },
@@ -1600,7 +1621,7 @@ var docs_data_default = {
1600
1621
  "description": "The `withMessage` wrapper lets you associate an error message with a rule.\nPass your rule as the first argument and the error message as the second.",
1601
1622
  "parameters": [{
1602
1623
  "name": "rule",
1603
- "type": "RegleRuleWithParamsDefinition<TType, TValue, TParams, TAsync, TMetadata>",
1624
+ "type": "RegleRuleWithParamsDefinition<TType, TValue, TParams, TAsync, TMetadata, TInput, TFilteredValue, TNonEmpty>",
1604
1625
  "description": "- The rule to wrap (can be inline function or rule definition)",
1605
1626
  "optional": false
1606
1627
  }, {
@@ -1609,7 +1630,7 @@ var docs_data_default = {
1609
1630
  "description": "- The error message (string or function returning a string)",
1610
1631
  "optional": false
1611
1632
  }],
1612
- "returnType": "RegleRuleWithParamsDefinition<TType, TValue, TParams, TAsync, TMetadata>",
1633
+ "returnType": "RegleRuleWithParamsDefinition<TType, TValue, TParams, TAsync, TMetadata, TInput, TFilteredValue, TNonEmpty>",
1613
1634
  "example": "import { withMessage } from '@regle/rules';\n\nconst { r$ } = useRegle({ name: '' }, {\n name: {\n // With a static message\n customRule1: withMessage((value) => !!value, \"Custom Error\"),\n // With dynamic message using metadata\n customRule2: withMessage(\n customRuleInlineWithMetaData,\n ({ $value, foo }) => `Custom Error: ${$value} ${foo}`\n ),\n }\n})",
1614
1635
  "tags": { "see": "://reglejs.dev/core-concepts/rules/rule-wrappers#withmessage Documentation" }
1615
1636
  },
@@ -1934,7 +1955,7 @@ function searchApi(query) {
1934
1955
  return results;
1935
1956
  }
1936
1957
 
1937
- var version = "1.18.2";
1958
+ var version = "1.19.0-beta.1";
1938
1959
 
1939
1960
  let posthogClient = null;
1940
1961
  posthogClient = new PostHog("phc_kqgJoylCpKkGkkRGxb4MyN2mViehoQcUFEGwVkk4l8E", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@regle/mcp-server",
3
- "version": "1.18.2",
3
+ "version": "1.19.0-beta.1",
4
4
  "description": "MCP Server for Regle",
5
5
  "keywords": [
6
6
  "ai",
@@ -45,12 +45,12 @@
45
45
  "access": "public"
46
46
  },
47
47
  "dependencies": {
48
- "@modelcontextprotocol/sdk": "1.25.3",
48
+ "@modelcontextprotocol/sdk": "1.26.0",
49
49
  "posthog-node": "5.24.1",
50
50
  "zod": "4.3.6"
51
51
  },
52
52
  "devDependencies": {
53
- "@types/node": "24.1.0",
53
+ "@types/node": "24.10.10",
54
54
  "dotenv": "17.2.3",
55
55
  "tsdown": "0.20.1",
56
56
  "tsx": "4.21.0",