diff --git a/.gitignore b/.gitignore index 63b3b9cc..9e9c4feb 100644 --- a/.gitignore +++ b/.gitignore @@ -189,3 +189,4 @@ dist !.yarn/releases !.yarn/sdks !.yarn/versions +./website/build diff --git a/README.md b/README.md index 249b96f3..057241da 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,10 @@ ```bash npm install patronum +# or +yarn add patronum +# or +pnpm add patronum ``` Next just import methods from `"patronum"` and use it: @@ -82,789 +86,11 @@ const userLoadFx = createEffect(); const $status = status({ effect: userLoadFx }); ``` -## 🐞 Debug and log - -Sometimes we need to log each event and change in our application, here we need to install [`effector-logger`](https://github.com/effector/logger): - -```bash -npm install --dev effector-logger -``` - -We have some variants how to use logger to debug our applications. Please, don't merge all variants, **it's not compatible**! - -### 1. Temporarily change imports in certain modules - -If we need to debug just some list of modules, we can just replace `effector` import to `effector-logger`: - -```diff --import { createStore, createEvent, sample } from 'effector' -+import { createStore, createEvent, sample } from 'effector-logger' -import { spread } from 'patronum' -``` - -Next just open the Console in browser DevTools. But here we see strange names of the stores and events like "ashg7d". -This means we need to use [effector babel plugin](https://effector.dev/docs/api/effector/babel-plugin/). - -> Note: You don't need to install it separately, because its bundled into effector package. - -```json5 -// .babelrc -{ - plugins: [ - ['effector/babel-plugin', { importName: 'effector-logger' }], // Just add this line into your .babelrc or babel.config.js plugins section. - ], - presets: [ - 'patronum/babel-preset', // Add this line at the end of the all presets - ], -} -``` - -### 2. Use `effector-logger/babel-plugin` to automatically replace all imports in development - -But some projects already use `effector/babel-plugin`, and for correct work with `effector-logger` we need **just one** instance of babel plugin. -This means that [effector-logger has its own babel-plugin](https://github.com/effector/logger#usage).
-**Don't use `effector/babel-plugin` simultaneously with `effector-logger/babel-plugin`!** Use just one at the time, for example: for the dev environment use `effector-logger/babel-plugin`, but for production use `effector/babel-plugin`. - -
- - How to setup `.babelrc` - - -```json5 -// .babelrc -{ - presets: [ - 'patronum/babel-preset', // Add this line at the end of the all presets in the root of the file - ], - env: { - development: { - plugins: [ - ['effector-logger/babel-plugin', {}], // In the curly brackets you can pass options for logger AND effector - ], - }, - production: { - plugins: [ - ['effector/babel-plugin', {}], // In the curly brackets you can pass options for effector - ], - }, - }, -} -``` - -If you need to pass factories, here you need to duplicate your array: - -```json5 -// .babelrc -{ - env: { - development: { - plugins: [ - [ - 'effector-logger/babel-plugin', - { - effector: { - factories: ['src/shared/lib/compare', 'src/shared/lib/timing'], - }, - }, - ], - ], - }, - production: { - plugins: [ - [ - 'effector/babel-plugin', - { factories: ['src/shared/lib/compare', 'src/shared/lib/timing'] }, - ], - ], - }, - }, -} -``` - -Also, you need to build your project with `BABEL_ENV=development` for dev and `BABEL_ENV=production` for prod, to choose the appropriate option in the `"env"` section. - -Relative links: - -- https://babeljs.io/docs/en/options#env -- https://babeljs.io/docs/en/config-files - -
- -
- - How to setup `babel.config.js` - - -```js -module.exports = (api) => { - const isDev = api.env('development'); - - return { - presets: [ - // Add next line at the end of presets list - 'patronum/babel-preset', - ], - plugins: [ - // Add next lines at the end of the plugins list - isDev ? ['effector-logger/babel-plugin', {}] : ['effector/babel-plugin', {}], - ], - }; -}; -``` - -If you want to pass factories to the effector plugin, you need just put it to the variable: - -```js -module.exports = (api) => { - const isDev = api.env('development'); - // Here your factories - const factories = ['src/shared/lib/compare', 'src/shared/lib/timing']; - - return { - plugins: [ - isDev - ? // All effector options passed into `effector` property - ['effector-logger/babel-plugin', { effector: { factories } }] - : ['effector/babel-plugin', { factories }], - ], - }; -}; -``` - -Also, you need to build your project with `BABEL_ENV=development` for dev and `BABEL_ENV=production` for prod, to choose the appropriate option in the `"env"` section. - -Relative links: - -- https://babeljs.io/docs/en/options#env -- https://babeljs.io/docs/en/config-files - -
- -### 3. CRA support with [macros](https://github.com/kentcdodds/babel-plugin-macros) - -[`babel-plugin-macros`](https://github.com/kentcdodds/babel-plugin-macros) is bundled into CRA, so we can use it due CRA don't support adding babel plugins into `.babelrc` or `babel.config.js`. - -Just import from `patronum/macro` and `effector-logger/macro`, and use as early: - -```ts -import { createStore, createEffect, sample } from 'effector-logger/macro'; -import { status, splitMap, combineEvents } from 'patronum/macro'; -``` - -> - Warning: babel-plugin-macros do not support `import * as name`! -> - Note: Since release of patronum@2.0.0 it is required to use babel-plugin-macros@3.0.0 or higher. -> - Please note, that react-scripts@4.0.3 and older **uses outdated version** of this plugin - you can either use [yarn resolutions](https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/) or use react-scripts@5.0.0 or higher. - ## Migration guide -
- - show / hide - - -### v2.0.0 - -Removed support of effector v21. Now the minimum supported version is `v22.1.2`. - -### v0.110 - -From `v0.110.0` patronum removed support of effector v20. Now minimum supported version is `v21.4`. - -Please, before upgrade review release notes of [`effector v21`](https://github.com/effector/effector/releases/tag/effector%4021.0.0). - -### v0.100 - -From `v0.100.0` patronum introduced object arguments form with **BREAKING CHANGES**. Please, review [migration guide](./MIGRATION.md) before upgrade from `v0.14.x` on your project. - -
- ---- - -## Condition - -[Method documentation & API](/src/condition) - -```ts -import { createEvent } from 'effector'; -import { condition } from 'patronum/condition'; - -const trigger = createEvent(); - -const longString = createEvent(); -const shortString = createEvent(); - -condition({ - source: trigger, - if: (string) => string.length > 6, - then: longString, - else: shortString, -}); - -longString.watch((str) => console.log('long', str)); -shortString.watch((str) => console.log('short', str)); - -trigger('hi'); // => short hi -trigger('welcome'); // => long welcome -``` - -[Try it](https://share.effector.dev/vGMekp9H 'in playground') - -## Delay - -[Method documentation & API](/src/delay) - -```ts -import { createEvent } from 'effector'; -import { delay } from 'patronum/delay'; - -const trigger = createEvent(); // createStore or createEffect - -// `timeout` also supports (payload) => number and Store -const delayed = delay({ source: trigger, timeout: 300 }); - -delayed.watch((payload) => console.info('triggered', payload)); - -trigger('hello'); -// after 300ms -// => triggered hello -``` - -[Try it](https://share.effector.dev/vWwXoL4n) - -## Debounce - -[Method documentation & API](/src/debounce) - -```ts -import { createEvent } from 'effector'; -import { debounce } from 'patronum/debounce'; - -// You should call this event -const trigger = createEvent(); - -const target = debounce({ source: trigger, timeout: 200 }); - -target.watch((payload) => console.info('debounced', payload)); - -trigger(1); -trigger(2); -trigger(3); -trigger(4); -// after 200ms -// => debounced 4 -``` - -[Try it](https://share.effector.dev/ZFXJbv1b) - -## Throttle - -[Method documentation & API](/src/throttle) - -```ts -import { createEvent } from 'effector'; -import { throttle } from 'patronum/throttle'; - -// You should call this event -const trigger = createEvent(); - -const target = throttle({ source: trigger, timeout: 200 }); - -target.watch((payload) => console.info('throttled', payload)); - -trigger(1); -trigger(2); -trigger(3); -trigger(4); -// 200ms after trigger(1) -// => throttled 4 -``` - -[Try it](https://share.effector.dev/OH0TUJUH) - -## Interval - -[Method documentation & API](/src/interval) - -```ts -import { createStore, createEvent } from 'effector'; -import { interval } from 'patronum'; - -const startCounter = createEvent(); -const stopCounter = createEvent(); -const $counter = createStore(0); - -const { tick } = interval({ - timeout: 500, - start: startCounter, - stop: stopCounter, -}); - -$counter.on(tick, (number) => number + 1); -$counter.watch((value) => console.log('COUNTER', value)); - -startCounter(); - -setTimeout(() => stopCounter(), 5000); -``` - -[Try it](https://share.effector.dev/EOVzc3df) - -## Debug - -[Method documentation & API](/src/debug) - -```ts -import { createStore, createEvent, createEffect } from 'effector'; -import { debug } from 'patronum/debug'; - -const event = createEvent(); -const effect = createEffect().use((payload) => Promise.resolve('result' + payload)); -const $store = createStore(0) - .on(event, (state, value) => state + value) - .on(effect.done, (state) => state * 10); - -debug($store, event, effect); - -event(5); -effect('demo'); - -// => [store] $store 1 -// => [event] event 5 -// => [store] $store 6 -// => [effect] effect demo -// => [effect] effect.done {"params":"demo", "result": "resultdemo"} -// => [store] $store 60 -``` - -[Try it](https://share.effector.dev/iFi3CahC) - -## Status - -[Method documentation & API](/src/status) - -```ts -import { createEvent, createEffect } from 'effector'; -import { status } from 'patronum/status'; - -const effect = createEffect().use(() => Promise.resolve(null)); -const $status = status({ effect }); - -$status.watch((value) => console.log(`status: ${value}`)); -// => status: "initial" - -effect(); -// => status: "pending" -// => status: "done" -``` - -[Try it](https://share.effector.dev/6VRR39iC) - -## Spread - -[Method documentation & API](/src/spread) - -```ts -import { createEvent, createStore } from 'effector'; -import { spread } from 'patronum/spread'; - -const trigger = createEvent<{ first: string; second: string }>(); - -const $first = createStore(''); -const $second = createStore(''); - -spread({ - source: trigger, - targets: { - first: $first, - second: $second, - }, -}); - -trigger({ first: 'Hello', second: 'World' }); - -$first.watch(console.log); // => Hello -$second.watch(console.log); // => World -``` - -[Try it](https://share.effector.dev/DmiLrYAC) - -## Snapshot - -[Method documentation & API](/src/snapshot) - -```ts -import { restore, createEvent } from 'effector'; -import { snapshot } from 'patronum/snapshot'; - -const changeText = createEvent(); -const createSnapshot = createEvent(); - -const $original = restore(changeText, 'Example'); - -const $snapshot = snapshot({ - source: $original, - clock: createSnapshot, -}); - -changeText('New text'); - -// $original -> Store with "New text" -// $snapshot -> Store with "Example" - -createSnapshot(); - -// $original -> Store with "New text" -// $snapshot -> Store with "New text" -``` +Patronum had 3 breaking changes: 1) from `0.14` to `0.100`, 2) from `0.100` to `0.110`, 3) from `0.110` to `1.0` -[Try it](https://share.effector.dev/HcsNyGfM) - -## CombineEvents - -[Method documentation & API](/src/combine-events) - -Call target event when all event from object/array is triggered - -```ts -import { createEvent } from 'effector'; -import { combineEvents } from 'patronum/combine-events'; - -const event1 = createEvent(); -const event2 = createEvent(); -const event3 = createEvent(); -const reset = createEvent(); - -const event = combineEvents({ - reset, - events: { - event1, - event2, - event3, - }, -}); - -event.watch((object) => console.log('triggered', object)); - -event1(true); // nothing -event2('demo'); // nothing -event3(5); // => triggered { event1: true, event2: "demo", event3: 5 } - -event1(true); // nothing -event2('demo'); // nothing -reset(); -event3(5); // nothing - -event1(true); // nothing -event2('demo'); // nothing -event3(5); // => triggered { event1: true, event2: "demo", event3: 5 } -``` - -[Try it](https://share.effector.dev/nzc276i0) - -## Every - -[Method documentation & API](/src/every) - -```ts -import { createStore } from 'effector'; -import { every } from 'patronum/every'; - -const $isPasswordCorrect = createStore(true); -const $isEmailCorrect = createStore(true); - -const $isFormCorrect = every([$isPasswordCorrect, $isEmailCorrect], true); - -$isFormCorrect.watch(console.log); // => true -``` - -[Try it](https://share.effector.dev/Q9ZZSXoZ) - -## InFlight - -[Method documentation & API](/src/in-flight) - -```ts -import { createEffect } from 'effector'; -import { inFlight } from 'patronum/in-flight'; - -const firstFx = createEffect().use(() => Promise.resolve(1)); -const secondFx = createEffect().use(() => Promise.resolve(2)); - -const $allInFlight = inFlight({ effects: [firstFx, secondFx] }); - -firstFx(); -secondFx(); -firstFx(); - -$allInFlight.watch(console.log); -// => 3 -// => 2 -// => 1 -// => 0 -``` - -[Try it](https://share.effector.dev/NYNJEbpH) - -## Pending - -[Method documentation & API](/src/pending) - -```ts -import { createEffect } from 'effector'; -import { pending } from 'patronum/pending'; - -const loadFirst = createEffect().use(() => Promise.resolve(null)); -const loadSecond = createEffect().use(() => Promise.resolve(2)); -const $processing = pending({ effects: [loadFirst, loadSecond] }); - -$processing.watch((processing) => console.info(`processing: ${processing}`)); -// => processing: false - -loadFirst(); -loadSecond(); -// => processing: true -// => processing: false -``` - -[Try it](https://share.effector.dev/TaxOi6nT) - -## Some - -[Method documentation & API](/src/some) - -```ts -import { createStore, restore, createEvent } from 'effector'; -import { some } from 'patronum/some'; - -const widthSet = createEvent(); -const $width = restore(widthSet, 820); -const $height = createStore(620); - -const $tooBig = some({ - predicate: (size) => size > 800, - stores: [$width, $height], -}); - -$tooBig.watch((big) => console.log('big', big)); // => big true - -widthSet(200); -// => big false -``` - -[Try it](https://share.effector.dev/NBxHl8xR) - -## Reshape - -[Method documentation & API](/src/reshape) - -```ts -import { createStore } from 'effector'; -import { reshape } from 'patronum/reshape'; - -const $original = createStore('Hello world'); - -const parts = reshape({ - source: $original, - shape: { - length: (string) => string.length, - first: (string) => string.split(' ')[0] || '', - second: (string) => string.split(' ')[1] || '', - }, -}); - -parts.length.watch(console.info); // 11 -parts.first.watch(console.log); // "Hello" -parts.second.watch(console.log); // "world" -``` - -[Try it](https://share.effector.dev/VbNg7nlV) - -## SplitMap - -[Method documentation & API](/src/split-map) - -```ts -import { createEvent } from 'effector'; -import { splitMap } from 'patronum/split-map'; - -type Action = - | { type: 'update'; content: string } - | { type: 'created'; value: number } - | { type: 'another' }; - -const serverActionReceived = createEvent(); - -const received = splitMap({ - source: serverActionReceived, - cases: { - update: (action) => (action.type === 'update' ? action.content : undefined), - created: (action) => (action.type === 'created' ? action.value : undefined), - }, -}); - -received.update.watch((payload) => - console.info('update received with content:', payload), -); -received.created.watch((payload) => console.info('created with value:', payload)); -received.__.watch((payload) => console.info('unknown action received:', payload)); - -serverActionReceived({ type: 'created', value: 1 }); -// => created with value: 1 - -serverActionReceived({ type: 'update', content: 'demo' }); -// => update received with content: "demo" - -serverActionReceived({ type: 'another' }); -// => unknown action received: { type: "another" } -``` - -[Try it](https://share.effector.dev/RRf57lK4) - -## Time - -[Method documentation & API](/src/time) - -```ts -import { createEvent } from 'effector'; -import { time } from 'patronum/time'; - -const readTime = createEvent(); -const $now = time({ clock: readTime }); - -$now.watch((now) => console.log('Now is:', now)); -// => Now is: 1636914286675 - -readTime(); -// => Now is: 1636914300691 -``` - -[Try it](https://share.effector.dev/BFlhNGvk) - -## Format - -[Method documentation & API](/src/format) - -```ts -import { createStore } from 'effector'; -import { format } from 'patronum'; - -const $firstName = createStore('John'); -const $lastName = createStore('Doe'); - -const $fullName = format`${$firstName} ${$lastName}`; -$fullName.watch(console.log); -// => John Doe -``` - -[Try it](https://share.effector.dev/IafeiFkF) - -## Reset - -[Method documentation & API](/src/reset) - -```ts -import { createEvent, createStore } from 'effector'; -import { reset } from 'patronum/reset'; - -const pageUnmounted = createEvent(); -const userSessionFinished = createEvent(); - -const $post = createStore(null); -const $comments = createStore([]); -const $draftComment = createStore(''); - -reset({ - clock: [pageUnmounted, userSessionFinished], - target: [$post, $comments, $draftComment], -}); -``` - -[Try it](https://share.effector.dev/06hpVftG) - -## And - -[Method documentation & API](/src/and) - -```ts -const $isAuthorized = createStore(true); -const $isAdmin = createStore(false); -const $orderFinished = createStore(true); - -const $showCancelButton = and($isAuthorized, $isAdmin, $orderFinished); -console.assert(false === $showCancelButton.getState()); -``` - -[Try it](https://share.effector.dev/YbahaYCO) - -## Empty - -[Method documentation & API](/src/empty) - -```ts -const $account = createStore(null); -const $anonymous = empty($account); -const $authorized = not($anonymous); - -console.assert(true === $anonymous.getState()); -console.assert(false === $authorized.getState()); -``` - -[Try it](https://share.effector.dev/aY8yRLP9) - -## Equals - -[Method documentation & API](/src/equals) - -```ts -const $first = createStore('foo bar'); -const $isEquals = equals($first, 'foo bar'); - -console.assert(true === $isEquals.getState()); -``` - -[Try it](https://share.effector.dev/UtAWVd9r) - -## Not - -[Method documentation & API](/src/not) - -```ts -const $isFinished = createStore(false); -const $stillGoingOn = not($isFinished); - -console.assert(true === $stillGoingOn.getState()); -``` - -[Try it](https://share.effector.dev/qpTZAzXC) - -## Or - -[Method documentation & API](/src/or) - -```ts -const $isAuthorized = createStore(true); -const $immediateOrder = createStore(false); -const $mocksForDemo = createStore(false); - -const $allowedToShow = or($isAuthorized, $immediateOrder, $mocksForDemo); -console.assert(true === $allowedToShow.getState()); -``` - -[Try it](https://share.effector.dev/H9cDYEp5) - -## Either - -[Method documentation & API](/src/either) - -```ts -const $showLatest = createStore(false); -const $latestTweets = createStore([]); -const $recommendedTweets = createStore([]); - -export const $tweets = either($showLatest, $latestTweets, $recommendedTweets); -``` - -[Try it](https://share.effector.dev/NGmPTxSG) +We have [migration guide](./migration-guide.md). # Development @@ -877,7 +103,3 @@ You can review [CONTRIBUTING.md](./CONTRIBUTING.md) 1. Update labels for PRs and titles, next [manually run the release drafter action](https://github.com/effector/patronum/actions/workflows/release-drafter.yml) to regenerate the draft release. 1. Review the new version and press "Publish" 1. If required check "Create discussion for this release" - -``` - -``` diff --git a/MIGRATION.md b/website/src/pages/docs/migration-guide.md similarity index 79% rename from MIGRATION.md rename to website/src/pages/docs/migration-guide.md index 56b862fe..a8ed0254 100644 --- a/MIGRATION.md +++ b/website/src/pages/docs/migration-guide.md @@ -1,11 +1,24 @@ -# Migration guide from `v0.14+` +# Migration guide -```shell -npm install patronum@next -``` +### v1.0.0 + +Removed support of effector v21. Now the minimum supported version is `v22.1.2`. +No breaking changes in code. + +### v0.110 + +From `v0.110.0` patronum removed support of effector v20. Now minimum supported version is `v21.4`. + +Please, before upgrade review release notes of [`effector v21`](https://github.com/effector/effector/releases/tag/effector%4021.0.0). + +### v0.100 + +From `v0.100.0` patronum introduced object arguments form with **BREAKING CHANGES**. ```shell -yarn add patronum@next +npm install patronum@0.14.3 +# or +yarn add patronum@0.14.3 ```
@@ -15,20 +28,20 @@ yarn add patronum@next import { throttle } from 'patronum/throttle'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts const throttled = throttle(source, timeout); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts const throttled = throttle({ source, timeout }); // Also you can set target -const throttled = createEvent(); // or any unit -throttle({ source, timeout, target: throttled }); +const throttled2 = createEvent(); // or any unit +throttle({ source, timeout, target: throttled2 }); ``` - Wrap `source` and `timeout` arguments to object @@ -45,13 +58,13 @@ https://github.com/sergeysova/patronum/pull/31 import { debounce } from 'patronum/debounce'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts const debounced = debounce(source, timeout); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts const debounced = debounce({ source, timeout }); @@ -75,7 +88,7 @@ https://github.com/sergeysova/patronum/pull/38 import { splitMap } from 'patronum/split-map'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts const received = splitMap(nameReceived, { @@ -84,7 +97,7 @@ const received = splitMap(nameReceived, { }); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts const received = splitMap({ @@ -92,7 +105,8 @@ const received = splitMap({ cases: { firstName: (string) => string.split(' ')[0], // string | undefined lastName: (string) => string.split(' ')[1], // string | undefined - }); + }, +}); ``` - First argument should be `source` @@ -109,13 +123,13 @@ https://github.com/sergeysova/patronum/pull/41 import { some } from 'patronum/some'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts const $tooBig = some((size) => size > 800, [$width, $height]); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts const $tooBig = some({ @@ -138,14 +152,14 @@ https://github.com/sergeysova/patronum/pull/43 import { every } from 'patronum/every'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts const $result = every(true, [$a, $b, $c]); const $result = every(() => true, [$a, $b, $c]); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts const $result = every({ predicate: true, stores: [$a, $b, $c] }); @@ -166,14 +180,14 @@ https://github.com/sergeysova/patronum/pull/50 import { delay } from 'patronum/delay'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts const delayed = delay(unit, 100); const logDelayed = delay(unit, { time: (payload) => 100 }); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts const delayed = delay({ @@ -208,13 +222,13 @@ https://github.com/sergeysova/patronum/pull/51 import { status } from 'patronum/status'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts const $status = status(effect, 'initial'); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts const $status = status({ effect, defaultValue: 'initial' }); @@ -234,7 +248,7 @@ https://github.com/sergeysova/patronum/pull/55 import { reshape } from 'patronum/reshape'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts const parts = reshape($original, { @@ -244,7 +258,7 @@ const parts = reshape($original, { }); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts const parts = reshape({ @@ -271,7 +285,7 @@ https://github.com/sergeysova/patronum/pull/57 import { combineEvents } from 'patronum/combine-events'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts const target = combineEvents([first, second, third]); @@ -281,7 +295,7 @@ const target = combineEvents({ }); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts const target = combineEvents({ events: [first, second, third] }); @@ -306,7 +320,7 @@ https://github.com/sergeysova/patronum/pull/58 import { spread } from 'patronum/spread'; ``` -### Previous version `v0.14.x` +#### Previous version `v0.14.x` ```ts spread(formReceived, { @@ -320,7 +334,7 @@ const source = spread({ }); ``` -### Current version `v0.102.x` +#### Current version `v0.102.x` ```ts spread({ @@ -340,10 +354,13 @@ const source = spread({ ``` 1. If you have two arguments: - - First argument should be `source` in object - - Second argument should be `targets` + +- First argument should be `source` in object +- Second argument should be `targets` + 1. If only one argument: - - Wrap it to object and assign to `targets` + +- Wrap it to object and assign to `targets` https://github.com/sergeysova/patronum/pull/61