From 532d522931637ed4cd7c0182bf3641a24cbedd06 Mon Sep 17 00:00:00 2001 From: Sergey Sova Date: Thu, 3 Feb 2022 18:34:57 +0300 Subject: [PATCH] feat(every): add short form --- README.md | 7 +-- src/every/every.fork.test.ts | 26 +++++++++ src/every/every.test.ts | 104 +++++++++++++++++++++++++++++++++++ src/every/index.ts | 35 +++++++++--- src/every/readme.md | 15 +++++ test-typings/every.ts | 27 +++++++++ 6 files changed, 201 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ac4281de..e303ddac 100644 --- a/README.md +++ b/README.md @@ -367,7 +367,7 @@ event3(5); // => triggered { event1: true, event2: "demo", event3: 5 } event1(true); // nothing event2('demo'); // nothing reset(); -event3(5) // nothing +event3(5); // nothing event1(true); // nothing event2('demo'); // nothing @@ -387,10 +387,7 @@ import { every } from 'patronum/every'; const $isPasswordCorrect = createStore(true); const $isEmailCorrect = createStore(true); -const $isFormCorrect = every({ - predicate: true, - stores: [$isPasswordCorrect, $isEmailCorrect], -}); +const $isFormCorrect = every([$isPasswordCorrect, $isEmailCorrect], true); $isFormCorrect.watch(console.log); // => true ``` diff --git a/src/every/every.fork.test.ts b/src/every/every.fork.test.ts index 3efb33c8..0be1f2c8 100644 --- a/src/every/every.fork.test.ts +++ b/src/every/every.fork.test.ts @@ -138,3 +138,29 @@ test('allow predicate to use store', async () => { await allSettled(setSource, { scope, params: false }); expect(scope.getState($result)).toBeFalsy(); }); + +test('allow predicate to use store in short form', async () => { + const setSource = createEvent(); + const setPredicate = createEvent(); + + const $predicate = createStore(false).on(setPredicate, (_, value) => value); + + const $first = createStore(true); + const $second = createStore(false).on(setSource, (_, value) => value); + const $third = createStore(true); + + const $result = every([$first, $second, $third], $predicate); + + const scope = fork(); + + expect(scope.getState($result)).toBeFalsy(); + + await allSettled(setSource, { scope, params: true }); + expect(scope.getState($result)).toBeFalsy(); + + await allSettled(setPredicate, { scope, params: true }); + expect(scope.getState($result)).toBeTruthy(); + + await allSettled(setSource, { scope, params: false }); + expect(scope.getState($result)).toBeFalsy(); +}); diff --git a/src/every/every.test.ts b/src/every/every.test.ts index 12b5a11f..a2109b0b 100644 --- a/src/every/every.test.ts +++ b/src/every/every.test.ts @@ -109,3 +109,107 @@ test('allow predicate to use store', () => { setSource(false); expect($result.getState()).toBeFalsy(); }); + +describe('short', () => { + test('boolean predicate', () => { + const fn = jest.fn(); + const change = createEvent(); + + const $first = createStore(true); + const $second = createStore(false).on(change, () => true); + const $third = createStore(true); + + const $result = every([$first, $second, $third], true); + + $result.watch(fn); + expect(fn).toHaveBeenCalledWith(false); + + change(); + expect(argumentHistory(fn)).toMatchInlineSnapshot(` + Array [ + false, + true, + ] + `); + }); + + test('number predicate', () => { + const fn = jest.fn(); + const change = createEvent(); + + const $first = createStore(4); + const $second = createStore(2).on(change, () => 4); + const $third = createStore(4); + + const $result = every([$first, $second, $third], 4); + + $result.watch(fn); + expect(fn).toHaveBeenCalledWith(false); + + change(); + expect(argumentHistory(fn)).toMatchInlineSnapshot(` + Array [ + false, + true, + ] + `); + }); + + test('function predicate', () => { + const fn = jest.fn(); + const change = createEvent(); + + const $first = createStore(10); + const $second = createStore(0).on(change, () => 5); + const $third = createStore(3); + + const $result = every([$first, $second, $third], (value) => value > 0); + + $result.watch(fn); + expect(fn).toHaveBeenCalledWith(false); + + change(); + expect(argumentHistory(fn)).toMatchInlineSnapshot(` + Array [ + false, + true, + ] + `); + }); + + test('initially true', () => { + const fn = jest.fn(); + + const $first = createStore(10); + const $second = createStore(2); + const $third = createStore(3); + + const $result = every([$first, $second, $third], (value) => value > 0); + + $result.watch(fn); + expect(fn).toHaveBeenCalledWith(true); + }); + + test('allow predicate to use store', () => { + const setSource = createEvent(); + const setPredicate = createEvent(); + + const $predicate = createStore(false).on(setPredicate, (_, value) => value); + + const $first = createStore(true); + const $second = createStore(false).on(setSource, (_, value) => value); + const $third = createStore(true); + + const $result = every([$first, $second, $third], $predicate); + expect($result.getState()).toBeFalsy(); + + setSource(true); + expect($result.getState()).toBeFalsy(); + + setPredicate(true); + expect($result.getState()).toBeTruthy(); + + setSource(false); + expect($result.getState()).toBeFalsy(); + }); +}); diff --git a/src/every/index.ts b/src/every/index.ts index 042b284f..73eb2060 100644 --- a/src/every/index.ts +++ b/src/every/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import { combine, is, Store } from 'effector'; export function every(_: { @@ -20,13 +21,32 @@ export function every(_: { stores: Array>; }): Store; -export function every({ - predicate, - stores, -}: { - predicate: T | ((value: T) => boolean) | Store; - stores: Array>; -}): Store { +export function every(stores: Store[], predicate: Store): Store; +export function every(stores: Store[], predicate: T): Store; +export function every( + stores: Store[], + predicate: (value: T) => boolean, +): Store; + +export function every( + configOrStores: + | { + predicate: T | ((value: T) => boolean) | Store; + stores: Array>; + } + | Store[], + predicateOrNone?: Store | T | ((value: T) => boolean), +): Store { + let stores: Store[] = []; + let predicate: Store | T | ((value: T) => boolean) = () => false; + if (Array.isArray(configOrStores)) { + stores = configOrStores; + predicate = predicateOrNone!; + } else if (Array.isArray(configOrStores.stores)) { + stores = configOrStores.stores; + predicate = configOrStores.predicate; + } + let checker; if (isFunction(predicate)) { checker = predicate; @@ -43,7 +63,6 @@ export function every({ return combine($checker, $values, (checker, values) => values.every(checker)); } -// eslint-disable-next-line @typescript-eslint/no-unused-vars function isFunction(value: unknown): value is (value: T) => boolean { return typeof value === 'function'; } diff --git a/src/every/readme.md b/src/every/readme.md index 58a129d7..588e72f8 100644 --- a/src/every/readme.md +++ b/src/every/readme.md @@ -121,3 +121,18 @@ const $isFormCorrect = every({ console.assert(true === $isFormCorrect.getState()); ``` + +## Shorthands + +```ts +$result = every(stores, value); +$result = every(stores, (value) => false); +$result = every(stores, $predicate); +``` + +Shorthand have the same rules as the main overrides, just it uses positional arguments instead of object-form. + +### Arguments + +1. `stores` _(`Array>`)_ — List of stores to compare with predicate in the second argument +2. `predicate` _(`Store | (value: T) => boolean | T`)_ — Predicate to compare with diff --git a/test-typings/every.ts b/test-typings/every.ts index 9656e833..edb213e8 100644 --- a/test-typings/every.ts +++ b/test-typings/every.ts @@ -69,3 +69,30 @@ import { every } from '../src/every'; // @ts-expect-error expectType>(every({ predicate: $invalid3, stores: [$a, $b] })); } + +// Short +{ + const predicate = (value: number) => value > 0; + const $predicate = createStore(0); + const $a = createStore(0); + const $b = createStore(1); + const $invalid1 = createStore(''); + const $invalid2 = createStore(true); + const $invalid3 = createStore({}); + + expectType>(every([$a, $b], 0)); + // @ts-expect-error + every([$a, $invalid1], 0); + + expectType>(every([$a, $b], predicate)); + // @ts-expect-error + every([$a, $invalid1], predicate); + + expectType>(every([$a, $b], $predicate)); + // @ts-expect-error + expectType>(every([$a, $b], $invalid1)); + // @ts-expect-error + expectType>(every([$a, $b], $invalid2)); + // @ts-expect-error + expectType>(every([$a, $b], $invalid3)); +}