From f25564aae97899b276925add1538e1d08805d4c0 Mon Sep 17 00:00:00 2001 From: Rhys Saldanha Date: Mon, 25 Jan 2021 22:06:21 +0000 Subject: [PATCH 1/6] Create recoil effect to partially update storage --- index.js | 51 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/index.js b/index.js index d860ad4..77d5aba 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,3 @@ -const { useTransactionObservation_UNSTABLE } = require('recoil') - /** * Recoil module to persist state to passed storage (it use localStorage by default) * @@ -13,41 +11,54 @@ const { useTransactionObservation_UNSTABLE } = require('recoil') */ function recoilPersist(paths = [], config = {}) { if (typeof window === 'undefined') { - return { RecoilPersist: () => null, updateState: () => {} } + return { + RecoilPersist: () => null, + updateState: () => {}, + } } const key = config.key || 'recoil-persist' const storage = config.storage || localStorage - function RecoilPersist() { - useTransactionObservation_UNSTABLE(persistState) - return null + function persistStateEffect({ onSet, node }) { + const name = node.key + if (paths.includes(name)) { + onSet(persistState(name)) + } } - function persistState(event) { - const toStore = {} - event.atomValues.forEach((value, atomName) => { - const name = atomName.split('__')[0] - if (paths.length === 0 || paths.includes(name)) { - toStore[name] = value - } - }) + function setState(state) { try { - storage.setItem(key, JSON.stringify(toStore)) + storage.setItem(key, JSON.stringify(state)) } catch (e) { console.error(e) } } - function updateState({ set }) { + function persistState(name) { + let state = getState() + if (state === null) { + return () => {} + } + + return (newValue) => { + state[name] = newValue + setState(state) + } + } + + function getState() { const toParse = storage.getItem(key) - let state try { - state = JSON.parse(toParse) + return JSON.parse(toParse) || {} } catch (e) { console.error(e) - return + return null } + } + + function updateState({ set }) { + let state = getState() if (state === null) { return } @@ -62,7 +73,7 @@ function recoilPersist(paths = [], config = {}) { }) } - return { RecoilPersist, updateState } + return { updateState, persistStateEffect } } module.exports = { recoilPersist } From 3cfcfc050a4d6289df5b9f1cc2da0274a5196679 Mon Sep 17 00:00:00 2001 From: Rhys Saldanha Date: Mon, 25 Jan 2021 22:06:37 +0000 Subject: [PATCH 2/6] Update demo to use recoil effect --- test/demo/index.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/test/demo/index.js b/test/demo/index.js index 7e1e4ff..ae47962 100644 --- a/test/demo/index.js +++ b/test/demo/index.js @@ -1,32 +1,26 @@ import React from 'react' import ReactDOM from 'react-dom' -import { atom, useRecoilState, RecoilRoot, atomFamily } from 'recoil' +import { atom, atomFamily, RecoilRoot, useRecoilState } from 'recoil' import { recoilPersist } from '../../index' -const { RecoilPersist, updateState } = recoilPersist(['count', 'count3']) +const { persistStateEffect, updateState } = recoilPersist(['count', 'count3']) const counterState = atom({ key: 'count', default: 0, - persistence_UNSTABLE: { - type: 'log', - }, + effects_UNSTABLE: [persistStateEffect], }) const counterState2 = atom({ key: 'count2', default: 0, - persistence_UNSTABLE: { - type: 'log', - }, + effects_UNSTABLE: [persistStateEffect], }) const counterFamily = atomFamily({ key: 'count3', default: 0, - persistence_UNSTABLE: { - type: 'log', - }, + effects_UNSTABLE: [persistStateEffect], }) export default function App() { From af336d2aeadf07cd44e8177a18fbf99ee12e2f05 Mon Sep 17 00:00:00 2001 From: Rhys Saldanha Date: Mon, 25 Jan 2021 22:12:07 +0000 Subject: [PATCH 3/6] Fix demo --- test/demo/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/demo/index.js b/test/demo/index.js index ae47962..f82530d 100644 --- a/test/demo/index.js +++ b/test/demo/index.js @@ -44,8 +44,7 @@ export default function App() { var mountNode = document.getElementById('app') ReactDOM.render( - updateState({ set })}> - + , mountNode, From 209a5bf1217df9aa9ddc4dbbe484d22ec451f4a8 Mon Sep 17 00:00:00 2001 From: Rhys Saldanha Date: Sun, 31 Jan 2021 19:35:38 +0000 Subject: [PATCH 4/6] Add typescript --- jest.config.js | 2 +- package.json | 5 ++++- tsconfig.json | 11 +++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 tsconfig.json diff --git a/jest.config.js b/jest.config.js index 1b300f0..120c3e4 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,6 @@ module.exports = { // if you're also using typescript - // preset: "ts-jest", + preset: 'ts-jest', testEnvironment: 'jsdom', verbose: true, // registers babel.config.js with jest diff --git a/package.json b/package.json index 26692b4..513e4c5 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@babel/preset-env": "^7.12.11", "@babel/preset-react": "^7.12.10", "@testing-library/react": "^11.2.3", + "@types/jest": "^26.0.20", "babel-jest": "^26.6.3", "clean-publish": "^1.1.8", "dual-publish": "^1.0.3", @@ -42,7 +43,9 @@ "prettier": "^2.2.1", "react": "^17.0.1", "react-dom": "^17.0.1", - "recoil": "^0.1.2" + "recoil": "^0.1.2", + "ts-jest": "^26.5.0", + "typescript": "^4.1.3" }, "size-limit": [ { diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..af7cbba --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "baseUrl": "./src", + "esModuleInterop": true, + "jsx": "react", + "paths": { + "~*": ["./*"] + } + }, + "include": ["src/**/*"] +} From 41bace4ee2371bca3b375749bc89a4f525964c0e Mon Sep 17 00:00:00 2001 From: Rhys Saldanha Date: Sun, 31 Jan 2021 19:37:33 +0000 Subject: [PATCH 5/6] Use recoil effects to persist and rehydrate recoil --- index.d.ts | 31 -------- index.js | 79 ------------------- src/index.ts | 75 ++++++++++++++++++ test/demo/index.js | 31 ++++---- test/index.spec.js | 184 -------------------------------------------- test/index.spec.tsx | 172 +++++++++++++++++++++++++++++++++++++++++ yarn.lock | 98 +++++++++++++++++------ 7 files changed, 339 insertions(+), 331 deletions(-) delete mode 100644 index.d.ts delete mode 100644 index.js create mode 100644 src/index.ts delete mode 100644 test/index.spec.js create mode 100644 test/index.spec.tsx diff --git a/index.d.ts b/index.d.ts deleted file mode 100644 index eeea327..0000000 --- a/index.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MutableSnapshot } from 'recoil' -import { FunctionComponent } from 'react' - -interface IPersistConfig { - // The default key to use in local storage - // default value is 'recoil-persist' - key?: string - - // Can be set as `sessionStorage` or `localStorage`. - // Defaults value is `localStorage`. - storage?: Storage -} - -/** - * Recoil module to persist state to passed storage (it use localStorage by default) - * - * @param {String[]} paths The keys of state object - * that will be store in storage - * @param {Object} config The config object - * @param {String} [config.key='recoil-persist'] The default key - * to use in local storage - * @param {Storage} [config.storage] Can be set as `sessionStorage` or - * `localStorage`. Defaults value is `localStorage`. - */ -export declare function recoilPersist( - paths?: string[], - config?: IPersistConfig, -): { - RecoilPersist: FunctionComponent - updateState: (params: MutableSnapshot) => void -} diff --git a/index.js b/index.js deleted file mode 100644 index 77d5aba..0000000 --- a/index.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Recoil module to persist state to passed storage (it use localStorage by default) - * - * @param {String[]} paths The keys of state object - * that will be store in storage - * @param {Object} config The config object - * @param {String} [config.key='recoil-persist'] The default key - * to use in local storage - * @param {Storage} [config.storage] Can be set as `sessionStorage` or - * `localStorage`. Defaults value is `localStorage`. - */ -function recoilPersist(paths = [], config = {}) { - if (typeof window === 'undefined') { - return { - RecoilPersist: () => null, - updateState: () => {}, - } - } - - const key = config.key || 'recoil-persist' - const storage = config.storage || localStorage - - function persistStateEffect({ onSet, node }) { - const name = node.key - if (paths.includes(name)) { - onSet(persistState(name)) - } - } - - function setState(state) { - try { - storage.setItem(key, JSON.stringify(state)) - } catch (e) { - console.error(e) - } - } - - function persistState(name) { - let state = getState() - if (state === null) { - return () => {} - } - - return (newValue) => { - state[name] = newValue - setState(state) - } - } - - function getState() { - const toParse = storage.getItem(key) - try { - return JSON.parse(toParse) || {} - } catch (e) { - console.error(e) - return null - } - } - - function updateState({ set }) { - let state = getState() - if (state === null) { - return - } - Object.keys(state).forEach((key) => { - if (paths.length === 0 || paths.includes(key)) { - try { - set({ key }, state[key]) - } catch (e) { - console.error(e) - } - } - }) - } - - return { updateState, persistStateEffect } -} - -module.exports = { recoilPersist } diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..2804539 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,75 @@ +import { AtomEffect } from 'recoil' + +export class PersistConfiguration { + key?: string + storage?: Storage +} + +/** + * Recoil module to persist state to storage + * + * @param config Optional configuration object + * @param config.key Used as key in local storage, defaults to `recoil-persist` + * @param config.storage Local storage to use, defaults to `localStorage` + */ +export const recoilPersist = (config: PersistConfiguration = {}): { persistAtom: AtomEffect } => { + const { + key = 'recoil-persist', + storage = localStorage, + } = config + + if (typeof window === 'undefined') { + return { + persistAtom: () => { + }, + } + } + + const persistAtom: AtomEffect = ({ onSet, node, trigger, setSelf }) => { + if (trigger === 'get') { + if (containsKey(node.key)) + setSelf(retrieveValue(node.key)) + } + onSet(persistValue(node.key)) + } + + const containsKey = (key: string): boolean => { + const state = getState() + return state.hasOwnProperty(key) + } + + const retrieveValue = (key: string): any => { + const state = getState() + return state[key] + } + + const persistValue = (name: string) => (newValue: any): void => { + let state = getState() + state[name] = newValue + setState(state) + } + + const getState = (): any => { + const toParse = storage.getItem(key) + if (toParse) { + try { + return JSON.parse(toParse) + } catch (e) { + console.error(e) + return {} + } + } else { + return {} + } + } + + const setState = (state: any): void => { + try { + storage.setItem(key, JSON.stringify(state)) + } catch (e) { + console.error(e) + } + } + + return { persistAtom } +} diff --git a/test/demo/index.js b/test/demo/index.js index f82530d..40ea5dc 100644 --- a/test/demo/index.js +++ b/test/demo/index.js @@ -1,50 +1,53 @@ import React from 'react' import ReactDOM from 'react-dom' import { atom, atomFamily, RecoilRoot, useRecoilState } from 'recoil' -import { recoilPersist } from '../../index' +import { recoilPersist } from '../../src' -const { persistStateEffect, updateState } = recoilPersist(['count', 'count3']) +const { persistAtom } = recoilPersist({ key: 'abc1234' }) const counterState = atom({ key: 'count', default: 0, - effects_UNSTABLE: [persistStateEffect], + effects_UNSTABLE: [persistAtom], }) -const counterState2 = atom({ - key: 'count2', +const counterFamily = atomFamily({ + key: 'countFamily', default: 0, - effects_UNSTABLE: [persistStateEffect], + effects_UNSTABLE: [persistAtom], }) -const counterFamily = atomFamily({ - key: 'count3', +const counterState4 = atom({ + key: 'count4', default: 0, - effects_UNSTABLE: [persistStateEffect], }) export default function App() { const [count, setCount] = useRecoilState(counterState) - const [count2, setCount2] = useRecoilState(counterState2) - const [count3, setCount3] = useRecoilState(counterFamily('key')) + const [count2, setCount2] = useRecoilState(counterFamily('2')) + const [count3, setCount3] = useRecoilState(counterFamily('3')) + const [count4, setCount4] = useRecoilState(counterState4) return (

Counter 1 (persist): {count}

-

Counter 2 (not persist): {count2}

+

Counter 2 (persist, atomFamily): {count2}

Counter 3 (persist, atomFamily): {count3}

+

Counter 4 (do not persist): {count4}

+ +
) } -var mountNode = document.getElementById('app') +const mountNode = document.getElementById('app') ReactDOM.render( - + , mountNode, diff --git a/test/index.spec.js b/test/index.spec.js deleted file mode 100644 index d3ea0e0..0000000 --- a/test/index.spec.js +++ /dev/null @@ -1,184 +0,0 @@ -import React from 'react' -import { recoilPersist } from '..' -import { render, fireEvent, waitFor } from '@testing-library/react' -import * as recoil from 'recoil' - -const { updateState, RecoilPersist } = recoilPersist() - -const counterState = recoil.atom({ - key: 'count', - default: 0, - persistence_UNSTABLE: { - type: 'log', - }, -}) - -const counter2State = recoil.atom({ - key: 'count2', - default: 0, - persistence_UNSTABLE: { - type: 'log', - }, -}) - -const counter3State = recoil.atomFamily({ - key: 'count3', - default: 0, - persistence_UNSTABLE: { - type: 'log', - }, -}) - -function Demo() { - const [count, setCount] = recoil.useRecoilState(counterState) - const [count2, setCount2] = recoil.useRecoilState(counter2State) - const [count3, setCount3] = recoil.useRecoilState(counter3State('key')) - return ( -
-

{count}

-

{count}

- - - -
- ) -} - -afterEach(() => { - localStorage.clear() - sessionStorage.clear() - jest.restoreAllMocks() -}) - -it('should update localStorage', async () => { - const { getByText, getByTestId } = render( - - - - , - ) - - fireEvent.click(getByText('Increase')) - await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('1')) - expect(JSON.parse(localStorage.getItem('recoil-persist'))).toStrictEqual({ - count: 1, - }) - expect(sessionStorage.getItem('recoil-persist')).toBeNull() -}) - -it('should update localStorage if using atomFamily', async () => { - const { getByText, getByTestId } = render( - - - - , - ) - fireEvent.click(getByText('Increase')) - fireEvent.click(getByText('Increase 3')) - await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('1')) - expect(JSON.parse(localStorage.getItem('recoil-persist'))).toStrictEqual({ - count: 1, - count3: 1, - }) -}) - -it('should update sessionStorage', async () => { - const { updateState, RecoilPersist } = recoilPersist([], { - storage: sessionStorage, - }) - const { getByText, getByTestId } = render( - - - - , - ) - - fireEvent.click(getByText('Increase')) - await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('1')) - expect(JSON.parse(sessionStorage.getItem('recoil-persist'))).toStrictEqual({ - count: 1, - }) - expect(localStorage.getItem('recoil-persist')).toBeNull() -}) - -it('should update the localStorage only white listed names', async () => { - const { updateState, RecoilPersist } = recoilPersist(['count']) - const { getByText, getByTestId } = render( - - - - , - ) - - fireEvent.click(getByText('Increase')) - fireEvent.click(getByText('Increase 2')) - await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('1')) - expect(JSON.parse(localStorage.getItem('recoil-persist'))).toStrictEqual({ - count: 1, - }) -}) - -it('should read state from localStorage', async () => { - localStorage.setItem( - 'recoil-persist', - JSON.stringify({ count: 1, count3: 1 }), - ) - - const { getByTestId } = render( - - - - , - ) - - expect(getByTestId('count-value').innerHTML).toBe('1') - expect(getByTestId('count3-value').innerHTML).toBe('1') -}) - -it('should handle non jsonable object in localStorage', async () => { - localStorage.setItem('recoil-persist', 'test string') - - const { getByTestId } = render( - - - - , - ) - - await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('0')) -}) - -it('should handle non jsonable object in state', async () => { - let mock = jest.spyOn(JSON, 'stringify').mockImplementation(() => { - throw Error('mock error') - }) - - const { getByText, getByTestId } = render( - - - - , - ) - - fireEvent.click(getByText('Increase')) - await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('1')) - expect(mock).toHaveBeenCalledTimes(1) -}) - -it('should handle non existing atom name stored in storage', async () => { - localStorage.setItem( - 'recoil-persist', - JSON.stringify({ - notExist: 'test value', - }), - ) - - const { getByTestId } = render( - - - - , - ) - - await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('0')) -}) diff --git a/test/index.spec.tsx b/test/index.spec.tsx new file mode 100644 index 0000000..74aad3a --- /dev/null +++ b/test/index.spec.tsx @@ -0,0 +1,172 @@ +import React from 'react' +import { fireEvent, render, waitFor } from '@testing-library/react' +import { atom, atomFamily, RecoilRoot, useRecoilState } from 'recoil' +import { recoilPersist } from '../src' + +const { persistAtom } = recoilPersist() + +const counterState = atom({ + key: 'count', + default: 0, + effects_UNSTABLE: [persistAtom], +}) + +const counterFamily = atomFamily({ + key: 'countFamily', + default: 0, + effects_UNSTABLE: [persistAtom], +}) + +const counterState4 = atom({ + key: 'count4', + default: 0, +}) + +function Demo() { + const [count, setCount] = useRecoilState(counterState) + const [count2, setCount2] = useRecoilState(counterFamily('2')) + const [count3, setCount3] = useRecoilState(counterFamily('3')) + const [count4, setCount4] = useRecoilState(counterState4) + return ( +
+

{count}

+

{count2}

+

{count3}

+

{count4}

+ + + + +
+ ) +} + +const error = jest.fn() +console.error = error + +afterEach(() => { + localStorage.clear() + sessionStorage.clear() + jest.restoreAllMocks() + error.mockClear() +}) + +it('should update localStorage', async () => { + const { getByTestId } = render( + + + , + ) + + fireEvent.click(getByTestId('count-increase')) + await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('1')) + expect(JSON.parse(localStorage.getItem('recoil-persist'))).toStrictEqual({ + count: 1, + }) + expect(sessionStorage.getItem('recoil-persist')).toBeNull() +}) + +it('should update localStorage if using atomFamily', async () => { + const { getByTestId } = render( + + + , + ) + fireEvent.click(getByTestId('count2-increase')) + fireEvent.click(getByTestId('count3-increase')) + await waitFor(() => expect(getByTestId('count2-value').innerHTML).toBe('1')) + await waitFor(() => expect(getByTestId('count3-value').innerHTML).toBe('1')) + expect(JSON.parse(localStorage.getItem('recoil-persist'))).toStrictEqual({ + 'countFamily__"2"': 1, + 'countFamily__"3"': 1, + }) +}) + +it('should not persist atom with no effect', async () => { + const { getByTestId } = render( + + + , + ) + + fireEvent.click(getByTestId('count4-increase')) + await waitFor(() => expect(getByTestId('count4-value').innerHTML).toBe('1')) + expect(JSON.parse(localStorage.getItem('recoil-persist'))).toBeNull() +}) + +it('should read state from localStorage', async () => { + localStorage.setItem( + 'recoil-persist', + JSON.stringify({ count: 1, 'countFamily__"2"': 1 }), + ) + + const { getByTestId } = render( + + + , + ) + + expect(getByTestId('count-value').innerHTML).toBe('1') + expect(getByTestId('count2-value').innerHTML).toBe('1') +}) + +it('should use default value if not in storage', async () => { + localStorage.setItem( + 'recoil-persist', + JSON.stringify({ count: 1, 'countFamily__"2"': 1 }), + ) + + const { getByTestId } = render( + + + , + ) + + expect(getByTestId('count3-value').innerHTML).toBe('0') +}) + +it('should handle non :jsonable object in localStorage', async () => { + localStorage.setItem('recoil-persist', 'test string') + + const { getByTestId } = render( + + + , + ) + + await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('0')) +}) + +it('should handle non jsonable object in state', async () => { + let mock = jest.spyOn(JSON, 'stringify').mockImplementation(() => { + throw Error('mock error') + }) + + const { getByTestId } = render( + + + , + ) + + fireEvent.click(getByTestId('count-increase')) + await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('1')) + expect(mock).toHaveBeenCalledTimes(1) + expect(console.error).toHaveBeenCalledTimes(1) +}) + +it('should handle non-existent atom name stored in storage', async () => { + localStorage.setItem( + 'recoil-persist', + JSON.stringify({ + notExist: 'test value', + }), + ) + + const { getByTestId } = render( + + + , + ) + + await waitFor(() => expect(getByTestId('count-value').innerHTML).toBe('0')) +}) diff --git a/yarn.lock b/yarn.lock index c43e6a7..d118de5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2201,6 +2201,14 @@ dependencies: "@types/istanbul-lib-report" "*" +"@types/jest@26.x", "@types/jest@^26.0.20": + version "26.0.20" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307" + integrity sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA== + dependencies: + jest-diff "^26.0.0" + pretty-format "^26.0.0" + "@types/json-schema@^7.0.3": version "7.0.4" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" @@ -2881,6 +2889,13 @@ browserslist@^4.14.5, browserslist@^4.15.0: escalade "^3.1.1" node-releases "^1.1.67" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -2893,7 +2908,7 @@ buffer-equal@0.0.1: resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" integrity sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs= -buffer-from@^1.0.0: +buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -4445,7 +4460,7 @@ fast-glob@^3.1.1: micromatch "^4.0.2" picomatch "^2.2.1" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -5541,7 +5556,7 @@ jest-config@^26.6.3: micromatch "^4.0.2" pretty-format "^26.6.2" -jest-diff@^26.6.2: +jest-diff@^26.0.0, jest-diff@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== @@ -5807,7 +5822,7 @@ jest-snapshot@^26.6.2: pretty-format "^26.6.2" semver "^7.3.2" -jest-util@^26.6.2: +jest-util@^26.1.0, jest-util@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== @@ -5987,6 +6002,13 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json5@2.x, json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -5994,13 +6016,6 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== - dependencies: - minimist "^1.2.5" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -6188,16 +6203,16 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= +lodash@4.x, lodash@^4.17.19, lodash@^4.17.20: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.4: version "4.17.19" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== -lodash@^4.17.19, lodash@^4.17.20: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== - log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -6255,6 +6270,11 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +make-error@1.x: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" @@ -6423,6 +6443,11 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mkdirp@1.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mkdirp@^0.5.1, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -7521,7 +7546,7 @@ prettier@^2.2.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== -pretty-format@^26.6.2: +pretty-format@^26.0.0, pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== @@ -8114,18 +8139,18 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.2.1, semver@^7.3.2: +semver@7.x, semver@^7.2.1, semver@^7.3.2: version "7.3.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== dependencies: lru-cache "^6.0.0" +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -8906,6 +8931,23 @@ tr46@^2.0.2: dependencies: punycode "^2.1.1" +ts-jest@^26.5.0: + version "26.5.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.0.tgz#3e3417d91bc40178a6716d7dacc5b0505835aa21" + integrity sha512-Ya4IQgvIFNa2Mgq52KaO8yBw2W8tWp61Ecl66VjF0f5JaV8u50nGoptHVILOPGoI7SDnShmEqnYQEmyHdQ+56g== + dependencies: + "@types/jest" "26.x" + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + jest-util "^26.1.0" + json5 "2.x" + lodash "4.x" + make-error "1.x" + mkdirp "1.x" + semver "7.x" + yargs-parser "20.x" + tslib@^1.8.1, tslib@^1.9.0: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" @@ -8981,6 +9023,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" + integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== + uncss@^0.17.2: version "0.17.3" resolved "https://registry.yarnpkg.com/uncss/-/uncss-0.17.3.tgz#50fc1eb4ed573ffff763458d801cd86e4d69ea11" @@ -9381,6 +9428,11 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== +yargs-parser@20.x: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + yargs-parser@^11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" From 36570f5ab561ff341476530f4a52e4de8a0899eb Mon Sep 17 00:00:00 2001 From: Rhys Saldanha Date: Sun, 31 Jan 2021 19:47:42 +0000 Subject: [PATCH 6/6] Use interface --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 2804539..a4385e7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { AtomEffect } from 'recoil' -export class PersistConfiguration { +export interface PersistConfiguration { key?: string storage?: Storage }