diff --git a/.eslintrc.json b/.eslintrc.json index 0efec398..2085a624 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -11,7 +11,8 @@ "@react-navigation/drawer", "@react-navigation/bottom-tabs", "@react-navigation/material-top-tabs", - "@react-navigation/material-bottom-tabs" + "@react-navigation/material-bottom-tabs", + "@react-navigation/devtools" ] }, "env": { "browser": true, "node": true } diff --git a/README.md b/README.md index 4710a047..bf90d570 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,17 @@ If you are looking for version 4, the code can be found in the [4.x branch](http ## Package Versions -| Name | Latest Version | -| ------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -| [@react-navigation/core](/packages/core) | [![badge](https://img.shields.io/npm/v/@react-navigation/core.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/core) | -| [@react-navigation/native](/packages/native) | [![badge](https://img.shields.io/npm/v/@react-navigation/native.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/native) | -| [@react-navigation/routers](/packages/routers) | [![badge](https://img.shields.io/npm/v/@react-navigation/routers.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/routers) | -| [@react-navigation/stack](/packages/stack) | [![badge](https://img.shields.io/npm/v/@react-navigation/stack.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/stack) | -| [@react-navigation/drawer](/packages/drawer) | [![badge](https://img.shields.io/npm/v/@react-navigation/drawer.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/drawer) | -| [@react-navigation/material-top-tabs](/packages/material-top-tabs) | [![badge](https://img.shields.io/npm/v/@react-navigation/material-top-tabs.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/material-top-tabs) | -| [@react-navigation/material-bottom-tabs](/packages/material-bottom-tabs) | [![badge](https://img.shields.io/npm/v/@react-navigation/material-bottom-tabs.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/material-bottom-tabs) | -| [@react-navigation/bottom-tabs](/packages/bottom-tabs) | [![badge](https://img.shields.io/npm/v/@react-navigation/bottom-tabs.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/bottom-tabs) | +| Name | Latest Version | +| ------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| [@react-navigation/core](/packages/core) | [![badge](https://img.shields.io/npm/v/@react-navigation/core.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/core) | +| [@react-navigation/native](/packages/native) | [![badge](https://img.shields.io/npm/v/@react-navigation/native.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/native) | +| [@react-navigation/routers](/packages/routers) | [![badge](https://img.shields.io/npm/v/@react-navigation/routers.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/routers) | +| [@react-navigation/stack](/packages/stack) | [![badge](https://img.shields.io/npm/v/@react-navigation/stack.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/stack) | +| [@react-navigation/drawer](/packages/drawer) | [![badge](https://img.shields.io/npm/v/@react-navigation/drawer.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/drawer) | +| [@react-navigation/material-top-tabs](/packages/material-top-tabs) | [![badge](https://img.shields.io/npm/v/@react-navigation/material-top-tabs.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/material-top-tabs) | +| [@react-navigation/material-bottom-tabs](/packages/material-bottom-tabs) | [![badge](https://img.shields.io/npm/v/@react-navigation/material-bottom-tabs.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/material-bottom-tabs) | +| [@react-navigation/bottom-tabs](/packages/bottom-tabs) | [![badge](https://img.shields.io/npm/v/@react-navigation/bottom-tabs.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/bottom-tabs) | +| [@react-navigation/devtools](/packages/devtools) | [![badge](https://img.shields.io/npm/v/@react-navigation/devtools.svg?style=flat-square)](https://www.npmjs.com/package/@react-navigation/devtools) | ## Contributing diff --git a/example/src/index.tsx b/example/src/index.tsx index ce55308d..fc5fee36 100644 --- a/example/src/index.tsx +++ b/example/src/index.tsx @@ -27,6 +27,7 @@ import { DefaultTheme, DarkTheme, PathConfig, + NavigationContainerRef, } from '@react-navigation/native'; import { createDrawerNavigator, @@ -37,6 +38,7 @@ import { StackNavigationProp, HeaderStyleInterpolators, } from '@react-navigation/stack'; +import { useReduxDevToolsExtension } from '@react-navigation/devtools'; import { restartApp } from './Restart'; import AsyncStorage from './AsyncStorage'; @@ -60,9 +62,6 @@ YellowBox.ignoreWarnings(['Require cycle:', 'Warning: Async Storage']); enableScreens(); -// @ts-ignore -global.REACT_NAVIGATION_REDUX_DEVTOOLS_EXTENSION_INTEGRATION_ENABLED = true; - type RootDrawerParamList = { Root: undefined; Another: undefined; @@ -192,6 +191,10 @@ export default function App() { return () => Dimensions.removeEventListener('change', onDimensionsChange); }, []); + const navigationRef = React.useRef(null); + + useReduxDevToolsExtension(navigationRef); + if (!isReady) { return null; } @@ -204,6 +207,7 @@ export default function App() { )} AsyncStorage.setItem( diff --git a/packages/core/src/BaseNavigationContainer.tsx b/packages/core/src/BaseNavigationContainer.tsx index a61023ed..2b174b3a 100644 --- a/packages/core/src/BaseNavigationContainer.tsx +++ b/packages/core/src/BaseNavigationContainer.tsx @@ -11,7 +11,6 @@ import EnsureSingleNavigator from './EnsureSingleNavigator'; import NavigationBuilderContext from './NavigationBuilderContext'; import { ScheduleUpdateContext } from './useScheduleUpdate'; import useFocusedListeners from './useFocusedListeners'; -import useDevTools from './useDevTools'; import useStateGetters from './useStateGetters'; import useOptionsGetters from './useOptionsGetters'; import useEventEmitter from './useEventEmitter'; @@ -23,14 +22,26 @@ import NavigationStateContext from './NavigationStateContext'; type State = NavigationState | PartialState | undefined; -const DEVTOOLS_CONFIG_KEY = - 'REACT_NAVIGATION_REDUX_DEVTOOLS_EXTENSION_INTEGRATION_ENABLED'; - const NOT_INITIALIZED_ERROR = "The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. See https://reactnavigation.org/docs/navigating-without-navigation-prop#handling-initialization for more details."; let hasWarnedForSerialization = false; +/** + * Migration instructions for removal of devtools from core + */ +Object.defineProperty( + global, + 'REACT_NAVIGATION_REDUX_DEVTOOLS_EXTENSION_INTEGRATION_ENABLED', + { + set(_) { + console.warn( + "Redux devtools extension integration can be enabled with the '@react-navigation/devtools' package. For more details, see https://reactnavigation.org/docs/devtools" + ); + }, + } +); + /** * Remove `key` and `routeNames` from the state objects recursively to get partial state. * @@ -100,7 +111,6 @@ const BaseNavigationContainer = React.forwardRef( ); const isFirstMountRef = React.useRef(true); - const skipTrackingRef = React.useRef(false); const navigatorKeyRef = React.useRef(); @@ -110,23 +120,6 @@ const BaseNavigationContainer = React.forwardRef( navigatorKeyRef.current = key; }, []); - const reset = React.useCallback( - (state: NavigationState) => { - skipTrackingRef.current = true; - setState(state); - }, - [setState] - ); - - const { trackState, trackAction } = useDevTools({ - enabled: - // @ts-ignore - DEVTOOLS_CONFIG_KEY in global ? global[DEVTOOLS_CONFIG_KEY] : false, - name: '@react-navigation', - reset, - state, - }); - const { listeners, addListener: addFocusedListener, @@ -162,10 +155,9 @@ const BaseNavigationContainer = React.forwardRef( const resetRoot = React.useCallback( (state?: PartialState | NavigationState) => { - trackAction('@@RESET_ROOT'); setState(state); }, - [setState, trackAction] + [setState] ); const getRootState = React.useCallback(() => { @@ -211,13 +203,20 @@ const BaseNavigationContainer = React.forwardRef( getCurrentOptions, })); + const onDispatchAction = React.useCallback( + (action: NavigationAction, noop: boolean) => { + emitter.emit({ type: '__unsafe_action__', data: { action, noop } }); + }, + [emitter] + ); + const builderContext = React.useMemo( () => ({ addFocusedListener, addStateGetter, - trackAction, + onDispatchAction, }), - [addFocusedListener, trackAction, addStateGetter] + [addFocusedListener, addStateGetter, onDispatchAction] ); const scheduleContext = React.useMemo( @@ -258,23 +257,14 @@ const BaseNavigationContainer = React.forwardRef( } } - emitter.emit({ - type: 'state', - data: { state }, - }); - - if (skipTrackingRef.current) { - skipTrackingRef.current = false; - } else { - trackState(getRootState); - } + emitter.emit({ type: 'state', data: { state } }); if (!isFirstMountRef.current && onStateChangeRef.current) { onStateChangeRef.current(getRootState()); } isFirstMountRef.current = false; - }, [trackState, getRootState, emitter, state]); + }, [getRootState, emitter, state]); return ( diff --git a/packages/core/src/NavigationBuilderContext.tsx b/packages/core/src/NavigationBuilderContext.tsx index 5bc2c3a3..a1a8364c 100644 --- a/packages/core/src/NavigationBuilderContext.tsx +++ b/packages/core/src/NavigationBuilderContext.tsx @@ -32,10 +32,10 @@ const NavigationBuilderContext = React.createContext<{ addActionListener?: (listener: ChildActionListener) => void; addFocusedListener?: (listener: FocusedNavigationListener) => void; onRouteFocus?: (key: string) => void; + onDispatchAction: (action: NavigationAction, noop: boolean) => void; addStateGetter?: (key: string, getter: NavigatorStateGetter) => void; - trackAction: (action: NavigationAction) => void; }>({ - trackAction: () => undefined, + onDispatchAction: () => undefined, }); export default NavigationBuilderContext; diff --git a/packages/core/src/types.tsx b/packages/core/src/types.tsx index 373da114..50fece8d 100644 --- a/packages/core/src/types.tsx +++ b/packages/core/src/types.tsx @@ -410,8 +410,39 @@ export type RouteConfig< } ); +export type NavigationContainerEventMap = { + /** + * Event which fires when the navigation state changes. + */ + state: { + data: { + /** + * The updated state object after the state change. + */ + state: NavigationState; + }; + }; + /** + * Event which fires when an action is dispatched. + * Only intended for debugging purposes, don't use it for app logic. + * This event will be emitted before state changes have been applied. + */ + __unsafe_action__: { + data: { + /** + * The action object which was dispatched. + */ + action: NavigationAction; + /** + * Whether the action was a no-op, i.e. resulted any state changes. + */ + noop: boolean; + }; + }; +}; + export type NavigationContainerRef = NavigationHelpers & - EventConsumer<{ state: { data: { state: NavigationState } } }> & { + EventConsumer & { /** * Reset the navigation state of the root navigator to the provided state. * diff --git a/packages/core/src/useDescriptors.tsx b/packages/core/src/useDescriptors.tsx index b17f5936..b1e46425 100644 --- a/packages/core/src/useDescriptors.tsx +++ b/packages/core/src/useDescriptors.tsx @@ -80,7 +80,7 @@ export default function useDescriptors< emitter, }: Options) { const [options, setOptions] = React.useState>({}); - const { trackAction } = React.useContext(NavigationBuilderContext); + const { onDispatchAction } = React.useContext(NavigationBuilderContext); const context = React.useMemo( () => ({ @@ -90,16 +90,16 @@ export default function useDescriptors< addFocusedListener, addStateGetter, onRouteFocus, - trackAction, + onDispatchAction, }), [ - navigation, - onAction, addActionListener, addFocusedListener, - onRouteFocus, addStateGetter, - trackAction, + navigation, + onAction, + onDispatchAction, + onRouteFocus, ] ); diff --git a/packages/core/src/useDevTools.tsx b/packages/core/src/useDevTools.tsx deleted file mode 100644 index 476b6785..00000000 --- a/packages/core/src/useDevTools.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import * as React from 'react'; -import { - NavigationState, - NavigationAction, - PartialState, -} from '@react-navigation/routers'; - -type State = NavigationState | PartialState | undefined; - -type Options = { - enabled: boolean; - name: string; - reset: (state: NavigationState) => void; - state: State; -}; - -type DevTools = { - init(value: any): void; - send(action: any, value: any): void; - subscribe( - listener: (message: { type: string; [key: string]: any }) => void - ): () => void; -}; - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace NodeJS { - interface Global { - __REDUX_DEVTOOLS_EXTENSION__: - | { - connect(options: { name: string }): DevTools; - disconnect(): void; - } - | undefined; - } - } -} - -export default function useDevTools({ name, reset, state, enabled }: Options) { - const devToolsRef = React.useRef(); - - if ( - enabled && - process.env.NODE_ENV !== 'production' && - global.__REDUX_DEVTOOLS_EXTENSION__ && - devToolsRef.current === undefined - ) { - devToolsRef.current = global.__REDUX_DEVTOOLS_EXTENSION__.connect({ name }); - } - - const devTools = devToolsRef.current; - const lastStateRef = React.useRef(state); - const actions = React.useRef<(NavigationAction | string)[]>([]); - - React.useEffect(() => { - devTools?.init(lastStateRef.current); - }, [devTools]); - - React.useEffect( - () => - devTools?.subscribe((message) => { - if (message.type === 'DISPATCH' && message.state) { - reset(JSON.parse(message.state)); - } - }), - [devTools, reset] - ); - - const trackState = React.useCallback( - (getState: () => State) => { - if (!devTools) { - return; - } - - while (actions.current.length > 1) { - devTools.send(actions.current.shift(), lastStateRef.current); - } - - const state = getState(); - - if (actions.current.length) { - devTools.send(actions.current.pop(), state); - } else { - devTools.send('@@UNKNOWN', state); - } - - lastStateRef.current = state; - }, - [devTools] - ); - - const trackAction = React.useCallback( - (action: NavigationAction | string) => { - if (!devTools) { - return; - } - - actions.current.push(action); - }, - [devTools] - ); - - return { - trackAction, - trackState, - }; -} diff --git a/packages/core/src/useOnAction.tsx b/packages/core/src/useOnAction.tsx index d9ef3574..1b10fbc1 100644 --- a/packages/core/src/useOnAction.tsx +++ b/packages/core/src/useOnAction.tsx @@ -40,7 +40,7 @@ export default function useOnAction({ onAction: onActionParent, onRouteFocus: onRouteFocusParent, addActionListener: addActionListenerParent, - trackAction, + onDispatchAction, } = React.useContext(NavigationBuilderContext); const routerConfigOptionsRef = React.useRef( @@ -81,7 +81,7 @@ export default function useOnAction({ result = result === null && action.target === state.key ? state : result; if (result !== null) { - trackAction(action); + onDispatchAction(action, state === result); if (state !== result) { setState(result); @@ -122,7 +122,7 @@ export default function useOnAction({ getState, router, onActionParent, - trackAction, + onDispatchAction, onRouteFocusParent, setState, key, diff --git a/packages/devtools/LICENSE b/packages/devtools/LICENSE new file mode 100644 index 00000000..9d268cb0 --- /dev/null +++ b/packages/devtools/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 React Navigation Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/devtools/README.md b/packages/devtools/README.md new file mode 100644 index 00000000..80445fb3 --- /dev/null +++ b/packages/devtools/README.md @@ -0,0 +1,33 @@ +# `@react-navigation/devtools` + +Developer tools for React Navigation. + +Installation instructions and documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/devtools). + +## Installation + +Open a Terminal in your project's folder and run, + +```sh +yarn add @react-navigation/devtools +``` + +## Usage + +For redux dev tools extension integration, you can pass a ref to the container: + +```js +import * as React from 'react'; +import { NavigationContainer } from '@react-navigation/native'; +import { useReduxDevToolsExtension } from '@react-navigation/devtools'; + +export default function App() { + const navigationRef = React.useRef(); + + useReduxDevToolsExtension(navigationRef); + + return ( + {/* ... */} + ); +} +``` diff --git a/packages/devtools/package.json b/packages/devtools/package.json new file mode 100644 index 00000000..fb285056 --- /dev/null +++ b/packages/devtools/package.json @@ -0,0 +1,64 @@ +{ + "name": "@react-navigation/devtools", + "description": "Developer tools for React Navigation", + "version": "5.0.0", + "keywords": [ + "react", + "react-native", + "react-navigation" + ], + "license": "MIT", + "repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/devtools", + "bugs": { + "url": "https://github.com/react-navigation/react-navigation/issues" + }, + "homepage": "https://reactnavigation.org", + "main": "lib/commonjs/index.js", + "react-native": "src/index.tsx", + "source": "src/index.tsx", + "module": "lib/module/index.js", + "types": "lib/typescript/src/index.d.ts", + "files": [ + "src", + "lib", + "!**/__tests__" + ], + "sideEffects": false, + "publishConfig": { + "access": "public" + }, + "scripts": { + "prepare": "bob build", + "clean": "del lib" + }, + "dependencies": { + "@react-navigation/core": "^5.10.0", + "deep-equal": "^2.0.3" + }, + "devDependencies": { + "@react-native-community/bob": "^0.15.1", + "@types/deep-equal": "^1.0.1", + "@types/react": "^16.9.36", + "del-cli": "^3.0.1", + "react": "~16.9.0", + "react-native-testing-library": "^2.1.0", + "typescript": "^3.9.5" + }, + "peerDependencies": { + "react": "*" + }, + "@react-native-community/bob": { + "source": "src", + "output": "lib", + "targets": [ + "commonjs", + "module", + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + } +} diff --git a/packages/devtools/src/index.tsx b/packages/devtools/src/index.tsx new file mode 100644 index 00000000..e1303063 --- /dev/null +++ b/packages/devtools/src/index.tsx @@ -0,0 +1,9 @@ +const noop: any = () => {}; + +export let useReduxDevToolsExtension: typeof import('./useReduxDevToolsExtension').default; + +if (process.env.NODE_ENV !== 'production') { + useReduxDevToolsExtension = require('./useReduxDevToolsExtension').default; +} else { + useReduxDevToolsExtension = noop; +} diff --git a/packages/devtools/src/useReduxDevToolsExtension.tsx b/packages/devtools/src/useReduxDevToolsExtension.tsx new file mode 100644 index 00000000..73d1b1e9 --- /dev/null +++ b/packages/devtools/src/useReduxDevToolsExtension.tsx @@ -0,0 +1,109 @@ +import * as React from 'react'; +import type { + NavigationContainerRef, + NavigationState, + NavigationAction, +} from '@react-navigation/core'; +import deepEqual from 'deep-equal'; + +type DevToolsConnection = { + init(value: any): void; + send(action: any, value: any): void; + subscribe( + listener: (message: { type: string; [key: string]: any }) => void + ): () => void; +}; + +type DevToolsExtension = { + connect(options: { name: string }): DevToolsConnection; + disconnect(): void; +}; + +declare const __REDUX_DEVTOOLS_EXTENSION__: DevToolsExtension | undefined; + +export default function useReduxDevToolsExtension( + ref: React.RefObject +) { + const devToolsRef = React.useRef(); + + if ( + devToolsRef.current === undefined && + typeof __REDUX_DEVTOOLS_EXTENSION__ !== 'undefined' + ) { + devToolsRef.current = __REDUX_DEVTOOLS_EXTENSION__.connect({ + name: '@react-navigation/devtools', + }); + } + + const lastStateRef = React.useRef(); + const lastActionRef = React.useRef(); + + React.useEffect( + () => + devToolsRef.current?.subscribe((message) => { + if (message.type === 'DISPATCH' && message.state) { + const state = JSON.parse(message.state); + + lastStateRef.current = state; + ref.current?.resetRoot(state); + } + }), + [ref] + ); + + React.useEffect(() => { + const devTools = devToolsRef.current; + const navigation = ref.current; + + if (!navigation || !devTools) { + return; + } + + if (lastStateRef.current === undefined) { + const state = navigation.getRootState(); + + devTools.init(state); + lastStateRef.current = state; + } + + const unsubscribeAction = navigation.addListener( + '__unsafe_action__', + (e) => { + const action = e.data.action; + + if (e.data.noop) { + // Even if the state didn't change, it's useful to show the action + devTools.send(action, lastStateRef.current); + } else { + lastActionRef.current = action; + } + } + ); + + const unsubscribeState = navigation.addListener('state', (e) => { + // Don't show the action in dev tools if the state is what we sent to reset earlier + if (lastStateRef.current === e.data.state) { + return; + } + + const lastState = lastStateRef.current; + const state = navigation.getRootState(); + const action = lastActionRef.current; + + lastActionRef.current = undefined; + lastStateRef.current = state; + + // If we don't have an action and the state didn't change, then it's probably extraneous + if (action === undefined && deepEqual(state, lastState)) { + return; + } + + devTools.send(action ?? '@@UNKNOWN', state); + }); + + return () => { + unsubscribeAction(); + unsubscribeState(); + }; + }); +} diff --git a/packages/devtools/tsconfig.build.json b/packages/devtools/tsconfig.build.json new file mode 100644 index 00000000..543a7876 --- /dev/null +++ b/packages/devtools/tsconfig.build.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig", + "compilerOptions": { + "paths": {} + } +} diff --git a/packages/devtools/tsconfig.json b/packages/devtools/tsconfig.json new file mode 100644 index 00000000..38344f2a --- /dev/null +++ b/packages/devtools/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig", + "references": [ + { "path": "../core" }, + { "path": "../routers" } + ], + "compilerOptions": { + "outDir": "./lib/typescript" + } +} diff --git a/yarn.lock b/yarn.lock index 62f218cb..c7977a9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4435,6 +4435,11 @@ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-0.0.30.tgz#dc1e40f7af3b9c815013a7860e6252f6352a84df" integrity sha512-orGL5LXERPYsLov6CWs3Fh6203+dXzJkR7OnddIr2514Hsecwc8xRpzCapshBbKFImCsvS/mk6+FWiN5LyZJAQ== +"@types/deep-equal@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/deep-equal/-/deep-equal-1.0.1.tgz#71cfabb247c22bcc16d536111f50c0ed12476b03" + integrity sha512-mMUu4nWHLBlHtxXY17Fg6+ucS/MnndyOWyOe7MmwkoMYxvfQU2ajtRaEvqSUv+aVkMqH/C0NCI8UoVfRNQ10yg== + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -5577,6 +5582,11 @@ array-differ@^2.0.3: resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-2.1.0.tgz#4b9c1c3f14b906757082925769e8ab904f4801b1" integrity sha512-KbUpJgx909ZscOc/7CLATBFam7P1Z1QRQInvgT0UztM9Q72aGKCunKASAl7WNW0tnPmPyEMeMhdsfWhfmW037w== +array-filter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" + integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= + array-filter@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" @@ -5762,6 +5772,13 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" + integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ== + dependencies: + array-filter "^1.0.0" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -8061,6 +8078,26 @@ deep-equal@^1.0.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" +deep-equal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.3.tgz#cad1c15277ad78a5c01c49c2dee0f54de8a6a7b0" + integrity sha512-Spqdl4H+ky45I9ByyJtXteOm9CaIrPmnIPmOhrkKGNYWeDgCvJ8jNYVCTjChxW4FqGuZnLHADc8EKRMX6+CgvA== + dependencies: + es-abstract "^1.17.5" + es-get-iterator "^1.1.0" + is-arguments "^1.0.4" + is-date-object "^1.0.2" + is-regex "^1.0.5" + isarray "^2.0.5" + object-is "^1.1.2" + object-keys "^1.1.1" + object.assign "^4.1.0" + regexp.prototype.flags "^1.3.0" + side-channel "^1.0.2" + which-boxed-primitive "^1.0.1" + which-collection "^1.0.1" + which-typed-array "^1.1.2" + deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -8656,7 +8693,7 @@ errorhandler@^1.5.0: accepts "~1.3.7" escape-html "~1.0.3" -es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5: +es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4, es-abstract@^1.17.5: version "1.17.5" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== @@ -8673,6 +8710,19 @@ es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstrac string.prototype.trimleft "^2.1.1" string.prototype.trimright "^2.1.1" +es-get-iterator@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.0.tgz#bb98ad9d6d63b31aacdc8f89d5d0ee57bcb5b4c8" + integrity sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ== + dependencies: + es-abstract "^1.17.4" + has-symbols "^1.0.1" + is-arguments "^1.0.4" + is-map "^2.0.1" + is-set "^2.0.1" + is-string "^1.0.5" + isarray "^2.0.5" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -9982,6 +10032,11 @@ for-in@^1.0.2: resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -11515,6 +11570,11 @@ is-arrayish@^0.3.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== +is-bigint@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.0.tgz#73da8c33208d00f130e9b5e15d23eac9215601c4" + integrity sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g== + is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -11529,6 +11589,11 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-boolean-object@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e" + integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ== + is-buffer@^1.1.5, is-buffer@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -11577,7 +11642,7 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1: +is-date-object@^1.0.1, is-date-object@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== @@ -11702,11 +11767,21 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= +is-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1" + integrity sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw== + is-npm@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== +is-number-object@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -11814,6 +11889,11 @@ is-root@2.1.0: resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== +is-set@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.1.tgz#d1604afdab1724986d30091575f54945da7e5f43" + integrity sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA== + is-ssh@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.1.tgz#f349a8cadd24e65298037a522cf7520f2e81a0f3" @@ -11831,7 +11911,7 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-string@^1.0.5: +is-string@^1.0.4, is-string@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== @@ -11857,6 +11937,16 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" +is-typed-array@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d" + integrity sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ== + dependencies: + available-typed-arrays "^1.0.0" + es-abstract "^1.17.4" + foreach "^2.0.5" + has-symbols "^1.0.1" + is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -11867,6 +11957,16 @@ is-utf8@^0.2.0: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + +is-weakset@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83" + integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw== + is-windows@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" @@ -11897,6 +11997,11 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isemail@3.x.x: version "3.2.0" resolved "https://registry.yarnpkg.com/isemail/-/isemail-3.2.0.tgz#59310a021931a9fb06bbb51e155ce0b3f236832c" @@ -14682,6 +14787,14 @@ object-is@^1.0.1: resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.2.tgz#6b80eb84fe451498f65007982f035a5b445edec4" integrity sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ== +object-is@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6" + integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -19838,6 +19951,27 @@ whatwg-url@^8.0.0: tr46 "^2.0.0" webidl-conversions "^5.0.0" +which-boxed-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz#cbe8f838ebe91ba2471bb69e9edbda67ab5a5ec1" + integrity sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ== + dependencies: + is-bigint "^1.0.0" + is-boolean-object "^1.0.0" + is-number-object "^1.0.3" + is-string "^1.0.4" + is-symbol "^1.0.2" + +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -19848,6 +19982,18 @@ which-pm-runs@^1.0.0: resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= +which-typed-array@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2" + integrity sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ== + dependencies: + available-typed-arrays "^1.0.2" + es-abstract "^1.17.5" + foreach "^2.0.5" + function-bind "^1.1.1" + has-symbols "^1.0.1" + is-typed-array "^1.1.3" + which@^1.2.12, which@^1.2.9, which@^1.3.0, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"