diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 94b191d..3335fa2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - typescript: [ "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9" ] + typescript: [ "4.1", "4.9", "5.0" ] name: typescript@${{ matrix.typescript }} steps: - uses: actions/checkout@v3 diff --git a/README.md b/README.md index 4f04dc0..ac8fb82 100644 --- a/README.md +++ b/README.md @@ -1,596 +1,431 @@

-
-
- Roqueform -
-
- - build + + Roqueform

-
- The form state management library that can handle hundreds of fields without breaking a sweat. -- Extremely fast, re-renders only updated fields; -- Laconic API with strict typings; -- [Pluggable architecture and great extensibility](#plugins); -- [Just 2 kB gzipped](https://bundlephobia.com/result?p=roqueform); -- [Custom validation support](#validation). +- Expressive and concise API with strict typings; +- Controlled and uncontrolled inputs; +- [Unparalleled extensibility with plugins;](#plugins-and-integrations) +- Supports your favourite rendering and [validation libraries;](#validation-scaffolding-plugin) +- [Just 2 kB gzipped.](https://bundlephobia.com/result?p=roqueform) -🔥 [**Try it on CodeSandbox**](https://codesandbox.io/s/roqueform-example-2evfif) +🔥 [**Try it on CodeSandbox**](https://codesandbox.io/s/2evfif) ```sh npm install --save-prod roqueform ``` -- [Foreword](#foreword) -- [`useField`](#usefield) - - [Field value updates](#field-value-updates) - - [Transient updates](#transient-updates) - - [Field observability](#field-observability) -- [`FieldRenderer`](#fieldrenderer) - - [Eager and lazy re-renders](#eager-and-lazy-re-renders) - - [Reacting to changes](#reacting-to-changes) -- [Plugins](#plugins) - - [Authoring a plugin](#authoring-a-plugin) - - [Composing plugins](#composing-plugins) -- [Form submission](#form-submission) -- [Validation](#validation) - - [Validation scaffolding plugin](#validation-scaffolding-plugin) +- [Plugins and integrations](#plugins-and-integrations) +- [Basics](#basics) +- [Transient updates](#transient-updates) - [Accessors](#accessors) +- [Authoring a plugin](#authoring-a-plugin) +- [Composing plugins](#composing-plugins) +- [Validation scaffolding plugin](#validation-scaffolding-plugin) +- [Motivation](#motivation) -# Foreword - -Form lifecycle consists of four separate phases: Input, Validate, Display errors, and Submit. These phases can be -represented as non-intersecting processes. The result obtained during one phase may be used as an input for another -phase. For example, let's consider the following set of actions: +# Plugins and integrations -- The user inputs form values; -- The input is validated; -- Validation errors are displayed; -- Input is submitted; -- Errors received from the backend are displayed. +- [constraint-validation-plugin](./packages/constraint-validation-plugin#readme)
+ Integrates fields with + [Constraint validation API](https://developer.mozilla.org/en-US/docs/Web/API/Constraint_validation). -These actions are non-intersecting and can happen in an arbitrary order, or even in parallel. The form management -library should allow to tap in (or at least not constrain the ability to do so) at any particular phase to tweak the -data flow. +- [doubter-plugin](./packages/doubter-plugin#readme)
+ Validates fields with [Doubter](https://github.com/smikhalevski/doubter#readme) shapes. -So the Roqueform was built to satisfy the following requirements: +- [react](./packages/react#readme)
+ Hooks and components to integrate with React. -- No excessive re-renders of unchanged fields. +- [ref-plugin](./packages/ref-plugin#readme)
+ Associates field with DOM elements. -- Everything should be statically and strictly typed up to the very field value setter. So there must be a compilation - error if the string value from the silly input is assigned to the number-typed value in the form state object. +- [reset-plugin](./packages/reset-plugin#readme)
+ Manages field initial value and dirty status. -- **Use the platform!** The form state management library must not constrain the use of the `form` submit behavior, - browser-based validation, and other related browser-native features. - -- There should be no restrictions on how and when the form input is submitted because data submission is generally - an application-specific process. +- [scroll-to-error-plugin](./packages/scroll-to-error-plugin#readme)
+ Enables scrolling to a field that has an associated validation error. Works with any validation plugin in this repo. -- There are many approaches to validation, and a great number of awesome validation libraries. The form library must - be agnostic to where (client-side, server-side, or both), how (on a field or on a form level), and when (sync, or - async) the validation is handled. +- [uncontrolled-plugin](./packages/uncontrolled-plugin#readme)
+ Updates fields by listening to change events of associated DOM elements. -- Validation errors aren't standardized, so an arbitrary error object shape must be allowed and related typings must be - seamlessly propagated to the error consumers/renderers. +- [zod-plugin](./packages/zod-plugin#readme)
+ Validates fields with [Zod](https://zod.dev/) schemas. -- The library API must be simple. +# Basics -# `useField` +The central piece of Roqueform is the concept of a field. A field holds a value and provides a couple of ways to update +it. Fields can be enhanced by plugins that provide such things as integration with rendering and validation libraries. -The central piece of Roqueform is a `useField` hook that returns a -[`Field`](https://smikhalevski.github.io/roqueform/interfaces/roqueform.Field.html) object that represents a node in a -tree of form input controllers: +Let's start by creating a field: ```ts -import { useField } from 'roqueform'; +import { createField } from 'roqueform'; -const field = useField(); -// → Field +const field = createField(); +// ⮕ Field ``` -You can provide an initial value to a field (a field value type would is automatically inferred): +A value can be set to and retrieved from the field: ```ts -const field = useField({ foo: 'bar' }); -// → Field<{ foo: string }> +field.setValue('Pluto'); + +field.value; +// ⮕ 'Pluto' ``` -You can derive new fields from the existing ones using `at` method: +Provide the initial value for a field: ```ts -const fooField = field.at('foo'); -// → Field +const ageField = createField(42); +// ⮕ Field + +ageField.value; +// ⮕ 42 ``` -`fooField` is a derived field, it is linked to the parent `field`. Fields returned by the `at` method have a stable -identity, so you can invoke `at` with the same key multiple times and the same field instance would be returned: +The field value type is inferred from the initial value, but you can explicitly specify the field value type: ```ts -field.at('foo') === field.at('foo') -// → true +const universeField = createField<{ planets?: string[] }>(); +// ⮕ Field<{ planets?: string[] } | undefined> ``` -Fields can be derived at any depth: +Derive a new field from the existing one: ```ts -const field = useField({ foo: [{ bar: 'qux' }] }); - -field.at('foo').at(0).at('bar'); -// → Field +const planetsField = universeField.at('planets'); +// ⮕ Field ``` -## Field value updates - -The field is essentially a container that encapsulates the value and provides methods to update it. Let's have a look at -the `setValue` method that updates the field value: +`planetsField` is a derived field, and it is linked to its parent `universeField`. ```ts -const field = useField({ foo: 'bar' }); +planetsField.key; +// ⮕ 'planets' -field.value; -// → { foo: 'bar' } +planetsField.parent; +// ⮕ universeField +``` -field.setValue({ foo: 'qux' }); +Fields returned by the [`at`](https://smikhalevski.github.io/roqueform/interfaces/roqueform.Field.html#at) method have a +stable identity. This means that you can invoke `at` with the same key multiple times and the same field instance would +be returned: -// 🟡 The field value was updated -field.value; -// → { foo: 'qux' } +```ts +universeField.at('planets'); +// ⮕ planetsField ``` -`useField` doesn't trigger re-renders of the enclosing component. Navigate to -[Field observability](#field-observability) section for more details. +Most of the time you don't need to store a derived field in a variable if you already have a reference to a parent +field. -When the parent field is updated using `setValue`, all of the affected derived fields also receive an update: +The derived field has all the same functionality as its parent, so you can derive a new field from it as well: ```ts -const field = useField({ foo: 'bar' }); -const fooField = field.at('foo'); - -field.value; -// → { foo: 'bar' } - -fooField.value; -// → 'bar' +planetsField.at(0).at('name'); +``` -// Updating the root field -field.setValue({ foo: 'qux' }); +When a value is set to a derived field, a parent field value is also updated. If parent field doesn't have a value yet, +Roqueform would infer its type from on the derived field key. -// 🟡 The update was propagated to the derived field -field.value; -// → { foo: 'qux' } +```ts +universeField.at('planets').at(0).at('name').setValue('Mars') -fooField.value; -// → 'qux' +universeField.value; +// ⮕ { planets: [{ name: 'Mars' }] } ``` -The same is valid for updating derived fields: when the derived field is updated using `setValue`, the update is -propagated to the parent field. +By default, for a string key a parent object is created, and for a number key a parent array is created. You can change +this behaviour with [Accessors](#accessors). + +When a value is set to a parent field, derived fields are also updated: ```ts -const field = useField({ foo: 'bar' }); -const fooField = field.at('foo'); +const nameField = universeField.at('planets').at(0).at('name'); -// Updating the derived field -fooField.setValue('qux'); +nameField.value; +// ⮕ 'Mars' -// The update was propagated to the parent field -field.value; -// → { foo: 'qux' } +universeField.setValue({ planets: ['Venus'] }); -fooField.value; -// → 'qux' +nameField.value; +// ⮕ 'Venus' ``` -`setValue` also has a callback signature: +You can subscribe to a field to receive notifications about field state changes. ```ts -fooField.setValue(prevValue => 'qux'); +const unsubscribe = planetsField.subscribe((targetField, currentField) => { + // Handle the update +}); +// ⮕ () => void ``` -## Transient updates +Subscriber callbacks are called with two arguments: -The field update can be done transiently, so the parent won't be notified. You can think about this as a commit in git: -you first stage your changes with `git add` and then commit them with `git commit`. +
+
targetField
+
-To achieve this behavior we're going to use `setTransientValue`/`dispatch` instead of `setValue` that we discussed in -[Field value updates](#field-value-updates) section: +The field that initiated the update. This can be `planetsField` itself, any of its derived fields, or any of its +ancestor fields. -```ts -const field = useField({ foo: 'bar' }); -const fooField = field.at('foo'); +
+
currentField
+
-// Set the transient value, "git add" -fooField.setTransientValue('qux'); +The field to which the listener is subscribed. In this example it is `planetsField`. -field.value; -// → { foo: 'bar' } +
+
-// 🟡 Notice that fooField was updated but field wasn't -fooField.value; -// → 'qux' +Subscribers are called when a field value is changed or [when a plugin mutates the field object](#authoring-a-plugin). -// Notify the parent, "git commit" -fooField.dispatch(); +# Transient updates -// Now both fields are in sync -field.value; -// → { foo: 'qux' } - -fooField.value; -// → 'qux' -``` - -`setTransientValue` can be called multiple times, but the most recent update would be propagated to the parent only -after the `dispatch` call. - -You can check that the field has a transient value using `transient` property: +When a derived field value is set transiently, the value of its parent _isn't_ immediately updated. ```ts -const field = useField({ foo: 'bar' }); -const fooField = field.at('foo'); - -fooField.setTransientValue('qux'); +const avatarField = createField(); -fooField.transient; -// → true +avatarField.at('eyeColor').setTransientValue('green'); -fooField.dispatch(); +avatarField.at('eyeColor').value; +// ⮕ 'green' -fooField.transient; -// → false +avatarField.value; +// ⮕ undefined ``` -## Field observability - -Fields are observable, you can subscribe to them and receive a callback whenever the field state is updated: +You can check that a field is in a transient state: ```ts -field.subscribe((targetField, currentField) => { - // Handle the update here -}); +avatarField.at('eyeColor').isTransient; +// ⮕ true ``` -`targetField` is a field that initiated the update, so this can be the `field` itself, any of its derived fields, or any -of its ancestors (if `field` is also a derived field). +To propagate the transient value contained by the derived field to its parent, use +the [`dispatch`](https://smikhalevski.github.io/roqueform/interfaces/roqueform.Field.html#dispatch) method: -`currentField` is the field to which the listener is subscribed, so in this case it is `field`. +```ts +avatarField.at('eyeColor').dispatch(); -# `FieldRenderer` +avatarField.value; +// ⮕ { eyeColor: 'green' } +``` -The `FieldRenderer` component subscribes to the given field instance and re-renders its children when the field is -notified: +`setTransientValue` can be called multiple times, but only the most recent update is propagated to the parent field +after the `dispatch` call. -```tsx -import { FieldRenderer, useField } from 'roqueform'; +When a derived field is in a transient state, its value as observed from the parent may differ from the actual value: -const App = () => { - const rootField = useField('foo'); +```ts +const planetsField = createField(['Mars', 'Pluto']); - return ( - - {rootField => ( - { - rootField.setValue(event.target.value); - }} - /> - )} - - ); -}; -``` +planetsField.at(1).setTransientValue('Venus'); -When a user updates the input value, the `rootField` is updated and `FieldRenderer` component is re-rendered. The single -argument of the `children` render function is the field passed as a `field` prop to the `FieldRenderer` component. - -It is unlikely that you would use a form with a single literal field. Most of the time multiple derived fields are -required: - -```tsx -const App = () => { - const rootField = useField({ foo: 'qux', bar: 123 }); - - return <> - - {fooField => ( - { - fooField.setValue(event.target.value); - }} - /> - )} - - - - {barField => ( - { - barField.setValue(event.target.valueAsNumber); - }} - /> - )} - - ; -}; +planetsField.value[1]; +// ⮕ 'Pluto' + +planetsField.at(1).value; +// ⮕ 'Venus' ``` -You may have noticed that even though we didn't specify any types yet, our fields are strictly typed. You can check this -by replacing the value dispatched to `barField`: +Values are synchronized after the update is dispatched: -```diff -- barField.setValue(event.target.valueAsNumber); -+ barField.setValue(event.target.value); -``` +```ts +planetsField.at(1).disaptch(); -This would cause TypeScript to show an error that `barField` value must be of a number type. - -## Eager and lazy re-renders - -Let's consider the form with two `FieldRenderer` elements. One of them renders the value of the root field and the other -one renders an input that updates the derived field: - -```tsx -const App = () => { - const rootField = useField({ bar: 'qux' }); - - return <> - - {rootField => JSON.stringify(rootField.value)} - - - - {barField => ( - { - barField.setValue(event.target.value); - }} - /> - )} - - ; -}; -``` +planetsField.value[1]; +// ⮕ 'Venus' -By default, `FieldRenderer` component re-renders only when the provided field was updated directly, so updates from -ancestors or derived fields would be ignored. Add the `eagerlyUpdated` property to force `FieldRenderer` to re-render -whenever its value was affected. - -```diff -- -+ - {rootField => JSON.stringify(rootField.value)} - +planetsField.at(1).value; +// ⮕ 'Venus' ``` -Now both fields are re-rendered when user edits the input text. - -## Reacting to changes - -[Subscribing to a field](#field-observability) isn't always convenient. Instead, you can use an `onChange` handler that -is triggered only when the field value was updated [non-transiently](#transient-updates). - -```tsx - { - // Handle the value change - }} -> - {barField => ( - { - barField.setValue(event.target.value); - }} - /> - )} - -``` +# Accessors -# Plugins +[`Accessor`](https://smikhalevski.github.io/roqueform/interfaces/roqueform.Accessor.html) instances create, read and +update field values. -Plugins are a very powerful mechanism that allows enriching fields with a custom functionality. +- When the new derived field is created, its value is read from the value of the parent field using the + [`get`](https://smikhalevski.github.io/roqueform/interfaces/roqueform.Accessor.html#get) of the associated accessor. -There's a set of plugins available in this repo: +- When a derived field is updated, the parent value should be returned from the + [`set`](https://smikhalevski.github.io/roqueform/interfaces/roqueform.Accessor.html#set) of the associated accessor. -- [@roqueform/doubter-plugin](./packages/doubter-plugin#readme)
- Enhances fields with validation methods powered by [Doubter](https://github.com/smikhalevski/doubter#readme). +Be default, [`objectAccessor`](https://smikhalevski.github.io/roqueform/variables/roqueform.objectAccessor.html) is +used. It creates parent values depending on a derived field key: for a string key a parent object is created, for a +number key a parent array is created. -- [@roqueform/ref-plugin](./packages/ref-plugin#readme)
- Enhances fields with DOM-related methods. +Provide an accessor along with the initial value to the field factory: -- [@roqueform/reset-plugin](./packages/reset-plugin#readme)
- Enhances fields with methods that manage the initial value. +```ts +import { objectAccessor } from 'roqueform'; -- [@roqueform/scroll-to-error-plugin](./packages/scroll-to-error-plugin#readme)
- Enables scrolling to a field that has an associated validation error. +const usersField = createField(['Mars', 'Venus'], objectAccessor); +``` -## Authoring a plugin +# Authoring a plugin -Let's enhance the field with the `ref` property that would hold the `RefObject`: +Plugin is a function that receives a field instance, an accessor, and a callback to notify the field subscribers about +changes. To illustrate how plugins work, let's create a simple plugin that enriches a field with a DOM element +reference. ```ts -import { createRef, RefObject } from 'react'; -import { Plugin, useField } from 'roqueform'; - -function refPlugin(): Plugin<{ ref: RefObject }> { - return field => { - Object.assign(field, { ref: createRef() }); - }; -} +import { Plugin } from 'roqueform'; -const rootField = useField({ bar: 'qux' }, refPlugin()); -// → Field<{ bar: string }, { ref: RefObject }> & { ref: RefObject } +const elementPlugin: Plugin<{ element: Element | null }> = field => { + field.element = null; +}; ``` -The second argument of the `useField` hook is the plugin function that accepts a field instance and enriches it with -the new functionality. In our case it adds the `ref` to each field derived from the `rootField` and to the `rootField` -itself. - -```tsx - - {barField => ( - { - barField.setValue(event.target.value); - }} - /> - )} - -``` +> **Note** The plugin function directly mutates the field instance. This is required since multiple plugins may be +> updating the same field and may need to share the same field identity. -After the `FieldRenderer` is mounted we can use ref to imperatively scroll the input element into view: +To apply the plugin to a field, pass it to the field factory: ```ts -rootField.at('bar').ref.current?.scrollIntoView(); -``` +const planetField = createField({ name: 'Mars' }, elementPlugin); +// ⮕ Field<{ name: string }, { element: Element | null }> -## Composing plugins +planetField.element; +// ⮕ null +``` -To combine multiple plugins into one, use `applyPlugins` helper function: +The plugin would be called for each derived field when it is first accessed: ```ts -import { applyPlugins, useField } from 'roqueform'; -import { refPlugin } from '@roqueform/ref-plugin'; - -const field = useField({ bar: 'qux' }, applyPlugins(refPlugin(), anotherPlugin())); +planetField.at('name').element +// ⮕ null ``` -# Form submission +We can now assign a DOM element reference to an `element` property, so we can later access an element through a field. +But with the current implementation, there's no way to notify field consumers that the value of the `element` property +has changed. Let's update the plugin implementation to trigger subscribers. + +```ts +import { Plugin } from 'roqueform'; + +interface ElementMixin { -Without plugins, Roqueform only manages the state of the form fields, and doesn't affect how the form is submitted. So -you can use `form` tags and read input values from the `Field` object: + readonly element: Element | null; -```tsx -const App = () => { - const rootField = useField({ bar: 'foo' }); + setElement(element: Element | null): void; +} - const handleSubmit = (event: SyntheticEvent): void => { - event.preventDefault(); +const elementPlugin: Plugin = (field, accessor, notify) => { + field.element = null; - // The form value to submit - rootField.value; + field.setElement = element => { + field.element = element; + + // 🟡 Synchronously triggers subscribers + notify(); }; - - return ( -
- - - {barField => ( - { - barField.setValue(event.target.value); - }} - /> - )} - - - - -
- ); }; ``` -You can always [create a plugin](#plugins) that would enhance the `Field` instance with custom submit mechanics. - -# Validation - -Roqueform isn't tied to any validation library. You can use an existing plugin, or write your own to extend Roqueform -with validation provided by an arbitrary library. - -Consider using [@roqueform/doubter-plugin](./packages/doubter-plugin#readme) which relies on -[Doubter](https://github.com/smikhalevski/doubter#readme) under-the-hood. +Now when `setElement` is called on a field, its subscribers would be invoked. ```ts -import { useField } from 'roqueform'; -import { doubterPlugin } from '@roqueform/doubter-plugin'; -import * as d from 'doubter'; +const planetField = createField({ name: 'Mars' }, elementPlugin); -const valueShape = d.object({ - bar: d.string().min(5) +planetField.at('name').subscribe((targetField, currentField) => { + // Handle the update + currentField.element; + // ⮕ Element }); -const rootField = useField({ bar: 'qux' }, doubterPlugin(valueShape)); +planetField.at('name').setElement(document.getElementById('name')); +``` -rootField.validate(); -// → [{ message'Must have the minimum length of 5', … }] +# Composing plugins -rootField.at('bar').error; -// → { message: 'Must have the minimum length of 5', … } -``` +To combine multiple plugins into a single function, use the +[`applyPlugins`](https://smikhalevski.github.io/roqueform/variables/roqueform.applyPlugins.html) helper: + +```ts +import { createField, applyPlugins } from 'roqueform'; -[Plugin usage details can be found here.](./packages/doubter-plugin#readme) +createField(['Mars'], applyPlugins(plugin1, plugin2)); +// ⮕ Field +``` -## Validation scaffolding plugin +# Validation scaffolding plugin -Roqueform a shipped with validation scaffolding plugin `validatePlugin`, so you can build your validation on top of it. +Roqueform a shipped with validation scaffolding plugin +[`validatePlugin`](https://smikhalevski.github.io/roqueform/variables/roqueform.validatePlugin.html), so you can build +your validation on top of it. ```ts -import { Plugin, useField, validationPlugin, ValidationMixin } from 'roqueform'; +import { validationPlugin } from 'roqueform'; -const plugin = validationPlugin((field, setInternalError, options) => { - if (field.at('foo').value === null) { - setInternalError(field.at('foo'), 'Must not be null'); +const plugin = validationPlugin((field, setInternalError) => { + if (!field.at('name').value) { + setInternalError(field.at('name'), 'Name must not be empty'); } }); -const field = useField({ foo: 'bar' }, plugin); - -// Manually set an error for a field -field.setError('Some useful message'); +const userField = createField({ name: 'James' }, plugin); -field.error; -// → 'Some useful message' +// Manually associate an error for a field +userField.setError('Some useful message'); -field.at('foo').error; -// → 'Must not be null' - -// Clear all errors of the field and its derived fields -field.clearErrors(); +userField.error; +// ⮕ 'Some useful message' ``` -This plugin makes all the heavy lifting related to field updates, manual validation error management, async validation +This plugin does all the heavy lifting related to field updates, manual validation error management, async validation abortions, etc. It takes a validator callback or an object that has a `validate` method and an optional `validateAsync` -method. The validator receives a field that must be validated and a `setInternalError` callback that to notifies -Roqueform that an error should be assigned to a particular field. +method. The validator receives a field that must be validated and a `setInternalError` callback that tells Roqueform +that an error should be assigned to a particular field. -`validatePlugin` distinguishes internal errors (those set via `setInternalError`) and external errors (those set via -`field.setError`). Internal errors are automatically cleared when the `field.validate` or `field.validateAsync` -methods are called. External errors are preserved as is, and you should explicitly call `field.clearErrors` before -validation to delete them. +To trigger validation call `validate`: -# Accessors +```ts +userField.at('name').setValue(''); -When you derive a new field or update a derived field, Roqueform uses an accessor to read and write a value to the -parent field. You can alter the way field values are read and written by providing a custom implementation of `Accessor` -interface to `AccessorContext`. +userField.validate(); -```tsx -import { objectAccessor, AccessorContext } from 'roqueform'; +userField.at('name').error; +// ⮕ 'Name must not be empty' +``` + +`validatePlugin` distinguishes internal errors (those set via `setInternalError`) and external errors (those set via +`setError`). Internal errors are automatically cleared when the `validate` or `validateAsync` methods are called. +External errors are preserved as is, and you should explicitly call `clearErrors` delete them. - - {/* useField should go here */} - +```ts +userField.clearErrors(); ``` + +# Motivation + +Roqueform was built to satisfy the following requirements: + +- Since the form lifecycle consists of separate phases (input, validate, display errors, and submit), the form state + management library should allow to tap in (or at least not constrain the ability to do so) at any particular phase to + tweak the data flow. + +- Form data should be statically and strictly typed up to the very field value setter. So there must be a compilation + error if the string value from the silly input is assigned to the number-typed value in the form state object. + +- **Use the platform!** The form state management library must not constrain the use of the `form` submit behavior, + browser-based validation, and other related native features. + +- There should be no restrictions on how and when the form input is submitted because data submission is generally + an application-specific process. + +- There are many approaches to validation, and a great number of awesome validation libraries. The form library must + be agnostic to where (client-side, server-side, or both), how (on a field or on a form level), and when (sync, or + async) the validation is handled. + +- Validation errors aren't standardized, so an arbitrary error object shape must be allowed and related typings must be + seamlessly propagated to the error consumers/renderers. + +- The library API must be simple and easily extensible. diff --git a/images/logo.png b/images/logo.png index 0276d4b..b6abe18 100644 Binary files a/images/logo.png and b/images/logo.png differ diff --git a/package-lock.json b/package-lock.json index d0f2223..5524646 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,21 +18,21 @@ "devDependencies": { "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-typescript": "^11.0.0", - "@testing-library/dom": "^8.20.0", - "@testing-library/react": "^13.4.0", - "@types/jest": "^29.4.0", + "@testing-library/dom": "^9.0.1", + "@testing-library/react": "^14.0.0", + "@types/jest": "^29.5.0", "@types/react": "^18.0.28", - "jest": "^29.4.2", - "jest-environment-jsdom": "^29.4.2", - "prettier": "^2.8.4", - "rimraf": "^4.1.2", - "rollup": "^3.15.0", - "rollup-plugin-dts": "^5.1.1", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "prettier": "^2.8.6", + "rimraf": "^4.4.0", + "rollup": "^3.20.0", + "rollup-plugin-dts": "^5.3.0", "ts-jest": "^29.0.5", - "tsd": "^0.25.0", + "tsd": "^0.28.0", "tslib": "^2.5.0", "typedoc": "^0.23.25", - "typescript": "^4.9.5" + "typescript": "^5.0.2" } }, "node_modules/@ampproject/remapping": { @@ -61,30 +61,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", - "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", + "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", - "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", + "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", "dev": true, "dependencies": { - "@ampproject/remapping": "^2.1.0", + "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", + "@babel/generator": "^7.21.3", "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helpers": "^7.20.7", - "@babel/parser": "^7.20.7", + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.3", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.12", - "@babel/types": "^7.20.7", + "@babel/traverse": "^7.21.3", + "@babel/types": "^7.21.3", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -106,13 +106,14 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", + "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", "dev": true, "dependencies": { - "@babel/types": "^7.20.7", + "@babel/types": "^7.21.3", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -162,13 +163,13 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" @@ -199,9 +200,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", + "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", @@ -210,8 +211,8 @@ "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.2", + "@babel/types": "^7.21.2" }, "engines": { "node": ">=6.9.0" @@ -269,23 +270,23 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", + "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", - "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", + "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", "dev": true, "dependencies": { "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.13", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" @@ -377,9 +378,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", + "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -566,9 +567,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", - "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.13.11" @@ -592,19 +593,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", + "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", + "@babel/generator": "^7.21.3", "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", + "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", + "@babel/parser": "^7.21.3", + "@babel/types": "^7.21.3", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -613,9 +614,9 @@ } }, "node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", + "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -658,16 +659,16 @@ } }, "node_modules/@jest/console": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.4.2.tgz", - "integrity": "sha512-0I/rEJwMpV9iwi9cDEnT71a5nNGK9lj8Z4+1pRAU2x/thVXCDnaTGrvxyK+cAqZTFVFCiR+hfVrP4l2m+dCmQg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", "dev": true, "dependencies": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.4.2", - "jest-util": "^29.4.2", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0" }, "engines": { @@ -675,37 +676,37 @@ } }, "node_modules/@jest/core": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.4.2.tgz", - "integrity": "sha512-KGuoQah0P3vGNlaS/l9/wQENZGNKGoWb+OPxh3gz+YzG7/XExvYu34MzikRndQCdM2S0tzExN4+FL37i6gZmCQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", "dev": true, "dependencies": { - "@jest/console": "^29.4.2", - "@jest/reporters": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.4.2", - "jest-config": "^29.4.2", - "jest-haste-map": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-regex-util": "^29.4.2", - "jest-resolve": "^29.4.2", - "jest-resolve-dependencies": "^29.4.2", - "jest-runner": "^29.4.2", - "jest-runtime": "^29.4.2", - "jest-snapshot": "^29.4.2", - "jest-util": "^29.4.2", - "jest-validate": "^29.4.2", - "jest-watcher": "^29.4.2", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", "micromatch": "^4.0.4", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -734,12 +735,12 @@ } }, "node_modules/@jest/core/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -754,88 +755,88 @@ "dev": true }, "node_modules/@jest/environment": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.4.2.tgz", - "integrity": "sha512-JKs3VUtse0vQfCaFGJRX1bir9yBdtasxziSyu+pIiEllAQOe4oQhdCYIf3+Lx+nGglFktSKToBnRJfD5QKp+NQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", "dev": true, "dependencies": { - "@jest/fake-timers": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.4.2" + "jest-mock": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.4.2.tgz", - "integrity": "sha512-NUAeZVApzyaeLjfWIV/64zXjA2SS+NuUPHpAlO7IwVMGd5Vf9szTl9KEDlxY3B4liwLO31os88tYNHl6cpjtKQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", "dev": true, "dependencies": { - "expect": "^29.4.2", - "jest-snapshot": "^29.4.2" + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.4.2.tgz", - "integrity": "sha512-Dd3ilDJpBnqa0GiPN7QrudVs0cczMMHtehSo2CSTjm3zdHx0RcpmhFNVEltuEFeqfLIyWKFI224FsMSQ/nsJQA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", "dev": true, "dependencies": { - "jest-get-type": "^29.4.2" + "jest-get-type": "^29.4.3" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.4.2.tgz", - "integrity": "sha512-Ny1u0Wg6kCsHFWq7A/rW/tMhIedq2siiyHyLpHCmIhP7WmcAmd2cx95P+0xtTZlj5ZbJxIRQi4OPydZZUoiSQQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", "dev": true, "dependencies": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.4.2", - "jest-mock": "^29.4.2", - "jest-util": "^29.4.2" + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/globals": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.4.2.tgz", - "integrity": "sha512-zCk70YGPzKnz/I9BNFDPlK+EuJLk21ur/NozVh6JVM86/YYZtZHqxFFQ62O9MWq7uf3vIZnvNA0BzzrtxD9iyg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", "dev": true, "dependencies": { - "@jest/environment": "^29.4.2", - "@jest/expect": "^29.4.2", - "@jest/types": "^29.4.2", - "jest-mock": "^29.4.2" + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/reporters": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.4.2.tgz", - "integrity": "sha512-10yw6YQe75zCgYcXgEND9kw3UZZH5tJeLzWv4vTk/2mrS1aY50A37F+XT2hPO5OqQFFnUWizXD8k1BMiATNfUw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", @@ -848,9 +849,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.4.2", - "jest-util": "^29.4.2", - "jest-worker": "^29.4.2", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -869,9 +870,9 @@ } }, "node_modules/@jest/schemas": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.2.tgz", - "integrity": "sha512-ZrGzGfh31NtdVH8tn0mgJw4khQuNHiKqdzJAFbCaERbyCP9tHlxWuL/mnMu8P7e/+k4puWjI1NOzi/sFsjce/g==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", "dev": true, "dependencies": { "@sinclair/typebox": "^0.25.16" @@ -881,9 +882,9 @@ } }, "node_modules/@jest/source-map": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.2.tgz", - "integrity": "sha512-tIoqV5ZNgYI9XCKXMqbYe5JbumcvyTgNN+V5QW4My033lanijvCD0D4PI9tBw4pRTqWOc00/7X3KVvUh+qnF4Q==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.15", @@ -895,13 +896,13 @@ } }, "node_modules/@jest/test-result": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.4.2.tgz", - "integrity": "sha512-HZsC3shhiHVvMtP+i55MGR5bPcc3obCFbA5bzIOb8pCjwBZf11cZliJncCgaVUbC5yoQNuGqCkC0Q3t6EItxZA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", "dev": true, "dependencies": { - "@jest/console": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, @@ -910,14 +911,14 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.4.2.tgz", - "integrity": "sha512-9Z2cVsD6CcObIVrWigHp2McRJhvCxL27xHtrZFgNC1RwnoSpDx6fZo8QYjJmziFlW9/hr78/3sxF54S8B6v8rg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", "dev": true, "dependencies": { - "@jest/test-result": "^29.4.2", + "@jest/test-result": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.4.2", + "jest-haste-map": "^29.5.0", "slash": "^3.0.0" }, "engines": { @@ -925,22 +926,22 @@ } }, "node_modules/@jest/transform": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.4.2.tgz", - "integrity": "sha512-kf1v5iTJHn7p9RbOsBuc/lcwyPtJaZJt5885C98omWz79NIeD3PfoiiaPSu7JyCyFzNOIzKhmMhQLUhlTL9BvQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.4.2", - "jest-regex-util": "^29.4.2", - "jest-util": "^29.4.2", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", @@ -951,12 +952,12 @@ } }, "node_modules/@jest/types": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.4.2.tgz", - "integrity": "sha512-CKlngyGP0fwlgC1BRUtPZSiWLBhyS9dKwKmyGxk8Z6M82LBEGB2aLQSg+U1MyLsU+M7UjnlLllBM2BLWKVm/Uw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -1155,9 +1156,9 @@ "link": true }, "node_modules/@sinclair/typebox": { - "version": "0.25.21", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.21.tgz", - "integrity": "sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g==", + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", "dev": true }, "node_modules/@sinonjs/commons": { @@ -1179,9 +1180,9 @@ } }, "node_modules/@testing-library/dom": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", - "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.0.1.tgz", + "integrity": "sha512-fTOVsMY9QLFCCXRHG3Ese6cMH5qIWwSbgxZsgeF5TNsy81HKaZ4kgehnSF8FsR3OF+numlIV2YcU79MzbnhSig==", "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", @@ -1190,25 +1191,25 @@ "aria-query": "^5.0.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", + "lz-string": "^1.5.0", "pretty-format": "^27.0.2" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.0.0.tgz", + "integrity": "sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", + "@testing-library/dom": "^9.0.0", "@types/react-dom": "^18.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" }, "peerDependencies": { "react": "^18.0.0", @@ -1225,9 +1226,9 @@ } }, "node_modules/@tsd/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-+UgxOvJUl5rQdPFSSOOwhmSmpThm8DJ3HwHxAOq5XYe7CcmG1LcM2QeqWwILzUIT5tbeMqY8qABiCsRtIjk/2g==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-UgFiSalbDaWrkMBQv8rHetnlwj3HVZtJo6i2aGLe50I6XdlPZFdGRfM2GOaP+i3Tm6p+YcyEql3yoi3ZPs/6Pw==", "dev": true }, "node_modules/@types/aria-query": { @@ -1327,9 +1328,9 @@ } }, "node_modules/@types/jest": { - "version": "29.4.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.0.tgz", - "integrity": "sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1349,12 +1350,12 @@ } }, "node_modules/@types/jest/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -1392,9 +1393,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "version": "18.15.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz", + "integrity": "sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -1427,9 +1428,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.0.10", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", - "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", + "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", "dev": true, "dependencies": { "@types/react": "*" @@ -1460,9 +1461,9 @@ "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.23.tgz", + "integrity": "sha512-yuogunc04OnzGQCrfHx+Kk883Q4X0aSwmYZhKjI21m+SVYzjIbrWl8dOOwSv5hf2Um2pdCOXWo9isteZTNXUZQ==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -1636,15 +1637,15 @@ } }, "node_modules/babel-jest": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.4.2.tgz", - "integrity": "sha512-vcghSqhtowXPG84posYkkkzcZsdayFkubUgbE3/1tuGbX7AQtwCkkNA/wIbB0BMjuCPoqTkiDyKN7Ty7d3uwNQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", "dev": true, "dependencies": { - "@jest/transform": "^29.4.2", + "@jest/transform": "^29.5.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.4.2", + "babel-preset-jest": "^29.5.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -1673,9 +1674,9 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.4.2.tgz", - "integrity": "sha512-5HZRCfMeWypFEonRbEkwWXtNS1sQK159LhRVyRuLzyfVBxDy/34Tr/rg4YVi0SScSJ4fqeaR/OIeceJ/LaQ0pQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", @@ -1711,12 +1712,12 @@ } }, "node_modules/babel-preset-jest": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.4.2.tgz", - "integrity": "sha512-ecWdaLY/8JyfUDr0oELBMpj3R5I1L6ZqG+kRJmwqfHtLWuPrJStR0LUkvUhfykJWTsXXMnohsayN/twltBbDrQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^29.4.2", + "babel-plugin-jest-hoist": "^29.5.0", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { @@ -1870,9 +1871,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001451", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz", - "integrity": "sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w==", + "version": "1.0.30001469", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001469.tgz", + "integrity": "sha512-Rcp7221ScNqQPP3W+lVOYDyjdR6dC+neEQCttoNr5bAyz54AboB4iwpnWgyi8P4YUsPybVzT4LgWiBbI3drL4g==", "dev": true, "funding": [ { @@ -2159,9 +2160,9 @@ "dev": true }, "node_modules/deepmerge": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", - "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "engines": { "node": ">=0.10.0" @@ -2202,9 +2203,9 @@ } }, "node_modules/diff-sequences": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.2.tgz", - "integrity": "sha512-R6P0Y6PrsH3n4hUXxL3nns0rbRk6Q33js3ygJBeEpbzLzgcNuJ61+u0RXasFpTKISw99TxUzFnumSnRLsjhLaw==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -2241,15 +2242,15 @@ } }, "node_modules/doubter": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/doubter/-/doubter-1.2.0.tgz", - "integrity": "sha512-HfsxdFbgu/F8wDJC6PR/+9AaZ6E3FRFcO4/BM6x6oC5z9iQRfoqXvGfBFS0w2zDQ4DcwP/PYmxXjpB9PSsip5Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doubter/-/doubter-2.1.0.tgz", + "integrity": "sha512-c+mrkVMpqnLjwkcsnMsZlvLwjeazuBbof3ocbDHK1DDptGUFCb/PNc+3djqcKOxMZcivOjqJtMoUUO97AASYog==", "peer": true }, "node_modules/electron-to-chromium": { - "version": "1.4.295", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz", - "integrity": "sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==", + "version": "1.4.334", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.334.tgz", + "integrity": "sha512-laZ1odk+TRen6q0GeyQx/JEkpD3iSZT7ewopCpKqg9bTjP1l8XRfU3Bg20CFjNPZkp5+NDBl3iqd4o/kPO+Vew==", "dev": true }, "node_modules/emittery": { @@ -2449,16 +2450,16 @@ } }, "node_modules/expect": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.4.2.tgz", - "integrity": "sha512-+JHYg9O3hd3RlICG90OPVjRkPBoiUH7PxvDVMnRiaq1g6JUgZStX514erMl0v2Dc5SkfVbm7ztqbd6qHHPn+mQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", "dev": true, "dependencies": { - "@jest/expect-utils": "^29.4.2", - "jest-get-type": "^29.4.2", - "jest-matcher-utils": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-util": "^29.4.2" + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -2725,9 +2726,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "node_modules/hard-rejection": { @@ -2981,9 +2982,9 @@ } }, "node_modules/irregular-plurals": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.4.0.tgz", - "integrity": "sha512-YXxECO/W6N9aMBVKMKKZ8TXESgq7EFrp3emCGGUcrYY1cgJIeZjoB75MTu8qi+NAKntS9NwPU8VdcQ3r6E6aWQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", + "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", "dev": true, "engines": { "node": ">=8" @@ -3006,13 +3007,13 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "is-typed-array": "^1.1.10" }, "funding": { @@ -3411,15 +3412,15 @@ } }, "node_modules/jest": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.4.2.tgz", - "integrity": "sha512-+5hLd260vNIHu+7ZgMIooSpKl7Jp5pHKb51e73AJU3owd5dEo/RfVwHbA/na3C/eozrt3hJOLGf96c7EWwIAzg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", "dev": true, "dependencies": { - "@jest/core": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", "import-local": "^3.0.2", - "jest-cli": "^29.4.2" + "jest-cli": "^29.5.0" }, "bin": { "jest": "bin/jest.js" @@ -3437,9 +3438,9 @@ } }, "node_modules/jest-changed-files": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.4.2.tgz", - "integrity": "sha512-Qdd+AXdqD16PQa+VsWJpxR3kN0JyOCX1iugQfx5nUgAsI4gwsKviXkpclxOK9ZnwaY2IQVHz+771eAvqeOlfuw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", "dev": true, "dependencies": { "execa": "^5.0.0", @@ -3450,28 +3451,29 @@ } }, "node_modules/jest-circus": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.4.2.tgz", - "integrity": "sha512-wW3ztp6a2P5c1yOc1Cfrt5ozJ7neWmqeXm/4SYiqcSriyisgq63bwFj1NuRdSR5iqS0CMEYwSZd89ZA47W9zUg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", "dev": true, "dependencies": { - "@jest/environment": "^29.4.2", - "@jest/expect": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.4.2", - "jest-matcher-utils": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-runtime": "^29.4.2", - "jest-snapshot": "^29.4.2", - "jest-util": "^29.4.2", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "p-limit": "^3.1.0", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -3492,12 +3494,12 @@ } }, "node_modules/jest-circus/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -3512,21 +3514,21 @@ "dev": true }, "node_modules/jest-cli": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.4.2.tgz", - "integrity": "sha512-b+eGUtXq/K2v7SH3QcJvFvaUaCDS1/YAZBYz0m28Q/Ppyr+1qNaHmVYikOrbHVbZqYQs2IeI3p76uy6BWbXq8Q==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", "dev": true, "dependencies": { - "@jest/core": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.4.2", - "jest-util": "^29.4.2", - "jest-validate": "^29.4.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "prompts": "^2.0.1", "yargs": "^17.3.1" }, @@ -3546,31 +3548,31 @@ } }, "node_modules/jest-config": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.4.2.tgz", - "integrity": "sha512-919CtnXic52YM0zW4C1QxjG6aNueX1kBGthuMtvFtRTAxhKfJmiXC9qwHmi6o2josjbDz8QlWyY55F1SIVmCWA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.4.2", - "@jest/types": "^29.4.2", - "babel-jest": "^29.4.2", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.4.2", - "jest-environment-node": "^29.4.2", - "jest-get-type": "^29.4.2", - "jest-regex-util": "^29.4.2", - "jest-resolve": "^29.4.2", - "jest-runner": "^29.4.2", - "jest-util": "^29.4.2", - "jest-validate": "^29.4.2", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -3603,12 +3605,12 @@ } }, "node_modules/jest-config/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -3623,15 +3625,15 @@ "dev": true }, "node_modules/jest-diff": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.4.2.tgz", - "integrity": "sha512-EK8DSajVtnjx9sa1BkjZq3mqChm2Cd8rIzdXkQMA8e0wuXq53ypz6s5o5V8HRZkoEt2ywJ3eeNWFKWeYr8HK4g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^29.4.2", - "jest-get-type": "^29.4.2", - "pretty-format": "^29.4.2" + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3650,12 +3652,12 @@ } }, "node_modules/jest-diff/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -3670,9 +3672,9 @@ "dev": true }, "node_modules/jest-docblock": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.2.tgz", - "integrity": "sha512-dV2JdahgClL34Y5vLrAHde3nF3yo2jKRH+GIYJuCpfqwEJZcikzeafVTGAjbOfKPG17ez9iWXwUYp7yefeCRag==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" @@ -3682,16 +3684,16 @@ } }, "node_modules/jest-each": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.4.2.tgz", - "integrity": "sha512-trvKZb0JYiCndc55V1Yh0Luqi7AsAdDWpV+mKT/5vkpnnFQfuQACV72IoRV161aAr6kAVIBpmYzwhBzm34vQkA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", "dev": true, "dependencies": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", - "jest-get-type": "^29.4.2", - "jest-util": "^29.4.2", - "pretty-format": "^29.4.2" + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3710,12 +3712,12 @@ } }, "node_modules/jest-each/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -3730,18 +3732,18 @@ "dev": true }, "node_modules/jest-environment-jsdom": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.4.2.tgz", - "integrity": "sha512-v1sH4Q0JGM+LPEGqHNM+m+uTMf3vpXpKiuDYqWUAh+0c9+nc7scGE+qTR5JuE+OOTDnwfzPgcv9sMq6zWAOaVg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.5.0.tgz", + "integrity": "sha512-/KG8yEK4aN8ak56yFVdqFDzKNHgF4BAymCx2LbPNPsUshUlfAl0eX402Xm1pt+eoG9SLZEUVifqXtX8SK74KCw==", "dev": true, "dependencies": { - "@jest/environment": "^29.4.2", - "@jest/fake-timers": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/jsdom": "^20.0.0", "@types/node": "*", - "jest-mock": "^29.4.2", - "jest-util": "^29.4.2", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0", "jsdom": "^20.0.0" }, "engines": { @@ -3757,46 +3759,46 @@ } }, "node_modules/jest-environment-node": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.4.2.tgz", - "integrity": "sha512-MLPrqUcOnNBc8zTOfqBbxtoa8/Ee8tZ7UFW7hRDQSUT+NGsvS96wlbHGTf+EFAT9KC3VNb7fWEM6oyvmxtE/9w==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "dependencies": { - "@jest/environment": "^29.4.2", - "@jest/fake-timers": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.4.2", - "jest-util": "^29.4.2" + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-get-type": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.2.tgz", - "integrity": "sha512-vERN30V5i2N6lqlFu4ljdTqQAgrkTFMC9xaIIfOPYBw04pufjXRty5RuXBiB1d72tGbURa/UgoiHB90ruOSivg==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-haste-map": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.4.2.tgz", - "integrity": "sha512-WkUgo26LN5UHPknkezrBzr7lUtV1OpGsp+NfXbBwHztsFruS3gz+AMTTBcEklvi8uPzpISzYjdKXYZQJXBnfvw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", "dev": true, "dependencies": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.2", - "jest-util": "^29.4.2", - "jest-worker": "^29.4.2", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "micromatch": "^4.0.4", "walker": "^1.0.8" }, @@ -3808,13 +3810,13 @@ } }, "node_modules/jest-leak-detector": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.4.2.tgz", - "integrity": "sha512-Wa62HuRJmWXtX9F00nUpWlrbaH5axeYCdyRsOs/+Rb1Vb6+qWTlB5rKwCCRKtorM7owNwKsyJ8NRDUcZ8ghYUA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", "dev": true, "dependencies": { - "jest-get-type": "^29.4.2", - "pretty-format": "^29.4.2" + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3833,12 +3835,12 @@ } }, "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -3853,15 +3855,15 @@ "dev": true }, "node_modules/jest-matcher-utils": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.4.2.tgz", - "integrity": "sha512-EZaAQy2je6Uqkrm6frnxBIdaWtSYFoR8SVb2sNLAtldswlR/29JAgx+hy67llT3+hXBaLB0zAm5UfeqerioZyg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^29.4.2", - "jest-get-type": "^29.4.2", - "pretty-format": "^29.4.2" + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3880,12 +3882,12 @@ } }, "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -3900,18 +3902,18 @@ "dev": true }, "node_modules/jest-message-util": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.4.2.tgz", - "integrity": "sha512-SElcuN4s6PNKpOEtTInjOAA8QvItu0iugkXqhYyguRvQoXapg5gN+9RQxLAkakChZA7Y26j6yUCsFWN+hlKD6g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -3932,12 +3934,12 @@ } }, "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -3952,14 +3954,14 @@ "dev": true }, "node_modules/jest-mock": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.4.2.tgz", - "integrity": "sha512-x1FSd4Gvx2yIahdaIKoBjwji6XpboDunSJ95RpntGrYulI1ByuYQCKN/P7hvk09JB74IonU3IPLdkutEWYt++g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", "dev": true, "dependencies": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-util": "^29.4.2" + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3983,26 +3985,26 @@ } }, "node_modules/jest-regex-util": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.2.tgz", - "integrity": "sha512-XYZXOqUl1y31H6VLMrrUL1ZhXuiymLKPz0BO1kEeR5xER9Tv86RZrjTm74g5l9bPJQXA/hyLdaVPN/sdqfteig==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.4.2.tgz", - "integrity": "sha512-RtKWW0mbR3I4UdkOrW7552IFGLYQ5AF9YrzD0FnIOkDu0rAMlA5/Y1+r7lhCAP4nXSBTaE7ueeqj6IOwZpgoqw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", "dev": true, "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.4.2", + "jest-haste-map": "^29.5.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.4.2", - "jest-validate": "^29.4.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "resolve": "^1.20.0", "resolve.exports": "^2.0.0", "slash": "^3.0.0" @@ -4012,43 +4014,43 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.4.2.tgz", - "integrity": "sha512-6pL4ptFw62rjdrPk7rRpzJYgcRqRZNsZTF1VxVTZMishbO6ObyWvX57yHOaNGgKoADtAHRFYdHQUEvYMJATbDg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", "dev": true, "dependencies": { - "jest-regex-util": "^29.4.2", - "jest-snapshot": "^29.4.2" + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-runner": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.4.2.tgz", - "integrity": "sha512-wqwt0drm7JGjwdH+x1XgAl+TFPH7poowMguPQINYxaukCqlczAcNLJiK+OLxUxQAEWMdy+e6nHZlFHO5s7EuRg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", "dev": true, "dependencies": { - "@jest/console": "^29.4.2", - "@jest/environment": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.2", - "jest-environment-node": "^29.4.2", - "jest-haste-map": "^29.4.2", - "jest-leak-detector": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-resolve": "^29.4.2", - "jest-runtime": "^29.4.2", - "jest-util": "^29.4.2", - "jest-watcher": "^29.4.2", - "jest-worker": "^29.4.2", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -4057,32 +4059,31 @@ } }, "node_modules/jest-runtime": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.4.2.tgz", - "integrity": "sha512-3fque9vtpLzGuxT9eZqhxi+9EylKK/ESfhClv4P7Y9sqJPs58LjVhTt8jaMp/pRO38agll1CkSu9z9ieTQeRrw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.4.2", - "@jest/fake-timers": "^29.4.2", - "@jest/globals": "^29.4.2", - "@jest/source-map": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-mock": "^29.4.2", - "jest-regex-util": "^29.4.2", - "jest-resolve": "^29.4.2", - "jest-snapshot": "^29.4.2", - "jest-util": "^29.4.2", - "semver": "^7.3.5", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -4090,43 +4091,10 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runtime/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-runtime/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-runtime/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/jest-snapshot": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.4.2.tgz", - "integrity": "sha512-PdfubrSNN5KwroyMH158R23tWcAXJyx4pvSvWls1dHoLCaUhGul9rsL3uVjtqzRpkxlkMavQjGuWG1newPgmkw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", @@ -4135,23 +4103,22 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.4.2", + "expect": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-diff": "^29.4.2", - "jest-get-type": "^29.4.2", - "jest-haste-map": "^29.4.2", - "jest-matcher-utils": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-util": "^29.4.2", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "natural-compare": "^1.4.0", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", "semver": "^7.3.5" }, "engines": { @@ -4183,12 +4150,12 @@ } }, "node_modules/jest-snapshot/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -4224,12 +4191,12 @@ "dev": true }, "node_modules/jest-util": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.4.2.tgz", - "integrity": "sha512-wKnm6XpJgzMUSRFB7YF48CuwdzuDIHenVuoIb1PLuJ6F+uErZsuDkU+EiExkChf6473XcawBrSfDSnXl+/YG4g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -4241,17 +4208,17 @@ } }, "node_modules/jest-validate": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.4.2.tgz", - "integrity": "sha512-tto7YKGPJyFbhcKhIDFq8B5od+eVWD/ySZ9Tvcp/NGCvYA4RQbuzhbwYWtIjMT5W5zA2W0eBJwu4HVw34d5G6Q==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", "dev": true, "dependencies": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^29.4.2", + "jest-get-type": "^29.4.3", "leven": "^3.1.0", - "pretty-format": "^29.4.2" + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4282,12 +4249,12 @@ } }, "node_modules/jest-validate/node_modules/pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -4302,18 +4269,18 @@ "dev": true }, "node_modules/jest-watcher": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.4.2.tgz", - "integrity": "sha512-onddLujSoGiMJt+tKutehIidABa175i/Ays+QvKxCqBwp7fvxP3ZhKsrIdOodt71dKxqk4sc0LN41mWLGIK44w==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", "dev": true, "dependencies": { - "@jest/test-result": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.4.2", + "jest-util": "^29.5.0", "string-length": "^4.0.1" }, "engines": { @@ -4321,13 +4288,13 @@ } }, "node_modules/jest-worker": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.4.2.tgz", - "integrity": "sha512-VIuZA2hZmFyRbchsUCHEehoSf2HEl0YVF8SDJqtPnKorAaBuh42V8QsLnde0XP5F6TyCynGPEGgBOn3Fc+wZGw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", "dev": true, "dependencies": { "@types/node": "*", - "jest-util": "^29.4.2", + "jest-util": "^29.5.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, @@ -4557,18 +4524,18 @@ "dev": true }, "node_modules/lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "bin": { "lz-string": "bin/bin.js" } }, "node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.13" @@ -4771,6 +4738,15 @@ "node": ">= 6" } }, + "node_modules/minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5077,6 +5053,31 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.1.tgz", + "integrity": "sha512-OW+5s+7cw6253Q4E+8qQ/u1fVvcJQCJo/VFD8pje+dbJCF1n5ZRMV2AEHbGp+5Q7jxQIYJxkHopnj6nzdGeZLA==", + "dev": true, + "dependencies": { + "lru-cache": "^7.14.1", + "minipass": "^4.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5150,9 +5151,9 @@ } }, "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.6.tgz", + "integrity": "sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -5218,6 +5219,22 @@ "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", + "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -5452,9 +5469,9 @@ } }, "node_modules/resolve.exports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.0.tgz", - "integrity": "sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", + "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", "dev": true, "engines": { "node": ">=10" @@ -5471,10 +5488,13 @@ } }, "node_modules/rimraf": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.1.2.tgz", - "integrity": "sha512-BlIbgFryTbw3Dz6hyoWFhKk+unCcHMSkZGrTFVAx2WmttdBSonsdtRlwiuTbDqTKr+UlXIUqJVS4QT5tUzGENQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.0.tgz", + "integrity": "sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==", "dev": true, + "dependencies": { + "glob": "^9.2.0" + }, "bin": { "rimraf": "dist/cjs/src/bin.js" }, @@ -5485,10 +5505,52 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.1.tgz", + "integrity": "sha512-qERvJb7IGsnkx6YYmaaGvDpf77c951hICMdWaFXyH3PlVob8sbPJJyJX0kWkiCWyXUzoy9UOTNjGg0RbD8bYIw==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.2.tgz", + "integrity": "sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rollup": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.15.0.tgz", - "integrity": "sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg==", + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.0.tgz", + "integrity": "sha512-YsIfrk80NqUDrxrjWPXUa7PWvAfegZEXHuPsEZg58fGCdjL1I9C1i/NaG+L+27kxxwkrG/QEDEQc8s/ynXWWGQ==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -5502,12 +5564,12 @@ } }, "node_modules/rollup-plugin-dts": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-5.1.1.tgz", - "integrity": "sha512-zpgo52XmnLg8w4k3MScinFHZK1+ro6r7uVe34fJ0Ee8AM45FvgvTuvfWWaRgIpA4pQ1BHJuu2ospncZhkcJVeA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-5.3.0.tgz", + "integrity": "sha512-8FXp0ZkyZj1iU5klkIJYLjIq/YZSwBoERu33QBDxm/1yw5UU4txrEtcmMkrq+ZiKu3Q4qvPCNqc3ovX6rjqzbQ==", "dev": true, "dependencies": { - "magic-string": "^0.27.0" + "magic-string": "^0.30.0" }, "engines": { "node": ">=v14" @@ -5520,7 +5582,7 @@ }, "peerDependencies": { "rollup": "^3.0.0", - "typescript": "^4.1" + "typescript": "^4.1 || ^5.0" } }, "node_modules/roqueform": { @@ -5675,9 +5737,9 @@ } }, "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -5701,9 +5763,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", "dev": true }, "node_modules/sprintf-js": { @@ -6014,14 +6076,15 @@ "dev": true }, "node_modules/tsd": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.25.0.tgz", - "integrity": "sha512-liUlvKtsdr+70XEZP/kkF6U8+Q9URZi4Pw58ih7a9x3kjJblG8rdVgvG62xcvkgRva1q3yWX5qAxfYZuYiC5CA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.28.0.tgz", + "integrity": "sha512-LWYyNoxmpp1PVfmSo84Uup304vclm4NHfS/YXUzNVRgvWrpkoSEmZuM0O5j58E+Z7fjjGRo6HlefGziKbD0zgw==", "dev": true, "dependencies": { - "@tsd/typescript": "~4.9.3", + "@tsd/typescript": "~5.0.2", "eslint-formatter-pretty": "^4.1.0", "globby": "^11.0.1", + "jest-diff": "^29.0.3", "meow": "^9.0.0", "path-exists": "^4.0.0", "read-pkg-up": "^7.0.0" @@ -6073,14 +6136,14 @@ } }, "node_modules/typedoc": { - "version": "0.23.25", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.25.tgz", - "integrity": "sha512-O1he153qVyoCgJYSvIyY3bPP1wAJTegZfa6tL3APinSZhJOf8CSd8F/21M6ex8pUY/fuY6n0jAsT4fIuMGA6sA==", + "version": "0.23.28", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.28.tgz", + "integrity": "sha512-9x1+hZWTHEQcGoP7qFmlo4unUoVJLB0H/8vfO/7wqTnZxg4kPuji9y3uRzEu0ZKez63OJAUmiGhUrtukC6Uj3w==", "dev": true, "dependencies": { "lunr": "^2.3.9", "marked": "^4.2.12", - "minimatch": "^6.1.6", + "minimatch": "^7.1.3", "shiki": "^0.14.1" }, "bin": { @@ -6090,7 +6153,7 @@ "node": ">= 14.14" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x" } }, "node_modules/typedoc/node_modules/brace-expansion": { @@ -6103,9 +6166,9 @@ } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", - "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.2.tgz", + "integrity": "sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -6118,16 +6181,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/universalify": { @@ -6176,9 +6239,9 @@ } }, "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -6393,9 +6456,9 @@ } }, "node_modules/ws": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", - "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, "engines": { "node": ">=10.0.0" @@ -6444,9 +6507,9 @@ "dev": true }, "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, "dependencies": { "cliui": "^8.0.1", @@ -6483,9 +6546,9 @@ } }, "node_modules/zod": { - "version": "3.20.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.6.tgz", - "integrity": "sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==", + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -6504,7 +6567,7 @@ "version": "1.0.0", "license": "MIT", "peerDependencies": { - "doubter": "^1.0.1", + "doubter": "^2.1.0", "roqueform": "^3.0.1" } }, @@ -6588,27 +6651,27 @@ } }, "@babel/compat-data": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", - "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", + "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", "dev": true }, "@babel/core": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", - "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", + "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", "dev": true, "requires": { - "@ampproject/remapping": "^2.1.0", + "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", + "@babel/generator": "^7.21.3", "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helpers": "^7.20.7", - "@babel/parser": "^7.20.7", + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.3", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.12", - "@babel/types": "^7.20.7", + "@babel/traverse": "^7.21.3", + "@babel/types": "^7.21.3", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -6625,13 +6688,14 @@ } }, "@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", + "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", "dev": true, "requires": { - "@babel/types": "^7.20.7", + "@babel/types": "^7.21.3", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "dependencies": { @@ -6668,13 +6732,13 @@ "dev": true }, "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", "dev": true, "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" } }, "@babel/helper-hoist-variables": { @@ -6696,9 +6760,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", + "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.18.9", @@ -6707,8 +6771,8 @@ "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.2", + "@babel/types": "^7.21.2" } }, "@babel/helper-plugin-utils": { @@ -6748,20 +6812,20 @@ "dev": true }, "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", + "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", "dev": true }, "@babel/helpers": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", - "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", + "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", "dev": true, "requires": { "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.13", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0" } }, "@babel/highlight": { @@ -6834,9 +6898,9 @@ } }, "@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", + "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -6966,9 +7030,9 @@ } }, "@babel/runtime": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", - "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "dev": true, "requires": { "regenerator-runtime": "^0.13.11" @@ -6986,27 +7050,27 @@ } }, "@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", + "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", + "@babel/generator": "^7.21.3", "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", + "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", + "@babel/parser": "^7.21.3", + "@babel/types": "^7.21.3", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", + "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.19.4", @@ -7040,51 +7104,51 @@ "dev": true }, "@jest/console": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.4.2.tgz", - "integrity": "sha512-0I/rEJwMpV9iwi9cDEnT71a5nNGK9lj8Z4+1pRAU2x/thVXCDnaTGrvxyK+cAqZTFVFCiR+hfVrP4l2m+dCmQg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", "dev": true, "requires": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.4.2", - "jest-util": "^29.4.2", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0" } }, "@jest/core": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.4.2.tgz", - "integrity": "sha512-KGuoQah0P3vGNlaS/l9/wQENZGNKGoWb+OPxh3gz+YzG7/XExvYu34MzikRndQCdM2S0tzExN4+FL37i6gZmCQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", "dev": true, "requires": { - "@jest/console": "^29.4.2", - "@jest/reporters": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.4.2", - "jest-config": "^29.4.2", - "jest-haste-map": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-regex-util": "^29.4.2", - "jest-resolve": "^29.4.2", - "jest-resolve-dependencies": "^29.4.2", - "jest-runner": "^29.4.2", - "jest-runtime": "^29.4.2", - "jest-snapshot": "^29.4.2", - "jest-util": "^29.4.2", - "jest-validate": "^29.4.2", - "jest-watcher": "^29.4.2", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", "micromatch": "^4.0.4", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -7096,12 +7160,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -7115,73 +7179,73 @@ } }, "@jest/environment": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.4.2.tgz", - "integrity": "sha512-JKs3VUtse0vQfCaFGJRX1bir9yBdtasxziSyu+pIiEllAQOe4oQhdCYIf3+Lx+nGglFktSKToBnRJfD5QKp+NQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", "dev": true, "requires": { - "@jest/fake-timers": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.4.2" + "jest-mock": "^29.5.0" } }, "@jest/expect": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.4.2.tgz", - "integrity": "sha512-NUAeZVApzyaeLjfWIV/64zXjA2SS+NuUPHpAlO7IwVMGd5Vf9szTl9KEDlxY3B4liwLO31os88tYNHl6cpjtKQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", "dev": true, "requires": { - "expect": "^29.4.2", - "jest-snapshot": "^29.4.2" + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" } }, "@jest/expect-utils": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.4.2.tgz", - "integrity": "sha512-Dd3ilDJpBnqa0GiPN7QrudVs0cczMMHtehSo2CSTjm3zdHx0RcpmhFNVEltuEFeqfLIyWKFI224FsMSQ/nsJQA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", "dev": true, "requires": { - "jest-get-type": "^29.4.2" + "jest-get-type": "^29.4.3" } }, "@jest/fake-timers": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.4.2.tgz", - "integrity": "sha512-Ny1u0Wg6kCsHFWq7A/rW/tMhIedq2siiyHyLpHCmIhP7WmcAmd2cx95P+0xtTZlj5ZbJxIRQi4OPydZZUoiSQQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", "dev": true, "requires": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.4.2", - "jest-mock": "^29.4.2", - "jest-util": "^29.4.2" + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" } }, "@jest/globals": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.4.2.tgz", - "integrity": "sha512-zCk70YGPzKnz/I9BNFDPlK+EuJLk21ur/NozVh6JVM86/YYZtZHqxFFQ62O9MWq7uf3vIZnvNA0BzzrtxD9iyg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", "dev": true, "requires": { - "@jest/environment": "^29.4.2", - "@jest/expect": "^29.4.2", - "@jest/types": "^29.4.2", - "jest-mock": "^29.4.2" + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" } }, "@jest/reporters": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.4.2.tgz", - "integrity": "sha512-10yw6YQe75zCgYcXgEND9kw3UZZH5tJeLzWv4vTk/2mrS1aY50A37F+XT2hPO5OqQFFnUWizXD8k1BMiATNfUw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", @@ -7194,9 +7258,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.4.2", - "jest-util": "^29.4.2", - "jest-worker": "^29.4.2", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -7204,18 +7268,18 @@ } }, "@jest/schemas": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.2.tgz", - "integrity": "sha512-ZrGzGfh31NtdVH8tn0mgJw4khQuNHiKqdzJAFbCaERbyCP9tHlxWuL/mnMu8P7e/+k4puWjI1NOzi/sFsjce/g==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", "dev": true, "requires": { "@sinclair/typebox": "^0.25.16" } }, "@jest/source-map": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.2.tgz", - "integrity": "sha512-tIoqV5ZNgYI9XCKXMqbYe5JbumcvyTgNN+V5QW4My033lanijvCD0D4PI9tBw4pRTqWOc00/7X3KVvUh+qnF4Q==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.15", @@ -7224,46 +7288,46 @@ } }, "@jest/test-result": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.4.2.tgz", - "integrity": "sha512-HZsC3shhiHVvMtP+i55MGR5bPcc3obCFbA5bzIOb8pCjwBZf11cZliJncCgaVUbC5yoQNuGqCkC0Q3t6EItxZA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", "dev": true, "requires": { - "@jest/console": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.4.2.tgz", - "integrity": "sha512-9Z2cVsD6CcObIVrWigHp2McRJhvCxL27xHtrZFgNC1RwnoSpDx6fZo8QYjJmziFlW9/hr78/3sxF54S8B6v8rg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", "dev": true, "requires": { - "@jest/test-result": "^29.4.2", + "@jest/test-result": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.4.2", + "jest-haste-map": "^29.5.0", "slash": "^3.0.0" } }, "@jest/transform": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.4.2.tgz", - "integrity": "sha512-kf1v5iTJHn7p9RbOsBuc/lcwyPtJaZJt5885C98omWz79NIeD3PfoiiaPSu7JyCyFzNOIzKhmMhQLUhlTL9BvQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.4.2", - "jest-regex-util": "^29.4.2", - "jest-util": "^29.4.2", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", @@ -7271,12 +7335,12 @@ } }, "@jest/types": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.4.2.tgz", - "integrity": "sha512-CKlngyGP0fwlgC1BRUtPZSiWLBhyS9dKwKmyGxk8Z6M82LBEGB2aLQSg+U1MyLsU+M7UjnlLllBM2BLWKVm/Uw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -7410,7 +7474,7 @@ "@roqueform/uncontrolled-plugin": { "version": "file:packages/uncontrolled-plugin", "requires": { - "fast-deep-equal": "*" + "fast-deep-equal": "^3.1.3" } }, "@roqueform/zod-plugin": { @@ -7418,9 +7482,9 @@ "requires": {} }, "@sinclair/typebox": { - "version": "0.25.21", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.21.tgz", - "integrity": "sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g==", + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", "dev": true }, "@sinonjs/commons": { @@ -7442,9 +7506,9 @@ } }, "@testing-library/dom": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", - "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.0.1.tgz", + "integrity": "sha512-fTOVsMY9QLFCCXRHG3Ese6cMH5qIWwSbgxZsgeF5TNsy81HKaZ4kgehnSF8FsR3OF+numlIV2YcU79MzbnhSig==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", @@ -7453,18 +7517,18 @@ "aria-query": "^5.0.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", + "lz-string": "^1.5.0", "pretty-format": "^27.0.2" } }, "@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.0.0.tgz", + "integrity": "sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", + "@testing-library/dom": "^9.0.0", "@types/react-dom": "^18.0.0" } }, @@ -7475,9 +7539,9 @@ "dev": true }, "@tsd/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-+UgxOvJUl5rQdPFSSOOwhmSmpThm8DJ3HwHxAOq5XYe7CcmG1LcM2QeqWwILzUIT5tbeMqY8qABiCsRtIjk/2g==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-UgFiSalbDaWrkMBQv8rHetnlwj3HVZtJo6i2aGLe50I6XdlPZFdGRfM2GOaP+i3Tm6p+YcyEql3yoi3ZPs/6Pw==", "dev": true }, "@types/aria-query": { @@ -7577,9 +7641,9 @@ } }, "@types/jest": { - "version": "29.4.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.0.tgz", - "integrity": "sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", "dev": true, "requires": { "expect": "^29.0.0", @@ -7593,12 +7657,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -7635,9 +7699,9 @@ "dev": true }, "@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "version": "18.15.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz", + "integrity": "sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==", "dev": true }, "@types/normalize-package-data": { @@ -7670,9 +7734,9 @@ } }, "@types/react-dom": { - "version": "18.0.10", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", - "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", + "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", "dev": true, "requires": { "@types/react": "*" @@ -7703,9 +7767,9 @@ "dev": true }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.23.tgz", + "integrity": "sha512-yuogunc04OnzGQCrfHx+Kk883Q4X0aSwmYZhKjI21m+SVYzjIbrWl8dOOwSv5hf2Um2pdCOXWo9isteZTNXUZQ==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -7837,15 +7901,15 @@ "dev": true }, "babel-jest": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.4.2.tgz", - "integrity": "sha512-vcghSqhtowXPG84posYkkkzcZsdayFkubUgbE3/1tuGbX7AQtwCkkNA/wIbB0BMjuCPoqTkiDyKN7Ty7d3uwNQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", "dev": true, "requires": { - "@jest/transform": "^29.4.2", + "@jest/transform": "^29.5.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.4.2", + "babel-preset-jest": "^29.5.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -7865,9 +7929,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.4.2.tgz", - "integrity": "sha512-5HZRCfMeWypFEonRbEkwWXtNS1sQK159LhRVyRuLzyfVBxDy/34Tr/rg4YVi0SScSJ4fqeaR/OIeceJ/LaQ0pQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -7897,12 +7961,12 @@ } }, "babel-preset-jest": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.4.2.tgz", - "integrity": "sha512-ecWdaLY/8JyfUDr0oELBMpj3R5I1L6ZqG+kRJmwqfHtLWuPrJStR0LUkvUhfykJWTsXXMnohsayN/twltBbDrQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^29.4.2", + "babel-plugin-jest-hoist": "^29.5.0", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -8007,9 +8071,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001451", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz", - "integrity": "sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w==", + "version": "1.0.30001469", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001469.tgz", + "integrity": "sha512-Rcp7221ScNqQPP3W+lVOYDyjdR6dC+neEQCttoNr5bAyz54AboB4iwpnWgyi8P4YUsPybVzT4LgWiBbI3drL4g==", "dev": true }, "chalk": { @@ -8227,9 +8291,9 @@ "dev": true }, "deepmerge": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", - "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true }, "define-properties": { @@ -8255,9 +8319,9 @@ "dev": true }, "diff-sequences": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.2.tgz", - "integrity": "sha512-R6P0Y6PrsH3n4hUXxL3nns0rbRk6Q33js3ygJBeEpbzLzgcNuJ61+u0RXasFpTKISw99TxUzFnumSnRLsjhLaw==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", "dev": true }, "dir-glob": { @@ -8285,15 +8349,15 @@ } }, "doubter": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/doubter/-/doubter-1.2.0.tgz", - "integrity": "sha512-HfsxdFbgu/F8wDJC6PR/+9AaZ6E3FRFcO4/BM6x6oC5z9iQRfoqXvGfBFS0w2zDQ4DcwP/PYmxXjpB9PSsip5Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doubter/-/doubter-2.1.0.tgz", + "integrity": "sha512-c+mrkVMpqnLjwkcsnMsZlvLwjeazuBbof3ocbDHK1DDptGUFCb/PNc+3djqcKOxMZcivOjqJtMoUUO97AASYog==", "peer": true }, "electron-to-chromium": { - "version": "1.4.295", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz", - "integrity": "sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==", + "version": "1.4.334", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.334.tgz", + "integrity": "sha512-laZ1odk+TRen6q0GeyQx/JEkpD3iSZT7ewopCpKqg9bTjP1l8XRfU3Bg20CFjNPZkp5+NDBl3iqd4o/kPO+Vew==", "dev": true }, "emittery": { @@ -8435,16 +8499,16 @@ "dev": true }, "expect": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.4.2.tgz", - "integrity": "sha512-+JHYg9O3hd3RlICG90OPVjRkPBoiUH7PxvDVMnRiaq1g6JUgZStX514erMl0v2Dc5SkfVbm7ztqbd6qHHPn+mQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", "dev": true, "requires": { - "@jest/expect-utils": "^29.4.2", - "jest-get-type": "^29.4.2", - "jest-matcher-utils": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-util": "^29.4.2" + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" } }, "fast-deep-equal": { @@ -8647,9 +8711,9 @@ } }, "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "hard-rejection": { @@ -8836,9 +8900,9 @@ } }, "irregular-plurals": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.4.0.tgz", - "integrity": "sha512-YXxECO/W6N9aMBVKMKKZ8TXESgq7EFrp3emCGGUcrYY1cgJIeZjoB75MTu8qi+NAKntS9NwPU8VdcQ3r6E6aWQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", + "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", "dev": true }, "is-arguments": { @@ -8852,13 +8916,13 @@ } }, "is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", "dev": true, "requires": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "is-typed-array": "^1.1.10" } }, @@ -9134,21 +9198,21 @@ } }, "jest": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.4.2.tgz", - "integrity": "sha512-+5hLd260vNIHu+7ZgMIooSpKl7Jp5pHKb51e73AJU3owd5dEo/RfVwHbA/na3C/eozrt3hJOLGf96c7EWwIAzg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", "dev": true, "requires": { - "@jest/core": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", "import-local": "^3.0.2", - "jest-cli": "^29.4.2" + "jest-cli": "^29.5.0" } }, "jest-changed-files": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.4.2.tgz", - "integrity": "sha512-Qdd+AXdqD16PQa+VsWJpxR3kN0JyOCX1iugQfx5nUgAsI4gwsKviXkpclxOK9ZnwaY2IQVHz+771eAvqeOlfuw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", "dev": true, "requires": { "execa": "^5.0.0", @@ -9156,28 +9220,29 @@ } }, "jest-circus": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.4.2.tgz", - "integrity": "sha512-wW3ztp6a2P5c1yOc1Cfrt5ozJ7neWmqeXm/4SYiqcSriyisgq63bwFj1NuRdSR5iqS0CMEYwSZd89ZA47W9zUg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", "dev": true, "requires": { - "@jest/environment": "^29.4.2", - "@jest/expect": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.4.2", - "jest-matcher-utils": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-runtime": "^29.4.2", - "jest-snapshot": "^29.4.2", - "jest-util": "^29.4.2", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "p-limit": "^3.1.0", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -9189,12 +9254,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -9208,51 +9273,51 @@ } }, "jest-cli": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.4.2.tgz", - "integrity": "sha512-b+eGUtXq/K2v7SH3QcJvFvaUaCDS1/YAZBYz0m28Q/Ppyr+1qNaHmVYikOrbHVbZqYQs2IeI3p76uy6BWbXq8Q==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", "dev": true, "requires": { - "@jest/core": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.4.2", - "jest-util": "^29.4.2", - "jest-validate": "^29.4.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "prompts": "^2.0.1", "yargs": "^17.3.1" } }, "jest-config": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.4.2.tgz", - "integrity": "sha512-919CtnXic52YM0zW4C1QxjG6aNueX1kBGthuMtvFtRTAxhKfJmiXC9qwHmi6o2josjbDz8QlWyY55F1SIVmCWA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.4.2", - "@jest/types": "^29.4.2", - "babel-jest": "^29.4.2", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.4.2", - "jest-environment-node": "^29.4.2", - "jest-get-type": "^29.4.2", - "jest-regex-util": "^29.4.2", - "jest-resolve": "^29.4.2", - "jest-runner": "^29.4.2", - "jest-util": "^29.4.2", - "jest-validate": "^29.4.2", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -9264,12 +9329,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -9283,15 +9348,15 @@ } }, "jest-diff": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.4.2.tgz", - "integrity": "sha512-EK8DSajVtnjx9sa1BkjZq3mqChm2Cd8rIzdXkQMA8e0wuXq53ypz6s5o5V8HRZkoEt2ywJ3eeNWFKWeYr8HK4g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^29.4.2", - "jest-get-type": "^29.4.2", - "pretty-format": "^29.4.2" + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "dependencies": { "ansi-styles": { @@ -9301,12 +9366,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -9320,25 +9385,25 @@ } }, "jest-docblock": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.2.tgz", - "integrity": "sha512-dV2JdahgClL34Y5vLrAHde3nF3yo2jKRH+GIYJuCpfqwEJZcikzeafVTGAjbOfKPG17ez9iWXwUYp7yefeCRag==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.4.2.tgz", - "integrity": "sha512-trvKZb0JYiCndc55V1Yh0Luqi7AsAdDWpV+mKT/5vkpnnFQfuQACV72IoRV161aAr6kAVIBpmYzwhBzm34vQkA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", "dev": true, "requires": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", - "jest-get-type": "^29.4.2", - "jest-util": "^29.4.2", - "pretty-format": "^29.4.2" + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" }, "dependencies": { "ansi-styles": { @@ -9348,12 +9413,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -9367,69 +9432,69 @@ } }, "jest-environment-jsdom": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.4.2.tgz", - "integrity": "sha512-v1sH4Q0JGM+LPEGqHNM+m+uTMf3vpXpKiuDYqWUAh+0c9+nc7scGE+qTR5JuE+OOTDnwfzPgcv9sMq6zWAOaVg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.5.0.tgz", + "integrity": "sha512-/KG8yEK4aN8ak56yFVdqFDzKNHgF4BAymCx2LbPNPsUshUlfAl0eX402Xm1pt+eoG9SLZEUVifqXtX8SK74KCw==", "dev": true, "requires": { - "@jest/environment": "^29.4.2", - "@jest/fake-timers": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/jsdom": "^20.0.0", "@types/node": "*", - "jest-mock": "^29.4.2", - "jest-util": "^29.4.2", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0", "jsdom": "^20.0.0" } }, "jest-environment-node": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.4.2.tgz", - "integrity": "sha512-MLPrqUcOnNBc8zTOfqBbxtoa8/Ee8tZ7UFW7hRDQSUT+NGsvS96wlbHGTf+EFAT9KC3VNb7fWEM6oyvmxtE/9w==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "requires": { - "@jest/environment": "^29.4.2", - "@jest/fake-timers": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.4.2", - "jest-util": "^29.4.2" + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" } }, "jest-get-type": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.2.tgz", - "integrity": "sha512-vERN30V5i2N6lqlFu4ljdTqQAgrkTFMC9xaIIfOPYBw04pufjXRty5RuXBiB1d72tGbURa/UgoiHB90ruOSivg==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true }, "jest-haste-map": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.4.2.tgz", - "integrity": "sha512-WkUgo26LN5UHPknkezrBzr7lUtV1OpGsp+NfXbBwHztsFruS3gz+AMTTBcEklvi8uPzpISzYjdKXYZQJXBnfvw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", "dev": true, "requires": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.2", - "jest-util": "^29.4.2", - "jest-worker": "^29.4.2", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "micromatch": "^4.0.4", "walker": "^1.0.8" } }, "jest-leak-detector": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.4.2.tgz", - "integrity": "sha512-Wa62HuRJmWXtX9F00nUpWlrbaH5axeYCdyRsOs/+Rb1Vb6+qWTlB5rKwCCRKtorM7owNwKsyJ8NRDUcZ8ghYUA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", "dev": true, "requires": { - "jest-get-type": "^29.4.2", - "pretty-format": "^29.4.2" + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "dependencies": { "ansi-styles": { @@ -9439,12 +9504,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -9458,15 +9523,15 @@ } }, "jest-matcher-utils": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.4.2.tgz", - "integrity": "sha512-EZaAQy2je6Uqkrm6frnxBIdaWtSYFoR8SVb2sNLAtldswlR/29JAgx+hy67llT3+hXBaLB0zAm5UfeqerioZyg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^29.4.2", - "jest-get-type": "^29.4.2", - "pretty-format": "^29.4.2" + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "dependencies": { "ansi-styles": { @@ -9476,12 +9541,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -9495,18 +9560,18 @@ } }, "jest-message-util": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.4.2.tgz", - "integrity": "sha512-SElcuN4s6PNKpOEtTInjOAA8QvItu0iugkXqhYyguRvQoXapg5gN+9RQxLAkakChZA7Y26j6yUCsFWN+hlKD6g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -9518,12 +9583,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -9537,14 +9602,14 @@ } }, "jest-mock": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.4.2.tgz", - "integrity": "sha512-x1FSd4Gvx2yIahdaIKoBjwji6XpboDunSJ95RpntGrYulI1ByuYQCKN/P7hvk09JB74IonU3IPLdkutEWYt++g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", "dev": true, "requires": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-util": "^29.4.2" + "jest-util": "^29.5.0" } }, "jest-pnp-resolver": { @@ -9555,128 +9620,101 @@ "requires": {} }, "jest-regex-util": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.2.tgz", - "integrity": "sha512-XYZXOqUl1y31H6VLMrrUL1ZhXuiymLKPz0BO1kEeR5xER9Tv86RZrjTm74g5l9bPJQXA/hyLdaVPN/sdqfteig==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", "dev": true }, "jest-resolve": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.4.2.tgz", - "integrity": "sha512-RtKWW0mbR3I4UdkOrW7552IFGLYQ5AF9YrzD0FnIOkDu0rAMlA5/Y1+r7lhCAP4nXSBTaE7ueeqj6IOwZpgoqw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", "dev": true, "requires": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.4.2", + "jest-haste-map": "^29.5.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.4.2", - "jest-validate": "^29.4.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "resolve": "^1.20.0", "resolve.exports": "^2.0.0", "slash": "^3.0.0" } }, "jest-resolve-dependencies": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.4.2.tgz", - "integrity": "sha512-6pL4ptFw62rjdrPk7rRpzJYgcRqRZNsZTF1VxVTZMishbO6ObyWvX57yHOaNGgKoADtAHRFYdHQUEvYMJATbDg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", "dev": true, "requires": { - "jest-regex-util": "^29.4.2", - "jest-snapshot": "^29.4.2" + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" } }, "jest-runner": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.4.2.tgz", - "integrity": "sha512-wqwt0drm7JGjwdH+x1XgAl+TFPH7poowMguPQINYxaukCqlczAcNLJiK+OLxUxQAEWMdy+e6nHZlFHO5s7EuRg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", "dev": true, "requires": { - "@jest/console": "^29.4.2", - "@jest/environment": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.2", - "jest-environment-node": "^29.4.2", - "jest-haste-map": "^29.4.2", - "jest-leak-detector": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-resolve": "^29.4.2", - "jest-runtime": "^29.4.2", - "jest-util": "^29.4.2", - "jest-watcher": "^29.4.2", - "jest-worker": "^29.4.2", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" } }, "jest-runtime": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.4.2.tgz", - "integrity": "sha512-3fque9vtpLzGuxT9eZqhxi+9EylKK/ESfhClv4P7Y9sqJPs58LjVhTt8jaMp/pRO38agll1CkSu9z9ieTQeRrw==", - "dev": true, - "requires": { - "@jest/environment": "^29.4.2", - "@jest/fake-timers": "^29.4.2", - "@jest/globals": "^29.4.2", - "@jest/source-map": "^29.4.2", - "@jest/test-result": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-mock": "^29.4.2", - "jest-regex-util": "^29.4.2", - "jest-resolve": "^29.4.2", - "jest-snapshot": "^29.4.2", - "jest-util": "^29.4.2", - "semver": "^7.3.5", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } } }, "jest-snapshot": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.4.2.tgz", - "integrity": "sha512-PdfubrSNN5KwroyMH158R23tWcAXJyx4pvSvWls1dHoLCaUhGul9rsL3uVjtqzRpkxlkMavQjGuWG1newPgmkw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", "dev": true, "requires": { "@babel/core": "^7.11.6", @@ -9685,23 +9723,22 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.4.2", - "@jest/transform": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.4.2", + "expect": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-diff": "^29.4.2", - "jest-get-type": "^29.4.2", - "jest-haste-map": "^29.4.2", - "jest-matcher-utils": "^29.4.2", - "jest-message-util": "^29.4.2", - "jest-util": "^29.4.2", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "natural-compare": "^1.4.0", - "pretty-format": "^29.4.2", + "pretty-format": "^29.5.0", "semver": "^7.3.5" }, "dependencies": { @@ -9721,12 +9758,12 @@ } }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -9755,12 +9792,12 @@ } }, "jest-util": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.4.2.tgz", - "integrity": "sha512-wKnm6XpJgzMUSRFB7YF48CuwdzuDIHenVuoIb1PLuJ6F+uErZsuDkU+EiExkChf6473XcawBrSfDSnXl+/YG4g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -9769,17 +9806,17 @@ } }, "jest-validate": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.4.2.tgz", - "integrity": "sha512-tto7YKGPJyFbhcKhIDFq8B5od+eVWD/ySZ9Tvcp/NGCvYA4RQbuzhbwYWtIjMT5W5zA2W0eBJwu4HVw34d5G6Q==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", "dev": true, "requires": { - "@jest/types": "^29.4.2", + "@jest/types": "^29.5.0", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^29.4.2", + "jest-get-type": "^29.4.3", "leven": "^3.1.0", - "pretty-format": "^29.4.2" + "pretty-format": "^29.5.0" }, "dependencies": { "ansi-styles": { @@ -9795,12 +9832,12 @@ "dev": true }, "pretty-format": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.2.tgz", - "integrity": "sha512-qKlHR8yFVCbcEWba0H0TOC8dnLlO4vPlyEjRPw31FZ2Rupy9nLa8ZLbYny8gWEl8CkEhJqAE6IzdNELTBVcBEg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^29.4.2", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } @@ -9814,29 +9851,29 @@ } }, "jest-watcher": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.4.2.tgz", - "integrity": "sha512-onddLujSoGiMJt+tKutehIidABa175i/Ays+QvKxCqBwp7fvxP3ZhKsrIdOodt71dKxqk4sc0LN41mWLGIK44w==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", "dev": true, "requires": { - "@jest/test-result": "^29.4.2", - "@jest/types": "^29.4.2", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.4.2", + "jest-util": "^29.5.0", "string-length": "^4.0.1" } }, "jest-worker": { - "version": "29.4.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.4.2.tgz", - "integrity": "sha512-VIuZA2hZmFyRbchsUCHEehoSf2HEl0YVF8SDJqtPnKorAaBuh42V8QsLnde0XP5F6TyCynGPEGgBOn3Fc+wZGw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", "dev": true, "requires": { "@types/node": "*", - "jest-util": "^29.4.2", + "jest-util": "^29.5.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, @@ -10009,15 +10046,15 @@ "dev": true }, "lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true }, "magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", "dev": true, "requires": { "@jridgewell/sourcemap-codec": "^1.4.13" @@ -10162,6 +10199,12 @@ "kind-of": "^6.0.3" } }, + "minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -10391,6 +10434,24 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-scurry": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.1.tgz", + "integrity": "sha512-OW+5s+7cw6253Q4E+8qQ/u1fVvcJQCJo/VFD8pje+dbJCF1n5ZRMV2AEHbGp+5Q7jxQIYJxkHopnj6nzdGeZLA==", + "dev": true, + "requires": { + "lru-cache": "^7.14.1", + "minipass": "^4.0.2" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + } + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -10440,9 +10501,9 @@ "dev": true }, "prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.6.tgz", + "integrity": "sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ==", "dev": true }, "pretty-format": { @@ -10486,6 +10547,12 @@ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true }, + "pure-rand": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", + "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", + "dev": true + }, "querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -10659,9 +10726,9 @@ "dev": true }, "resolve.exports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.0.tgz", - "integrity": "sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", + "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", "dev": true }, "reusify": { @@ -10671,28 +10738,63 @@ "dev": true }, "rimraf": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.1.2.tgz", - "integrity": "sha512-BlIbgFryTbw3Dz6hyoWFhKk+unCcHMSkZGrTFVAx2WmttdBSonsdtRlwiuTbDqTKr+UlXIUqJVS4QT5tUzGENQ==", - "dev": true + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.0.tgz", + "integrity": "sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==", + "dev": true, + "requires": { + "glob": "^9.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.1.tgz", + "integrity": "sha512-qERvJb7IGsnkx6YYmaaGvDpf77c951hICMdWaFXyH3PlVob8sbPJJyJX0kWkiCWyXUzoy9UOTNjGg0RbD8bYIw==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + } + }, + "minimatch": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.2.tgz", + "integrity": "sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } }, "rollup": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.15.0.tgz", - "integrity": "sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg==", + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.0.tgz", + "integrity": "sha512-YsIfrk80NqUDrxrjWPXUa7PWvAfegZEXHuPsEZg58fGCdjL1I9C1i/NaG+L+27kxxwkrG/QEDEQc8s/ynXWWGQ==", "dev": true, "requires": { "fsevents": "~2.3.2" } }, "rollup-plugin-dts": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-5.1.1.tgz", - "integrity": "sha512-zpgo52XmnLg8w4k3MScinFHZK1+ro6r7uVe34fJ0Ee8AM45FvgvTuvfWWaRgIpA4pQ1BHJuu2ospncZhkcJVeA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-5.3.0.tgz", + "integrity": "sha512-8FXp0ZkyZj1iU5klkIJYLjIq/YZSwBoERu33QBDxm/1yw5UU4txrEtcmMkrq+ZiKu3Q4qvPCNqc3ovX6rjqzbQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "magic-string": "^0.27.0" + "magic-string": "^0.30.0" } }, "roqueform": { @@ -10811,9 +10913,9 @@ } }, "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -10837,9 +10939,9 @@ } }, "spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", "dev": true }, "sprintf-js": { @@ -11056,14 +11158,15 @@ } }, "tsd": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.25.0.tgz", - "integrity": "sha512-liUlvKtsdr+70XEZP/kkF6U8+Q9URZi4Pw58ih7a9x3kjJblG8rdVgvG62xcvkgRva1q3yWX5qAxfYZuYiC5CA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.28.0.tgz", + "integrity": "sha512-LWYyNoxmpp1PVfmSo84Uup304vclm4NHfS/YXUzNVRgvWrpkoSEmZuM0O5j58E+Z7fjjGRo6HlefGziKbD0zgw==", "dev": true, "requires": { - "@tsd/typescript": "~4.9.3", + "@tsd/typescript": "~5.0.2", "eslint-formatter-pretty": "^4.1.0", "globby": "^11.0.1", + "jest-diff": "^29.0.3", "meow": "^9.0.0", "path-exists": "^4.0.0", "read-pkg-up": "^7.0.0" @@ -11097,14 +11200,14 @@ "dev": true }, "typedoc": { - "version": "0.23.25", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.25.tgz", - "integrity": "sha512-O1he153qVyoCgJYSvIyY3bPP1wAJTegZfa6tL3APinSZhJOf8CSd8F/21M6ex8pUY/fuY6n0jAsT4fIuMGA6sA==", + "version": "0.23.28", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.28.tgz", + "integrity": "sha512-9x1+hZWTHEQcGoP7qFmlo4unUoVJLB0H/8vfO/7wqTnZxg4kPuji9y3uRzEu0ZKez63OJAUmiGhUrtukC6Uj3w==", "dev": true, "requires": { "lunr": "^2.3.9", "marked": "^4.2.12", - "minimatch": "^6.1.6", + "minimatch": "^7.1.3", "shiki": "^0.14.1" }, "dependencies": { @@ -11118,9 +11221,9 @@ } }, "minimatch": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", - "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.2.tgz", + "integrity": "sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -11129,9 +11232,9 @@ } }, "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", "dev": true }, "universalify": { @@ -11161,9 +11264,9 @@ } }, "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.12", @@ -11332,9 +11435,9 @@ } }, "ws": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", - "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, "requires": {} }, @@ -11363,9 +11466,9 @@ "dev": true }, "yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, "requires": { "cliui": "^8.0.1", @@ -11390,9 +11493,9 @@ "dev": true }, "zod": { - "version": "3.20.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.6.tgz", - "integrity": "sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==", + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", "peer": true } } diff --git a/package.json b/package.json index d52f748..3529bfa 100644 --- a/package.json +++ b/package.json @@ -21,20 +21,20 @@ "devDependencies": { "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-typescript": "^11.0.0", - "@testing-library/dom": "^8.20.0", - "@testing-library/react": "^13.4.0", - "@types/jest": "^29.4.0", + "@testing-library/dom": "^9.0.1", + "@testing-library/react": "^14.0.0", + "@types/jest": "^29.5.0", "@types/react": "^18.0.28", - "jest": "^29.4.2", - "jest-environment-jsdom": "^29.4.2", - "prettier": "^2.8.4", - "rimraf": "^4.1.2", - "rollup": "^3.15.0", - "rollup-plugin-dts": "^5.1.1", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "prettier": "^2.8.6", + "rimraf": "^4.4.0", + "rollup": "^3.20.0", + "rollup-plugin-dts": "^5.3.0", "ts-jest": "^29.0.5", - "tsd": "^0.25.0", + "tsd": "^0.28.0", "tslib": "^2.5.0", "typedoc": "^0.23.25", - "typescript": "^4.9.5" + "typescript": "^5.0.2" } } diff --git a/packages/constraint-validation-plugin/README.md b/packages/constraint-validation-plugin/README.md index 56e9e8c..3666550 100644 --- a/packages/constraint-validation-plugin/README.md +++ b/packages/constraint-validation-plugin/README.md @@ -1,7 +1,7 @@ # Constraint validation API plugin for Roqueform -Enhances [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields with validation methods that use -[Constraint validation API](https://developer.mozilla.org/en-US/docs/Web/API/Constraint_validation). +Integrates [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields with +[Constraint validation API.](https://developer.mozilla.org/en-US/docs/Web/API/Constraint_validation) ```sh npm install --save-prod @roqueform/constraint-validation-plugin @@ -9,34 +9,34 @@ npm install --save-prod @roqueform/constraint-validation-plugin # Usage example -🔎[API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/Constraint_Validation_Plugin.html) +🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/constraint_validation_plugin.html) ```tsx import { useEffect } from 'react'; -import { useField } from 'roqueform'; +import { FieldRenderer, useField } from '@roqueform/react'; import { constraintValidationPlugin } from '@roqueform/constraint-validation-plugin'; export const App = () => { - const rootField = useField({ bar: 'qux' }, constraintValidationPlugin()); + const planetField = useField({ name: 'Mars' }, constraintValidationPlugin()); useEffect(() => { - rootField.reportValidity(); + planetField.reportValidity(); }, []); return ( - - {barField => ( + + {nameField => ( { - barField.dispatchValue(event.target.value); + nameField.setValue(event.target.value); }} /> )} - +
); }; ``` diff --git a/packages/constraint-validation-plugin/package.json b/packages/constraint-validation-plugin/package.json index d9eafca..6ca08d8 100644 --- a/packages/constraint-validation-plugin/package.json +++ b/packages/constraint-validation-plugin/package.json @@ -1,13 +1,14 @@ { "name": "@roqueform/constraint-validation-plugin", "version": "1.0.0", - "description": "Enhances Roqueform fields with validation methods that use Constraint validation API.", + "description": "Integrates Roqueform fields with Constraint validation API.", "main": "./lib/index.js", "module": "./lib/index.mjs", "types": "./lib/index.d.ts", "typedoc": { "entryPoint": "./src/main/index.ts", - "displayName": "Constraint validation plugin" + "displayName": "constraint-validation-plugin", + "readmeFile": "none" }, "sideEffects": false, "files": [ diff --git a/packages/constraint-validation-plugin/src/main/constraintValidationPlugin.ts b/packages/constraint-validation-plugin/src/main/constraintValidationPlugin.ts index fc7faaf..fae95c7 100644 --- a/packages/constraint-validation-plugin/src/main/constraintValidationPlugin.ts +++ b/packages/constraint-validation-plugin/src/main/constraintValidationPlugin.ts @@ -12,7 +12,7 @@ export interface ConstraintValidationMixin { /** * `true` if the field or any of its derived fields have an associated error, or `false` otherwise. */ - readonly invalid: boolean; + readonly isInvalid: boolean; /** * The [validity state](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState), or `null` if there's no @@ -83,10 +83,10 @@ export function constraintValidationPlugin(): Plugin ) { invalid ||= isInvalid(controller); - if (ancestor._invalid === invalid) { + if (ancestor._isInvalid === invalid) { break; } - ancestor._invalid = invalid; + ancestor._isInvalid = invalid; ancestor._notify(); } }; @@ -97,7 +97,7 @@ export function constraintValidationPlugin(): Plugin _field: field, _element: null, _validity: null, - _invalid: false, + _isInvalid: false, _error: '', _notify: notify, _notifyAncestors: notifyAncestors, @@ -122,8 +122,8 @@ export function constraintValidationPlugin(): Plugin }; Object.defineProperties(field, { - invalid: { enumerable: true, get: () => isInvalid(controller) }, error: { enumerable: true, get: () => getError(controller) }, + isInvalid: { enumerable: true, get: () => isInvalid(controller) }, validity: { enumerable: true, get: () => controller._validity }, }); @@ -192,7 +192,7 @@ interface FieldController { /** * The invalid status for which the field was notified the last time. */ - _invalid: boolean; + _isInvalid: boolean; /** * An error that is used if the field doesn't have an associated element. diff --git a/packages/constraint-validation-plugin/src/test/constraintValidationPlugin.test.ts b/packages/constraint-validation-plugin/src/test/constraintValidationPlugin.test.ts index 2da5b8f..8aaa9c1 100644 --- a/packages/constraint-validation-plugin/src/test/constraintValidationPlugin.test.ts +++ b/packages/constraint-validation-plugin/src/test/constraintValidationPlugin.test.ts @@ -1,4 +1,4 @@ -import { createField, objectAccessor } from 'roqueform'; +import { createField } from 'roqueform'; import { constraintValidationPlugin } from '../main'; import { fireEvent } from '@testing-library/dom'; @@ -14,17 +14,17 @@ describe('constraintValidationPlugin', () => { }); test('enhances the field', () => { - const field = createField(objectAccessor, { foo: 0 }, constraintValidationPlugin()); + const field = createField({ foo: 0 }, constraintValidationPlugin()); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('sets an error to the field that does not have an associated element', () => { - const field = createField(objectAccessor, { foo: 0 }, constraintValidationPlugin()); + const field = createField({ foo: 0 }, constraintValidationPlugin()); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -34,9 +34,9 @@ describe('constraintValidationPlugin', () => { field.at('foo').setError('aaa'); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe('aaa'); expect(listenerMock).toHaveBeenCalledTimes(1); @@ -44,7 +44,7 @@ describe('constraintValidationPlugin', () => { }); test('setting an error to the parent field does not affect the child field', () => { - const field = createField(objectAccessor, { foo: 0 }, constraintValidationPlugin()); + const field = createField({ foo: 0 }, constraintValidationPlugin()); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -54,9 +54,9 @@ describe('constraintValidationPlugin', () => { field.setError('aaa'); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe('aaa'); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); expect(listenerMock).toHaveBeenCalledTimes(1); @@ -64,7 +64,7 @@ describe('constraintValidationPlugin', () => { }); test('does not notify the field if the same error is set', () => { - const field = createField(objectAccessor, 0, constraintValidationPlugin()); + const field = createField(0, constraintValidationPlugin()); const listenerMock = jest.fn(); @@ -77,7 +77,7 @@ describe('constraintValidationPlugin', () => { }); test('deletes an error from the field', () => { - const field = createField(objectAccessor, 0, constraintValidationPlugin()); + const field = createField(0, constraintValidationPlugin()); const listenerMock = jest.fn(); @@ -86,13 +86,13 @@ describe('constraintValidationPlugin', () => { field.setError('aaa'); field.deleteError(); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); expect(listenerMock).toHaveBeenCalledTimes(2); }); test('clears an error of a derived field', () => { - const field = createField(objectAccessor, { foo: 0 }, constraintValidationPlugin()); + const field = createField({ foo: 0 }, constraintValidationPlugin()); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -103,15 +103,15 @@ describe('constraintValidationPlugin', () => { field.at('foo').setError('aaa'); field.clearErrors(); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('reports validity of the root field', () => { - const field = createField(objectAccessor, { foo: 0 }, constraintValidationPlugin()); + const field = createField({ foo: 0 }, constraintValidationPlugin()); expect(field.reportValidity()).toBe(true); expect(field.at('foo').reportValidity()).toBe(true); @@ -128,7 +128,7 @@ describe('constraintValidationPlugin', () => { }); test('reports validity of the derived field', () => { - const field = createField(objectAccessor, { foo: 0 }, constraintValidationPlugin()); + const field = createField({ foo: 0 }, constraintValidationPlugin()); field.at('foo').setError('aaa'); @@ -142,21 +142,21 @@ describe('constraintValidationPlugin', () => { }); test('uses a validationMessage as an error', () => { - const field = createField(objectAccessor, { foo: 0 }, constraintValidationPlugin()); + const field = createField({ foo: 0 }, constraintValidationPlugin()); element.required = true; field.at('foo').refCallback(element); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual('Constraints not satisfied'); }); test('deletes an error when a ref is changed', () => { - const field = createField(objectAccessor, 0, constraintValidationPlugin()); + const field = createField(0, constraintValidationPlugin()); const listenerMock = jest.fn(); @@ -166,19 +166,19 @@ describe('constraintValidationPlugin', () => { field.refCallback(element); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toEqual('Constraints not satisfied'); expect(listenerMock).toHaveBeenCalledTimes(1); field.refCallback(null); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); expect(listenerMock).toHaveBeenCalledTimes(2); }); test('notifies the field when the value is changed', () => { - const field = createField(objectAccessor, { foo: 0 }, constraintValidationPlugin()); + const field = createField({ foo: 0 }, constraintValidationPlugin()); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -195,7 +195,7 @@ describe('constraintValidationPlugin', () => { field.at('foo').refCallback(element); expect(listenerMock).toHaveBeenCalledTimes(0); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); fireEvent.change(element, { target: { value: '' } }); @@ -204,7 +204,7 @@ describe('constraintValidationPlugin', () => { }); test('does not notify an already invalid parent', () => { - const field = createField(objectAccessor, { foo: 0 }, constraintValidationPlugin()); + const field = createField({ foo: 0 }, constraintValidationPlugin()); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -221,7 +221,7 @@ describe('constraintValidationPlugin', () => { field.at('foo').refCallback(element); expect(listenerMock).toHaveBeenCalledTimes(0); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); fireEvent.change(element, { target: { value: '' } }); diff --git a/packages/doubter-plugin/README.md b/packages/doubter-plugin/README.md index 3598dfc..4139c93 100644 --- a/packages/doubter-plugin/README.md +++ b/packages/doubter-plugin/README.md @@ -1,9 +1,9 @@ # Doubter plugin for Roqueform -Enhances [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields with validation methods powered by -[Doubter](https://github.com/smikhalevski/doubter#readme). +Validates [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields with +[Doubter](https://github.com/smikhalevski/doubter#readme) shapes. -🔥 [**Try it on CodeSandbox**](https://codesandbox.io/s/roqueform-doubter-plugin-example-74hkgw) +🔥 [**Try it on CodeSandbox**](https://codesandbox.io/s/74hkgw) ```sh npm install --save-prod @roqueform/doubter-plugin @@ -16,50 +16,49 @@ npm install --save-prod @roqueform/doubter-plugin # Usage example -🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/Doubter_plugin.html) +🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/doubter_plugin.html) ```tsx import { SyntheticEvent } from 'react'; -import { FieldRenderer, useField } from 'roqueform'; +import { FieldRenderer, useField } from '@roqueform/react'; import { doubterPlugin } from '@roqueform/doubter-plugin'; import * as d from 'doubter'; -// Define a value shape using Doubter -const valueShape = d.object({ - bar: d.string().min(1), +const planetShape = d.object({ + name: d.string().min(1), }); export const App = () => { - const rootField = useField({ bar: '' }, doubterPlugin(valueShape)); + const planetField = useField({ name: '' }, doubterPlugin(planetShape)); - const handleSubmit = (event: SyntheticEvent): void => { + const handleSubmit = (event: SyntheticEvent) => { event.preventDefault(); - if (rootField.validate()) { + if (planetField.validate()) { // Errors are associated with fields automatically return; } - // If your shapes have transformations, you can safely parse + // If your shapes have transformations or refinements, you can safely parse // the field value after it was successfully validated - const value = rootField.shape.parse(rootField.value); + const value = planetShape.parse(planetField.value); }; return (
- - {barField => ( + + {nameField => ( <> { - barField.setValue(event.target.value); + nameField.setValue(event.target.value); }} - aria-invalid={barField.invalid} + aria-invalid={nameField.isInvalid} /> - {barField.error?.message} + {nameField.error?.message} )} @@ -75,53 +74,53 @@ export const App = () => { # Validating fields -First, you should first define a field value shape using [Doubter](https://github.com/smikhalevski/doubter#readme). +Define a field value shape using [Doubter](https://github.com/smikhalevski/doubter#readme). ```ts import * as d from 'doubter'; -const valueShape = d.object({ - bar: d.string().min(5) +const planetShape = d.object({ + name: d.string().min(5) }); -// → Shape<{ bar: string }> +// ⮕ Shape<{ name: string }> ``` -Then you can create a new field and enhance it with validation methods: +Create a new field and enhance it with the plugin: ```ts -import { useField } from 'roqueform'; +import { useField } from '@roqueform/react'; import { doubterPlugin } from '@roqueform/doubter-plugin'; -const rootField = useField({ bar: 'qux' }, doubterPlugin(valueShape)); +const planetField = useField({ name: 'Mars' }, doubterPlugin(planetShape)); ``` -Type of the field value is inferred from the provided shape, so everything remains statically checked. +The type of the field value is inferred from the provided shape, so the field value is statically checked. -When you call the `validate` method it triggers validation of the field and all of its derived fields. So if you call +When you call the `validate` method, it triggers validation of the field and all of its derived fields. So if you call `validate` on the derived field, it won't validate the parent field: ```ts -rootField.at('bar').validate(); -// → [{ message: 'Must have the minimum length of 5', … }] +planetField.at('name').validate(); +// ⮕ [{ message: 'Must have the minimum length of 5', … }] ``` -In this example, `rootField.value` isn't validated, but `rootField.at('bar').value` is validated. +In this example, `planetField.value` _is not_ validated, and `planetField.at('name').value` _is_ validated. -It's safe to trigger validation of a single text field on every keystroke, since validation doesn't have to process the -whole form object. +> **Note** It's safe to trigger validation of a single text field on every keystroke, since validation doesn't have +> to process the whole form state. To detect whether the field, or any of its derived fields contain a validation error: ```ts -rootField.invalid; -// → true +planetField.isInvalid; +// ⮕ true ``` To retrieve an error associated with a particular field: ```ts -rootField.at('bar').error; -// → { message: 'Must have the minimum length of 5', … } +planetField.at('name').error; +// ⮕ { message: 'Must have the minimum length of 5', … } ``` # Managing errors manually @@ -129,7 +128,7 @@ rootField.at('bar').error; You can manually associate an error with the field: ```ts -rootField.at('bar').setError({ message: 'Oh, snap!' }); +planetField.at('name').setError({ message: 'Oh, snap!' }); ``` This may come handy when you want to mix client-side and server-side validation. @@ -137,13 +136,13 @@ This may come handy when you want to mix client-side and server-side validation. To delete an error for the particular field: ```ts -rootField.at('bar').deleteError(); +planetField.at('name').deleteError(); ``` Sometimes it is required to clear errors of the field itself and all of its derived fields: ```ts -rootField.clearErrors(); +planetField.clearErrors(); ``` # Custom error messages @@ -151,16 +150,16 @@ rootField.clearErrors(); You can customize messages for errors raised by Doubter (the component code is omitted for clarity): ```ts -import { useField } from 'roqueform'; +import { useField } from '@roqueform/react'; import { doubterPlugin } from '@roqueform/doubter-plugin'; import * as d from 'doubter'; const valueShape = d.array(d.string(), 'Expected an array').min(3, 'Not enough elements'); -const rootField = useField([], doubterPlugin(valueShape)); +const field = useField([], doubterPlugin(valueShape)); -rootField.validate(); +field.validate(); -rootField.error; -// → { message: 'Not enough elements', … } +field.error; +// ⮕ { message: 'Not enough elements', … } ``` diff --git a/packages/doubter-plugin/package.json b/packages/doubter-plugin/package.json index 0f92bb3..682e13c 100644 --- a/packages/doubter-plugin/package.json +++ b/packages/doubter-plugin/package.json @@ -1,13 +1,14 @@ { "name": "@roqueform/doubter-plugin", "version": "1.0.0", - "description": "Enhances Roqueform fields with validation methods powered by Doubter.", + "description": "Validates Roqueform fields with Doubter shapes.", "main": "./lib/index.js", "module": "./lib/index.mjs", "types": "./lib/index.d.ts", "typedoc": { "entryPoint": "./src/main/index.ts", - "displayName": "Doubter plugin" + "displayName": "doubter-plugin", + "readmeFile": "none" }, "sideEffects": false, "files": [ @@ -38,7 +39,7 @@ }, "homepage": "https://github.com/smikhalevski/roqueform/tree/master/packages/doubter-plugin#readme", "peerDependencies": { - "doubter": "^1.0.1", + "doubter": "^2.1.0", "roqueform": "^3.0.1" } } diff --git a/packages/doubter-plugin/src/main/doubterPlugin.ts b/packages/doubter-plugin/src/main/doubterPlugin.ts index 20bdbd4..d7e7ab9 100644 --- a/packages/doubter-plugin/src/main/doubterPlugin.ts +++ b/packages/doubter-plugin/src/main/doubterPlugin.ts @@ -7,7 +7,7 @@ const anyShape = new Shape(); * The mixin added to fields by the {@linkcode doubterPlugin}. */ export interface DoubterMixin extends ValidationMixin { - setError(error: Partial | string): void; + setError(error: Issue | string): void; } /** @@ -28,12 +28,7 @@ export function doubterPlugin(shape: Shape): Plugin if (typeof error === 'string') { error = { message: error }; } - if (error.code == null) { - error.code = 'unknown'; - } - if (error.path == null) { - error.path = prependPath(field, []); - } + error.path = prependPath(field, error.path); error.input = field.value; setError(error); @@ -79,23 +74,24 @@ function getShape(field: Field, shapeCache: WeakMap, rootShape: return shape; } -function prependPath(field: Field, path: unknown[]): unknown[] { +function prependPath(field: Field, path: unknown[] | undefined): unknown[] | undefined { for (let ancestor = field; ancestor.parent !== null; ancestor = ancestor.parent) { - path.unshift(ancestor.key); + (path ||= []).unshift(ancestor.key); } return path; } function setIssues(field: Field, issues: Issue[], setInternalError: (field: Field, error: Issue) => void): void { for (const issue of issues) { - const { path } = issue; - let targetField = field; - for (let i = 0; i < path.length; ++i) { - targetField = targetField.at(path[i]); + if (Array.isArray(issue.path)) { + for (const key of issue.path) { + targetField = targetField.at(key); + } } - prependPath(field, path); + + issue.path = prependPath(field, issue.path); setInternalError(targetField, issue); } } diff --git a/packages/doubter-plugin/src/test/doubterPlugin.test-d.ts b/packages/doubter-plugin/src/test/doubterPlugin.test-d.ts index f2d5668..5129e97 100644 --- a/packages/doubter-plugin/src/test/doubterPlugin.test-d.ts +++ b/packages/doubter-plugin/src/test/doubterPlugin.test-d.ts @@ -1,10 +1,10 @@ import * as d from 'doubter'; import { expectType } from 'tsd'; -import { createField, Field, objectAccessor } from 'roqueform'; +import { createField, Field } from 'roqueform'; import { DoubterMixin, doubterPlugin } from '@roqueform/doubter-plugin'; const shape = d.object({ foo: d.object({ bar: d.string() }) }); expectType & DoubterMixin>( - createField(objectAccessor, { foo: { bar: 'aaa' } }, doubterPlugin(shape)) + createField({ foo: { bar: 'aaa' } }, doubterPlugin(shape)) ); diff --git a/packages/doubter-plugin/src/test/doubterPlugin.test.tsx b/packages/doubter-plugin/src/test/doubterPlugin.test.tsx index d94e6e6..e62d0ba 100644 --- a/packages/doubter-plugin/src/test/doubterPlugin.test.tsx +++ b/packages/doubter-plugin/src/test/doubterPlugin.test.tsx @@ -1,6 +1,6 @@ import * as d from 'doubter'; import { doubterPlugin } from '../main'; -import { createField, objectAccessor } from 'roqueform'; +import { createField } from 'roqueform'; describe('doubterPlugin', () => { const fooShape = d.object({ @@ -13,85 +13,85 @@ describe('doubterPlugin', () => { }); test('enhances the field', () => { - const field = createField(objectAccessor, { foo: 0 }, doubterPlugin(fooShape)); + const field = createField({ foo: 0 }, doubterPlugin(fooShape)); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('sets an issue to the root field', () => { - const field = createField(objectAccessor, { foo: 0 }, doubterPlugin(fooShape)); + const field = createField({ foo: 0 }, doubterPlugin(fooShape)); const issue = { code: 'aaa' }; field.setError(issue); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(issue); - expect(field.error).toEqual({ code: 'aaa', input: { foo: 0 }, path: [] }); + expect(field.error).toEqual({ code: 'aaa', input: { foo: 0 } }); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('sets an issue to the child field', () => { - const field = createField(objectAccessor, { foo: 0 }, doubterPlugin(fooShape)); + const field = createField({ foo: 0 }, doubterPlugin(fooShape)); const issue = { code: 'aaa' }; field.at('foo').setError(issue); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(issue); expect(field.at('foo').error).toEqual({ code: 'aaa', input: 0, path: ['foo'] }); }); test('converts string errors to issue messages', () => { - const field = createField(objectAccessor, { foo: 0 }, doubterPlugin(fooShape)); + const field = createField({ foo: 0 }, doubterPlugin(fooShape)); field.at('foo').setError('aaa'); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); - expect(field.at('foo').error).toEqual({ code: 'unknown', message: 'aaa', input: 0, path: ['foo'] }); + expect(field.at('foo').isInvalid).toBe(true); + expect(field.at('foo').error).toEqual({ message: 'aaa', input: 0, path: ['foo'] }); }); test('deletes an issue from the root field', () => { - const field = createField(objectAccessor, { foo: 0 }, doubterPlugin(fooShape)); + const field = createField({ foo: 0 }, doubterPlugin(fooShape)); field.setError({ code: 'aaa' }); field.deleteError(); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('deletes an issue from the child field', () => { - const field = createField(objectAccessor, { foo: 0 }, doubterPlugin(fooShape)); + const field = createField({ foo: 0 }, doubterPlugin(fooShape)); field.at('foo').setError({ code: 'aaa' }); field.at('foo').deleteError(); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('deletes an issue from the child field but parent remains invalid', () => { - const field = createField(objectAccessor, { foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); + const field = createField({ foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); const issue1 = { code: 'aaa' }; const issue2 = { code: 'bbb' }; @@ -101,18 +101,18 @@ describe('doubterPlugin', () => { field.at('bar').deleteError(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(issue1); - expect(field.at('bar').invalid).toBe(false); + expect(field.at('bar').isInvalid).toBe(false); expect(field.at('bar').error).toBe(null); }); test('clears all issues', () => { - const field = createField(objectAccessor, { foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); + const field = createField({ foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); const issue1 = { code: 'aaa' }; const issue2 = { code: 'bbb' }; @@ -122,25 +122,25 @@ describe('doubterPlugin', () => { field.clearErrors(); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); - expect(field.at('bar').invalid).toBe(false); + expect(field.at('bar').isInvalid).toBe(false); expect(field.at('bar').error).toBe(null); }); test('validates the root field', () => { - const field = createField(objectAccessor, { foo: 0 }, doubterPlugin(fooShape)); + const field = createField({ foo: 0 }, doubterPlugin(fooShape)); field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'numberGreaterThanOrEqual', path: ['foo'], @@ -152,14 +152,14 @@ describe('doubterPlugin', () => { }); test('validates the child field', () => { - const field = createField(objectAccessor, { foo: 0 }, doubterPlugin(fooShape)); + const field = createField({ foo: 0 }, doubterPlugin(fooShape)); field.at('foo').validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'numberGreaterThanOrEqual', path: ['foo'], @@ -171,14 +171,14 @@ describe('doubterPlugin', () => { }); test('validates multiple fields', () => { - const field = createField(objectAccessor, { foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); + const field = createField({ foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'numberGreaterThanOrEqual', path: ['foo'], @@ -188,7 +188,7 @@ describe('doubterPlugin', () => { meta: undefined, }); - expect(field.at('bar').invalid).toBe(true); + expect(field.at('bar').isInvalid).toBe(true); expect(field.at('bar').error).toEqual({ code: 'stringMaxLength', path: ['bar'], @@ -200,7 +200,7 @@ describe('doubterPlugin', () => { }); test('validate clears previous validation issues', () => { - const field = createField(objectAccessor, { foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); + const field = createField({ foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); field.validate(); @@ -208,10 +208,10 @@ describe('doubterPlugin', () => { field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'numberGreaterThanOrEqual', path: ['foo'], @@ -221,12 +221,12 @@ describe('doubterPlugin', () => { meta: undefined, }); - expect(field.at('bar').invalid).toBe(false); + expect(field.at('bar').isInvalid).toBe(false); expect(field.at('bar').error).toBe(null); }); test('validate does not clear an issue set from userland', () => { - const field = createField(objectAccessor, { foo: 0, bar: '' }, doubterPlugin(fooBarShape)); + const field = createField({ foo: 0, bar: '' }, doubterPlugin(fooBarShape)); const issue = { code: 'aaa' }; @@ -234,10 +234,10 @@ describe('doubterPlugin', () => { field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'numberGreaterThanOrEqual', path: ['foo'], @@ -247,21 +247,21 @@ describe('doubterPlugin', () => { meta: undefined, }); - expect(field.at('bar').invalid).toBe(true); + expect(field.at('bar').isInvalid).toBe(true); expect(field.at('bar').error).toBe(issue); }); test('validate does not raise issues for transient fields', () => { - const field = createField(objectAccessor, { foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); + const field = createField({ foo: 0, bar: 'qux' }, doubterPlugin(fooBarShape)); field.at('bar').setTransientValue('aaabbb'); field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'numberGreaterThanOrEqual', path: ['foo'], @@ -271,7 +271,7 @@ describe('doubterPlugin', () => { meta: undefined, }); - expect(field.at('bar').invalid).toBe(false); + expect(field.at('bar').isInvalid).toBe(false); expect(field.at('bar').error).toBe(null); }); }); diff --git a/packages/react/README.md b/packages/react/README.md index a6f9bad..5d45952 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -1,6 +1,6 @@ # React integration for Roqueform -Hooks and components that integrate [Roqueform](https://github.com/smikhalevski/roqueform#readme) into a React app. +Hooks and components to integrate [Roqueform](https://github.com/smikhalevski/roqueform#readme) with React. ```sh npm install --save-prod @roqueform/react @@ -8,4 +8,172 @@ npm install --save-prod @roqueform/react # Usage example -🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/React_integration.html) +🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/react.html) + +```tsx +import { SyntheticEvent } from 'react'; +import { FieldRenderer, useField } from '@roqueform/react'; + +export const App = () => { + const planetField = useField({ name: 'Mars' }); + + const handleSubmit = (event: SyntheticEvent) => { + event.preventDefault(); + + // Submit the field value + planetField.value; + }; + + return ( + + + + {nameField => ( + { + nameField.setValue(event.target.value); + }} + /> + )} + + + + + + ); +}; +``` + +# `useField` + +`useField` is hook that returns a [`Field`](https://smikhalevski.github.io/roqueform/interfaces/roqueform.Field.html) +instance that is preserved between re-renders. + +```ts +useField(); +// ⮕ Field +``` + +You can provide the initial value for a field. + +```ts +useField({ planet: 'Mars' }); +// ⮕ Field<{ foo: string }> +``` + +If you pass a callback as an initial value, it would be invoked when the field is initialized. + +```ts +useField(() => getInitialValue()); +``` + +Pass [a plugin](../../#plugins-and-integrations) as the second argument of the `useField` hook. + +```ts +import { useField } from '@roqueform/react'; +import { uncontrolledPlugin } from '@roqueform/uncontrolled-plugin'; + +useField({ planet: 'Pluto' }, uncontrolledPlugin()); +``` + +# `FieldRenderer` + +The `FieldRenderer` component subscribes to the given field instance and re-renders children when the field is notified: + +```tsx +import { FieldRenderer, useField } from '@roqueform/react'; + +const App = () => { + const planetField = useField({ name: 'Mars' }); + + return ( + + {nameField => ( + { + nameField.setValue(event.target.value); + }} + /> + )} + + ); +}; +``` + +When a user updates the input value, the `nameField` is updated and `FieldRenderer` component is re-rendered. The single +argument of the `children` render function is the field passed as a `field` prop to the `FieldRenderer` component. + +## Eager and lazy re-renders + +Let's consider the form with two `FieldRenderer` elements. One of them renders the value of the root field and the other +one renders an input that updates the derived field: + +```tsx +const App = () => { + const planetField = useField({ name: 'Mars' }); + + return <> + + {() => JSON.stringify(planetField.value)} + + + + {nameField => ( + { + nameField.setValue(event.target.value); + }} + /> + )} + + ; +}; +``` + +By default, `FieldRenderer` component re-renders only when the provided field was updated directly, so updates from +ancestors or derived fields would be ignored. Add the `eagerlyUpdated` property to force `FieldRenderer` to re-render +whenever its value was affected. + +```diff +- ++ + {() => JSON.stringify(planetField.value)} + +``` + +Now both fields are re-rendered when user edits the input text. + +## Reacting to changes + +You can use an `onChange` handler that is triggered only when the field value was updated +[non-transiently](../../#transient-updates). + +```tsx + { + // Handle the value change + }} +> + {barField => ( + { + barField.setValue(event.target.value); + }} + /> + )} + +``` diff --git a/packages/react/package.json b/packages/react/package.json index e31a45b..2c6a129 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,13 +1,14 @@ { "name": "@roqueform/react", "version": "1.0.0", - "description": "Hooks and components that integrate Roqueform into a React app.", + "description": "Hooks and components to integrate Roqueform with React.", "main": "./lib/index.js", "module": "./lib/index.mjs", "types": "./lib/index.d.ts", "typedoc": { "entryPoint": "./src/main/index.ts", - "displayName": "React integration" + "displayName": "react", + "readmeFile": "none" }, "sideEffects": false, "files": [ diff --git a/packages/react/src/main/FieldRenderer.ts b/packages/react/src/main/FieldRenderer.ts index 2468bde..66ac9d8 100644 --- a/packages/react/src/main/FieldRenderer.ts +++ b/packages/react/src/main/FieldRenderer.ts @@ -50,7 +50,7 @@ export function FieldRenderer(props: FieldRendererProps): Re handleChangeRef.current = props.onChange; useEffect(() => { - let prevValue: F['value'] | undefined; + let prevValue: unknown; return field.subscribe(targetField => { const { value } = field; @@ -58,7 +58,7 @@ export function FieldRenderer(props: FieldRendererProps): Re if (eagerlyUpdated || field === targetField) { rerender(); } - if (field.transient || isEqual(value, prevValue)) { + if (field.isTransient || isEqual(value, prevValue)) { return; } diff --git a/packages/react/src/main/useField.ts b/packages/react/src/main/useField.ts index aba8941..7410851 100644 --- a/packages/react/src/main/useField.ts +++ b/packages/react/src/main/useField.ts @@ -1,4 +1,4 @@ -import { DependencyList, useContext, useMemo } from 'react'; +import { useContext, useRef } from 'react'; import { callOrGet, createField, Field, Plugin } from 'roqueform'; import { AccessorContext } from './AccessorContext'; @@ -27,22 +27,14 @@ export function useField(initialValue: T | (() => T)): Field; * * @param initialValue The initial value assigned to the field. * @param plugin Enhances the field with additional functionality. - * @param deps The array of dependencies that trigger the field re-instantiation. * @returns The {@linkcode Field} instance. * @template T The root field value. * @template M The mixin added by the plugin. */ -export function useField( - initialValue: T | (() => T), - plugin: Plugin>, - deps?: DependencyList -): Field & M; +export function useField(initialValue: T | (() => T), plugin: Plugin>): Field & M; -export function useField(initialValue?: unknown, plugin?: Plugin, deps?: DependencyList) { +export function useField(initialValue?: unknown, plugin?: Plugin) { const accessor = useContext(AccessorContext); - return useMemo( - () => createField(accessor, callOrGet(initialValue), plugin!), - Array.isArray(deps) ? deps.concat(accessor) : [accessor] - ); + return (useRef().current ||= createField(callOrGet(initialValue), plugin!, accessor)); } diff --git a/packages/react/src/test/useField.test.ts b/packages/react/src/test/useField.test.ts index 23c13b8..5f1aa11 100644 --- a/packages/react/src/test/useField.test.ts +++ b/packages/react/src/test/useField.test.ts @@ -37,17 +37,4 @@ describe('useField', () => { expect(pluginMock).toHaveBeenCalledTimes(1); }); - - test('re-creates a field when deps are changed', () => { - let depsMock = [111]; - const pluginMock = jest.fn(); - - const hook = renderHook(() => useField(111, pluginMock, depsMock)); - - const field = hook.result.current; - depsMock = [222]; - hook.rerender(); - - expect(hook.result.current).not.toBe(field); - }); }); diff --git a/packages/ref-plugin/README.md b/packages/ref-plugin/README.md index 79aa17d..e817583 100644 --- a/packages/ref-plugin/README.md +++ b/packages/ref-plugin/README.md @@ -1,6 +1,6 @@ # DOM reference plugin for Roqueform -Enhances [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields with DOM-related methods. +Associates [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields with DOM elements. ```sh npm install --save-prod @roqueform/ref-plugin @@ -8,28 +8,28 @@ npm install --save-prod @roqueform/ref-plugin # Usage example -🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/DOM_reference_plugin.html) +🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/ref_plugin.html) ```tsx import { useEffect } from 'react'; -import { FieldRenderer, useField } from 'roqueform'; +import { FieldRenderer, useField } from '@roqueform/react'; import { refPlugin } from '@roqueform/ref-plugin'; export const App = () => { - const rootField = useField({ bar: 'qux' }, refPlugin()); + const planetField = useField({ name: 'Venus' }, refPlugin()); useEffect(() => { - rootField.at('bar').scrollIntoView({ behavior: 'smooth' }); + planetField.at('name').scrollIntoView({ behavior: 'smooth' }); }, []); return ( - - {barField => ( + + {nameField => ( { - barField.setValue(event.target.value); + nameField.setValue(event.target.value); }} /> )} diff --git a/packages/ref-plugin/package.json b/packages/ref-plugin/package.json index a05e6e8..03ca9ab 100644 --- a/packages/ref-plugin/package.json +++ b/packages/ref-plugin/package.json @@ -1,13 +1,14 @@ { "name": "@roqueform/ref-plugin", "version": "3.0.0", - "description": "Enhances Roqueform fields with DOM-related methods.", + "description": "Associates Roqueform fields with DOM elements.", "main": "./lib/index.js", "module": "./lib/index.mjs", "types": "./lib/index.d.ts", "typedoc": { "entryPoint": "./src/main/index.ts", - "displayName": "DOM reference plugin" + "displayName": "ref-plugin", + "readmeFile": "none" }, "sideEffects": false, "files": [ diff --git a/packages/ref-plugin/src/test/refPlugin.test.ts b/packages/ref-plugin/src/test/refPlugin.test.ts index 1fd4ef6..7f330e2 100644 --- a/packages/ref-plugin/src/test/refPlugin.test.ts +++ b/packages/ref-plugin/src/test/refPlugin.test.ts @@ -1,16 +1,16 @@ -import { applyPlugins, createField, objectAccessor } from 'roqueform'; +import { applyPlugins, createField } from 'roqueform'; import { refPlugin } from '../main'; describe('refPlugin', () => { test('adds an element property to the field', () => { - const field = createField(objectAccessor, { bar: 111 }, refPlugin()); + const field = createField({ bar: 111 }, refPlugin()); expect(field.element).toBe(null); expect(field.at('bar').element).toBe(null); }); test('refCallback updates an element property', () => { - const field = createField(objectAccessor, { bar: 111 }, refPlugin()); + const field = createField({ bar: 111 }, refPlugin()); const element = document.createElement('input'); field.refCallback(element); @@ -22,7 +22,6 @@ describe('refPlugin', () => { const refCallbackMock = jest.fn(() => undefined); const field = createField( - objectAccessor, { bar: 111 }, applyPlugins(field => Object.assign(field, { refCallback: refCallbackMock }), refPlugin()) ); diff --git a/packages/reset-plugin/README.md b/packages/reset-plugin/README.md index 9779651..12cf403 100644 --- a/packages/reset-plugin/README.md +++ b/packages/reset-plugin/README.md @@ -1,7 +1,6 @@ # Reset plugin for Roqueform -Enhances [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields with methods that manage the initial -value. +Manages [Roqueform](https://github.com/smikhalevski/roqueform#readme) field initial value and dirty status. ```sh npm install --save-prod @roqueform/reset-plugin @@ -9,28 +8,28 @@ npm install --save-prod @roqueform/reset-plugin # Usage example -🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/Reset_Plugin.html) +🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/reset_plugin.html) The field is considered dirty when its value differs from the initial value. Values are compared using an equality checker function passed to the `resetPlugin`. By default, values are compared using [fast-deep-equal](https://github.com/epoberezkin/fast-deep-equal). ```tsx -import { FieldRenderer, useField } from 'roqueform'; +import { FieldRenderer, useField } from '@roqueform/react'; import { resetPlugin } from '@roqueform/reset-plugin'; export const App = () => { - const rootField = useField({ bar: '' }, resetPlugin()); + const planetField = useField({ name: 'Pluto' }, resetPlugin()); return (
- - {barField => ( + + {nameField => ( { - barField.setValue(event.target.value); + nameField.setValue(event.target.value); }} /> )} @@ -38,7 +37,7 @@ export const App = () => { @@ -46,7 +45,7 @@ export const App = () => { diff --git a/packages/reset-plugin/package.json b/packages/reset-plugin/package.json index d186961..799ff28 100644 --- a/packages/reset-plugin/package.json +++ b/packages/reset-plugin/package.json @@ -1,13 +1,14 @@ { "name": "@roqueform/reset-plugin", "version": "2.0.0", - "description": "Enhances Roqueform fields with methods that manage the initial value.", + "description": "Manages Roqueform field initial value and dirty status.", "main": "./lib/index.js", "module": "./lib/index.mjs", "types": "./lib/index.d.ts", "typedoc": { "entryPoint": "./src/main/index.ts", - "displayName": "Reset plugin" + "displayName": "reset-plugin", + "readmeFile": "none" }, "sideEffects": false, "files": [ @@ -32,7 +33,7 @@ "initial", "dirty" ], - "author": "Dmitry Paskhin ", + "author": "Savva Mikhalevski ", "license": "MIT", "bugs": { "url": "https://github.com/smikhalevski/roqueform/issues" diff --git a/packages/reset-plugin/src/main/resetPlugin.ts b/packages/reset-plugin/src/main/resetPlugin.ts index 53b82dc..9736ee9 100644 --- a/packages/reset-plugin/src/main/resetPlugin.ts +++ b/packages/reset-plugin/src/main/resetPlugin.ts @@ -13,7 +13,7 @@ export interface ResetMixin { /** * `true` if the field value is different from its initial value, or `false` otherwise. */ - readonly dirty: boolean; + readonly isDirty: boolean; /** * The initial field value. @@ -54,7 +54,7 @@ export function resetPlugin( _children: null, _field: field, _key: field.key, - _dirty: false, + _isDirty: false, _initialValue: field.value, _accessor: accessor, _equalityChecker: equalityChecker, @@ -73,7 +73,7 @@ export function resetPlugin( } Object.defineProperties(field, { - dirty: { enumerable: true, get: () => controller._dirty }, + isDirty: { enumerable: true, get: () => controller._isDirty }, initialValue: { enumerable: true, get: () => controller._initialValue }, }); @@ -98,7 +98,7 @@ interface FieldController { _children: FieldController[] | null; _field: Field; _key: unknown; - _dirty: boolean; + _isDirty: boolean; _initialValue: unknown; _accessor: Accessor; _equalityChecker: (initialValue: any, value: any) => boolean; @@ -106,7 +106,7 @@ interface FieldController { } function applyDirty(controller: FieldController): void { - controller._dirty = !controller._equalityChecker(controller._initialValue, controller._field.value); + controller._isDirty = !controller._equalityChecker(controller._initialValue, controller._field.value); } function applyInitialValue(controller: FieldController, initialValue: unknown): void { diff --git a/packages/reset-plugin/src/test/resetPlugin.test-d.ts b/packages/reset-plugin/src/test/resetPlugin.test-d.ts index 6502a76..b812100 100644 --- a/packages/reset-plugin/src/test/resetPlugin.test-d.ts +++ b/packages/reset-plugin/src/test/resetPlugin.test-d.ts @@ -1,5 +1,5 @@ import { expectType } from 'tsd'; -import { createField, objectAccessor } from 'roqueform'; +import { createField } from 'roqueform'; import { resetPlugin } from '@roqueform/reset-plugin'; -expectType(createField(objectAccessor, { foo: 111 }, resetPlugin()).at('foo').initialValue); +expectType(createField({ foo: 111 }, resetPlugin()).at('foo').initialValue); diff --git a/packages/reset-plugin/src/test/resetPlugin.test.ts b/packages/reset-plugin/src/test/resetPlugin.test.ts index 500a289..7355d67 100644 --- a/packages/reset-plugin/src/test/resetPlugin.test.ts +++ b/packages/reset-plugin/src/test/resetPlugin.test.ts @@ -1,40 +1,40 @@ -import { createField, objectAccessor } from 'roqueform'; +import { createField } from 'roqueform'; import { resetPlugin } from '../main'; describe('resetPlugin', () => { test('field is dirty if the field value is not equal to an initial value', () => { const initialValue = { foo: 111 }; - const field = createField(objectAccessor, initialValue, resetPlugin()); + const field = createField(initialValue, resetPlugin()); expect(field.initialValue).toBe(initialValue); expect(field.at('foo').initialValue).toBe(111); field.at('foo').setValue(222); - expect(field.at('foo').dirty).toBe(true); - expect(field.dirty).toBe(true); + expect(field.at('foo').isDirty).toBe(true); + expect(field.isDirty).toBe(true); field.setValue(initialValue); - expect(field.at('foo').dirty).toBe(false); - expect(field.dirty).toBe(false); + expect(field.at('foo').isDirty).toBe(false); + expect(field.isDirty).toBe(false); }); test('field is not dirty it has the value that is deeply equal to the initial value', () => { const initialValue = { foo: 111 }; - const field = createField(objectAccessor, initialValue, resetPlugin()); + const field = createField(initialValue, resetPlugin()); field.at('foo').setValue(222); - expect(field.at('foo').dirty).toBe(true); - expect(field.dirty).toBe(true); + expect(field.at('foo').isDirty).toBe(true); + expect(field.isDirty).toBe(true); field.setValue({ foo: 111 }); - expect(field.at('foo').dirty).toBe(false); - expect(field.dirty).toBe(false); + expect(field.at('foo').isDirty).toBe(false); + expect(field.isDirty).toBe(false); }); test('updates the initial value and notifies fields', () => { @@ -43,7 +43,7 @@ describe('resetPlugin', () => { const initialValue = { foo: 111 }; - const field = createField(objectAccessor, initialValue, resetPlugin()); + const field = createField(initialValue, resetPlugin()); field.subscribe(listenerMock); field.at('foo').subscribe(fooListenerMock); @@ -55,30 +55,30 @@ describe('resetPlugin', () => { expect(listenerMock).toHaveBeenCalledTimes(1); expect(fooListenerMock).toHaveBeenCalledTimes(1); expect(field.at('foo').initialValue).toBe(222); - expect(field.at('foo').dirty).toBe(true); + expect(field.at('foo').isDirty).toBe(true); expect(field.initialValue).toBe(initialValue2); - expect(field.dirty).toBe(true); + expect(field.isDirty).toBe(true); }); test('derived field is dirty if its value was updated before the Field instance was created', () => { - const field = createField(objectAccessor, { foo: 111 }, resetPlugin()); + const field = createField({ foo: 111 }, resetPlugin()); field.setValue({ foo: 222 }); - expect(field.at('foo').dirty).toBe(true); + expect(field.at('foo').isDirty).toBe(true); }); test('resets to the initial value', () => { - const field = createField(objectAccessor, { foo: 111 }, resetPlugin()); + const field = createField({ foo: 111 }, resetPlugin()); field.at('foo').setValue(222); - expect(field.dirty).toBe(true); - expect(field.at('foo').dirty).toBe(true); + expect(field.isDirty).toBe(true); + expect(field.at('foo').isDirty).toBe(true); field.reset(); - expect(field.at('foo').dirty).toBe(false); - expect(field.dirty).toBe(false); + expect(field.at('foo').isDirty).toBe(false); + expect(field.isDirty).toBe(false); }); }); diff --git a/packages/roqueform/package.json b/packages/roqueform/package.json index 79a1e18..f260204 100644 --- a/packages/roqueform/package.json +++ b/packages/roqueform/package.json @@ -7,7 +7,8 @@ "types": "./lib/index.d.ts", "typedoc": { "entryPoint": "./src/main/index.ts", - "displayName": "Roqueform" + "displayName": "roqueform", + "readmeFile": "none" }, "sideEffects": false, "files": [ diff --git a/packages/roqueform/src/main/createField.ts b/packages/roqueform/src/main/createField.ts index 47c3162..1758caa 100644 --- a/packages/roqueform/src/main/createField.ts +++ b/packages/roqueform/src/main/createField.ts @@ -1,5 +1,6 @@ import { Accessor, Field, Plugin } from './shared-types'; import { callAll, callOrGet, isEqual } from './utils'; +import { objectAccessor } from './objectAccessor'; // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#type-inference-in-conditional-types type NoInfer = T extends infer T ? T : never; @@ -7,32 +8,36 @@ type NoInfer = T extends infer T ? T : never; /** * Creates the new field instance. * - * @param accessor Resolves values for derived fields. + * @template T The root field value. */ -export function createField(accessor: Accessor): Field; +export function createField(): Field; /** * Creates the new field instance. * - * @param accessor Resolves values for derived fields. * @param initialValue The initial value assigned to the field. + * @param accessor Resolves values for derived fields. * @template T The root field value. */ -export function createField(accessor: Accessor, initialValue: T): Field; +export function createField(initialValue: T, accessor?: Accessor): Field; /** * Creates the new field instance. * - * @param accessor Resolves values for derived fields. * @param initialValue The initial value assigned to the field. * @param plugin The plugin that enhances the field. + * @param accessor Resolves values for derived fields. * @template T The root field value. * @template M The mixin added by the plugin. */ -export function createField(accessor: Accessor, initialValue: T, plugin: Plugin>): Field & M; +export function createField(initialValue: T, plugin: Plugin>, accessor?: Accessor): Field & M; -export function createField(accessor: Accessor, initialValue?: unknown, plugin?: Plugin) { - return getOrCreateFieldController(accessor, null, null, initialValue, plugin)._field; +export function createField(initialValue?: unknown, plugin?: Plugin | Accessor, accessor?: Accessor) { + if (typeof plugin !== 'function') { + plugin = undefined; + accessor = plugin; + } + return getOrCreateFieldController(accessor || objectAccessor, null, null, initialValue, plugin)._field; } interface FieldController { @@ -46,7 +51,7 @@ interface FieldController { _field: Field; _key: unknown; _value: unknown; - _transient: boolean; + _isTransient: boolean; _accessor: Accessor; _notify: (targetField: Field) => void; } @@ -104,7 +109,7 @@ function getOrCreateFieldController( parent: { enumerable: true, value: parent }, key: { enumerable: true, value: key }, value: { enumerable: true, get: () => controller._value }, - transient: { enumerable: true, get: () => controller._transient }, + isTransient: { enumerable: true, get: () => controller._isTransient }, }); const controller: FieldController = { @@ -114,7 +119,7 @@ function getOrCreateFieldController( _field: field, _key: key, _value: initialValue, - _transient: false, + _isTransient: false, _notify: notify, _accessor: accessor, }; @@ -130,15 +135,15 @@ function getOrCreateFieldController( } function applyValue(controller: FieldController, value: unknown, transient: boolean): void { - if (isEqual(controller._value, value) && controller._transient === transient) { + if (isEqual(controller._value, value) && controller._isTransient === transient) { return; } - controller._transient = transient; + controller._isTransient = transient; let rootController = controller; - while (rootController._parent !== null && !rootController._transient) { + while (rootController._parent !== null && !rootController._isTransient) { const { _key } = rootController; rootController = rootController._parent; value = controller._accessor.set(rootController._value, _key, value); @@ -159,7 +164,7 @@ function propagateValue( if (controller._children !== null) { for (const child of controller._children) { - if (child._transient) { + if (child._isTransient) { continue; } diff --git a/packages/roqueform/src/main/shared-types.ts b/packages/roqueform/src/main/shared-types.ts index 99f79d2..31337e2 100644 --- a/packages/roqueform/src/main/shared-types.ts +++ b/packages/roqueform/src/main/shared-types.ts @@ -14,6 +14,8 @@ type ConsolidateUnion = { */ type ExtractObjects = T extends object ? (T extends (...args: any[]) => any ? never : T) : never; +type Mutable = { -readonly [P in keyof T]: T[P] }; + /** * The key in {@linkcode Plugin} that stores the root field value type. */ @@ -31,10 +33,11 @@ declare const ROOT_VALUE: unique symbol; * @template T The root field value. */ export interface Plugin { - (field: Field & M, accessor: Accessor, notify: () => void): void; + (field: Mutable, accessor: Accessor, notify: () => void): void; /** - * Prevents root value type erasure. + * Prevents root field value type erasure. + * * @internal */ [ROOT_VALUE]?: T; @@ -87,26 +90,26 @@ export interface Field { /** * `true` if the value was last updated using {@linkcode setTransientValue}, or `false` otherwise. */ - readonly transient: boolean; + readonly isTransient: boolean; /** * Updates the value of the field and notifies both ancestors and derived fields. If field withholds a - * {@linkcode transient} value then it becomes non-transient. + * {@linkcode isTransient} value then it becomes non-isTransient. * * @param value The value to set or a callback that receives a previous value and returns a new one. */ setValue(value: T | ((prevValue: T) => T)): void; /** - * Updates the value of the field and notifies only derived fields and marks value as {@linkcode transient}. + * Updates the value of the field and notifies only derived fields and marks value as {@link isTransient transient}. * * @param value The value to set or a callback that receives a previous value and returns a new one. */ setTransientValue(value: T | ((prevValue: T) => T)): void; /** - * If the current value is {@linkcode transient} then notifies parent about this value and marks value as - * non-transient. + * If the current value {@link isTransient is transient} then `dispatch` notifies the parent about this value and + * marks value as non-transient. No-op otherwise. */ dispatch(): void; @@ -122,7 +125,7 @@ export interface Field { ): Field>[K] | (T extends null | undefined ? undefined : never), M> & M; /** - * Subscribes the listener to the field updates. + * Subscribes the listener to field updates. * * Listeners are guaranteed to be called once when {@linkcode notify} is called. * @@ -132,8 +135,8 @@ export interface Field { subscribe( /** * @param targetField The field that triggered the update. This can be ancestor ot descendant field. - * @param field The field to which this listener is subscribed. + * @param currentField The field to which this listener is subscribed. */ - listener: (targetField: Field & M, field: Field & M) => void + listener: (targetField: Field & M, currentField: Field & M) => void ): () => void; } diff --git a/packages/roqueform/src/main/utils.ts b/packages/roqueform/src/main/utils.ts index 005283d..8fe0792 100644 --- a/packages/roqueform/src/main/utils.ts +++ b/packages/roqueform/src/main/utils.ts @@ -15,16 +15,13 @@ export function callOrGet(value: T | ((...args: A) => T), .. * Calls each callback from the list once with given set of arguments. * * If the list contains the same callback multiple times then the callback is called only once. If a callback throws an - * error, the remaining callbacks are still called and the first occurred error is re-thrown in the end. + * error, the remaining callbacks are still called and the error is re-thrown asynchronously. * * @param callbacks The list of callbacks. * @param args The list of arguments to pass to each callback. * @template A The list of callback arguments. */ export function callAll(callbacks: Array<(...args: A) => any>, ...args: A): void { - let errored = false; - let error; - for (let i = 0; i < callbacks.length; ++i) { const cb = callbacks[i]; @@ -33,16 +30,12 @@ export function callAll(callbacks: Array<(...args: A) => any>, } try { cb.apply(undefined, args); - } catch (e) { - if (!errored) { - errored = true; - error = e; - } + } catch (error) { + setTimeout(() => { + throw error; + }, 0); } } - if (errored) { - throw error; - } } /** diff --git a/packages/roqueform/src/main/validationPlugin.ts b/packages/roqueform/src/main/validationPlugin.ts index 3399cf7..8b2cffa 100644 --- a/packages/roqueform/src/main/validationPlugin.ts +++ b/packages/roqueform/src/main/validationPlugin.ts @@ -16,12 +16,12 @@ export interface ValidationMixin { /** * `true` if the field or any of its derived fields have an associated error, or `false` otherwise. */ - readonly invalid: boolean; + readonly isInvalid: boolean; /** * `true` if an async validation is pending, or `false` otherwise. */ - readonly validating: boolean; + readonly isValidating: boolean; /** * Associates an error with the field and notifies the subscribers. @@ -129,9 +129,9 @@ export function validationPlugin( _children: null, _field: field, _errorCount: 0, - _errored: false, + _isErrored: false, _error: null, - _internal: false, + _isInternal: false, _validator: typeof validator === 'function' ? { validate: validator } : validator, _initiator: null, _validationNonce: 0, @@ -155,28 +155,22 @@ export function validationPlugin( Object.defineProperties(field, { error: { enumerable: true, get: () => controller._error }, - invalid: { enumerable: true, get: () => controller._errorCount !== 0 }, - validating: { enumerable: true, get: () => controller._initiator !== null }, + isInvalid: { enumerable: true, get: () => controller._errorCount !== 0 }, + isValidating: { enumerable: true, get: () => controller._initiator !== null }, }); field.setTransientValue = value => { - try { - if (controller._initiator !== null) { - callAll(endValidation(controller, controller._initiator, true, [])); - } - } finally { - setTransientValue(value); + if (controller._initiator !== null) { + callAll(endValidation(controller, controller._initiator, true, [])); } + setTransientValue(value); }; field.setValue = value => { - try { - if (controller._initiator !== null) { - callAll(endValidation(controller, controller._initiator, true, [])); - } - } finally { - setValue(value); + if (controller._initiator !== null) { + callAll(endValidation(controller, controller._initiator, true, [])); } + setValue(value); }; field.setError = error => { @@ -214,14 +208,14 @@ interface FieldController { /** * `true` if this field has an associated error, or `false` otherwise. */ - _errored: boolean; + _isErrored: boolean; _error: unknown | null; /** * `true` if an error was set internally by {@linkcode ValidationMixin.validate}, or `false` if an issue was set by * the user through {@linkcode ValidationMixin.setError}. */ - _internal: boolean; + _isInternal: boolean; _validator: Validator; /** @@ -266,21 +260,21 @@ function setError( internal: boolean, notifyCallbacks: Array<() => void> ): Array<() => void> { - if (controller._errored && isEqual(controller._error, error) && controller._internal === internal) { + if (controller._isErrored && isEqual(controller._error, error) && controller._isInternal === internal) { return notifyCallbacks; } controller._error = error; - controller._internal = internal; + controller._isInternal = internal; notifyCallbacks.push(controller._notify); - if (controller._errored) { + if (controller._isErrored) { return notifyCallbacks; } controller._errorCount++; - controller._errored = true; + controller._isErrored = true; for (let ancestor = controller._parent; ancestor !== null; ancestor = ancestor._parent) { if (ancestor._errorCount++ === 0) { @@ -305,13 +299,13 @@ function deleteError( internal: boolean, notifyCallbacks: Array<() => void> ): Array<() => void> { - if (!controller._errored || (internal && !controller._internal)) { + if (!controller._isErrored || (internal && !controller._isInternal)) { return notifyCallbacks; } controller._error = null; controller._errorCount--; - controller._internal = controller._errored = false; + controller._isInternal = controller._isErrored = false; notifyCallbacks.push(controller._notify); @@ -367,7 +361,7 @@ function beginValidation( if (controller._children !== null) { for (const child of controller._children) { - if (!child._field.transient) { + if (!child._field.isTransient) { beginValidation(child, initiator, notifyCallbacks); } } @@ -448,11 +442,9 @@ function validate(controller: FieldController, options: unknown): any[] | null { try { controller._validator.validate(controller._field, setInternalError, options); - } catch (e) { - try { - callAll(endValidation(controller, controller, false, notifyCallbacks)); - } catch {} - throw e; + } catch (error) { + callAll(endValidation(controller, controller, false, notifyCallbacks)); + throw error; } callAll(endValidation(controller, controller, false, notifyCallbacks)); @@ -513,9 +505,7 @@ function validateAsync(controller: FieldController, options: unknown): Promise { - try { - callAll(endValidation(controller, controller, false, [])); - } catch {} + callAll(endValidation(controller, controller, false, [])); throw error; } ); diff --git a/packages/roqueform/src/test/applyPlugins.test-d.ts b/packages/roqueform/src/test/applyPlugins.test-d.ts index 0a8659a..6d65e2b 100644 --- a/packages/roqueform/src/test/applyPlugins.test-d.ts +++ b/packages/roqueform/src/test/applyPlugins.test-d.ts @@ -1,12 +1,12 @@ import { expectType } from 'tsd'; -import { applyPlugins, createField, objectAccessor, Plugin } from 'roqueform'; +import { applyPlugins, createField, Plugin } from 'roqueform'; declare const plugin1: Plugin<{ aaa: number }>; declare const plugin2: Plugin<{ bbb: boolean }>; expectType>(applyPlugins(plugin1, plugin2)); -const field = createField(objectAccessor, { foo: 111 }, applyPlugins(plugin1, plugin2)); +const field = createField({ foo: 111 }, applyPlugins(plugin1, plugin2)); expectType<{ foo: number }>(field.value); expectType(field.aaa); diff --git a/packages/roqueform/src/test/createField.test-d.ts b/packages/roqueform/src/test/createField.test-d.ts index 975c6aa..c440a63 100644 --- a/packages/roqueform/src/test/createField.test-d.ts +++ b/packages/roqueform/src/test/createField.test-d.ts @@ -1,9 +1,9 @@ import { expectType } from 'tsd'; -import { createField, objectAccessor } from 'roqueform'; +import { createField } from 'roqueform'; // Optional properties -const field1 = createField<{ foo: { bar?: string } | null }>(objectAccessor, { foo: null }); +const field1 = createField<{ foo: { bar?: string } | null }>({ foo: null }); expectType<{ bar?: string } | null>(field1.at('foo').value); @@ -13,7 +13,7 @@ expectType(field1.at('foo').at('bar').value); type Field2Value = { aaa: number } | { aaa: boolean; bbb: string }; -const field2 = createField(objectAccessor, { aaa: 111 }); +const field2 = createField({ aaa: 111 }); expectType(field2.at('aaa').value); diff --git a/packages/roqueform/src/test/createField.test.ts b/packages/roqueform/src/test/createField.test.ts index f5b62f5..e8af559 100644 --- a/packages/roqueform/src/test/createField.test.ts +++ b/packages/roqueform/src/test/createField.test.ts @@ -1,23 +1,29 @@ import { createField, objectAccessor, Plugin } from '../main'; +jest.useFakeTimers(); + +beforeEach(() => { + jest.clearAllTimers(); +}); + describe('createField', () => { test('creates a field without an initial value', () => { - const field = createField(objectAccessor); + const field = createField(); expect(field.parent).toBe(null); expect(field.key).toBe(null); expect(field.value).toBe(undefined); - expect(field.transient).toBe(false); + expect(field.isTransient).toBe(false); }); test('creates a field with the initial value', () => { - const field = createField(objectAccessor, 111); + const field = createField(111); expect(field.value).toBe(111); }); test('returns a field at key', () => { - const field = createField(objectAccessor, { foo: 111 }); + const field = createField({ foo: 111 }); expect(field.at('foo').parent).toBe(field); expect(field.at('foo').key).toBe('foo'); @@ -25,37 +31,37 @@ describe('createField', () => { }); test('returns the same field for the same key', () => { - const field = createField(objectAccessor, { foo: 111 }); + const field = createField({ foo: 111 }); expect(field.at('foo')).toBe(field.at('foo')); }); test('dispatches a value to a root field', () => { - const field = createField(objectAccessor, 111); + const field = createField(111); field.setValue(222); expect(field.value).toBe(222); - expect(field.transient).toBe(false); + expect(field.isTransient).toBe(false); }); test('dispatches a value to a derived field', () => { - const field = createField(objectAccessor, { foo: 111 }); + const field = createField({ foo: 111 }); field.at('foo').setValue(222); expect(field.value).toEqual({ foo: 222 }); - expect(field.transient).toBe(false); + expect(field.isTransient).toBe(false); expect(field.at('foo').value).toBe(222); - expect(field.at('foo').transient).toBe(false); + expect(field.at('foo').isTransient).toBe(false); }); - test('invokes a subscriber during value dispatch', () => { + test('invokes a subscriber when value is updated', () => { const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); - const field = createField(objectAccessor, { foo: 111 }); + const field = createField({ foo: 111 }); field.subscribe(listenerMock); field.at('foo').subscribe(fooListenerMock); @@ -69,47 +75,81 @@ describe('createField', () => { expect(fooListenerMock).toHaveBeenNthCalledWith(1, field.at('foo'), field.at('foo')); }); + test('does not invoke the subscriber of the unchanged sibling field', () => { + const fooListenerMock = jest.fn(); + const barListenerMock = jest.fn(); + + const field = createField({ foo: 111, bar: 'aaa' }); + + field.at('foo').subscribe(fooListenerMock); + field.at('bar').subscribe(barListenerMock); + + field.at('foo').setValue(222); + + expect(barListenerMock).not.toHaveBeenCalled(); + + expect(fooListenerMock).toHaveBeenCalledTimes(1); + expect(fooListenerMock).toHaveBeenNthCalledWith(1, field.at('foo'), field.at('foo')); + }); + + test('does not invoke the subscriber of the unchanged derived field', () => { + const fooListenerMock = jest.fn(); + const barListenerMock = jest.fn(); + + const field = createField({ foo: 111, bar: 'aaa' }); + + field.at('foo').subscribe(fooListenerMock); + field.at('bar').subscribe(barListenerMock); + + field.setValue({ foo: 222, bar: 'aaa' }); + + expect(barListenerMock).not.toHaveBeenCalled(); + + expect(fooListenerMock).toHaveBeenCalledTimes(1); + expect(fooListenerMock).toHaveBeenNthCalledWith(1, field, field.at('foo')); + }); + test('sets a value to a root field', () => { - const field = createField(objectAccessor, 111); + const field = createField(111); field.setTransientValue(222); expect(field.value).toBe(222); - expect(field.transient).toBe(true); + expect(field.isTransient).toBe(true); }); test('sets a value to a derived field', () => { const initialValue = { foo: 111 }; - const field = createField(objectAccessor, initialValue); + const field = createField(initialValue); field.at('foo').setTransientValue(222); expect(field.value).toBe(initialValue); - expect(field.transient).toBe(false); + expect(field.isTransient).toBe(false); expect(field.at('foo').value).toBe(222); - expect(field.at('foo').transient).toBe(true); + expect(field.at('foo').isTransient).toBe(true); }); test('dispatches a value after it was set to a derived field', () => { - const field = createField(objectAccessor, { foo: 111 }); + const field = createField({ foo: 111 }); field.at('foo').setTransientValue(222); field.at('foo').dispatch(); expect(field.value).toEqual({ foo: 222 }); - expect(field.transient).toBe(false); + expect(field.isTransient).toBe(false); expect(field.at('foo').value).toBe(222); - expect(field.at('foo').transient).toBe(false); + expect(field.at('foo').isTransient).toBe(false); }); - test('invokes a subscriber during value set', () => { + test('invokes a subscriber when a value is updated transiently', () => { const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); - const field = createField(objectAccessor, { foo: 111 }); + const field = createField({ foo: 111 }); field.subscribe(listenerMock); field.at('foo').subscribe(fooListenerMock); @@ -129,20 +169,23 @@ describe('createField', () => { throw new Error('barExpected'); }); - const field = createField(objectAccessor, { foo: 111, bar: 222 }); + const field = createField({ foo: 111, bar: 222 }); field.at('foo').subscribe(fooListenerMock); field.at('bar').subscribe(barListenerMock); - expect(() => field.setValue({ foo: 333, bar: 444 })).toThrow(new Error('fooExpected')); + field.setValue({ foo: 333, bar: 444 }); expect(fooListenerMock).toHaveBeenCalledTimes(1); expect(barListenerMock).toHaveBeenCalledTimes(1); expect(field.at('foo').value).toBe(333); expect(field.at('bar').value).toBe(444); + + expect(() => jest.runAllTimers()).toThrow(new Error('fooExpected')); + expect(() => jest.runAllTimers()).toThrow(new Error('barExpected')); }); - test('calls all listeners and throws the first caught error', () => { + test('calls all listeners and throws error asynchronously', () => { const listenerMock1 = jest.fn(() => { throw new Error('expected1'); }); @@ -150,24 +193,27 @@ describe('createField', () => { throw new Error('expected2'); }); - const field = createField(objectAccessor, { foo: 111, bar: 222 }); + const field = createField({ foo: 111, bar: 222 }); field.at('foo').subscribe(listenerMock1); field.at('foo').subscribe(listenerMock2); - expect(() => field.setValue({ foo: 333, bar: 444 })).toThrow(new Error('expected1')); + field.setValue({ foo: 333, bar: 444 }); expect(listenerMock1).toHaveBeenCalledTimes(1); expect(listenerMock2).toHaveBeenCalledTimes(1); expect(field.at('foo').value).toBe(333); expect(field.at('bar').value).toBe(444); + + expect(() => jest.runAllTimers()).toThrow(new Error('expected1')); + expect(() => jest.runAllTimers()).toThrow(new Error('expected2')); }); test('propagates a new value to the derived field', () => { const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); - const field = createField(objectAccessor, { foo: 111 }); + const field = createField({ foo: 111 }); field.subscribe(listenerMock); field.at('foo').subscribe(fooListenerMock); @@ -179,17 +225,17 @@ describe('createField', () => { expect(fooListenerMock).toHaveBeenCalledTimes(1); expect(field.value).toBe(nextValue); - expect(field.transient).toBe(false); + expect(field.isTransient).toBe(false); expect(field.at('foo').value).toBe(333); - expect(field.at('foo').transient).toBe(false); + expect(field.at('foo').isTransient).toBe(false); }); test('does not propagate a new value to the transient derived field', () => { const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); - const field = createField(objectAccessor, { foo: 111 }); + const field = createField({ foo: 111 }); field.subscribe(listenerMock); field.at('foo').subscribe(fooListenerMock); @@ -201,7 +247,7 @@ describe('createField', () => { expect(fooListenerMock).toHaveBeenCalledTimes(1); expect(field.at('foo').value).toBe(222); - expect(field.at('foo').transient).toBe(true); + expect(field.at('foo').isTransient).toBe(true); }); test('does not notify subscribers if a value of the derived field did not change', () => { @@ -210,7 +256,7 @@ describe('createField', () => { const fooValue = { bar: 111 }; - const field = createField(objectAccessor, { foo: fooValue }); + const field = createField({ foo: fooValue }); field.subscribe(listenerMock); field.at('foo').subscribe(fooListenerMock); @@ -226,7 +272,7 @@ describe('createField', () => { test('applies a plugin to the root field', () => { const pluginMock = jest.fn(); - const field = createField(objectAccessor, 111, pluginMock); + const field = createField(111, pluginMock); expect(pluginMock).toHaveBeenCalledTimes(1); expect(pluginMock).toHaveBeenNthCalledWith(1, field, objectAccessor, expect.any(Function)); @@ -235,7 +281,7 @@ describe('createField', () => { test('returns a field if plugin returns undefined', () => { const pluginMock = jest.fn(); - const field = createField(objectAccessor, 111, pluginMock); + const field = createField(111, pluginMock); expect(field.value).toBe(111); @@ -246,7 +292,7 @@ describe('createField', () => { test('applies a plugin to the derived field', () => { const pluginMock = jest.fn(); - const field = createField(objectAccessor, { foo: 111 }, pluginMock); + const field = createField({ foo: 111 }, pluginMock); const fooField = field.at('foo'); @@ -264,7 +310,7 @@ describe('createField', () => { const listenerMock1 = jest.fn(); const listenerMock2 = jest.fn(); - const field = createField(objectAccessor, { foo: 111 }, plugin); + const field = createField({ foo: 111 }, plugin); field.subscribe(listenerMock1); field.at('foo').subscribe(listenerMock2); @@ -291,7 +337,7 @@ describe('createField', () => { const listenerMock1 = jest.fn(); const listenerMock2 = jest.fn(); - const field = createField(objectAccessor, { foo: 111 }, plugin); + const field = createField({ foo: 111 }, plugin); field.subscribe(listenerMock1); field.at('foo').subscribe(listenerMock2); @@ -306,7 +352,7 @@ describe('createField', () => { }); test('an actual parent value is visible in the derived field listener', done => { - const field = createField(objectAccessor, { foo: 111 }); + const field = createField({ foo: 111 }); const newValue = { foo: 222 }; field.at('foo').subscribe(targetField => { @@ -328,7 +374,7 @@ describe('createField', () => { throw new Error('expected2'); }); - const field = createField(objectAccessor, { foo: 111 }, pluginMock); + const field = createField({ foo: 111 }, pluginMock); expect(() => field.at('foo')).toThrow(new Error('expected1')); expect(() => field.at('foo')).toThrow(new Error('expected2')); diff --git a/packages/roqueform/src/test/utils.test.ts b/packages/roqueform/src/test/utils.test.ts index fe04c4f..5382db3 100644 --- a/packages/roqueform/src/test/utils.test.ts +++ b/packages/roqueform/src/test/utils.test.ts @@ -1,5 +1,7 @@ import { callAll, callOrGet } from '../main'; +jest.useFakeTimers(); + describe('callOrGet', () => { test('returns non function value as is', () => { const obj = {}; @@ -35,7 +37,7 @@ describe('callAll', () => { expect(cbMock3).toHaveBeenNthCalledWith(1, 'foo', 'bar'); }); - test('throws the first captured error', () => { + test('throws errors asynchronously', () => { const cbMock1 = jest.fn(() => {}); const cbMock2 = jest.fn(() => { throw new Error('expected2'); @@ -44,10 +46,13 @@ describe('callAll', () => { throw new Error('expected3'); }); - expect(() => callAll([cbMock1, cbMock2, cbMock3])).toThrow(new Error('expected2')); + callAll([cbMock1, cbMock2, cbMock3]); + expect(cbMock1).toHaveBeenCalledTimes(1); expect(cbMock2).toHaveBeenCalledTimes(1); expect(cbMock3).toHaveBeenCalledTimes(1); + + expect(() => jest.runAllTimers()).toThrow(); }); test('does not call the same callback twice', () => { diff --git a/packages/roqueform/src/test/validationPlugin.test.tsx b/packages/roqueform/src/test/validationPlugin.test.tsx index e4b4115..942dc8e 100644 --- a/packages/roqueform/src/test/validationPlugin.test.tsx +++ b/packages/roqueform/src/test/validationPlugin.test.tsx @@ -1,4 +1,4 @@ -import { createField, objectAccessor, validationPlugin, Validator } from '../main'; +import { createField, validationPlugin, Validator } from '../main'; describe('validationPlugin', () => { const noopValidator: Validator = { @@ -6,19 +6,19 @@ describe('validationPlugin', () => { }; test('enhances the field', () => { - const field = createField(objectAccessor, { foo: 0 }, validationPlugin(noopValidator)); + const field = createField({ foo: 0 }, validationPlugin(noopValidator)); - expect(field.validating).toBe(false); - expect(field.invalid).toBe(false); + expect(field.isValidating).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').validating).toBe(false); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isValidating).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('sets an error to the root field', () => { - const field = createField(objectAccessor, { foo: 0 }, validationPlugin(noopValidator)); + const field = createField({ foo: 0 }, validationPlugin(noopValidator)); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -28,10 +28,10 @@ describe('validationPlugin', () => { field.setError(111); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(111); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); expect(listenerMock).toHaveBeenCalledTimes(1); @@ -39,7 +39,7 @@ describe('validationPlugin', () => { }); test('sets an error to the child field', () => { - const field = createField(objectAccessor, { foo: 0 }, validationPlugin(noopValidator)); + const field = createField({ foo: 0 }, validationPlugin(noopValidator)); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -49,10 +49,10 @@ describe('validationPlugin', () => { field.at('foo').setError(111); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); expect(listenerMock).toHaveBeenCalledTimes(1); @@ -60,19 +60,19 @@ describe('validationPlugin', () => { }); test('sets null as an error to the root field', () => { - const field = createField(objectAccessor, { foo: 0 }, validationPlugin(noopValidator)); + const field = createField({ foo: 0 }, validationPlugin(noopValidator)); field.setError(null); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('deletes an error from the root field', () => { - const field = createField(objectAccessor, { foo: 0 }, validationPlugin(noopValidator)); + const field = createField({ foo: 0 }, validationPlugin(noopValidator)); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -83,10 +83,10 @@ describe('validationPlugin', () => { field.setError(111); field.deleteError(); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); expect(listenerMock).toHaveBeenCalledTimes(2); @@ -94,7 +94,7 @@ describe('validationPlugin', () => { }); test('deletes an error from the child field', () => { - const field = createField(objectAccessor, { foo: 0 }, validationPlugin(noopValidator)); + const field = createField({ foo: 0 }, validationPlugin(noopValidator)); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -105,10 +105,10 @@ describe('validationPlugin', () => { field.at('foo').setError(111); field.at('foo').deleteError(); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); expect(listenerMock).toHaveBeenCalledTimes(2); @@ -116,7 +116,7 @@ describe('validationPlugin', () => { }); test('deletes an error from the child field but parent remains invalid', () => { - const field = createField(objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin(noopValidator)); + const field = createField({ foo: 0, bar: 'qux' }, validationPlugin(noopValidator)); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -131,13 +131,13 @@ describe('validationPlugin', () => { field.at('bar').deleteError(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); - expect(field.at('bar').invalid).toBe(false); + expect(field.at('bar').isInvalid).toBe(false); expect(field.at('bar').error).toBe(null); expect(listenerMock).toHaveBeenCalledTimes(1); @@ -146,7 +146,7 @@ describe('validationPlugin', () => { }); test('clears all errors', () => { - const field = createField(objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin(noopValidator)); + const field = createField({ foo: 0, bar: 'qux' }, validationPlugin(noopValidator)); const listenerMock = jest.fn(); const fooListenerMock = jest.fn(); @@ -161,13 +161,13 @@ describe('validationPlugin', () => { field.clearErrors(); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); - expect(field.at('bar').invalid).toBe(false); + expect(field.at('bar').isInvalid).toBe(false); expect(field.at('bar').error).toBe(null); expect(listenerMock).toHaveBeenCalledTimes(2); @@ -177,7 +177,6 @@ describe('validationPlugin', () => { test('clears errors from nested fields', () => { const field = createField( - objectAccessor, { foo: { bar: { @@ -194,18 +193,17 @@ describe('validationPlugin', () => { field.clearErrors(); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); - expect(field.at('foo').at('bar').invalid).toBe(false); - expect(field.at('foo').at('bar').at('baz').invalid).toBe(false); - expect(field.at('foo').at('bar').at('qux').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); + expect(field.at('foo').at('bar').isInvalid).toBe(false); + expect(field.at('foo').at('bar').at('baz').isInvalid).toBe(false); + expect(field.at('foo').at('bar').at('qux').isInvalid).toBe(false); }); test('synchronously validates the root field', () => { const field = createField( - objectAccessor, { foo: 0 }, validationPlugin({ validate(field, setInternalError) { @@ -222,12 +220,12 @@ describe('validationPlugin', () => { expect(field.validate()).toEqual([111]); - expect(field.validating).toBe(false); - expect(field.invalid).toBe(true); + expect(field.isValidating).toBe(false); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').validating).toBe(false); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isValidating).toBe(false); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); expect(listenerMock).toHaveBeenCalledTimes(1); @@ -236,7 +234,6 @@ describe('validationPlugin', () => { test('synchronously validates the root field with a callback validator', () => { const field = createField( - objectAccessor, { foo: 0 }, validationPlugin((field, setInternalError) => { setInternalError(field.at('foo'), 111); @@ -251,12 +248,12 @@ describe('validationPlugin', () => { expect(field.validate()).toEqual([111]); - expect(field.validating).toBe(false); - expect(field.invalid).toBe(true); + expect(field.isValidating).toBe(false); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').validating).toBe(false); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isValidating).toBe(false); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); expect(listenerMock).toHaveBeenCalledTimes(1); @@ -265,7 +262,6 @@ describe('validationPlugin', () => { test('synchronously validates the child field', () => { const field = createField( - objectAccessor, { foo: 0 }, validationPlugin({ validate(field, setInternalError) { @@ -282,12 +278,12 @@ describe('validationPlugin', () => { field.at('foo').validate(); - expect(field.validating).toBe(false); - expect(field.invalid).toBe(true); + expect(field.isValidating).toBe(false); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').validating).toBe(false); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isValidating).toBe(false); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); expect(listenerMock).toHaveBeenCalledTimes(1); @@ -296,7 +292,6 @@ describe('validationPlugin', () => { test('synchronously validates multiple fields', () => { const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate(field, setInternalError) { @@ -308,13 +303,13 @@ describe('validationPlugin', () => { field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); - expect(field.at('bar').invalid).toBe(true); + expect(field.at('bar').isInvalid).toBe(true); expect(field.at('bar').error).toBe(222); }); @@ -331,7 +326,6 @@ describe('validationPlugin', () => { }); const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate: validateMock, @@ -343,19 +337,18 @@ describe('validationPlugin', () => { expect(validateMock).toHaveBeenCalledTimes(2); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); - expect(field.at('bar').invalid).toBe(false); + expect(field.at('bar').isInvalid).toBe(false); expect(field.at('bar').error).toBe(null); }); test('does not clear an error set by the user before validation', () => { const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate(field, setInternalError) { @@ -368,19 +361,18 @@ describe('validationPlugin', () => { field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual(111); - expect(field.at('bar').invalid).toBe(true); + expect(field.at('bar').isInvalid).toBe(true); expect(field.at('bar').error).toBe(222); }); test('does not raise validation errors for transient fields', () => { const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate(field, setInternalError) { @@ -394,19 +386,18 @@ describe('validationPlugin', () => { field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); - expect(field.at('bar').invalid).toBe(false); + expect(field.at('bar').isInvalid).toBe(false); expect(field.at('bar').error).toBe(null); }); test('asynchronously validates the root field', async () => { const field = createField( - objectAccessor, { foo: 0 }, validationPlugin({ validate: () => undefined, @@ -427,17 +418,17 @@ describe('validationPlugin', () => { expect(promise).toBeInstanceOf(Promise); - expect(field.validating).toBe(true); - expect(field.at('foo').validating).toBe(true); + expect(field.isValidating).toBe(true); + expect(field.at('foo').isValidating).toBe(true); await expect(promise).resolves.toEqual([111]); - expect(field.validating).toBe(false); - expect(field.invalid).toBe(true); + expect(field.isValidating).toBe(false); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').validating).toBe(false); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isValidating).toBe(false); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); expect(listenerMock).toHaveBeenCalledTimes(3); @@ -446,7 +437,6 @@ describe('validationPlugin', () => { test('asynchronously validates the child field', async () => { const field = createField( - objectAccessor, { foo: 0 }, validationPlugin({ validate: () => undefined, @@ -465,17 +455,17 @@ describe('validationPlugin', () => { const promise = field.at('foo').validateAsync(); - expect(field.validating).toBe(false); - expect(field.at('foo').validating).toBe(true); + expect(field.isValidating).toBe(false); + expect(field.at('foo').isValidating).toBe(true); await expect(promise).resolves.toEqual([111]); - expect(field.validating).toBe(false); - expect(field.invalid).toBe(true); + expect(field.isValidating).toBe(false); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').validating).toBe(false); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isValidating).toBe(false); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toBe(111); expect(listenerMock).toHaveBeenCalledTimes(1); @@ -484,7 +474,6 @@ describe('validationPlugin', () => { test('cleans up validation if a sync error is thrown', () => { const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate() { @@ -497,18 +486,17 @@ describe('validationPlugin', () => { expect(() => field.validate()).toThrow(new Error('expected')); - expect(field.validating).toBe(false); - expect(field.invalid).toBe(false); + expect(field.isValidating).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').validating).toBe(false); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isValidating).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('cleans up validation if an async error is thrown', async () => { const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate: () => undefined, @@ -525,12 +513,12 @@ describe('validationPlugin', () => { await expect(promise).rejects.toEqual(new Error('expected')); - expect(field.validating).toBe(false); - expect(field.invalid).toBe(false); + expect(field.isValidating).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').validating).toBe(false); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isValidating).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); @@ -538,7 +526,6 @@ describe('validationPlugin', () => { let lastSignal: AbortSignal | undefined; const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate: () => undefined, @@ -551,14 +538,14 @@ describe('validationPlugin', () => { const promise = field.validateAsync(); - expect(field.validating).toBe(true); - expect(field.at('foo').validating).toBe(true); + expect(field.isValidating).toBe(true); + expect(field.at('foo').isValidating).toBe(true); field.abortValidation(); expect(lastSignal!.aborted).toBe(true); - expect(field.validating).toBe(false); - expect(field.at('foo').validating).toBe(false); + expect(field.isValidating).toBe(false); + expect(field.at('foo').isValidating).toBe(false); await expect(promise).rejects.toEqual(new Error('Validation aborted')); }); @@ -567,7 +554,6 @@ describe('validationPlugin', () => { const signals: AbortSignal[] = []; const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate: () => undefined, @@ -592,7 +578,6 @@ describe('validationPlugin', () => { const signals: AbortSignal[] = []; const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate: () => undefined, @@ -622,7 +607,6 @@ describe('validationPlugin', () => { }); const field = createField( - objectAccessor, { foo: 0, bar: 'qux' }, validationPlugin({ validate: () => undefined, diff --git a/packages/scroll-to-error-plugin/README.md b/packages/scroll-to-error-plugin/README.md index df5055d..689bab2 100644 --- a/packages/scroll-to-error-plugin/README.md +++ b/packages/scroll-to-error-plugin/README.md @@ -9,64 +9,65 @@ npm install --save-prod @roqueform/scroll-to-error-plugin # Usage example -🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/Scroll_to_error_plugin.html) +🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/scroll_to_error_plugin.html) -Scroll plugin assumes that the field is enhanced with `ref` and `error` properties. The `ref` property should be a Rect -reference object that points to the `Element`, and `error` holds a validation error. If an element is displayed and an -error is defined and not `null` than `scrollToError()` would reveal this element on the screen. +This plugin works in conjunction with [a validation plugin](../../#plugins-and-integrations). If an element associated +with the field is displayed and an `error` isn't `null` than `scrollToError()` would scroll the viewport, so the element +is reveled on the screen. + +The example below uses [Doubter](https://github.com/smikhalevski/doubter#readme) shapes and +[Doubter plugin](../doubter-plugin#readme) for validation. ```tsx -import { useEffect } from 'react'; -import { FieldRenderer, useField } from 'roqueform'; +import { SyntheticEvent, useEffect } from 'react'; +import { applyPlugins } from 'roqueform'; +import { FieldRenderer, useField } from '@roqueform/react'; import { doubterPlugin } from '@roqueform/doubter-plugin'; -import { refPlugin } from '@roqueform/ref-plugin'; import { scrollToErrorPlugin } from '@roqueform/scroll-to-error-plugin'; import * as d from 'doubter'; -// Define a runtime type using Doubter -const valueShape = d.object({ - bar: d.string().min(1), +const planetShape = d.object({ + name: d.string().min(1), }); export const App = () => { - const rootField = useField( - { bar: 'qux' }, + const planetField = useField( + { name: '' }, applyPlugins( - refPlugin(), - doubterPlugin(valueShape), + doubterPlugin(planetShape), scrollToErrorPlugin() ) ); - const handleSubmit = (event: SyntheticEvent): void => { + const handleSubmit = (event: SyntheticEvent) => { event.preventDefault(); - if (rootField.validate()) { + if (planetField.validate()) { // Scroll to the error that is closest to the top left conrner of the document - rootField.scrollToError(0, { behavior: 'smooth' }); + planetField.scrollToError(0, { behavior: 'smooth' }); return; } // The form value to submit - rootField.value; + planetField.value; }; return ( - - {barField => ( + + {nameField => ( <> { - barField.setValue(event.target.value); + nameField.setValue(event.target.value); }} /> - {barField.error?.message} + {nameField.error?.message} )} diff --git a/packages/scroll-to-error-plugin/package.json b/packages/scroll-to-error-plugin/package.json index 2817368..2025e6a 100644 --- a/packages/scroll-to-error-plugin/package.json +++ b/packages/scroll-to-error-plugin/package.json @@ -7,7 +7,8 @@ "types": "./lib/index.d.ts", "typedoc": { "entryPoint": "./src/main/index.ts", - "displayName": "Scroll to error plugin" + "displayName": "scroll-to-error-plugin", + "readmeFile": "none" }, "sideEffects": false, "files": [ diff --git a/packages/scroll-to-error-plugin/src/test/scrollToErrorPlugin.test.tsx b/packages/scroll-to-error-plugin/src/test/scrollToErrorPlugin.test.tsx index 7f48621..b3ac545 100644 --- a/packages/scroll-to-error-plugin/src/test/scrollToErrorPlugin.test.tsx +++ b/packages/scroll-to-error-plugin/src/test/scrollToErrorPlugin.test.tsx @@ -1,5 +1,5 @@ import { act } from '@testing-library/react'; -import { applyPlugins, createField, objectAccessor, validationPlugin } from 'roqueform'; +import { applyPlugins, createField, validationPlugin } from 'roqueform'; import { scrollToErrorPlugin } from '../main'; class DOMRect { @@ -21,7 +21,6 @@ class DOMRect { describe('scrollToErrorPlugin', () => { test('returns false if there are no errors', () => { const field = createField( - objectAccessor, { foo: 111 }, applyPlugins( validationPlugin(() => undefined), @@ -34,7 +33,6 @@ describe('scrollToErrorPlugin', () => { test('scrolls to error at index with RTL text direction', async () => { const rootField = createField( - objectAccessor, { foo: 111, bar: 'aaa' }, applyPlugins( validationPlugin(() => undefined), @@ -111,7 +109,6 @@ describe('scrollToErrorPlugin', () => { test('scrolls to error at index with LTR text direction', async () => { const rootField = createField( - objectAccessor, { foo: 111, bar: 'aaa' }, applyPlugins( validationPlugin(() => undefined), diff --git a/packages/uncontrolled-plugin/README.md b/packages/uncontrolled-plugin/README.md index 050797e..b8dbdef 100644 --- a/packages/uncontrolled-plugin/README.md +++ b/packages/uncontrolled-plugin/README.md @@ -1,29 +1,127 @@ -# Uncontrolled elements plugin for Roqueform +# Uncontrolled plugin for Roqueform -Allows [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields to be updated by DOM change events. +Updates [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields by listening to change events of associated +DOM elements. + +🔥 [**Try it on CodeSandbox**](https://codesandbox.io/s/fsdshx) + +```sh +npm install --save-prod @roqueform/uncontrolled-plugin +``` + +# Usage example + +🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/uncontrolled_plugin.html) ```tsx -import { useEffect } from 'react'; -import { useField } from 'roqueform'; +import { SyntheticEvent } from 'react'; +import { useField } from '@roqueform/react'; import { uncontrolledPlugin } from '@roqueform/uncontrolled-plugin'; export const App = () => { - const field = useField({ bar: 'qux' }, uncontrolledPlugin()); + const planetField = useField({ name: 'Mars' }, uncontrolledPlugin()); - const handleSubmit = (event: SyntheticEvent): void => { + const handleSubmit = (event: SyntheticEvent) => { event.preventDefault(); - // The field value is always in sync with the input element value - field.value; - // → { bar: 'qux' } + // The field value is always in sync with the input element value. + planetField.value; }; return ( - + ); }; ``` + +# Value coercion + +To associate field with a form element, pass `refCallback` as a `ref` attribute of an `input`, `textarea`, or any other +form element: + +```tsx + +``` + +The plugin would synchronize the field value and the input value. When the input value is changed and `change` or +`input` event is dispatched, `field` is updated with the corresponding value. + +If you have a set of radio buttons, or checkboxes that update a single field, provide the same `refCallback` to all +inputs, `uncontrolledPlugin` would use them a source of values. + +```ts +const namesField = useField(['Mars', 'Pluto'], uncontrolledPlugin()); +``` + +The plugin relies only on `value` attribute, so `name` and other attributes are optional: + +```tsx +
+ + +
+``` + +By default, `uncontrolledPlugin` uses the opinionated element value accessor that applies following coercion rules to +values of form elements: + +- Single checkboxes → boolean; + +- Multiple checkboxes → an array of `value` attributes of checked checkboxes; + +- Radio buttons → the `value` attribute of a radio button that is checked or `null` if no radio buttons are checked; + +- Number input → number, or `null` if empty; + +- Range input → number; + +- Date input → the `value` attribute, or `null` if empty; + +- Time input → a time string, or `null` if empty; + +- Image input → string value of the `src` attribute; + +- File input → `File` or `null` if no file selected, file inputs are read-only; + +- Multi-file input → array of `File`; + +- Others → `value` attribute, or `null` if element doesn't support it; + +- `null`, `undefined`, `NaN` and non-finite numbers are coerced to an empty string and written to `value` attribute. + +This behaviour can be changed by passing a custom +[`ElementValueAccessor`](https://smikhalevski.github.io/roqueform/interfaces/uncontrolled_plugin.ElementValueAccessor.html) +implementation to a plugin. Or you can use a +[`createElementValueAccessor`](https://smikhalevski.github.io/roqueform/functions/uncontrolled_plugin.createElementValueAccessor.html) +factory to customise the default behaviour: + +```ts +import { useField } from '@roqueform/react'; +import { uncontrolledPlugin } from '@roqueform/uncontrolled-plugin'; + +const personField = useField( + { dateOfBirth: 316310400000 }, + uncontrolledPlugin( + createElementValueAccessor({ dateFormat: 'timestamp' }) + ) +); +``` + +Read more about available options in +[`ElementValueAccessorOptions`](https://smikhalevski.github.io/roqueform/interfaces/uncontrolled_plugin.ElementValueAccessorOptions.html). diff --git a/packages/uncontrolled-plugin/package.json b/packages/uncontrolled-plugin/package.json index 12184c1..0691222 100644 --- a/packages/uncontrolled-plugin/package.json +++ b/packages/uncontrolled-plugin/package.json @@ -1,13 +1,14 @@ { "name": "@roqueform/uncontrolled-plugin", "version": "1.0.0", - "description": "Allows Roqueform fields to be updated by DOM change events.", + "description": "Updates Roqueform fields by listening to change events of associated DOM elements.", "main": "./lib/index.js", "module": "./lib/index.mjs", "types": "./lib/index.d.ts", "typedoc": { "entryPoint": "./src/main/index.ts", - "displayName": "Uncontrolled elements plugin" + "displayName": "uncontrolled-plugin", + "readmeFile": "none" }, "sideEffects": false, "files": [ @@ -28,7 +29,7 @@ "field", "plugin", "dom", - "ref" + "uncontrolled" ], "author": "Savva Mikhalevski ", "license": "MIT", diff --git a/packages/uncontrolled-plugin/src/test/uncontrolledPlugin.test.ts b/packages/uncontrolled-plugin/src/test/uncontrolledPlugin.test.ts index 5e1dc29..55ed59b 100644 --- a/packages/uncontrolled-plugin/src/test/uncontrolledPlugin.test.ts +++ b/packages/uncontrolled-plugin/src/test/uncontrolledPlugin.test.ts @@ -15,7 +15,7 @@ describe('uncontrolledPlugin', () => { test('updates field value on input change', () => { const listenerMock = jest.fn(); - const field = createField(objectAccessor, { foo: 0 }, uncontrolledPlugin()); + const field = createField({ foo: 0 }, uncontrolledPlugin()); element.type = 'number'; @@ -29,7 +29,7 @@ describe('uncontrolledPlugin', () => { }); test('updates input value on field change', () => { - const field = createField(objectAccessor, { foo: 0 }, uncontrolledPlugin()); + const field = createField({ foo: 0 }, uncontrolledPlugin()); field.at('foo').refCallback(element); field.at('foo').setValue(111); @@ -38,7 +38,7 @@ describe('uncontrolledPlugin', () => { }); test('sets the initial value to the element', () => { - const field = createField(objectAccessor, { foo: 111 }, uncontrolledPlugin()); + const field = createField({ foo: 111 }, uncontrolledPlugin()); element.type = 'number'; @@ -53,7 +53,7 @@ describe('uncontrolledPlugin', () => { field.refCallback = refCallbackMock; }); - const field = createField(objectAccessor, { foo: 111 }, applyPlugins(pluginMock, uncontrolledPlugin())); + const field = createField({ foo: 111 }, applyPlugins(pluginMock, uncontrolledPlugin())); expect(pluginMock).toHaveBeenCalledTimes(1); expect(pluginMock).toHaveBeenNthCalledWith(1, field, objectAccessor, expect.any(Function)); @@ -75,7 +75,7 @@ describe('uncontrolledPlugin', () => { const element1 = document.body.appendChild(document.createElement('input')); const element2 = document.body.appendChild(document.createElement('input')); - const field = createField(objectAccessor, { foo: 111 }, applyPlugins(plugin, uncontrolledPlugin())); + const field = createField({ foo: 111 }, applyPlugins(plugin, uncontrolledPlugin())); field.at('foo').refCallback(element1); field.at('foo').refCallback(element2); @@ -93,7 +93,7 @@ describe('uncontrolledPlugin', () => { const element1 = document.body.appendChild(document.createElement('input')); const element2 = document.body.appendChild(document.createElement('textarea')); - const field = createField(objectAccessor, { foo: 111 }, applyPlugins(plugin, uncontrolledPlugin())); + const field = createField({ foo: 111 }, applyPlugins(plugin, uncontrolledPlugin())); field.at('foo').refCallback(element1); field.at('foo').refCallback(element2); @@ -116,7 +116,7 @@ describe('uncontrolledPlugin', () => { field.refCallback = refCallbackMock; }; - const field = createField(objectAccessor, { foo: 111 }, applyPlugins(plugin, uncontrolledPlugin())); + const field = createField({ foo: 111 }, applyPlugins(plugin, uncontrolledPlugin())); field.at('foo').refCallback(element); @@ -136,7 +136,7 @@ describe('uncontrolledPlugin', () => { field.refCallback = refCallbackMock; }; - const field = createField(objectAccessor, { foo: 111 }, applyPlugins(plugin, uncontrolledPlugin())); + const field = createField({ foo: 111 }, applyPlugins(plugin, uncontrolledPlugin())); field.at('foo').refCallback(null); @@ -149,7 +149,7 @@ describe('uncontrolledPlugin', () => { set: jest.fn(), }; - const field = createField(objectAccessor, 'aaa', uncontrolledPlugin(accessorMock)); + const field = createField('aaa', uncontrolledPlugin(accessorMock)); const setValueMock = (field.setValue = jest.fn(field.setValue)); @@ -176,7 +176,7 @@ describe('uncontrolledPlugin', () => { set: jest.fn(), }; - const field = createField(objectAccessor, { foo: 'aaa' }, uncontrolledPlugin(accessorMock)); + const field = createField({ foo: 'aaa' }, uncontrolledPlugin(accessorMock)); field.at('foo').refCallback(element); @@ -195,7 +195,7 @@ describe('uncontrolledPlugin', () => { set: jest.fn(), }; - const field = createField(objectAccessor, { foo: 'aaa' }, uncontrolledPlugin(accessorMock)); + const field = createField({ foo: 'aaa' }, uncontrolledPlugin(accessorMock)); field.at('foo').setValue('bbb'); @@ -211,7 +211,7 @@ describe('uncontrolledPlugin', () => { const element1 = document.body.appendChild(document.createElement('input')); const element2 = document.body.appendChild(document.createElement('textarea')); - const field = createField(objectAccessor, { foo: 111 }, uncontrolledPlugin(accessorMock)); + const field = createField({ foo: 111 }, uncontrolledPlugin(accessorMock)); field.at('foo').refCallback(element1); @@ -232,7 +232,7 @@ describe('uncontrolledPlugin', () => { const element = document.createElement('input'); - const field = createField(objectAccessor, { foo: 111 }, uncontrolledPlugin(accessorMock)); + const field = createField({ foo: 111 }, uncontrolledPlugin(accessorMock)); field.at('foo').refCallback(element); @@ -242,7 +242,7 @@ describe('uncontrolledPlugin', () => { test('mutation observer disconnects after last element is removed', done => { const disconnectMock = jest.spyOn(MutationObserver.prototype, 'disconnect'); - const field = createField(objectAccessor, { foo: 111 }, uncontrolledPlugin()); + const field = createField({ foo: 111 }, uncontrolledPlugin()); field.at('foo').refCallback(element); diff --git a/packages/zod-plugin/README.md b/packages/zod-plugin/README.md index 9744dbb..d0ec19a 100644 --- a/packages/zod-plugin/README.md +++ b/packages/zod-plugin/README.md @@ -1,7 +1,6 @@ # Zod plugin for Roqueform -Enhances [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields with validation methods powered by -[Zod](https://zod.dev/). +Validates [Roqueform](https://github.com/smikhalevski/roqueform#readme) fields with [Zod](https://zod.dev/) schemas. ```sh npm install --save-prod @roqueform/zod-plugin @@ -9,50 +8,48 @@ npm install --save-prod @roqueform/zod-plugin # Usage example -🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/Zod_plugin.html) +🔎 [API documentation is available here.](https://smikhalevski.github.io/roqueform/modules/zod_plugin.html) ```tsx import { SyntheticEvent } from 'react'; -import { FieldRenderer, useField } from 'roqueform'; +import { FieldRenderer, useField } from '@roqueform/react'; import { zodPlugin } from '@roqueform/zod-plugin'; import { z } from 'zod'; -// Define a value shape using Zod -const valueType = d.object({ - bar: d.string().min(1), +const planetSchema = z.object({ + name: z.string().min(1), }); export const App = () => { - const rootField = useField({ bar: '' }, zodPlugin(valueType)); + const planetField = useField({ name: '' }, zodPlugin(planetSchema)); - const handleSubmit = (event: SyntheticEvent): void => { + const handleSubmit = (event: SyntheticEvent) => { event.preventDefault(); - if (rootField.validate()) { + if (planetField.validate()) { // Errors are associated with fields automatically return; } - // If your shapes have transformations, you can safely parse + // If your shapes have transformations or refinements, you can safely parse // the field value after it was successfully validated - const value = valueType.parse(rootField.value); + const value = planetSchema.parse(planetField.value); }; return (
- - {barField => ( + + {nameField => ( <> { - barField.setValue(event.target.value); + nameField.setValue(event.target.value); }} - aria-invalid={barField.invalid} /> - {barField.error?.message} + {nameField.error?.message} )} diff --git a/packages/zod-plugin/package.json b/packages/zod-plugin/package.json index a76fb79..1bed31e 100644 --- a/packages/zod-plugin/package.json +++ b/packages/zod-plugin/package.json @@ -1,13 +1,14 @@ { "name": "@roqueform/zod-plugin", "version": "1.0.0", - "description": "Enhances Roqueform fields with validation methods powered by Zod.", + "description": "Validates Roqueform fields with Zod schemas.", "main": "./lib/index.js", "module": "./lib/index.mjs", "types": "./lib/index.d.ts", "typedoc": { "entryPoint": "./src/main/index.ts", - "displayName": "Zod plugin" + "displayName": "zod-plugin", + "readmeFile": "none" }, "sideEffects": false, "files": [ diff --git a/packages/zod-plugin/src/test/zodPlugin.test-d.ts b/packages/zod-plugin/src/test/zodPlugin.test-d.ts index 0f0efac..3fc297c 100644 --- a/packages/zod-plugin/src/test/zodPlugin.test-d.ts +++ b/packages/zod-plugin/src/test/zodPlugin.test-d.ts @@ -1,10 +1,10 @@ import { z } from 'zod'; import { expectType } from 'tsd'; -import { createField, Field, objectAccessor } from 'roqueform'; +import { createField, Field } from 'roqueform'; import { ZodMixin, zodPlugin } from '@roqueform/zod-plugin'; const shape = z.object({ foo: z.object({ bar: z.string() }) }); expectType & ZodMixin>( - createField(objectAccessor, { foo: { bar: 'aaa' } }, zodPlugin(shape)) + createField({ foo: { bar: 'aaa' } }, zodPlugin(shape)) ); diff --git a/packages/zod-plugin/src/test/zodPlugin.test.tsx b/packages/zod-plugin/src/test/zodPlugin.test.tsx index acd6531..771d0a3 100644 --- a/packages/zod-plugin/src/test/zodPlugin.test.tsx +++ b/packages/zod-plugin/src/test/zodPlugin.test.tsx @@ -1,6 +1,6 @@ import { z, ZodErrorMap, ZodIssue, ZodIssueCode } from 'zod'; import { zodPlugin } from '../main'; -import { createField, objectAccessor } from 'roqueform'; +import { createField } from 'roqueform'; describe('zodPlugin', () => { const fooType = z.object({ @@ -13,17 +13,17 @@ describe('zodPlugin', () => { }); test('enhances the field', () => { - const field = createField(objectAccessor, { foo: 0 }, zodPlugin(fooType)); + const field = createField({ foo: 0 }, zodPlugin(fooType)); - expect(field.invalid).toBe(false); + expect(field.isInvalid).toBe(false); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toBe(null); }); test('converts string errors to issue messages', () => { - const field = createField(objectAccessor, { foo: 0 }, zodPlugin(fooType)); + const field = createField({ foo: 0 }, zodPlugin(fooType)); field.setError('aaa'); @@ -31,7 +31,7 @@ describe('zodPlugin', () => { }); test('sets issue as an error', () => { - const field = createField(objectAccessor, { foo: 0 }, zodPlugin(fooType)); + const field = createField({ foo: 0 }, zodPlugin(fooType)); const issue: ZodIssue = { code: ZodIssueCode.custom, path: ['bbb'], message: 'aaa' }; @@ -42,14 +42,14 @@ describe('zodPlugin', () => { }); test('validates the root field', () => { - const field = createField(objectAccessor, { foo: 0 }, zodPlugin(fooType)); + const field = createField({ foo: 0 }, zodPlugin(fooType)); field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'too_small', exact: false, @@ -62,14 +62,14 @@ describe('zodPlugin', () => { }); test('validates the child field', () => { - const field = createField(objectAccessor, { foo: 0 }, zodPlugin(fooType)); + const field = createField({ foo: 0 }, zodPlugin(fooType)); field.at('foo').validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'too_small', exact: false, @@ -82,14 +82,14 @@ describe('zodPlugin', () => { }); test('validates multiple fields', () => { - const field = createField(objectAccessor, { foo: 0, bar: 'qux' }, zodPlugin(fooBarType)); + const field = createField({ foo: 0, bar: 'qux' }, zodPlugin(fooBarType)); field.validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'too_small', exact: false, @@ -100,7 +100,7 @@ describe('zodPlugin', () => { type: 'number', }); - expect(field.at('bar').invalid).toBe(true); + expect(field.at('bar').isInvalid).toBe(true); expect(field.at('bar').error).toEqual({ code: 'too_big', exact: false, @@ -113,17 +113,17 @@ describe('zodPlugin', () => { }); test('does not validate sibling fields', () => { - const field = createField(objectAccessor, { foo: 0, bar: 'qux' }, zodPlugin(fooBarType)); + const field = createField({ foo: 0, bar: 'qux' }, zodPlugin(fooBarType)); field.at('bar').validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toEqual(null); - expect(field.at('bar').invalid).toBe(true); + expect(field.at('bar').isInvalid).toBe(true); expect(field.at('bar').error).toEqual({ code: 'too_big', exact: false, @@ -136,18 +136,18 @@ describe('zodPlugin', () => { }); test('validates a transient value', () => { - const field = createField(objectAccessor, { foo: 0, bar: '' }, zodPlugin(fooBarType)); + const field = createField({ foo: 0, bar: '' }, zodPlugin(fooBarType)); field.at('bar').setTransientValue('qux'); field.at('bar').validate(); - expect(field.invalid).toBe(true); + expect(field.isInvalid).toBe(true); expect(field.error).toBe(null); - expect(field.at('foo').invalid).toBe(false); + expect(field.at('foo').isInvalid).toBe(false); expect(field.at('foo').error).toEqual(null); - expect(field.at('bar').invalid).toBe(true); + expect(field.at('bar').isInvalid).toBe(true); expect(field.at('bar').error).toEqual({ code: 'too_big', exact: false, @@ -164,13 +164,13 @@ describe('zodPlugin', () => { return { message: 'aaa' }; }); - const field = createField(objectAccessor, { foo: 0, bar: '' }, zodPlugin(fooBarType, errorMapMock)); + const field = createField({ foo: 0, bar: '' }, zodPlugin(fooBarType, errorMapMock)); field.validate(); expect(errorMapMock).toHaveBeenCalledTimes(1); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'too_small', exact: false, @@ -187,13 +187,13 @@ describe('zodPlugin', () => { return { message: 'aaa' }; }); - const field = createField(objectAccessor, { foo: 0, bar: '' }, zodPlugin(fooBarType)); + const field = createField({ foo: 0, bar: '' }, zodPlugin(fooBarType)); field.validate({ errorMap: errorMapMock }); expect(errorMapMock).toHaveBeenCalledTimes(1); - expect(field.at('foo').invalid).toBe(true); + expect(field.at('foo').isInvalid).toBe(true); expect(field.at('foo').error).toEqual({ code: 'too_small', exact: false, diff --git a/typedoc.json b/typedoc.json index 9a811d1..4b5ea07 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,9 +1,12 @@ { "name": "Roqueform", - "out": "./docs", "entryPoints": [ "./packages/*" ], + "excludePrivate": true, + "excludeExternals": true, "excludeInternal": true, - "entryPointStrategy": "packages" + "entryPointStrategy": "packages", + "disableSources": true, + "readme": "none" }