From 4a14ac99bee4b1e1babc91fffb88772eb47552ce Mon Sep 17 00:00:00 2001 From: PabloSzx Date: Tue, 24 Mar 2020 18:59:32 -0300 Subject: [PATCH 1/8] localStorage plugin & update dependencies --- package.json | 60 +- src/common.ts | 2 + src/createStore.ts | 44 +- src/plugins/localStorage.ts | 56 + stories/createStore/asyncActions.stories.tsx | 10 +- stories/createStore/basicUsage.stories.tsx | 4 +- .../createStore/createSelector.stories.tsx | 16 +- stories/createStore/multipleProps.stories.tsx | 2 +- .../asyncActionsContext.stories.tsx | 10 +- .../basicUsageContext.stories.tsx | 4 +- stories/devTools/createStore.stories.tsx | 4 +- .../devTools/createStoreContext.stories.tsx | 4 +- test/createStore.test.tsx | 1580 +++++++------- test/createStoreContext.test.tsx | 1844 ++++++++--------- test/devTools.test.tsx | 16 +- test/utils/useRenderCount.ts | 26 +- yarn.lock | 1586 ++++++++++---- 17 files changed, 3047 insertions(+), 2221 deletions(-) create mode 100644 src/plugins/localStorage.ts diff --git a/package.json b/package.json index f25fa8a..0b5c3fd 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ }, "husky": { "hooks": { - "pre-commit": "tsdx lint src stories test" + "pre-commit": "tsdx lint --fix src stories test" } }, "jest": { @@ -38,54 +38,56 @@ "coverageDirectory": "./coverage/" }, "resolutions": { - "@types/react": "16.9.23" + "@types/react": "16.9.25", + "prettier": "^2.0.2" }, "dependencies": { - "immer": "^6.0.1", + "immer": "^6.0.2", "reselect": "^4.0.0" }, "devDependencies": { - "@babel/core": "^7.8.6", - "@storybook/addon-actions": "^5.3.14", - "@storybook/addon-docs": "^5.3.14", - "@storybook/addon-info": "^5.3.14", - "@storybook/addon-links": "^5.3.14", - "@storybook/addon-storysource": "^5.3.14", - "@storybook/addons": "^5.3.14", - "@storybook/core": "^5.3.14", - "@storybook/preset-create-react-app": "^2.0.0", - "@storybook/react": "^5.3.14", + "@babel/core": "^7.9.0", + "@storybook/addon-actions": "^5.3.17", + "@storybook/addon-docs": "^5.3.17", + "@storybook/addon-info": "^5.3.17", + "@storybook/addon-links": "^5.3.17", + "@storybook/addon-storysource": "^5.3.17", + "@storybook/addons": "^5.3.17", + "@storybook/core": "^5.3.17", + "@storybook/preset-create-react-app": "^2.1.0", + "@storybook/react": "^5.3.17", "@testing-library/jest-dom": "^5.1.1", - "@testing-library/react": "^9.4.1", + "@testing-library/react": "^10.0.1", "@testing-library/react-hooks": "^3.2.1", "@types/babel__core": "^7.1.6", - "@types/jest": "^25.1.3", - "@types/react": "^16.9.23", + "@types/jest": "^25.1.4", + "@types/react": "^16.9.25", "@types/react-dom": "^16.9.5", "@types/react-is": "^16.7.1", "@types/react-test-renderer": "^16.9.2", "@types/storybook__addon-info": "^5.2.1", - "@types/testing-library__jest-dom": "^5.0.1", - "@types/testing-library__react": "^9.1.2", + "@types/testing-library__jest-dom": "^5.0.2", + "@types/testing-library__react": "^9.1.3", "@types/testing-library__react-hooks": "^3.2.0", - "@types/webpack": "^4.41.7", - "babel-loader": "^8.0.6", + "@types/webpack": "^4.41.8", + "babel-loader": "^8.1.0", "husky": "^4.2.3", + "prettier": "^2.0.2", "react": "^16.13.0", "react-docgen-typescript-loader": "^3.7.1", - "react-dom": "^16.13.0", - "react-is": "^16.13.0", - "react-scripts": "^3.4.0", - "react-state-selector": "^1.0.0", - "react-test-renderer": "^16.13.0", - "regenerator-runtime": "^0.13.3", - "ts-loader": "^6.2.1", - "tsdx": "^0.12.3", + "react-dom": "^16.13.1", + "react-is": "^16.13.1", + "react-scripts": "^3.4.1", + "react-state-selector": "^1.0.1", + "react-test-renderer": "^16.13.1", + "regenerator-runtime": "^0.13.5", + "ts-loader": "^6.2.2", + "tsdx": "^0.13.0", "tslib": "^1.11.1", "typescript": "^3.8.3", "use-context-selector": "^1.1.0", "wait-for-expect": "^3.0.2", - "webpack": "^4.41.6" + "webpack": "^4.42.1" }, "peerDependencies": { "react": ">=16.8" diff --git a/src/common.ts b/src/common.ts index 680a7cd..0fff97a 100644 --- a/src/common.ts +++ b/src/common.ts @@ -32,6 +32,8 @@ export const useUpdate = () => { return useCallback(() => setState(incrementParameter), emptyArray); }; +export const isClientSide = typeof window !== "undefined"; + type NN = NonNullable; export type IProduce = ( diff --git a/src/createStore.ts b/src/createStore.ts index a105d08..0eb84e6 100644 --- a/src/createStore.ts +++ b/src/createStore.ts @@ -24,6 +24,7 @@ import { IHooks, IHooksObj, IProduce, + isClientSide, IUseStore, Selector, toAnonFunction, @@ -31,6 +32,10 @@ import { useUpdate, } from "./common"; import { connectDevTools, ReduxDevTools } from "./plugins/devTools"; +import { + connectLocalStorage, + LocalStoragePlugin, +} from "./plugins/localStorage"; export { createSelector } from "reselect"; export { @@ -113,6 +118,12 @@ export function createStore< * @type {boolean} */ devToolsInProduction?: boolean; + /** + * Flag to activate localStorage persistence method + * + * @type {boolean} + */ + localStoragePersistence?: boolean; } ): { /** @@ -176,6 +187,7 @@ export function createStore< } let devTools: ReduxDevTools | undefined; + let localStoragePlugin: LocalStoragePlugin | undefined; if ( options?.devName && @@ -216,7 +228,7 @@ export function createStore< produce: IProduce; asyncProduce: IAsyncProduce; } = { - produce: draft => { + produce: (draft) => { if (typeof draft !== "function") return currentStore; if (devTools) { @@ -245,20 +257,23 @@ export function createStore< currentStore = produceFn(currentStore); } + listeners.forEach((props, listener) => { listener(currentStore, props); }); + localStoragePlugin?.setState(currentStore as TStore); + return currentStore; }, - asyncProduce: async draft => { + asyncProduce: async (draft) => { if (typeof draft !== "function") return currentStore; const storeDraft = createDraft(currentStore as TStore); await Promise.resolve(draft(storeDraft)); - finishDraft(storeDraft, changes => { + finishDraft(storeDraft, (changes) => { if (changes.length) { currentStore = applyPatches(currentStore, changes); @@ -275,10 +290,28 @@ export function createStore< } }); + localStoragePlugin?.setState(currentStore as TStore); + return currentStore; }, }; + if (options?.localStoragePersistence && options.devName) { + if (typeof initialStore !== "object") { + throw new Error( + "For local storage persistence your store has to be an object" + ); + } + localStoragePlugin = connectLocalStorage( + options.devName, + initialStore as TStore, + produceObj.produce + ); + if (isClientSide) { + localStoragePlugin.getState(); + } + } + const actionsObj: Record< string, (...args: unknown[]) => Immutable @@ -325,6 +358,8 @@ export function createStore< listener(currentStore, props); }); + localStoragePlugin?.setState(currentStore as TStore); + return currentStore; }; } @@ -335,6 +370,7 @@ export function createStore< asyncActionsObj[actionName] = async (...args) => { await actionFn(produceObj.produce)(...args); + localStoragePlugin?.setState(currentStore as TStore); return currentStore; }; } @@ -363,7 +399,7 @@ export function createStore< const { updateSelector, initialStateRef } = useMemo(() => { return { - updateSelector: createSelector(hookSelector, result => { + updateSelector: createSelector(hookSelector, (result) => { stateRef.current = result; if (!isMountedRef.current) { diff --git a/src/plugins/localStorage.ts b/src/plugins/localStorage.ts new file mode 100644 index 0000000..06b66c0 --- /dev/null +++ b/src/plugins/localStorage.ts @@ -0,0 +1,56 @@ +import { Immutable } from "immer"; + +import { IProduce, isClientSide } from "../common"; + +export type LocalStoragePlugin = { + getState: () => Immutable; + setState: (state: T) => void; +}; + +export const connectLocalStorage = ( + persistenceName: string, + defaultInitialState: T, + produce: IProduce, + wait = 3000, + persistenceMethod = isClientSide ? window.localStorage : undefined +): LocalStoragePlugin => { + let isConnected = false; + let timeout: NodeJS.Timeout | undefined; + + const setStateFn = (state: T) => { + if (persistenceMethod) { + persistenceMethod.setItem(persistenceName, JSON.stringify(state)); + if (!isConnected) isConnected = true; + } + }; + + const setState = (state: T) => { + const execLater = () => { + timeout = undefined; + setStateFn(state); + }; + if (timeout !== undefined) clearTimeout(timeout); + timeout = setTimeout(execLater, wait); + }; + + return { + getState: () => { + if (isConnected) return produce(); + + try { + const state = persistenceMethod?.getItem(persistenceName); + + if (state != null) { + const connectedState = produce(() => ({ + ...produce(), + ...JSON.parse(state), + })); + isConnected = true; + return connectedState; + } + } catch (err) {} + return defaultInitialState as Immutable; + }, + setState, + }; +}; diff --git a/stories/createStore/asyncActions.stories.tsx b/stories/createStore/asyncActions.stories.tsx index a1c5de2..2e35392 100644 --- a/stories/createStore/asyncActions.stories.tsx +++ b/stories/createStore/asyncActions.stories.tsx @@ -30,9 +30,9 @@ const initialState: IPosts = { const Store = createStore(initialState, { asyncActions: { - getPosts: produce => async () => { + getPosts: (produce) => async () => { try { - produce(draft => { + produce((draft) => { draft.state = FetchState.loading; }); @@ -40,12 +40,12 @@ const Store = createStore(initialState, { await fetch("https://jsonplaceholder.typicode.com/posts") ).json(); - produce(draft => { + produce((draft) => { draft.posts = data; draft.state = FetchState.complete; }); } catch (err) { - produce(draft => { + produce((draft) => { draft.state = FetchState.error; draft.fetchError = JSON.stringify(err); }); @@ -86,7 +86,7 @@ export const AsyncActions = () => { Get Data
    - {posts?.slice(0, 10).map(value => { + {posts?.slice(0, 10).map((value) => { return (
  1. {value.title}

    diff --git a/stories/createStore/basicUsage.stories.tsx b/stories/createStore/basicUsage.stories.tsx index 6d7e287..533d46c 100644 --- a/stories/createStore/basicUsage.stories.tsx +++ b/stories/createStore/basicUsage.stories.tsx @@ -29,10 +29,10 @@ const { }, }, actions: { - incrementA: (n: number) => draft => { + incrementA: (n: number) => (draft) => { draft.a += n; }, - incrementB: (n: number) => draft => { + incrementB: (n: number) => (draft) => { draft.b += n; }, }, diff --git a/stories/createStore/createSelector.stories.tsx b/stories/createStore/createSelector.stories.tsx index c0d90fe..6282bda 100644 --- a/stories/createStore/createSelector.stories.tsx +++ b/stories/createStore/createSelector.stories.tsx @@ -20,17 +20,17 @@ const Store = createStore( * in the store due to that in every call * the "map" function is giving a new array. */ - useMultiply2DataWithoutSelector: state => { - return state.data.map(n => n * 2); + useMultiply2DataWithoutSelector: (state) => { + return state.data.map((n) => n * 2); }, /** * This hook is only going to be listening to changes * to "data" inside the store */ useMultiply2Data: createSelector( - state => state.data, - data => { - return data.map(n => n * 2); + (state) => state.data, + (data) => { + return data.map((n) => n * 2); } ), /** @@ -44,15 +44,15 @@ const Store = createStore( (state: Immutable, _n: number) => state.data, (_state, nMultiply) => nMultiply, (data, nMultiply) => { - return data.map(n => nMultiply * n); + return data.map((n) => nMultiply * n); } ), }, actions: { - newData: () => draft => { + newData: () => (draft) => { draft.data = genData(); }, - newN: () => draft => { + newN: () => (draft) => { draft.n = Math.round(Math.random() * 10000); }, }, diff --git a/stories/createStore/multipleProps.stories.tsx b/stories/createStore/multipleProps.stories.tsx index 2768f55..2b32ac5 100644 --- a/stories/createStore/multipleProps.stories.tsx +++ b/stories/createStore/multipleProps.stories.tsx @@ -25,7 +25,7 @@ const Store = createStore( */ useGetElement: (state, arg: { color: string; n: number }) => { return state.data.find( - value => value.color === arg.color || value.n === arg.n + (value) => value.color === arg.color || value.n === arg.n ); }, }, diff --git a/stories/createStoreContext/asyncActionsContext.stories.tsx b/stories/createStoreContext/asyncActionsContext.stories.tsx index efee15f..d1a402f 100644 --- a/stories/createStoreContext/asyncActionsContext.stories.tsx +++ b/stories/createStoreContext/asyncActionsContext.stories.tsx @@ -30,9 +30,9 @@ const initialState: IPosts = { const Store = createStoreContext(initialState, { asyncActions: { - getPosts: produce => async () => { + getPosts: (produce) => async () => { try { - produce(draft => { + produce((draft) => { draft.state = FetchState.loading; }); @@ -40,12 +40,12 @@ const Store = createStoreContext(initialState, { await fetch("https://jsonplaceholder.typicode.com/posts") ).json(); - produce(draft => { + produce((draft) => { draft.posts = data; draft.state = FetchState.complete; }); } catch (err) { - produce(draft => { + produce((draft) => { draft.state = FetchState.error; draft.fetchError = JSON.stringify(err); }); @@ -87,7 +87,7 @@ export const AsyncActionsContext = () => { Get Data
      - {posts?.slice(0, 10).map(value => { + {posts?.slice(0, 10).map((value) => { return (
    1. {value.title}

      diff --git a/stories/createStoreContext/basicUsageContext.stories.tsx b/stories/createStoreContext/basicUsageContext.stories.tsx index f1e9967..41515bb 100644 --- a/stories/createStoreContext/basicUsageContext.stories.tsx +++ b/stories/createStoreContext/basicUsageContext.stories.tsx @@ -30,10 +30,10 @@ const { }, }, actions: { - incrementA: (n: number) => draft => { + incrementA: (n: number) => (draft) => { draft.a += n; }, - incrementB: (n: number) => draft => { + incrementB: (n: number) => (draft) => { draft.b += n; }, }, diff --git a/stories/devTools/createStore.stories.tsx b/stories/devTools/createStore.stories.tsx index 28fd439..e662c14 100644 --- a/stories/devTools/createStore.stories.tsx +++ b/stories/devTools/createStore.stories.tsx @@ -32,10 +32,10 @@ const { }, }, actions: { - incrementA: (n: number) => draft => { + incrementA: (n: number) => (draft) => { draft.a += n; }, - incrementB: (n: number) => draft => { + incrementB: (n: number) => (draft) => { draft.b += n; }, }, diff --git a/stories/devTools/createStoreContext.stories.tsx b/stories/devTools/createStoreContext.stories.tsx index af77a74..889615a 100644 --- a/stories/devTools/createStoreContext.stories.tsx +++ b/stories/devTools/createStoreContext.stories.tsx @@ -33,10 +33,10 @@ const { }, }, actions: { - incrementA: (n: number) => draft => { + incrementA: (n: number) => (draft) => { draft.a += n; }, - incrementB: (n: number) => draft => { + incrementB: (n: number) => (draft) => { draft.b += n; }, }, diff --git a/test/createStore.test.tsx b/test/createStore.test.tsx index 8b0e240..5cd3717 100644 --- a/test/createStore.test.tsx +++ b/test/createStore.test.tsx @@ -1,790 +1,790 @@ -/* eslint react-hooks/exhaustive-deps: 0 */ - -import { enableMapSet } from "immer"; -import React, { FC, useLayoutEffect } from "react"; -import waitForExpect from "wait-for-expect"; - -import { act, cleanup, render } from "@testing-library/react"; - -import { createSelector, createStore } from "../src"; -import { nRenderString, useRenderCount } from "./utils/useRenderCount"; - -enableMapSet(); -afterEach(cleanup); - -describe("basic createStore", () => { - const initialStore = Object.freeze({ - a: 5, - b: -5, - }); - - it("useStore works", () => { - const { useStore } = createStore(initialStore); - - const UseStoreComponent: FC = () => { - const store = useStore(); - return {store.a}; - }; - - const { getByText } = render(); - - const comp = getByText(initialStore.a.toString()); - - expect(comp).toBeTruthy(); - }); - - it("produce works with useStore", () => { - const { useStore, produce } = createStore(initialStore); - - const n = 5; - - const ProduceComponent: FC = () => { - const store = useStore(); - - useLayoutEffect(() => { - act(() => { - produce(draft => { - draft.a += n; - }); - }); - }, []); - - return {store.a}; - }; - - const { getByText } = render(); - - const comp = getByText((initialStore.a + n).toString()); - - expect(comp).toBeTruthy(); - }); - - it("asyncProduce works with useStore", async () => { - const { useStore, asyncProduce } = createStore(initialStore); - - const n = 5; - - const AsyncProduceComponent: FC = () => { - const store = useStore(); - - return ( - <> - - {store.a} - - ); - }; - - const { getByTestId, container } = render(); - - expect(container.innerHTML).toContain(initialStore.a); - - getByTestId("button").click(); - - await waitForExpect( - async () => { - expect(container.innerHTML).toContain(initialStore.a + n); - }, - 2000, - 250 - ); - }); - - it("asyncProduce works as getter", () => { - const { asyncProduce, produce } = createStore({ a: 1 }); - - expect(produce()).toEqual({ a: 1 }); - - expect(asyncProduce()).resolves.toEqual({ a: 1 }); - - expect(asyncProduce(async () => {})).resolves.toEqual({ a: 1 }); - }); -}); - -describe("actions", () => { - it("defined actions work", () => { - const initialStore = Object.freeze({ - a: 1, - }); - const { actions, useStore } = createStore(initialStore, { - actions: { - increment: (n: number) => draft => { - draft.a += n; - }, - decrement: (n: number) => draft => { - draft.a -= n; - }, - }, - }); - - const n = 5; - - const ActionsComp: FC = () => { - const { a } = useStore(); - - return ( -
      -
      - ); - }; - - const { container, getByTestId } = render(); - - const IncrementButton = getByTestId("increment"); - const DecrementButton = getByTestId("decrement"); - - expect(container.innerHTML).toContain(initialStore.a); - - act(() => { - IncrementButton.click(); - }); - - expect(container.innerHTML).toContain(initialStore.a + n /* 6 */); - - act(() => { - DecrementButton.click(); - DecrementButton.click(); - }); - - expect(container.innerHTML).toContain(initialStore.a + n - n * 2 /* -4 */); - }); - - enum AsyncState { - waiting, - loading, - error, - complete, - } - - it("async actions work", async () => { - const initialStore = Object.freeze({ - a: 1, - state: AsyncState.waiting, - }); - - const Store = createStore(initialStore, { - hooks: {}, - asyncActions: { - asyncIncrement: produce => async (n: number) => { - produce(draft => { - draft.state = AsyncState.loading; - }); - await new Promise(resolve => setTimeout(resolve, 500)); - produce(draft => { - draft.state = AsyncState.complete; - draft.a += n; - }); - }, - }, - actions: { - increment: (n: number) => draft => { - draft.a += n; - }, - }, - }); - - expect(Store.produce()).toBe(initialStore); - - const inc = Store.actions.increment(20); - - expect(inc).toEqual({ a: 21, state: AsyncState.waiting }); - - const promiseIncrement = expect( - Store.actions.asyncIncrement(10) - ).resolves.toEqual({ - a: 31, - state: AsyncState.complete, - }); - - expect(Store.produce()).toEqual({ a: 21, state: AsyncState.loading }); - - await promiseIncrement; - - expect(Store.produce()).toEqual({ - a: 31, - state: AsyncState.complete, - }); - }); - - it("async actions handle errors", async () => { - const initialStore = Object.freeze({ - a: 1, - state: AsyncState.waiting, - }); - - const SampleError = new Error("test error"); - - const Store = createStore(initialStore, { - hooks: {}, - asyncActions: { - asyncError: produce => async (_n: number) => { - await new Promise((_resolve, reject) => { - produce(draft => { - draft.state = AsyncState.loading; - }); - setTimeout(() => { - produce(draft => { - draft.state = AsyncState.error; - }); - reject(SampleError); - }, 500); - }); - }, - }, - }); - - expect(Store.produce().state).toBe(AsyncState.waiting); - const rejectPromise = expect(Store.actions.asyncError(10)).rejects.toBe( - SampleError - ); - expect(Store.produce().state).toBe(AsyncState.loading); - await rejectPromise; - expect(Store.produce().state).toBe(AsyncState.error); - }); - - it("should detect the same name on actions and asyncActions", () => { - expect(() => { - createStore( - {}, - { - actions: { - sameName: () => () => {}, - }, - asyncActions: { - sameName: () => async () => {}, - }, - } - ); - }).toThrowError( - 'All the actions and asyncActions should have different names and "sameName" exists in both objects!' - ); - }); - - it("should ignore the same name on actions and asyncActions in production", () => { - expect(() => { - const beforeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = "production"; - createStore( - {}, - { - actions: { - sameName: () => () => {}, - }, - asyncActions: { - sameName: () => async () => {}, - }, - } - ); - process.env.NODE_ENV = beforeEnv; - }).not.toThrow(); - }); -}); - -describe("selectors and listeners", () => { - it("basic number object and individual selectors", () => { - const initialStore = Object.freeze({ - a: 1, - b: 2, - c: 3, - }); - - const { - hooks: { useA, useB, useC }, - } = createStore(initialStore, { - hooks: { - useA: store => store.a, - useB: store => store.b, - useC: store => store.c, - }, - actions: {}, - }); - - const AComp: FC = () => { - const n = useA(); - - return {n}; - }; - const BComp: FC = () => { - const n = useB(); - - return {n}; - }; - const CComp: FC = () => { - const n = useC(); - - return {n}; - }; - - const aComp = render(); - const bComp = render(); - const cComp = render(); - - expect(aComp.container.textContent).toBe(initialStore.a.toString()); - expect(bComp.container.textContent).toBe(initialStore.b.toString()); - expect(cComp.container.textContent).toBe(initialStore.c.toString()); - }); - - it("selectors accept plain props", () => { - const initialStore = Object.freeze({ - a: 1, - }); - const { - hooks: { useATimesN }, - } = createStore(initialStore, { - hooks: { - useATimesN: (store, n: number) => { - return store.a * n; - }, - }, - }); - const Comp: FC<{ n: number }> = ({ n }) => { - const a = useATimesN(n); - - return ( -
      - {a} -
      - ); - }; - - const n = 4; - - const { container } = render(); - - expect(container.innerHTML).toContain(initialStore.a * n); - }); - it("selectors accept complex props", () => { - const initialStore = Object.freeze({ - a: 1, - }); - const { - hooks: { useATimesN }, - } = createStore(initialStore, { - hooks: { - useATimesN: (store, n: number) => { - return store.a * n; - }, - }, - }); - const Comp: FC<{ n: number }> = ({ n }) => { - const a = useATimesN(() => { - for (let i = 0; i < 1000; ++i) { - Math.random(); - } - - return n; - }, [n]); - - return ( -
      - {a} -
      - ); - }; - - const n = 10; - - const { container } = render(); - - expect(container.innerHTML).toContain(initialStore.a * n); - }); - - it("selectors only re-renders component when needed", () => { - const initialStore = Object.freeze({ - a: 5, - b: 10, - }); - - const { - useStore, - hooks: { useA, useB, useAxB }, - produce, - } = createStore(initialStore, { - hooks: { - useA: store => { - return store.a; - }, - useB: store => { - return store.b; - }, - useAxB: store => store.a * store.b, - }, - actions: {}, - }); - - const AllStoreComp: FC = () => { - const store = useStore(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} - {JSON.stringify(store)} -
      - ); - }; - - const OnlyAComp: FC = () => { - const a = useA(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} - A={a} -
      - ); - }; - - const OnlyBComp: FC = () => { - const b = useB(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} - B={b} -
      - ); - }; - - const OnlyAxBComp: FC = () => { - const AxB = useAxB(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} - AxB={AxB} -
      - ); - }; - - const allStoreComp = render(); - const aComp = render(); - const bComp = render(); - const axbComp = render(); - - expect(allStoreComp.container.innerHTML).toContain(nRenderString(1)); - expect(allStoreComp.container.innerHTML).toContain( - JSON.stringify(initialStore) - ); - - expect(aComp.container.innerHTML).toContain(nRenderString(1)); - expect(aComp.container.innerHTML).toContain(`A=${initialStore.a}`); - - expect(bComp.container.innerHTML).toContain(nRenderString(1)); - expect(bComp.container.innerHTML).toContain(`B=${initialStore.b}`); - - expect(axbComp.container.innerHTML).toContain(nRenderString(1)); - expect(axbComp.container.innerHTML).toContain( - `AxB=${initialStore.a * initialStore.b}` - ); - - const newA = 20; - act(() => { - produce(store => { - store.a = newA; - }); - }); - - expect(allStoreComp.container.innerHTML).toContain(nRenderString(2)); - expect(allStoreComp.container.innerHTML).toContain( - // We can use "produce" as a getState - JSON.stringify(produce(s => s)) - ); - - expect(aComp.container.innerHTML).toContain(nRenderString(2)); - expect(aComp.container.innerHTML).toContain(`A=${newA}`); - - expect(bComp.container.innerHTML).toContain(nRenderString(1)); - expect(bComp.container.innerHTML).toContain(`B=${initialStore.b}`); - - expect(axbComp.container.innerHTML).toContain(nRenderString(2)); - expect(axbComp.container.innerHTML).toContain( - `AxB=${newA * initialStore.b}` - ); - }); - - it("createSelector support and it makes a difference", () => { - const initialStore = Object.freeze({ - list: Object.freeze([1, 3, 5, 7]), - otherList: Object.freeze([0, 2, 4, 6]), - }); - - const { - hooks: { useMultiplySlow, useMultiplyFast }, - produce, - } = createStore(initialStore, { - hooks: { - useMultiplySlow: store => { - return store.list.map(n => n * 2); - }, - useMultiplyFast: createSelector( - state => state.list, - list => { - return list.map(n => n * 2); - } - ), - }, - actions: {}, - }); - - const CompSlow: FC = () => { - const list = useMultiplySlow(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} -
      - {list.join("|")} -
      - ); - }; - - const CompFast: FC = () => { - const list = useMultiplyFast(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} -
      - {list.join("|")} -
      - ); - }; - - const initialListJoin = initialStore.list.map(n => n * 2).join("|"); - - const compSlow = render(); - - const compFast = render(); - - expect(compSlow.container.innerHTML).toContain(nRenderString(1)); - expect(compFast.container.innerHTML).toContain(nRenderString(1)); - expect(compSlow.container.innerHTML).toContain(initialListJoin); - expect(compFast.container.innerHTML).toContain(initialListJoin); - - act(() => { - produce(draft => { - draft.otherList.push(9); - }); - }); - - expect(compSlow.container.innerHTML).toContain(nRenderString(2)); - expect(compFast.container.innerHTML).toContain(nRenderString(1)); - expect(compSlow.container.innerHTML).toContain(initialListJoin); - expect(compFast.container.innerHTML).toContain(initialListJoin); - }); - - it("createSelector with props support and it makes a difference", () => { - const initialStore = Object.freeze({ - list: Object.freeze([1, 3, 5, 7]), - otherList: Object.freeze([0, 2, 4, 6]), - }); - - const { - hooks: { useMultiplySlow, useMultiplyFast }, - produce, - } = createStore(initialStore, { - hooks: { - useMultiplySlow: (store, i: number) => { - return store.list.map(n => n * i); - }, - useMultiplyFast: createSelector< - { list: readonly number[] }, - number, - readonly number[], - number, - number[] - >( - state => state.list, - (_, n) => n, - (list, n) => { - return list.map(i => i * n); - } - ), - }, - actions: {}, - }); - - const nArg = 4; - - const CompSlow: FC = () => { - const list = useMultiplySlow(nArg); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} -
      - {list.join("|")} -
      - ); - }; - - const CompFast: FC = () => { - const list = useMultiplyFast(nArg); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} -
      - {list.join("|")} -
      - ); - }; - - const initialListJoin = initialStore.list.map(n => n * nArg).join("|"); - - const compSlow = render(); - - const compFast = render(); - - expect(compSlow.container.innerHTML).toContain(nRenderString(1)); - expect(compFast.container.innerHTML).toContain(nRenderString(1)); - expect(compSlow.container.innerHTML).toContain(initialListJoin); - expect(compFast.container.innerHTML).toContain(initialListJoin); - - act(() => { - produce(draft => { - draft.otherList.push(9); - }); - }); - - expect(compSlow.container.innerHTML).toContain(nRenderString(2)); - expect(compFast.container.innerHTML).toContain(nRenderString(1)); - expect(compSlow.container.innerHTML).toContain(initialListJoin); - expect(compFast.container.innerHTML).toContain(initialListJoin); - }); - - describe("draft function returns new instance of store", () => { - it("actions gives new instance of store", () => { - const initialStore = Object.freeze({ - a: 1, - b: 2, - }); - const newStore = Object.freeze({ - a: 4, - b: 5, - }); - const Store = createStore(initialStore, { - actions: { - newStore: () => () => { - return newStore; - }, - }, - hooks: {}, - }); - - expect(Store.produce()).toBe(initialStore); - - expect(Store.actions.newStore()).toBe(newStore); - - expect(Store.produce()).toBe(newStore); - }); - - it("produce gives new instance of store", () => { - const initialStore = Object.freeze({ - a: 1, - b: 2, - }); - const newStore = Object.freeze({ - a: 4, - b: 5, - }); - const Store = createStore(initialStore, { - actions: { - newStore: () => () => { - return newStore; - }, - }, - hooks: {}, - }); - - expect(Store.produce()).toBe(initialStore); - - expect(Store.produce(() => newStore)).toBe(newStore); - - expect(Store.produce()).toBe(newStore); - }); - }); -}); - -describe("map inside object", () => { - const obj1 = { a: 1, b: "asd" }; - const obj2 = { zxc: "8234" }; - - const initialStore = { - mapInside: new Map(), - }; - initialStore.mapInside.set(obj2, true); - - const Store = createStore(initialStore, { - hooks: { - useIsCheckedInside: ({ mapInside }, obj: object) => { - return !!mapInside.get(obj); - }, - }, - actions: { - toggleInside: (obj: object) => draft => { - draft.mapInside.set(obj, !draft.mapInside.get(obj)); - }, - }, - }); - - const CheckInsideComp: FC<{ obj: object; testId: string }> = ({ - testId, - obj, - }) => { - const isChecked = Store.hooks.useIsCheckedInside(obj); - - return
      {isChecked ? "yes" : "no"}
      ; - }; - - const { getByTestId } = render( - <> - - - - ); - - const CompObj1 = getByTestId("obj1"); - const CompObj2 = getByTestId("obj2"); - - expect(CompObj1.textContent).toBe("no"); - expect(CompObj2.textContent).toBe("yes"); - - act(() => { - Store.actions.toggleInside(obj1); - }); - - expect(CompObj1.textContent).toBe("yes"); -}); +/* eslint react-hooks/exhaustive-deps: 0 */ + +import { enableMapSet } from "immer"; +import React, { FC, useLayoutEffect } from "react"; +import waitForExpect from "wait-for-expect"; + +import { act, cleanup, render } from "@testing-library/react"; + +import { createSelector, createStore } from "../src"; +import { nRenderString, useRenderCount } from "./utils/useRenderCount"; + +enableMapSet(); +afterEach(cleanup); + +describe("basic createStore", () => { + const initialStore = Object.freeze({ + a: 5, + b: -5, + }); + + it("useStore works", () => { + const { useStore } = createStore(initialStore); + + const UseStoreComponent: FC = () => { + const store = useStore(); + return {store.a}; + }; + + const { getByText } = render(); + + const comp = getByText(initialStore.a.toString()); + + expect(comp).toBeTruthy(); + }); + + it("produce works with useStore", () => { + const { useStore, produce } = createStore(initialStore); + + const n = 5; + + const ProduceComponent: FC = () => { + const store = useStore(); + + useLayoutEffect(() => { + act(() => { + produce((draft) => { + draft.a += n; + }); + }); + }, []); + + return {store.a}; + }; + + const { getByText } = render(); + + const comp = getByText((initialStore.a + n).toString()); + + expect(comp).toBeTruthy(); + }); + + it("asyncProduce works with useStore", async () => { + const { useStore, asyncProduce } = createStore(initialStore); + + const n = 5; + + const AsyncProduceComponent: FC = () => { + const store = useStore(); + + return ( + <> + + {store.a} + + ); + }; + + const { getByTestId, container } = render(); + + expect(container.innerHTML).toContain(initialStore.a); + + getByTestId("button").click(); + + await waitForExpect( + async () => { + expect(container.innerHTML).toContain(initialStore.a + n); + }, + 2000, + 250 + ); + }); + + it("asyncProduce works as getter", () => { + const { asyncProduce, produce } = createStore({ a: 1 }); + + expect(produce()).toEqual({ a: 1 }); + + expect(asyncProduce()).resolves.toEqual({ a: 1 }); + + expect(asyncProduce(async () => {})).resolves.toEqual({ a: 1 }); + }); +}); + +describe("actions", () => { + it("defined actions work", () => { + const initialStore = Object.freeze({ + a: 1, + }); + const { actions, useStore } = createStore(initialStore, { + actions: { + increment: (n: number) => (draft) => { + draft.a += n; + }, + decrement: (n: number) => (draft) => { + draft.a -= n; + }, + }, + }); + + const n = 5; + + const ActionsComp: FC = () => { + const { a } = useStore(); + + return ( +
      +
      + ); + }; + + const { container, getByTestId } = render(); + + const IncrementButton = getByTestId("increment"); + const DecrementButton = getByTestId("decrement"); + + expect(container.innerHTML).toContain(initialStore.a); + + act(() => { + IncrementButton.click(); + }); + + expect(container.innerHTML).toContain(initialStore.a + n /* 6 */); + + act(() => { + DecrementButton.click(); + DecrementButton.click(); + }); + + expect(container.innerHTML).toContain(initialStore.a + n - n * 2 /* -4 */); + }); + + enum AsyncState { + waiting, + loading, + error, + complete, + } + + it("async actions work", async () => { + const initialStore = Object.freeze({ + a: 1, + state: AsyncState.waiting, + }); + + const Store = createStore(initialStore, { + hooks: {}, + asyncActions: { + asyncIncrement: (produce) => async (n: number) => { + produce((draft) => { + draft.state = AsyncState.loading; + }); + await new Promise((resolve) => setTimeout(resolve, 500)); + produce((draft) => { + draft.state = AsyncState.complete; + draft.a += n; + }); + }, + }, + actions: { + increment: (n: number) => (draft) => { + draft.a += n; + }, + }, + }); + + expect(Store.produce()).toBe(initialStore); + + const inc = Store.actions.increment(20); + + expect(inc).toEqual({ a: 21, state: AsyncState.waiting }); + + const promiseIncrement = expect( + Store.actions.asyncIncrement(10) + ).resolves.toEqual({ + a: 31, + state: AsyncState.complete, + }); + + expect(Store.produce()).toEqual({ a: 21, state: AsyncState.loading }); + + await promiseIncrement; + + expect(Store.produce()).toEqual({ + a: 31, + state: AsyncState.complete, + }); + }); + + it("async actions handle errors", async () => { + const initialStore = Object.freeze({ + a: 1, + state: AsyncState.waiting, + }); + + const SampleError = new Error("test error"); + + const Store = createStore(initialStore, { + hooks: {}, + asyncActions: { + asyncError: (produce) => async (_n: number) => { + await new Promise((_resolve, reject) => { + produce((draft) => { + draft.state = AsyncState.loading; + }); + setTimeout(() => { + produce((draft) => { + draft.state = AsyncState.error; + }); + reject(SampleError); + }, 500); + }); + }, + }, + }); + + expect(Store.produce().state).toBe(AsyncState.waiting); + const rejectPromise = expect(Store.actions.asyncError(10)).rejects.toBe( + SampleError + ); + expect(Store.produce().state).toBe(AsyncState.loading); + await rejectPromise; + expect(Store.produce().state).toBe(AsyncState.error); + }); + + it("should detect the same name on actions and asyncActions", () => { + expect(() => { + createStore( + {}, + { + actions: { + sameName: () => () => {}, + }, + asyncActions: { + sameName: () => async () => {}, + }, + } + ); + }).toThrowError( + 'All the actions and asyncActions should have different names and "sameName" exists in both objects!' + ); + }); + + it("should ignore the same name on actions and asyncActions in production", () => { + expect(() => { + const beforeEnv = process.env.NODE_ENV; + process.env.NODE_ENV = "production"; + createStore( + {}, + { + actions: { + sameName: () => () => {}, + }, + asyncActions: { + sameName: () => async () => {}, + }, + } + ); + process.env.NODE_ENV = beforeEnv; + }).not.toThrow(); + }); +}); + +describe("selectors and listeners", () => { + it("basic number object and individual selectors", () => { + const initialStore = Object.freeze({ + a: 1, + b: 2, + c: 3, + }); + + const { + hooks: { useA, useB, useC }, + } = createStore(initialStore, { + hooks: { + useA: (store) => store.a, + useB: (store) => store.b, + useC: (store) => store.c, + }, + actions: {}, + }); + + const AComp: FC = () => { + const n = useA(); + + return {n}; + }; + const BComp: FC = () => { + const n = useB(); + + return {n}; + }; + const CComp: FC = () => { + const n = useC(); + + return {n}; + }; + + const aComp = render(); + const bComp = render(); + const cComp = render(); + + expect(aComp.container.textContent).toBe(initialStore.a.toString()); + expect(bComp.container.textContent).toBe(initialStore.b.toString()); + expect(cComp.container.textContent).toBe(initialStore.c.toString()); + }); + + it("selectors accept plain props", () => { + const initialStore = Object.freeze({ + a: 1, + }); + const { + hooks: { useATimesN }, + } = createStore(initialStore, { + hooks: { + useATimesN: (store, n: number) => { + return store.a * n; + }, + }, + }); + const Comp: FC<{ n: number }> = ({ n }) => { + const a = useATimesN(n); + + return ( +
      + {a} +
      + ); + }; + + const n = 4; + + const { container } = render(); + + expect(container.innerHTML).toContain(initialStore.a * n); + }); + it("selectors accept complex props", () => { + const initialStore = Object.freeze({ + a: 1, + }); + const { + hooks: { useATimesN }, + } = createStore(initialStore, { + hooks: { + useATimesN: (store, n: number) => { + return store.a * n; + }, + }, + }); + const Comp: FC<{ n: number }> = ({ n }) => { + const a = useATimesN(() => { + for (let i = 0; i < 1000; ++i) { + Math.random(); + } + + return n; + }, [n]); + + return ( +
      + {a} +
      + ); + }; + + const n = 10; + + const { container } = render(); + + expect(container.innerHTML).toContain(initialStore.a * n); + }); + + it("selectors only re-renders component when needed", () => { + const initialStore = Object.freeze({ + a: 5, + b: 10, + }); + + const { + useStore, + hooks: { useA, useB, useAxB }, + produce, + } = createStore(initialStore, { + hooks: { + useA: (store) => { + return store.a; + }, + useB: (store) => { + return store.b; + }, + useAxB: (store) => store.a * store.b, + }, + actions: {}, + }); + + const AllStoreComp: FC = () => { + const store = useStore(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} + {JSON.stringify(store)} +
      + ); + }; + + const OnlyAComp: FC = () => { + const a = useA(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} + A={a} +
      + ); + }; + + const OnlyBComp: FC = () => { + const b = useB(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} + B={b} +
      + ); + }; + + const OnlyAxBComp: FC = () => { + const AxB = useAxB(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} + AxB={AxB} +
      + ); + }; + + const allStoreComp = render(); + const aComp = render(); + const bComp = render(); + const axbComp = render(); + + expect(allStoreComp.container.innerHTML).toContain(nRenderString(1)); + expect(allStoreComp.container.innerHTML).toContain( + JSON.stringify(initialStore) + ); + + expect(aComp.container.innerHTML).toContain(nRenderString(1)); + expect(aComp.container.innerHTML).toContain(`A=${initialStore.a}`); + + expect(bComp.container.innerHTML).toContain(nRenderString(1)); + expect(bComp.container.innerHTML).toContain(`B=${initialStore.b}`); + + expect(axbComp.container.innerHTML).toContain(nRenderString(1)); + expect(axbComp.container.innerHTML).toContain( + `AxB=${initialStore.a * initialStore.b}` + ); + + const newA = 20; + act(() => { + produce((store) => { + store.a = newA; + }); + }); + + expect(allStoreComp.container.innerHTML).toContain(nRenderString(2)); + expect(allStoreComp.container.innerHTML).toContain( + // We can use "produce" as a getState + JSON.stringify(produce((s) => s)) + ); + + expect(aComp.container.innerHTML).toContain(nRenderString(2)); + expect(aComp.container.innerHTML).toContain(`A=${newA}`); + + expect(bComp.container.innerHTML).toContain(nRenderString(1)); + expect(bComp.container.innerHTML).toContain(`B=${initialStore.b}`); + + expect(axbComp.container.innerHTML).toContain(nRenderString(2)); + expect(axbComp.container.innerHTML).toContain( + `AxB=${newA * initialStore.b}` + ); + }); + + it("createSelector support and it makes a difference", () => { + const initialStore = Object.freeze({ + list: Object.freeze([1, 3, 5, 7]), + otherList: Object.freeze([0, 2, 4, 6]), + }); + + const { + hooks: { useMultiplySlow, useMultiplyFast }, + produce, + } = createStore(initialStore, { + hooks: { + useMultiplySlow: (store) => { + return store.list.map((n) => n * 2); + }, + useMultiplyFast: createSelector( + (state) => state.list, + (list) => { + return list.map((n) => n * 2); + } + ), + }, + actions: {}, + }); + + const CompSlow: FC = () => { + const list = useMultiplySlow(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} +
      + {list.join("|")} +
      + ); + }; + + const CompFast: FC = () => { + const list = useMultiplyFast(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} +
      + {list.join("|")} +
      + ); + }; + + const initialListJoin = initialStore.list.map((n) => n * 2).join("|"); + + const compSlow = render(); + + const compFast = render(); + + expect(compSlow.container.innerHTML).toContain(nRenderString(1)); + expect(compFast.container.innerHTML).toContain(nRenderString(1)); + expect(compSlow.container.innerHTML).toContain(initialListJoin); + expect(compFast.container.innerHTML).toContain(initialListJoin); + + act(() => { + produce((draft) => { + draft.otherList.push(9); + }); + }); + + expect(compSlow.container.innerHTML).toContain(nRenderString(2)); + expect(compFast.container.innerHTML).toContain(nRenderString(1)); + expect(compSlow.container.innerHTML).toContain(initialListJoin); + expect(compFast.container.innerHTML).toContain(initialListJoin); + }); + + it("createSelector with props support and it makes a difference", () => { + const initialStore = Object.freeze({ + list: Object.freeze([1, 3, 5, 7]), + otherList: Object.freeze([0, 2, 4, 6]), + }); + + const { + hooks: { useMultiplySlow, useMultiplyFast }, + produce, + } = createStore(initialStore, { + hooks: { + useMultiplySlow: (store, i: number) => { + return store.list.map((n) => n * i); + }, + useMultiplyFast: createSelector< + { list: readonly number[] }, + number, + readonly number[], + number, + number[] + >( + (state) => state.list, + (_, n) => n, + (list, n) => { + return list.map((i) => i * n); + } + ), + }, + actions: {}, + }); + + const nArg = 4; + + const CompSlow: FC = () => { + const list = useMultiplySlow(nArg); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} +
      + {list.join("|")} +
      + ); + }; + + const CompFast: FC = () => { + const list = useMultiplyFast(nArg); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} +
      + {list.join("|")} +
      + ); + }; + + const initialListJoin = initialStore.list.map((n) => n * nArg).join("|"); + + const compSlow = render(); + + const compFast = render(); + + expect(compSlow.container.innerHTML).toContain(nRenderString(1)); + expect(compFast.container.innerHTML).toContain(nRenderString(1)); + expect(compSlow.container.innerHTML).toContain(initialListJoin); + expect(compFast.container.innerHTML).toContain(initialListJoin); + + act(() => { + produce((draft) => { + draft.otherList.push(9); + }); + }); + + expect(compSlow.container.innerHTML).toContain(nRenderString(2)); + expect(compFast.container.innerHTML).toContain(nRenderString(1)); + expect(compSlow.container.innerHTML).toContain(initialListJoin); + expect(compFast.container.innerHTML).toContain(initialListJoin); + }); + + describe("draft function returns new instance of store", () => { + it("actions gives new instance of store", () => { + const initialStore = Object.freeze({ + a: 1, + b: 2, + }); + const newStore = Object.freeze({ + a: 4, + b: 5, + }); + const Store = createStore(initialStore, { + actions: { + newStore: () => () => { + return newStore; + }, + }, + hooks: {}, + }); + + expect(Store.produce()).toBe(initialStore); + + expect(Store.actions.newStore()).toBe(newStore); + + expect(Store.produce()).toBe(newStore); + }); + + it("produce gives new instance of store", () => { + const initialStore = Object.freeze({ + a: 1, + b: 2, + }); + const newStore = Object.freeze({ + a: 4, + b: 5, + }); + const Store = createStore(initialStore, { + actions: { + newStore: () => () => { + return newStore; + }, + }, + hooks: {}, + }); + + expect(Store.produce()).toBe(initialStore); + + expect(Store.produce(() => newStore)).toBe(newStore); + + expect(Store.produce()).toBe(newStore); + }); + }); +}); + +describe("map inside object", () => { + const obj1 = { a: 1, b: "asd" }; + const obj2 = { zxc: "8234" }; + + const initialStore = { + mapInside: new Map(), + }; + initialStore.mapInside.set(obj2, true); + + const Store = createStore(initialStore, { + hooks: { + useIsCheckedInside: ({ mapInside }, obj: object) => { + return !!mapInside.get(obj); + }, + }, + actions: { + toggleInside: (obj: object) => (draft) => { + draft.mapInside.set(obj, !draft.mapInside.get(obj)); + }, + }, + }); + + const CheckInsideComp: FC<{ obj: object; testId: string }> = ({ + testId, + obj, + }) => { + const isChecked = Store.hooks.useIsCheckedInside(obj); + + return
      {isChecked ? "yes" : "no"}
      ; + }; + + const { getByTestId } = render( + <> + + + + ); + + const CompObj1 = getByTestId("obj1"); + const CompObj2 = getByTestId("obj2"); + + expect(CompObj1.textContent).toBe("no"); + expect(CompObj2.textContent).toBe("yes"); + + act(() => { + Store.actions.toggleInside(obj1); + }); + + expect(CompObj1.textContent).toBe("yes"); +}); diff --git a/test/createStoreContext.test.tsx b/test/createStoreContext.test.tsx index a6fdfe6..12e1750 100644 --- a/test/createStoreContext.test.tsx +++ b/test/createStoreContext.test.tsx @@ -1,922 +1,922 @@ -/* eslint react-hooks/exhaustive-deps: 0 */ - -import React, { FC, useEffect, useLayoutEffect } from "react"; -import waitForExpect from "wait-for-expect"; - -import { act, cleanup, render } from "@testing-library/react"; -import { act as actHooks, renderHook } from "@testing-library/react-hooks"; - -import { createSelector, createStoreContext } from "../src"; -import { nRenderString, useRenderCount } from "./utils/useRenderCount"; - -afterEach(cleanup); - -describe("basic createStore", () => { - const initialStore = Object.freeze({ - a: 5, - b: -5, - }); - - it("useStore works", () => { - const { useStore, Provider } = createStoreContext(initialStore); - - const UseStoreComponent: FC = () => { - const store = useStore(); - return {store.a}; - }; - - const { getByText, unmount } = render(, { - wrapper: Provider, - }); - - const comp = getByText(initialStore.a.toString()); - - expect(comp).toBeTruthy(); - unmount(); - }); - - it("produce works with useStore", () => { - const { useStore, useProduce, Provider } = createStoreContext(initialStore); - - const n = 5; - - const ProduceComponent: FC = () => { - const store = useStore(); - const { produce } = useProduce(); - - useLayoutEffect(() => { - act(() => { - produce(draft => { - draft.a += n; - }); - }); - }, []); - - return {store.a}; - }; - - const { container, unmount } = render(, { - wrapper: Provider, - }); - - expect(container.innerHTML).toContain(initialStore.a + n); - - unmount(); - }); - - it("asyncProduce works with useStore", async () => { - const { useStore, useProduce } = createStoreContext(initialStore); - - const n = 5; - - const AsyncProduceComponent: FC = () => { - const store = useStore(); - const { asyncProduce } = useProduce(); - - return ( - <> - - {store.a} - - ); - }; - - const { container, unmount, getByTestId } = render( - - ); - - expect(container.innerHTML).toContain(initialStore.a); - - getByTestId("button").click(); - await waitForExpect( - async () => { - expect(container.innerHTML).toContain((initialStore.a + n).toString()); - }, - 2000, - 250 - ); - unmount(); - }); - - it("asyncProduce works as getter", () => { - const { useProduce, useStore } = createStoreContext({ a: 1 }); - - const { result, unmount } = renderHook(() => { - const store = useStore(); - const produceObj = useProduce(); - - return { ...produceObj, store }; - }); - expect(result.current.produce()).toEqual({ a: 1 }); - expect(result.current.store).toEqual({ a: 1 }); - - expect(result.current.asyncProduce()).resolves.toEqual({ - a: 1, - }); - expect(result.current.store).toEqual({ a: 1 }); - - expect(result.current.asyncProduce(async () => {})).resolves.toEqual({ - a: 1, - }); - expect(result.current.store).toEqual({ a: 1 }); - - unmount(); - }); -}); - -describe("actions", () => { - it("defined actions work", () => { - const initialStore = Object.freeze({ - a: 1, - }); - const { useActions, useStore, Provider } = createStoreContext( - initialStore, - { - actions: { - increment: (n: number) => draft => { - draft.a += n; - }, - decrement: (n: number) => draft => { - draft.a -= n; - }, - }, - } - ); - - const n = 5; - - const ActionsComp: FC = () => { - const { a } = useStore(); - const Actions1 = useActions(); - // Check if the memoization of the actions is working - const Actions2 = useActions(); - expect(Actions1).toBe(Actions2); - - return ( -
      -
      - ); - }; - - const { container, getByTestId, unmount } = render(, { - wrapper: Provider, - }); - - const IncrementButton = getByTestId("increment"); - const DecrementButton = getByTestId("decrement"); - - expect(container.innerHTML).toContain(initialStore.a); - - act(() => { - IncrementButton.click(); - }); - - expect(container.innerHTML).toContain(initialStore.a + n); - - act(() => { - DecrementButton.click(); - DecrementButton.click(); - }); - - expect(container.innerHTML).toContain(initialStore.a + n - n * 2); - - unmount(); - }); - it("empty actions options means useActions gives empty object", () => { - const initialStore = Object.freeze({ - a: 1, - }); - const { useActions } = createStoreContext(initialStore); - - const Comp: FC = () => { - const actions = useActions(); - - return {JSON.stringify(actions)}; - }; - - const { unmount, container } = render(); - - expect(container.innerHTML).toContain("{}"); - unmount(); - }); - - enum AsyncState { - waiting, - loading, - error, - complete, - } - - it("async actions work", async () => { - const initialStore = Object.freeze({ - a: 1, - state: AsyncState.waiting, - }); - - const Store = createStoreContext(initialStore, { - hooks: {}, - asyncActions: { - asyncIncrement: produce => async (n: number) => { - produce(draft => { - draft.state = AsyncState.loading; - }); - await new Promise(resolve => setTimeout(resolve, 500)); - - produce(draft => { - draft.state = AsyncState.complete; - draft.a += n; - }); - }, - }, - actions: { - increment: (n: number) => draft => { - draft.a += n; - }, - }, - }); - - const { unmount, result } = renderHook( - () => { - const store = Store.useStore(); - const actions = Store.useActions(); - - return { store, actions }; - }, - { - wrapper: Store.Provider, - } - ); - - expect(result.current.store).toEqual({ - a: 1, - state: AsyncState.waiting, - }); - - actHooks(() => { - result.current.actions.increment(20); - }); - - expect(result.current.store).toEqual({ a: 21, state: AsyncState.waiting }); - - const promiseIncrement = actHooks(async () => { - await result.current.actions.asyncIncrement(10); - }); - expect(result.current.store).toEqual({ - a: 21, - state: AsyncState.loading, - }); - - await promiseIncrement; - - expect(result.current.store).toEqual({ a: 31, state: AsyncState.complete }); - - unmount(); - }); - - it("async actions handle errors", async () => { - const initialStore = Object.freeze({ - a: 1, - state: AsyncState.waiting, - }); - - const SampleError = new Error("test error"); - - const Store = createStoreContext(initialStore, { - hooks: {}, - asyncActions: { - asyncError: produce => async (_n: number) => { - await actHooks(async () => { - produce(draft => { - draft.state = AsyncState.loading; - }); - await new Promise((_resolve, reject) => - setTimeout(() => { - produce(draft => { - draft.state = AsyncState.error; - }); - reject(SampleError); - }, 500) - ); - }); - }, - }, - }); - - const { unmount, result } = renderHook( - () => { - const store = Store.useStore(); - const actions = Store.useActions(); - - return { store, actions }; - }, - { - wrapper: Store.Provider, - } - ); - - expect(result.current.store).toEqual({ - a: 1, - state: AsyncState.waiting, - }); - - const promiseIncrement = expect( - result.current.actions.asyncError(10) - ).rejects.toBe(SampleError); - - expect(result.current.store).toEqual({ - a: 1, - state: AsyncState.loading, - }); - - await promiseIncrement; - - expect(result.current.store).toEqual({ - a: 1, - state: AsyncState.error, - }); - - unmount(); - }); - - it("should detect the same name on actions and asyncActions", () => { - expect(() => { - createStoreContext( - {}, - { - actions: { - sameName: () => () => {}, - }, - asyncActions: { - sameName: () => async () => {}, - }, - } - ); - }).toThrowError( - 'All the actions and asyncActions should have different names and "sameName" exists in both objects!' - ); - }); - - it("should ignore the same name on actions and asyncActions in production", () => { - expect(() => { - const beforeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = "production"; - createStoreContext( - {}, - { - actions: { - sameName: () => () => {}, - }, - asyncActions: { - sameName: () => async () => {}, - }, - } - ); - process.env.NODE_ENV = beforeEnv; - }).not.toThrow(); - }); -}); - -describe("selectors and listeners", () => { - it("basic number object and individual selectors", () => { - const initialStore = Object.freeze({ - a: 1, - b: 2, - c: 3, - }); - - const { - hooks: { useA, useB, useC }, - } = createStoreContext(initialStore, { - hooks: { - useA: store => store.a, - useB: store => store.b, - useC: store => store.c, - }, - }); - - const AComp: FC = () => { - const n = useA(); - - return {n}; - }; - const BComp: FC = () => { - const n = useB(); - - return {n}; - }; - const CComp: FC = () => { - const n = useC(); - - return {n}; - }; - - const aComp = render(); - const bComp = render(); - const cComp = render(); - - expect(aComp.container.textContent).toBe(initialStore.a.toString()); - expect(bComp.container.textContent).toBe(initialStore.b.toString()); - expect(cComp.container.textContent).toBe(initialStore.c.toString()); - - aComp.unmount(); - bComp.unmount(); - cComp.unmount(); - }); - - it("selectors only re-renders component when needed", () => { - const initialStore = Object.freeze({ - a: 5, - b: 10, - }); - - const { - useStore, - hooks: { useA, useB, useAxB }, - useProduce, - Provider, - } = createStoreContext(initialStore, { - hooks: { - useA: store => { - return store.a; - }, - useB: store => { - return store.b; - }, - useAxB: store => store.a * store.b, - }, - }); - - const AllStoreComp: FC = () => { - const store = useStore(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} - {JSON.stringify(store)} -
      - ); - }; - - const OnlyAComp: FC = () => { - const a = useA(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} - A={a} -
      - ); - }; - - const OnlyBComp: FC = () => { - const b = useB(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} - B={b} -
      - ); - }; - - const OnlyAxBComp: FC = () => { - const AxB = useAxB(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} - AxB={AxB} -
      - ); - }; - - const plusA = 5; - - const ProducerComp: FC = () => { - const { produce } = useProduce(); - - return ( - - ); - }; - - const { getByTestId, unmount } = render( - - - - - - - - ); - - const allStoreComp = getByTestId("allStore"); - const aComp = getByTestId("onlyA"); - const bComp = getByTestId("onlyB"); - const axbComp = getByTestId("onlyAxB"); - const producerComp = getByTestId("producer"); - - expect(allStoreComp.innerHTML).toContain(nRenderString(1)); - expect(allStoreComp.innerHTML).toContain(JSON.stringify(initialStore)); - - expect(aComp.innerHTML).toContain(nRenderString(1)); - expect(aComp.innerHTML).toContain(`A=${initialStore.a}`); - - expect(bComp.innerHTML).toContain(nRenderString(1)); - expect(bComp.innerHTML).toContain(`B=${initialStore.b}`); - - expect(axbComp.innerHTML).toContain(nRenderString(1)); - expect(axbComp.innerHTML).toContain( - `AxB=${initialStore.a * initialStore.b}` - ); - - act(() => { - producerComp.click(); - }); - - expect(allStoreComp.innerHTML).toContain(nRenderString(2)); - expect(allStoreComp.innerHTML).toContain( - JSON.stringify({ ...initialStore, a: initialStore.a + plusA }) - ); - - expect(aComp.innerHTML).toContain(nRenderString(2)); - expect(aComp.innerHTML).toContain(`A=${initialStore.a + plusA}`); - - expect(bComp.innerHTML).toContain(nRenderString(1)); - expect(bComp.innerHTML).toContain(`B=${initialStore.b}`); - - expect(axbComp.innerHTML).toContain(nRenderString(2)); - expect(axbComp.innerHTML).toContain( - `AxB=${(initialStore.a + plusA) * initialStore.b}` - ); - - unmount(); - }); - - it("createSelector support and it makes a difference", () => { - const initialStore = Object.freeze({ - list: Object.freeze([1, 3, 5, 7]), - otherList: Object.freeze([0, 2, 4, 6]), - }); - - const { - hooks: { useMultiplySlow, useMultiplyFast }, - useProduce, - Provider, - } = createStoreContext(initialStore, { - hooks: { - useMultiplySlow: store => { - return store.list.map(n => n * 2); - }, - useMultiplyFast: createSelector( - state => state.list, - list => { - return list.map(n => n * 2); - } - ), - }, - }); - - const CompSlow: FC = () => { - const list = useMultiplySlow(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} -
      - {list.join("|")} -
      - ); - }; - - const CompFast: FC = () => { - const list = useMultiplyFast(); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} -
      - {list.join("|")} -
      - ); - }; - - const ProducerComp: FC = () => { - const { produce } = useProduce(); - - return ( - - ); - }; - - const initialListJoin = initialStore.list.map(n => n * 2).join("|"); - - const { unmount, getByTestId } = render( - - - - - - ); - const compSlow = getByTestId("compSlow"); - - const compFast = getByTestId("compFast"); - - const producerComp = getByTestId("producer"); - - expect(compSlow.innerHTML).toContain(nRenderString(1)); - expect(compFast.innerHTML).toContain(nRenderString(1)); - expect(compSlow.innerHTML).toContain(initialListJoin); - expect(compFast.innerHTML).toContain(initialListJoin); - - act(() => { - producerComp.click(); - }); - - expect(compSlow.innerHTML).toContain(nRenderString(2)); - expect(compFast.innerHTML).toContain(nRenderString(1)); - expect(compSlow.innerHTML).toContain(initialListJoin); - expect(compFast.innerHTML).toContain(initialListJoin); - - unmount(); - }); - - it("createSelector with props support and it makes a difference", () => { - const initialStore = Object.freeze({ - list: Object.freeze([1, 3, 5, 7]), - otherList: Object.freeze([0, 2, 4, 6]), - }); - - const { - hooks: { useMultiplySlow, useMultiplyFast }, - useProduce, - Provider, - } = createStoreContext(initialStore, { - hooks: { - useMultiplySlow: (store, i: number) => { - return store.list.map(n => n * i); - }, - useMultiplyFast: createSelector< - { list: readonly number[] }, - number, - readonly number[], - number, - number[] - >( - state => state.list, - (_, n) => n, - (list, n) => { - return list.map(i => i * n); - } - ), - }, - actions: {}, - }); - - const nArg = 4; - - const CompSlow: FC = () => { - const list = useMultiplySlow(nArg); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} -
      - {list.join("|")} -
      - ); - }; - - const CompFast: FC = () => { - const list = useMultiplyFast(nArg); - const renderCount = useRenderCount(); - - return ( -
      - {renderCount} -
      - {list.join("|")} -
      - ); - }; - - const ProducerComp: FC = () => { - const { produce } = useProduce(); - - return ( - - ); - }; - - const initialListJoin = initialStore.list.map(n => n * nArg).join("|"); - - const { unmount, getByTestId } = render( - - - - - - ); - - const compSlow = getByTestId("compSlow"); - - const compFast = getByTestId("compFast"); - - const producerComp = getByTestId("producer"); - - expect(compSlow.innerHTML).toContain(nRenderString(1)); - expect(compFast.innerHTML).toContain(nRenderString(1)); - expect(compSlow.innerHTML).toContain(initialListJoin); - expect(compFast.innerHTML).toContain(initialListJoin); - - act(() => { - producerComp.click(); - }); - - expect(compSlow.innerHTML).toContain(nRenderString(2)); - expect(compFast.innerHTML).toContain(nRenderString(1)); - expect(compSlow.innerHTML).toContain(initialListJoin); - expect(compFast.innerHTML).toContain(initialListJoin); - - unmount(); - }); -}); - -describe("context providers", () => { - it("different providers have different state", () => { - const initialStore = Object.freeze({ - a: 1, - b: 2, - }); - - const { Provider, useStore, useProduce } = createStoreContext(initialStore); - - const StoreWatch: FC = () => { - const store = useStore(); - - return {JSON.stringify(store)}; - }; - - const Producer: FC<{ id?: string }> = ({ id }) => { - const { produce } = useProduce(); - - return ( - - ); - }; - - const ContextA = render( - - - - - ); - const ContextB = render( - - - - - ); - - expect(ContextA.container.innerHTML).toContain( - JSON.stringify(initialStore) - ); - expect(ContextB.container.innerHTML).toContain( - JSON.stringify(initialStore) - ); - - ContextA.getByTestId("button").click(); - - expect(ContextA.container.innerHTML).toContain( - JSON.stringify({ a: initialStore.a * 2, b: initialStore.b * 2 }) - ); - expect(ContextB.container.innerHTML).toContain( - JSON.stringify(initialStore) - ); - - ContextA.unmount(); - ContextB.unmount(); - }); - - it("produce gives new instance of store", () => { - const initialStore = Object.freeze({ - a: 1, - b: 2, - }); - const newStore = Object.freeze({ - a: 4, - b: 5, - }); - const Store = createStoreContext(initialStore, { - actions: { - newStore: () => () => { - return newStore; - }, - }, - hooks: {}, - }); - const { unmount, result, rerender } = renderHook( - (n?: typeof newStore) => { - const store = Store.useStore(); - const { produce } = Store.useProduce(); - useEffect(() => { - if (n) { - act(() => { - produce(() => newStore); - }); - } - }, [n, produce]); - return { store, produceGetterResult: produce() }; - }, - { - wrapper: Store.Provider, - } - ); - - expect(result.current.store).toBe(initialStore); - expect(result.current.produceGetterResult).toBe(initialStore); - - rerender(newStore); - - expect(result.current.store).toBe(newStore); - expect(result.current.produceGetterResult).toBe(newStore); - - unmount(); - }); -}); +/* eslint react-hooks/exhaustive-deps: 0 */ + +import React, { FC, useEffect, useLayoutEffect } from "react"; +import waitForExpect from "wait-for-expect"; + +import { act, cleanup, render } from "@testing-library/react"; +import { act as actHooks, renderHook } from "@testing-library/react-hooks"; + +import { createSelector, createStoreContext } from "../src"; +import { nRenderString, useRenderCount } from "./utils/useRenderCount"; + +afterEach(cleanup); + +describe("basic createStore", () => { + const initialStore = Object.freeze({ + a: 5, + b: -5, + }); + + it("useStore works", () => { + const { useStore, Provider } = createStoreContext(initialStore); + + const UseStoreComponent: FC = () => { + const store = useStore(); + return {store.a}; + }; + + const { getByText, unmount } = render(, { + wrapper: Provider, + }); + + const comp = getByText(initialStore.a.toString()); + + expect(comp).toBeTruthy(); + unmount(); + }); + + it("produce works with useStore", () => { + const { useStore, useProduce, Provider } = createStoreContext(initialStore); + + const n = 5; + + const ProduceComponent: FC = () => { + const store = useStore(); + const { produce } = useProduce(); + + useLayoutEffect(() => { + act(() => { + produce((draft) => { + draft.a += n; + }); + }); + }, []); + + return {store.a}; + }; + + const { container, unmount } = render(, { + wrapper: Provider, + }); + + expect(container.innerHTML).toContain(initialStore.a + n); + + unmount(); + }); + + it("asyncProduce works with useStore", async () => { + const { useStore, useProduce } = createStoreContext(initialStore); + + const n = 5; + + const AsyncProduceComponent: FC = () => { + const store = useStore(); + const { asyncProduce } = useProduce(); + + return ( + <> + + {store.a} + + ); + }; + + const { container, unmount, getByTestId } = render( + + ); + + expect(container.innerHTML).toContain(initialStore.a); + + getByTestId("button").click(); + await waitForExpect( + async () => { + expect(container.innerHTML).toContain((initialStore.a + n).toString()); + }, + 2000, + 250 + ); + unmount(); + }); + + it("asyncProduce works as getter", () => { + const { useProduce, useStore } = createStoreContext({ a: 1 }); + + const { result, unmount } = renderHook(() => { + const store = useStore(); + const produceObj = useProduce(); + + return { ...produceObj, store }; + }); + expect(result.current.produce()).toEqual({ a: 1 }); + expect(result.current.store).toEqual({ a: 1 }); + + expect(result.current.asyncProduce()).resolves.toEqual({ + a: 1, + }); + expect(result.current.store).toEqual({ a: 1 }); + + expect(result.current.asyncProduce(async () => {})).resolves.toEqual({ + a: 1, + }); + expect(result.current.store).toEqual({ a: 1 }); + + unmount(); + }); +}); + +describe("actions", () => { + it("defined actions work", () => { + const initialStore = Object.freeze({ + a: 1, + }); + const { useActions, useStore, Provider } = createStoreContext( + initialStore, + { + actions: { + increment: (n: number) => (draft) => { + draft.a += n; + }, + decrement: (n: number) => (draft) => { + draft.a -= n; + }, + }, + } + ); + + const n = 5; + + const ActionsComp: FC = () => { + const { a } = useStore(); + const Actions1 = useActions(); + // Check if the memoization of the actions is working + const Actions2 = useActions(); + expect(Actions1).toBe(Actions2); + + return ( +
      +
      + ); + }; + + const { container, getByTestId, unmount } = render(, { + wrapper: Provider, + }); + + const IncrementButton = getByTestId("increment"); + const DecrementButton = getByTestId("decrement"); + + expect(container.innerHTML).toContain(initialStore.a); + + act(() => { + IncrementButton.click(); + }); + + expect(container.innerHTML).toContain(initialStore.a + n); + + act(() => { + DecrementButton.click(); + DecrementButton.click(); + }); + + expect(container.innerHTML).toContain(initialStore.a + n - n * 2); + + unmount(); + }); + it("empty actions options means useActions gives empty object", () => { + const initialStore = Object.freeze({ + a: 1, + }); + const { useActions } = createStoreContext(initialStore); + + const Comp: FC = () => { + const actions = useActions(); + + return {JSON.stringify(actions)}; + }; + + const { unmount, container } = render(); + + expect(container.innerHTML).toContain("{}"); + unmount(); + }); + + enum AsyncState { + waiting, + loading, + error, + complete, + } + + it("async actions work", async () => { + const initialStore = Object.freeze({ + a: 1, + state: AsyncState.waiting, + }); + + const Store = createStoreContext(initialStore, { + hooks: {}, + asyncActions: { + asyncIncrement: (produce) => async (n: number) => { + produce((draft) => { + draft.state = AsyncState.loading; + }); + await new Promise((resolve) => setTimeout(resolve, 500)); + + produce((draft) => { + draft.state = AsyncState.complete; + draft.a += n; + }); + }, + }, + actions: { + increment: (n: number) => (draft) => { + draft.a += n; + }, + }, + }); + + const { unmount, result } = renderHook( + () => { + const store = Store.useStore(); + const actions = Store.useActions(); + + return { store, actions }; + }, + { + wrapper: Store.Provider, + } + ); + + expect(result.current.store).toEqual({ + a: 1, + state: AsyncState.waiting, + }); + + actHooks(() => { + result.current.actions.increment(20); + }); + + expect(result.current.store).toEqual({ a: 21, state: AsyncState.waiting }); + + const promiseIncrement = actHooks(async () => { + await result.current.actions.asyncIncrement(10); + }); + expect(result.current.store).toEqual({ + a: 21, + state: AsyncState.loading, + }); + + await promiseIncrement; + + expect(result.current.store).toEqual({ a: 31, state: AsyncState.complete }); + + unmount(); + }); + + it("async actions handle errors", async () => { + const initialStore = Object.freeze({ + a: 1, + state: AsyncState.waiting, + }); + + const SampleError = new Error("test error"); + + const Store = createStoreContext(initialStore, { + hooks: {}, + asyncActions: { + asyncError: (produce) => async (_n: number) => { + await actHooks(async () => { + produce((draft) => { + draft.state = AsyncState.loading; + }); + await new Promise((_resolve, reject) => + setTimeout(() => { + produce((draft) => { + draft.state = AsyncState.error; + }); + reject(SampleError); + }, 500) + ); + }); + }, + }, + }); + + const { unmount, result } = renderHook( + () => { + const store = Store.useStore(); + const actions = Store.useActions(); + + return { store, actions }; + }, + { + wrapper: Store.Provider, + } + ); + + expect(result.current.store).toEqual({ + a: 1, + state: AsyncState.waiting, + }); + + const promiseIncrement = expect( + result.current.actions.asyncError(10) + ).rejects.toBe(SampleError); + + expect(result.current.store).toEqual({ + a: 1, + state: AsyncState.loading, + }); + + await promiseIncrement; + + expect(result.current.store).toEqual({ + a: 1, + state: AsyncState.error, + }); + + unmount(); + }); + + it("should detect the same name on actions and asyncActions", () => { + expect(() => { + createStoreContext( + {}, + { + actions: { + sameName: () => () => {}, + }, + asyncActions: { + sameName: () => async () => {}, + }, + } + ); + }).toThrowError( + 'All the actions and asyncActions should have different names and "sameName" exists in both objects!' + ); + }); + + it("should ignore the same name on actions and asyncActions in production", () => { + expect(() => { + const beforeEnv = process.env.NODE_ENV; + process.env.NODE_ENV = "production"; + createStoreContext( + {}, + { + actions: { + sameName: () => () => {}, + }, + asyncActions: { + sameName: () => async () => {}, + }, + } + ); + process.env.NODE_ENV = beforeEnv; + }).not.toThrow(); + }); +}); + +describe("selectors and listeners", () => { + it("basic number object and individual selectors", () => { + const initialStore = Object.freeze({ + a: 1, + b: 2, + c: 3, + }); + + const { + hooks: { useA, useB, useC }, + } = createStoreContext(initialStore, { + hooks: { + useA: (store) => store.a, + useB: (store) => store.b, + useC: (store) => store.c, + }, + }); + + const AComp: FC = () => { + const n = useA(); + + return {n}; + }; + const BComp: FC = () => { + const n = useB(); + + return {n}; + }; + const CComp: FC = () => { + const n = useC(); + + return {n}; + }; + + const aComp = render(); + const bComp = render(); + const cComp = render(); + + expect(aComp.container.textContent).toBe(initialStore.a.toString()); + expect(bComp.container.textContent).toBe(initialStore.b.toString()); + expect(cComp.container.textContent).toBe(initialStore.c.toString()); + + aComp.unmount(); + bComp.unmount(); + cComp.unmount(); + }); + + it("selectors only re-renders component when needed", () => { + const initialStore = Object.freeze({ + a: 5, + b: 10, + }); + + const { + useStore, + hooks: { useA, useB, useAxB }, + useProduce, + Provider, + } = createStoreContext(initialStore, { + hooks: { + useA: (store) => { + return store.a; + }, + useB: (store) => { + return store.b; + }, + useAxB: (store) => store.a * store.b, + }, + }); + + const AllStoreComp: FC = () => { + const store = useStore(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} + {JSON.stringify(store)} +
      + ); + }; + + const OnlyAComp: FC = () => { + const a = useA(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} + A={a} +
      + ); + }; + + const OnlyBComp: FC = () => { + const b = useB(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} + B={b} +
      + ); + }; + + const OnlyAxBComp: FC = () => { + const AxB = useAxB(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} + AxB={AxB} +
      + ); + }; + + const plusA = 5; + + const ProducerComp: FC = () => { + const { produce } = useProduce(); + + return ( + + ); + }; + + const { getByTestId, unmount } = render( + + + + + + + + ); + + const allStoreComp = getByTestId("allStore"); + const aComp = getByTestId("onlyA"); + const bComp = getByTestId("onlyB"); + const axbComp = getByTestId("onlyAxB"); + const producerComp = getByTestId("producer"); + + expect(allStoreComp.innerHTML).toContain(nRenderString(1)); + expect(allStoreComp.innerHTML).toContain(JSON.stringify(initialStore)); + + expect(aComp.innerHTML).toContain(nRenderString(1)); + expect(aComp.innerHTML).toContain(`A=${initialStore.a}`); + + expect(bComp.innerHTML).toContain(nRenderString(1)); + expect(bComp.innerHTML).toContain(`B=${initialStore.b}`); + + expect(axbComp.innerHTML).toContain(nRenderString(1)); + expect(axbComp.innerHTML).toContain( + `AxB=${initialStore.a * initialStore.b}` + ); + + act(() => { + producerComp.click(); + }); + + expect(allStoreComp.innerHTML).toContain(nRenderString(2)); + expect(allStoreComp.innerHTML).toContain( + JSON.stringify({ ...initialStore, a: initialStore.a + plusA }) + ); + + expect(aComp.innerHTML).toContain(nRenderString(2)); + expect(aComp.innerHTML).toContain(`A=${initialStore.a + plusA}`); + + expect(bComp.innerHTML).toContain(nRenderString(1)); + expect(bComp.innerHTML).toContain(`B=${initialStore.b}`); + + expect(axbComp.innerHTML).toContain(nRenderString(2)); + expect(axbComp.innerHTML).toContain( + `AxB=${(initialStore.a + plusA) * initialStore.b}` + ); + + unmount(); + }); + + it("createSelector support and it makes a difference", () => { + const initialStore = Object.freeze({ + list: Object.freeze([1, 3, 5, 7]), + otherList: Object.freeze([0, 2, 4, 6]), + }); + + const { + hooks: { useMultiplySlow, useMultiplyFast }, + useProduce, + Provider, + } = createStoreContext(initialStore, { + hooks: { + useMultiplySlow: (store) => { + return store.list.map((n) => n * 2); + }, + useMultiplyFast: createSelector( + (state) => state.list, + (list) => { + return list.map((n) => n * 2); + } + ), + }, + }); + + const CompSlow: FC = () => { + const list = useMultiplySlow(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} +
      + {list.join("|")} +
      + ); + }; + + const CompFast: FC = () => { + const list = useMultiplyFast(); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} +
      + {list.join("|")} +
      + ); + }; + + const ProducerComp: FC = () => { + const { produce } = useProduce(); + + return ( + + ); + }; + + const initialListJoin = initialStore.list.map((n) => n * 2).join("|"); + + const { unmount, getByTestId } = render( + + + + + + ); + const compSlow = getByTestId("compSlow"); + + const compFast = getByTestId("compFast"); + + const producerComp = getByTestId("producer"); + + expect(compSlow.innerHTML).toContain(nRenderString(1)); + expect(compFast.innerHTML).toContain(nRenderString(1)); + expect(compSlow.innerHTML).toContain(initialListJoin); + expect(compFast.innerHTML).toContain(initialListJoin); + + act(() => { + producerComp.click(); + }); + + expect(compSlow.innerHTML).toContain(nRenderString(2)); + expect(compFast.innerHTML).toContain(nRenderString(1)); + expect(compSlow.innerHTML).toContain(initialListJoin); + expect(compFast.innerHTML).toContain(initialListJoin); + + unmount(); + }); + + it("createSelector with props support and it makes a difference", () => { + const initialStore = Object.freeze({ + list: Object.freeze([1, 3, 5, 7]), + otherList: Object.freeze([0, 2, 4, 6]), + }); + + const { + hooks: { useMultiplySlow, useMultiplyFast }, + useProduce, + Provider, + } = createStoreContext(initialStore, { + hooks: { + useMultiplySlow: (store, i: number) => { + return store.list.map((n) => n * i); + }, + useMultiplyFast: createSelector< + { list: readonly number[] }, + number, + readonly number[], + number, + number[] + >( + (state) => state.list, + (_, n) => n, + (list, n) => { + return list.map((i) => i * n); + } + ), + }, + actions: {}, + }); + + const nArg = 4; + + const CompSlow: FC = () => { + const list = useMultiplySlow(nArg); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} +
      + {list.join("|")} +
      + ); + }; + + const CompFast: FC = () => { + const list = useMultiplyFast(nArg); + const renderCount = useRenderCount(); + + return ( +
      + {renderCount} +
      + {list.join("|")} +
      + ); + }; + + const ProducerComp: FC = () => { + const { produce } = useProduce(); + + return ( + + ); + }; + + const initialListJoin = initialStore.list.map((n) => n * nArg).join("|"); + + const { unmount, getByTestId } = render( + + + + + + ); + + const compSlow = getByTestId("compSlow"); + + const compFast = getByTestId("compFast"); + + const producerComp = getByTestId("producer"); + + expect(compSlow.innerHTML).toContain(nRenderString(1)); + expect(compFast.innerHTML).toContain(nRenderString(1)); + expect(compSlow.innerHTML).toContain(initialListJoin); + expect(compFast.innerHTML).toContain(initialListJoin); + + act(() => { + producerComp.click(); + }); + + expect(compSlow.innerHTML).toContain(nRenderString(2)); + expect(compFast.innerHTML).toContain(nRenderString(1)); + expect(compSlow.innerHTML).toContain(initialListJoin); + expect(compFast.innerHTML).toContain(initialListJoin); + + unmount(); + }); +}); + +describe("context providers", () => { + it("different providers have different state", () => { + const initialStore = Object.freeze({ + a: 1, + b: 2, + }); + + const { Provider, useStore, useProduce } = createStoreContext(initialStore); + + const StoreWatch: FC = () => { + const store = useStore(); + + return {JSON.stringify(store)}; + }; + + const Producer: FC<{ id?: string }> = ({ id }) => { + const { produce } = useProduce(); + + return ( + + ); + }; + + const ContextA = render( + + + + + ); + const ContextB = render( + + + + + ); + + expect(ContextA.container.innerHTML).toContain( + JSON.stringify(initialStore) + ); + expect(ContextB.container.innerHTML).toContain( + JSON.stringify(initialStore) + ); + + ContextA.getByTestId("button").click(); + + expect(ContextA.container.innerHTML).toContain( + JSON.stringify({ a: initialStore.a * 2, b: initialStore.b * 2 }) + ); + expect(ContextB.container.innerHTML).toContain( + JSON.stringify(initialStore) + ); + + ContextA.unmount(); + ContextB.unmount(); + }); + + it("produce gives new instance of store", () => { + const initialStore = Object.freeze({ + a: 1, + b: 2, + }); + const newStore = Object.freeze({ + a: 4, + b: 5, + }); + const Store = createStoreContext(initialStore, { + actions: { + newStore: () => () => { + return newStore; + }, + }, + hooks: {}, + }); + const { unmount, result, rerender } = renderHook( + (n?: typeof newStore) => { + const store = Store.useStore(); + const { produce } = Store.useProduce(); + useEffect(() => { + if (n) { + act(() => { + produce(() => newStore); + }); + } + }, [n, produce]); + return { store, produceGetterResult: produce() }; + }, + { + wrapper: Store.Provider, + } + ); + + expect(result.current.store).toBe(initialStore); + expect(result.current.produceGetterResult).toBe(initialStore); + + rerender(newStore); + + expect(result.current.store).toBe(newStore); + expect(result.current.produceGetterResult).toBe(newStore); + + unmount(); + }); +}); diff --git a/test/devTools.test.tsx b/test/devTools.test.tsx index 0be81bc..6085b65 100644 --- a/test/devTools.test.tsx +++ b/test/devTools.test.tsx @@ -67,7 +67,7 @@ describe("with redux dev tools", () => { { devName: "test", actions: { - increment: (n: number) => draft => { + increment: (n: number) => (draft) => { draft.a += n; }, }, @@ -78,7 +78,7 @@ describe("with redux dev tools", () => { ); expect(devToolsMock.init).toHaveBeenCalledTimes(1); - Store.produce(draft => { + Store.produce((draft) => { draft.a += 1; }); @@ -97,8 +97,8 @@ describe("with redux dev tools", () => { const newAsyncA = 10; - await Store.asyncProduce(async draft => { - draft.a = await new Promise(resolve => { + await Store.asyncProduce(async (draft) => { + draft.a = await new Promise((resolve) => { setTimeout(() => { resolve(newAsyncA); }, 500); @@ -141,7 +141,7 @@ describe("with redux dev tools", () => { const Store = createStoreContext(initialStore, { devName: "test", actions: { - increment: (n: number) => draft => { + increment: (n: number) => (draft) => { draft.a += n; }, }, @@ -167,8 +167,8 @@ describe("with redux dev tools", () => { useEffect(() => { if (newA) { if (asyncNew) { - asyncProduce(async draft => { - draft.a = await new Promise(resolve => { + asyncProduce(async (draft) => { + draft.a = await new Promise((resolve) => { setTimeout(() => { resolve(newA); }, 500); @@ -176,7 +176,7 @@ describe("with redux dev tools", () => { }); } else { act(() => { - produce(draft => { + produce((draft) => { draft.a = newA; }); }); diff --git a/test/utils/useRenderCount.ts b/test/utils/useRenderCount.ts index d085557..8cacebc 100644 --- a/test/utils/useRenderCount.ts +++ b/test/utils/useRenderCount.ts @@ -1,13 +1,13 @@ -import { useRef } from "react"; - -export function nRenderString(n: number) { - return `nRenders=${n}`; -} - -export function useRenderCount() { - const renderCountRef = useRef(0); - - renderCountRef.current += 1; - - return nRenderString(renderCountRef.current); -} +import { useRef } from "react"; + +export function nRenderString(n: number) { + return `nRenders=${n}`; +} + +export function useRenderCount() { + const renderCountRef = useRef(0); + + renderCountRef.current += 1; + + return nRenderString(renderCountRef.current); +} diff --git a/yarn.lock b/yarn.lock index b2dc918..968e26a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,7 +16,7 @@ dependencies: "@babel/highlight" "^7.8.3" -"@babel/compat-data@^7.8.4", "@babel/compat-data@^7.8.6": +"@babel/compat-data@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.6.tgz#7eeaa0dfa17e50c7d9c0832515eee09b56f04e35" integrity sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q== @@ -25,6 +25,15 @@ invariant "^2.2.4" semver "^5.5.0" +"@babel/compat-data@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c" + integrity sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g== + dependencies: + browserslist "^4.9.1" + invariant "^2.2.4" + semver "^5.5.0" + "@babel/core@7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" @@ -46,7 +55,29 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.1.6", "@babel/core@^7.4.4", "@babel/core@^7.4.5", "@babel/core@^7.7.5", "@babel/core@^7.8.6": +"@babel/core@7.9.0", "@babel/core@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" + integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.0" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helpers" "^7.9.0" + "@babel/parser" "^7.9.0" + "@babel/template" "^7.8.6" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/core@^7.1.0", "@babel/core@^7.1.6", "@babel/core@^7.4.4", "@babel/core@^7.4.5", "@babel/core@^7.7.5": version "7.8.7" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.7.tgz#b69017d221ccdeb203145ae9da269d72cf102f3b" integrity sha512-rBlqF3Yko9cynC5CCFy6+K/w2N+Sq/ff2BPy+Krp7rHlABIr5epbA7OxVeKoMHB39LZOp1UY5SuLjy6uWi35yA== @@ -77,6 +108,16 @@ lodash "^4.17.13" source-map "^0.5.0" +"@babel/generator@^7.9.0": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.4.tgz#12441e90c3b3c4159cdecf312075bf1a8ce2dbce" + integrity sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA== + dependencies: + "@babel/types" "^7.9.0" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" @@ -92,6 +133,15 @@ "@babel/helper-explode-assignable-expression" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helper-builder-react-jsx-experimental@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.9.0.tgz#066d80262ade488f9c1b1823ce5db88a4cedaa43" + integrity sha512-3xJEiyuYU4Q/Ar9BsHisgdxZsRlsShMe90URZ0e6przL26CCs8NJbDoxH94kKT17PcxlMhsCAwZd90evCo26VQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-module-imports" "^7.8.3" + "@babel/types" "^7.9.0" + "@babel/helper-builder-react-jsx@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.8.3.tgz#dee98d7d79cc1f003d80b76fe01c7f8945665ff6" @@ -100,6 +150,14 @@ "@babel/types" "^7.8.3" esutils "^2.0.0" +"@babel/helper-builder-react-jsx@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.9.0.tgz#16bf391990b57732700a3278d4d9a81231ea8d32" + integrity sha512-weiIo4gaoGgnhff54GQ3P5wsUQmnSwpkvU0r6ZHq6TzoSzKy4JxHEgnxNytaKbov2a9z/CVNyzliuCOUPEX3Jw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/types" "^7.9.0" + "@babel/helper-call-delegate@^7.8.7": version "7.8.7" resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.7.tgz#28a279c2e6c622a6233da548127f980751324cab" @@ -109,7 +167,7 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.7" -"@babel/helper-compilation-targets@^7.8.4", "@babel/helper-compilation-targets@^7.8.7": +"@babel/helper-compilation-targets@^7.8.7": version "7.8.7" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== @@ -141,6 +199,15 @@ "@babel/helper-regex" "^7.8.3" regexpu-core "^4.6.0" +"@babel/helper-create-regexp-features-plugin@^7.8.8": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" + integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + regexpu-core "^4.7.0" + "@babel/helper-define-map@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" @@ -208,6 +275,19 @@ "@babel/types" "^7.8.6" lodash "^4.17.13" +"@babel/helper-module-transforms@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" + integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.9.0" + lodash "^4.17.13" + "@babel/helper-optimise-call-expression@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" @@ -263,6 +343,11 @@ dependencies: "@babel/types" "^7.8.3" +"@babel/helper-validator-identifier@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" + integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== + "@babel/helper-wrap-function@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" @@ -282,6 +367,15 @@ "@babel/traverse" "^7.8.4" "@babel/types" "^7.8.3" +"@babel/helpers@^7.9.0": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" + integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" + "@babel/highlight@^7.0.0", "@babel/highlight@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" @@ -291,11 +385,16 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.1.6", "@babel/parser@^7.4.2", "@babel/parser@^7.4.3", "@babel/parser@^7.6.0", "@babel/parser@^7.7.0", "@babel/parser@^7.8.4", "@babel/parser@^7.8.6", "@babel/parser@^7.8.7": +"@babel/parser@^7.1.0", "@babel/parser@^7.1.6", "@babel/parser@^7.4.2", "@babel/parser@^7.4.3", "@babel/parser@^7.6.0", "@babel/parser@^7.7.0", "@babel/parser@^7.8.4", "@babel/parser@^7.8.6", "@babel/parser@^7.8.7": version "7.8.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.7.tgz#7b8facf95d25fef9534aad51c4ffecde1a61e26a" integrity sha512-9JWls8WilDXFGxs0phaXAZgpxTZhSk/yOYH2hTHC0X1yC7Z78IJfvR1vJ+rmJKq3I35td2XzXzN6ZLYlna+r/A== +"@babel/parser@^7.9.0": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" + integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== + "@babel/plugin-proposal-async-generator-functions@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" @@ -338,7 +437,7 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.0" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.7.4", "@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": +"@babel/plugin-proposal-nullish-coalescing-operator@7.8.3", "@babel/plugin-proposal-nullish-coalescing-operator@^7.7.4", "@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== @@ -346,7 +445,7 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" -"@babel/plugin-proposal-numeric-separator@7.8.3": +"@babel/plugin-proposal-numeric-separator@7.8.3", "@babel/plugin-proposal-numeric-separator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== @@ -362,6 +461,14 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" +"@babel/plugin-proposal-object-rest-spread@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz#a28993699fc13df165995362693962ba6b061d6f" + integrity sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-proposal-optional-catch-binding@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" @@ -370,6 +477,14 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" +"@babel/plugin-proposal-optional-chaining@7.9.0", "@babel/plugin-proposal-optional-chaining@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58" + integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-proposal-optional-chaining@^7.7.5", "@babel/plugin-proposal-optional-chaining@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz#ae10b3214cb25f7adb1f3bc87ba42ca10b7e2543" @@ -378,6 +493,14 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.0" +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" + integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.8" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-unicode-property-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz#b646c3adea5f98800c9ab45105ac34d06cd4a47f" @@ -435,7 +558,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== @@ -508,7 +631,7 @@ "@babel/helper-plugin-utils" "^7.8.3" lodash "^4.17.13" -"@babel/plugin-transform-classes@^7.8.3", "@babel/plugin-transform-classes@^7.8.6": +"@babel/plugin-transform-classes@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz#77534447a477cbe5995ae4aee3e39fbc8090c46d" integrity sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg== @@ -522,6 +645,20 @@ "@babel/helper-split-export-declaration" "^7.8.3" globals "^11.1.0" +"@babel/plugin-transform-classes@^7.9.0": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz#8603fc3cc449e31fdbdbc257f67717536a11af8d" + integrity sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-split-export-declaration" "^7.8.3" + globals "^11.1.0" + "@babel/plugin-transform-computed-properties@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" @@ -536,7 +673,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-dotall-regex@^7.8.3": +"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== @@ -559,7 +696,15 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-flow-strip-types@7.8.3", "@babel/plugin-transform-flow-strip-types@^7.8.3": +"@babel/plugin-transform-flow-strip-types@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz#8a3538aa40434e000b8f44a3c5c9ac7229bd2392" + integrity sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-flow" "^7.8.3" + +"@babel/plugin-transform-flow-strip-types@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.8.3.tgz#da705a655466b2a9b36046b57bf0cbcd53551bd4" integrity sha512-g/6WTWG/xbdd2exBBzMfygjX/zw4eyNC4X8pRaq7aRHRoDUCzAIu3kGYIXviOv8BjCuWm8vDBwjHcjiRNgXrPA== @@ -567,13 +712,20 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-flow" "^7.8.3" -"@babel/plugin-transform-for-of@^7.8.4", "@babel/plugin-transform-for-of@^7.8.6": +"@babel/plugin-transform-for-of@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz#a051bd1b402c61af97a27ff51b468321c7c2a085" integrity sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw== dependencies: "@babel/helper-plugin-utils" "^7.8.3" +"@babel/plugin-transform-for-of@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" + integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-function-name@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" @@ -605,6 +757,15 @@ "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" +"@babel/plugin-transform-modules-amd@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz#19755ee721912cf5bb04c07d50280af3484efef4" + integrity sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q== + dependencies: + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + "@babel/plugin-transform-modules-commonjs@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz#df251706ec331bd058a34bdd72613915f82928a5" @@ -615,6 +776,16 @@ "@babel/helper-simple-access" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" +"@babel/plugin-transform-modules-commonjs@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz#e3e72f4cbc9b4a260e30be0ea59bdf5a39748940" + integrity sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g== + dependencies: + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + "@babel/plugin-transform-modules-systemjs@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz#d8bbf222c1dbe3661f440f2f00c16e9bb7d0d420" @@ -625,6 +796,16 @@ "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" +"@babel/plugin-transform-modules-systemjs@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz#e9fd46a296fc91e009b64e07ddaa86d6f0edeb90" + integrity sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + "@babel/plugin-transform-modules-umd@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz#592d578ce06c52f5b98b02f913d653ffe972661a" @@ -633,6 +814,14 @@ "@babel/helper-module-transforms" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" +"@babel/plugin-transform-modules-umd@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" + integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== + dependencies: + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" @@ -655,7 +844,7 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-replace-supers" "^7.8.3" -"@babel/plugin-transform-parameters@^7.8.4", "@babel/plugin-transform-parameters@^7.8.7": +"@babel/plugin-transform-parameters@^7.8.7": version "7.8.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.7.tgz#66fa2f1de4129b4e0447509223ac71bda4955395" integrity sha512-brYWaEPTRimOctz2NDA3jnBbDi7SVN2T4wYuu0aqSzxC3nozFZngGaw29CJ9ZPweB7k+iFmZuoG3IVPIcXmD2g== @@ -686,6 +875,15 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" +"@babel/plugin-transform-react-jsx-development@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.9.0.tgz#3c2a130727caf00c2a293f0aed24520825dbf754" + integrity sha512-tK8hWKrQncVvrhvtOiPpKrQjfNX3DtkNLSX4ObuGcpS9p0QrGetKmlySIGR07y48Zft8WVgPakqd/bk46JrMSw== + dependencies: + "@babel/helper-builder-react-jsx-experimental" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + "@babel/plugin-transform-react-jsx-self@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.8.3.tgz#c4f178b2aa588ecfa8d077ea80d4194ee77ed702" @@ -694,6 +892,14 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-jsx" "^7.8.3" +"@babel/plugin-transform-react-jsx-self@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.9.0.tgz#f4f26a325820205239bb915bad8e06fcadabb49b" + integrity sha512-K2ObbWPKT7KUTAoyjCsFilOkEgMvFG+y0FqOl6Lezd0/13kMkkjHskVsZvblRPj1PHA44PrToaZANrryppzTvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + "@babel/plugin-transform-react-jsx-source@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.8.3.tgz#951e75a8af47f9f120db731be095d2b2c34920e0" @@ -702,6 +908,14 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-jsx" "^7.8.3" +"@babel/plugin-transform-react-jsx-source@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.9.0.tgz#89ef93025240dd5d17d3122294a093e5e0183de0" + integrity sha512-K6m3LlSnTSfRkM6FcRk8saNEeaeyG5k7AVkBU2bZK3+1zdkSED3qNdsWrUgQBeTVD2Tp3VMmerxVO2yM5iITmw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + "@babel/plugin-transform-react-jsx@^7.3.0", "@babel/plugin-transform-react-jsx@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.8.3.tgz#4220349c0390fdefa505365f68c103562ab2fc4a" @@ -711,7 +925,17 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-jsx" "^7.8.3" -"@babel/plugin-transform-regenerator@^7.4.5", "@babel/plugin-transform-regenerator@^7.8.3", "@babel/plugin-transform-regenerator@^7.8.7": +"@babel/plugin-transform-react-jsx@^7.9.1": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.9.4.tgz#86f576c8540bd06d0e95e0b61ea76d55f6cbd03f" + integrity sha512-Mjqf3pZBNLt854CK0C/kRuXAnE6H/bo7xYojP+WGtX8glDGSibcwnsWwhwoSuRg0+EBnxPC1ouVnuetUIlPSAw== + dependencies: + "@babel/helper-builder-react-jsx" "^7.9.0" + "@babel/helper-builder-react-jsx-experimental" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-jsx" "^7.8.3" + +"@babel/plugin-transform-regenerator@^7.4.5", "@babel/plugin-transform-regenerator@^7.8.7": version "7.8.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== @@ -725,7 +949,17 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-runtime@7.8.3", "@babel/plugin-transform-runtime@^7.6.0": +"@babel/plugin-transform-runtime@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz#45468c0ae74cc13204e1d3b1f4ce6ee83258af0b" + integrity sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + resolve "^1.8.1" + semver "^5.5.1" + +"@babel/plugin-transform-runtime@^7.6.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.8.3.tgz#c0153bc0a5375ebc1f1591cb7eea223adea9f169" integrity sha512-/vqUt5Yh+cgPZXXjmaG9NT8aVfThKk7G4OqkVhrXqwsC5soMn/qTCxs36rZ2QFhpfTJcjw4SNDIZ4RUb8OL4jQ== @@ -781,6 +1015,15 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-typescript" "^7.8.3" +"@babel/plugin-transform-typescript@^7.9.0": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.9.4.tgz#4bb4dde4f10bbf2d787fce9707fb09b483e33359" + integrity sha512-yeWeUkKx2auDbSxRe8MusAG+n4m9BFY/v+lPjmQDgOFX5qnySkUY5oXzkp6FwPdsYqnKay6lorXYdC0n3bZO7w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-typescript" "^7.8.3" + "@babel/plugin-transform-unicode-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" @@ -797,27 +1040,29 @@ core-js "^2.6.5" regenerator-runtime "^0.13.4" -"@babel/preset-env@7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.4.tgz#9dac6df5f423015d3d49b6e9e5fa3413e4a72c4e" - integrity sha512-HihCgpr45AnSOHRbS5cWNTINs0TwaR8BS8xIIH+QwiW8cKL0llV91njQMpeMReEPVs+1Ao0x3RLEBLtt1hOq4w== +"@babel/preset-env@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.0.tgz#a5fc42480e950ae8f5d9f8f2bbc03f52722df3a8" + integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ== dependencies: - "@babel/compat-data" "^7.8.4" - "@babel/helper-compilation-targets" "^7.8.4" + "@babel/compat-data" "^7.9.0" + "@babel/helper-compilation-targets" "^7.8.7" "@babel/helper-module-imports" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-proposal-async-generator-functions" "^7.8.3" "@babel/plugin-proposal-dynamic-import" "^7.8.3" "@babel/plugin-proposal-json-strings" "^7.8.3" "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-proposal-object-rest-spread" "^7.8.3" + "@babel/plugin-proposal-numeric-separator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.9.0" "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" - "@babel/plugin-proposal-optional-chaining" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.9.0" "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" "@babel/plugin-syntax-async-generators" "^7.8.0" "@babel/plugin-syntax-dynamic-import" "^7.8.0" "@babel/plugin-syntax-json-strings" "^7.8.0" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.8.0" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" "@babel/plugin-syntax-optional-chaining" "^7.8.0" @@ -826,26 +1071,26 @@ "@babel/plugin-transform-async-to-generator" "^7.8.3" "@babel/plugin-transform-block-scoped-functions" "^7.8.3" "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.8.3" + "@babel/plugin-transform-classes" "^7.9.0" "@babel/plugin-transform-computed-properties" "^7.8.3" "@babel/plugin-transform-destructuring" "^7.8.3" "@babel/plugin-transform-dotall-regex" "^7.8.3" "@babel/plugin-transform-duplicate-keys" "^7.8.3" "@babel/plugin-transform-exponentiation-operator" "^7.8.3" - "@babel/plugin-transform-for-of" "^7.8.4" + "@babel/plugin-transform-for-of" "^7.9.0" "@babel/plugin-transform-function-name" "^7.8.3" "@babel/plugin-transform-literals" "^7.8.3" "@babel/plugin-transform-member-expression-literals" "^7.8.3" - "@babel/plugin-transform-modules-amd" "^7.8.3" - "@babel/plugin-transform-modules-commonjs" "^7.8.3" - "@babel/plugin-transform-modules-systemjs" "^7.8.3" - "@babel/plugin-transform-modules-umd" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.9.0" + "@babel/plugin-transform-modules-commonjs" "^7.9.0" + "@babel/plugin-transform-modules-systemjs" "^7.9.0" + "@babel/plugin-transform-modules-umd" "^7.9.0" "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" "@babel/plugin-transform-new-target" "^7.8.3" "@babel/plugin-transform-object-super" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.8.4" + "@babel/plugin-transform-parameters" "^7.8.7" "@babel/plugin-transform-property-literals" "^7.8.3" - "@babel/plugin-transform-regenerator" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.7" "@babel/plugin-transform-reserved-words" "^7.8.3" "@babel/plugin-transform-shorthand-properties" "^7.8.3" "@babel/plugin-transform-spread" "^7.8.3" @@ -853,8 +1098,9 @@ "@babel/plugin-transform-template-literals" "^7.8.3" "@babel/plugin-transform-typeof-symbol" "^7.8.4" "@babel/plugin-transform-unicode-regex" "^7.8.3" - "@babel/types" "^7.8.3" - browserslist "^4.8.5" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.9.0" + browserslist "^4.9.1" core-js-compat "^3.6.2" invariant "^2.2.2" levenary "^1.1.1" @@ -931,7 +1177,30 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-flow-strip-types" "^7.8.3" -"@babel/preset-react@7.8.3", "@babel/preset-react@^7.0.0": +"@babel/preset-modules@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" + integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@7.9.1": + version "7.9.1" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.9.1.tgz#b346403c36d58c3bb544148272a0cefd9c28677a" + integrity sha512-aJBYF23MPj0RNdp/4bHnAP0NVqqZRr9kl0NAOP4nJCex6OYVio59+dnQzsAWFuogdLyeaKA1hmfUIVZkY5J+TQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-react-display-name" "^7.8.3" + "@babel/plugin-transform-react-jsx" "^7.9.1" + "@babel/plugin-transform-react-jsx-development" "^7.9.0" + "@babel/plugin-transform-react-jsx-self" "^7.9.0" + "@babel/plugin-transform-react-jsx-source" "^7.9.0" + +"@babel/preset-react@^7.0.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.8.3.tgz#23dc63f1b5b0751283e04252e78cf1d6589273d2" integrity sha512-9hx0CwZg92jGb7iHYQVgi0tOEHP/kM60CtWJQnmbATSPIQQ2xYzfoCI3EdqAhFBeeJwYMdWQuDUHMsuDbH9hyQ== @@ -942,7 +1211,15 @@ "@babel/plugin-transform-react-jsx-self" "^7.8.3" "@babel/plugin-transform-react-jsx-source" "^7.8.3" -"@babel/preset-typescript@7.8.3", "@babel/preset-typescript@^7.1.0": +"@babel/preset-typescript@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.9.0.tgz#87705a72b1f0d59df21c179f7c3d2ef4b16ce192" + integrity sha512-S4cueFnGrIbvYJgwsVFKdvOmpiL0XGw9MFW9D0vgRys5g36PBhZRL8NX8Gr2akz8XRtzq6HuDXPD/1nniagNUg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-typescript" "^7.9.0" + +"@babel/preset-typescript@^7.1.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.8.3.tgz#90af8690121beecd9a75d0cc26c6be39d1595d13" integrity sha512-qee5LgPGui9zQ0jR1TeU5/fP9L+ovoArklEqY12ek8P/wV5ZeM/VYSQYwICeoT6FfpJTekG9Ilay5PhwsOpMHA== @@ -969,12 +1246,12 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308" - integrity sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ== +"@babel/runtime@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.0.tgz#337eda67401f5b066a6f205a3113d4ac18ba495b" + integrity sha512-cTIudHnzuWLS56ik4DnRnqqNf8MkdUzV4iFFI1h7Jo9xvrpQROYaAnaSd2mHLQAzzZAPfATynX5ord6YlNYNMA== dependencies: - regenerator-runtime "^0.13.2" + regenerator-runtime "^0.13.4" "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.8.7" @@ -983,6 +1260,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.9.2": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" + integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/standalone@^7.4.5": version "7.8.7" resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.8.7.tgz#905e2ba733bb5e5916d5324d860cf855232e1dce" @@ -997,7 +1281,7 @@ "@babel/parser" "^7.8.6" "@babel/types" "^7.8.6" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff" integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A== @@ -1012,6 +1296,21 @@ globals "^11.1.0" lodash "^4.17.13" +"@babel/traverse@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892" + integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.0" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.9.0" + "@babel/types" "^7.9.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + "@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.6.0", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.8.7": version "7.8.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.7.tgz#1fc9729e1acbb2337d5b6977a63979b4819f5d1d" @@ -1021,6 +1320,15 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5" + integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng== + dependencies: + "@babel/helper-validator-identifier" "^7.9.0" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@base2/pretty-print-object@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.0.tgz#860ce718b0b73f4009e153541faff2cb6b85d047" @@ -1425,16 +1733,16 @@ dependencies: "@rollup/pluginutils" "^3.0.4" -"@rollup/plugin-node-resolve@^6.0.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-6.1.0.tgz#0d2909f4bf606ae34d43a9bc8be06a9b0c850cf0" - integrity sha512-Cv7PDIvxdE40SWilY5WgZpqfIUEaDxFxs89zCAHjqyRwlTSuql4M5hjIuc5QYJkOH0/vyiyNXKD72O+LhRipGA== +"@rollup/plugin-node-resolve@^7.1.0": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.1.tgz#8c6e59c4b28baf9d223028d0e450e06a485bb2b7" + integrity sha512-14ddhD7TnemeHE97a4rLOhobfYvUVcaYuqTnL8Ti7Jxi9V9Jr5LY7Gko4HZ5k4h4vqQM0gBQt6tsp9xXW94WPA== dependencies: - "@rollup/pluginutils" "^3.0.0" + "@rollup/pluginutils" "^3.0.6" "@types/resolve" "0.0.8" builtin-modules "^3.1.0" is-module "^1.0.0" - resolve "^1.11.1" + resolve "^1.14.2" "@rollup/plugin-replace@^2.2.1": version "2.3.1" @@ -1444,29 +1752,24 @@ "@rollup/pluginutils" "^3.0.4" magic-string "^0.25.5" -"@rollup/pluginutils@^3.0.0", "@rollup/pluginutils@^3.0.4": +"@rollup/pluginutils@^3.0.0", "@rollup/pluginutils@^3.0.4", "@rollup/pluginutils@^3.0.6": version "3.0.8" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.0.8.tgz#4e94d128d94b90699e517ef045422960d18c8fde" integrity sha512-rYGeAc4sxcZ+kPG/Tw4/fwJODC3IXHYDH4qusdN/b6aLw5LPUbzpecYbEJh4sVQGPFJxd2dBU4kc1H3oy9/bnw== dependencies: estree-walker "^1.0.1" -"@sheerun/mutationobserver-shim@^0.3.2": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25" - integrity sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw== - -"@storybook/addon-actions@^5.3.14": - version "5.3.14" - resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.3.14.tgz#aacc4d2703fc200a4565bfaa9f5870ed70a6fe32" - integrity sha512-4lKrTMzw/r6VQiBY24v72WC3jibW7pc9BIJgtPpTmTUQWTxPnkmxDfT81pV4BjS1GFH9VCnU6f5fWK+5lrQlsw== - dependencies: - "@storybook/addons" "5.3.14" - "@storybook/api" "5.3.14" - "@storybook/client-api" "5.3.14" - "@storybook/components" "5.3.14" - "@storybook/core-events" "5.3.14" - "@storybook/theming" "5.3.14" +"@storybook/addon-actions@^5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.3.17.tgz#ec7ae8fa25ef211c2a3302b6ac1d271a6247f767" + integrity sha512-06HQSBqWFyXcqV418Uv3oMHomNy9g3uCt0FHrqY3BAc7PldY1X0tW65oy//uBueaRaYKdhtRrrjfXRaPQWmDbA== + dependencies: + "@storybook/addons" "5.3.17" + "@storybook/api" "5.3.17" + "@storybook/client-api" "5.3.17" + "@storybook/components" "5.3.17" + "@storybook/core-events" "5.3.17" + "@storybook/theming" "5.3.17" core-js "^3.0.1" fast-deep-equal "^2.0.1" global "^4.3.2" @@ -1476,10 +1779,10 @@ react-inspector "^4.0.0" uuid "^3.3.2" -"@storybook/addon-docs@^5.3.14": - version "5.3.14" - resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-5.3.14.tgz#4c12d24bb035482749aeb16476bdf09dd8ddcef9" - integrity sha512-UFu0ERWbJeK/B6gXDLrCSB1M5TMz0+noAnyeUijWaeMEC1CouDL++JLlnEUyHgRLhrpLZKiajJIcm5FfNOT2gw== +"@storybook/addon-docs@^5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-5.3.17.tgz#d637388e96d554c0d8eff2b749dc65a1dabe55dc" + integrity sha512-RDAJqJpd5g5dJDt6FIOITEaNAqrlm3pkBGf5YenKlT96lDJb22Cga97mErze9tyaLGxz9MAhoT197KJtqkiQLQ== dependencies: "@babel/generator" "^7.4.0" "@babel/parser" "^7.4.2" @@ -1489,14 +1792,14 @@ "@mdx-js/loader" "^1.5.1" "@mdx-js/mdx" "^1.5.1" "@mdx-js/react" "^1.5.1" - "@storybook/addons" "5.3.14" - "@storybook/api" "5.3.14" - "@storybook/components" "5.3.14" - "@storybook/core-events" "5.3.14" + "@storybook/addons" "5.3.17" + "@storybook/api" "5.3.17" + "@storybook/components" "5.3.17" + "@storybook/core-events" "5.3.17" "@storybook/csf" "0.0.1" - "@storybook/postinstall" "5.3.14" - "@storybook/source-loader" "5.3.14" - "@storybook/theming" "5.3.14" + "@storybook/postinstall" "5.3.17" + "@storybook/source-loader" "5.3.17" + "@storybook/theming" "5.3.17" acorn "^7.1.0" acorn-jsx "^5.1.0" acorn-walk "^7.0.0" @@ -1516,15 +1819,15 @@ vue-docgen-api "^4.1.0" vue-docgen-loader "^1.3.0-beta.0" -"@storybook/addon-info@^5.3.14": - version "5.3.14" - resolved "https://registry.yarnpkg.com/@storybook/addon-info/-/addon-info-5.3.14.tgz#2d5309f12816ff51c5a141616133a2701b39173b" - integrity sha512-xZCR1OmOIT2zz0r22PSMCUvcIqCWxTTpAc3R8ByJts9j/FxlvMerAgPYhZ8R9WNFEjG2Mszwyw66pU7Oj+qipg== +"@storybook/addon-info@^5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/addon-info/-/addon-info-5.3.17.tgz#39704362d5d9688ac3d9dce96b63b868103ec32c" + integrity sha512-64+Prf+7t0MlrEmJplRwKNjXcZDqNFx+yNJ0kiWfR+Ueyq58kv5gawtImZnj2dRZNOR776GPVj30BlvaxK4jsA== dependencies: - "@storybook/addons" "5.3.14" - "@storybook/client-logger" "5.3.14" - "@storybook/components" "5.3.14" - "@storybook/theming" "5.3.14" + "@storybook/addons" "5.3.17" + "@storybook/client-logger" "5.3.17" + "@storybook/components" "5.3.17" + "@storybook/theming" "5.3.17" core-js "^3.0.1" global "^4.3.2" marksy "^8.0.0" @@ -1537,32 +1840,32 @@ react-lifecycles-compat "^3.0.4" util-deprecate "^1.0.2" -"@storybook/addon-links@^5.3.14": - version "5.3.14" - resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-5.3.14.tgz#67756a27b7d3d13163f4bd0679b91e9cc90ada5f" - integrity sha512-6qr6PNw7eCwGZ1OwApG7yiUUE+zhVzXIkxZFq3bVIreFnkNbH+nAA4pvHjKdeHK8jmTyj/ifJdiFXZSUIRhuLw== +"@storybook/addon-links@^5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-5.3.17.tgz#bccbd49108f03eb8f7a72106fbbceed671e042a9" + integrity sha512-g8PsDoHYEmgK1q1h+eLqXsWLhCj5CFyiZLrtomjCp1R0XpZA7PS8LyO5yHbxzEzEv68DHlU5rwQnNnkbGnr7XA== dependencies: - "@storybook/addons" "5.3.14" - "@storybook/client-logger" "5.3.14" - "@storybook/core-events" "5.3.14" + "@storybook/addons" "5.3.17" + "@storybook/client-logger" "5.3.17" + "@storybook/core-events" "5.3.17" "@storybook/csf" "0.0.1" - "@storybook/router" "5.3.14" + "@storybook/router" "5.3.17" core-js "^3.0.1" global "^4.3.2" prop-types "^15.7.2" qs "^6.6.0" ts-dedent "^1.1.0" -"@storybook/addon-storysource@^5.3.14": - version "5.3.14" - resolved "https://registry.yarnpkg.com/@storybook/addon-storysource/-/addon-storysource-5.3.14.tgz#da820431638f36e961f74c6f4e4dea4b7d9ec9f9" - integrity sha512-ctNmSkvnMGmYUUjdzKtuA71CsxNfQ9/FSDWV7pbaMNNsq05QVT6CcC9as80wcw32RdD58kHWXfPuNZ2Z8s3CMQ== +"@storybook/addon-storysource@^5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/addon-storysource/-/addon-storysource-5.3.17.tgz#127a5983af9e5877d6b1ab1dfdcf10448493174a" + integrity sha512-P91U67lbrtyUtdATlzNIYyfocEGQf06B/vH8luAN6FFt1V4JL/CWwx2LNDOC19ArMtrz9slAiE73+03QOcsgdg== dependencies: - "@storybook/addons" "5.3.14" - "@storybook/components" "5.3.14" - "@storybook/router" "5.3.14" - "@storybook/source-loader" "5.3.14" - "@storybook/theming" "5.3.14" + "@storybook/addons" "5.3.17" + "@storybook/components" "5.3.17" + "@storybook/router" "5.3.17" + "@storybook/source-loader" "5.3.17" + "@storybook/theming" "5.3.17" core-js "^3.0.1" estraverse "^4.2.0" loader-utils "^1.2.3" @@ -1572,7 +1875,7 @@ regenerator-runtime "^0.13.3" util-deprecate "^1.0.2" -"@storybook/addons@5.3.14", "@storybook/addons@^5.2.0", "@storybook/addons@^5.3.14": +"@storybook/addons@5.3.14", "@storybook/addons@^5.2.0": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.3.14.tgz#ff96c2c46a617f777c3660395017d2aef5319f19" integrity sha512-zoN1MYlArdThp93i+Ogil/pihyx8n7nkrdSO0j9HUh6jUsGeFFEluPQZdRFte9NIoY6ZWSWwuEMDgrv2Pw9r2Q== @@ -1585,6 +1888,19 @@ global "^4.3.2" util-deprecate "^1.0.2" +"@storybook/addons@5.3.17", "@storybook/addons@^5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.3.17.tgz#8efab65904040b0b8578eedc9a5772dbcbf6fa83" + integrity sha512-zg6O1bmffRsHXJOWAnSD2O3tPnVMoD8Yfu+a5zBVXDiUP1E/TGzgjjjYBUUCU3yQg1Ted5rIn4o6ql/rZNNlgA== + dependencies: + "@storybook/api" "5.3.17" + "@storybook/channels" "5.3.17" + "@storybook/client-logger" "5.3.17" + "@storybook/core-events" "5.3.17" + core-js "^3.0.1" + global "^4.3.2" + util-deprecate "^1.0.2" + "@storybook/api@5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.3.14.tgz#8c2bb226a4a5de7974ee2ccce36986b72f462f1b" @@ -1611,6 +1927,32 @@ telejson "^3.2.0" util-deprecate "^1.0.2" +"@storybook/api@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.3.17.tgz#1c0dad3309afef6b0a5585cb59c65824fb4d2721" + integrity sha512-G40jtXFY10hQo6GSw5JeFYt41loD4+7s0uU18Rm6lfa/twOgp6vqqyDCWDvpRRxRBB5uDIKKHLt13X9gWe8tQQ== + dependencies: + "@reach/router" "^1.2.1" + "@storybook/channels" "5.3.17" + "@storybook/client-logger" "5.3.17" + "@storybook/core-events" "5.3.17" + "@storybook/csf" "0.0.1" + "@storybook/router" "5.3.17" + "@storybook/theming" "5.3.17" + "@types/reach__router" "^1.2.3" + core-js "^3.0.1" + fast-deep-equal "^2.0.1" + global "^4.3.2" + lodash "^4.17.15" + memoizerific "^1.11.3" + prop-types "^15.6.2" + react "^16.8.3" + semver "^6.0.0" + shallow-equal "^1.1.0" + store2 "^2.7.1" + telejson "^3.2.0" + util-deprecate "^1.0.2" + "@storybook/channel-postmessage@5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.3.14.tgz#768c87411d98caf09fdd92539b9edaaed26d5965" @@ -1622,6 +1964,17 @@ global "^4.3.2" telejson "^3.2.0" +"@storybook/channel-postmessage@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.3.17.tgz#807b6316cd0e52d9f27363d5092ad1cd896b694c" + integrity sha512-1aSQNeO2+roPRgMFjW3AWTO3uS93lbCMUTYCBdi20md4bQ9SutJy33rynCQcWuMj1prCQ2Ekz4BGhdcIQVKlzg== + dependencies: + "@storybook/channels" "5.3.17" + "@storybook/client-logger" "5.3.17" + core-js "^3.0.1" + global "^4.3.2" + telejson "^3.2.0" + "@storybook/channels@5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.3.14.tgz#9969e27761a80afb495bc1475f0173f9b6ef5a76" @@ -1629,6 +1982,13 @@ dependencies: core-js "^3.0.1" +"@storybook/channels@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.3.17.tgz#74eccb10c2395499da6a290bcd0272d6d6c7c5b2" + integrity sha512-5hlBRbyk+YxC4KgecYG8wWwB2v1BzRJXhSlemFDOQk9wx37gVpne+rBydEtNFO4InmaZf6tKbBcpH0wBFLdWYA== + dependencies: + core-js "^3.0.1" + "@storybook/client-api@5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.3.14.tgz#5f4b199d2f2b193f9f5a856c5eb8be43a9113d12" @@ -1652,6 +2012,29 @@ ts-dedent "^1.1.0" util-deprecate "^1.0.2" +"@storybook/client-api@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.3.17.tgz#fc1d247caf267ebcc6ddf957fca7e02ae752d99e" + integrity sha512-oe55FPTGVL2k+j45eCN3oE7ePkE4VpgUQ/dhJbjU0R2L+HyRyBhd0wnMYj1f5E8uVNbtjFYAtbjjgcf1R1imeg== + dependencies: + "@storybook/addons" "5.3.17" + "@storybook/channel-postmessage" "5.3.17" + "@storybook/channels" "5.3.17" + "@storybook/client-logger" "5.3.17" + "@storybook/core-events" "5.3.17" + "@storybook/csf" "0.0.1" + "@types/webpack-env" "^1.15.0" + core-js "^3.0.1" + eventemitter3 "^4.0.0" + global "^4.3.2" + is-plain-object "^3.0.0" + lodash "^4.17.15" + memoizerific "^1.11.3" + qs "^6.6.0" + stable "^0.1.8" + ts-dedent "^1.1.0" + util-deprecate "^1.0.2" + "@storybook/client-logger@5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.3.14.tgz#85068f1b665a52163191eb5976f1581bce6df0e4" @@ -1659,6 +2042,13 @@ dependencies: core-js "^3.0.1" +"@storybook/client-logger@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.3.17.tgz#bf9c7ef52da75a5c1f2c5d74724442224deea6e4" + integrity sha512-GYYvVGIOs+fq11LXXy7x2sr3hhC9LMI1jtIckjKV1dsY9MJ5g22M+Wl5Iw4nf6VMWsqcN9LSlYE+u/H+Q2uCHw== + dependencies: + core-js "^3.0.1" + "@storybook/components@5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.3.14.tgz#0f2f90113674e14ee74d5d16d6b3b1220cb0fa16" @@ -1686,6 +2076,33 @@ simplebar-react "^1.0.0-alpha.6" ts-dedent "^1.1.0" +"@storybook/components@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.3.17.tgz#287430fc9c5f59b1d3590b50b3c7688355b22639" + integrity sha512-M5oqbzcqFX4VDNI8siT3phT7rmFwChQ/xPwX9ygByBsZCoNuLMzafavfTOhZvxCPiliFbBxmxtK/ibCsSzuKZg== + dependencies: + "@storybook/client-logger" "5.3.17" + "@storybook/theming" "5.3.17" + "@types/react-syntax-highlighter" "11.0.4" + "@types/react-textarea-autosize" "^4.3.3" + core-js "^3.0.1" + global "^4.3.2" + lodash "^4.17.15" + markdown-to-jsx "^6.9.1" + memoizerific "^1.11.3" + polished "^3.3.1" + popper.js "^1.14.7" + prop-types "^15.7.2" + react "^16.8.3" + react-dom "^16.8.3" + react-focus-lock "^2.1.0" + react-helmet-async "^1.0.2" + react-popper-tooltip "^2.8.3" + react-syntax-highlighter "^11.0.2" + react-textarea-autosize "^7.1.0" + simplebar-react "^1.0.0-alpha.6" + ts-dedent "^1.1.0" + "@storybook/core-events@5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.3.14.tgz#d476eea7032670db1a84bef7e5baadb04c2de529" @@ -1693,7 +2110,14 @@ dependencies: core-js "^3.0.1" -"@storybook/core@5.3.14", "@storybook/core@^5.3.14": +"@storybook/core-events@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.3.17.tgz#698ce0a36c29fe8fa04608f56ccca53aa1d31638" + integrity sha512-DOeX9fpeGW4o9Gocxa4VW9wAlAyfIVNDTzq0wVvvMBthTTo9u58NmndglEMDgDa2Cq6iAIPh7vz2bRJCNexzLw== + dependencies: + core-js "^3.0.1" + +"@storybook/core@5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.3.14.tgz#510f204219695045f249733bf94018e52c7b1448" integrity sha512-Y57cchCRw1vvZe8OhMmgAkaHciGLm2eztdfzZMUmeHH8csBt/0RO5gYzOhWDGgdC2D9HSlaysZEDJ6sH3PChlw== @@ -1772,6 +2196,85 @@ webpack-hot-middleware "^2.25.0" webpack-virtual-modules "^0.2.0" +"@storybook/core@5.3.17", "@storybook/core@^5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.3.17.tgz#abd09dc416f87c7954ef3615bc3f4898c93e2b45" + integrity sha512-H6G8ygjb4RSVSKPdWz6su3Nvzxm8CfrHuCyUo4DLC46mirXfYRrJV1HiwXriViqoZV4gFbpaNKTDzTl/QKFDAg== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.7.0" + "@babel/plugin-proposal-object-rest-spread" "^7.6.2" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/plugin-transform-react-constant-elements" "^7.2.0" + "@babel/preset-env" "^7.4.5" + "@storybook/addons" "5.3.17" + "@storybook/channel-postmessage" "5.3.17" + "@storybook/client-api" "5.3.17" + "@storybook/client-logger" "5.3.17" + "@storybook/core-events" "5.3.17" + "@storybook/csf" "0.0.1" + "@storybook/node-logger" "5.3.17" + "@storybook/router" "5.3.17" + "@storybook/theming" "5.3.17" + "@storybook/ui" "5.3.17" + airbnb-js-shims "^2.2.1" + ansi-to-html "^0.6.11" + autoprefixer "^9.7.2" + babel-plugin-add-react-displayname "^0.0.5" + babel-plugin-emotion "^10.0.20" + babel-plugin-macros "^2.7.0" + babel-preset-minify "^0.5.0 || 0.6.0-alpha.5" + boxen "^4.1.0" + case-sensitive-paths-webpack-plugin "^2.2.0" + chalk "^3.0.0" + cli-table3 "0.5.1" + commander "^4.0.1" + core-js "^3.0.1" + corejs-upgrade-webpack-plugin "^2.2.0" + css-loader "^3.0.0" + detect-port "^1.3.0" + dotenv-webpack "^1.7.0" + ejs "^2.7.4" + express "^4.17.0" + file-loader "^4.2.0" + file-system-cache "^1.0.5" + find-cache-dir "^3.0.0" + find-up "^4.1.0" + fs-extra "^8.0.1" + glob-base "^0.3.0" + global "^4.3.2" + html-webpack-plugin "^4.0.0-beta.2" + inquirer "^7.0.0" + interpret "^2.0.0" + ip "^1.1.5" + json5 "^2.1.1" + lazy-universal-dotenv "^3.0.1" + micromatch "^4.0.2" + node-fetch "^2.6.0" + open "^7.0.0" + pnp-webpack-plugin "1.5.0" + postcss-flexbugs-fixes "^4.1.0" + postcss-loader "^3.0.0" + pretty-hrtime "^1.0.3" + qs "^6.6.0" + raw-loader "^3.1.0" + react-dev-utils "^9.0.0" + regenerator-runtime "^0.13.3" + resolve "^1.11.0" + resolve-from "^5.0.0" + semver "^6.0.0" + serve-favicon "^2.5.0" + shelljs "^0.8.3" + style-loader "^1.0.0" + terser-webpack-plugin "^2.1.2" + ts-dedent "^1.1.0" + unfetch "^4.1.0" + url-loader "^2.0.1" + util-deprecate "^1.0.2" + webpack "^4.33.0" + webpack-dev-middleware "^3.7.0" + webpack-hot-middleware "^2.25.0" + webpack-virtual-modules "^0.2.0" + "@storybook/csf@0.0.1": version "0.0.1" resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.0.1.tgz#95901507dc02f0bc6f9ac8ee1983e2fc5bb98ce6" @@ -1791,23 +2294,36 @@ pretty-hrtime "^1.0.3" regenerator-runtime "^0.13.3" -"@storybook/postinstall@5.3.14": - version "5.3.14" - resolved "https://registry.yarnpkg.com/@storybook/postinstall/-/postinstall-5.3.14.tgz#f17f4963036d0746503f863b511a112b3a85e289" - integrity sha512-qziSInBJeSr25Ba0TyF0f0z8rjgIqTRjFcSpNSVPWHlN366HpiWC2qTxvHn9rJisl8c0P5QnfTQeCvgyenNy6Q== +"@storybook/node-logger@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.3.17.tgz#f3ad5bf9dd74d8e1cdfb8d831d66a80c5039cf4c" + integrity sha512-onfcxl37BYZI1HGuPI9MelkyUWjn7NpfN8RUYdqG9P6WKiIY5xbpG0V6qod5jvIKIypK0NmfJTtneOu46L/oDg== dependencies: + "@types/npmlog" "^4.1.2" + chalk "^3.0.0" core-js "^3.0.1" + npmlog "^4.1.2" + pretty-hrtime "^1.0.3" + regenerator-runtime "^0.13.3" -"@storybook/preset-create-react-app@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@storybook/preset-create-react-app/-/preset-create-react-app-2.0.0.tgz#f6bc430cd3dcfcf42490505d9f0dbc5dbc84ca3e" - integrity sha512-EvYvQWtJRiLrO3aL6fnawDyujMXQOSD1KO74k60cE8XLASm9slGtzeyrz/Awpb9eZHFS8dUx9cyMv1dm53CxJw== +"@storybook/postinstall@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/postinstall/-/postinstall-5.3.17.tgz#b4168e395a7d9ec2b58103a1ff13278bdb25d2d7" + integrity sha512-bWmXwux1J4iVC6/tLJIfjK02VUMTo4G9g09BxboRDYLB+Y1byQYK8dcZIqVVZag33AbZWFL9s4QA2cCb0KBFsg== + dependencies: + core-js "^3.0.1" + +"@storybook/preset-create-react-app@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@storybook/preset-create-react-app/-/preset-create-react-app-2.1.0.tgz#842c50f52f8ec3d4c386b399763d3539011a8bdf" + integrity sha512-jfE+RVbcRKzCms1hXNBj9LEusznCvwjpCwGiBk66iW9NxpRryJhZXYxR+X6ngXjnqUXnsgum5vEiDAbqFvhl0Q== dependencies: "@storybook/node-logger" "^5.3.14" "@types/webpack" "^4.41.7" + pnp-webpack-plugin "^1.6.4" semver "^7.1.3" -"@storybook/react@^5.2.0", "@storybook/react@^5.3.14": +"@storybook/react@^5.2.0": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/react/-/react-5.3.14.tgz#6715d9ee64e1c7b5c1e45cdbbf6df809bad60b8c" integrity sha512-8n0oCkaxFMrimngxnISEQFkHGSF5z65Lh1XPypjIndIJ0b/IVWRJcUEh3M3xOaydFatEG+lfQbF/5OznyYEefA== @@ -1834,6 +2350,33 @@ ts-dedent "^1.1.0" webpack "^4.33.0" +"@storybook/react@^5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/react/-/react-5.3.17.tgz#403b58606211a9ca87d40e38d55186b3e088640d" + integrity sha512-FQLH3q2Ge68oLBaTge7wl5Y1KkB+pqL36llor7TOO9IxGLF6o2t2qillWnrgX6yZUpkvJK8MgkZW1/N3tslw4Q== + dependencies: + "@babel/plugin-transform-react-constant-elements" "^7.6.3" + "@babel/preset-flow" "^7.0.0" + "@babel/preset-react" "^7.0.0" + "@storybook/addons" "5.3.17" + "@storybook/core" "5.3.17" + "@storybook/node-logger" "5.3.17" + "@svgr/webpack" "^4.0.3" + "@types/webpack-env" "^1.15.0" + babel-plugin-add-react-displayname "^0.0.5" + babel-plugin-named-asset-import "^0.3.1" + babel-plugin-react-docgen "^4.0.0" + core-js "^3.0.1" + global "^4.3.2" + lodash "^4.17.15" + mini-css-extract-plugin "^0.7.0" + prop-types "^15.7.2" + react-dev-utils "^9.0.0" + regenerator-runtime "^0.13.3" + semver "^6.0.0" + ts-dedent "^1.1.0" + webpack "^4.33.0" + "@storybook/router@5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.3.14.tgz#6535267624da5f54971c37e497df1c161f65be8f" @@ -1849,30 +2392,63 @@ qs "^6.6.0" util-deprecate "^1.0.2" -"@storybook/source-loader@5.3.14": - version "5.3.14" - resolved "https://registry.yarnpkg.com/@storybook/source-loader/-/source-loader-5.3.14.tgz#62428a1b12fc9f51f24d27194a06d343366d8bf5" - integrity sha512-j4z83KLfiYrFi/KDwX9K6LsLfFo0vbsWProUMjVV/Hapio/ozvFm2YAYc4UWrYkzg+DM8/OKrK5wXLf18HcHDA== +"@storybook/router@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.3.17.tgz#4db96b45f39b25a3f7a4e2899c36e7e9e4ba6108" + integrity sha512-ANsiehGRTVSremgTW0Vt47dQ4JA86a4/w/4G6QqHU8Cm4jO3cw/wAcCxlzfcgCXOUiq+SuyPTU43+0O5uBx33g== dependencies: - "@storybook/addons" "5.3.14" - "@storybook/client-logger" "5.3.14" + "@reach/router" "^1.2.1" + "@storybook/csf" "0.0.1" + "@types/reach__router" "^1.2.3" + core-js "^3.0.1" + global "^4.3.2" + lodash "^4.17.15" + memoizerific "^1.11.3" + qs "^6.6.0" + util-deprecate "^1.0.2" + +"@storybook/source-loader@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/source-loader/-/source-loader-5.3.17.tgz#f407aed52bc758b2c0c760d28b4525b8337e6944" + integrity sha512-VfY+NIAvyasHhLtVC9CsLaTgVWPmjt4nf1mZE+I69+S+qrk1KZeLCsafTOugkm3QMNJ/BXelwkKaYrutrnXLiQ== + dependencies: + "@storybook/addons" "5.3.17" + "@storybook/client-logger" "5.3.17" "@storybook/csf" "0.0.1" core-js "^3.0.1" estraverse "^4.2.0" global "^4.3.2" - loader-utils "^1.2.3" - prettier "^1.16.4" + loader-utils "^1.2.3" + prettier "^1.16.4" + prop-types "^15.7.2" + regenerator-runtime "^0.13.3" + +"@storybook/theming@5.3.14": + version "5.3.14" + resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.3.14.tgz#4923739ad0d7d673b7844f27da8a3c6cf118790f" + integrity sha512-raqXC3yJycEt1CrCAfnBYUA6pyJI80E9M26EeQl3UfytJOL6euprOi+D17QvxqBn7jmmf9ZDw5XRkvJhQ17Y7Q== + dependencies: + "@emotion/core" "^10.0.20" + "@emotion/styled" "^10.0.17" + "@storybook/client-logger" "5.3.14" + core-js "^3.0.1" + deep-object-diff "^1.1.0" + emotion-theming "^10.0.19" + global "^4.3.2" + memoizerific "^1.11.3" + polished "^3.3.1" prop-types "^15.7.2" - regenerator-runtime "^0.13.3" + resolve-from "^5.0.0" + ts-dedent "^1.1.0" -"@storybook/theming@5.3.14": - version "5.3.14" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.3.14.tgz#4923739ad0d7d673b7844f27da8a3c6cf118790f" - integrity sha512-raqXC3yJycEt1CrCAfnBYUA6pyJI80E9M26EeQl3UfytJOL6euprOi+D17QvxqBn7jmmf9ZDw5XRkvJhQ17Y7Q== +"@storybook/theming@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.3.17.tgz#cf6278c4857229c7167faf04d5b2206bc5ee04e1" + integrity sha512-4JeOZnDDHtb4LOt5sXe/s1Jhbb2UPsr8zL9NWmKJmTsgnyTvBipNHOmFYDUsIacB5K4GXSqm+cZ7Z4AkUgWCDw== dependencies: "@emotion/core" "^10.0.20" "@emotion/styled" "^10.0.17" - "@storybook/client-logger" "5.3.14" + "@storybook/client-logger" "5.3.17" core-js "^3.0.1" deep-object-diff "^1.1.0" emotion-theming "^10.0.19" @@ -1923,6 +2499,46 @@ telejson "^3.2.0" util-deprecate "^1.0.2" +"@storybook/ui@5.3.17": + version "5.3.17" + resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.3.17.tgz#2d47617896a2d928fb79dc8a0e709cee9b57cc50" + integrity sha512-5S9r70QbtNKu8loa5pfO5lLX9coF/ZqesEKcanfvuSwqCSg/Z51UwFCuO6eNhVlpXzyZXi5d8qKbZlbf+uvDAA== + dependencies: + "@emotion/core" "^10.0.20" + "@storybook/addons" "5.3.17" + "@storybook/api" "5.3.17" + "@storybook/channels" "5.3.17" + "@storybook/client-logger" "5.3.17" + "@storybook/components" "5.3.17" + "@storybook/core-events" "5.3.17" + "@storybook/router" "5.3.17" + "@storybook/theming" "5.3.17" + copy-to-clipboard "^3.0.8" + core-js "^3.0.1" + core-js-pure "^3.0.1" + emotion-theming "^10.0.19" + fast-deep-equal "^2.0.1" + fuse.js "^3.4.6" + global "^4.3.2" + lodash "^4.17.15" + markdown-to-jsx "^6.9.3" + memoizerific "^1.11.3" + polished "^3.3.1" + prop-types "^15.7.2" + qs "^6.6.0" + react "^16.8.3" + react-dom "^16.8.3" + react-draggable "^4.0.3" + react-helmet-async "^1.0.2" + react-hotkeys "2.0.0" + react-sizeme "^2.6.7" + regenerator-runtime "^0.13.2" + resolve-from "^5.0.0" + semver "^6.0.0" + store2 "^2.7.1" + telejson "^3.2.0" + util-deprecate "^1.0.2" + "@svgr/babel-plugin-add-jsx-attribute@^4.2.0": version "4.2.0" resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1" @@ -2026,18 +2642,16 @@ "@svgr/plugin-svgo" "^4.3.1" loader-utils "^1.2.3" -"@testing-library/dom@^6.15.0": - version "6.15.0" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-6.15.0.tgz#042abea7b4685b70d9a919100da9024507dc20bb" - integrity sha512-8N24c4XwOigPicwc8n4ECgEoJW2/mMzRJBxu4Uo0zhLERZTbNzqpL5fyCigu7JGUXX+ITuiK4z9/lnHbYRHLwQ== +"@testing-library/dom@^7.0.2": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.1.1.tgz#bf890c2468bd717ffd8b336a819686907fbe4daa" + integrity sha512-CxspAIntyK2joLUJChOZgnwx7xBxdBC8ugwP+Z49Dd9O3sGVs0wHkOUOsfBVXHgBjmdZk8E3SyHZVrMRd9O1sA== dependencies: - "@babel/runtime" "^7.8.4" - "@sheerun/mutationobserver-shim" "^0.3.2" - "@types/testing-library__dom" "^6.12.1" + "@babel/runtime" "^7.9.2" + "@types/testing-library__dom" "^7.0.0" aria-query "^4.0.2" - dom-accessibility-api "^0.3.0" + dom-accessibility-api "^0.4.2" pretty-format "^25.1.0" - wait-for-expect "^3.0.2" "@testing-library/jest-dom@^5.1.1": version "5.1.1" @@ -2063,14 +2677,14 @@ "@babel/runtime" "^7.5.4" "@types/testing-library__react-hooks" "^3.0.0" -"@testing-library/react@^9.4.1": - version "9.5.0" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-9.5.0.tgz#71531655a7890b61e77a1b39452fbedf0472ca5e" - integrity sha512-di1b+D0p+rfeboHO5W7gTVeZDIK5+maEgstrZbWZSSvxDyfDRkkyBE1AJR5Psd6doNldluXlCWqXriUfqu/9Qg== +"@testing-library/react@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-10.0.1.tgz#4f5e2a8836257c5bd3df640b21d7bea5a0d83ead" + integrity sha512-sMHWud2dcymOzq2AhEniICSijEwKeTiBX+K0y36FYNY7wH2t0SIP1o732Bf5dDY0jYoMC2hj2UJSVpZC/rDsWg== dependencies: - "@babel/runtime" "^7.8.4" - "@testing-library/dom" "^6.15.0" - "@types/testing-library__react" "^9.1.2" + "@babel/runtime" "^7.8.7" + "@testing-library/dom" "^7.0.2" + "@types/testing-library__react" "^9.1.3" "@types/anymatch@*": version "1.3.1" @@ -2186,7 +2800,7 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" -"@types/jest@*", "@types/jest@^25.1.3": +"@types/jest@*", "@types/jest@^25.1.4": version "25.1.4" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.1.4.tgz#9e9f1e59dda86d3fd56afce71d1ea1b331f6f760" integrity sha512-QDDY2uNAhCV7TMCITrxz+MRk1EizcsevzfeS6LykIlq2V1E5oO4wXG8V2ZEd9w7Snxeeagk46YbMgZ8ESHx3sw== @@ -2258,6 +2872,13 @@ dependencies: "@types/react" "*" +"@types/react-syntax-highlighter@11.0.4": + version "11.0.4" + resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.4.tgz#d86d17697db62f98046874f62fdb3e53a0bbc4cd" + integrity sha512-9GfTo3a0PHwQeTVoqs0g5bS28KkSY48pp5659wA+Dp4MqceDEa8EHBqrllJvvtyusszyJhViUEap0FDvlk/9Zg== + dependencies: + "@types/react" "*" + "@types/react-test-renderer@*", "@types/react-test-renderer@^16.9.2": version "16.9.2" resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.9.2.tgz#e1c408831e8183e5ad748fdece02214a7c2ab6c5" @@ -2272,10 +2893,10 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@16.9.23", "@types/react@^16.9.23": - version "16.9.23" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.23.tgz#1a66c6d468ba11a8943ad958a8cb3e737568271c" - integrity sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw== +"@types/react@*", "@types/react@16.9.25", "@types/react@^16.9.25": + version "16.9.25" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.25.tgz#6ae2159b40138c792058a23c3c04fd3db49e929e" + integrity sha512-Dlj2V72cfYLPNscIG3/SMUOzhzj7GK3bpSrfefwt2YT9GLynvLCCZjbhyF6VsT0q0+aRACRX03TDJGb7cA0cqg== dependencies: "@types/prop-types" "*" csstype "^2.2.0" @@ -2287,14 +2908,6 @@ dependencies: "@types/node" "*" -"@types/rimraf@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.3.tgz#0199a46af106729ba14213fda7b981278d8c84f2" - integrity sha512-dZfyfL/u9l/oi984hEXdmAjX3JHry7TLWw43u1HQ8HhPv6KtfxnrZ3T/bleJ0GEvnk9t5sM7eePkgMqz3yBcGg== - dependencies: - "@types/glob" "*" - "@types/node" "*" - "@types/shelljs@^0.8.5": version "0.8.6" resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.6.tgz#45193a51df99e0f00513c39a2152832399783221" @@ -2327,20 +2940,34 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" integrity sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== -"@types/testing-library__dom@*", "@types/testing-library__dom@^6.12.1": +"@types/testing-library__dom@*": version "6.14.0" resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-6.14.0.tgz#1aede831cb4ed4a398448df5a2c54b54a365644e" integrity sha512-sMl7OSv0AvMOqn1UJ6j1unPMIHRXen0Ita1ujnMX912rrOcawe4f7wu0Zt9GIQhBhJvH2BaibqFgQ3lP+Pj2hA== dependencies: pretty-format "^24.3.0" -"@types/testing-library__jest-dom@^5.0.0", "@types/testing-library__jest-dom@^5.0.1": +"@types/testing-library__dom@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-7.0.0.tgz#c0fb7d1c2495a3d26f19342102142d47500f0319" + integrity sha512-1TEPWyqQ6IQ7R1hCegZmFSA3KrBQjdzJW7yC9ybpRcFst5XuPOqBGNr0mTAKbxwI/TrTyc1skeyLJrpcvAf93w== + dependencies: + pretty-format "^25.1.0" + +"@types/testing-library__jest-dom@^5.0.0": version "5.0.1" resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.0.1.tgz#cc7f384535a3d9597e27f58d38a795f5c137cc53" integrity sha512-GiPXQBVF9O4DG9cssD2d266vozBJvC5Tnv6aeH5ujgYJgys1DYm9AFCz7YC+STR5ksGxq3zCt+yP8T1wbk2DFg== dependencies: "@types/jest" "*" +"@types/testing-library__jest-dom@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.0.2.tgz#89b782e0f187fe1e80d6375133da74182ba02065" + integrity sha512-dZP+/WHndgCSmdaImITy0KhjGAa9c0hlGGkzefbtrPFpnGEPZECDA0zyvfSp8RKhHECJJSKHFExjOwzo0rHyIA== + dependencies: + "@types/jest" "*" + "@types/testing-library__react-hooks@^3.0.0", "@types/testing-library__react-hooks@^3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@types/testing-library__react-hooks/-/testing-library__react-hooks-3.2.0.tgz#52f3a109bef06080e3b1e3ae7ea1c014ce859897" @@ -2349,7 +2976,7 @@ "@types/react" "*" "@types/react-test-renderer" "*" -"@types/testing-library__react@^9.1.2": +"@types/testing-library__react@^9.1.3": version "9.1.3" resolved "https://registry.yarnpkg.com/@types/testing-library__react/-/testing-library__react-9.1.3.tgz#35eca61cc6ea923543796f16034882a1603d7302" integrity sha512-iCdNPKU3IsYwRK9JieSYAiX0+aYDXOGAmrC/3/M7AqqSDKnWWVv07X+Zk1uFSL7cMTUYzv4lQRfohucEocn5/w== @@ -2396,6 +3023,18 @@ "@types/webpack-sources" "*" source-map "^0.6.0" +"@types/webpack@^4.41.8": + version "4.41.8" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.8.tgz#d2244f5f612ee30230a5c8c4ae678bce90d27277" + integrity sha512-mh4litLHTlDG84TGCFv1pZldndI34vkrW9Mks++Zx4KET7DRMoCXUvLbTISiuF4++fMgNnhV9cc1nCXJQyBYbQ== + dependencies: + "@types/anymatch" "*" + "@types/node" "*" + "@types/tapable" "*" + "@types/uglify-js" "*" + "@types/webpack-sources" "*" + source-map "^0.6.0" + "@types/yargs-parser@*": version "15.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" @@ -2467,21 +3106,45 @@ "@webassemblyjs/helper-wasm-bytecode" "1.8.5" "@webassemblyjs/wast-parser" "1.8.5" +"@webassemblyjs/ast@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" + integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== + dependencies: + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" + "@webassemblyjs/floating-point-hex-parser@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== +"@webassemblyjs/floating-point-hex-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" + integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== + "@webassemblyjs/helper-api-error@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== +"@webassemblyjs/helper-api-error@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" + integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== + "@webassemblyjs/helper-buffer@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== +"@webassemblyjs/helper-buffer@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" + integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== + "@webassemblyjs/helper-code-frame@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" @@ -2489,11 +3152,23 @@ dependencies: "@webassemblyjs/wast-printer" "1.8.5" +"@webassemblyjs/helper-code-frame@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" + integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== + dependencies: + "@webassemblyjs/wast-printer" "1.9.0" + "@webassemblyjs/helper-fsm@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== +"@webassemblyjs/helper-fsm@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" + integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== + "@webassemblyjs/helper-module-context@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" @@ -2502,11 +3177,23 @@ "@webassemblyjs/ast" "1.8.5" mamacro "^0.0.3" +"@webassemblyjs/helper-module-context@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" + integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== +"@webassemblyjs/helper-wasm-bytecode@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" + integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== + "@webassemblyjs/helper-wasm-section@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" @@ -2517,6 +3204,16 @@ "@webassemblyjs/helper-wasm-bytecode" "1.8.5" "@webassemblyjs/wasm-gen" "1.8.5" +"@webassemblyjs/helper-wasm-section@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" + integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/ieee754@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" @@ -2524,6 +3221,13 @@ dependencies: "@xtuc/ieee754" "^1.2.0" +"@webassemblyjs/ieee754@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" + integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + "@webassemblyjs/leb128@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" @@ -2531,11 +3235,23 @@ dependencies: "@xtuc/long" "4.2.2" +"@webassemblyjs/leb128@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" + integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== + dependencies: + "@xtuc/long" "4.2.2" + "@webassemblyjs/utf8@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== +"@webassemblyjs/utf8@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" + integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== + "@webassemblyjs/wasm-edit@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" @@ -2550,6 +3266,20 @@ "@webassemblyjs/wasm-parser" "1.8.5" "@webassemblyjs/wast-printer" "1.8.5" +"@webassemblyjs/wasm-edit@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" + integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/helper-wasm-section" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-opt" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + "@webassemblyjs/wast-printer" "1.9.0" + "@webassemblyjs/wasm-gen@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" @@ -2561,6 +3291,17 @@ "@webassemblyjs/leb128" "1.8.5" "@webassemblyjs/utf8" "1.8.5" +"@webassemblyjs/wasm-gen@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" + integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" + "@webassemblyjs/wasm-opt@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" @@ -2571,6 +3312,16 @@ "@webassemblyjs/wasm-gen" "1.8.5" "@webassemblyjs/wasm-parser" "1.8.5" +"@webassemblyjs/wasm-opt@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" + integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + "@webassemblyjs/wasm-parser@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" @@ -2583,6 +3334,18 @@ "@webassemblyjs/leb128" "1.8.5" "@webassemblyjs/utf8" "1.8.5" +"@webassemblyjs/wasm-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" + integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" + "@webassemblyjs/wast-parser@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" @@ -2595,6 +3358,18 @@ "@webassemblyjs/helper-fsm" "1.8.5" "@xtuc/long" "4.2.2" +"@webassemblyjs/wast-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" + integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/floating-point-hex-parser" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-code-frame" "1.9.0" + "@webassemblyjs/helper-fsm" "1.9.0" + "@xtuc/long" "4.2.2" + "@webassemblyjs/wast-printer@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" @@ -2604,6 +3379,15 @@ "@webassemblyjs/wast-parser" "1.8.5" "@xtuc/long" "4.2.2" +"@webassemblyjs/wast-printer@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" + integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" + "@xtuc/long" "4.2.2" + "@webpack-contrib/schema-utils@^1.0.0-beta.0": version "1.0.0-beta.0" resolved "https://registry.yarnpkg.com/@webpack-contrib/schema-utils/-/schema-utils-1.0.0-beta.0.tgz#bf9638c9464d177b48209e84209e23bee2eb4f65" @@ -3146,19 +3930,7 @@ babel-core@^7.0.0-bridge.0: resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== -babel-eslint@10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" - integrity sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - -babel-eslint@^10.0.3: +babel-eslint@10.1.0, babel-eslint@^10.0.3: version "10.1.0" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== @@ -3225,15 +3997,16 @@ babel-jest@^24.9.0: chalk "^2.4.2" slash "^2.0.0" -babel-loader@8.0.6, babel-loader@^8.0.6: - version "8.0.6" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" - integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== +babel-loader@8.1.0, babel-loader@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.1.0.tgz#c611d5112bd5209abe8b9fa84c3e4da25275f1c3" + integrity sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw== dependencies: - find-cache-dir "^2.0.0" - loader-utils "^1.0.2" - mkdirp "^0.5.1" + find-cache-dir "^2.1.0" + loader-utils "^1.4.0" + mkdirp "^0.5.3" pify "^4.0.1" + schema-utils "^2.6.5" babel-messages@^6.23.0: version "6.23.0" @@ -3540,22 +4313,24 @@ babel-preset-jest@^24.9.0: babel-plugin-transform-undefined-to-void "^6.9.4" lodash "^4.17.11" -babel-preset-react-app@^9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-9.1.1.tgz#d1ceb47cbe48b285fdd5c562c54c432ed5a41e0e" - integrity sha512-YkWP2UwY//TLltNlEBRngDOrYhvSLb+CA330G7T9M5UhGEMWe+JK/8IXJc5p2fDTSfSiETf+PY0+PYXFMix81Q== +babel-preset-react-app@^9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-9.1.2.tgz#54775d976588a8a6d1a99201a702befecaf48030" + integrity sha512-k58RtQOKH21NyKtzptoAvtAODuAJJs3ZhqBMl456/GnXEQ/0La92pNmwgWoMn5pBTrsvk3YYXdY7zpY4e3UIxA== dependencies: - "@babel/core" "7.8.4" + "@babel/core" "7.9.0" "@babel/plugin-proposal-class-properties" "7.8.3" "@babel/plugin-proposal-decorators" "7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "7.8.3" "@babel/plugin-proposal-numeric-separator" "7.8.3" - "@babel/plugin-transform-flow-strip-types" "7.8.3" + "@babel/plugin-proposal-optional-chaining" "7.9.0" + "@babel/plugin-transform-flow-strip-types" "7.9.0" "@babel/plugin-transform-react-display-name" "7.8.3" - "@babel/plugin-transform-runtime" "7.8.3" - "@babel/preset-env" "7.8.4" - "@babel/preset-react" "7.8.3" - "@babel/preset-typescript" "7.8.3" - "@babel/runtime" "7.8.4" + "@babel/plugin-transform-runtime" "7.9.0" + "@babel/preset-env" "7.9.0" + "@babel/preset-react" "7.9.1" + "@babel/preset-typescript" "7.9.0" + "@babel/runtime" "7.9.0" babel-plugin-macros "2.8.0" babel-plugin-transform-react-remove-prop-types "0.4.24" @@ -3664,11 +4439,6 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bluebird@3.5.5: - version "3.5.5" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" - integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== - bluebird@^3.3.5, bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -3833,6 +4603,16 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" +browserslist@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.10.0.tgz#f179737913eaf0d2b98e4926ac1ca6a15cbcc6a9" + integrity sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA== + dependencies: + caniuse-lite "^1.0.30001035" + electron-to-chromium "^1.3.378" + node-releases "^1.1.52" + pkg-up "^3.1.0" + browserslist@4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.0.tgz#9ee89225ffc07db03409f2fee524dc8227458a17" @@ -3842,15 +4622,6 @@ browserslist@4.7.0: electron-to-chromium "^1.3.247" node-releases "^1.1.29" -browserslist@4.8.6: - version "4.8.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.6.tgz#96406f3f5f0755d272e27a66f4163ca821590a7e" - integrity sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg== - dependencies: - caniuse-lite "^1.0.30001023" - electron-to-chromium "^1.3.341" - node-releases "^1.1.47" - browserslist@^4.0.0, browserslist@^4.6.2, browserslist@^4.6.4, browserslist@^4.8.3, browserslist@^4.8.5, browserslist@^4.9.1: version "4.9.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.9.1.tgz#01ffb9ca31a1aef7678128fc6a2253316aa7287c" @@ -4063,11 +4834,16 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001023, caniuse-lite@^1.0.30001030: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001030: version "1.0.30001033" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001033.tgz#60c328fb56860de60f9a2cb419c31fb80587cba0" integrity sha512-8Ibzxee6ibc5q88cM1usPsMpJOG5CTq0s/dKOmlekPbDGKt+UrnOOTPSjQz3kVo6yL7N4SB5xd+FGLHQmbzh6A== +caniuse-lite@^1.0.30001035: + version "1.0.30001036" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001036.tgz#930ea5272010d8bf190d859159d757c0b398caf0" + integrity sha512-jU8CIFIj2oR7r4W+5AKcsvWNVIb6Q6OZE3UsrXrZBHFtreT4YgTeOJtTucp+zSedEpTi3L5wASSP0LYIE3if6w== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -4153,35 +4929,6 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -chokidar-cli@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/chokidar-cli/-/chokidar-cli-1.2.3.tgz#28fe28da1c3a12b444f52ddbe8a472358a32279f" - integrity sha512-HcHjqeQaT/u0Swy4eaqqg0NhPjsXq6ZN9YzP48EYc81FXBLQuvMXBsrEMDkgH+Puup1mBc0gD0qqECDy/WiMOA== - dependencies: - bluebird "3.5.5" - chokidar "2.1.5" - lodash "4.17.15" - yargs "13.3.0" - -chokidar@2.1.5: - version "2.1.5" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d" - integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - chokidar@^2.0.2, chokidar@^2.0.4, chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" @@ -4738,13 +5485,6 @@ create-react-context@0.3.0, create-react-context@^0.3.0: gud "^1.0.0" warning "^4.0.3" -cross-env@6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941" - integrity sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag== - dependencies: - cross-spawn "^7.0.0" - cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -5289,10 +6029,10 @@ doctypes@^1.1.0: resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= -dom-accessibility-api@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.3.0.tgz#511e5993dd673b97c87ea47dba0e3892f7e0c983" - integrity sha512-PzwHEmsRP3IGY4gv/Ug+rMeaTIyTJvadCb+ujYXYeIylbHJezIyNToe8KfEgHTCEYyC+/bUghYOGg8yMGlZ6vA== +dom-accessibility-api@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.4.3.tgz#93ca9002eb222fd5a343b6e5e6b9cf5929411c4c" + integrity sha512-JZ8iPuEHDQzq6q0k7PKMGbrIdsgBB7TRrtVOUm4nSMCExlg5qQG4KXWTH2k90yggjM4tTumRGwTKJSldMzKyLA== dom-converter@^0.2: version "0.2.0" @@ -5436,11 +6176,16 @@ ejs@^2.7.4: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== -electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.341, electron-to-chromium@^1.3.363: +electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.363: version "1.3.376" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.376.tgz#7cb7b5205564a06c8f8ecfbe832cbd47a1224bb1" integrity sha512-cv/PYVz5szeMz192ngilmezyPNFkUjuynuL2vNdiqIrio440nfTDdc0JJU0TS2KHLSVCs9gBbt4CFqM+HcBnjw== +electron-to-chromium@^1.3.378: + version "1.3.383" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.383.tgz#8bbef55963529bfbf8344ac3620e1bcb455cffc3" + integrity sha512-EHYVJl6Ox1kFy/SzGVbijHu8ksQotJnqHCFFfaVhXiC+erOSplwhCtOTSocu1jRwirlNsSn/aZ9Kf84Z6s5qrg== + element-resize-detector@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/element-resize-detector/-/element-resize-detector-1.2.1.tgz#b0305194447a4863155e58f13323a0aef30851d1" @@ -5523,7 +6268,7 @@ enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: memory-fs "^0.5.0" tapable "^1.0.0" -enquirer@^2.3.0: +enquirer@^2.3.4: version "2.3.4" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.4.tgz#c608f2e1134c7f68c1c9ee056de13f9b31076de9" integrity sha512-pkYrrDZumL2VS6VBGDhqbajCM2xpkUNLuKfGPjfKaSIBKYopQbqEFyrOkRMIb2HDR/rO1kGhEt/5twBwtzKBXw== @@ -5668,13 +6413,20 @@ eslint-config-prettier@^6.0.0: dependencies: get-stdin "^6.0.0" -eslint-config-react-app@^5.0.2, eslint-config-react-app@^5.2.0: +eslint-config-react-app@^5.0.2: version "5.2.0" resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.2.0.tgz#135110ba56a9e378f7acfe5f36e2ae76a2317899" integrity sha512-WrHjoGpKr1kLLiWDD81tme9jMM0hk5cMxasLSdyno6DdPt+IfLOrDJBVo6jN7tn4y1nzhs43TmUaZWO6Sf0blw== dependencies: confusing-browser-globals "^1.0.9" +eslint-config-react-app@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz#698bf7aeee27f0cea0139eaef261c7bf7dd623df" + integrity sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ== + dependencies: + confusing-browser-globals "^1.0.9" + eslint-import-resolver-node@^0.3.2: version "0.3.3" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" @@ -5716,25 +6468,7 @@ eslint-plugin-flowtype@^3.13.0: dependencies: lodash "^4.17.15" -eslint-plugin-import@2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz#d749a7263fb6c29980def8e960d380a6aa6aecaa" - integrity sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ== - dependencies: - array-includes "^3.0.3" - array.prototype.flat "^1.2.1" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.2" - eslint-module-utils "^2.4.1" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.0" - read-pkg-up "^2.0.0" - resolve "^1.12.0" - -eslint-plugin-import@^2.18.2: +eslint-plugin-import@2.20.1, eslint-plugin-import@^2.18.2: version "2.20.1" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3" integrity sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw== @@ -5784,22 +6518,7 @@ eslint-plugin-react-hooks@^2.2.0: resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.5.0.tgz#c50ab7ca5945ce6d1cf8248d9e185c80b54171b6" integrity sha512-bzvdX47Jx847bgAYf0FPX3u1oxU+mKU8tqrpj4UX9A96SbAmj/HVEefEy6rJUog5u8QIlOPTKZcBpGn5kkKfAQ== -eslint-plugin-react@7.18.0: - version "7.18.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.18.0.tgz#2317831284d005b30aff8afb7c4e906f13fa8e7e" - integrity sha512-p+PGoGeV4SaZRDsXqdj9OWcOrOpZn8gXoGPcIQTzo2IDMbAKhNDnME9myZWqO3Ic4R3YmwAZ1lDjWl2R2hMUVQ== - dependencies: - array-includes "^3.1.1" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.2.3" - object.entries "^1.1.1" - object.fromentries "^2.0.2" - object.values "^1.1.1" - prop-types "^15.7.2" - resolve "^1.14.2" - -eslint-plugin-react@^7.14.3: +eslint-plugin-react@7.19.0, eslint-plugin-react@^7.14.3: version "7.19.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz#6d08f9673628aa69c5559d33489e855d83551666" integrity sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ== @@ -7276,6 +7995,11 @@ immer@^6.0.1: resolved "https://registry.yarnpkg.com/immer/-/immer-6.0.1.tgz#7af35e35753d9da6bc9123f0cc99f7e8f2e10681" integrity sha512-oXwigCKgznQywsXi1VgrqgWbQEU3wievNCVc4Fcwky6mwXU6YHj6JuYp0WEM/B1EphkqsLr0x18lm5OiuemPcA== +immer@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/immer/-/immer-6.0.2.tgz#5bc08dc4930c756d0749533a2afbd88c8de0cd19" + integrity sha512-56CMvUMZl4kkWJFFUe1TjBgGbyb9ibzpLyHD+RSKSVdytuDXgT/HXO1S+GJVywMVl5neGTdAogoR15eRVEd10Q== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -8606,6 +9330,13 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +json5@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e" + integrity sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ== + dependencies: + minimist "^1.2.5" + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -8807,7 +9538,7 @@ loader-utils@1.2.3: emojis-list "^2.0.0" json5 "^1.0.1" -loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: +loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== @@ -8889,7 +9620,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.15, "lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5: +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -9310,6 +10041,11 @@ minimist@^1.1.1, minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.4.tgz#40357ef9582f8cd42ba8eaa274ddcf27f0c979b7" integrity sha512-wTiNDqe4D2rbTJGZk1qcdZgFtY0/r+iuE6GDT7V0/+Gu5MLpIDm4+CssDECR79OJs/OxLPXMzdxy153b5Qy3hg== +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + minipass-collect@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" @@ -9377,6 +10113,13 @@ mkdirp@0.5.1, mkdirp@0.x, mkdirp@^0.5.1, mkdirp@~0.5.1: dependencies: minimist "0.0.8" +mkdirp@^0.5.3: + version "0.5.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" + integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== + dependencies: + minimist "^1.2.5" + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -9574,13 +10317,20 @@ node-notifier@^5.4.2: shellwords "^0.1.1" which "^1.3.0" -node-releases@^1.1.29, node-releases@^1.1.47, node-releases@^1.1.50: +node-releases@^1.1.29, node-releases@^1.1.50: version "1.1.51" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.51.tgz#70d0e054221343d2966006bfbd4d98622cc00bd0" integrity sha512-1eQEs6HFYY1kMXQPOLzCf7HdjReErmvn85tZESMczdCNVWP3Y7URYLBAyYynuI7yef1zj4HN5q+oB2x67QU0lw== dependencies: semver "^6.3.0" +node-releases@^1.1.52: + version "1.1.52" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.52.tgz#bcffee3e0a758e92e44ecfaecd0a47554b0bcba9" + integrity sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ== + dependencies: + semver "^6.3.0" + normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -10279,7 +11029,7 @@ pkg-up@2.0.0: dependencies: find-up "^2.1.0" -pkg-up@3.1.0: +pkg-up@3.1.0, pkg-up@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== @@ -10305,12 +11055,12 @@ pnp-webpack-plugin@1.5.0: dependencies: ts-pnp "^1.1.2" -pnp-webpack-plugin@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.0.tgz#d5c068013a2fdc82224ca50ed179c8fba9036a8e" - integrity sha512-ZcMGn/xF/fCOq+9kWMP9vVVxjIkMCja72oy3lziR7UHy0hHFZ57iVpQ71OtveVbmzeCmphBg8pxNdk/hlK99aQ== +pnp-webpack-plugin@1.6.4, pnp-webpack-plugin@^1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" + integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg== dependencies: - ts-pnp "^1.1.2" + ts-pnp "^1.1.6" polished@^3.3.1: version "3.4.4" @@ -11023,10 +11773,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^1.16.4, prettier@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== +prettier@^1.16.4, prettier@^1.19.1, prettier@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.2.tgz#1ba8f3eb92231e769b7fcd7cb73ae1b6b74ade08" + integrity sha512-5xJQIPT8BraI7ZnaDwSbu5zLrB6vvi8hVV58yHQ+QK64qrY40dULy0HSRlQ2/2IdzeBpjhDkqdcFBnFeDEMVdg== pretty-bytes@^5.1.0: version "5.3.0" @@ -11474,14 +12224,14 @@ react-clientside-effect@^1.2.2: dependencies: "@babel/runtime" "^7.0.0" -react-dev-utils@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-10.2.0.tgz#b11cc48aa2be2502fb3c27a50d1dfa95cfa9dfe0" - integrity sha512-MwrvQW2TFjLblhqpDNeqCXHBkz3G5vc7k4wntgutAJZX4ia3o07eGKo6uYGhUOeJ0hfOxcpJFNFk7+4XCc1S8g== +react-dev-utils@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-10.2.1.tgz#f6de325ae25fa4d546d09df4bb1befdc6dd19c19" + integrity sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ== dependencies: "@babel/code-frame" "7.8.3" address "1.1.2" - browserslist "4.8.6" + browserslist "4.10.0" chalk "2.4.2" cross-spawn "7.0.1" detect-port-alt "1.1.6" @@ -11498,7 +12248,7 @@ react-dev-utils@^10.2.0: loader-utils "1.2.3" open "^7.0.2" pkg-up "3.1.0" - react-error-overlay "^6.0.6" + react-error-overlay "^6.0.7" recursive-readdir "2.2.2" shell-quote "1.7.2" strip-ansi "6.0.0" @@ -11563,7 +12313,17 @@ react-docgen@^5.0.0: node-dir "^0.1.10" strip-indent "^3.0.0" -react-dom@^16.13.0, react-dom@^16.8.3: +react-dom@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" + integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.19.1" + +react-dom@^16.8.3: version "16.13.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.0.tgz#cdde54b48eb9e8a0ca1b3dc9943d9bb409b81866" integrity sha512-y09d2c4cG220DzdlFkPTnVvGTszVvNpC73v+AaLGLHbkpy3SSgvYq8x0rNwPJ/Rk/CicTNgk0hbHNw1gMEZAXg== @@ -11589,11 +12349,16 @@ react-element-to-jsx-string@^14.0.2, react-element-to-jsx-string@^14.1.0: "@base2/pretty-print-object" "1.0.0" is-plain-object "3.0.0" -react-error-overlay@^6.0.3, react-error-overlay@^6.0.6: +react-error-overlay@^6.0.3: version "6.0.6" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.6.tgz#ac4d9dc4c1b5c536c2c312bf66aa2b09bfa384e2" integrity sha512-Yzpno3enVzSrSCnnljmr4b/2KUQSMZaPuqmS26t9k4nW7uwJk6STWmH9heNjPuvqUTO3jOSPkHoKgO4+Dw7uIw== +react-error-overlay@^6.0.7: + version "6.0.7" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" + integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA== + react-fast-compare@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" @@ -11638,11 +12403,16 @@ react-inspector@^4.0.0: is-dom "^1.0.9" prop-types "^15.6.1" -react-is@^16.12.0, react-is@^16.13.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.3, react-is@^16.8.4, react-is@^16.8.6: +react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.3, react-is@^16.8.4, react-is@^16.8.6: version "16.13.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527" integrity sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA== +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -11669,32 +12439,32 @@ react-popper@^1.3.6: typed-styles "^0.0.7" warning "^4.0.2" -react-scripts@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.4.0.tgz#f413680f0b5b937c8879ba1ffdae9b8c5b364bf5" - integrity sha512-pBqaAroFoHnFAkuX+uSK9Th1uEh2GYdGY2IG1I9/7HmuEf+ls3lLCk1p2GFYRSrLMz6ieQR/SyN6TLIGK3hKRg== +react-scripts@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.4.1.tgz#f551298b5c71985cc491b9acf3c8e8c0ae3ada0a" + integrity sha512-JpTdi/0Sfd31mZA6Ukx+lq5j1JoKItX7qqEK4OiACjVQletM1P38g49d9/D0yTxp9FrSF+xpJFStkGgKEIRjlQ== dependencies: - "@babel/core" "7.8.4" + "@babel/core" "7.9.0" "@svgr/webpack" "4.3.3" "@typescript-eslint/eslint-plugin" "^2.10.0" "@typescript-eslint/parser" "^2.10.0" - babel-eslint "10.0.3" + babel-eslint "10.1.0" babel-jest "^24.9.0" - babel-loader "8.0.6" + babel-loader "8.1.0" babel-plugin-named-asset-import "^0.3.6" - babel-preset-react-app "^9.1.1" + babel-preset-react-app "^9.1.2" camelcase "^5.3.1" case-sensitive-paths-webpack-plugin "2.3.0" css-loader "3.4.2" dotenv "8.2.0" dotenv-expand "5.1.0" eslint "^6.6.0" - eslint-config-react-app "^5.2.0" + eslint-config-react-app "^5.2.1" eslint-loader "3.0.3" eslint-plugin-flowtype "4.6.0" - eslint-plugin-import "2.20.0" + eslint-plugin-import "2.20.1" eslint-plugin-jsx-a11y "6.2.3" - eslint-plugin-react "7.18.0" + eslint-plugin-react "7.19.0" eslint-plugin-react-hooks "^1.6.1" file-loader "4.3.0" fs-extra "^8.1.0" @@ -11706,24 +12476,24 @@ react-scripts@^3.4.0: jest-watch-typeahead "0.4.2" mini-css-extract-plugin "0.9.0" optimize-css-assets-webpack-plugin "5.0.3" - pnp-webpack-plugin "1.6.0" + pnp-webpack-plugin "1.6.4" postcss-flexbugs-fixes "4.1.0" postcss-loader "3.0.0" postcss-normalize "8.0.1" postcss-preset-env "6.7.0" postcss-safe-parser "4.0.1" react-app-polyfill "^1.0.6" - react-dev-utils "^10.2.0" + react-dev-utils "^10.2.1" resolve "1.15.0" resolve-url-loader "3.1.1" sass-loader "8.0.2" semver "6.3.0" style-loader "0.23.1" - terser-webpack-plugin "2.3.4" - ts-pnp "1.1.5" + terser-webpack-plugin "2.3.5" + ts-pnp "1.1.6" url-loader "2.3.0" - webpack "4.41.5" - webpack-dev-server "3.10.2" + webpack "4.42.0" + webpack-dev-server "3.10.3" webpack-manifest-plugin "2.2.0" workbox-webpack-plugin "4.3.1" optionalDependencies: @@ -11739,14 +12509,13 @@ react-sizeme@^2.6.7: shallowequal "^1.1.0" throttle-debounce "^2.1.0" -react-state-selector@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/react-state-selector/-/react-state-selector-1.0.0.tgz#500b26437e76b75e11bf36d0a9fe45ed8fc2da7e" - integrity sha512-KUevUWacrFkq19VdYce/2vQfb73f+bjUp4wpAJqzkpR0PIwW4ndeVyVzpEmiCyNdmwrQlM83fmapTUCDMlbjiw== +react-state-selector@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/react-state-selector/-/react-state-selector-1.0.1.tgz#95de7c8a6cea69e4d703ad0baaaa4ac86d906acf" + integrity sha512-NBj5ldkKdfaCfzEX0Fz4vuuTubAH+WiBvv/S6lGckH6PY1hag2nUZPDaAR42oBKMMKSZIZVUtW+JzU3uLIQC7g== dependencies: immer "^6.0.1" reselect "^4.0.0" - skmeans "^0.11.3" react-syntax-highlighter@^11.0.2: version "11.0.2" @@ -11759,15 +12528,15 @@ react-syntax-highlighter@^11.0.2: prismjs "^1.8.4" refractor "^2.4.1" -react-test-renderer@^16.13.0: - version "16.13.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.0.tgz#39ba3bf72cedc8210c3f81983f0bb061b14a3014" - integrity sha512-NQ2S9gdMUa7rgPGpKGyMcwl1d6D9MCF0lftdI3kts6kkiX+qvpC955jNjAZXlIDTjnN9jwFI8A8XhRh/9v0spA== +react-test-renderer@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.1.tgz#de25ea358d9012606de51e012d9742e7f0deabc1" + integrity sha512-Sn2VRyOK2YJJldOqoh8Tn/lWQ+ZiKhyZTPtaO0Q6yNj+QDbmRkVFap6pZPy3YQk8DScRDfyqm/KxKYP9gCMRiQ== dependencies: object-assign "^4.1.1" prop-types "^15.6.2" react-is "^16.8.6" - scheduler "^0.19.0" + scheduler "^0.19.1" react-textarea-autosize@^7.1.0: version "7.1.2" @@ -11953,6 +12722,11 @@ regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz#e96bf612a3362d12bb69f7e8f74ffeab25c7ac91" integrity sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g== +regenerator-runtime@^0.13.5: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + regenerator-transform@^0.14.2: version "0.14.2" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.2.tgz#949d9d87468ff88d5a7e4734ebb994a892de1ff2" @@ -11992,7 +12766,7 @@ regexpp@^3.0.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e" integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g== -regexpu-core@^4.6.0: +regexpu-core@^4.6.0, regexpu-core@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== @@ -12234,13 +13008,6 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" - integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== - dependencies: - path-parse "^1.0.6" - resolve@1.15.0: version "1.15.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5" @@ -12248,7 +13015,7 @@ resolve@1.15.0: dependencies: path-parse "^1.0.6" -resolve@1.x, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.3.2, resolve@^1.8.1: +resolve@1.15.1, resolve@1.x, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.3.2, resolve@^1.8.1: version "1.15.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== @@ -12325,13 +13092,6 @@ rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.3, rimraf@^2.7.1: dependencies: glob "^7.1.3" -rimraf@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -12367,32 +13127,25 @@ rollup-plugin-terser@^5.1.2: serialize-javascript "^2.1.2" terser "^4.6.2" -rollup-plugin-typescript2@^0.25.3: - version "0.25.3" - resolved "https://registry.yarnpkg.com/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.25.3.tgz#a5fb2f0f85488789334ce540abe6c7011cbdf40f" - integrity sha512-ADkSaidKBovJmf5VBnZBZe+WzaZwofuvYdzGAKTN/J4hN7QJCFYAq7IrH9caxlru6T5qhX41PNFS1S4HqhsGQg== +rollup-plugin-typescript2@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.26.0.tgz#cee2b44d51d9623686656d76dc30a73c4de91672" + integrity sha512-lUK7XZVG77tu8dmv1L/0LZFlavED/5Yo6e4iMMl6fdox/yKdj4IFRRPPJEXNdmEaT1nDQQeCi7b5IwKHffMNeg== dependencies: - find-cache-dir "^3.0.0" + find-cache-dir "^3.2.0" fs-extra "8.1.0" - resolve "1.12.0" - rollup-pluginutils "2.8.1" + resolve "1.15.1" + rollup-pluginutils "2.8.2" tslib "1.10.0" -rollup-pluginutils@2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz#8fa6dd0697344938ef26c2c09d2488ce9e33ce97" - integrity sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg== - dependencies: - estree-walker "^0.6.1" - -rollup-pluginutils@^2.0.1, rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: +rollup-pluginutils@2.8.2, rollup-pluginutils@^2.0.1, rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: version "2.8.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== dependencies: estree-walker "^0.6.1" -rollup@^1.27.8: +rollup@^1.32.1: version "1.32.1" resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.32.1.tgz#4480e52d9d9e2ae4b46ba0d9ddeaf3163940f9c4" integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A== @@ -12512,6 +13265,14 @@ scheduler@^0.19.0: loose-envify "^1.1.0" object-assign "^4.1.1" +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" + integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" @@ -12521,7 +13282,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.0.1, schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6.4: +schema-utils@^2.0.1, schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6.4, schema-utils@^2.6.5: version "2.6.5" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.5.tgz#c758f0a7e624263073d396e29cd40aa101152d8a" integrity sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ== @@ -12787,11 +13548,6 @@ sisteransi@^1.0.4: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.4.tgz#386713f1ef688c7c0304dc4c0632898941cad2e3" integrity sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig== -skmeans@^0.11.3: - version "0.11.3" - resolved "https://registry.yarnpkg.com/skmeans/-/skmeans-0.11.3.tgz#6d4dafb8058520a792c10bae9d9b953a6b6379f4" - integrity sha512-nccEnlSeOMNAYM9ETMSq+m15u8g0KRCIvH2an/ROTx4Igmci/j3oYHBPGdAeGjhR7knAVoIIQwr/wy2dN/eKQA== - slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -13412,10 +14168,10 @@ term-size@^2.1.0: resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw== -terser-webpack-plugin@2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.4.tgz#ac045703bd8da0936ce910d8fb6350d0e1dee5fe" - integrity sha512-Nv96Nws2R2nrFOpbzF6IxRDpIkkIfmhvOws+IqMvYdFLO7o6wAILWFKONFgaYy8+T4LVz77DQW0f7wOeDEAjrg== +terser-webpack-plugin@2.3.5, terser-webpack-plugin@^2.1.2: + version "2.3.5" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz#5ad971acce5c517440ba873ea4f09687de2f4a81" + integrity sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w== dependencies: cacache "^13.0.1" find-cache-dir "^3.2.0" @@ -13442,21 +14198,6 @@ terser-webpack-plugin@^1.4.3: webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser-webpack-plugin@^2.1.2: - version "2.3.5" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz#5ad971acce5c517440ba873ea4f09687de2f4a81" - integrity sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w== - dependencies: - cacache "^13.0.1" - find-cache-dir "^3.2.0" - jest-worker "^25.1.0" - p-limit "^2.2.2" - schema-utils "^2.6.4" - serialize-javascript "^2.1.2" - source-map "^0.6.1" - terser "^4.4.3" - webpack-sources "^1.4.3" - terser@^4.1.2, terser@^4.4.3, terser@^4.6.2, terser@^4.6.3: version "4.6.6" resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.6.tgz#da2382e6cafbdf86205e82fb9a115bd664d54863" @@ -13664,10 +14405,10 @@ ts-jest@^24.0.2: semver "^5.5" yargs-parser "10.x" -ts-loader@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.1.tgz#67939d5772e8a8c6bdaf6277ca023a4812da02ef" - integrity sha512-Dd9FekWuABGgjE1g0TlQJ+4dFUfYGbYcs52/HQObE0ZmUNjQlmLAS7xXsSzy23AMaMwipsx5sNHvoEpT2CZq1g== +ts-loader@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.2.tgz#dffa3879b01a1a1e0a4b85e2b8421dc0dfff1c58" + integrity sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ== dependencies: chalk "^2.3.0" enhanced-resolve "^4.0.0" @@ -13680,20 +14421,15 @@ ts-map@^1.0.3: resolved "https://registry.yarnpkg.com/ts-map/-/ts-map-1.0.3.tgz#1c4d218dec813d2103b7e04e4bcf348e1471c1ff" integrity sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w== -ts-pnp@1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.5.tgz#840e0739c89fce5f3abd9037bb091dbff16d9dec" - integrity sha512-ti7OGMOUOzo66wLF3liskw6YQIaSsBgc4GOAlWRnIEj8htCxJUxskanMUoJOD6MDCRAXo36goXJZch+nOS0VMA== - -ts-pnp@^1.1.2: +ts-pnp@1.1.6, ts-pnp@^1.1.2, ts-pnp@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.6.tgz#389a24396d425a0d3162e96d2b4638900fdc289a" integrity sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ== -tsdx@^0.12.3: - version "0.12.3" - resolved "https://registry.yarnpkg.com/tsdx/-/tsdx-0.12.3.tgz#688ef9c4ed8f1c5de5da94daf2e3cc02f8134c2c" - integrity sha512-BQ0oj9S5Yti6Esol+29ztiJs0kSUA57LngT0G4VF2lqTDRZcMlByCMyWa7yOih08t1wNUj8ah0ml7WJkf8PIbA== +tsdx@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/tsdx/-/tsdx-0.13.0.tgz#f8348b22724a7e618d501d0e8d133ff95d43f3e3" + integrity sha512-upsdQfzLz6eR5tDn0qQ/UJzQQk/mZLHE+2XNHndI87U3gvnXOJjvXcEx2X/Rl5n36bk44Ynvt5V9N3waT8tZng== dependencies: "@babel/core" "^7.4.4" "@babel/helper-module-imports" "^7.0.0" @@ -13707,9 +14443,8 @@ tsdx@^0.12.3: "@babel/preset-env" "^7.4.4" "@rollup/plugin-commonjs" "^11.0.0" "@rollup/plugin-json" "^4.0.0" - "@rollup/plugin-node-resolve" "^6.0.0" + "@rollup/plugin-node-resolve" "^7.1.0" "@rollup/plugin-replace" "^2.2.1" - "@types/rimraf" "^2.0.2" "@types/shelljs" "^0.8.5" "@typescript-eslint/eslint-plugin" "^2.12.0" "@typescript-eslint/parser" "^2.12.0" @@ -13725,10 +14460,7 @@ tsdx@^0.12.3: babylon "^6.18.0" camelcase "^5.0.0" chalk "^2.4.2" - chokidar-cli "^1.2.2" - cross-env "6.0.3" - cross-spawn "^6.0.5" - enquirer "^2.3.0" + enquirer "^2.3.4" eslint "^6.1.0" eslint-config-prettier "^6.0.0" eslint-config-react-app "^5.0.2" @@ -13744,17 +14476,15 @@ tsdx@^0.12.3: jest-watch-typeahead "^0.4.0" jpjs "^1.2.1" lodash.merge "^4.6.2" - mkdirp "^0.5.1" ora "^3.4.0" pascal-case "^2.0.1" prettier "^1.19.1" progress-estimator "^0.2.2" - rimraf "^3.0.0" - rollup "^1.27.8" + rollup "^1.32.1" rollup-plugin-babel "^4.3.2" rollup-plugin-sourcemaps "^0.4.2" rollup-plugin-terser "^5.1.2" - rollup-plugin-typescript2 "^0.25.3" + rollup-plugin-typescript2 "^0.26.0" sade "^1.4.2" shelljs "^0.8.3" tiny-glob "^0.2.6" @@ -14354,10 +15084,10 @@ webpack-dev-middleware@^3.7.0, webpack-dev-middleware@^3.7.2: range-parser "^1.2.1" webpack-log "^2.0.0" -webpack-dev-server@3.10.2: - version "3.10.2" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.10.2.tgz#3403287d674c7407aab6d9b3f72259ecd0aa0874" - integrity sha512-pxZKPYb+n77UN8u9YxXT4IaIrGcNtijh/mi8TXbErHmczw0DtPnMTTjHj+eNjkqLOaAZM/qD7V59j/qJsEiaZA== +webpack-dev-server@3.10.3: + version "3.10.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz#f35945036813e57ef582c2420ef7b470e14d3af0" + integrity sha512-e4nWev8YzEVNdOMcNzNeCN947sWJNd43E5XvsJzbAL08kGc2frm1tQ32hTJslRS+H65LCb/AaUCYU7fjHCpDeQ== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" @@ -14446,10 +15176,10 @@ webpack-virtual-modules@^0.2.0: dependencies: debug "^3.0.0" -webpack@4.41.5: - version "4.41.5" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.5.tgz#3210f1886bce5310e62bb97204d18c263341b77c" - integrity sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw== +webpack@4.42.0, webpack@^4.33.0, webpack@^4.38.0: + version "4.42.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.42.0.tgz#b901635dd6179391d90740a63c93f76f39883eb8" + integrity sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -14475,15 +15205,15 @@ webpack@4.41.5: watchpack "^1.6.0" webpack-sources "^1.4.1" -webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.6: - version "4.42.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.42.0.tgz#b901635dd6179391d90740a63c93f76f39883eb8" - integrity sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w== +webpack@^4.42.1: + version "4.42.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.42.1.tgz#ae707baf091f5ca3ef9c38b884287cfe8f1983ef" + integrity sha512-SGfYMigqEfdGchGhFFJ9KyRpQKnipvEvjc1TwrXEPCM6H5Wywu10ka8o3KGrMzSMxMQKt8aCHUFh5DaQ9UmyRg== dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-module-context" "1.8.5" - "@webassemblyjs/wasm-edit" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/wasm-edit" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" acorn "^6.2.1" ajv "^6.10.2" ajv-keywords "^3.4.1" @@ -14495,7 +15225,7 @@ webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.6: loader-utils "^1.2.3" memory-fs "^0.4.1" micromatch "^3.1.10" - mkdirp "^0.5.1" + mkdirp "^0.5.3" neo-async "^2.6.1" node-libs-browser "^2.2.1" schema-utils "^1.0.0" @@ -14922,7 +15652,7 @@ yargs@12.0.5: y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" -yargs@13.3.0, yargs@^13.3.0: +yargs@^13.3.0: version "13.3.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== From ff0d44a0bd81068a5867cbd1e8981c57017f0475 Mon Sep 17 00:00:00 2001 From: PabloSzx Date: Tue, 24 Mar 2020 19:00:38 -0300 Subject: [PATCH 2/8] v1.0.2 --- package.json | 2 +- src/createStoreContext.ts | 4 +- src/plugins/localStorage.ts | 112 ++++++++++++++++++------------------ 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/package.json b/package.json index 0b5c3fd..26e2937 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-state-selector", - "version": "1.0.1", + "version": "1.0.2", "keywords": [ "react", "immer", diff --git a/src/createStoreContext.ts b/src/createStoreContext.ts index f22db7a..29b6f14 100644 --- a/src/createStoreContext.ts +++ b/src/createStoreContext.ts @@ -323,7 +323,7 @@ export function createStoreContext< await Promise.resolve(draft(storeDraft)); - finishDraft(storeDraft, changes => { + finishDraft(storeDraft, (changes) => { if (changes.length) { storeCtx.current.store = applyPatches( storeCtx.current.store, @@ -457,7 +457,7 @@ export function createStoreContext< const { updateSelector, initialStateRef } = useMemo(() => { return { - updateSelector: createSelector(hookSelector, result => { + updateSelector: createSelector(hookSelector, (result) => { stateRef.current = result; if (!isMountedRef.current) { diff --git a/src/plugins/localStorage.ts b/src/plugins/localStorage.ts index 06b66c0..87e1f5c 100644 --- a/src/plugins/localStorage.ts +++ b/src/plugins/localStorage.ts @@ -1,56 +1,56 @@ -import { Immutable } from "immer"; - -import { IProduce, isClientSide } from "../common"; - -export type LocalStoragePlugin = { - getState: () => Immutable; - setState: (state: T) => void; -}; - -export const connectLocalStorage = ( - persistenceName: string, - defaultInitialState: T, - produce: IProduce, - wait = 3000, - persistenceMethod = isClientSide ? window.localStorage : undefined -): LocalStoragePlugin => { - let isConnected = false; - let timeout: NodeJS.Timeout | undefined; - - const setStateFn = (state: T) => { - if (persistenceMethod) { - persistenceMethod.setItem(persistenceName, JSON.stringify(state)); - if (!isConnected) isConnected = true; - } - }; - - const setState = (state: T) => { - const execLater = () => { - timeout = undefined; - setStateFn(state); - }; - if (timeout !== undefined) clearTimeout(timeout); - timeout = setTimeout(execLater, wait); - }; - - return { - getState: () => { - if (isConnected) return produce(); - - try { - const state = persistenceMethod?.getItem(persistenceName); - - if (state != null) { - const connectedState = produce(() => ({ - ...produce(), - ...JSON.parse(state), - })); - isConnected = true; - return connectedState; - } - } catch (err) {} - return defaultInitialState as Immutable; - }, - setState, - }; -}; +import { Immutable } from "immer"; + +import { IProduce, isClientSide } from "../common"; + +export type LocalStoragePlugin = { + getState: () => Immutable; + setState: (state: T) => void; +}; + +export const connectLocalStorage = ( + persistenceName: string, + defaultInitialState: T, + produce: IProduce, + wait = 3000, + persistenceMethod = isClientSide ? window.localStorage : undefined +): LocalStoragePlugin => { + let isConnected = false; + let timeout: NodeJS.Timeout | undefined; + + const setStateFn = (state: T) => { + if (persistenceMethod) { + persistenceMethod.setItem(persistenceName, JSON.stringify(state)); + if (!isConnected) isConnected = true; + } + }; + + const setState = (state: T) => { + const execLater = () => { + timeout = undefined; + setStateFn(state); + }; + if (timeout !== undefined) clearTimeout(timeout); + timeout = setTimeout(execLater, wait); + }; + + return { + getState: () => { + if (isConnected) return produce(); + + try { + const state = persistenceMethod?.getItem(persistenceName); + + if (state != null) { + const connectedState = produce(() => ({ + ...produce(), + ...JSON.parse(state), + })); + isConnected = true; + return connectedState; + } + } catch (err) {} + return defaultInitialState as Immutable; + }, + setState, + }; +}; From 2e54f4ea00dd720dff3710e746808620edc605a6 Mon Sep 17 00:00:00 2001 From: PabloSzx Date: Tue, 24 Mar 2020 19:05:41 -0300 Subject: [PATCH 3/8] v1.0.3 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 26e2937..a2c6f7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-state-selector", - "version": "1.0.2", + "version": "1.0.3", "keywords": [ "react", "immer", @@ -15,7 +15,7 @@ "author": "PabloSzx", "main": "dist/index.js", "module": "dist/react-state-selector.esm.js", - "typings": "dist/index.d.ts", + "typings": "dist/index.d.ts/src/index.d.ts", "files": [ "dist" ], From b9efe0a4ad4e80d78dd496be27d32439c9fc0628 Mon Sep 17 00:00:00 2001 From: PabloSzx Date: Tue, 24 Mar 2020 19:33:10 -0300 Subject: [PATCH 4/8] v1.0.4 --- package.json | 6 +++--- src/common.ts | 8 +++++++- src/createStore.ts | 9 ++------- src/plugins/localStorage.ts | 18 ++++++++---------- stories/devTools/createStore.stories.tsx | 3 ++- .../devTools/createStoreContext.stories.tsx | 3 ++- tsconfig.json | 5 ++--- yarn.lock | 2 +- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index a2c6f7d..1ea445a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-state-selector", - "version": "1.0.3", + "version": "1.0.4", "keywords": [ "react", "immer", @@ -15,7 +15,7 @@ "author": "PabloSzx", "main": "dist/index.js", "module": "dist/react-state-selector.esm.js", - "typings": "dist/index.d.ts/src/index.d.ts", + "typings": "dist/index.d.ts", "files": [ "dist" ], @@ -38,7 +38,7 @@ "coverageDirectory": "./coverage/" }, "resolutions": { - "@types/react": "16.9.25", + "@types/react": "^16.9.25", "prettier": "^2.0.2" }, "dependencies": { diff --git a/src/common.ts b/src/common.ts index 0fff97a..d8fd101 100644 --- a/src/common.ts +++ b/src/common.ts @@ -4,6 +4,8 @@ import { Draft, enablePatches, Immutable } from "immer"; import { useCallback, useEffect, useLayoutEffect, useState } from "react"; import { ParametricSelector } from "reselect"; +import { LocalStoragePlugin } from "./plugins/localStorage"; + enablePatches(); export type Selector< @@ -26,9 +28,13 @@ const incrementParameter = (num: number) => ++num; export const emptyArray: [] = []; -export const useUpdate = () => { +export const useUpdate = (persistencePlugin?: LocalStoragePlugin) => { const [, setState] = useState(0); + useEffect(() => { + persistencePlugin?.getState(); + }, emptyArray); + return useCallback(() => setState(incrementParameter), emptyArray); }; diff --git a/src/createStore.ts b/src/createStore.ts index 0eb84e6..e4ad251 100644 --- a/src/createStore.ts +++ b/src/createStore.ts @@ -24,7 +24,6 @@ import { IHooks, IHooksObj, IProduce, - isClientSide, IUseStore, Selector, toAnonFunction, @@ -205,7 +204,7 @@ export function createStore< } const useStore = () => { - const update = useUpdate(); + const update = useUpdate(localStoragePlugin); useIsomorphicLayoutEffect(() => { const globalListener = createSelector( @@ -304,12 +303,8 @@ export function createStore< } localStoragePlugin = connectLocalStorage( options.devName, - initialStore as TStore, produceObj.produce ); - if (isClientSide) { - localStoragePlugin.getState(); - } } const actionsObj: Record< @@ -388,7 +383,7 @@ export function createStore< hooksProps?: (() => unknown) | unknown, hookPropsDeps?: unknown[] ) => { - const update = useUpdate(); + const update = useUpdate(localStoragePlugin); const props = useMemo( toAnonFunction(hooksProps), diff --git a/src/plugins/localStorage.ts b/src/plugins/localStorage.ts index 87e1f5c..5115985 100644 --- a/src/plugins/localStorage.ts +++ b/src/plugins/localStorage.ts @@ -1,15 +1,12 @@ -import { Immutable } from "immer"; - import { IProduce, isClientSide } from "../common"; export type LocalStoragePlugin = { - getState: () => Immutable; + getState: () => void; setState: (state: T) => void; }; export const connectLocalStorage = ( persistenceName: string, - defaultInitialState: T, produce: IProduce, wait = 3000, persistenceMethod = isClientSide ? window.localStorage : undefined @@ -35,21 +32,22 @@ export const connectLocalStorage = ( return { getState: () => { - if (isConnected) return produce(); + if (isConnected) return; try { const state = persistenceMethod?.getItem(persistenceName); - - if (state != null) { - const connectedState = produce(() => ({ + if (state === undefined) { + isConnected = true; + } else if (state != null) { + produce(() => ({ ...produce(), ...JSON.parse(state), })); isConnected = true; - return connectedState; + return; } } catch (err) {} - return defaultInitialState as Immutable; + return; }, setState, }; diff --git a/stories/devTools/createStore.stories.tsx b/stories/devTools/createStore.stories.tsx index e662c14..083ed1b 100644 --- a/stories/devTools/createStore.stories.tsx +++ b/stories/devTools/createStore.stories.tsx @@ -1,6 +1,7 @@ import React, { CSSProperties, FC, useState } from "react"; import { createStore } from "react-state-selector"; -import { DevTools } from "stories/utils/devTools"; + +import { DevTools } from "../../stories/utils/devTools"; const boxStyle = (color: string): CSSProperties => { return { diff --git a/stories/devTools/createStoreContext.stories.tsx b/stories/devTools/createStoreContext.stories.tsx index 889615a..b4b921c 100644 --- a/stories/devTools/createStoreContext.stories.tsx +++ b/stories/devTools/createStoreContext.stories.tsx @@ -1,6 +1,7 @@ import React, { CSSProperties, FC, useState } from "react"; import { createStoreContext } from "react-state-selector"; -import { DevTools } from "stories/utils/devTools"; + +import { DevTools } from "../../stories/utils/devTools"; const boxStyle = (color: string): CSSProperties => { return { diff --git a/tsconfig.json b/tsconfig.json index 6fc1774..ca2ae0e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,8 +7,7 @@ "importHelpers": true, "declaration": true, "sourceMap": true, - "rootDir": "./", - "declarationDir": "./dist/index.d.ts", + "declarationDir": "./dist", "strict": true, "noImplicitAny": true, "strictNullChecks": true, @@ -21,7 +20,7 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "moduleResolution": "node", - "baseUrl": "./", + "baseUrl": "./src", "jsx": "react", "esModuleInterop": true } diff --git a/yarn.lock b/yarn.lock index 968e26a..f1e72f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2893,7 +2893,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@16.9.25", "@types/react@^16.9.25": +"@types/react@*", "@types/react@^16.9.25": version "16.9.25" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.25.tgz#6ae2159b40138c792058a23c3c04fd3db49e929e" integrity sha512-Dlj2V72cfYLPNscIG3/SMUOzhzj7GK3bpSrfefwt2YT9GLynvLCCZjbhyF6VsT0q0+aRACRX03TDJGb7cA0cqg== From 0ea84144d1ee2c80103cf6ed2440b923e9b792c0 Mon Sep 17 00:00:00 2001 From: PabloSzx Date: Wed, 25 Mar 2020 00:39:39 -0300 Subject: [PATCH 5/8] persistenceStorage on createStore 100% coverage --- package.json | 3 +- src/common.ts | 18 +- src/createStore.ts | 82 ++++++-- src/plugins/localStorage.ts | 54 ------ src/plugins/persistenceStorage.ts | 77 ++++++++ test/persistenceStorageBrowser.test.tsx | 248 ++++++++++++++++++++++++ test/persistenceStorageServer.test.tsx | 96 +++++++++ test/utils/localStorage.ts | 42 ++++ yarn.lock | 72 ++++++- 9 files changed, 618 insertions(+), 74 deletions(-) delete mode 100644 src/plugins/localStorage.ts create mode 100644 src/plugins/persistenceStorage.ts create mode 100644 test/persistenceStorageBrowser.test.tsx create mode 100644 test/persistenceStorageServer.test.tsx create mode 100644 test/utils/localStorage.ts diff --git a/package.json b/package.json index 1ea445a..650ca81 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ }, "husky": { "hooks": { - "pre-commit": "tsdx lint --fix src stories test" + "pre-commit": "pretty-quick --staged && tsdx lint --fix src stories test" } }, "jest": { @@ -73,6 +73,7 @@ "babel-loader": "^8.1.0", "husky": "^4.2.3", "prettier": "^2.0.2", + "pretty-quick": "^2.0.1", "react": "^16.13.0", "react-docgen-typescript-loader": "^3.7.1", "react-dom": "^16.13.1", diff --git a/src/common.ts b/src/common.ts index d8fd101..6124409 100644 --- a/src/common.ts +++ b/src/common.ts @@ -4,7 +4,7 @@ import { Draft, enablePatches, Immutable } from "immer"; import { useCallback, useEffect, useLayoutEffect, useState } from "react"; import { ParametricSelector } from "reselect"; -import { LocalStoragePlugin } from "./plugins/localStorage"; +import { LocalStoragePlugin } from "./plugins/persistenceStorage"; enablePatches(); @@ -18,9 +18,8 @@ export const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect; export function toAnonFunction(arg: unknown): () => typeof arg { - if (typeof arg === "function") { - return arg as () => typeof arg; - } + if (typeof arg === "function") return arg as () => typeof arg; + return () => arg; } @@ -28,11 +27,13 @@ const incrementParameter = (num: number) => ++num; export const emptyArray: [] = []; -export const useUpdate = (persistencePlugin?: LocalStoragePlugin) => { +export const useUpdate = (persistencePlugin?: LocalStoragePlugin) => { const [, setState] = useState(0); useEffect(() => { - persistencePlugin?.getState(); + if (persistencePlugin?.current.isSSR) { + persistencePlugin.getState(); + } }, emptyArray); return useCallback(() => setState(incrementParameter), emptyArray); @@ -100,3 +101,8 @@ export type IUseProduce = () => { asyncProduce: IAsyncProduce; produce: IProduce; }; + +export type IPersistenceMethod = { + setItem(key: string, data: any): any; + getItem(key: string): string | null; +}; diff --git a/src/createStore.ts b/src/createStore.ts index e4ad251..786f812 100644 --- a/src/createStore.ts +++ b/src/createStore.ts @@ -23,6 +23,7 @@ import { IAsyncProduce, IHooks, IHooksObj, + IPersistenceMethod, IProduce, IUseStore, Selector, @@ -32,9 +33,9 @@ import { } from "./common"; import { connectDevTools, ReduxDevTools } from "./plugins/devTools"; import { - connectLocalStorage, + connectPersistenceStorage, LocalStoragePlugin, -} from "./plugins/localStorage"; +} from "./plugins/persistenceStorage"; export { createSelector } from "reselect"; export { @@ -117,12 +118,60 @@ export function createStore< * @type {boolean} */ devToolsInProduction?: boolean; + /** - * Flag to activate localStorage persistence method + * Storage persistence for the store. + * By default uses window.localStorage * - * @type {boolean} + * @type {{ + * debounceWait?: number; + * persistenceKey?: string; + * active?: boolean; + * }} */ - localStoragePersistence?: boolean; + storagePersistence?: { + /** + * The amount of milliseconds for the + * the debouncing of the calls to the + * persistence method, by default 3000 ms + * + * @type {number} + */ + debounceWait?: number; + /** + * The key used in the persistence method. + * If not specified, it uses the "devName" + * + * @type {string} + */ + persistenceKey?: string; + /** + * Flag to activate or deactivate the + * persistence. + * "false" by default. + * + * @type {boolean} + */ + isActive?: boolean; + /** + * Persistence method used, by default it + * uses localStorage + * + * @type {IPersistenceMethod} + */ + persistenceMethod?: IPersistenceMethod; + /** + * Flag used to specify that this store + * is going to be used in server side + * rendering context, this flag prevents + * client/server mismatched html + * on client side hydration + * + * "false" by default. + * @type {boolean} + */ + isSSR?: boolean; + }; } ): { /** @@ -295,16 +344,25 @@ export function createStore< }, }; - if (options?.localStoragePersistence && options.devName) { - if (typeof initialStore !== "object") { + if (options?.storagePersistence?.isActive) { + if (typeof initialStore !== "object" || Array.isArray(initialStore)) throw new Error( "For local storage persistence your store has to be an object" ); - } - localStoragePlugin = connectLocalStorage( - options.devName, - produceObj.produce - ); + + const persistenceKey = + options.storagePersistence.persistenceKey || options.devName; + + if (!persistenceKey) + throw new Error("You have to specify persistence key or devName"); + + localStoragePlugin = connectPersistenceStorage({ + persistenceKey, + produce: produceObj.produce, + debounceWait: options.storagePersistence.debounceWait, + persistenceMethod: options.storagePersistence.persistenceMethod, + isSSR: options.storagePersistence.isSSR, + }); } const actionsObj: Record< diff --git a/src/plugins/localStorage.ts b/src/plugins/localStorage.ts deleted file mode 100644 index 5115985..0000000 --- a/src/plugins/localStorage.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { IProduce, isClientSide } from "../common"; - -export type LocalStoragePlugin = { - getState: () => void; - setState: (state: T) => void; -}; - -export const connectLocalStorage = ( - persistenceName: string, - produce: IProduce, - wait = 3000, - persistenceMethod = isClientSide ? window.localStorage : undefined -): LocalStoragePlugin => { - let isConnected = false; - let timeout: NodeJS.Timeout | undefined; - - const setStateFn = (state: T) => { - if (persistenceMethod) { - persistenceMethod.setItem(persistenceName, JSON.stringify(state)); - if (!isConnected) isConnected = true; - } - }; - - const setState = (state: T) => { - const execLater = () => { - timeout = undefined; - setStateFn(state); - }; - if (timeout !== undefined) clearTimeout(timeout); - timeout = setTimeout(execLater, wait); - }; - - return { - getState: () => { - if (isConnected) return; - - try { - const state = persistenceMethod?.getItem(persistenceName); - if (state === undefined) { - isConnected = true; - } else if (state != null) { - produce(() => ({ - ...produce(), - ...JSON.parse(state), - })); - isConnected = true; - return; - } - } catch (err) {} - return; - }, - setState, - }; -}; diff --git a/src/plugins/persistenceStorage.ts b/src/plugins/persistenceStorage.ts new file mode 100644 index 0000000..81b00cf --- /dev/null +++ b/src/plugins/persistenceStorage.ts @@ -0,0 +1,77 @@ +import { IPersistenceMethod, IProduce, isClientSide } from "../common"; + +export type LocalStoragePlugin = { + getState: () => void; + setState: (state: T) => void; + current: Pick< + ConnectPersistenceStorageArgs, + "persistenceKey" | "isSSR" | "persistenceMethod" | "debounceWait" + > & { isConnected: boolean }; +}; + +export type ConnectPersistenceStorageArgs = { + persistenceKey: string; + produce: IProduce; + debounceWait?: number; + persistenceMethod?: IPersistenceMethod | undefined; + isSSR?: boolean; +}; + +export const connectPersistenceStorage = ({ + persistenceKey: persistenceName, + produce, + debounceWait = 3000, + persistenceMethod = isClientSide ? window.localStorage : undefined, + isSSR, +}: ConnectPersistenceStorageArgs): LocalStoragePlugin => { + let isConnected = false; + let timeout: NodeJS.Timeout | undefined; + + const setStateFn = (state: unknown) => { + if (persistenceMethod) { + persistenceMethod.setItem(persistenceName, JSON.stringify(state)); + if (!isConnected) isConnected = true; + } + }; + + const setState = (state: unknown) => { + const execLater = () => { + timeout = undefined; + setStateFn(state); + }; + if (timeout !== undefined) clearTimeout(timeout); + timeout = setTimeout(execLater, debounceWait); + }; + + const getState = () => { + if (isConnected || !persistenceMethod) return; + + try { + const state = persistenceMethod.getItem(persistenceName); + if (state == null) { + isConnected = true; + return; + } + + produce(() => ({ + ...produce(), + ...JSON.parse(state), + })); + isConnected = true; + } catch (err) {} + }; + + if (!isSSR) getState(); + + return { + getState, + setState, + current: { + persistenceKey: persistenceName, + persistenceMethod, + isSSR, + isConnected, + debounceWait, + }, + }; +}; diff --git a/test/persistenceStorageBrowser.test.tsx b/test/persistenceStorageBrowser.test.tsx new file mode 100644 index 0000000..cd40353 --- /dev/null +++ b/test/persistenceStorageBrowser.test.tsx @@ -0,0 +1,248 @@ +import waitForExpect from "wait-for-expect"; + +import { cleanup, renderHook } from "@testing-library/react-hooks"; + +import { createStore } from "../src"; +import { mockLocalStorage } from "./utils/localStorage"; + +afterEach(async () => { + await cleanup(); +}); + +describe("default persistence on localStorage works", () => { + test("gets data from localStorage", () => { + const initialState = { a: 1 }; + const rememberedInitialState = { a: 2 }; + const persistenceKey = "gets_data_from_localStorage"; + localStorage.setItem( + persistenceKey, + JSON.stringify(rememberedInitialState) + ); + const StoreRemember = createStore(initialState, { + storagePersistence: { + persistenceKey, + isActive: true, + }, + }); + + localStorage.removeItem(persistenceKey); + const StoreNoRemember = createStore(initialState, { + storagePersistence: { + persistenceKey, + isActive: true, + }, + }); + + expect(StoreNoRemember.produce()).toEqual(initialState); + expect(StoreRemember.produce()).toEqual(rememberedInitialState); + }); + + test("debounces calls to the persistence method", async () => { + const initialState = { a: 1 }; + const rememberedInitialState = { a: 2 }; + const persistenceKey = "gets_data_from_localStorage"; + + const mockedLocalStorage = mockLocalStorage(); + + localStorage.setItem( + persistenceKey, + JSON.stringify(rememberedInitialState) + ); + + const StoreRemember = createStore(initialState, { + storagePersistence: { + persistenceKey, + isActive: true, + debounceWait: 1000, + }, + }); + + expect(mockedLocalStorage.localStorageMock.getItem).toBeCalledTimes(1); + + expect(mockedLocalStorage.localStorageMock.setItem).toBeCalledTimes(1); + + expect(StoreRemember.produce()).toEqual(rememberedInitialState); + + expect( + StoreRemember.produce((draft) => { + draft.a = 4; + }) + ); + + expect(StoreRemember.produce()).toEqual({ a: 4 }); + + expect(mockedLocalStorage.localStorageMock.setItem).toBeCalledTimes(1); + + expect(window.localStorage.getItem(persistenceKey)).toEqual( + JSON.stringify({ a: 2 }) + ); + + expect( + StoreRemember.produce((draft) => { + draft.a = 5; + }) + ); + + expect(StoreRemember.produce()).toEqual({ a: 5 }); + + expect( + StoreRemember.produce((draft) => { + draft.a = 6; + }) + ); + expect(StoreRemember.produce()).toEqual({ a: 6 }); + + await waitForExpect( + async () => { + expect(mockedLocalStorage.localStorageMock.setItem).toBeCalledTimes(2); + }, + 1000, + 100 + ); + + expect(window.localStorage.getItem(persistenceKey)).toEqual( + JSON.stringify({ a: 6 }) + ); + + expect(mockedLocalStorage.localStorageMock.getItem).toBeCalledTimes(3); + + mockedLocalStorage.unmockLocalStorage(); + }); + + test("edge cases", () => { + const persistenceKey = "edgeCasesBrowser"; + const Store = createStore( + { a: 1 }, + { + storagePersistence: { + persistenceKey, + isActive: true, + isSSR: true, + }, + } + ); + + const Case1 = renderHook(() => { + return Store.useStore(); + }); + + const Case2 = renderHook(() => { + return Store.useStore(); + }); + + expect(Case1.result.current).toEqual({ a: 1 }); + expect(Case2.result.current).toEqual({ a: 1 }); + + // const StoreSSR = createStore({a: 1}, { + // storagePersistence: { + // persistenceKey, + // isActive: true, + // isSSR: true + // } + // }) + }); + + test("work with asyncProduce, actions and asyncActions", async () => { + const persistenceKey = "asyncStore"; + const storagePersistence = mockLocalStorage(); + const Store = createStore( + { + a: 1, + }, + { + actions: { + increment: () => (draft) => { + draft.a += 1; + }, + }, + asyncActions: { + asyncIncrement: (produce) => async () => { + produce((draft) => { + draft.a += 1; + }); + }, + }, + storagePersistence: { + debounceWait: 500, + persistenceKey, + isActive: true, + persistenceMethod: storagePersistence.localStorageMock, + }, + } + ); + + expect(Store.produce()).toEqual({ a: 1 }); + + expect(storagePersistence.localStorageMock.setItem).toBeCalledTimes(0); + + expect(storagePersistence.localStorageMock.getItem).toBeCalledTimes(1); + + await expect( + Store.asyncProduce(async (draft) => { + draft.a += 1; + }) + ).resolves.toEqual({ a: 2 }); + + await waitForExpect(() => { + expect(storagePersistence.localStorageMock.setItem).toBeCalledTimes(1); + }); + + expect(storagePersistence.localStorageMock.getItem(persistenceKey)).toBe( + JSON.stringify({ a: 2 }) + ); + + expect(storagePersistence.localStorageMock.getItem).toBeCalledTimes(2); + + expect(Store.actions.increment()).toEqual({ a: 3 }); + + expect(storagePersistence.localStorageMock.getItem).toBeCalledTimes(2); + + await expect(Store.actions.asyncIncrement()).resolves.toEqual({ + a: 4, + }); + + expect(storagePersistence.localStorageMock.getItem(persistenceKey)).toBe( + JSON.stringify({ a: 2 }) + ); + + expect(storagePersistence.localStorageMock.getItem).toBeCalledTimes(3); + + expect(storagePersistence.localStorageMock.setItem).toBeCalledTimes(1); + + await waitForExpect(() => { + expect(storagePersistence.localStorageMock.setItem).toBeCalledTimes(2); + }); + + expect(storagePersistence.localStorageMock.getItem(persistenceKey)).toBe( + JSON.stringify({ a: 4 }) + ); + + storagePersistence.unmockLocalStorage(); + }); + + test("throw incorrect store type", () => { + expect(() => { + createStore([], { + storagePersistence: { + isActive: true, + persistenceKey: "asd", + }, + }); + }).toThrowError( + "For local storage persistence your store has to be an object" + ); + }); + + test("throw no persistence key nor dev name", () => { + expect(() => { + createStore( + {}, + { + storagePersistence: { + isActive: true, + }, + } + ); + }).toThrowError("You have to specify persistence key or devName"); + }); +}); diff --git a/test/persistenceStorageServer.test.tsx b/test/persistenceStorageServer.test.tsx new file mode 100644 index 0000000..22cfafa --- /dev/null +++ b/test/persistenceStorageServer.test.tsx @@ -0,0 +1,96 @@ +/** + * @jest-environment node + */ + +import waitForExpect from "wait-for-expect"; + +import { createStore } from "../src"; +import { mockLocalStorage } from "./utils/localStorage"; + +describe("on server it gets ignored", () => { + test("is ignored", () => { + const initialState = { a: 1 }; + const persistenceKey = "gets_data_from_localStorage_server"; + + const StoreRemember = createStore(initialState, { + storagePersistence: { + persistenceKey, + isActive: true, + isSSR: true, + }, + }); + const StoreNoRemember = createStore(initialState, { + storagePersistence: { + persistenceKey, + isActive: false, + }, + }); + + expect(StoreNoRemember.produce()).toEqual(initialState); + expect(StoreRemember.produce()).toEqual(initialState); + + StoreRemember.produce((draft) => { + draft.a = 2; + }); + + expect(StoreRemember.produce()).toEqual({ a: 2 }); + }); + + test("edge cases", async () => { + const persistenceKey = "edgeCases"; + const Store = createStore( + { + a: 1, + }, + { + devName: persistenceKey, + storagePersistence: { + debounceWait: 0, + isActive: true, + isSSR: true, + persistenceMethod: null as any, + }, + } + ); + + expect(Store.produce()).toEqual({ a: 1 }); + Store.produce((draft) => { + draft.a = 2; + }); + expect(Store.produce()).toEqual({ a: 2 }); + }); + + test("mocking localStorage on server", async () => { + const mockStorage = mockLocalStorage(false); + + const persistenceKey = "mockServer"; + const Store = createStore( + { a: 1 }, + { + storagePersistence: { + persistenceKey, + isActive: true, + persistenceMethod: mockStorage.localStorageMock, + isSSR: true, + debounceWait: 500, + }, + } + ); + expect(mockStorage.localStorageMock.getItem).toBeCalledTimes(0); + + expect(Store.produce()).toEqual({ a: 1 }); + expect(mockStorage.localStorageMock.setItem).toBeCalledTimes(0); + + Store.produce((draft) => { + draft.a = 2; + }); + expect(Store.produce()).toEqual({ a: 2 }); + expect(mockStorage.localStorageMock.getItem(persistenceKey)).toEqual(null); + await waitForExpect(async () => { + expect(mockStorage.localStorageMock.setItem).toBeCalledTimes(1); + }); + expect(mockStorage.localStorageMock.getItem(persistenceKey)).toEqual( + JSON.stringify({ a: 2 }) + ); + }); +}); diff --git a/test/utils/localStorage.ts b/test/utils/localStorage.ts new file mode 100644 index 0000000..033da94 --- /dev/null +++ b/test/utils/localStorage.ts @@ -0,0 +1,42 @@ +const previousLocalStorage = + typeof window !== "undefined" ? window.localStorage : undefined; + +export const mockLocalStorage = (mockWindow = true) => { + const storageState: Record = {}; + + const localStorageMock = { + key: jest.fn(), + clear: jest.fn(), + getItem: jest.fn(), + removeItem: jest.fn(), + length: 0, + setItem: jest.fn(), + }; + + localStorageMock.getItem.mockImplementation((key: string) => { + return storageState[key] ?? null; + }); + localStorageMock.setItem.mockImplementation((key: string, data: string) => { + storageState[key] = data; + }); + localStorageMock.removeItem((key: string) => { + delete storageState[key]; + }); + + if (mockWindow) + Object.defineProperty(window, "localStorage", { + value: localStorageMock, + }); + + const unmockLocalStorage = () => { + if (mockWindow) + Object.defineProperty(window, "localStorage", { + value: previousLocalStorage, + }); + }; + + return { + localStorageMock, + unmockLocalStorage, + }; +}; diff --git a/yarn.lock b/yarn.lock index f1e72f8..501ba5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2813,7 +2813,7 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== -"@types/minimatch@*": +"@types/minimatch@*", "@types/minimatch@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== @@ -3712,6 +3712,11 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= +array-differ@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" + integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== + array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" @@ -3743,6 +3748,11 @@ array-union@^1.0.1: dependencies: array-uniq "^1.0.1" +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -3785,6 +3795,11 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + asap@~2.0.3, asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -6719,6 +6734,21 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-2.1.0.tgz#e5d3ecd837d2a60ec50f3da78fd39767747bbe99" + integrity sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^3.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -7985,6 +8015,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" + integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== + immer@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" @@ -10137,6 +10172,11 @@ mri@^1.1.0: resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== +mri@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.5.tgz#ce21dba2c69f74a9b7cf8a1ec62307e089e223e0" + integrity sha512-d2RKzMD4JNyHMbnbWnznPaa8vbdlq/4pNZ3IgdaGrVbBhebBsGUUE/6qorTMYNS6TwuH3ilfOlD2bf4Igh8CKg== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -10165,6 +10205,17 @@ multicast-dns@^6.0.1: dns-packet "^1.3.1" thunky "^1.0.2" +multimatch@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3" + integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ== + dependencies: + "@types/minimatch" "^3.0.3" + array-differ "^3.0.0" + array-union "^2.1.0" + arrify "^2.0.1" + minimatch "^3.0.4" + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -10380,6 +10431,13 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" +npm-run-path@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" + integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== + dependencies: + path-key "^3.0.0" + npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -11816,6 +11874,18 @@ pretty-hrtime@^1.0.3: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= +pretty-quick@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-2.0.1.tgz#417ee605ade98ecc686e72f63b5d28a2c35b43e9" + integrity sha512-y7bJt77XadjUr+P1uKqZxFWLddvj3SKY6EU4BuQtMxmmEFSMpbN132pUWdSG1g1mtUfO0noBvn7wBf0BVeomHg== + dependencies: + chalk "^2.4.2" + execa "^2.1.0" + find-up "^4.1.0" + ignore "^5.1.4" + mri "^1.1.4" + multimatch "^4.0.0" + prismjs@^1.8.4: version "1.19.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.19.0.tgz#713afbd45c3baca4b321569f2df39e17e729d4dc" From 250bf21fa24f95053fadada9bbb58d110a4c592d Mon Sep 17 00:00:00 2001 From: PabloSzx Date: Wed, 25 Mar 2020 21:54:20 -0300 Subject: [PATCH 6/8] persistence storage for createStoreContext --- src/common.ts | 6 +- src/createStore.ts | 57 +---- src/createStoreContext.ts | 320 ++++++++++++++---------- src/index.ts | 1 + src/plugins/persistenceStorage.ts | 57 ++++- test/persistenceStorageBrowser.test.tsx | 201 ++++++++++++++- 6 files changed, 437 insertions(+), 205 deletions(-) diff --git a/src/common.ts b/src/common.ts index 6124409..30a4379 100644 --- a/src/common.ts +++ b/src/common.ts @@ -4,7 +4,7 @@ import { Draft, enablePatches, Immutable } from "immer"; import { useCallback, useEffect, useLayoutEffect, useState } from "react"; import { ParametricSelector } from "reselect"; -import { LocalStoragePlugin } from "./plugins/persistenceStorage"; +import { PersistenceStoragePlugin } from "./plugins/persistenceStorage"; enablePatches(); @@ -27,7 +27,9 @@ const incrementParameter = (num: number) => ++num; export const emptyArray: [] = []; -export const useUpdate = (persistencePlugin?: LocalStoragePlugin) => { +export const useUpdate = ( + persistencePlugin?: PersistenceStoragePlugin | null +) => { const [, setState] = useState(0); useEffect(() => { diff --git a/src/createStore.ts b/src/createStore.ts index 786f812..1ed321a 100644 --- a/src/createStore.ts +++ b/src/createStore.ts @@ -23,7 +23,6 @@ import { IAsyncProduce, IHooks, IHooksObj, - IPersistenceMethod, IProduce, IUseStore, Selector, @@ -34,7 +33,8 @@ import { import { connectDevTools, ReduxDevTools } from "./plugins/devTools"; import { connectPersistenceStorage, - LocalStoragePlugin, + IPersistenceOptions, + PersistenceStoragePlugin, } from "./plugins/persistenceStorage"; export { createSelector } from "reselect"; @@ -123,55 +123,9 @@ export function createStore< * Storage persistence for the store. * By default uses window.localStorage * - * @type {{ - * debounceWait?: number; - * persistenceKey?: string; - * active?: boolean; - * }} + * @type {IPersistenceOptions} */ - storagePersistence?: { - /** - * The amount of milliseconds for the - * the debouncing of the calls to the - * persistence method, by default 3000 ms - * - * @type {number} - */ - debounceWait?: number; - /** - * The key used in the persistence method. - * If not specified, it uses the "devName" - * - * @type {string} - */ - persistenceKey?: string; - /** - * Flag to activate or deactivate the - * persistence. - * "false" by default. - * - * @type {boolean} - */ - isActive?: boolean; - /** - * Persistence method used, by default it - * uses localStorage - * - * @type {IPersistenceMethod} - */ - persistenceMethod?: IPersistenceMethod; - /** - * Flag used to specify that this store - * is going to be used in server side - * rendering context, this flag prevents - * client/server mismatched html - * on client side hydration - * - * "false" by default. - * @type {boolean} - */ - isSSR?: boolean; - }; + storagePersistence?: IPersistenceOptions; } ): { /** @@ -235,7 +189,7 @@ export function createStore< } let devTools: ReduxDevTools | undefined; - let localStoragePlugin: LocalStoragePlugin | undefined; + let localStoragePlugin: PersistenceStoragePlugin | undefined | null; if ( options?.devName && @@ -423,7 +377,6 @@ export function createStore< asyncActionsObj[actionName] = async (...args) => { await actionFn(produceObj.produce)(...args); - localStoragePlugin?.setState(currentStore as TStore); return currentStore; }; } diff --git a/src/createStoreContext.ts b/src/createStoreContext.ts index 29b6f14..79b7474 100644 --- a/src/createStoreContext.ts +++ b/src/createStoreContext.ts @@ -42,6 +42,11 @@ import { useUpdate, } from "./common"; import { connectDevTools, ReduxDevTools } from "./plugins/devTools"; +import { + connectPersistenceStorage, + IPersistenceOptions, + PersistenceStoragePlugin, +} from "./plugins/persistenceStorage"; /** * Create React Context version of a **react-state-selector** global store @@ -115,6 +120,14 @@ export function createStoreContext< * @type {boolean} */ devToolsInProduction?: boolean; + + /** + * Storage persistence options for the store. + * By default uses window.localStorage + * + * @type {IPersistenceOptions} + */ + storagePersistence?: IPersistenceOptions; } ): { /** @@ -180,72 +193,188 @@ export function createStoreContext< } } - const StoreContext = createContext< - MutableRefObject<{ - store: Immutable; - listeners: Map< - ParametricSelector, unknown, unknown>, - unknown - >; - devTools: ReduxDevTools | undefined; - actions?: IActionsObj & - IAsyncActionsObj; - produce?: { - produce: IProduce; - asyncProduce: IAsyncProduce; - }; - }> - >({ - current: { - store: initialStore, - listeners: new Map(), - devTools: (() => { - if ( - options?.devName && - (options.devToolsInProduction || - process.env.NODE_ENV !== "production") - ) { - const devTools = connectDevTools(options.devName + "-noProvider"); - if (devTools) { - devTools.init(initialStore); - } - return devTools; - } - return undefined; - })(), - }, - }); + const createStoragePersistenceInstance = ( + produceStore: IProduce, + debugName?: string | null + ) => { + if (options?.storagePersistence?.isActive) { + if (typeof initialStore !== "object" || Array.isArray(initialStore)) + throw new Error( + "For local storage persistence your store has to be an object" + ); + + const persistenceKey = + options.storagePersistence.persistenceKey || + debugName || + options.devName; + + if (!persistenceKey) + throw new Error( + "You have to specify persistence key, debugName or devName" + ); + + return connectPersistenceStorage({ + persistenceKey, + produce: produceStore, + debounceWait: options.storagePersistence.debounceWait, + persistenceMethod: options.storagePersistence.persistenceMethod, + isSSR: options.storagePersistence.isSSR, + }); + } + return null; + }; + + const createDevToolsInstance = (debugName?: string | null) => { + if ( + options?.devName && + (options.devToolsInProduction || process.env.NODE_ENV !== "production") + ) { + let devToolsName: string; + if (debugName) { + devToolsName = options.devName + "-" + debugName; + } else if (debugName === null) { + devToolsName = options.devName + "-noProvider"; + } else { + devToolsName = options.devName; + } + const devTools = connectDevTools(devToolsName); + if (devTools) { + devTools.init(initialStore); + } + return devTools; + } + return undefined; + }; + + type IStore = { + store: Immutable; + listeners: Map< + ParametricSelector, unknown, unknown>, + unknown + >; + devTools: ReduxDevTools | undefined; + actions?: IActionsObj & + IAsyncActionsObj; + produce: { + produce: IProduce; + asyncProduce: IAsyncProduce; + }; + storagePersistence?: PersistenceStoragePlugin | null; + }; - const providerRefCallback = (debugName?: string) => () => { + const createProduceObj = ( + storeRef: Pick< + IStore, + "devTools" | "store" | "listeners" | "storagePersistence" + > + ) => { return { - store: initialStore, - listeners: new Map>, unknown /* props */>(), - devTools: (() => { - if ( - options?.devName && - (options.devToolsInProduction || - process.env.NODE_ENV !== "production") - ) { - const devTools = connectDevTools( - debugName ? options.devName + "-" + debugName : options.devName + produce: (draft?: (draft: Draft) => void) => { + if (typeof draft !== "function") return storeRef.store; + + if (storeRef.devTools) { + const produceFn = produceWithPatches< + (draft: Draft) => void, + [Draft], + TStore + >(draft); + + const produceResult = produceFn(storeRef.store); + + storeRef.store = produceResult[0]; + storeRef.devTools.send( + { + type: "produce", + payload: produceResult[1], + }, + storeRef.store ); - if (devTools) { - devTools.init(initialStore); - } - return devTools; + } else { + const produceFn = produce< + (draft: Draft) => void, + [Draft], + TStore + >(draft); + + storeRef.store = produceFn(storeRef.store); } - return undefined; - })(), + + storeRef.listeners.forEach((props, listener) => { + listener(storeRef.store, props); + }); + + storeRef.storagePersistence?.setState(storeRef.store); + + return storeRef.store; + }, + asyncProduce: async (draft?: (draft: Draft) => Promise) => { + if (typeof draft !== "function") return storeRef.store; + + const storeDraft = createDraft(storeRef.store as TStore); + + await Promise.resolve(draft(storeDraft)); + + finishDraft(storeDraft, (changes) => { + if (changes.length) { + storeRef.store = applyPatches(storeRef.store, changes); + + if (storeRef.devTools) { + storeRef.devTools.send( + { + type: "asyncProduce", + payload: changes, + }, + storeRef.store + ); + } + + storeRef.listeners.forEach((props, listener) => { + listener(storeRef.store, props); + }); + } + }); + + storeRef.storagePersistence?.setState(storeRef.store); + + return storeRef.store; + }, }; }; + const providerRefCallback = (debugName?: string | null) => () => { + const storeRef: Pick< + IStore, + "store" | "listeners" | "devTools" | "storagePersistence" + > & + Partial> = { + store: initialStore, + listeners: new Map>, unknown /* props */>(), + devTools: createDevToolsInstance(debugName), + }; + + const produceObj = createProduceObj(storeRef); + + storeRef.produce = produceObj; + + storeRef.storagePersistence = createStoragePersistenceInstance( + produceObj.produce, + debugName + ); + + return Object.assign(storeRef, { produce: produceObj }); + }; + + const StoreContext = createContext>({ + current: providerRefCallback(null)(), + }); + const Provider: FunctionComponent<{ debugName?: string }> = memo( ({ children, debugName }) => { const initialRef = useMemo(providerRefCallback(debugName), emptyArray); - const valueRef = useRef(initialRef); + const value = useRef(initialRef); return createElement(StoreContext.Provider, { - value: valueRef, + value, children, }); } @@ -253,7 +382,7 @@ export function createStoreContext< const useStore = () => { const storeCtx = useContext(StoreContext); - const update = useUpdate(); + const update = useUpdate(storeCtx.current.storagePersistence); useIsomorphicLayoutEffect(() => { const globalListener = createSelector( @@ -275,84 +404,7 @@ export function createStoreContext< const useProduce = () => { const storeCtx = useContext(StoreContext); - return useMemo(() => { - if (storeCtx.current.produce === undefined) { - storeCtx.current.produce = { - produce: (draft?: (draft: Draft) => void) => { - if (typeof draft !== "function") return storeCtx.current.store; - - if (storeCtx.current.devTools) { - const produceFn = produceWithPatches< - (draft: Draft) => void, - [Draft], - TStore - >(draft); - - const produceResult = produceFn(storeCtx.current.store); - - storeCtx.current.store = produceResult[0]; - storeCtx.current.devTools.send( - { - type: "produce", - payload: produceResult[1], - }, - storeCtx.current.store - ); - } else { - const produceFn = produce< - (draft: Draft) => void, - [Draft], - TStore - >(draft); - - storeCtx.current.store = produceFn(storeCtx.current.store); - } - - storeCtx.current.listeners.forEach((props, listener) => { - listener(storeCtx.current.store, props); - }); - - return storeCtx.current.store; - }, - asyncProduce: async ( - draft?: (draft: Draft) => Promise - ) => { - if (typeof draft !== "function") return storeCtx.current.store; - - const storeDraft = createDraft(storeCtx.current.store as TStore); - - await Promise.resolve(draft(storeDraft)); - - finishDraft(storeDraft, (changes) => { - if (changes.length) { - storeCtx.current.store = applyPatches( - storeCtx.current.store, - changes - ); - - if (storeCtx.current.devTools) { - storeCtx.current.devTools.send( - { - type: "asyncProduce", - payload: changes, - }, - storeCtx.current.store - ); - } - - storeCtx.current.listeners.forEach((props, listener) => { - listener(storeCtx.current.store, props); - }); - } - }); - - return storeCtx.current.store; - }, - }; - } - - return storeCtx.current.produce; - }, [storeCtx]); + return storeCtx.current.produce; }; const useActions = () => { @@ -446,7 +498,7 @@ export function createStoreContext< ) => { const storeCtx = useContext(StoreContext); - const update = useUpdate(); + const update = useUpdate(storeCtx.current.storagePersistence); const props = useMemo( toAnonFunction(hooksProps), diff --git a/src/index.ts b/src/index.ts index 452d8ca..2ed0896 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,4 +19,5 @@ export { IHooks, IActions, IAsyncActions, + IPersistenceMethod, } from "./common"; diff --git a/src/plugins/persistenceStorage.ts b/src/plugins/persistenceStorage.ts index 81b00cf..bd16181 100644 --- a/src/plugins/persistenceStorage.ts +++ b/src/plugins/persistenceStorage.ts @@ -1,6 +1,6 @@ import { IPersistenceMethod, IProduce, isClientSide } from "../common"; -export type LocalStoragePlugin = { +export type PersistenceStoragePlugin = { getState: () => void; setState: (state: T) => void; current: Pick< @@ -9,6 +9,50 @@ export type LocalStoragePlugin = { > & { isConnected: boolean }; }; +export type IPersistenceOptions = { + /** + * The amount of milliseconds for the + * the debouncing of the calls to the + * persistence method, by default 3000 ms + * + * @type {number} + */ + debounceWait?: number; + /** + * The key used in the persistence method. + * If not specified, it uses the "devName" + * + * @type {string} + */ + persistenceKey?: string; + /** + * Flag to activate or deactivate the + * persistence. + * "false" by default. + * + * @type {boolean} + */ + isActive?: boolean; + /** + * Persistence method used, by default it + * uses localStorage + * + * @type {IPersistenceMethod} + */ + persistenceMethod?: IPersistenceMethod; + /** + * Flag used to specify that this store + * is going to be used in server side + * rendering context, this flag prevents + * client/server mismatched html + * on client side hydration + * + * "false" by default. + * @type {boolean} + */ + isSSR?: boolean; +}; + export type ConnectPersistenceStorageArgs = { persistenceKey: string; produce: IProduce; @@ -23,15 +67,15 @@ export const connectPersistenceStorage = ({ debounceWait = 3000, persistenceMethod = isClientSide ? window.localStorage : undefined, isSSR, -}: ConnectPersistenceStorageArgs): LocalStoragePlugin => { +}: ConnectPersistenceStorageArgs): PersistenceStoragePlugin | null => { + if (!persistenceMethod) return null; + let isConnected = false; let timeout: NodeJS.Timeout | undefined; const setStateFn = (state: unknown) => { - if (persistenceMethod) { - persistenceMethod.setItem(persistenceName, JSON.stringify(state)); - if (!isConnected) isConnected = true; - } + persistenceMethod.setItem(persistenceName, JSON.stringify(state)); + if (!isConnected) isConnected = true; }; const setState = (state: unknown) => { @@ -48,6 +92,7 @@ export const connectPersistenceStorage = ({ try { const state = persistenceMethod.getItem(persistenceName); + if (state == null) { isConnected = true; return; diff --git a/test/persistenceStorageBrowser.test.tsx b/test/persistenceStorageBrowser.test.tsx index cd40353..71d90a1 100644 --- a/test/persistenceStorageBrowser.test.tsx +++ b/test/persistenceStorageBrowser.test.tsx @@ -1,15 +1,16 @@ +import { createElement } from "react"; import waitForExpect from "wait-for-expect"; -import { cleanup, renderHook } from "@testing-library/react-hooks"; +import { act, cleanup, renderHook } from "@testing-library/react-hooks"; -import { createStore } from "../src"; +import { createStore, createStoreContext } from "../src"; import { mockLocalStorage } from "./utils/localStorage"; afterEach(async () => { await cleanup(); }); -describe("default persistence on localStorage works", () => { +describe("createStore", () => { test("gets data from localStorage", () => { const initialState = { a: 1 }; const rememberedInitialState = { a: 2 }; @@ -132,14 +133,6 @@ describe("default persistence on localStorage works", () => { expect(Case1.result.current).toEqual({ a: 1 }); expect(Case2.result.current).toEqual({ a: 1 }); - - // const StoreSSR = createStore({a: 1}, { - // storagePersistence: { - // persistenceKey, - // isActive: true, - // isSSR: true - // } - // }) }); test("work with asyncProduce, actions and asyncActions", async () => { @@ -246,3 +239,189 @@ describe("default persistence on localStorage works", () => { }).toThrowError("You have to specify persistence key or devName"); }); }); + +describe("createStoreContext", () => { + test("correct usage", async () => { + const persistenceKey = "createStoreCtx"; + + localStorage.setItem(persistenceKey, JSON.stringify({ a: 4 })); + + const StoreRemember = createStoreContext( + { + a: 1, + }, + { + devName: persistenceKey, + storagePersistence: { + persistenceKey, + isActive: true, + }, + } + ); + + const StoreNoRemember = createStoreContext( + { + a: 1, + }, + { + devName: persistenceKey, + storagePersistence: { + persistenceKey, + isActive: false, + debounceWait: 1000, + }, + } + ); + + const wrapper = (debugName: string, store: typeof StoreRemember) => ( + props: any + ) => { + return createElement(store.Provider, { + debugName, + ...props, + }); + }; + + const rememberedState = renderHook( + () => { + const store = StoreRemember.useStore(); + const produce = StoreRemember.useProduce(); + + return { store, produce }; + }, + { + wrapper: wrapper(persistenceKey, StoreRemember), + } + ); + + const notRememberedState = renderHook( + () => { + const store = StoreNoRemember.useStore(); + const produce = StoreNoRemember.useProduce(); + + return { store, produce }; + }, + { + wrapper: wrapper(persistenceKey, StoreNoRemember), + } + ); + + expect(rememberedState.result.current.store).toEqual({ a: 4 }); + expect(notRememberedState.result.current.store).toEqual({ a: 1 }); + + act(() => { + rememberedState.result.current.produce.produce((draft) => { + draft.a = 10; + }); + + notRememberedState.result.current.produce.produce((draft) => { + draft.a = 20; + }); + }); + + expect(rememberedState.result.current.store).toEqual({ a: 10 }); + expect(notRememberedState.result.current.store).toEqual({ a: 20 }); + + await act(async () => { + rememberedState.result.current.produce.asyncProduce(async (draft) => { + draft.a = 100; + }); + + notRememberedState.result.current.produce.asyncProduce(async (draft) => { + draft.a = 200; + }); + }); + + expect(rememberedState.result.current.store).toEqual({ a: 100 }); + expect(notRememberedState.result.current.store).toEqual({ a: 200 }); + + expect(localStorage.getItem(persistenceKey)).toEqual( + JSON.stringify({ a: 4 }) + ); + + await waitForExpect(async () => { + expect(localStorage.getItem(persistenceKey)).toEqual( + JSON.stringify({ a: 100 }) + ); + }); + + expect(localStorage.getItem(persistenceKey)).toEqual( + JSON.stringify({ a: 100 }) + ); + }); + + test("no provider should work anyway", async () => { + const persistenceKey = "noProviderStoreCtx"; + + localStorage.setItem(persistenceKey, JSON.stringify({ a: 10 })); + + const Store = createStoreContext( + { + a: 1, + }, + { + storagePersistence: { + debounceWait: 1000, + persistenceKey, + isActive: true, + }, + } + ); + + const HookResult = renderHook(() => { + const store = Store.useStore(); + const produce = Store.useProduce(); + + return { + store, + produce, + }; + }); + + expect(HookResult.result.current.store).toEqual({ a: 10 }); + + act(() => { + HookResult.result.current.produce.produce((draft) => { + draft.a = 20; + }); + }); + + expect(HookResult.result.current.store).toEqual({ a: 20 }); + + expect(localStorage.getItem(persistenceKey)).toBe( + JSON.stringify({ a: 10 }) + ); + + await waitForExpect(() => { + expect(localStorage.getItem(persistenceKey)).toBe( + JSON.stringify({ a: 20 }) + ); + }); + }); + + test("find wrong usage", () => { + expect(() => { + createStoreContext([], { + storagePersistence: { + isActive: true, + persistenceKey: "asd", + }, + }); + }).toThrowError( + "For local storage persistence your store has to be an object" + ); + + expect(() => { + createStoreContext( + {}, + { + storagePersistence: { + isActive: true, + }, + } + ); + }).toThrowError( + "You have to specify persistence key, debugName or devName" + ); + }); +}); From 948d77dbe9c7eabc76a04edde55a50d30b060ea9 Mon Sep 17 00:00:00 2001 From: PabloSzx Date: Wed, 25 Mar 2020 21:55:13 -0300 Subject: [PATCH 7/8] v1.0.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 650ca81..f397f77 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-state-selector", - "version": "1.0.4", + "version": "1.0.5", "keywords": [ "react", "immer", From 753b90a7da5dc80a1beb6242ae87605548cca522 Mon Sep 17 00:00:00 2001 From: PabloSzx Date: Thu, 26 Mar 2020 22:33:53 -0300 Subject: [PATCH 8/8] improve createStoreContext persistence key names --- README.md | 116 ++++++++++++++++++++---- package.json | 9 +- src/createStoreContext.ts | 20 ++-- test/persistenceStorageBrowser.test.tsx | 72 +++++++++++---- yarn.lock | 61 +++++++------ 5 files changed, 205 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index d6c3e5d..ff8a142 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,13 @@ yarn add react-state-selector > Check **https://pabloszx.github.io/react-state-selector** for more detailed examples and use cases. -### TODOs +### Features -- [x] Redux DevTools -- [x] async actions +- [x] Redux **DevTools** support +- [x] **async** actions (_**redux-thunk** alike_) - [x] **TypeScript** first class support - [x] **_reselect_** createSelector support -- [ ] **More** examples and use cases (In progress...) +- [x] Easy and efficient **localStorage** data persistence ### Basic Usage @@ -57,12 +57,12 @@ const { }, }, actions: { - incrementA: (n: number) => draft => { + incrementA: (n: number) => (draft) => { // Here you can mutate "draft", and immer will // automatically make the immutable equivalent draft.countA += n; }, - incrementB: (n: number) => draft => { + incrementB: (n: number) => (draft) => { draft.countB += n; }, }, @@ -126,12 +126,12 @@ const { }, }, actions: { - incrementA: (n: number) => draft => { + incrementA: (n: number) => (draft) => { // Here you can mutate "draft", and immer will // automatically make the immutable equivalent draft.countA += n; }, - incrementB: (n: number) => draft => { + incrementB: (n: number) => (draft) => { draft.countB += n; }, }, @@ -195,7 +195,7 @@ By default every created store gives a couple of out of the box functionality, i - If you **don't** give it a function, it will work simply as a **state getter**, so you can check the global state anytime without any restriction. ```ts -const state = produce(draft => { +const state = produce((draft) => { draft.a += 1; }); console.log(produce() === state); // true @@ -208,7 +208,7 @@ console.log(produce() === state); // true - You shouldn't rely on this feature to transform the entire state as with [produce](#produce-functiondraft--void--tstore-tstore) or [custom actions](#custom-actions); ```ts -const state = await asyncProduce(async draft => { +const state = await asyncProduce(async (draft) => { draft.users = await (await fetch("/api/users")).json(); }); console.log(produce() === state); // true @@ -251,7 +251,7 @@ const IncrementComp = () => { return (